日常开发记录-dangerouslyUseHTMLString:true; 属性的作用

将 dangerouslyUseHtmlString 属性设置为 true ,message 就会被当做 HTML 片段处理。

 案例 demo :

this.$notify({
        title: 'HTML 片段',
        dangerouslyUseHTMLString: true,
        message: '<div>这是 <i>HTML</i> 片段</div>'
      })

效果展示:

<template> <div class="app-container"> <el-tabs v-model="activeTab" class="setting-tabs" type="border-card"> <!-- 收件人管理标签页 --> <el-tab-pane label="收件人管理" name="receivers"> <el-card class="setting-card"> <template #header> <div class="card-header"> <el-icon class="header-icon"><User /></el-icon> <span>收件人管理</span> <el-text type="info" class="header-desc">管理接收提醒邮件的人员信息</el-text> </div> </template> <div class="card-content"> <!-- 选择用户区域 --> <el-form inline class="add-receiver-form"> <el-form-item label="选择用户"> <el-input v-model="userSearchText" placeholder="点击搜索框选择用户" readonly @click="openUserSelectModal" class="user-select-input" > <template #suffix> <el-icon class="search-icon" @click.stop="openUserSelectModal"> <Search /> </el-icon> </template> </el-input> </el-form-item> <el-form-item> <el-button type="primary" :icon="Plus" @click="handleAddSelectedUsers" :disabled="selectedUserIds.length === 0" > 添加到收件人列表 </el-button> </el-form-item> </el-form> <!-- 已选用户预览 --> <div v-if="selectedUserIds.length > 0" class="selected-users-preview"> <el-tag v-for="userId in selectedUserIds" :key="userId" closable @close="removeSelectedUser(userId)" class="selected-tag" > {{ getUserNameById(userId) }} </el-tag> </div> <!-- 已选收件人列表 --> <div class="receiver-list-container"> <el-table :data="filteredReceivers" border stripe :loading="receiverLoading" class="receiver-table" max-height="400" row-key="recipientId" > <el-table-column type="index" label="序号" width="80" align="center" /> <el-table-column prop="recipientName" label="姓名" width="160" /> <el-table-column prop="email" label="邮箱地址" min-width="200"> <template #default="scope"> <el-tooltip :content="scope.row.email || '未设置邮箱'" placement="top"> <span class="email-text">{{ scope.row.email || '未设置邮箱' }}</span> </el-tooltip> </template> </el-table-column> <el-table-column label="状态" width="120" align="center"> <template #default="scope"> <el-switch v-model="scope.row.status" active-value="1" inactive-value="0" @change="handleStatusChange(scope.row)" :loading="scope.row.statusLoading" /> </template> </el-table-column> <el-table-column label="是否默认" width="120" align="center"> <template #default="scope"> <el-checkbox v-model="scope.row.isDefault" :true-label="1" :false-label="0" @change="handleDefaultChange(scope.row)" :disabled="scope.row.defaultDisabled" /> </template> </el-table-column> <el-table-column label="排序" width="100" align="center"> <template #default="scope"> <el-input-number v-model="scope.row.sort" min="0" @change="handleSortChange(scope.row)" size="small" :disabled="scope.row.sortDisabled" /> </template> </el-table-column> <el-table-column label="操作" width="160" align="center"> <template #default="scope"> <el-button size="small" type="text" @click="handleEditReceiver(scope.row)" :icon="Edit" :disabled="scope.row.operateDisabled" /> <el-button size="small" type="text" text-color="#F53F3F" @click="handleDeleteReceiver(scope.row.recipientId)" :icon="Delete" :disabled="scope.row.operateDisabled" /> </template> </el-table-column> </el-table> <div v-if="filteredReceivers.length === 0 && !receiverLoading" class="empty-state"> <el-empty description="暂无收件人,请从系统用户中选择" /> </div> <div class="form-actions"> <el-button type="primary" @click="handleSaveReceivers" :icon="Check" :loading="saveReceiversLoading" > 保存收件人设置 </el-button> </div> </div> </div> </el-card> </el-tab-pane> <!-- 发送配置标签页 --> <el-tab-pane label="发送配置" name="config"> <el-card class="setting-card"> <template #header> <div class="card-header"> <el-icon class="header-icon"><Clock /></el-icon> <span>发送配置</span> <el-text type="info" class="header-desc">配置邮件发送服务器及提醒频率</el-text> </div> </template> <div class="card-content"> <el-form :model="sendConfig" :rules="configRules" ref="configFormRef" class="config-form" label-width="160px" > <!-- 基础SMTP配置 --> <el-collapse v-model="activeCollapse" class="config-collapse"> <el-collapse-item title="SMTP服务器配置" name="smtp"> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="是否启用邮件发送" prop="enable"> <el-switch v-model="sendConfig.enable" active-value="1" inactive-value="0" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="发件人显示名称" prop="senderName"> <el-input v-model="sendConfig.senderName" placeholder="请输入发件人显示名称" class="input-control" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="SMTP服务器地址" prop="host"> <el-input v-model="sendConfig.host" placeholder="如: smtp.qq.com" class="input-control" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="SMTP服务器端口" prop="port"> <el-input-number v-model="sendConfig.port" min="1" max="65535" class="input-control" placeholder="如: 587" /> </el-form-item> </el-col> </el-row> </el-collapse-item> <!-- 提醒频率配置 --> <el-collapse-item title="提醒频率配置" name="frequency"> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="发送频率" prop="frequency"> <el-select v-model="sendConfig.frequency" placeholder="请选择发送频率" class="input-control" @change="handleFrequencyChange" > <el-option label="每天" value="daily" /> <el-option label="每周" value="weekly" /> <el-option label="每月" value="monthly" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="发送时间" prop="sendTime"> <el-time-picker v-model="sendConfig.sendTime" format="HH:mm" value-format="HH:mm" placeholder="选择发送时间" class="input-control" /> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="提前__天" prop="advanceTime"> <el-input-number v-model="sendConfig.advanceTime" min="0" placeholder="请输入提前天数" class="input-control" /> </el-form-item> </el-col> </el-row> </el-collapse-item> </el-collapse> <el-form-item class="form-actions"> <el-button type="primary" @click="handleSaveConfig" :icon="Check" :loading="saveConfigLoading" > 保存发送配置 </el-button> </el-form-item> </el-form> </div> </el-card> </el-tab-pane> <!-- 邮件模板标签页 --> <el-tab-pane label="邮件模板" name="template"> <el-card class="setting-card"> <template #header> <div class="card-header"> <el-icon class="header-icon"><Document /></el-icon> <span>邮件模板</span> <el-text type="info" class="header-desc">自定义提醒邮件的模板内容</el-text> </div> </template> <div class="card-content"> <!-- 模板类型选择 --> <el-radio-group v-model="activeTemplateType" class="template-type-group" @change="handleTemplateTypeChange" :disabled="templateLoading" > <el-radio-button label="license">项目授权到期提醒</el-radio-button> <el-radio-button label="maintenance">项目运维到期提醒</el-radio-button> </el-radio-group> <el-form :model="currentTemplate" :rules="templateRules" ref="templateFormRef" class="template-form" label-width="140px" :disabled="templateLoading" > <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="模板名称" prop="templateName"> <el-input v-model="currentTemplate.templateName" placeholder="请输入模板名称" class="input-control" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="模板状态" prop="status"> <el-switch v-model="currentTemplate.status" active-value="1" inactive-value="0" /> </el-form-item> </el-col> </el-row> <el-form-item label="邮件标题" prop="subject"> <el-input v-model="currentTemplate.subject" placeholder="请输入邮件标题" class="input-control" /> <el-text type="info" class="help-text">点击下方变量可快速插入</el-text> </el-form-item> <el-form-item label="邮件内容" prop="content"> <el-input v-model="currentTemplate.content" type="textarea" rows="10" placeholder="请输入邮件内容" class="input-control" /> <div class="template-variables"> <el-text type="info">支持变量:</el-text> <el-tag v-for="(desc, key) in getAvailableVariables()" :key="key" class="variable-tag" @click="insertVariable(key)" > ${key} <span class="variable-desc">={{ desc }}</span> </el-tag> </div> </el-form-item> <el-form-item> <el-button type="primary" @click="handlePreviewTemplate" :icon="View" class="preview-btn" > 预览 </el-button> <el-button type="success" @click="handleSaveTemplate" :icon="Check" :loading="saveTemplateLoading" > 保存模板 </el-button> </el-form-item> </el-form> </div> </el-card> </el-tab-pane> <!-- 提醒规则配置标签页 --> <el-tab-pane label="提醒规则" name="reminder"> <el-card class="setting-card"> <template #header> <div class="card-header"> <el-icon class="header-icon"><Star /></el-icon> <span>提醒规则配置</span> <el-text type="info" class="header-desc">设置项目到期提醒的触发条件与规则</el-text> </div> </template> <div class="card-content"> <el-form :model="reminderRule" :rules="reminderRules" ref="reminderFormRef" class="reminder-form" label-width="180px" > <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="是否启用提醒规则" prop="enable"> <el-switch v-model="reminderRule.enable" active-value="1" inactive-value="0" @change="handleRuleEnableChange" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="提醒触发类型" prop="triggerType"> <el-select v-model="reminderRule.triggerType" placeholder="请选择触发类型" class="input-control" :disabled="reminderRule.enable === '0'" > <el-option label="按到期时间" value="expireDate" /> <el-option label="按剩余天数" value="remainingDays" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="20" v-if="reminderRule.enable === '1'"> <el-col :span="12"> <el-form-item label="提前提醒天数" prop="advanceDays" :rules="[ { required: reminderRule.triggerType === 'remainingDays', message: '请输入提前提醒天数', trigger: 'blur' }, { type: 'number', min: 0, message: '提前天数不能为负数', trigger: 'blur' } ]" > <el-input-number v-model="reminderRule.advanceDays" min="0" placeholder="如:7(提前7天提醒)" class="input-control" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="重复提醒间隔" prop="repeatInterval"> <el-select v-model="reminderRule.repeatInterval" placeholder="请选择重复间隔" class="input-control" > <el-option label="不重复" value="none" /> <el-option label="每天" value="daily" /> <el-option label="每3天" value="3days" /> <el-option label="每周" value="weekly" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="20" v-if="reminderRule.enable === '1'"> <el-col :span="24"> <el-form-item label="适用项目类型" prop="projectTypes"> <el-select v-model="reminderRule.projectTypes" placeholder="请选择适用项目类型(可多选)" class="input-control" multiple > <el-option label="授权项目" value="license" /> <el-option label="运维项目" value="maintenance" /> <el-option label="定制开发项目" value="custom" /> </el-select> </el-form-item> </el-col> </el-row> <el-form-item class="form-actions"> <el-button type="primary" @click="handleSaveReminderRule" :icon="Check" :loading="saveReminderLoading" > 保存提醒规则 </el-button> </el-form-item> </el-form> </div> </el-card> </el-tab-pane> </el-tabs> <!-- 用户选择弹窗 --> <el-dialog v-model="userSelectModalVisible" title="选择用户" width="70%" max-height="80vh" :before-close="handleModalClose" :close-on-click-modal="false" > <div class="user-modal-content"> <!-- 搜索框 --> <el-input v-model="modalSearchQuery" placeholder="输入用户名或邮箱搜索" class="modal-search-input" @input="handleModalSearch" > <template #suffix> <el-icon> <Search /> </el-icon> </template> </el-input> <!-- 用户列表 --> <el-table :data="filteredModalUsers" border stripe :loading="modalUserLoading" class="user-select-table" max-height="500px" @selection-change="handleUserSelectionChange" row-key="userId" > <el-table-column type="selection" width="55" /> <el-table-column prop="userId" label="用户ID" width="100" /> <el-table-column prop="userName" label="姓名" width="120" /> <el-table-column prop="email" label="邮箱地址" min-width="200"> <template #default="scope"> <el-tooltip :content="scope.row.email || '未设置邮箱'" placement="top"> <span class="email-text">{{ scope.row.email || '未设置邮箱' }}</span> </el-tooltip> </template> </el-table-column> <el-table-column prop="deptName" label="部门" width="150" /> <el-table-column prop="status" label="状态" width="100" align="center"> <template #default="scope"> <el-tag :type="scope.row.status === '0' ? 'success' : 'danger'"> {{ scope.row.status === '0' ? '启用' : '禁用' }} </el-tag> </template> </el-table-column> </el-table> <!-- 分页 --> <el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize" :total="totalUsers" :page-sizes="[10, 20, 50]" layout="total, sizes, prev, pager, next, jumper" @size-change="handlePageSizeChange" @current-change="handlePageChange" class="user-pagination" /> </div> <template #footer> <el-button @click="resetUserSelection">清空选择</el-button> <el-button type="primary" @click="confirmUserSelection">确认选择</el-button> </template> </el-dialog> </div> </template> <script setup> import { ref, reactive, computed, onMounted, watch } from 'vue' import { User, Clock, Document, Plus, Edit, Delete, Check, View, Search, Star } from '@element-plus/icons-vue' import { ElMessage, ElMessageBox, ElTooltip } from 'element-plus' import emailApi from '@/api/project/email' import useUserStore from '@/store/modules/user' // 基础状态管理 const activeTab = ref('receivers') const userStore = useUserStore() const currentUserId = userStore.id || 'admin' // 加载状态管理 const receiverLoading = ref(false) const modalUserLoading = ref(false) const saveReceiversLoading = ref(false) const saveConfigLoading = ref(false) const saveTemplateLoading = ref(false) const templateLoading = ref(false) const saveReminderLoading = ref(false) // 收件人管理核心逻辑 const selectedUserIds = ref([]) const userSearchText = ref('') const receivers = ref([]) // 过滤已删除的收件人(修复:使用数字0判断) const filteredReceivers = computed(() => { return receivers.value.filter(item => item.status !== 0) }) // 用户选择弹窗核心逻辑 const userSelectModalVisible = ref(false) const modalSearchQuery = ref('') const currentPage = ref(1) const pageSize = ref(10) const totalUsers = ref(0) const modalUsers = ref([]) const selectedModalUsers = ref([]) const filteredModalUsers = computed(() => { if (!modalSearchQuery.value) return modalUsers.value const query = modalSearchQuery.value.toLowerCase() return modalUsers.value.filter(user => user.userName.toLowerCase().includes(query) || (user.email && user.email.toLowerCase().includes(query)) || (user.deptName && user.deptName.toLowerCase().includes(query)) ) }) // 发送配置核心逻辑 const sendConfig = reactive({ enable: '1', senderName: '', host: '', port: 587, frequency: 'daily', sendTime: '09:00', advanceTime: 10, createBy: currentUserId, updateBy: currentUserId }) const configRules = reactive({ senderName: [{ required: true, message: '请输入发件人显示名称', trigger: 'blur' }], host: [{ required: true, message: '请输入SMTP服务器地址', trigger: 'blur' }], port: [ { required: true, message: '请输入SMTP服务器端口', trigger: 'blur' }, { type: 'number', message: '端口必须为数字', trigger: 'blur' } ], sendTime: [{ required: true, message: '请选择发送时间', trigger: 'change' }], advanceTime: [ { required: true, message: '请输入提前天数', trigger: 'blur' }, { type: 'number', message: '提前天数必须为数字', trigger: 'blur' } ] }) const configFormRef = ref(null) const activeCollapse = ref(['smtp', 'frequency']) // 邮件模板核心逻辑 const activeTemplateType = ref('license') const emailTemplates = reactive({ license: { templateId: '', templateName: '项目授权到期提醒', type: 'license', status: '1', isDefault: '1', subject: '【重要提醒】${projectName} 授权即将到期', content: '尊敬的${userName}:\n\n您负责的项目 "${projectName}" 授权将于 ${expireDate} 到期,请及时处理。\n\n授权信息:\n- 授权类型:${licenseType}\n- 授权范围:${licenseScope}\n- 授权编号:${licenseCode}\n\n到期后,系统将无法正常使用,请提前做好续费或升级准备。\n\n如有疑问,请联系管理员。', createBy: currentUserId, updateBy: currentUserId }, maintenance: { templateId: '', templateName: '项目运维到期提醒', type: 'maintenance', status: '1', isDefault: '1', subject: '【重要提醒】${projectName} 运维服务即将到期', content: '尊敬的${userName}:\n\n您负责的项目 "${projectName}" 运维服务将于 ${expireDate} 到期,请及时处理。\n\n运维服务信息:\n- 服务内容:${maintenanceContent}\n- 服务提供商:${serviceProvider}\n- 服务级别:${serviceLevel}\n\n到期后,将不再提供技术支持和维护服务,请提前做好准备。\n\n如有疑问,请联系管理员。', createBy: currentUserId, updateBy: currentUserId } }) const currentTemplate = computed({ get() { return emailTemplates[activeTemplateType.value] }, set(value) { emailTemplates[activeTemplateType.value] = { ...value, updateBy: currentUserId } } }) const templateRules = reactive({ templateName: [{ required: true, message: '请输入模板名称', trigger: 'blur' }], subject: [{ required: true, message: '请输入邮件标题', trigger: 'blur' }], content: [{ required: true, message: '请输入邮件内容', trigger: 'blur' }] }) const templateFormRef = ref(null) // 提醒规则核心逻辑 const reminderRule = reactive({ enable: '1', triggerType: 'remainingDays', advanceDays: 7, repeatInterval: 'daily', projectTypes: ['license', 'maintenance'], createBy: currentUserId, updateBy: currentUserId }) const reminderRules = reactive({ enable: [{ required: true, message: '请选择是否启用规则', trigger: 'change' }], triggerType: [{ required: true, message: '请选择提醒触发类型', trigger: 'change' }], repeatInterval: [{ required: true, message: '请选择重复提醒间隔', trigger: 'change' }], projectTypes: [{ required: true, message: '请选择适用项目类型', trigger: 'change' }] }) const reminderFormRef = ref(null) // 工具函数 const debounce = (fn, delay) => { let timer = null return function(...args) { if (timer) clearTimeout(timer) timer = setTimeout(() => fn.apply(this, args), delay) } } const getUserNameById = (userId) => { let user = modalUsers.value.find(u => u.userId === userId) if (!user) user = receivers.value.find(r => r.userId === userId) return user ? user.userName : '未知用户' } const getAvailableVariables = () => { const baseVars = { projectName: '项目名称', expireDate: '到期时间', userName: '接收人姓名', projectManager: '项目经理', projectStartDate: '项目开始日期' } if (activeTemplateType.value === 'license') { return { ...baseVars, licenseType: '授权类型', licenseScope: '授权范围', licenseCode: '授权编号', licenseIssuer: '授权颁发方' } } return { ...baseVars, maintenanceContent: '运维内容', serviceProvider: '服务提供商', serviceLevel: '服务级别', maintenanceContact: '运维联系人' } } // 事件处理函数 const openUserSelectModal = async () => { modalSearchQuery.value = '' currentPage.value = 1 selectedModalUsers.value = [] userSelectModalVisible.value = true await fetchModalUsers() const existingIds = receivers.value.map(r => r.userId) modalUsers.value.forEach(user => { if (existingIds.includes(user.userId)) { selectedModalUsers.value.push(user) } }) } const fetchModalUsers = async () => { modalUserLoading.value = true try { const res = await emailApi.getUserList({ keyword: modalSearchQuery.value, pageNum: currentPage.value, pageSize: pageSize.value }) modalUsers.value = res.rows || [] totalUsers.value = res.total || 0 } catch (error) { ElMessage.error('获取用户列表失败:' + (error.msg || error.message)) console.error('用户列表请求错误:', error) } finally { modalUserLoading.value = false } } const removeSelectedUser = (userId) => { selectedUserIds.value = selectedUserIds.value.filter(id => id !== userId) } // 修复:添加选中用户到收件人列表 const handleAddSelectedUsers = async () => { if (selectedUserIds.length === 0) { ElMessage.warning('请先在弹窗中选择用户') return } const newReceivers = selectedModalUsers.value .filter(user => !receivers.value.some(r => r.userId === user.userId)) .map(user => ({ recipientId: '', recipientName: user.userName, email: user.email || '', userId: user.userId, isDefault: 0, // 修复:使用数字0 status: 1, // 修复:使用数字1表示启用 sort: receivers.value.length + 1, createBy: currentUserId, updateBy: currentUserId })) if (newReceivers.length === 0) { ElMessage.info('所选用户已在收件人列表中,无需重复添加') selectedUserIds.value = [] return } saveReceiversLoading.value = true try { const res = await emailApi.saveReceivers(newReceivers) if (res.code === 200) { // 修复:从Page对象的records属性获取数据 receivers.value = [...receivers.value, ...(res.records || newReceivers)] ElMessage.success(`成功添加 ${newReceivers.length} 位用户到收件人列表`) } else { throw new Error(res.msg || '添加失败') } } catch (error) { ElMessage.error('添加用户失败:' + error.message) console.error('添加收件人错误:', error) } finally { saveReceiversLoading.value = false selectedUserIds.value = [] } } // 修复:切换收件人状态 const handleStatusChange = async (row) => { row.statusLoading = true try { // 修复:使用数字类型状态值 const newStatus = row.status === 1 ? 0 : 1 const res = await emailApi.updateReceiver({ ...row, status: newStatus, updateBy: currentUserId }) if (res.code !== 200) throw new Error(res.msg || '状态更新失败') row.status = newStatus ElMessage.success('状态更新成功') } catch (error) { row.status = row.status === 1 ? 0 : 1 ElMessage.error('状态更新失败:' + error.message) console.error('更新收件人状态错误:', error) } finally { row.statusLoading = false } } // 修复:切换收件人默认状态 const handleDefaultChange = async (row) => { // 修复:使用数字类型 const newIsDefault = row.isDefault === 1 ? 0 : 1 if (newIsDefault === 1) { receivers.value.forEach(item => { if (item.recipientId !== row.recipientId) { item.isDefault = 0 } }) } row.defaultDisabled = true try { const res = await emailApi.updateReceiver({ ...row, isDefault: newIsDefault, updateBy: currentUserId }) if (res.code !== 200) throw new Error(res.msg || '默认状态更新失败') row.isDefault = newIsDefault ElMessage.success('默认状态更新成功') } catch (error) { row.isDefault = row.isDefault === 1 ? 0 : 1 ElMessage.error('默认状态更新失败:' + error.message) console.error('更新默认状态错误:', error) } finally { row.defaultDisabled = false } } const handleSortChange = async (row) => { row.sortDisabled = true try { const res = await emailApi.updateReceiver({ ...row, updateBy: currentUserId }) if (res.code !== 200) throw new Error(res.msg || '排序更新失败') ElMessage.success('排序更新成功') } catch (error) { ElMessage.error('排序更新失败:' + error.message) console.error('更新排序错误:', error) } finally { row.sortDisabled = false } } const handleEditReceiver = async (row) => { try { const { value: newEmail } = await ElMessageBox.prompt( `编辑 ${row.recipientName} 的邮箱`, '编辑收件人邮箱', { inputValue: row.email || '', inputPlaceholder: '请输入有效的邮箱地址', inputPattern: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/, inputErrorMessage: '请输入有效的邮箱地址' } ) const res = await emailApi.updateReceiver({ ...row, email: newEmail, updateBy: currentUserId }) if (res.code === 200) { row.email = newEmail ElMessage.success('邮箱编辑成功') } else { throw new Error(res.msg || '编辑失败') } } catch (error) { if (error !== 'cancel') { ElMessage.error('编辑失败:' + (error.message || '操作取消')) } } } const handleDeleteReceiver = async (recipientId) => { try { await ElMessageBox.confirm( '确定要删除该收件人吗?删除后将无法恢复', '删除确认', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' } ) const res = await emailApi.deleteReceiver(recipientId) if (res.code === 200) { receivers.value = receivers.value.filter(r => r.recipientId !== recipientId) ElMessage.success('收件人删除成功') } else { throw new Error(res.msg || '删除失败') } } catch (error) { if (error !== 'cancel') { ElMessage.error('删除失败:' + (error.message || '操作取消')) } } } const handleSaveReceivers = async () => { if (receivers.value.length === 0) { ElMessage.warning('暂无收件人可保存') return } saveReceiversLoading.value = true try { const receiversWithUpdateBy = receivers.value.map(r => ({ ...r, updateBy: currentUserId })) const res = await emailApi.saveReceivers(receiversWithUpdateBy) if (res.code === 200) { ElMessage.success('收件人设置保存成功') } else { throw new Error(res.msg || '保存失败') } } catch (error) { ElMessage.error('保存失败:' + error.message) console.error('保存收件人错误:', error) } finally { saveReceiversLoading.value = false } } // 发送配置事件 const handleSaveConfig = async () => { const form = configFormRef.value if (!form) return try { await form.validate() sendConfig.updateBy = currentUserId saveConfigLoading.value = true const res = await emailApi.saveSendConfig(sendConfig) if (res.code === 200) { ElMessage.success('发送配置保存成功') } else { throw new Error(res.msg || '保存失败') } } catch (error) { if (error.name !== 'ValidateError') { ElMessage.error('保存失败:' + (error.message || '表单验证失败')) } console.error('保存发送配置错误:', error) } finally { saveConfigLoading.value = false } } const handleFrequencyChange = () => { ElMessage.info(`已选择发送频率:${ sendConfig.frequency === 'daily' ? '每天' : sendConfig.frequency === 'weekly' ? '每周' : '每月' }`) } // 邮件模板事件 const handleTemplateTypeChange = async () => { const currentForm = templateFormRef.value if (currentForm) { try { await currentForm.validate() const hasChange = JSON.stringify(currentTemplate.value) !== JSON.stringify(emailTemplates[activeTemplateType.value]) if (hasChange) { await ElMessageBox.confirm( '当前模板有未保存的修改,切换类型将丢失,是否继续?', '切换模板确认', { type: 'warning' } ) } } catch (error) { if (error === 'cancel') { activeTemplateType.value = activeTemplateType.value === 'license' ? 'maintenance' : 'license' } } } templateLoading.value = true try { await fetchEmailTemplates() } catch (error) { ElMessage.error('切换模板失败:' + error.message) } finally { templateLoading.value = false } } const insertVariable = (key) => { currentTemplate.value.content += `\${${key}}` } const handlePreviewTemplate = () => { const basePreviewData = { projectName: '企业资源管理系统V3.0', expireDate: '2024-12-31', userName: '张经理', projectManager: '李工程师', projectStartDate: '2023-01-15' } let previewData, previewTitle if (activeTemplateType.value === 'license') { previewTitle = '项目授权到期提醒预览' previewData = { ...basePreviewData, licenseType: '企业版年度授权', licenseScope: '全模块使用权限', licenseCode: 'LIC-20230115-8762', licenseIssuer: '北京科技有限公司' } } else { previewTitle = '项目运维到期提醒预览' previewData = { ...basePreviewData, maintenanceContent: '系统日常维护、漏洞修复、性能优化、数据备份', serviceProvider: '技术支持部', serviceLevel: '7×24小时响应', maintenanceContact: '王技术员 (13800138000)' } } let previewSubject = currentTemplate.value.subject let previewContent = currentTemplate.value.content Object.keys(previewData).forEach(key => { const reg = new RegExp(`\\\${${key}}`, 'g') previewSubject = previewSubject.replace(reg, previewData[key]) previewContent = previewContent.replace(reg, previewData[key]) }) previewContent = previewContent.replace(/\n/g, '<br>') ElMessageBox.alert( `<h3 style="margin-bottom: 15px; color: #333;">${previewSubject}</h3> <div style="text-align: left; line-height: 1.8; color: #666;">${previewContent}</div>`, previewTitle, { dangerouslyUseHTMLString: true, width: '60%', confirmButtonText: '关闭预览' } ) } const handleSaveTemplate = async () => { const form = templateFormRef.value if (!form) return try { await form.validate() const templateData = { ...currentTemplate.value, type: activeTemplateType.value, updateBy: currentUserId } saveTemplateLoading.value = true const res = await emailApi.saveEmailTemplate(templateData) if (res.code === 200) { if (res.data?.templateId) { emailTemplates[activeTemplateType.value].templateId = res.data.templateId } ElMessage.success('邮件模板保存成功') } else { throw new Error(res.msg || '保存失败') } } catch (error) { if (error.name !== 'ValidateError') { ElMessage.error('保存失败:' + (error.message || '表单验证失败')) } console.error('保存模板错误:', error) } finally { saveTemplateLoading.value = false } } // 提醒规则事件 const handleRuleEnableChange = () => { if (reminderRule.enable === '0') { ElMessage.info('提醒规则已禁用,将不再触发到期提醒') } } const handleSaveReminderRule = async () => { const form = reminderFormRef.value if (!form) return try { await form.validate() reminderRule.updateBy = currentUserId saveReminderLoading.value = true const res = await emailApi.saveReminderRule(reminderRule) if (res.code === 200) { ElMessage.success('提醒规则保存成功') } else { throw new Error(res.msg || '保存失败') } } catch (error) { if (error.name !== 'ValidateError') { ElMessage.error('保存失败:' + (error.message || '表单验证失败')) } console.error('保存提醒规则错误:', error) } finally { saveReminderLoading.value = false } } // 弹窗分页与搜索事件 const handleModalSearch = debounce(async () => { currentPage.value = 1 await fetchModalUsers() }, 300) const handlePageSizeChange = async (size) => { pageSize.value = size currentPage.value = 1 await fetchModalUsers() } const handlePageChange = async (page) => { currentPage.value = page await fetchModalUsers() } const handleUserSelectionChange = (selection) => { selectedModalUsers.value = selection selectedUserIds.value = selection.map(user => user.userId) } const confirmUserSelection = () => { userSelectModalVisible.value = false } const resetUserSelection = () => { selectedModalUsers.value = [] selectedUserIds.value = [] } const handleModalClose = () => { selectedModalUsers.value = [] selectedUserIds.value = [] userSelectModalVisible.value = false } // 生命周期与数据加载 onMounted(() => { Promise.all([ fetchReceivers(), fetchSendConfig(), fetchEmailTemplates(), fetchReminderRule() ]).catch(error => { console.error('初始数据加载失败:', error) }) }) watch(selectedUserIds, (newVal) => { userSearchText.value = newVal.length > 0 ? `已选择 ${newVal.length} 位用户` : '' }) // 修复:从后端获取收件人列表(关键修复) const fetchReceivers = async () => { receiverLoading.value = true try { const res = await emailApi.listReceivers() // 关键修复:从Page对象的records属性获取数据列表 receivers.value = res.records || [] console.log('获取到的收件人数据:', receivers.value) } catch (error) { ElMessage.error('获取收件人列表失败:' + (error.msg || error.message)) console.error('获取收件人错误:', error) } finally { receiverLoading.value = false } } const fetchSendConfig = async () => { try { const res = await emailApi.getSendConfig() if (res.code === 200 && res.data) { Object.assign(sendConfig, res.data) } } catch (error) { ElMessage.error('获取发送配置失败:' + (error.msg || error.message)) console.error('获取发送配置错误:', error) } } const fetchEmailTemplates = async () => { templateLoading.value = true try { const res = await emailApi.getEmailTemplate() const templates = res.rows || [] if (Array.isArray(templates)) { templates.forEach(template => { if (template.type === 'license' || template.type === 'maintenance') { emailTemplates[template.type] = { ...emailTemplates[template.type], ...template, updateBy: currentUserId } } }) } } catch (error) { ElMessage.error('获取邮件模板失败:' + (error.msg || error.message)) console.error('获取模板错误:', error) } finally { templateLoading.value = false } } const fetchReminderRule = async () => { try { const res = await emailApi.getReminderRule() if (res.code === 200 && res.data) { Object.assign(reminderRule, res.data) } } catch (error) { ElMessage.error('获取提醒规则失败:' + (error.msg || error.message)) console.error('获取提醒规则错误:', error) } } </script> <style scoped> .setting-tabs { width: 100%; margin-bottom: 20px; } .setting-card { margin-bottom: 24px; border-radius: 8px; } .card-header { display: flex; align-items: center; gap: 10px; padding: 12px 0; } .header-icon { color: #409eff; font-size: 18px; } .header-desc { margin-left: 8px; font-size: 12px; color: #666; } .card-content { padding: 20px; } .add-receiver-form { margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #f0f0f0; } .user-select-input { width: 420px; cursor: pointer; } .search-icon { cursor: pointer; color: #999; } .selected-users-preview { margin: 16px 0; display: flex; gap: 8px; flex-wrap: wrap; } .selected-tag { background-color: #f5f7fa; color: #666; } .receiver-list-container { margin-top: 16px; } .receiver-table { width: 100%; border-radius: 4px; } .empty-state { padding: 60px 0; text-align: center; } .form-actions { margin-top: 24px; text-align: right; } .config-collapse { margin-top: 16px; } .config-form { margin-top: 8px; } .template-type-group { margin-bottom: 24px; padding: 12px; background-color: #f5f7fa; border-radius: 4px; } .template-variables { margin-top: 12px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; } .variable-tag { cursor: pointer; white-space: nowrap; background-color: #ecf5ff; color: #409eff; } .variable-desc { font-size: 11px; color: #888; margin-left: 5px; } .help-text { margin-left: 8px; font-size: 12px; color: #666; } .preview-btn { margin-right: 12px; } .reminder-form { margin-top: 16px; } .user-modal-content { display: flex; flex-direction: column; gap: 16px; } .modal-search-input { width: 100%; } .user-select-table { width: 100%; } .user-pagination { margin-top: 16px; text-align: right; } .email-text { display: inline-block; width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } @media (max-width: 1200px) { .user-select-input { width: 320px; } } @media (max-width: 768px) { .user-select-input { width: 100%; } .card-content { padding: 12px; } .template-type-group { flex-direction: column; gap: 8px; } .el-row { flex-direction: column; gap: 16px !important; } .el-col { width: 100% !important; } } </style> 使用若依框架编写后端代码
09-04
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值