fix: 添加邮箱抄送密发功能

This commit is contained in:
陆光LG
2025-08-18 12:45:26 +08:00
parent e34b931798
commit 40447d980c
5 changed files with 152 additions and 102 deletions

View File

@@ -1,92 +0,0 @@
# Email组件外部表格保存功能测试说明
## 功能概述
已为Email组件实现了模仿Setting组件的外部表格保存功能。当用户在Email组件中进行设置时配置数据会自动保存到store中当关闭弹窗时外部的EmailForm会从store中获取这些数据并显示在表格中。
## 实现细节
### 1. 创建了Email Store (`src/store/modules/email.ts`)
- `emailFormList`: 存储邮件配置数据的数组
- `addEmailData()`: 添加邮件配置数据
- `updateEmailData()`: 更新邮件配置数据
- `removeEmailData()`: 删除邮件配置数据
- `clearEmailData()`: 清空所有邮件配置数据
### 2. 创建了Email消息发送函数 (`src/components/Email/index.ts`)
- `sendEmailMsg()`: 将邮件设置数据保存到store中
- 格式化数据支持boolean类型显示为"打开/关闭",其他类型直接显示值
- 数据结构:`{ contentIn: "设置描述", content: "category@key@value" }`
- 避免重复相同category@key的数据会被更新而不是重复添加
### 3. 修改了Email Setting组件 (`src/components/Email/components/setting.vue`)
- 导入了`sendEmailMsg`函数
- 为所有设置项的变更事件添加了数据保存调用:
- 语言设置:`common@language@value`
- 文字大小:`common@fontSize@value`
- 邮件数量:`common@emailCount@value`
- 邮件选项:`common@checkList@value`
- 天气显示:`common@weather@value`
- 生日提醒:`common@birthdayRemind@value`
- 邮件昵称:`account@nickname@value`
- 生日信息:`account@birthYear/birthMonth/birthDay@value`
- 生日可见性:`account@birthdayVisible@value`
- 默认账户:`account@defaultAccount@value`
### 4. 修改了Email子组件 (`src/components/Email/children/components/skinSettings.vue`)
- 为皮肤设置功能添加了数据保存:
- 选择皮肤:`skin@selectedSkin@value`
- 应用皮肤:`skin@appliedSkin@value`
- 恢复默认:`skin@resetSkin@default`
### 5. 修改了EmailForm组件 (`src/views/paper/question/EmailForm.vue`)
- 导入了`useEmailStore`
- 添加了`handleEmailForm()`函数在dialog关闭时从store获取数据
- 修改了dialog的`@close`事件,绑定到`handleEmailForm`
- 调整了表格显示:
- 将"试题考点"改为"邮件配置"
- 将"考点"列改为"配置项"列
- 将"权值"列改为"配置值"列
- 将"添加"按钮改为"设置"按钮
## 使用流程
1. 用户在EmailForm中点击"设置"按钮
2. 打开Email组件的设置弹窗
3. 用户在Email组件中进行各种设置语言、皮肤、账户等
4. 每次设置都会通过`sendEmailMsg()`保存到`emailStore.emailFormList`
5. 用户关闭弹窗时,触发`handleEmailForm()`函数
6. `handleEmailForm()`从store中获取数据并更新外部表格`list.value`
7. 表格显示格式化的配置信息,如:
- "设置邮件界面语言: 中文" | "common@language@zh_cn"
- "设置邮件应用皮肤: default" | "skin@appliedSkin@default"
- "设置邮件邮件昵称: demo" | "account@nickname@demo"
## 数据格式说明
每个配置项在store中的数据格式
```javascript
{
contentIn: "设置邮件界面语言: 中文", // 用户友好的描述
content: "common@language@zh_cn" // 结构化的数据标识
}
```
## 测试验证
可以按以下步骤测试功能:
1. 打开EmailForm页面
2. 点击"邮件配置"标签页中的"设置"按钮
3. 在Email组件中修改各种设置语言、皮肤等
4. 关闭设置弹窗
5. 检查外部表格是否显示了相应的配置项
6. 通过浏览器开发者工具查看console.log输出确认数据保存
这样就完成了Email组件的外部表格保存功能与Setting组件的实现模式完全一致。

View File

@@ -45,8 +45,8 @@
 封邮件  封邮件
</div> </div>
<el-checkbox-group v-model="commonForm.checkList" @change="handleCheckboxChange"> <el-checkbox-group v-model="commonForm.checkList" @change="handleCheckboxChange">
<el-checkbox label="main">显示邮件摘要</el-checkbox> <el-checkbox label="显示邮件摘要">显示邮件摘要</el-checkbox>
<el-checkbox label="size">显示邮件大小</el-checkbox> <el-checkbox label="显示邮件大小">显示邮件大小</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
<el-form-item label="在首页上:"> <el-form-item label="在首页上:">
@@ -260,7 +260,7 @@ const handleLanguageChange = (value: string) => {
// 文字大小变更处理 // 文字大小变更处理
const handleFontSizeChange = (value: number) => { const handleFontSizeChange = (value: number) => {
const sizeText = ['标准', '中号', '大号'][value] const sizeText = ['标准', '中号', '大号'][value]
sendEmailMsg(name.value, '文字大小', 'common', 'fontSize', value) sendEmailMsg(name.value, '文字大小', 'common', 'fontSize', sizeText)
ElMessage.success(`文字大小已设置为: ${sizeText}`) ElMessage.success(`文字大小已设置为: ${sizeText}`)
console.log('文字大小变更:', value, sizeText) console.log('文字大小变更:', value, sizeText)
} }

View File

@@ -19,13 +19,27 @@
<span class="text-label">收件人</span> <span class="text-label">收件人</span>
<el-input v-model="recipient" class="row-input" /> <el-input v-model="recipient" class="row-input" />
</div> </div>
<!-- 抄送输入框 -->
<div v-if="showCc" class="row flex" style="margin-bottom: 5px">
<span class="text-label">抄送</span>
<el-input v-model="cc" class="row-input" placeholder="请输入抄送邮箱地址" />
</div>
<!-- 密送输入框 -->
<div v-if="showBcc" class="row flex" style="margin-bottom: 5px">
<span class="text-label">密送</span>
<el-input v-model="bcc" class="row-input" placeholder="请输入密送邮箱地址" />
</div>
<div <div
class="row flex" class="row flex"
style="justify-content: flex-start; padding-left: 7.5%; margin-bottom: 8px" style="justify-content: flex-start; padding-left: 7.5%; margin-bottom: 8px"
> >
<div class="text-button" style="margin-right: 8px">添加抄送</div> <div class="text-button" style="margin-right: 8px" @click="toggleCc">
{{ showCc ? '隐藏抄送' : '添加抄送' }}
</div>
<div class="text-divider" style="margin-right: 8px">-</div> <div class="text-divider" style="margin-right: 8px">-</div>
<div class="text-button" style="margin-right: 8px">添加密送</div> <div class="text-button" style="margin-right: 8px" @click="toggleBcc">
{{ showBcc ? '隐藏密送' : '添加密送' }}
</div>
<div class="text-divider" style="margin-right: 8px; color: #ccc6bf">|</div> <div class="text-divider" style="margin-right: 8px; color: #ccc6bf">|</div>
<div class="text-button">分别发送</div> <div class="text-button">分别发送</div>
</div> </div>
@@ -37,7 +51,7 @@
class="row flex" class="row flex"
style="justify-content: flex-start; padding-left: 7.5%; margin-bottom: 5px" style="justify-content: flex-start; padding-left: 7.5%; margin-bottom: 5px"
> >
<div class="text-button flex" style="margin-right: 10px"> <div class="text-button flex" style="margin-right: 10px" @click="handleAddAttachment">
<img src="../img/annex_logo.png" style="width: 14px; height: 14px; margin-right: 3px" /> <img src="../img/annex_logo.png" style="width: 14px; height: 14px; margin-right: 3px" />
添加附件 添加附件
</div> </div>
@@ -82,6 +96,57 @@
格式 格式
</div> </div>
</div> </div>
<!-- 附件显示区域 -->
<div
v-if="attachments.length > 0"
class="row flex"
style="flex-direction: column; align-items: flex-start; margin-bottom: 8px"
>
<span class="text-label" style="margin-bottom: 5px; margin-left: 7.5%"
>附件 ({{ attachments.length }})</span
>
<div
style="
width: 93%;
margin-left: 7.5%;
border: 1px solid #707070;
background: #fff;
padding: 8px;
"
>
<div
v-for="(attachment, index) in attachments"
:key="attachment.id"
class="attachment-item flex"
style="
justify-content: space-between;
align-items: center;
margin-bottom: 5px;
padding: 5px;
background: #f5f5f5;
border-radius: 3px;
"
>
<div class="attachment-info flex" style="align-items: center">
<img
src="../img/annex_logo.png"
style="width: 16px; height: 16px; margin-right: 5px"
/>
<span style="font-size: 14px; color: #333">{{ attachment.name }}</span>
<span style="font-size: 12px; color: #666; margin-left: 10px"
>({{ attachment.size }})</span
>
</div>
<el-button
type="danger"
size="small"
@click="removeAttachment(index)"
style="padding: 2px 5px; font-size: 12px"
>删除</el-button
>
</div>
</div>
</div>
<div class="row flex" style="flex: 1; align-items: flex-start; margin-bottom: 8px"> <div class="row flex" style="flex: 1; align-items: flex-start; margin-bottom: 8px">
<span class="text-label">正文</span> <span class="text-label">正文</span>
<el-input v-model="content" type="textarea" class="row-input" /> <el-input v-model="content" type="textarea" class="row-input" />
@@ -121,6 +186,56 @@ const recipient = ref('')
const subject = ref('') const subject = ref('')
const content = ref('') const content = ref('')
// CC和BCC相关
const showCc = ref(false)
const cc = ref('')
const showBcc = ref(false)
const bcc = ref('')
// 附件相关
const attachments = ref<Array<{ id: number; name: string; size: string; file: File }>>([])
// 切换CC显示
const toggleCc = () => {
showCc.value = !showCc.value
}
// 切换BCC显示
const toggleBcc = () => {
showBcc.value = !showBcc.value
}
// 添加附件
const handleAddAttachment = () => {
// 创建文件输入元素
const input = document.createElement('input')
input.type = 'file'
input.multiple = true
input.onchange = (event: Event) => {
const target = event.target as HTMLInputElement
const files = target?.files
if (files) {
for (let i = 0; i < files.length; i++) {
const file = files[i]
attachments.value.push({
id: Date.now() + i,
name: file.name,
size: (file.size / 1024 / 1024).toFixed(2) + 'MB',
file: file
})
}
ElMessage.success(`已添加 ${files.length} 个附件`)
}
}
input.click()
}
// 删除附件
const removeAttachment = (index: number) => {
attachments.value.splice(index, 1)
ElMessage.info('已删除附件')
}
// 发送邮件 // 发送邮件
const handleSend = () => { const handleSend = () => {
if (!recipient.value.trim()) { if (!recipient.value.trim()) {
@@ -141,6 +256,22 @@ const handleSend = () => {
sendEmailMsg(name.value, '邮件主题', 'write', 'subject', subject.value) sendEmailMsg(name.value, '邮件主题', 'write', 'subject', subject.value)
sendEmailMsg(name.value, '邮件正文', 'write', 'content', content.value) sendEmailMsg(name.value, '邮件正文', 'write', 'content', content.value)
// 保存CC信息
if (cc.value.trim()) {
sendEmailMsg(name.value, '抄送', 'write', 'cc', cc.value)
}
// 保存BCC信息
if (bcc.value.trim()) {
sendEmailMsg(name.value, '密送', 'write', 'bcc', bcc.value)
}
// 保存附件信息
if (attachments.value.length > 0) {
const attachmentNames = attachments.value.map((att) => att.name).join(', ')
sendEmailMsg(name.value, '附件', 'write', 'attachments', attachmentNames)
}
ElMessage.success('邮件发送成功!') ElMessage.success('邮件发送成功!')
// 清空表单 // 清空表单
@@ -206,6 +337,11 @@ const clearForm = () => {
recipient.value = '' recipient.value = ''
subject.value = '' subject.value = ''
content.value = '' content.value = ''
cc.value = ''
bcc.value = ''
attachments.value = []
showCc.value = false
showBcc.value = false
} }
</script> </script>

View File

@@ -26,8 +26,8 @@ export function sendEmailMsg(pageName: string, description: string, category: st
// 拼接 content 字符串 // 拼接 content 字符串
const content = `${category}@${key}@${value}` const content = `${category}@${key}@${value}`
// 创建数据对象并添加到 store包含scoreRate权值字段默认为空,由用户填写 // 创建数据对象并添加到 store包含scoreRate权值字段默认为1
const data = { contentIn, content, scoreRate: '' }; const data = { contentIn, content, scoreRate: 1 };
// 为了避免重复,可以先查找并更新,如果不存在再添加 // 为了避免重复,可以先查找并更新,如果不存在再添加
const existingIndex = emailStore.emailFormList.findIndex(item => item.content.startsWith(`${category}@${key}@`)); const existingIndex = emailStore.emailFormList.findIndex(item => item.content.startsWith(`${category}@${key}@`));

View File

@@ -515,7 +515,7 @@ const open = async (queryParams: any, type: string, id?: number) => {
dialogVisible.value = true dialogVisible.value = true
dialogTitle.value = t('action.' + type) dialogTitle.value = t('action.' + type)
formType.value = type formType.value = type
resetForm()
// 修改时,设置数据 // 修改时,设置数据
if (id) { if (id) {
formLoading.value = true formLoading.value = true
@@ -554,6 +554,12 @@ defineExpose({ open }) // 提供 open 方法,用于打开弹窗
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
const submitForm = async () => { const submitForm = async () => {
formData.value.answerList = list.value formData.value.answerList = list.value
//默认权值为1
formData.value.answerList.forEach((item) => {
if (!item.scoreRate) {
item.scoreRate = '1' // 设置默认权值为1
}
})
formData.value.fileUploads = documentList.value formData.value.fileUploads = documentList.value
const values = Object.values(formData) const values = Object.values(formData)
console.log(values) console.log(values)
@@ -600,7 +606,7 @@ const resetForm = () => {
image: '', image: '',
content: '', content: '',
contentIn: '', contentIn: '',
scoreRate: '' scoreRate: '1'
} }
], ],
fileUploads: [ fileUploads: [