Merge branch 'master' of https://gitee.com/yudaocode/yudao-ui-admin-vben
						commit
						7206b7914e
					
				|  | @ -34,3 +34,30 @@ export function listSimplePosts() { | ||||||
| export function exportNotifyTemplateExcel(params) { | export function exportNotifyTemplateExcel(params) { | ||||||
|   return defHttp.download({ url: '/system/notify-template/export-excel', params }, '导出站内信模板.xls') |   return defHttp.download({ url: '/system/notify-template/export-excel', params }, '导出站内信模板.xls') | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | export type SendNotifyParam = { | ||||||
|  |   userId: number | ||||||
|  |   templateCode: string | ||||||
|  |   templateParams: { | ||||||
|  |     [key: string]: string | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export type NotifyTemplate = { | ||||||
|  |   name: string | ||||||
|  |   code: string | ||||||
|  |   type: number | ||||||
|  |   nickname: string | ||||||
|  |   content: string | ||||||
|  |   status: number | ||||||
|  |   remark?: any | ||||||
|  |   id: number | ||||||
|  |   params: string[] | ||||||
|  |   createTime: number | ||||||
|  |   key: string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 发送
 | ||||||
|  | export function sendNotify(data: SendNotifyParam) { | ||||||
|  |   return defHttp.post({ url: '/system/notify-template/send-notify', data }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -9,5 +9,6 @@ export default { | ||||||
|   export: '导出', |   export: '导出', | ||||||
|   import: '导入', |   import: '导入', | ||||||
|   sync: '同步', |   sync: '同步', | ||||||
|   cancel: '取消' |   cancel: '取消', | ||||||
|  |   send: '发送' | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -24,7 +24,8 @@ const [registerTable, { getSelectRowKeys, getForm }] = useTable({ | ||||||
|   useSearchForm: true, |   useSearchForm: true, | ||||||
|   pagination: false, |   pagination: false, | ||||||
|   showTableSetting: false, |   showTableSetting: false, | ||||||
|   showIndexColumn: false |   showIndexColumn: false, | ||||||
|  |   immediate: false | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| const [registerModal, { setModalProps, closeModal }] = useModalInner(async () => { | const [registerModal, { setModalProps, closeModal }] = useModalInner(async () => { | ||||||
|  |  | ||||||
|  | @ -0,0 +1,27 @@ | ||||||
|  | <template> | ||||||
|  |   <BasicModal title="详情" @register="innerRegister"> | ||||||
|  |     <Description @register="descriptionRegister" /> | ||||||
|  |   </BasicModal> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <script setup lang="ts"> | ||||||
|  | import { ref } from 'vue' | ||||||
|  | import { BasicModal, useModalInner } from '@/components/Modal' | ||||||
|  | import { Description, useDescription } from '@/components/Description/index' | ||||||
|  | import { infoSchema, MessageInfo } from './message.data' | ||||||
|  | 
 | ||||||
|  | defineOptions({ name: 'MessageInfoModal' }) | ||||||
|  | 
 | ||||||
|  | const [innerRegister] = useModalInner((value: MessageInfo) => { | ||||||
|  |   data.value = value | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | const data = ref<MessageInfo>() | ||||||
|  | const [descriptionRegister] = useDescription({ | ||||||
|  |   column: 1, | ||||||
|  |   schema: infoSchema, | ||||||
|  |   data | ||||||
|  | }) | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <style scoped></style> | ||||||
|  | @ -1,15 +1,36 @@ | ||||||
| <template> | <template> | ||||||
|   <div> |   <div> | ||||||
|     <BasicTable @register="registerTable" /> |     <BasicTable @register="registerTable"> | ||||||
|  |       <template #bodyCell="{ column, record }"> | ||||||
|  |         <template v-if="column.key === 'action'"> | ||||||
|  |           <TableAction | ||||||
|  |             :actions="[ | ||||||
|  |               { | ||||||
|  |                 label: '详情', | ||||||
|  |                 icon: IconEnum.LOG, | ||||||
|  |                 onClick: handleShowInfo.bind(null, record) | ||||||
|  |               } | ||||||
|  |             ]" | ||||||
|  |           /> | ||||||
|  |         </template> | ||||||
|  |       </template> | ||||||
|  |     </BasicTable> | ||||||
|  |     <MessageInfoModal @register="registerModal" /> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
| <script lang="ts" setup> | <script lang="ts" setup> | ||||||
| import { BasicTable, useTable } from '@/components/Table' | import { IconEnum } from '@/enums/appEnum' | ||||||
|  | import { useI18n } from '@/hooks/web/useI18n' | ||||||
|  | import { BasicTable, useTable, TableAction } from '@/components/Table' | ||||||
| import { getNotifyMessagePage } from '@/api/system/notify/message' | import { getNotifyMessagePage } from '@/api/system/notify/message' | ||||||
| import { columns, searchFormSchema } from './message.data' | import { columns, searchFormSchema } from './message.data' | ||||||
|  | import MessageInfoModal from './MessageInfoModal.vue' | ||||||
|  | import { useModal } from '@/components/Modal' | ||||||
| 
 | 
 | ||||||
| defineOptions({ name: 'SystemMessage' }) | defineOptions({ name: 'SystemMessage' }) | ||||||
| 
 | 
 | ||||||
|  | const { t } = useI18n() | ||||||
|  | 
 | ||||||
| const [registerTable] = useTable({ | const [registerTable] = useTable({ | ||||||
|   title: '站内信记录列表', |   title: '站内信记录列表', | ||||||
|   api: getNotifyMessagePage, |   api: getNotifyMessagePage, | ||||||
|  | @ -17,6 +38,18 @@ const [registerTable] = useTable({ | ||||||
|   formConfig: { labelWidth: 120, schemas: searchFormSchema }, |   formConfig: { labelWidth: 120, schemas: searchFormSchema }, | ||||||
|   useSearchForm: true, |   useSearchForm: true, | ||||||
|   showTableSetting: true, |   showTableSetting: true, | ||||||
|   showIndexColumn: false |   showIndexColumn: false, | ||||||
|  |   actionColumn: { | ||||||
|  |     width: 100, | ||||||
|  |     title: t('common.action'), | ||||||
|  |     fixed: 'right', | ||||||
|  |     key: 'action' | ||||||
|  |   } | ||||||
| }) | }) | ||||||
|  | 
 | ||||||
|  | const [registerModal, { openModal }] = useModal() | ||||||
|  | 
 | ||||||
|  | const handleShowInfo = (record: Recordable) => { | ||||||
|  |   openModal(true, record) | ||||||
|  | } | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
|  | @ -1,5 +1,8 @@ | ||||||
| import { BasicColumn, FormSchema, useRender } from '@/components/Table' | import { BasicColumn, FormSchema, useRender } from '@/components/Table' | ||||||
| import { DICT_TYPE, getDictOptions } from '@/utils/dict' | import { DICT_TYPE, getDictOptions } from '@/utils/dict' | ||||||
|  | import { JsonPreview } from '@/components/CodeEditor' | ||||||
|  | import { DescItem } from '@/components/Description/index' | ||||||
|  | import { h } from 'vue' | ||||||
| 
 | 
 | ||||||
| export const columns: BasicColumn[] = [ | export const columns: BasicColumn[] = [ | ||||||
|   { |   { | ||||||
|  | @ -56,6 +59,9 @@ export const columns: BasicColumn[] = [ | ||||||
|     dataIndex: 'readTime', |     dataIndex: 'readTime', | ||||||
|     width: 180, |     width: 180, | ||||||
|     customRender: ({ text }) => { |     customRender: ({ text }) => { | ||||||
|  |       if (!text) { | ||||||
|  |         return useRender.renderTag('未阅读') | ||||||
|  |       } | ||||||
|       return useRender.renderDate(text) |       return useRender.renderDate(text) | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|  | @ -104,3 +110,95 @@ export const searchFormSchema: FormSchema[] = [ | ||||||
|     colProps: { span: 8 } |     colProps: { span: 8 } | ||||||
|   } |   } | ||||||
| ] | ] | ||||||
|  | 
 | ||||||
|  | // 站内信详情modal
 | ||||||
|  | export const infoSchema: DescItem[] = [ | ||||||
|  |   { | ||||||
|  |     field: 'id', | ||||||
|  |     label: '编号', | ||||||
|  |     labelMinWidth: 50 | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     field: 'readStatus', | ||||||
|  |     label: '是否已读', | ||||||
|  |     render: (value) => { | ||||||
|  |       return useRender.renderDict(value, DICT_TYPE.INFRA_BOOLEAN_STRING) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     field: 'userType', | ||||||
|  |     label: '用户类型', | ||||||
|  |     render: (value) => { | ||||||
|  |       console.log(value) | ||||||
|  |       return useRender.renderDict(value, DICT_TYPE.USER_TYPE) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     field: 'userType', | ||||||
|  |     label: '用户编号' | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     field: 'templateId', | ||||||
|  |     label: '模板编号' | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     field: 'templateCode', | ||||||
|  |     label: '模板编码' | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     field: 'templateNickname', | ||||||
|  |     label: '发送人名称' | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     field: 'templateContent', | ||||||
|  |     label: '模板内容' | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     field: 'templateParams', | ||||||
|  |     label: '模板参数', | ||||||
|  |     render: (value) => { | ||||||
|  |       return h(JsonPreview, { data: value }) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     field: 'templateType', | ||||||
|  |     label: '模板类型', | ||||||
|  |     render: (value) => { | ||||||
|  |       return useRender.renderDict(value, DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     field: 'readTime', | ||||||
|  |     label: '阅读时间', | ||||||
|  |     render: (value) => { | ||||||
|  |       if (!value) { | ||||||
|  |         return useRender.renderTag('未阅读') | ||||||
|  |       } | ||||||
|  |       return useRender.renderDate(value) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     field: 'createTime', | ||||||
|  |     label: '创建时间', | ||||||
|  |     render: (value) => { | ||||||
|  |       return useRender.renderDate(value) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | // 站内信详情
 | ||||||
|  | export interface MessageInfo { | ||||||
|  |   userId: number | ||||||
|  |   userType: number | ||||||
|  |   templateId: number | ||||||
|  |   templateCode: string | ||||||
|  |   templateNickname: string | ||||||
|  |   templateContent: string | ||||||
|  |   templateType: number | ||||||
|  |   templateParams: { [key: string]: string } | ||||||
|  |   readStatus: boolean | ||||||
|  |   readTime?: any | ||||||
|  |   id: number | ||||||
|  |   createTime: number | ||||||
|  |   key: string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,89 @@ | ||||||
|  | <template> | ||||||
|  |   <BasicModal v-bind="$attrs" title="发送站内信" @register="innerRegister" @ok="submit"> | ||||||
|  |     <BasicForm @register="register" :schemas="reactiveSchemas" /> | ||||||
|  |   </BasicModal> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <script setup lang="ts"> | ||||||
|  | import { BasicModal, useModalInner } from '@/components/Modal' | ||||||
|  | import { BasicForm, FormSchema, useForm } from '@/components/Form' | ||||||
|  | import { reactive, ref } from 'vue' | ||||||
|  | import { useMessage } from '@/hooks/web/useMessage' | ||||||
|  | import { sendNotify, SendNotifyParam, NotifyTemplate } from '@/api/system/notify/template' | ||||||
|  | import { baseSendSchemas } from './template.data' | ||||||
|  | 
 | ||||||
|  | defineOptions({ name: 'SendNotifyModal' }) | ||||||
|  | 
 | ||||||
|  | const { createMessage } = useMessage() | ||||||
|  | let reactiveSchemas: FormSchema[] = reactive([]) | ||||||
|  | const templateCode = ref<string>('') | ||||||
|  | 
 | ||||||
|  | const [register, { setFieldsValue, getFieldsValue, validateFields, resetFields, clearValidate, setProps }] = useForm({ | ||||||
|  |   labelWidth: 100, | ||||||
|  |   // schemas: reactiveSchemas, 这里用动态绑定会有问题 | ||||||
|  |   baseColProps: { | ||||||
|  |     span: 24 | ||||||
|  |   }, | ||||||
|  |   showSubmitButton: false, | ||||||
|  |   showResetButton: false | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | const [innerRegister, { changeLoading, closeModal }] = useModalInner((data: NotifyTemplate) => { | ||||||
|  |   resetForm() | ||||||
|  |   data.params.forEach((item) => { | ||||||
|  |     const dySchema: FormSchema = { | ||||||
|  |       // 这里加上前缀 防止和content/userId字段重名 | ||||||
|  |       field: `key-${item}`, | ||||||
|  |       label: `参数{${item}} `, | ||||||
|  |       component: 'Input', | ||||||
|  |       componentProps: { | ||||||
|  |         placeholder: `输入{${item}}` | ||||||
|  |       }, | ||||||
|  |       required: true | ||||||
|  |     } | ||||||
|  |     reactiveSchemas.push(dySchema) | ||||||
|  |   }) | ||||||
|  |   const { content, code } = data | ||||||
|  |   setFieldsValue({ content }) | ||||||
|  |   templateCode.value = code | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | const submit = async () => { | ||||||
|  |   try { | ||||||
|  |     setProps({ disabled: true }) | ||||||
|  |     changeLoading(true) | ||||||
|  |     await validateFields() | ||||||
|  |     const fields = getFieldsValue() | ||||||
|  |     const data: SendNotifyParam = { | ||||||
|  |       userId: fields.userId, | ||||||
|  |       templateCode: templateCode.value, | ||||||
|  |       templateParams: {} | ||||||
|  |     } | ||||||
|  |     Object.keys(fields).forEach((key) => { | ||||||
|  |       if (key === 'content' || key === 'userId') { | ||||||
|  |         return | ||||||
|  |       } | ||||||
|  |       // 去掉 - 后的key | ||||||
|  |       const realKey = key.split('-')[1] | ||||||
|  |       data.templateParams[realKey] = fields[key] | ||||||
|  |     }) | ||||||
|  |     await sendNotify(data) | ||||||
|  |     createMessage.success(`发送站内信成功`) | ||||||
|  |     closeModal() | ||||||
|  |   } finally { | ||||||
|  |     setProps({ disabled: false }) | ||||||
|  |     changeLoading(false) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const resetForm = () => { | ||||||
|  |   // 这里需要每次清空动态表单 | ||||||
|  |   reactiveSchemas.splice(0, reactiveSchemas.length) | ||||||
|  |   reactiveSchemas.push(...baseSendSchemas) | ||||||
|  |   // 清除上一次的表单校验和参数 | ||||||
|  |   resetFields() | ||||||
|  |   clearValidate() | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <style scoped></style> | ||||||
|  | @ -10,6 +10,12 @@ | ||||||
|         <template v-if="column.key === 'action'"> |         <template v-if="column.key === 'action'"> | ||||||
|           <TableAction |           <TableAction | ||||||
|             :actions="[ |             :actions="[ | ||||||
|  |               { | ||||||
|  |                 icon: IconEnum.UPLOAD, | ||||||
|  |                 label: t('action.send'), | ||||||
|  |                 auth: 'system:notify-template:update', | ||||||
|  |                 onClick: handleSend.bind(null, record) | ||||||
|  |               }, | ||||||
|               { |               { | ||||||
|                 icon: IconEnum.EDIT, |                 icon: IconEnum.EDIT, | ||||||
|                 label: t('action.edit'), |                 label: t('action.edit'), | ||||||
|  | @ -33,6 +39,7 @@ | ||||||
|       </template> |       </template> | ||||||
|     </BasicTable> |     </BasicTable> | ||||||
|     <TemplateModal @register="registerModal" @success="reload()" /> |     <TemplateModal @register="registerModal" @success="reload()" /> | ||||||
|  |     <SendNotifyModal @register="registerSendModal" /> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
| <script lang="ts" setup> | <script lang="ts" setup> | ||||||
|  | @ -44,12 +51,14 @@ import { IconEnum } from '@/enums/appEnum' | ||||||
| import { BasicTable, useTable, TableAction } from '@/components/Table' | import { BasicTable, useTable, TableAction } from '@/components/Table' | ||||||
| import { deleteNotifyTemplate, getNotifyTemplatePage } from '@/api/system/notify/template' | import { deleteNotifyTemplate, getNotifyTemplatePage } from '@/api/system/notify/template' | ||||||
| import { columns, searchFormSchema } from './template.data' | import { columns, searchFormSchema } from './template.data' | ||||||
|  | import SendNotifyModal from './SendNotifyModal.vue' | ||||||
| 
 | 
 | ||||||
| defineOptions({ name: 'SystemMessageTemplate' }) | defineOptions({ name: 'SystemMessageTemplate' }) | ||||||
| 
 | 
 | ||||||
| const { t } = useI18n() | const { t } = useI18n() | ||||||
| const { createMessage } = useMessage() | const { createMessage } = useMessage() | ||||||
| const [registerModal, { openModal }] = useModal() | const [registerModal, { openModal }] = useModal() | ||||||
|  | const [registerSendModal, { openModal: openSendModal }] = useModal() | ||||||
| 
 | 
 | ||||||
| const [registerTable, { reload }] = useTable({ | const [registerTable, { reload }] = useTable({ | ||||||
|   title: '站内信模板列表', |   title: '站内信模板列表', | ||||||
|  | @ -60,7 +69,7 @@ const [registerTable, { reload }] = useTable({ | ||||||
|   showTableSetting: true, |   showTableSetting: true, | ||||||
|   showIndexColumn: false, |   showIndexColumn: false, | ||||||
|   actionColumn: { |   actionColumn: { | ||||||
|     width: 140, |     width: 200, | ||||||
|     title: t('common.action'), |     title: t('common.action'), | ||||||
|     dataIndex: 'action', |     dataIndex: 'action', | ||||||
|     fixed: 'right' |     fixed: 'right' | ||||||
|  | @ -75,6 +84,11 @@ function handleEdit(record: Recordable) { | ||||||
|   openModal(true, { record, isUpdate: true }) |   openModal(true, { record, isUpdate: true }) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | function handleSend(record: Recordable) { | ||||||
|  |   console.log(JSON.stringify(record, [...Object.keys(record)], 2)) | ||||||
|  |   openSendModal(true, record) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| async function handleDelete(record: Recordable) { | async function handleDelete(record: Recordable) { | ||||||
|   await deleteNotifyTemplate(record.id) |   await deleteNotifyTemplate(record.id) | ||||||
|   createMessage.success(t('common.delSuccessText')) |   createMessage.success(t('common.delSuccessText')) | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| import { BasicColumn, FormSchema, useRender } from '@/components/Table' | import { BasicColumn, FormSchema, useRender } from '@/components/Table' | ||||||
| import { DICT_TYPE, getDictOptions } from '@/utils/dict' | import { DICT_TYPE, getDictOptions } from '@/utils/dict' | ||||||
|  | import { getListSimpleUsers } from '@/api/system/user/index' | ||||||
| 
 | 
 | ||||||
| export const columns: BasicColumn[] = [ | export const columns: BasicColumn[] = [ | ||||||
|   { |   { | ||||||
|  | @ -125,6 +126,7 @@ export const formSchema: FormSchema[] = [ | ||||||
|   { |   { | ||||||
|     label: '开启状态', |     label: '开启状态', | ||||||
|     field: 'status', |     field: 'status', | ||||||
|  |     required: true, | ||||||
|     component: 'RadioGroup', |     component: 'RadioGroup', | ||||||
|     componentProps: { |     componentProps: { | ||||||
|       options: getDictOptions(DICT_TYPE.COMMON_STATUS) |       options: getDictOptions(DICT_TYPE.COMMON_STATUS) | ||||||
|  | @ -136,3 +138,27 @@ export const formSchema: FormSchema[] = [ | ||||||
|     component: 'InputTextArea' |     component: 'InputTextArea' | ||||||
|   } |   } | ||||||
| ] | ] | ||||||
|  | 
 | ||||||
|  | // 发送站内信
 | ||||||
|  | export const baseSendSchemas: FormSchema[] = [ | ||||||
|  |   { | ||||||
|  |     field: 'content', | ||||||
|  |     component: 'InputTextArea', | ||||||
|  |     label: '模板内容 ', | ||||||
|  |     required: false, | ||||||
|  |     componentProps: { | ||||||
|  |       disabled: true | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     field: 'userId', | ||||||
|  |     component: 'ApiSelect', | ||||||
|  |     label: '接收人 ', | ||||||
|  |     required: true, | ||||||
|  |     componentProps: { | ||||||
|  |       api: getListSimpleUsers, | ||||||
|  |       labelField: 'nickname', | ||||||
|  |       valueField: 'id' | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | ] | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 xingyu
						xingyu