Browse Source

消息通知改造部分代码-接收人类型添加提交

master_hella_20240701
ljlong_2630 7 months ago
parent
commit
e88a1ead75
  1. 60
      src/api/system/messageSet/index.ts
  2. 4
      src/api/system/notify/template/index.ts
  3. 4
      src/api/system/sms/smsTemplate/index.ts
  4. 64
      src/api/system/tableActionRel/index.ts
  5. 7
      src/utils/dict.ts
  6. 42
      src/utils/tree.ts
  7. 85
      src/views/system/mail/template/MailTemplateForm.vue
  8. 120
      src/views/system/mail/template/template.data.ts
  9. 276
      src/views/system/messageSet/index.vue
  10. 156
      src/views/system/messageSet/messageSet.data.ts
  11. 132
      src/views/system/notify/template/NotifyTemplateForm.vue
  12. 130
      src/views/system/sms/template/SmsTemplateForm.vue
  13. 275
      src/views/system/tableActionRel/index.vue
  14. 144
      src/views/system/tableActionRel/tableActionRel.data.ts

60
src/api/system/messageSet/index.ts

@ -0,0 +1,60 @@
import request from '@/config/axios'
export interface MessageSetVO {
id: number
tableName: string
action: number
available: string
remark: string
deletionTime: Date
deleterId: string
extraProperties: string
concurrencyStamp: number
siteId: string
}
// 查询消息设置列表
export const getMessageSetPage = async (params) => {
if (params.isSearch) {
delete params.isSearch
const data = {...params}
return await request.post({ url: '/system/message-set/senior', data })
} else {
return await request.get({ url: `/system/message-set/page`, params })
}
}
// 查询消息设置详情
export const getMessageSet = async (id: number) => {
return await request.get({ url: `/system/message-set/get?id=` + id })
}
// 新增消息设置
export const createMessageSet = async (data: MessageSetVO) => {
return await request.post({ url: `/system/message-set/create`, data })
}
// 修改消息设置
export const updateMessageSet = async (data: MessageSetVO) => {
return await request.put({ url: `/system/message-set/update`, data })
}
// 删除消息设置
export const deleteMessageSet = async (id: number) => {
return await request.delete({ url: `/system/message-set/delete?id=` + id })
}
// 导出消息设置 Excel
export const exportMessageSet = async (params) => {
return await request.download({ url: `/system/message-set/export-excel`, params })
}
// 下载用户导入模板
export const importTemplate = () => {
return request.download({ url: '/system/message-set/get-import-template' })
}
// 查询消息设置列表不分页
export const getMessageSetNoPage = async (params) => {
return await request.get({ url: `/system/message-set/noPage`, params })
}

4
src/api/system/notify/template/index.ts

@ -11,6 +11,10 @@ export interface NotifyTemplateVO {
params: string params: string
status: number status: number
remark: string remark: string
roleIdList: []
deptIdList: []
postIdList: []
userIdList: []
} }
export interface NotifySendReqVO { export interface NotifySendReqVO {

4
src/api/system/sms/smsTemplate/index.ts

@ -13,6 +13,10 @@ export interface SmsTemplateVO {
channelCode?: string channelCode?: string
params?: string[] params?: string[]
createTime?: Date createTime?: Date
roleIdList: []
deptIdList: []
postIdList: []
userIdList: []
} }
export interface SendSmsReqVO { export interface SendSmsReqVO {

64
src/api/system/tableActionRel/index.ts

@ -0,0 +1,64 @@
import request from '@/config/axios'
export interface TableActionRelVO {
id: number
tableName: string
action: number
type: number
name: string
available: string
activeTime: Date
expireTime: Date
remark: string
deletionTime: Date
deleterId: string
extraProperties: string
concurrencyStamp: number
siteId: string
}
// 查询表名动作关系列表
export const getTableActionRelPage = async (params) => {
if (params.isSearch) {
delete params.isSearch
const data = {...params}
return await request.post({ url: '/system/table-action-rel/senior', data })
} else {
return await request.get({ url: `/system/table-action-rel/page`, params })
}
}
// 查询表名动作关系详情
export const getTableActionRel = async (id: number) => {
return await request.get({ url: `/system/table-action-rel/get?id=` + id })
}
// 新增表名动作关系
export const createTableActionRel = async (data: TableActionRelVO) => {
return await request.post({ url: `/system/table-action-rel/create`, data })
}
// 修改表名动作关系
export const updateTableActionRel = async (data: TableActionRelVO) => {
return await request.put({ url: `/system/table-action-rel/update`, data })
}
// 删除表名动作关系
export const deleteTableActionRel = async (id: number) => {
return await request.delete({ url: `/system/table-action-rel/delete?id=` + id })
}
// 导出表名动作关系 Excel
export const exportTableActionRel = async (params) => {
return await request.download({ url: `/system/table-action-rel/export-excel`, params })
}
// 下载用户导入模板
export const importTemplate = () => {
return request.download({ url: '/system/table-action-rel/get-import-template' })
}
// 查询表名动作关系列表
export const getTableActionRelNoPage = async (params) => {
return await request.get({ url: `/system/table-action-rel/noPage`, params })
}

7
src/utils/dict.ts

@ -322,4 +322,11 @@ export enum DICT_TYPE {
SUPPLIERINVOICE_REQUEST_STATUS = 'supplierinvoice_request_status', //发票申请状态 SUPPLIERINVOICE_REQUEST_STATUS = 'supplierinvoice_request_status', //发票申请状态
SUPPLIERINVOICE_STATUS = 'supplierinvoice_status', //待开票审核状态 SUPPLIERINVOICE_STATUS = 'supplierinvoice_status', //待开票审核状态
// ========== system - 消息通知优化 - ==========
MESSAGE_NOTICE_TABLE = 'message_notice_table',//消息通知表
NOTICE_ACTION_TYPE = 'notice_action_type',//消息通知动作类型
FALSE_OR_TRUE = 'false_or_true',//是或否
RECEIVER_TYPE = 'receiver_type',//接收人类型
} }

42
src/utils/tree.ts

@ -397,3 +397,45 @@ export const treeToString = (tree: any[], nodeId) => {
} }
return str return str
} }
export type FormValueType = string | number | string[] | number[] | boolean | undefined | null
interface Recordable<T = any> {
[key: string]: T;
}
export type ComponentOptions = {
label?: string;
value?: FormValueType;
disabled?: boolean;
key?: string | number;
children?: ComponentOptions[];
options?: ComponentOptions[];
} & Recordable;
export const handleTreeToComponentOptions = (data: any[], id?: string, parentId?: string, children?: string)=> {
const deptTree = handleTree(data, id, parentId, children)
return convertFieldToOptions(deptTree)
}
function convertFieldToOptions(deptTree: any[]): ComponentOptions[] {
return deptTree.map((item) => {
// 构建当前节点的基本结构
const option: ComponentOptions = {
label: item.name,
value: item.id,
key: item.id,
disabled: false, // 这里假设所有项默认都是启用的
};
// 如果存在子部门,递归调用转换函数
if (item.children && item.children.length > 0) {
const childrenOptions = convertFieldToOptions(item.children);
option.children = childrenOptions;
option.options = childrenOptions; // 确保 options 也被赋值
}
return option;
});
}

85
src/views/system/mail/template/MailTemplateForm.vue

@ -6,7 +6,7 @@
:title="dialogTitle" :title="dialogTitle"
:width="800" :width="800"
> >
<Form ref="formRef" v-loading="formLoading" :rules="rules" :schema="allSchemas.formSchema" /> <Form ref="formRef" v-loading="formLoading" :rules="rules" :schema="allSchemas.formSchema" @onChange="onChange" />
<template #footer> <template #footer>
<el-button :disabled="formLoading" type="primary" @click="submitForm"> </el-button> <el-button :disabled="formLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="dialogVisible = false"> </el-button> <el-button @click="dialogVisible = false"> </el-button>
@ -15,6 +15,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import * as MailTemplateApi from '@/api/system/mail/template' import * as MailTemplateApi from '@/api/system/mail/template'
import { fi } from 'element-plus/es/locale'
import { allSchemas, rules } from './template.data' import { allSchemas, rules } from './template.data'
defineOptions({ name: 'SystemMailTemplateForm' }) defineOptions({ name: 'SystemMailTemplateForm' })
@ -33,6 +34,7 @@ const open = async (type: string, id?: number) => {
dialogVisible.value = true dialogVisible.value = true
dialogTitle.value = t('action.' + type) dialogTitle.value = t('action.' + type)
formType.value = type formType.value = type
resetReceiverType()
// //
if (id) { if (id) {
formLoading.value = true formLoading.value = true
@ -42,6 +44,7 @@ const open = async (type: string, id?: number) => {
} finally { } finally {
formLoading.value = false formLoading.value = false
} }
showReceiver(formRef.value)
} }
} }
defineExpose({ open }) // open defineExpose({ open }) // open
@ -71,4 +74,84 @@ const submitForm = async () => {
formLoading.value = false formLoading.value = false
} }
} }
const onChange = async (field, cur) => {
if(field === 'receiverType'){
//
const setV = {
roleIdList: [],
deptIdList: [],
postIdList: [],
userIdList: []
};
//
formRef.value.setValues(setV);
//
const fieldsToDisable = ['roleIdList', 'deptIdList', 'postIdList', 'userIdList'];
fieldsToDisable.forEach(field => {
const item = allSchemas.formSchema.find(item => item.field === field);
if (item) {
item.componentProps.disabled = true;
}
});
// receiverType
const fieldMap = {
1: 'roleIdList',
2: 'deptIdList',
3: 'postIdList',
4: 'userIdList'
};
const enableField = fieldMap[cur];
if (enableField) {
const itemToEnable = allSchemas.formSchema.find(item => item.field === enableField);
if (itemToEnable) {
itemToEnable.componentProps.disabled = false;
}
}
}
}
const resetReceiverType = () => {
//
const setV = {
roleIdList: [],
deptIdList: [],
postIdList: [],
userIdList: []
};
//
formRef.value.setValues(setV);
//
const fieldsToDisable = ['roleIdList', 'deptIdList', 'postIdList', 'userIdList'];
fieldsToDisable.forEach(field => {
const item = allSchemas.formSchema.find(item => item.field === field);
if (item) {
item.componentProps.disabled = true;
}
});
}
const showReceiver = (formValue) => {
if(formValue){
// receiverType
const fieldMap = {
1: 'roleIdList',
2: 'deptIdList',
3: 'postIdList',
4: 'userIdList'
};
const enableField = fieldMap[formValue.receiverType];
if (enableField) {
const itemToEnable = allSchemas.formSchema.find(item => item.field === enableField);
if (itemToEnable) {
itemToEnable.componentProps.disabled = false;
}
}
}
}
</script> </script>

120
src/views/system/mail/template/template.data.ts

@ -2,9 +2,30 @@ import type { CrudSchema } from '@/hooks/web/useCrudSchemas'
import { dateFormatter } from '@/utils/formatTime' import { dateFormatter } from '@/utils/formatTime'
import { TableColumn } from '@/types/table' import { TableColumn } from '@/types/table'
import * as MailAccountApi from '@/api/system/mail/account' import * as MailAccountApi from '@/api/system/mail/account'
import { getIntDictOptions } from '@/utils/dict'
import { handleTreeToComponentOptions } from '@/utils/tree'
import * as RoleApi from '@/api/system/role'
import * as PostApi from '@/api/system/post'
import * as DeptApi from '@/api/system/dept'
import * as UserApi from '@/api/system/user'
// 邮箱账号的列表 // 邮箱账号的列表
const accountList = await MailAccountApi.getSimpleMailAccountList() const accountList = await MailAccountApi.getSimpleMailAccountList()
const receiverTypeOptions = getIntDictOptions(DICT_TYPE.RECEIVER_TYPE)
const roleList = ref([]) // 角色的列表
const deptList = ref<Tree[]>([]) // 树形结构
const postList = ref([]) // 岗位列表
const userList = ref([]) // 用户列表
// 获得角色列表
roleList.value = await RoleApi.getSimpleRoleList()
// 加载部门树(默认格式)
deptList.value = handleTreeToComponentOptions(await DeptApi.getSimpleDeptList())
// 加载岗位列表
postList.value = await PostApi.getSimplePostList()
// 加载用户列表
userList.value = await UserApi.getSimpleUserList()
// 表单校验 // 表单校验
export const rules = reactive({ export const rules = reactive({
@ -44,6 +65,105 @@ const crudSchemas = reactive<CrudSchema[]>([
} }
} }
}, },
{
label: '接收人类型',
field: 'receiverType',
isTable: false,
isDetail: false,
isSearch: false,
isTableForm: false,
form: {
component: 'Select',
componentProps: {
options: receiverTypeOptions, // 假设这是获取选项的函数
placeholder: "请选择角色"
}
}
},
{
label: '角色',
field: 'roleIdList',
isTable: false,
isDetail: false,
isSearch: false,
isTableForm: false,
form: {
component: 'Select',
componentProps: {
options: roleList.value,
optionsAlias: {
labelField: 'name',
valueField: 'id'
},
disabled: true,
filterable: true,
multiple: true,
placeholder: "请选择角色"
}
}
},
{
label: '部门',
field: 'deptIdList',
isTable: false,
isDetail: false,
isSearch: false,
isTableForm: false,
form: {
component: 'TreeSelect',
componentProps: { // 假设deptList是部门数据列表
data: deptList,
disabled: true,
placeholder: "请选择部门",
filterable: true,
multiple: true,
}
}
},
{
label: '岗位',
field: 'postIdList',
isTable: false,
isDetail: false,
isSearch: false,
isTableForm: false,
form: {
component: 'Select',
componentProps: {
options: postList.value,
optionsAlias: {
labelField: 'name',
valueField: 'id'
},
disabled: true,
filterable: true,
multiple: true,
placeholder: "请选择"
}
}
},
{
label: '用户',
field: 'userIdList',
isTable: false,
isDetail: false,
isSearch: false,
isTableForm: false,
form: {
component: 'Select',
componentProps: {
options: userList.value,
optionsAlias: {
labelField: 'nickname',
valueField: 'id'
},
disabled: true,
filterable: true,
multiple: true,
placeholder: "请选择"
}
}
},
{ {
label: '邮箱账号', label: '邮箱账号',
field: 'accountId', field: 'accountId',

276
src/views/system/messageSet/index.vue

@ -0,0 +1,276 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<Search :schema="MessageSet.allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />
</ContentWrap>
<!-- 列表头部 -->
<TableHead
:HeadButttondata="HeadButttondata"
@button-base-click="buttonBaseClick"
:routeName="routeName"
@updataTableColumns="updataTableColumns"
@searchFormClick="searchFormClick"
:allSchemas="MessageSet.allSchemas"
/>
<!-- 列表 -->
<ContentWrap>
<Table
:columns="tableColumns"
:data="tableObject.tableList"
:loading="tableObject.loading"
:pagination="{
total: tableObject.total
}"
v-model:pageSize="tableObject.pageSize"
v-model:currentPage="tableObject.currentPage"
v-model:sort="tableObject.sort"
>
<template #code="{row}">
<el-button type="primary" link @click="openDetail(row, '代码', row.code)">
<span>{{ row.code }}</span>
</el-button>
</template>
<template #action="{ row }">
<ButtonBase :Butttondata="butttondata" @button-base-click="buttonTableClick($event,row)" />
</template>
</Table>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<BasicForm
ref="basicFormRef"
@success="formsSuccess"
:rules="MessageSetRules"
:formAllSchemas="MessageSet.allSchemas"
:apiUpdate="MessageSetApi.updateMessageSet"
:apiCreate="MessageSetApi.createMessageSet"
@searchTableSuccess="searchTableSuccess"
:isBusiness="false"
@onChange="onChange"
/>
<!-- 详情 -->
<Detail ref="detailRef" :isBasic="true" :allSchemas="MessageSet.allSchemas" />
<!-- 导入 -->
<ImportForm ref="importFormRef" url="/system/message-set/import" :importTemplateData="importTemplateData" @success="importSuccess" />
</template>
<script setup lang="ts">
import download from '@/utils/download'
import { MessageSet,MessageSetRules } from './messageSet.data'
import * as MessageSetApi from '@/api/system/messageSet'
import * as defaultButtons from '@/utils/disposition/defaultButtons'
import TableHead from '@/components/TableHead/src/TableHead.vue'
import ImportForm from '@/components/ImportForm/src/ImportForm.vue'
import Detail from '@/components/Detail/src/Detail.vue'
import * as TableActionRelApi from '@/api/system/tableActionRel'
defineOptions({ name: 'MessageSet' })
const message = useMessage() //
const { t } = useI18n() //
const route = useRoute() //
const routeName = ref()
routeName.value = route.name
const tableColumns = ref(MessageSet.allSchemas.tableColumns)
//
const searchTableSuccess = (formField, searchField, val, formRef) => {
nextTick(() => {
const setV = {}
setV[formField] = val[0][searchField]
formRef.setValues(setV)
})
}
//
const updataTableColumns = (val) => {
tableColumns.value = val
}
const { tableObject, tableMethods } = useTable({
getListApi: MessageSetApi.getMessageSetPage //
})
//
const { getList, setSearchParams } = tableMethods
//
const HeadButttondata = [
defaultButtons.defaultAddBtn({hasPermi:'system:message-set:create'}), //
defaultButtons.defaultImportBtn({hasPermi:'system:message-set:import'}), //
defaultButtons.defaultExportBtn({hasPermi:'system:message-set:export'}), //
defaultButtons.defaultFreshBtn(null), //
defaultButtons.defaultFilterBtn(null), //
defaultButtons.defaultSetBtn(null), //
// {
// label: '',
// name: 'zdy',
// hide: false,
// type: 'primary',
// icon: 'Select',
// color: ''
// },
]
//
const buttonBaseClick = (val, item) => {
if (val == 'add') { //
openForm('create')
} else if (val == 'import') { //
handleImport()
} else if (val == 'export') { //
handleExport()
} else if (val == 'refresh') { //
getList()
} else if (val == 'filtrate') { //
} else { //
console.log('其他按钮', item)
}
}
// -
const butttondata = [
defaultButtons.mainListEditBtn({hasPermi:'system:message-set:update'}), //
defaultButtons.mainListDeleteBtn({hasPermi:'system:message-set:delete'}), //
]
// -
const buttonTableClick = async (val, row) => {
if (val == 'edit') { //
openForm('update', row)
} else if (val == 'delete') { //
handleDelete(row.id)
}
}
const tableActionRef = ref()
const alreadySelectedActionList = ref()
/** 添加/修改操作 */
const basicFormRef = ref()
const openForm = (type: string, row?: any) => {
TableActionRelApi.getTableActionRelNoPage({}).then(res=>{
tableActionRef.value = res
});
MessageSetApi.getMessageSetNoPage({}).then(res=>{
alreadySelectedActionList.value = res
});
basicFormRef.value.open(type, row)
}
// form
const formsSuccess = async (formType,data) => {
var isHave =MessageSet.allSchemas.formSchema.some(function (item) {
return item.field === 'activeTime' || item.field === 'expireTime';
});
if(isHave){
if(data.activeTime && data.expireTime && data.activeTime >=data.expireTime){
message.error('失效时间要大于生效时间')
return;
}
}
if(data.activeTime==0)data.activeTime = null;
if(data.expireTime==0)data.expireTime = null;
if (formType === 'create') {
await MessageSetApi.createMessageSet(data)
message.success(t('common.createSuccess'))
} else {
await MessageSetApi.updateMessageSet(data)
message.success(t('common.updateSuccess'))
}
basicFormRef.value.dialogVisible = false
getList()
}
/** 详情操作 */
const detailRef = ref()
const openDetail = (row: any, titleName: any, titleValue: any) => {
detailRef.value.openDetail(row, titleName, titleValue, 'basicMessageSet')
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await MessageSetApi.deleteMessageSet(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const exportLoading = ref(false) //
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await MessageSetApi.exportMessageSet(tableObject.params)
download.excel(data, '消息设置.xlsx')
} catch {
} finally {
exportLoading.value = false
}
}
/** 导入 */
const importFormRef = ref()
const handleImport = () => {
importFormRef.value.open()
}
//
const importTemplateData = reactive({
templateUrl: '',
templateTitle: '消息设置导入模版.xlsx'
})
//
const importSuccess = () => {
getList()
}
//
const searchFormClick = (searchData) => {
tableObject.params = {
isSearch: true,
filters: searchData.filters
}
getList() //
}
const onChange = (field, cur) => {
if (field == 'tableName') {
// curactionList
let actionList = tableActionRef.value.filter(element => element.tableName === cur);
// actionListalreadySelectedActionList
actionList = actionList.filter(element =>
!alreadySelectedActionList.value.some(elementA =>
element.tableName == elementA.tableName && element.act == elementA.act
)
);
// MessageSet.allSchemas.formSchemacomponentProps.options
const formItem = MessageSet.allSchemas.formSchema.find(element => element.field == 'act');
if (formItem && formItem.componentProps) {
formItem.componentProps.options = actionList;
formItem.componentProps.optionsAlias = { valueField: 'act', labelField: 'name' };
}
}
};
/** 初始化 **/
onMounted(async () => {
getList()
importTemplateData.templateUrl = await MessageSetApi.importTemplate()
})
</script>

156
src/views/system/messageSet/messageSet.data.ts

@ -0,0 +1,156 @@
import type { CrudSchema } from '@/hooks/web/useCrudSchemas'
import { dateFormatter } from '@/utils/formatTime'
import * as TableActionRelApi from '@/api/system/tableActionRel'
import { getStrDictOptions } from '@/utils/dict'
// 假设这是TableActionRelApi.getTableActionRelNoPage({})的返回类型
interface Table {
tableName: string;
tableLabel: string;
// 可以添加其他字段
}
// 假设的异步调用,这里假定返回类型为Table[]
const tableList: Table[] = await TableActionRelApi.getTableActionRelNoPage({});
const noticeTableList = getStrDictOptions(DICT_TYPE.MESSAGE_NOTICE_TABLE);
const noticeActionList = getStrDictOptions(DICT_TYPE.NOTICE_ACTION_TYPE);
// 使用Set记录已经出现过的tableName
const seen = new Set<string>();
// 使用filter方法去重
const uniqueTableList: Table[] = tableList.filter(table => {
if (seen.has(table.tableName)) {
// 如果seen中已经有了tableName,表示这个tableName已经处理过,应该被过滤掉
return false;
} else {
// 如果seen中没有tableName,将其添加到seen中,并保留在结果数组中
seen.add(table.tableName);
return true;
}
});
// 此时,uniqueTableList应该是去重后的结果
uniqueTableList.forEach(table => {
// 在noticeActionList中查找与当前table.tableName匹配的value
const matchingAction = noticeTableList.find(action => action.value === table.tableName);
// 如果找到了匹配项,就将其label值赋给table的tableLabel字段
if (matchingAction) {
table.tableLabel = matchingAction.label;
} else {
// 如果没有找到匹配项,可以根据需要决定是否给tableLabel赋一个默认值
table.tableLabel = ''; // 或者可以选择不赋值
}
});
const actionList = ref(tableList)
// 表单校验
export const MessageSetRules = reactive({
tableName: [required],
act: [required],
available: [required],
})
export const MessageSet = useCrudSchemas(reactive<CrudSchema[]>([
// {
// label: 'id',
// field: 'id',
// sort: 'custom',
// isForm: false,
// isSearch: false,
// isDetail: false,
// isTable: false,
// isTableForm: false,
// fixed: 'left'
// },
{
label: '表名',
field: 'tableName',
sort: 'custom',
isSearch: true,
formatter: (_: Recordable, __: TableColumn, cellValue: number) => {
return uniqueTableList.find(item=>cellValue==item.tableName).tableLabel
},
form: {
component: 'Select',
componentProps: {
options: uniqueTableList,
optionsAlias:{
labelField: 'tableLabel',
valueField: 'tableName'
}
}
},
search: {
component: 'Select',
componentProps: {
options: uniqueTableList,
optionsAlias:{
labelField: 'tableLabel',
valueField: 'tableName'
},
onChange: (val) => {{
actionList.value = tableList.filter(item=>item.tableName==val)
}}
},
}
},
{
label: '动作',
field: 'act',
sort: 'custom',
isSearch: true,
formatter: (_: Recordable, __: TableColumn, cellValue: number) => {
return noticeActionList.find(item=>cellValue==item.value).label
},
form: {
component: 'Select',
componentProps: {
options: noticeActionList,
optionsAlias: {
valueField: 'value',
labelField: 'label'
}
}
},
search: {
component: 'Select',
componentProps: {
options: actionList.value,
optionsAlias: {
valueField: 'act',
labelField: 'name'
}
}
}
},
{
label: '是否可用',
field: 'available',
sort: 'custom',
isSearch: true,
dictType: DICT_TYPE.FALSE_OR_TRUE,
dictClass: 'string', // 默认都是字符串类型其他暂不考虑
form: {
component: 'SelectV2',
}
},
{
label: '备注',
field: 'remark',
sort: 'custom',
isSearch: true
},
{
label: '操作',
field: 'action',
isForm: false,
table: {
width: 150,
fixed: 'right'
}
}
]))

132
src/views/system/notify/template/NotifyTemplateForm.vue

@ -21,6 +21,52 @@
<el-option v-for="item in roleList" :key="item.id" :label="item.name" :value="item.id" /> <el-option v-for="item in roleList" :key="item.id" :label="item.name" :value="item.id" />
/></el-select> /></el-select>
</el-form-item> </el-form-item>
<el-form-item label="接收人类型" prop="receiverType">
<el-select v-model="formData.receiverType" @change="onChangeReceiverType" placeholder="请选择角色">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.RECEIVER_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/></el-select>
</el-form-item>
<el-form-item v-show="roleShow" label="角色" prop="roleIdList">
<el-select v-model="formData.roleIdList" filterable multiple placeholder="请选择角色">
<el-option v-for="item in roleList" :key="item.id" :label="item.name" :value="item.id" />
/></el-select>
</el-form-item>
<el-form-item v-show="deptShow" label="部门" prop="deptIdList">
<el-tree-select
v-model="formData.deptIdList"
:data="deptList"
:props="defaultProps"
check-strictly
node-key="id"
placeholder="请选择部门"
filterable
multiple
/>
</el-form-item>
<el-form-item v-show="postShow" label="岗位" prop="postIdList">
<el-select v-model="formData.postIdList" filterable multiple placeholder="请选择">
<el-option
v-for="item in postList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item v-show="userShow" label="用户" prop="userIdList">
<el-select v-model="formData.userIdList" filterable multiple placeholder="请选择">
<el-option
v-for="item in userList"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="模板内容" prop="content"> <el-form-item label="模板内容" prop="content">
<el-input type="textarea" v-model="formData.content" placeholder="请输入模板内容" /> <el-input type="textarea" v-model="formData.content" placeholder="请输入模板内容" />
</el-form-item> </el-form-item>
@ -59,7 +105,11 @@
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import * as NotifyTemplateApi from '@/api/system/notify/template' import * as NotifyTemplateApi from '@/api/system/notify/template'
import { CommonStatusEnum } from '@/utils/constants' import { CommonStatusEnum } from '@/utils/constants'
import { defaultProps, handleTree } from '@/utils/tree'
import * as RoleApi from '@/api/system/role' import * as RoleApi from '@/api/system/role'
import * as PostApi from '@/api/system/post'
import * as DeptApi from '@/api/system/dept'
import * as UserApi from '@/api/system/user'
const message = useMessage() // const message = useMessage() //
const dialogVisible = ref(false) // const dialogVisible = ref(false) //
@ -67,6 +117,13 @@ const dialogTitle = ref('') // 弹窗的标题
const formLoading = ref(false) // 12 const formLoading = ref(false) // 12
const formType = ref('') // const formType = ref('') //
const roleList = ref([]) // const roleList = ref([]) //
const deptList = ref<Tree[]>([]) //
const postList = ref([]) //
const userList = ref([]) //
const userShow = ref(false)
const roleShow = ref(false)
const deptShow = ref(false)
const postShow = ref(false)
const formData = ref<NotifyTemplateApi.NotifyTemplateVO>({ const formData = ref<NotifyTemplateApi.NotifyTemplateVO>({
id: null, id: null,
@ -78,7 +135,11 @@ const formData = ref<NotifyTemplateApi.NotifyTemplateVO>({
roleIds: [], roleIds: [],
params: '', params: '',
status: CommonStatusEnum.ENABLE, status: CommonStatusEnum.ENABLE,
remark: '' remark: '',
roleIdList: [],
deptIdList: [],
postIdList: [],
userIdList: []
}) })
const formRules = reactive({ const formRules = reactive({
type: [{ required: true, message: '消息类型不能为空', trigger: 'change' }], type: [{ required: true, message: '消息类型不能为空', trigger: 'change' }],
@ -97,6 +158,10 @@ const open = async (type: string, id?: number) => {
dialogTitle.value = type dialogTitle.value = type
formType.value = type formType.value = type
resetForm() resetForm()
//
getReceiverData()
//
resetReceiverType()
// //
if (id) { if (id) {
formLoading.value = true formLoading.value = true
@ -105,9 +170,8 @@ const open = async (type: string, id?: number) => {
} finally { } finally {
formLoading.value = false formLoading.value = false
} }
showReceiver(formData.value)
} }
//
roleList.value = await RoleApi.getSimpleRoleList()
} }
defineExpose({ open }) // open defineExpose({ open }) // open
@ -125,6 +189,7 @@ const submitForm = async () => {
await NotifyTemplateApi.createNotifyTemplate(data) await NotifyTemplateApi.createNotifyTemplate(data)
message.success('新增成功') message.success('新增成功')
} else { } else {
debugger
await NotifyTemplateApi.updateNotifyTemplate(data) await NotifyTemplateApi.updateNotifyTemplate(data)
message.success('修改成功') message.success('修改成功')
} }
@ -146,8 +211,67 @@ const resetForm = () => {
type: null, type: null,
params: '', params: '',
status: CommonStatusEnum.ENABLE, status: CommonStatusEnum.ENABLE,
remark: '' remark: '',
postIdList: [],
userIdList: [],
deptIdList: [],
roleIdList: [],
} }
formRef.value?.resetFields() formRef.value?.resetFields()
} }
const onChangeReceiverType = (val) => {
//
resetReceiverType()
// val
if (val === 1) {
roleShow.value = true;
} else if (val === 2) {
deptShow.value = true;
} else if (val === 3) {
postShow.value = true;
} else if (val === 4) {
userShow.value = true;
}
// val === '5'false
}
const getReceiverData = async() =>{
//
roleList.value = await RoleApi.getSimpleRoleList()
//
deptList.value = handleTree(await DeptApi.getSimpleDeptList())
//
postList.value = await PostApi.getSimplePostList()
//
userList.value = await UserApi.getSimpleUserList()
}
const resetReceiverType = () => {
formData.value.postIdList = [];
formData.value.userIdList = [];
formData.value.deptIdList = [];
formData.value.roleIdList = [];
roleShow.value = false;
deptShow.value = false;
postShow.value = false;
userShow.value = false;
}
const showReceiver = (formValue) => {
if(formValue){
if(formValue.receiverType == 1){
roleShow.value = true;
}else if(formValue.receiverType == 2){
deptShow.value = true;
}else if(formValue.receiverType == 3){
postShow.value = true;
}else if(formValue.receiverType == 4){
userShow.value = true;
}
}
}
</script> </script>

130
src/views/system/sms/template/SmsTemplateForm.vue

@ -35,6 +35,51 @@
</el-form-item> </el-form-item>
<el-form-item label="模板名称" prop="name"> <el-form-item label="模板名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入模板名称" /> <el-input v-model="formData.name" placeholder="请输入模板名称" />
</el-form-item><el-form-item label="" prop="receiverType">
<el-select v-model="formData.receiverType" @change="onChangeReceiverType" placeholder="请选择角色">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.RECEIVER_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/></el-select>
</el-form-item>
<el-form-item v-show="roleShow" label="角色" prop="roleIdList">
<el-select v-model="formData.roleIdList" filterable multiple placeholder="请选择角色">
<el-option v-for="item in roleList" :key="item.id" :label="item.name" :value="item.id" />
/></el-select>
</el-form-item>
<el-form-item v-show="deptShow" label="部门" prop="deptIdList">
<el-tree-select
v-model="formData.deptIdList"
:data="deptList"
:props="defaultProps"
check-strictly
node-key="id"
placeholder="请选择部门"
filterable
multiple
/>
</el-form-item>
<el-form-item v-show="postShow" label="岗位" prop="postIdList">
<el-select v-model="formData.postIdList" filterable multiple placeholder="请选择">
<el-option
v-for="item in postList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item v-show="userShow" label="用户" prop="userIdList">
<el-select v-model="formData.userIdList" filterable multiple placeholder="请选择">
<el-option
v-for="item in userList"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select>
</el-form-item> </el-form-item>
<el-form-item label="模板内容" prop="content"> <el-form-item label="模板内容" prop="content">
<el-input v-model="formData.content" placeholder="请输入模板内容" type="textarea" /> <el-input v-model="formData.content" placeholder="请输入模板内容" type="textarea" />
@ -68,6 +113,12 @@ import { DICT_TYPE, getDictLabel, getIntDictOptions } from '@/utils/dict'
import * as SmsTemplateApi from '@/api/system/sms/smsTemplate' import * as SmsTemplateApi from '@/api/system/sms/smsTemplate'
import * as SmsChannelApi from '@/api/system/sms/smsChannel' import * as SmsChannelApi from '@/api/system/sms/smsChannel'
import { CommonStatusEnum } from '@/utils/constants' import { CommonStatusEnum } from '@/utils/constants'
import { defaultProps, handleTree } from '@/utils/tree'
import * as RoleApi from '@/api/system/role'
import * as PostApi from '@/api/system/post'
import * as DeptApi from '@/api/system/dept'
import * as UserApi from '@/api/system/user'
import { async } from '@antv/x6/lib/registry/marker/async'
defineOptions({ name: 'SystemSmsTemplateForm' }) defineOptions({ name: 'SystemSmsTemplateForm' })
@ -78,6 +129,14 @@ const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') // const dialogTitle = ref('') //
const formLoading = ref(false) // 12 const formLoading = ref(false) // 12
const formType = ref('') // const formType = ref('') //
const roleList = ref([]) //
const deptList = ref<Tree[]>([]) //
const postList = ref([]) //
const userList = ref([]) //
const userShow = ref(false)
const roleShow = ref(false)
const deptShow = ref(false)
const postShow = ref(false)
const formData = ref<SmsTemplateApi.SmsTemplateVO>({ const formData = ref<SmsTemplateApi.SmsTemplateVO>({
id: null, id: null,
type: null, type: null,
@ -87,7 +146,11 @@ const formData = ref<SmsTemplateApi.SmsTemplateVO>({
content: '', content: '',
remark: '', remark: '',
apiTemplateId: '', apiTemplateId: '',
channelId: null channelId: null,
roleIdList: [],
deptIdList: [],
postIdList: [],
userIdList: []
}) })
const formRules = reactive({ const formRules = reactive({
type: [{ required: true, message: '短信类型不能为空', trigger: 'change' }], type: [{ required: true, message: '短信类型不能为空', trigger: 'change' }],
@ -106,6 +169,10 @@ const open = async (type: string, id?: number) => {
dialogTitle.value = t('action.' + type) dialogTitle.value = t('action.' + type)
formType.value = type formType.value = type
resetForm() resetForm()
//
getReceiverData()
//
resetReceiverType()
// //
if (id) { if (id) {
formLoading.value = true formLoading.value = true
@ -114,6 +181,7 @@ const open = async (type: string, id?: number) => {
} finally { } finally {
formLoading.value = false formLoading.value = false
} }
showReceiver(formData.value)
} }
// //
channelList.value = await SmsChannelApi.getSimpleSmsChannelList() channelList.value = await SmsChannelApi.getSimpleSmsChannelList()
@ -156,8 +224,66 @@ const resetForm = () => {
content: '', content: '',
remark: '', remark: '',
apiTemplateId: '', apiTemplateId: '',
channelId: null channelId: null,
roleIdList: [],
deptIdList: [],
postIdList: [],
userIdList: []
} }
formRef.value?.resetFields() formRef.value?.resetFields()
} }
const onChangeReceiverType = (val) => {
//
resetReceiverType()
// val
if (val === 1) {
roleShow.value = true;
} else if (val === 2) {
deptShow.value = true;
} else if (val === 3) {
postShow.value = true;
} else if (val === 4) {
userShow.value = true;
}
// val === '5'false
}
const getReceiverData = async() =>{
//
roleList.value = await RoleApi.getSimpleRoleList()
//
deptList.value = handleTree(await DeptApi.getSimpleDeptList())
//
postList.value = await PostApi.getSimplePostList()
//
userList.value = await UserApi.getSimpleUserList()
}
const resetReceiverType = () => {
formData.value.postIdList = [];
formData.value.userIdList = [];
formData.value.deptIdList = [];
formData.value.roleIdList = [];
roleShow.value = false;
deptShow.value = false;
postShow.value = false;
userShow.value = false;
}
const showReceiver = (formValue) => {
if(formValue){
if(formValue.receiverType == 1){
roleShow.value = true;
}else if(formValue.receiverType == 2){
deptShow.value = true;
}else if(formValue.receiverType == 3){
postShow.value = true;
}else if(formValue.receiverType == 4){
userShow.value = true;
}
}
}
</script> </script>

275
src/views/system/tableActionRel/index.vue

@ -0,0 +1,275 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<Search :schema="TableActionRel.allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />
</ContentWrap>
<!-- 列表头部 -->
<TableHead
:HeadButttondata="HeadButttondata"
@button-base-click="buttonBaseClick"
:routeName="routeName"
@updataTableColumns="updataTableColumns"
@searchFormClick="searchFormClick"
:allSchemas="TableActionRel.allSchemas"
/>
<!-- 列表 -->
<ContentWrap>
<Table
:columns="tableColumns"
:data="tableObject.tableList"
:loading="tableObject.loading"
:pagination="{
total: tableObject.total
}"
v-model:pageSize="tableObject.pageSize"
v-model:currentPage="tableObject.currentPage"
v-model:sort="tableObject.sort"
>
<template #code="{row}">
<el-button type="primary" link @click="openDetail(row, '代码', row.code)">
<span>{{ row.code }}</span>
</el-button>
</template>
<template #action="{ row }">
<ButtonBase :Butttondata="butttondata" @button-base-click="buttonTableClick($event,row)" />
</template>
</Table>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<BasicForm
ref="basicFormRef"
@success="formsSuccess"
:rules="TableActionRelRules"
:formAllSchemas="TableActionRel.allSchemas"
:apiUpdate="TableActionRelApi.updateTableActionRel"
:apiCreate="TableActionRelApi.createTableActionRel"
@searchTableSuccess="searchTableSuccess"
:isBusiness="false"
@onChange="onChange"
/>
<!-- 详情 -->
<Detail ref="detailRef" :isBasic="true" :allSchemas="TableActionRel.allSchemas" />
<!-- 导入 -->
<ImportForm ref="importFormRef" url="/system/table-action-rel/import" :importTemplateData="importTemplateData" @success="importSuccess" />
</template>
<script setup lang="ts">
import download from '@/utils/download'
import { TableActionRel,TableActionRelRules } from './tableActionRel.data'
import * as TableActionRelApi from '@/api/system/tableActionRel'
import * as defaultButtons from '@/utils/disposition/defaultButtons'
import TableHead from '@/components/TableHead/src/TableHead.vue'
import ImportForm from '@/components/ImportForm/src/ImportForm.vue'
import Detail from '@/components/Detail/src/Detail.vue'
import { getStrDictOptions } from '@/utils/dict'
defineOptions({ name: 'TableActionRel' })
const message = useMessage() //
const { t } = useI18n() //
const route = useRoute() //
const routeName = ref()
routeName.value = route.name
const tableColumns = ref(TableActionRel.allSchemas.tableColumns)
const noticeActionList = getStrDictOptions(DICT_TYPE.NOTICE_ACTION_TYPE)
const noticeActionListA = getStrDictOptions(DICT_TYPE.NOTICE_ACTION_TYPE)
//
const searchTableSuccess = (formField, searchField, val, formRef) => {
nextTick(() => {
const setV = {}
setV[formField] = val[0][searchField]
formRef.setValues(setV)
})
}
//
const updataTableColumns = (val) => {
tableColumns.value = val
}
const { tableObject, tableMethods } = useTable({
getListApi: TableActionRelApi.getTableActionRelPage //
})
//
const { getList, setSearchParams } = tableMethods
//
const HeadButttondata = [
defaultButtons.defaultAddBtn({hasPermi:'system:table-action-rel:create'}), //
defaultButtons.defaultImportBtn({hasPermi:'system:table-action-rel:import'}), //
defaultButtons.defaultExportBtn({hasPermi:'system:table-action-rel:export'}), //
defaultButtons.defaultFreshBtn(null), //
defaultButtons.defaultFilterBtn(null), //
defaultButtons.defaultSetBtn(null), //
// {
// label: '',
// name: 'zdy',
// hide: false,
// type: 'primary',
// icon: 'Select',
// color: ''
// },
]
//
const buttonBaseClick = (val, item) => {
if (val == 'add') { //
openForm('create')
} else if (val == 'import') { //
handleImport()
} else if (val == 'export') { //
handleExport()
} else if (val == 'refresh') { //
getList()
} else if (val == 'filtrate') { //
} else { //
console.log('其他按钮', item)
}
}
// -
const butttondata = [
defaultButtons.mainListEditBtn({hasPermi:'system:table-action-rel:update'}), //
defaultButtons.mainListDeleteBtn({hasPermi:'system:table-action-rel:delete'}), //
]
// -
const buttonTableClick = async (val, row) => {
if (val == 'edit') { //
openForm('update', row)
} else if (val == 'delete') { //
handleDelete(row.id)
}
}
const tableActionRef = ref()
/** 添加/修改操作 */
const basicFormRef = ref()
const openForm = (type: string, row?: any) => {
TableActionRelApi.getTableActionRelNoPage({}).then(res=>{
tableActionRef.value = res
});
basicFormRef.value.open(type, row)
}
// form
const formsSuccess = async (formType,data) => {
var isHave =TableActionRel.allSchemas.formSchema.some(function (item) {
return item.field === 'activeTime' || item.field === 'expireTime';
});
if(isHave){
if(data.activeTime && data.expireTime && data.activeTime >=data.expireTime){
message.error('失效时间要大于生效时间')
return;
}
}
if(data.activeTime==0)data.activeTime = null;
if(data.expireTime==0)data.expireTime = null;
if (formType === 'create') {
await TableActionRelApi.createTableActionRel(data)
message.success(t('common.createSuccess'))
} else {
await TableActionRelApi.updateTableActionRel(data)
message.success(t('common.updateSuccess'))
}
basicFormRef.value.dialogVisible = false
getList()
}
/** 详情操作 */
const detailRef = ref()
const openDetail = (row: any, titleName: any, titleValue: any) => {
detailRef.value.openDetail(row, titleName, titleValue, 'basicTableActionRel')
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await TableActionRelApi.deleteTableActionRel(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const exportLoading = ref(false) //
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await TableActionRelApi.exportTableActionRel(tableObject.params)
download.excel(data, '表名动作关系.xlsx')
} catch {
} finally {
exportLoading.value = false
}
}
/** 导入 */
const importFormRef = ref()
const handleImport = () => {
importFormRef.value.open()
}
//
const importTemplateData = reactive({
templateUrl: '',
templateTitle: '表名动作关系导入模版.xlsx'
})
//
const importSuccess = () => {
getList()
}
//
const searchFormClick = (searchData) => {
tableObject.params = {
isSearch: true,
filters: searchData.filters
}
getList() //
}
const onChange = (field,cur,item)=>{
if(field == 'act'){
nextTick(() => {
const actName = noticeActionList.find(item=>item.value == cur)?.label
const setV = {}
setV['name'] = actName
item.value.setValues(setV)
})
}
if(field == 'tableName'){
// actionListalreadySelectedActionList
let actionList = noticeActionListA.filter(element =>
!tableActionRef.value.some(elementA =>
cur == elementA.tableName && element.value == elementA.act
)
);
// MessageSet.allSchemas.formSchemacomponentProps.options
const formItem = TableActionRel.allSchemas.formSchema.find(element => element.field == 'act');
if (formItem && formItem.componentProps) {
formItem.componentProps.options = actionList;
}
}
}
/** 初始化 **/
onMounted(async () => {
getList()
importTemplateData.templateUrl = await TableActionRelApi.importTemplate()
})
</script>

144
src/views/system/tableActionRel/tableActionRel.data.ts

@ -0,0 +1,144 @@
import type { CrudSchema } from '@/hooks/web/useCrudSchemas'
import { dateFormatter } from '@/utils/formatTime'
// 表单校验
export const TableActionRelRules = reactive({
tableName: [required],
available: [required],
concurrencyStamp: [required]
})
export const TableActionRel = useCrudSchemas(reactive<CrudSchema[]>([
// {
// label: 'id',
// field: 'id',
// sort: 'custom',
// isForm: false,
// isSearch: false,
// isDetail: false,
// isTable: false,
// isTableForm: false,
// fixed: 'left'
// },
{
label: '表名',
field: 'tableName',
sort: 'custom',
dictType: DICT_TYPE.MESSAGE_NOTICE_TABLE,
dictClass: 'string', // 默认都是字符串类型其他暂不考虑
isSearch: true,
form: {
component: 'SelectV2',
componentProps: {
filterable: true,
}
},
search: {
component: 'SelectV2',
componentProps: {
filterable: true,
}
}
},
{
label: '动作',
field: 'act',
sort: 'custom',
isSearch: true,
isDetail: false,
dictType: DICT_TYPE.NOTICE_ACTION_TYPE,
dictClass: 'string', // 默认都是字符串类型其他暂不考虑
form: {
component: 'SelectV2',
componentProps: {
filterable: true,
}
},
search: {
component: 'SelectV2',
componentProps: {
filterable: true,
}
}
},
{
label: '动作',
field: 'name',
sort: 'custom',
isForm: false,
isSearch: false,
isDetail: true,
isTable: false,
isTableForm: false,
},
{
label: '是否可用',
field: 'available',
sort: 'custom',
isSearch: true,
dictType: DICT_TYPE.FALSE_OR_TRUE,
dictClass: 'string', // 默认都是字符串类型其他暂不考虑
form: {
component: 'SelectV2',
}
},
{
label: '生效时间',
field: 'activeTime',
sort: 'custom',
formatter: dateFormatter,
isSearch: true,
search: {
component: 'DatePicker',
componentProps: {
valueFormat: 'YYYY-MM-DD HH:mm:ss',
type: 'daterange',
defaultTime: [new Date('1 00:00:00'), new Date('1 23:59:59')]
}
},
form: {
component: 'DatePicker',
componentProps: {
type: 'datetime',
valueFormat: 'x'
}
}
},
{
label: '失效时间',
field: 'expireTime',
sort: 'custom',
formatter: dateFormatter,
isSearch: true,
search: {
component: 'DatePicker',
componentProps: {
valueFormat: 'YYYY-MM-DD HH:mm:ss',
type: 'daterange',
defaultTime: [new Date('1 00:00:00'), new Date('1 23:59:59')]
}
},
form: {
component: 'DatePicker',
componentProps: {
type: 'datetime',
valueFormat: 'x'
}
}
},
{
label: '备注',
field: 'remark',
sort: 'custom',
isSearch: true
},
{
label: '操作',
field: 'action',
isForm: false,
table: {
width: 150,
fixed: 'right'
}
}
]))
Loading…
Cancel
Save