msmail / src /views /MailView.vue
github-actions[bot]
Update from GitHub Actions
7fc5208
raw
history blame
13.3 kB
<script setup lang="ts">
import { computed, ref, watch, onMounted } from 'vue';
import { MessagePlugin, DialogPlugin } from 'tdesign-vue-next';
import { accountApi, type Account } from '../services/accountApi';
import { mailApi } from '../services/mailApi';
const loading = ref(false);
const pagination = ref({
current: 1,
total: 0,
pageSize: 18
});
const allData = ref<Account[]>([]);
const userSearch = ref(''); // 添加用户搜索字段
const sort = ref<{ sortBy: string; descending: boolean }>({
sortBy: '',
descending: true
});
const columns = [
{ colKey: 'email', title: '用户', width: 200, sorter: true },
{
colKey: 'action',
title: '操作',
width: 400, // 增加宽度以容纳多个按钮
}
];
// 添加下拉菜单选项函数
const actionOptions = (row: Account) => [
{ content: '刷新认证', value: 'refresh', onClick: () => handleRefreshAuth(row) },
{ content: '最新邮件', value: 'latest', onClick: () => handleLatestMails(row) },
{ content: '所有邮件', value: 'all', onClick: () => handleAllMails(row) },
{ content: '发送邮件', value: 'send', onClick: () => handleSendMail(row) },
];
// 实现处理函数
const handleRefreshAuth = async (row: Account) => {
try {
loading.value = true;
await mailApi.refreshAuth(row.email); // 假设此API存在
MessagePlugin.success('认证已刷新');
} catch (error) {
MessagePlugin.error('刷新认证失败');
} finally {
loading.value = false;
}
};
interface ParsedEmail {
subject: string;
from: string;
to: string[];
date: string;
text: string;
html: string;
}
const showEmailDialog = ref(false);
const currentEmail = ref<any>(null);
const handleLatestMails = async (row: Account) => {
try {
loading.value = true;
const result = await mailApi.getLatestMails(row.email);
if (result) {
currentEmail.value = result;
showEmailDialog.value = true;
} else {
MessagePlugin.info('没有找到邮件');
}
} catch (error:any) {
MessagePlugin.error(`${error.message}`);
} finally {
loading.value = false;
}
};
// 添加所有邮件列表相关的状态
const showAllMailsDialog = ref(false);
const allMailsList = ref<any[]>([]);
const mailsLoading = ref(false);
const handleAllMails = async (row: Account) => {
try {
mailsLoading.value = true;
showAllMailsDialog.value = true;
allMailsList.value= []
const emails = await mailApi.getAllMails(row.email);
allMailsList.value = emails;
} catch (error: any) {
MessagePlugin.error(`获取邮件失败: ${error.message}`);
} finally {
mailsLoading.value = false;
}
};
// 用于打开指定邮件详情
const viewMailDetail = (email: any) => {
currentEmail.value = email;
showEmailDialog.value = true;
};
// 添加发送邮件相关的状态
const showSendDialog = ref(false);
const sendMailForm = ref({
to: '',
subject: '',
body: '',
isHtml: false
});
const currentMailAccount = ref<Account | null>(null);
// 修改发送邮件处理函数
const handleSendMail = async (row: Account) => {
currentMailAccount.value = row;
sendMailForm.value = {
to: '',
subject: '',
body: '',
isHtml: false
};
showSendDialog.value = true;
};
// 添加发送邮件提交函数
const submitSendMail = async () => {
if (!currentMailAccount.value) return;
try {
loading.value = true;
await mailApi.sendMail({
email: currentMailAccount.value.email,
to: sendMailForm.value.to.split(',').map(e => e.trim()),
subject: sendMailForm.value.subject,
body: sendMailForm.value.body,
isHtml: sendMailForm.value.isHtml
});
MessagePlugin.success('邮件发送成功');
showSendDialog.value = false;
} catch (error: any) {
MessagePlugin.error(`发送失败: ${error.message}`);
} finally {
loading.value = false;
}
};
const handleSort = (sortInfo: { sortBy: string; descending: boolean }) => {
sort.value = sortInfo;
pagination.value.current = 1;
};
// 使用计算属性处理排序和分页
const processedData = computed(() => {
let result = [...allData.value];
// 用户搜索过滤
if (userSearch.value) {
result = result.filter(log =>
log.email.toLowerCase().includes(userSearch.value.toLowerCase())
);
}
pagination.value.total = result.length; // 更新总数以反映过滤后的结果
// 分页处理
const start = (pagination.value.current - 1) * pagination.value.pageSize;
const end = start + pagination.value.pageSize;
return result.slice(start, end);
});
const fetchData = async () => {
loading.value = true;
try {
const data = await accountApi.get();
allData.value = data;
pagination.value.total = data.length;
} catch (error) {
MessagePlugin.error('获取数据失败');
} finally {
loading.value = false;
}
};
// 添加 onMounted 钩子
onMounted(() => {
fetchData();
});
</script>
<template>
<div class="w-full h-full flex flex-col p-2 md:p-5 gap-2 md:gap-5">
<div class="flex flex-col md:flex-row md:items-center md:justify-between">
<div class="flex flex-col md:flex-row md:items-center gap-4">
<t-input v-model="userSearch" class="w-full md:w-40" placeholder="搜索用户" clearable />
</div>
</div>
<div class="overflow-x-auto flex-1 overflow-y-auto">
<t-table :data="processedData" :loading="loading" :columns="columns" row-key="datetime" hover
:sort="sort" @sort-change="handleSort" size="small" class="min-w-full">
<template #action="{ row }">
<!-- 桌面端显示 -->
<div class="hidden md:flex flex-wrap gap-2">
<t-button size="small" variant="outline" @click="handleRefreshAuth(row)">刷新认证</t-button>
<t-button size="small" variant="outline" @click="handleLatestMails(row)">最新邮件</t-button>
<t-button size="small" variant="outline" @click="handleAllMails(row)">所有邮件</t-button>
<t-button size="small" variant="outline" @click="handleSendMail(row)">发送邮件</t-button>
</div>
<!-- 移动端显示 -->
<div class="md:hidden">
<t-dropdown :options="actionOptions(row)">
<t-button variant="outline" size="small">操作 <t-icon name="chevron-down" /></t-button>
</t-dropdown>
</div>
</template>
</t-table>
</div>
<div class="flex justify-end">
<t-pagination v-model="pagination.current" :total="pagination.total" :page-size="pagination.pageSize"
size="small" />
</div>
<!-- 邮件详情对话框 -->
<t-dialog
:visible="showEmailDialog"
:header="currentEmail?.subject"
@close="showEmailDialog = false"
:width="800"
:footer="false"
class="email-detail-dialog"
>
<template v-if="currentEmail">
<div class="email-details">
<div class="email-meta">
<p><strong>发件人:</strong> {{ currentEmail.from }}</p>
<p><strong>收件人:</strong> {{ currentEmail.to?.join(', ') }}</p>
<p><strong>时间:</strong> {{ new Date(currentEmail.date.received).toLocaleString() }}</p>
<p v-if="currentEmail.metadata?.location"><strong>位置:</strong> {{ currentEmail.metadata.location }}</p>
<p v-if="currentEmail.metadata?.ip"><strong>IP:</strong> {{ currentEmail.metadata.ip }}</p>
<p v-if="currentEmail.metadata?.platform"><strong>平台:</strong> {{ currentEmail.metadata.platform }}</p>
<p v-if="currentEmail.metadata?.browser"><strong>浏览器:</strong> {{ currentEmail.metadata.browser }}</p>
<p><strong>重要性:</strong> {{ currentEmail.importance }}</p>
<p><strong>状态:</strong> {{ currentEmail.isRead ? '已读' : '未读' }}</p>
</div>
<div class="email-content" v-html="currentEmail.html || currentEmail.text"></div>
<div v-if="currentEmail.hasAttachments" class="email-attachments">包含附件</div>
<div class="email-actions">
<a :href="currentEmail.webLink" target="_blank">在Outlook中查看</a>
</div>
</div>
</template>
</t-dialog>
<!-- 所有邮件列表对话框 -->
<t-dialog
:visible="showAllMailsDialog"
header="所有邮件"
@close="showAllMailsDialog = false"
:width="900"
:footer="false"
>
<t-loading :loading="mailsLoading">
<div class="emails-list">
<t-list>
<t-list-item
v-for="email in allMailsList"
:key="email.id"
@click="viewMailDetail(email)"
class="email-list-item"
>
<div class="flex flex-col gap-1 w-full cursor-pointer hover:bg-gray-50 p-2">
<div class="flex justify-between">
<span class="font-medium">{{ email.subject || '(无主题)' }}</span>
<span class="text-gray-500 text-sm">
{{ new Date(email.date.received).toLocaleString() }}
</span>
</div>
<div class="flex justify-between text-sm">
<span class="text-gray-600">发件人: {{ email.from }}</span>
<span :class="{'text-green-600': email.isRead, 'text-red-600': !email.isRead}">
{{ email.isRead ? '已读' : '未读' }}
</span>
</div>
</div>
</t-list-item>
</t-list>
</div>
</t-loading>
</t-dialog>
<!-- 发送邮件对话框 -->
<t-dialog
:visible="showSendDialog"
header="发送邮件"
@close="showSendDialog = false"
:width="600"
:footer="false"
>
<template v-if="currentMailAccount">
<div class="send-mail-form">
<t-form>
<t-form-item label="发件人">
<t-input disabled :value="currentMailAccount.email" />
</t-form-item>
<t-form-item label="收件人">
<t-input v-model="sendMailForm.to" placeholder="多个收件人请用逗号分隔" />
</t-form-item>
<t-form-item label="主题">
<t-input v-model="sendMailForm.subject" />
</t-form-item>
<t-form-item label="内容">
<t-textarea v-model="sendMailForm.body" :rows="6" />
</t-form-item>
<t-form-item>
<t-checkbox v-model="sendMailForm.isHtml">HTML 格式</t-checkbox>
</t-form-item>
<t-form-item>
<div class="flex justify-end gap-2">
<t-button theme="default" @click="showSendDialog = false">取消</t-button>
<t-button theme="primary" @click="submitSendMail" :loading="loading">发送</t-button>
</div>
</t-form-item>
</t-form>
</div>
</template>
</t-dialog>
</div>
</template>
<style scoped>
@media (max-width: 768px) {
:deep(.t-table__header) {
font-size: 14px;
}
:deep(.t-table td) {
font-size: 13px;
}
}
.email-details {
max-height: 60vh;
overflow-y: auto;
padding: 16px;
}
.email-content {
margin-top: 16px;
border-top: 1px solid #eee;
padding-top: 16px;
}
.email-meta {
background: #f5f5f5;
padding: 12px;
border-radius: 4px;
margin-bottom: 16px;
}
.email-actions {
margin-top: 16px;
text-align: right;
}
.email-attachments {
margin-top: 16px;
color: #666;
font-style: italic;
}
.send-mail-form {
padding: 16px;
}
.emails-list {
max-height: 60vh;
overflow-y: auto;
}
.email-list-item {
border-bottom: 1px solid #eee;
}
.email-list-item:last-child {
border-bottom: none;
}
/* 添加以下CSS确保邮件详情弹窗总是显示在最上层 */
:deep(.email-detail-dialog) {
z-index: 3000 !important; /* 确保高于其他弹窗 */
}
/* 可能需要调整其他弹窗的z-index */
:deep(.t-dialog) {
z-index: 2000;
}
</style>