Commit 09e61f7ef342db5c0a85c977338ab711524bc673

Authored by xingyu
1 parent 12ac097b

refactor: sms

yudao-ui-admin-vue3/src/api/system/sms/smsChannel/index.ts
1 import request from '@/config/axios' 1 import request from '@/config/axios'
2 -import type { SmsChannelVO } from './types' 2 +export type SmsChannelVO = {
  3 + id: number
  4 + status: number
  5 + signature: string
  6 + remark: string
  7 + apiKey: string
  8 + apiSecret: string
  9 + callbackUrl: string
  10 + createTime: string
  11 +}
  12 +
  13 +export interface SmsChannelPageReqVO extends PageParam {
  14 + signature?: string
  15 + code?: string
  16 + status?: number
  17 +}
3 18
4 // 查询短信渠道列表 19 // 查询短信渠道列表
5 -export const getSmsChannelPageApi = (params) => { 20 +export const getSmsChannelPageApi = (params: SmsChannelPageReqVO) => {
6 return request.get({ url: '/system/sms-channel/page', params }) 21 return request.get({ url: '/system/sms-channel/page', params })
7 } 22 }
8 23
yudao-ui-admin-vue3/src/api/system/sms/smsChannel/types.ts deleted
1 -export type SmsChannelVO = {  
2 - id: number  
3 - status: number  
4 - signature: string  
5 - remark: string  
6 - apiKey: string  
7 - apiSecret: string  
8 - callbackUrl: string  
9 - createTime: string  
10 -}  
yudao-ui-admin-vue3/src/api/system/sms/smsLog/index.ts
1 import request from '@/config/axios' 1 import request from '@/config/axios'
  2 +export type SmsLogVO = {
  3 + id: number
  4 + idchannelId: number
  5 + templateId: number
  6 + mobile: string
  7 + userId: number
  8 + userType: number
  9 + sendStatus: number
  10 + receiveStatus: number
  11 + templateType: number
  12 + templateContent: string
  13 + templateParams: Map<string, object>
  14 + apiTemplateId: string
  15 + sendTime: string
  16 + createTime: string
  17 +}
  18 +
  19 +export interface SmsLogPageReqVO extends PageParam {
  20 + signature?: string
  21 + code?: string
  22 + status?: number
  23 +}
  24 +export interface SmsLogExportReqVO {
  25 + code?: string
  26 + name?: string
  27 + status?: number
  28 +}
2 29
3 // 查询短信日志列表 30 // 查询短信日志列表
4 -export const getSmsLogPageApi = (params) => { 31 +export const getSmsLogPageApi = (params: SmsLogPageReqVO) => {
5 return request.get({ url: '/system/sms-log/page', params }) 32 return request.get({ url: '/system/sms-log/page', params })
6 } 33 }
7 34
8 // 导出短信日志 35 // 导出短信日志
9 -export const exportSmsLogApi = (params) => { 36 +export const exportSmsLogApi = (params: SmsLogExportReqVO) => {
10 return request.download({ url: '/system/sms-log/export', params }) 37 return request.download({ url: '/system/sms-log/export', params })
11 } 38 }
yudao-ui-admin-vue3/src/api/system/sms/smsLog/types.ts deleted
1 -export type SmsLogVO = {  
2 - id: number  
3 - idchannelId: number  
4 - templateId: number  
5 - mobile: string  
6 - sendStatus: number  
7 - receiveStatus: number  
8 - createTime: string  
9 -}  
yudao-ui-admin-vue3/src/api/system/sms/smsTemplate/index.ts
1 import request from '@/config/axios' 1 import request from '@/config/axios'
2 -import type { SmsTemplateVO } from './types' 2 +export type SmsTemplateVO = {
  3 + id: number
  4 + type: number
  5 + status: number
  6 + code: string
  7 + name: string
  8 + content: string
  9 + remark: string
  10 + apiTemplateId: string
  11 + channelId: number
  12 + channelCode: string
  13 + createTime: string
  14 +}
  15 +
  16 +export type SmsSendVO = {
  17 + mobile: string
  18 + templateCode: string
  19 + templateParams: string
  20 +}
3 21
4 // 查询短信模板列表 22 // 查询短信模板列表
5 export const getSmsTemplatePageApi = (params) => { 23 export const getSmsTemplatePageApi = (params) => {
yudao-ui-admin-vue3/src/api/system/sms/smsTemplate/types.ts deleted
1 -export type SmsTemplateVO = {  
2 - id: number  
3 - type: number  
4 - status: number  
5 - code: string  
6 - name: string  
7 - content: string  
8 - remark: string  
9 - apiTemplateId: string  
10 - channelId: number  
11 - channelCode: string  
12 - createTime: string  
13 -}  
14 -  
15 -export type SmsSendVO = {  
16 - mobile: string  
17 - templateCode: string  
18 - templateParams: string  
19 -}  
yudao-ui-admin-vue3/src/views/system/sms/smsChannel/index.vue
1 <template> 1 <template>
2 - <!-- 搜索工作区 -->  
3 <ContentWrap> 2 <ContentWrap>
4 - <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />  
5 - </ContentWrap>  
6 - <ContentWrap>  
7 - <!-- 操作工具栏 -->  
8 - <div class="mb-10px">  
9 - <XButton  
10 - type="primary"  
11 - preIcon="ep:zoom-in"  
12 - :title="t('action.add')"  
13 - v-hasPermi="['system:sms-channel:create']"  
14 - @click="handleCreate()"  
15 - />  
16 - </div>  
17 <!-- 列表 --> 3 <!-- 列表 -->
18 - <Table  
19 - :columns="allSchemas.tableColumns"  
20 - :selection="false"  
21 - :data="tableObject.tableList"  
22 - :loading="tableObject.loading"  
23 - :pagination="{  
24 - total: tableObject.total  
25 - }"  
26 - v-model:pageSize="tableObject.pageSize"  
27 - v-model:currentPage="tableObject.currentPage"  
28 - @register="register"  
29 - >  
30 - <template #code="{ row }">  
31 - <DictTag :type="DICT_TYPE.SYSTEM_SMS_CHANNEL_CODE" :value="row.code" />  
32 - </template>  
33 - <template #status="{ row }">  
34 - <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />  
35 - </template>  
36 - <template #createTime="{ row }">  
37 - <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span> 4 + <vxe-grid ref="xGrid" v-bind="gridOptions" class="xtable-scrollbar">
  5 + <!-- 操作:新增 -->
  6 + <template #toolbar_buttons>
  7 + <XButton
  8 + type="primary"
  9 + preIcon="ep:zoom-in"
  10 + :title="t('action.add')"
  11 + v-hasPermi="['system:sms-channel:create']"
  12 + @click="handleCreate()"
  13 + />
38 </template> 14 </template>
39 - <template #action="{ row }"> 15 + <template #actionbtns_default="{ row }">
40 <!-- 操作:修改 --> 16 <!-- 操作:修改 -->
41 <XTextButton 17 <XTextButton
42 preIcon="ep:edit" 18 preIcon="ep:edit"
@@ -49,20 +25,20 @@ @@ -49,20 +25,20 @@
49 preIcon="ep:view" 25 preIcon="ep:view"
50 :title="t('action.detail')" 26 :title="t('action.detail')"
51 v-hasPermi="['system:sms-channel:update']" 27 v-hasPermi="['system:sms-channel:update']"
52 - @click="handleDetail(row)" 28 + @click="handleDetail(row.id)"
53 /> 29 />
54 <!-- 操作:删除 --> 30 <!-- 操作:删除 -->
55 <XTextButton 31 <XTextButton
56 preIcon="ep:delete" 32 preIcon="ep:delete"
57 :title="t('action.del')" 33 :title="t('action.del')"
58 v-hasPermi="['system:sms-channel:delete']" 34 v-hasPermi="['system:sms-channel:delete']"
59 - @click="delList(row.id, false)" 35 + @click="handleDelete(row.id)"
60 /> 36 />
61 </template> 37 </template>
62 - </Table> 38 + </vxe-grid>
63 </ContentWrap> 39 </ContentWrap>
64 40
65 - <XModal v-model="dialogVisible" :title="dialogTitle"> 41 + <XModal id="smsChannel" v-model="dialogVisible" :title="dialogTitle">
66 <!-- 对话框(添加 / 修改) --> 42 <!-- 对话框(添加 / 修改) -->
67 <Form 43 <Form
68 v-if="['create', 'update'].includes(actionType)" 44 v-if="['create', 'update'].includes(actionType)"
@@ -74,7 +50,7 @@ @@ -74,7 +50,7 @@
74 <Descriptions 50 <Descriptions
75 v-if="actionType === 'detail'" 51 v-if="actionType === 'detail'"
76 :schema="allSchemas.detailSchema" 52 :schema="allSchemas.detailSchema"
77 - :data="detailRef" 53 + :data="detailData"
78 /> 54 />
79 <!-- 操作按钮 --> 55 <!-- 操作按钮 -->
80 <template #footer> 56 <template #footer>
@@ -83,41 +59,45 @@ @@ -83,41 +59,45 @@
83 v-if="['create', 'update'].includes(actionType)" 59 v-if="['create', 'update'].includes(actionType)"
84 type="primary" 60 type="primary"
85 :title="t('action.save')" 61 :title="t('action.save')"
86 - :loading="loading" 62 + :loading="actionLoading"
87 @click="submitForm()" 63 @click="submitForm()"
88 /> 64 />
89 <!-- 按钮:关闭 --> 65 <!-- 按钮:关闭 -->
90 - <XButton :loading="loading" :title="t('dialog.close')" @click="dialogVisible = false" /> 66 + <XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" />
91 </template> 67 </template>
92 </XModal> 68 </XModal>
93 </template> 69 </template>
94 70
95 <script setup lang="ts"> 71 <script setup lang="ts">
  72 +// 全局相关的 import
96 import { ref, unref } from 'vue' 73 import { ref, unref } from 'vue'
97 -import dayjs from 'dayjs'  
98 -import { ElMessage } from 'element-plus'  
99 -import { DICT_TYPE } from '@/utils/dict'  
100 -import { useTable } from '@/hooks/web/useTable'  
101 import { useI18n } from '@/hooks/web/useI18n' 74 import { useI18n } from '@/hooks/web/useI18n'
  75 +import { useMessage } from '@/hooks/web/useMessage'
  76 +import { useVxeGrid } from '@/hooks/web/useVxeGrid'
  77 +import { VxeGridInstance } from 'vxe-table'
102 import { FormExpose } from '@/components/Form' 78 import { FormExpose } from '@/components/Form'
103 -import type { SmsChannelVO } from '@/api/system/sms/smsChannel/types'  
104 -import { rules, allSchemas } from './sms.channel.data' 79 +// 业务相关的 import
105 import * as SmsChannelApi from '@/api/system/sms/smsChannel' 80 import * as SmsChannelApi from '@/api/system/sms/smsChannel'
  81 +import { rules, allSchemas } from './sms.channel.data'
  82 +
106 const { t } = useI18n() // 国际化 83 const { t } = useI18n() // 国际化
  84 +const message = useMessage() // 消息弹窗
107 85
108 -// ========== 列表相关 ==========  
109 -const { register, tableObject, methods } = useTable<SmsChannelVO>({ 86 +// 列表相关的变量
  87 +const xGrid = ref<VxeGridInstance>() // 列表 Grid Ref
  88 +const { gridOptions, reloadList, delList } = useVxeGrid<SmsChannelApi.SmsChannelVO>({
  89 + allSchemas: allSchemas,
110 getListApi: SmsChannelApi.getSmsChannelPageApi, 90 getListApi: SmsChannelApi.getSmsChannelPageApi,
111 delListApi: SmsChannelApi.deleteSmsChannelApi 91 delListApi: SmsChannelApi.deleteSmsChannelApi
112 }) 92 })
113 -const { getList, setSearchParams, delList } = methods  
114 93
115 -// ========== CRUD 相关 ==========  
116 -const loading = ref(false) // 遮罩层  
117 -const actionType = ref('') // 操作按钮的类型 94 +// 弹窗相关的变量
118 const dialogVisible = ref(false) // 是否显示弹出层 95 const dialogVisible = ref(false) // 是否显示弹出层
119 const dialogTitle = ref('edit') // 弹出层标题 96 const dialogTitle = ref('edit') // 弹出层标题
  97 +const actionType = ref('') // 操作按钮的类型
  98 +const actionLoading = ref(false) // 按钮 Loading
120 const formRef = ref<FormExpose>() // 表单 Ref 99 const formRef = ref<FormExpose>() // 表单 Ref
  100 +const detailData = ref() // 详情 Ref
121 101
122 // 设置标题 102 // 设置标题
123 const setDialogTile = (type: string) => { 103 const setDialogTile = (type: string) => {
@@ -139,43 +119,42 @@ const handleUpdate = async (rowId: number) =&gt; { @@ -139,43 +119,42 @@ const handleUpdate = async (rowId: number) =&gt; {
139 unref(formRef)?.setValues(res) 119 unref(formRef)?.setValues(res)
140 } 120 }
141 121
  122 +// 详情操作
  123 +const handleDetail = async (rowId: number) => {
  124 + setDialogTile('detail')
  125 + const res = await SmsChannelApi.getSmsChannelApi(rowId)
  126 + detailData.value = res
  127 +}
  128 +
  129 +// 删除操作
  130 +const handleDelete = async (rowId: number) => {
  131 + await delList(xGrid, rowId)
  132 +}
  133 +
142 // 提交按钮 134 // 提交按钮
143 const submitForm = async () => { 135 const submitForm = async () => {
144 const elForm = unref(formRef)?.getElFormRef() 136 const elForm = unref(formRef)?.getElFormRef()
145 if (!elForm) return 137 if (!elForm) return
146 elForm.validate(async (valid) => { 138 elForm.validate(async (valid) => {
147 if (valid) { 139 if (valid) {
148 - loading.value = true 140 + actionLoading.value = true
149 // 提交请求 141 // 提交请求
150 try { 142 try {
151 - const data = unref(formRef)?.formModel as SmsChannelVO 143 + const data = unref(formRef)?.formModel as SmsChannelApi.SmsChannelVO
152 if (actionType.value === 'create') { 144 if (actionType.value === 'create') {
153 await SmsChannelApi.createSmsChannelApi(data) 145 await SmsChannelApi.createSmsChannelApi(data)
154 - ElMessage.success(t('common.createSuccess')) 146 + message.success(t('common.createSuccess'))
155 } else { 147 } else {
156 await SmsChannelApi.updateSmsChannelApi(data) 148 await SmsChannelApi.updateSmsChannelApi(data)
157 - ElMessage.success(t('common.updateSuccess')) 149 + message.success(t('common.updateSuccess'))
158 } 150 }
159 - // 操作成功,重新加载列表  
160 dialogVisible.value = false 151 dialogVisible.value = false
161 - await getList()  
162 } finally { 152 } finally {
163 - loading.value = false 153 + actionLoading.value = false
  154 + // 刷新列表
  155 + reloadList(xGrid)
164 } 156 }
165 } 157 }
166 }) 158 })
167 } 159 }
168 -  
169 -// ========== 详情相关 ==========  
170 -const detailRef = ref() // 详情 Ref  
171 -  
172 -// 详情操作  
173 -const handleDetail = async (row: SmsChannelVO) => {  
174 - // 设置数据  
175 - detailRef.value = row  
176 - setDialogTile('detail')  
177 -}  
178 -  
179 -// ========== 初始化 ==========  
180 -getList()  
181 </script> 160 </script>
yudao-ui-admin-vue3/src/views/system/sms/smsChannel/sms.channel.data.ts
1 import { reactive } from 'vue' 1 import { reactive } from 'vue'
2 import { useI18n } from '@/hooks/web/useI18n' 2 import { useI18n } from '@/hooks/web/useI18n'
3 import { required } from '@/utils/formRules' 3 import { required } from '@/utils/formRules'
4 -import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas'  
5 import { DICT_TYPE } from '@/utils/dict' 4 import { DICT_TYPE } from '@/utils/dict'
  5 +import { VxeCrudSchema, useVxeCrudSchemas } from '@/hooks/web/useVxeCrudSchemas'
6 const { t } = useI18n() // 国际化 6 const { t } = useI18n() // 国际化
7 7
8 // 表单校验 8 // 表单校验
@@ -14,79 +14,46 @@ export const rules = reactive({ @@ -14,79 +14,46 @@ export const rules = reactive({
14 }) 14 })
15 15
16 // CrudSchema 16 // CrudSchema
17 -const crudSchemas = reactive<CrudSchema[]>([  
18 - {  
19 - label: t('common.index'),  
20 - field: 'id',  
21 - type: 'index',  
22 - form: {  
23 - show: false 17 +const crudSchemas = reactive<VxeCrudSchema>({
  18 + primaryKey: 'id',
  19 + primaryType: 'seq',
  20 + action: true,
  21 + columns: [
  22 + {
  23 + title: '短信签名',
  24 + field: 'signature',
  25 + isSearch: true
24 }, 26 },
25 - detail: {  
26 - show: false  
27 - }  
28 - },  
29 - {  
30 - label: '短信签名',  
31 - field: 'signature',  
32 - search: {  
33 - show: true  
34 - }  
35 - },  
36 - {  
37 - label: '渠道编码',  
38 - field: 'code',  
39 - dictType: DICT_TYPE.SYSTEM_SMS_CHANNEL_CODE,  
40 - search: {  
41 - show: true  
42 - }  
43 - },  
44 - {  
45 - label: t('common.status'),  
46 - field: 'status',  
47 - dictType: DICT_TYPE.COMMON_STATUS,  
48 - search: {  
49 - show: true  
50 - }  
51 - },  
52 - {  
53 - label: '短信 API 的账号',  
54 - field: 'apiKey'  
55 - },  
56 - {  
57 - label: '短信 API 的密钥',  
58 - field: 'apiSecret'  
59 - },  
60 - {  
61 - label: '短信发送回调 URL',  
62 - field: 'callbackUrl'  
63 - },  
64 - {  
65 - label: t('common.createTime'),  
66 - field: 'createTime',  
67 - form: {  
68 - show: false 27 + {
  28 + title: '渠道编码',
  29 + field: 'code',
  30 + dictType: DICT_TYPE.SYSTEM_SMS_CHANNEL_CODE,
  31 + isSearch: true
69 }, 32 },
70 - search: {  
71 - show: true,  
72 - component: 'DatePicker',  
73 - componentProps: {  
74 - type: 'daterange',  
75 - valueFormat: 'YYYY-MM-DD HH:mm:ss',  
76 - defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]  
77 - }  
78 - }  
79 - },  
80 - {  
81 - label: t('table.action'),  
82 - field: 'action',  
83 - width: '240px',  
84 - form: {  
85 - show: false 33 + {
  34 + title: t('common.status'),
  35 + field: 'status',
  36 + dictType: DICT_TYPE.COMMON_STATUS,
  37 + isSearch: true
86 }, 38 },
87 - detail: {  
88 - show: false 39 + {
  40 + title: '短信 API 的账号',
  41 + field: 'apiKey'
  42 + },
  43 + {
  44 + title: '短信 API 的密钥',
  45 + field: 'apiSecret'
  46 + },
  47 + {
  48 + title: '短信发送回调 URL',
  49 + field: 'callbackUrl'
  50 + },
  51 + {
  52 + title: t('common.createTime'),
  53 + field: 'createTime',
  54 + formatter: 'formatDate',
  55 + isForm: false
89 } 56 }
90 - }  
91 -])  
92 -export const { allSchemas } = useCrudSchemas(crudSchemas) 57 + ]
  58 +})
  59 +export const { allSchemas } = useVxeCrudSchemas(crudSchemas)
yudao-ui-admin-vue3/src/views/system/sms/smsLog/index.vue
1 <template> 1 <template>
2 - <!-- 搜索工作区 -->  
3 - <ContentWrap>  
4 - <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />  
5 - </ContentWrap>  
6 <ContentWrap> 2 <ContentWrap>
7 <!-- 列表 --> 3 <!-- 列表 -->
8 - <Table  
9 - :columns="allSchemas.tableColumns"  
10 - :selection="false"  
11 - :data="tableObject.tableList"  
12 - :loading="tableObject.loading"  
13 - :pagination="{  
14 - total: tableObject.total  
15 - }"  
16 - v-model:pageSize="tableObject.pageSize"  
17 - v-model:currentPage="tableObject.currentPage"  
18 - @register="register"  
19 - >  
20 - <template #code="{ row }">  
21 - <DictTag :type="DICT_TYPE.SYSTEM_SMS_CHANNEL_CODE" :value="row.code" />  
22 - </template>  
23 - <template #status="{ row }">  
24 - <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />  
25 - </template>  
26 - <template #createTime="{ row }">  
27 - <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>  
28 - </template>  
29 - <template #receiveTime="{ row }">  
30 - <span>{{ dayjs(row.receiveTime).format('YYYY-MM-DD HH:mm:ss') }}</span> 4 + <vxe-grid ref="xGrid" v-bind="gridOptions" class="xtable-scrollbar">
  5 + <!-- 操作:导出 -->
  6 + <template #toolbar_buttons>
  7 + <XButton
  8 + type="warning"
  9 + preIcon="ep:download"
  10 + :title="t('action.export')"
  11 + @click="handleExport()"
  12 + />
31 </template> 13 </template>
32 - <template #action="{ row }"> 14 + <template #actionbtns_default="{ row }">
33 <XTextButton preIcon="ep:view" :title="t('action.detail')" @click="handleDetail(row)" /> 15 <XTextButton preIcon="ep:view" :title="t('action.detail')" @click="handleDetail(row)" />
34 </template> 16 </template>
35 - </Table> 17 + </vxe-grid>
36 </ContentWrap> 18 </ContentWrap>
37 19
38 - <XModal v-model="dialogVisible" :title="dialogTitle"> 20 + <XModal id="smsLog" v-model="dialogVisible" :title="dialogTitle">
39 <!-- 对话框(详情) --> 21 <!-- 对话框(详情) -->
40 <Descriptions 22 <Descriptions
41 v-if="actionType === 'detail'" 23 v-if="actionType === 'detail'"
@@ -50,33 +32,37 @@ @@ -50,33 +32,37 @@
50 </template> 32 </template>
51 33
52 <script setup lang="ts"> 34 <script setup lang="ts">
  35 +// 全局相关的 import
53 import { ref } from 'vue' 36 import { ref } from 'vue'
54 -import dayjs from 'dayjs'  
55 -import { DICT_TYPE } from '@/utils/dict'  
56 -import { useTable } from '@/hooks/web/useTable'  
57 import { useI18n } from '@/hooks/web/useI18n' 37 import { useI18n } from '@/hooks/web/useI18n'
58 -import type { SmsLogVO } from '@/api/system/sms/smsLog/types' 38 +import { useVxeGrid } from '@/hooks/web/useVxeGrid'
  39 +import { VxeGridInstance } from 'vxe-table'
59 import { allSchemas } from './sms.log.data' 40 import { allSchemas } from './sms.log.data'
60 import * as SmsLoglApi from '@/api/system/sms/smsLog' 41 import * as SmsLoglApi from '@/api/system/sms/smsLog'
61 const { t } = useI18n() // 国际化 42 const { t } = useI18n() // 国际化
62 43
63 -// ========== 列表相关 ==========  
64 -const { register, tableObject, methods } = useTable<SmsLogVO>({  
65 - getListApi: SmsLoglApi.getSmsLogPageApi 44 +// 列表相关的变量
  45 +const xGrid = ref<VxeGridInstance>() // 列表 Grid Ref
  46 +const { gridOptions, exportList } = useVxeGrid<SmsLoglApi.SmsLogVO>({
  47 + allSchemas: allSchemas,
  48 + getListApi: SmsLoglApi.getSmsLogPageApi,
  49 + exportListApi: SmsLoglApi.exportSmsLogApi
66 }) 50 })
67 -const { getList, setSearchParams } = methods  
68 51
69 -// ========== CRUD 相关 ==========  
70 -const actionType = ref('') // 操作按钮的类型 52 +// 弹窗相关的变量
71 const dialogVisible = ref(false) // 是否显示弹出层 53 const dialogVisible = ref(false) // 是否显示弹出层
72 -const dialogTitle = ref(t('action.detail')) // 弹出层标题 54 +const dialogTitle = ref('edit') // 弹出层标题
  55 +const actionType = ref('') // 操作按钮的类型
73 // ========== 详情相关 ========== 56 // ========== 详情相关 ==========
74 const detailRef = ref() // 详情 Ref 57 const detailRef = ref() // 详情 Ref
75 -const handleDetail = (row: SmsLogVO) => { 58 +const handleDetail = (row: SmsLoglApi.SmsLogVO) => {
76 // 设置数据 59 // 设置数据
77 detailRef.value = row 60 detailRef.value = row
78 dialogVisible.value = true 61 dialogVisible.value = true
79 } 62 }
80 -// ========== 初始化 ==========  
81 -getList() 63 +
  64 +// 导出操作
  65 +const handleExport = async () => {
  66 + await exportList(xGrid, '短信日志.xls')
  67 +}
82 </script> 68 </script>
yudao-ui-admin-vue3/src/views/system/sms/smsLog/sms.log.data.ts
1 import { reactive } from 'vue' 1 import { reactive } from 'vue'
2 import { useI18n } from '@/hooks/web/useI18n' 2 import { useI18n } from '@/hooks/web/useI18n'
3 -import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas'  
4 import { DICT_TYPE } from '@/utils/dict' 3 import { DICT_TYPE } from '@/utils/dict'
  4 +import { VxeCrudSchema, useVxeCrudSchemas } from '@/hooks/web/useVxeCrudSchemas'
5 const { t } = useI18n() // 国际化 5 const { t } = useI18n() // 国际化
6 6
7 // CrudSchema 7 // CrudSchema
8 -const crudSchemas = reactive<CrudSchema[]>([  
9 - {  
10 - label: t('common.index'),  
11 - field: 'id',  
12 - type: 'index',  
13 - form: {  
14 - show: false 8 +const crudSchemas = reactive<VxeCrudSchema>({
  9 + primaryKey: 'id',
  10 + primaryType: 'seq',
  11 + action: true,
  12 + columns: [
  13 + {
  14 + title: '手机号',
  15 + field: 'mobile',
  16 + isSearch: true
15 }, 17 },
16 - detail: {  
17 - show: false  
18 - }  
19 - },  
20 - {  
21 - label: '手机号',  
22 - field: 'mobile',  
23 - search: {  
24 - show: true  
25 - }  
26 - },  
27 - {  
28 - label: '短信内容',  
29 - field: 'templateContent'  
30 - },  
31 - {  
32 - label: '短信渠道',  
33 - field: 'channelId',  
34 - dictType: DICT_TYPE.SYSTEM_SMS_CHANNEL_CODE,  
35 - search: {  
36 - show: true  
37 - }  
38 - },  
39 - {  
40 - label: '发送状态',  
41 - field: 'sendStatus',  
42 - dictType: DICT_TYPE.SYSTEM_SMS_SEND_STATUS,  
43 - search: {  
44 - show: true  
45 - }  
46 - },  
47 - {  
48 - label: '接收状态',  
49 - field: 'receiveTime',  
50 - dictType: DICT_TYPE.SYSTEM_SMS_RECEIVE_STATUS,  
51 - search: {  
52 - show: true  
53 - }  
54 - },  
55 - {  
56 - label: '模板编号',  
57 - field: 'templateId',  
58 - search: {  
59 - show: true  
60 - }  
61 - },  
62 - {  
63 - label: '短信类型',  
64 - field: 'channelId',  
65 - dictType: DICT_TYPE.SYSTEM_SMS_TEMPLATE_TYPE,  
66 - search: {  
67 - show: true  
68 - }  
69 - },  
70 - {  
71 - label: '接收时间',  
72 - field: 'receiveTime',  
73 - form: {  
74 - show: false  
75 - }  
76 - },  
77 - {  
78 - label: t('common.createTime'),  
79 - field: 'createTime',  
80 - form: {  
81 - show: false 18 + {
  19 + title: '短信内容',
  20 + field: 'templateContent'
82 }, 21 },
83 - search: {  
84 - show: true,  
85 - component: 'DatePicker',  
86 - componentProps: {  
87 - type: 'daterange',  
88 - valueFormat: 'YYYY-MM-DD HH:mm:ss',  
89 - defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]  
90 - }  
91 - }  
92 - },  
93 - {  
94 - label: t('table.action'),  
95 - field: 'action',  
96 - width: '80px',  
97 - form: {  
98 - show: false 22 + {
  23 + title: '短信渠道',
  24 + field: 'channelId',
  25 + dictType: DICT_TYPE.SYSTEM_SMS_CHANNEL_CODE,
  26 + isSearch: true
  27 + },
  28 + {
  29 + title: '发送状态',
  30 + field: 'sendStatus',
  31 + dictType: DICT_TYPE.SYSTEM_SMS_SEND_STATUS,
  32 + isSearch: true
  33 + },
  34 + {
  35 + title: '接收状态',
  36 + field: 'receiveStatus',
  37 + dictType: DICT_TYPE.SYSTEM_SMS_RECEIVE_STATUS,
  38 + isSearch: true
99 }, 39 },
100 - detail: {  
101 - show: false 40 + {
  41 + title: '模板编号',
  42 + field: 'templateId',
  43 + isSearch: true
  44 + },
  45 + {
  46 + title: '短信类型',
  47 + field: 'templateType',
  48 + dictType: DICT_TYPE.SYSTEM_SMS_TEMPLATE_TYPE,
  49 + isSearch: true
  50 + },
  51 + {
  52 + title: '接收时间',
  53 + field: 'receiveTime'
  54 + },
  55 + {
  56 + title: t('common.createTime'),
  57 + field: 'createTime',
  58 + formatter: 'formatDate',
  59 + search: {
  60 + show: true,
  61 + itemRender: {
  62 + name: 'XDataTimePicker'
  63 + }
  64 + }
102 } 65 }
103 - }  
104 -])  
105 -export const { allSchemas } = useCrudSchemas(crudSchemas) 66 + ]
  67 +})
  68 +export const { allSchemas } = useVxeCrudSchemas(crudSchemas)
yudao-ui-admin-vue3/src/views/system/sms/smsTemplate/index.vue
1 <template> 1 <template>
2 - <!-- 搜索工作区 -->  
3 <ContentWrap> 2 <ContentWrap>
4 - <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />  
5 - </ContentWrap>  
6 - <ContentWrap>  
7 - <!-- 操作工具栏 -->  
8 - <div class="mb-10px">  
9 - <XButton  
10 - type="primary"  
11 - preIcon="ep:zoom-in"  
12 - :title="t('action.add')"  
13 - v-hasPermi="['system:sms-channel:create']"  
14 - @click="handleCreate()"  
15 - />  
16 - </div>  
17 <!-- 列表 --> 3 <!-- 列表 -->
18 - <Table  
19 - :columns="allSchemas.tableColumns"  
20 - :selection="false"  
21 - :data="tableObject.tableList"  
22 - :loading="tableObject.loading"  
23 - :pagination="{  
24 - total: tableObject.total  
25 - }"  
26 - v-model:pageSize="tableObject.pageSize"  
27 - v-model:currentPage="tableObject.currentPage"  
28 - @register="register"  
29 - >  
30 - <template #type="{ row }">  
31 - <DictTag :type="DICT_TYPE.SYSTEM_SMS_TEMPLATE_TYPE" :value="row.type" />  
32 - </template>  
33 - <template #status="{ row }">  
34 - <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />  
35 - </template>  
36 - <template #createTime="{ row }">  
37 - <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span> 4 + <vxe-grid ref="xGrid" v-bind="gridOptions" class="xtable-scrollbar">
  5 + <!-- 操作:新增 -->
  6 + <template #toolbar_buttons>
  7 + <XButton
  8 + type="primary"
  9 + preIcon="ep:zoom-in"
  10 + :title="t('action.add')"
  11 + v-hasPermi="['system:sms-channel:create']"
  12 + @click="handleCreate()"
  13 + />
38 </template> 14 </template>
39 - <template #action="{ row }"> 15 + <template #actionbtns_default="{ row }">
40 <XTextButton 16 <XTextButton
41 preIcon="ep:cpu" 17 preIcon="ep:cpu"
42 :title="t('action.test')" 18 :title="t('action.test')"
@@ -55,20 +31,20 @@ @@ -55,20 +31,20 @@
55 preIcon="ep:view" 31 preIcon="ep:view"
56 :title="t('action.detail')" 32 :title="t('action.detail')"
57 v-hasPermi="['system:sms-template:update']" 33 v-hasPermi="['system:sms-template:update']"
58 - @click="handleDetail(row)" 34 + @click="handleDetail(row.id)"
59 /> 35 />
60 <!-- 操作:删除 --> 36 <!-- 操作:删除 -->
61 <XTextButton 37 <XTextButton
62 preIcon="ep:delete" 38 preIcon="ep:delete"
63 :title="t('action.del')" 39 :title="t('action.del')"
64 v-hasPermi="['system:sms-template:delete']" 40 v-hasPermi="['system:sms-template:delete']"
65 - @click="delList(row.id, false)" 41 + @click="handleDelete(row.id)"
66 /> 42 />
67 </template> 43 </template>
68 - </Table> 44 + </vxe-grid>
69 </ContentWrap> 45 </ContentWrap>
70 46
71 - <XModal v-model="dialogVisible" :title="dialogTitle"> 47 + <XModal id="smsTemplate" v-model="dialogVisible" :title="dialogTitle">
72 <!-- 对话框(添加 / 修改) --> 48 <!-- 对话框(添加 / 修改) -->
73 <Form 49 <Form
74 v-if="['create', 'update'].includes(actionType)" 50 v-if="['create', 'update'].includes(actionType)"
@@ -80,7 +56,7 @@ @@ -80,7 +56,7 @@
80 <Descriptions 56 <Descriptions
81 v-if="actionType === 'detail'" 57 v-if="actionType === 'detail'"
82 :schema="allSchemas.detailSchema" 58 :schema="allSchemas.detailSchema"
83 - :data="detailRef" 59 + :data="detailData"
84 /> 60 />
85 <!-- 操作按钮 --> 61 <!-- 操作按钮 -->
86 <template #footer> 62 <template #footer>
@@ -89,14 +65,14 @@ @@ -89,14 +65,14 @@
89 v-if="['create', 'update'].includes(actionType)" 65 v-if="['create', 'update'].includes(actionType)"
90 type="primary" 66 type="primary"
91 :title="t('action.save')" 67 :title="t('action.save')"
92 - :loading="loading" 68 + :loading="actionLoading"
93 @click="submitForm()" 69 @click="submitForm()"
94 /> 70 />
95 <!-- 按钮:关闭 --> 71 <!-- 按钮:关闭 -->
96 - <XButton :loading="loading" :title="t('dialog.close')" @click="dialogVisible = false" /> 72 + <XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" />
97 </template> 73 </template>
98 </XModal> 74 </XModal>
99 - <XModal v-model="sendVisible" title="测试"> 75 + <XModal id="sendTest" v-model="sendVisible" title="测试">
100 <el-form :model="sendSmsForm" :rules="sendSmsRules" label-width="140px"> 76 <el-form :model="sendSmsForm" :rules="sendSmsRules" label-width="140px">
101 <el-form-item label="模板内容" prop="content"> 77 <el-form-item label="模板内容" prop="content">
102 <el-input 78 <el-input
@@ -123,38 +99,47 @@ @@ -123,38 +99,47 @@
123 </el-form> 99 </el-form>
124 <!-- 操作按钮 --> 100 <!-- 操作按钮 -->
125 <template #footer> 101 <template #footer>
126 - <XButton type="primary" :title="t('action.test')" :loading="loading" @click="sendSmsTest()" /> 102 + <XButton
  103 + type="primary"
  104 + :title="t('action.test')"
  105 + :loading="actionLoading"
  106 + @click="sendSmsTest()"
  107 + />
127 <XButton :title="t('dialog.close')" @click="dialogVisible = false" /> 108 <XButton :title="t('dialog.close')" @click="dialogVisible = false" />
128 </template> 109 </template>
129 </XModal> 110 </XModal>
130 </template> 111 </template>
131 112
132 <script setup lang="ts"> 113 <script setup lang="ts">
  114 +// 全局相关的 import
133 import { ref, unref } from 'vue' 115 import { ref, unref } from 'vue'
134 -import dayjs from 'dayjs'  
135 -import { ElMessage, ElForm, ElFormItem, ElInput } from 'element-plus'  
136 -import { DICT_TYPE } from '@/utils/dict'  
137 -import { useTable } from '@/hooks/web/useTable'  
138 import { useI18n } from '@/hooks/web/useI18n' 116 import { useI18n } from '@/hooks/web/useI18n'
  117 +import { useMessage } from '@/hooks/web/useMessage'
  118 +import { useVxeGrid } from '@/hooks/web/useVxeGrid'
  119 +import { VxeGridInstance } from 'vxe-table'
139 import { FormExpose } from '@/components/Form' 120 import { FormExpose } from '@/components/Form'
140 -import type { SmsTemplateVO } from '@/api/system/sms/smsTemplate/types'  
141 -import { rules, allSchemas } from './sms.template.data' 121 +// 业务相关的 import
142 import * as SmsTemplateApi from '@/api/system/sms/smsTemplate' 122 import * as SmsTemplateApi from '@/api/system/sms/smsTemplate'
  123 +import { rules, allSchemas } from './sms.template.data'
  124 +
143 const { t } = useI18n() // 国际化 125 const { t } = useI18n() // 国际化
  126 +const message = useMessage() // 消息弹窗
144 127
145 -// ========== 列表相关 ==========  
146 -const { register, tableObject, methods } = useTable<SmsTemplateVO>({ 128 +// 列表相关的变量
  129 +const xGrid = ref<VxeGridInstance>() // 列表 Grid Ref
  130 +const { gridOptions, reloadList, delList } = useVxeGrid<SmsTemplateApi.SmsTemplateVO>({
  131 + allSchemas: allSchemas,
147 getListApi: SmsTemplateApi.getSmsTemplatePageApi, 132 getListApi: SmsTemplateApi.getSmsTemplatePageApi,
148 delListApi: SmsTemplateApi.deleteSmsTemplateApi 133 delListApi: SmsTemplateApi.deleteSmsTemplateApi
149 }) 134 })
150 -const { getList, setSearchParams, delList } = methods  
151 135
152 -// ========== CRUD 相关 ==========  
153 -const loading = ref(false) // 遮罩层  
154 -const actionType = ref('') // 操作按钮的类型 136 +// 弹窗相关的变量
155 const dialogVisible = ref(false) // 是否显示弹出层 137 const dialogVisible = ref(false) // 是否显示弹出层
156 const dialogTitle = ref('edit') // 弹出层标题 138 const dialogTitle = ref('edit') // 弹出层标题
  139 +const actionType = ref('') // 操作按钮的类型
  140 +const actionLoading = ref(false) // 按钮 Loading
157 const formRef = ref<FormExpose>() // 表单 Ref 141 const formRef = ref<FormExpose>() // 表单 Ref
  142 +const detailData = ref() // 详情 Ref
158 143
159 // 设置标题 144 // 设置标题
160 const setDialogTile = (type: string) => { 145 const setDialogTile = (type: string) => {
@@ -176,42 +161,46 @@ const handleUpdate = async (rowId: number) =&gt; { @@ -176,42 +161,46 @@ const handleUpdate = async (rowId: number) =&gt; {
176 unref(formRef)?.setValues(res) 161 unref(formRef)?.setValues(res)
177 } 162 }
178 163
  164 +// 详情操作
  165 +const handleDetail = async (rowId: number) => {
  166 + setDialogTile('detail')
  167 + // 设置数据
  168 + const res = await SmsTemplateApi.getSmsTemplateApi(rowId)
  169 + detailData.value = res
  170 +}
  171 +
  172 +// 删除操作
  173 +const handleDelete = async (rowId: number) => {
  174 + await delList(xGrid, rowId)
  175 +}
  176 +
179 // 提交按钮 177 // 提交按钮
180 const submitForm = async () => { 178 const submitForm = async () => {
181 const elForm = unref(formRef)?.getElFormRef() 179 const elForm = unref(formRef)?.getElFormRef()
182 if (!elForm) return 180 if (!elForm) return
183 elForm.validate(async (valid) => { 181 elForm.validate(async (valid) => {
184 if (valid) { 182 if (valid) {
185 - loading.value = true 183 + actionLoading.value = true
186 // 提交请求 184 // 提交请求
187 try { 185 try {
188 - const data = unref(formRef)?.formModel as SmsTemplateVO 186 + const data = unref(formRef)?.formModel as SmsTemplateApi.SmsTemplateVO
189 if (actionType.value === 'create') { 187 if (actionType.value === 'create') {
190 await SmsTemplateApi.createSmsTemplateApi(data) 188 await SmsTemplateApi.createSmsTemplateApi(data)
191 - ElMessage.success(t('common.createSuccess')) 189 + message.success(t('common.createSuccess'))
192 } else { 190 } else {
193 await SmsTemplateApi.updateSmsTemplateApi(data) 191 await SmsTemplateApi.updateSmsTemplateApi(data)
194 - ElMessage.success(t('common.updateSuccess')) 192 + message.success(t('common.updateSuccess'))
195 } 193 }
196 - // 操作成功,重新加载列表  
197 dialogVisible.value = false 194 dialogVisible.value = false
198 - await getList()  
199 } finally { 195 } finally {
200 - loading.value = false 196 + actionLoading.value = false
  197 + // 刷新列表
  198 + reloadList(xGrid)
201 } 199 }
202 } 200 }
203 }) 201 })
204 } 202 }
205 203
206 -// ========== 详情相关 ==========  
207 -const detailRef = ref() // 详情 Ref  
208 -  
209 -// 详情操作  
210 -const handleDetail = async (row: SmsTemplateVO) => {  
211 - // 设置数据  
212 - detailRef.value = row  
213 - setDialogTile('detail')  
214 -}  
215 // ========== 测试相关 ========== 204 // ========== 测试相关 ==========
216 const sendSmsForm = ref({ 205 const sendSmsForm = ref({
217 content: '', 206 content: '',
@@ -249,10 +238,7 @@ const sendSmsTest = () =&gt; { @@ -249,10 +238,7 @@ const sendSmsTest = () =&gt; {
249 templateParams: sendSmsForm.value.templateParams 238 templateParams: sendSmsForm.value.templateParams
250 } 239 }
251 SmsTemplateApi.sendSmsApi(data) 240 SmsTemplateApi.sendSmsApi(data)
252 - ElMessage.info('发送成功') 241 + message.info('发送成功')
253 sendVisible.value = false 242 sendVisible.value = false
254 } 243 }
255 -  
256 -// ========== 初始化 ==========  
257 -getList()  
258 </script> 244 </script>
yudao-ui-admin-vue3/src/views/system/sms/smsTemplate/sms.template.data.ts
1 import { reactive } from 'vue' 1 import { reactive } from 'vue'
2 import { useI18n } from '@/hooks/web/useI18n' 2 import { useI18n } from '@/hooks/web/useI18n'
3 import { required } from '@/utils/formRules' 3 import { required } from '@/utils/formRules'
4 -import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas'  
5 import { DICT_TYPE } from '@/utils/dict' 4 import { DICT_TYPE } from '@/utils/dict'
  5 +import { VxeCrudSchema, useVxeCrudSchemas } from '@/hooks/web/useVxeCrudSchemas'
6 const { t } = useI18n() // 国际化 6 const { t } = useI18n() // 国际化
7 7
8 // 表单校验 8 // 表单校验
@@ -17,86 +17,57 @@ export const rules = reactive({ @@ -17,86 +17,57 @@ export const rules = reactive({
17 }) 17 })
18 18
19 // CrudSchema 19 // CrudSchema
20 -const crudSchemas = reactive<CrudSchema[]>([  
21 - {  
22 - label: t('common.index'),  
23 - field: 'id',  
24 - type: 'index',  
25 - form: {  
26 - show: false 20 +const crudSchemas = reactive<VxeCrudSchema>({
  21 + primaryKey: 'id',
  22 + primaryType: 'seq',
  23 + action: true,
  24 + columns: [
  25 + {
  26 + label: '模板编码',
  27 + field: 'code',
  28 + isSearch: true
27 }, 29 },
28 - detail: {  
29 - show: false  
30 - }  
31 - },  
32 - {  
33 - label: '模板编码',  
34 - field: 'code',  
35 - search: {  
36 - show: true  
37 - }  
38 - },  
39 - {  
40 - label: '模板名称',  
41 - field: 'name',  
42 - search: {  
43 - show: true  
44 - }  
45 - },  
46 - {  
47 - label: '模板内容',  
48 - field: 'content'  
49 - },  
50 - {  
51 - label: '短信 API 的模板编号',  
52 - field: 'apiTemplateId',  
53 - search: {  
54 - show: true  
55 - }  
56 - },  
57 - {  
58 - label: '短信类型',  
59 - field: 'type',  
60 - dictType: DICT_TYPE.SYSTEM_SMS_TEMPLATE_TYPE  
61 - },  
62 - {  
63 - label: t('common.status'),  
64 - field: 'status',  
65 - dictType: DICT_TYPE.COMMON_STATUS  
66 - },  
67 - {  
68 - label: t('form.remark'),  
69 - field: 'remark',  
70 - table: {  
71 - show: false  
72 - }  
73 - },  
74 - {  
75 - label: t('common.createTime'),  
76 - field: 'createTime',  
77 - form: {  
78 - show: false 30 + {
  31 + label: '模板名称',
  32 + field: 'name',
  33 + isSearch: true
79 }, 34 },
80 - search: {  
81 - show: true,  
82 - component: 'DatePicker',  
83 - componentProps: {  
84 - type: 'daterange',  
85 - valueFormat: 'YYYY-MM-DD HH:mm:ss',  
86 - defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]  
87 - }  
88 - }  
89 - },  
90 - {  
91 - label: t('table.action'),  
92 - field: 'action',  
93 - width: '320px',  
94 - form: {  
95 - show: false 35 + {
  36 + label: '模板内容',
  37 + field: 'content'
96 }, 38 },
97 - detail: {  
98 - show: false 39 + {
  40 + label: '短信 API 的模板编号',
  41 + field: 'apiTemplateId',
  42 + isSearch: true
  43 + },
  44 + {
  45 + label: '短信类型',
  46 + field: 'type',
  47 + dictType: DICT_TYPE.SYSTEM_SMS_TEMPLATE_TYPE
  48 + },
  49 + {
  50 + label: t('common.status'),
  51 + field: 'status',
  52 + dictType: DICT_TYPE.COMMON_STATUS
  53 + },
  54 + {
  55 + label: t('form.remark'),
  56 + field: 'remark',
  57 + isTable: false
  58 + },
  59 + {
  60 + title: t('common.createTime'),
  61 + field: 'createTime',
  62 + formatter: 'formatDate',
  63 + isForm: false,
  64 + search: {
  65 + show: true,
  66 + itemRender: {
  67 + name: 'XDataTimePicker'
  68 + }
  69 + }
99 } 70 }
100 - }  
101 -])  
102 -export const { allSchemas } = useCrudSchemas(crudSchemas) 71 + ]
  72 +})
  73 +export const { allSchemas } = useVxeCrudSchemas(crudSchemas)