Commit 4cbf7398e850deb88e8aa40cf90c8e5c3906ad9f
1 parent
2c55d294
邮箱模块:vue3 邮箱账号的管理
Showing
5 changed files
with
259 additions
and
1 deletions
README.md
| ... | ... | @@ -91,6 +91,7 @@ |
| 91 | 91 | | 🚀 | 租户套餐 | 配置租户套餐,自定每个租户的菜单、操作、按钮的权限 | |
| 92 | 92 | | | 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 | |
| 93 | 93 | | 🚀 | 短信管理 | 短信渠道、短息模板、短信日志,对接阿里云、腾讯云等主流短信平台 | |
| 94 | +| 🚀 | 邮件管理 | 邮箱账号、邮件模版、邮件发送日志,支持所有邮件平台 | | |
| 94 | 95 | | 🚀 | 操作日志 | 系统正常操作日志记录和查询,集成 Swagger 生成日志内容 | |
| 95 | 96 | | ⭐️ | 登录日志 | 系统登录日志记录查询,包含登录异常 | |
| 96 | 97 | | 🚀 | 错误码管理 | 系统所有错误码的管理,可在线修改错误提示,无需重启服务 | | ... | ... |
yudao-ui-admin-vue3/src/api/system/mail/account/index.ts
0 → 100644
| 1 | +import request from '@/config/axios' | |
| 2 | + | |
| 3 | +export interface MailAccountVO { | |
| 4 | + id: number | |
| 5 | + mail: string | |
| 6 | + username: string | |
| 7 | + password: string | |
| 8 | + host: string | |
| 9 | + port: number | |
| 10 | + sslEnable: boolean | |
| 11 | +} | |
| 12 | + | |
| 13 | +export interface MailAccountPageReqVO extends PageParam { | |
| 14 | + mail?: string | |
| 15 | + username?: string | |
| 16 | +} | |
| 17 | + | |
| 18 | +// 查询邮箱账号列表 | |
| 19 | +export const getMailAccountPageApi = async (params: MailAccountPageReqVO) => { | |
| 20 | + return await request.get({ url: '/system/mail-account/page', params }) | |
| 21 | +} | |
| 22 | + | |
| 23 | +// 查询邮箱账号详情 | |
| 24 | +export const getMailAccountApi = async (id: number) => { | |
| 25 | + return await request.get({ url: '/system/mail-account/get?id=' + id }) | |
| 26 | +} | |
| 27 | + | |
| 28 | +// 新增邮箱账号 | |
| 29 | +export const createMailAccountApi = async (data: MailAccountVO) => { | |
| 30 | + return await request.post({ url: '/system/mail-account/create', data }) | |
| 31 | +} | |
| 32 | + | |
| 33 | +// 修改邮箱账号 | |
| 34 | +export const updateMailAccountApi = async (data: MailAccountVO) => { | |
| 35 | + return await request.put({ url: '/system/mail-account/update', data }) | |
| 36 | +} | |
| 37 | + | |
| 38 | +// 删除邮箱账号 | |
| 39 | +export const deleteMailAccountApi = async (id: number) => { | |
| 40 | + return await request.delete({ url: '/system/mail-account/delete?id=' + id }) | |
| 41 | +} | ... | ... |
yudao-ui-admin-vue3/src/views/system/mail/account/account.template.data.ts
0 → 100644
| 1 | +import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas' | |
| 2 | + | |
| 3 | +// 表单校验 | |
| 4 | +export const rules = reactive({ | |
| 5 | + mail: [required], | |
| 6 | + username: [required], | |
| 7 | + password: [required], | |
| 8 | + host: [required], | |
| 9 | + port: [required], | |
| 10 | + sslEnable: [required] | |
| 11 | +}) | |
| 12 | + | |
| 13 | +// CrudSchema | |
| 14 | +const crudSchemas = reactive<VxeCrudSchema>({ | |
| 15 | + primaryKey: 'id', // 默认的主键 ID | |
| 16 | + primaryTitle: '编号', | |
| 17 | + primaryType: 'id', | |
| 18 | + action: true, | |
| 19 | + actionWidth: '200', // 3 个按钮默认 200,如有删减对应增减即可 | |
| 20 | + columns: [ | |
| 21 | + { | |
| 22 | + title: '邮箱', | |
| 23 | + field: 'mail', | |
| 24 | + isSearch: true | |
| 25 | + }, | |
| 26 | + { | |
| 27 | + title: '用户名', | |
| 28 | + field: 'username', | |
| 29 | + isSearch: true | |
| 30 | + }, | |
| 31 | + { | |
| 32 | + title: '密码', | |
| 33 | + field: 'password', | |
| 34 | + isTable: false | |
| 35 | + }, | |
| 36 | + { | |
| 37 | + title: 'SMTP 服务器域名', | |
| 38 | + field: 'host' | |
| 39 | + }, | |
| 40 | + { | |
| 41 | + title: 'SMTP 服务器端口', | |
| 42 | + field: 'port', | |
| 43 | + form: { | |
| 44 | + component: 'InputNumber', | |
| 45 | + value: 465 | |
| 46 | + } | |
| 47 | + }, | |
| 48 | + { | |
| 49 | + title: '是否开启 SSL', | |
| 50 | + field: 'sslEnable', | |
| 51 | + dictType: DICT_TYPE.INFRA_BOOLEAN_STRING, | |
| 52 | + dictClass: 'boolean' | |
| 53 | + }, | |
| 54 | + { | |
| 55 | + title: '创建时间', | |
| 56 | + field: 'createTime', | |
| 57 | + isForm: false, | |
| 58 | + formatter: 'formatDate', | |
| 59 | + table: { | |
| 60 | + width: 180 | |
| 61 | + } | |
| 62 | + } | |
| 63 | + ] | |
| 64 | +}) | |
| 65 | +export const { allSchemas } = useVxeCrudSchemas(crudSchemas) | ... | ... |
yudao-ui-admin-vue3/src/views/system/mail/account/index.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <ContentWrap> | |
| 3 | + <!-- 列表 --> | |
| 4 | + <XTable @register="registerTable"> | |
| 5 | + <template #toolbar_buttons> | |
| 6 | + <!-- 操作:新增 --> | |
| 7 | + <XButton | |
| 8 | + type="primary" | |
| 9 | + preIcon="ep:zoom-in" | |
| 10 | + :title="t('action.add')" | |
| 11 | + v-hasPermi="['system:mail-account:create']" | |
| 12 | + @click="handleCreate()" | |
| 13 | + /> | |
| 14 | + </template> | |
| 15 | + <template #actionbtns_default="{ row }"> | |
| 16 | + <!-- 操作:修改 --> | |
| 17 | + <XTextButton | |
| 18 | + preIcon="ep:edit" | |
| 19 | + :title="t('action.edit')" | |
| 20 | + v-hasPermi="['system:mail-account:update']" | |
| 21 | + @click="handleUpdate(row.id)" | |
| 22 | + /> | |
| 23 | + <!-- 操作:详情 --> | |
| 24 | + <XTextButton | |
| 25 | + preIcon="ep:view" | |
| 26 | + :title="t('action.detail')" | |
| 27 | + v-hasPermi="['system:mail-account:query']" | |
| 28 | + @click="handleDetail(row.id)" | |
| 29 | + /> | |
| 30 | + <!-- 操作:删除 --> | |
| 31 | + <XTextButton | |
| 32 | + preIcon="ep:delete" | |
| 33 | + :title="t('action.del')" | |
| 34 | + v-hasPermi="['system:mail-account:delete']" | |
| 35 | + @click="deleteData(row.id)" | |
| 36 | + /> | |
| 37 | + </template> | |
| 38 | + </XTable> | |
| 39 | + </ContentWrap> | |
| 40 | + <!-- 弹窗 --> | |
| 41 | + <XModal id="mailAccountModel" :loading="modelLoading" v-model="modelVisible" :title="modelTitle"> | |
| 42 | + <!-- 表单:添加/修改 --> | |
| 43 | + <Form | |
| 44 | + ref="formRef" | |
| 45 | + v-if="['create', 'update'].includes(actionType)" | |
| 46 | + :schema="allSchemas.formSchema" | |
| 47 | + :rules="rules" | |
| 48 | + /> | |
| 49 | + <!-- 表单:详情 --> | |
| 50 | + <Descriptions | |
| 51 | + v-if="actionType === 'detail'" | |
| 52 | + :schema="allSchemas.detailSchema" | |
| 53 | + :data="detailData" | |
| 54 | + /> | |
| 55 | + <template #footer> | |
| 56 | + <!-- 按钮:保存 --> | |
| 57 | + <XButton | |
| 58 | + v-if="['create', 'update'].includes(actionType)" | |
| 59 | + type="primary" | |
| 60 | + :title="t('action.save')" | |
| 61 | + :loading="actionLoading" | |
| 62 | + @click="submitForm()" | |
| 63 | + /> | |
| 64 | + <!-- 按钮:关闭 --> | |
| 65 | + <XButton :loading="actionLoading" :title="t('dialog.close')" @click="modelVisible = false" /> | |
| 66 | + </template> | |
| 67 | + </XModal> | |
| 68 | +</template> | |
| 69 | +<script setup lang="ts" name="MailAccount"> | |
| 70 | +import { FormExpose } from '@/components/Form' | |
| 71 | +// 业务相关的 import | |
| 72 | +import { rules, allSchemas } from './account.template.data' | |
| 73 | +import * as MailAccountApi from '@/api/system/mail/account' | |
| 74 | + | |
| 75 | +const { t } = useI18n() // 国际化 | |
| 76 | +const message = useMessage() // 消息弹窗 | |
| 77 | + | |
| 78 | +// 列表相关的变量 | |
| 79 | +const [registerTable, { reload, deleteData }] = useXTable({ | |
| 80 | + allSchemas: allSchemas, | |
| 81 | + getListApi: MailAccountApi.getMailAccountPageApi, | |
| 82 | + deleteApi: MailAccountApi.deleteMailAccountApi | |
| 83 | +}) | |
| 84 | + | |
| 85 | +// 弹窗相关的变量 | |
| 86 | +const modelVisible = ref(false) // 是否显示弹出层 | |
| 87 | +const modelTitle = ref('edit') // 弹出层标题 | |
| 88 | +const modelLoading = ref(false) // 弹出层loading | |
| 89 | +const actionType = ref('') // 操作按钮的类型 | |
| 90 | +const actionLoading = ref(false) // 按钮 Loading | |
| 91 | +const formRef = ref<FormExpose>() // 表单 Ref | |
| 92 | +const detailData = ref() // 详情 Ref | |
| 93 | + | |
| 94 | +// 设置标题 | |
| 95 | +const setDialogTile = (type: string) => { | |
| 96 | + modelLoading.value = true | |
| 97 | + modelTitle.value = t('action.' + type) | |
| 98 | + actionType.value = type | |
| 99 | + modelVisible.value = true | |
| 100 | +} | |
| 101 | + | |
| 102 | +// 新增操作 | |
| 103 | +const handleCreate = () => { | |
| 104 | + setDialogTile('create') | |
| 105 | + modelLoading.value = false | |
| 106 | +} | |
| 107 | + | |
| 108 | +// 修改操作 | |
| 109 | +const handleUpdate = async (rowId: number) => { | |
| 110 | + setDialogTile('update') | |
| 111 | + // 设置数据 | |
| 112 | + const res = await MailAccountApi.getMailAccountApi(rowId) | |
| 113 | + unref(formRef)?.setValues(res) | |
| 114 | + modelLoading.value = false | |
| 115 | +} | |
| 116 | + | |
| 117 | +// 详情操作 | |
| 118 | +const handleDetail = async (rowId: number) => { | |
| 119 | + setDialogTile('detail') | |
| 120 | + const res = await MailAccountApi.getMailAccountApi(rowId) | |
| 121 | + detailData.value = res | |
| 122 | + modelLoading.value = false | |
| 123 | +} | |
| 124 | + | |
| 125 | +// 提交按钮 | |
| 126 | +const submitForm = async () => { | |
| 127 | + const elForm = unref(formRef)?.getElFormRef() | |
| 128 | + if (!elForm) return | |
| 129 | + elForm.validate(async (valid) => { | |
| 130 | + if (valid) { | |
| 131 | + actionLoading.value = true | |
| 132 | + // 提交请求 | |
| 133 | + try { | |
| 134 | + const data = unref(formRef)?.formModel as MailAccountApi.MailAccountVO | |
| 135 | + if (actionType.value === 'create') { | |
| 136 | + await MailAccountApi.createMailAccountApi(data) | |
| 137 | + message.success(t('common.createSuccess')) | |
| 138 | + } else { | |
| 139 | + await MailAccountApi.updateMailAccountApi(data) | |
| 140 | + message.success(t('common.updateSuccess')) | |
| 141 | + } | |
| 142 | + modelVisible.value = false | |
| 143 | + } finally { | |
| 144 | + actionLoading.value = false | |
| 145 | + // 刷新列表 | |
| 146 | + await reload() | |
| 147 | + } | |
| 148 | + } | |
| 149 | + }) | |
| 150 | +} | |
| 151 | +</script> | ... | ... |
yudao-ui-admin/src/views/system/mail/account/index.vue
| ... | ... | @@ -27,7 +27,7 @@ |
| 27 | 27 | |
| 28 | 28 | <!-- 列表 --> |
| 29 | 29 | <el-table v-loading="loading" :data="list"> |
| 30 | - <el-table-column label="主键" align="center" prop="id" /> | |
| 30 | + <el-table-column label="编号" align="center" prop="id" /> | |
| 31 | 31 | <el-table-column label="邮箱" align="center" prop="mail" /> |
| 32 | 32 | <el-table-column label="用户名" align="center" prop="username" /> |
| 33 | 33 | <el-table-column label="SMTP 服务器域名" align="center" prop="host" /> | ... | ... |