19 changed files with 1205 additions and 87 deletions
@ -0,0 +1,15 @@ |
|||||
|
import { request } from '@/utils/request'; |
||||
|
|
||||
|
/** |
||||
|
* @description 附件上传 |
||||
|
* @param {} data |
||||
|
* @returns |
||||
|
*/ |
||||
|
export function commonUpload(data) { |
||||
|
return request({ |
||||
|
url: `/file/upload`, |
||||
|
method: 'post', |
||||
|
data, |
||||
|
timeout: 30000, |
||||
|
}); |
||||
|
} |
@ -0,0 +1,3 @@ |
|||||
|
declare namespace API { |
||||
|
|
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
export function downloadByData(data: BlobPart, filename: string, mime?: string, bom?: BlobPart) { |
||||
|
const blobData = typeof bom !== 'undefined' ? [bom, data] : [data]; |
||||
|
const blob = new Blob(blobData, { type: mime || 'application/vnd.ms-excel' }); |
||||
|
|
||||
|
const blobURL = window.URL.createObjectURL(blob); |
||||
|
const tempLink = document.createElement('a'); |
||||
|
tempLink.style.display = 'none'; |
||||
|
tempLink.href = blobURL; |
||||
|
tempLink.setAttribute('download', filename); |
||||
|
if (typeof tempLink.download === 'undefined') { |
||||
|
tempLink.setAttribute('target', '_blank'); |
||||
|
} |
||||
|
document.body.appendChild(tempLink); |
||||
|
tempLink.click(); |
||||
|
document.body.removeChild(tempLink); |
||||
|
window.URL.revokeObjectURL(blobURL); |
||||
|
} |
||||
|
|
||||
|
export function getFileExtension(filename: string): string | null { |
||||
|
const dotIndex = filename.lastIndexOf('.'); |
||||
|
if (dotIndex === -1) { |
||||
|
return null; // 文件名中不存在扩展名
|
||||
|
} |
||||
|
return filename.slice(dotIndex + 1).toLowerCase(); |
||||
|
} |
@ -1,14 +1,32 @@ |
|||||
export const sexTypeList:any = [ |
|
||||
|
export const stateTypeList: any = [ |
||||
|
// Init(0,"初始化"),
|
||||
|
// Back(1,"退回"),
|
||||
|
// Develop(2,"开发"),
|
||||
|
// Test(3,"测试"),
|
||||
|
// End(4,"结束"),
|
||||
{ |
{ |
||||
label: '男', |
|
||||
|
label: '初始化', |
||||
|
value: 0, |
||||
|
color: '#f50', |
||||
|
}, |
||||
|
{ |
||||
|
label: '退回', |
||||
value: 1, |
value: 1, |
||||
|
color: '#2db7f5', |
||||
}, |
}, |
||||
{ |
{ |
||||
label: '女', |
|
||||
|
label: '开发', |
||||
value: 2, |
value: 2, |
||||
|
color: '#87d068', |
||||
}, |
}, |
||||
{ |
{ |
||||
label: '未知', |
|
||||
|
label: '测试', |
||||
value: 3, |
value: 3, |
||||
|
color: '#108ee9', |
||||
|
}, |
||||
|
{ |
||||
|
label: '结束', |
||||
|
value: 4, |
||||
|
color: '#f50', |
||||
}, |
}, |
||||
]; |
]; |
||||
|
@ -1,21 +0,0 @@ |
|||||
import type { FormSchema } from '@/components/core/schema-form/'; |
|
||||
|
|
||||
export const issueSchemas: FormSchema<API.CreateIssueParams>[] = [ |
|
||||
{ |
|
||||
field: 'title', |
|
||||
component: 'Input', |
|
||||
label: '账号', |
|
||||
colProps: { |
|
||||
span: 12, |
|
||||
}, |
|
||||
rules: [{ required: true }], |
|
||||
}, |
|
||||
{ |
|
||||
field: 'content', |
|
||||
label: '内容', |
|
||||
slot: 'content', |
|
||||
colProps: { |
|
||||
span: 12, |
|
||||
}, |
|
||||
}, |
|
||||
]; |
|
@ -0,0 +1,171 @@ |
|||||
|
import type { FormSchema } from '@/components/core/schema-form/'; |
||||
|
import { TableListItem } from './columns'; |
||||
|
import { commonUpload } from '@/api/upload'; |
||||
|
import { message, Button } from 'ant-design-vue'; |
||||
|
import { getFileExtension } from '@/utils/fileUtils'; |
||||
|
import { UploadOutlined } from '@ant-design/icons-vue'; |
||||
|
import { stateTypeList } from './data'; |
||||
|
import { url } from 'inspector'; |
||||
|
import component from '@/locales/lang/en-US/component'; |
||||
|
// 编辑页字段
|
||||
|
export const getEditFormSchema: ( |
||||
|
row?: Partial<TableListItem>, |
||||
|
isDetail?: boolean, |
||||
|
) => FormSchema[] = (record = {}, isDetail = false) => { |
||||
|
return [ |
||||
|
{ |
||||
|
field: 'title', |
||||
|
component: 'Input', |
||||
|
label: '问题标题', |
||||
|
colProps: { |
||||
|
span: 12, |
||||
|
}, |
||||
|
rules: [{ required: true }], |
||||
|
}, |
||||
|
|
||||
|
{ |
||||
|
field: 'billcode', |
||||
|
component: 'Input', |
||||
|
label: '问题号', |
||||
|
colProps: { |
||||
|
span: 12, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'customer', |
||||
|
component: 'Input', |
||||
|
label: '客户', |
||||
|
colProps: { |
||||
|
span: 12, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'product', |
||||
|
component: 'Input', |
||||
|
label: '产品', |
||||
|
colProps: { |
||||
|
span: 12, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'agent', |
||||
|
component: 'Input', |
||||
|
label: '代理商', |
||||
|
colProps: { |
||||
|
span: 12, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'attribute', |
||||
|
component: 'Input', |
||||
|
label: '问题属性', |
||||
|
colProps: { |
||||
|
span: 12, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'serviceNumber', |
||||
|
component: 'Input', |
||||
|
label: '服务号', |
||||
|
colProps: { |
||||
|
span: 12, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'contacts', |
||||
|
component: 'Input', |
||||
|
label: '联系人', |
||||
|
colProps: { |
||||
|
span: 12, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'contactsEmail', |
||||
|
component: 'Input', |
||||
|
label: '联系人邮箱', |
||||
|
colProps: { |
||||
|
span: 12, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'contactsMobile', |
||||
|
component: 'Input', |
||||
|
label: '联系人手机号', |
||||
|
colProps: { |
||||
|
span: 12, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'state', |
||||
|
component: 'Select', |
||||
|
label: '状态', |
||||
|
colProps: { |
||||
|
span: 12, |
||||
|
}, |
||||
|
componentProps: { |
||||
|
options: stateTypeList, |
||||
|
}, |
||||
|
rules: [{ required: true, type: 'number' }], |
||||
|
}, |
||||
|
{ |
||||
|
field: 'description', |
||||
|
component: 'InputTextArea', |
||||
|
componentProps: { |
||||
|
rows: 4, |
||||
|
placeholder: '请输入问题描述', |
||||
|
}, |
||||
|
label: '问题描述', |
||||
|
colProps: { |
||||
|
span: 24, |
||||
|
}, |
||||
|
rules: [{ required: true }], |
||||
|
}, |
||||
|
{ |
||||
|
label: '描述附件', |
||||
|
field: 'fileList', |
||||
|
component: 'Upload', |
||||
|
componentProps: { |
||||
|
disabled: isDetail, |
||||
|
customRequest: async (data) => { |
||||
|
console.log('data: ', data); |
||||
|
const formData = new FormData(); |
||||
|
formData.append('file', data.file); |
||||
|
const res = await commonUpload(formData); |
||||
|
console.log('res: ', res); |
||||
|
data?.onSuccess && data?.onSuccess(res, data.file as any); |
||||
|
}, |
||||
|
beforeUpload: (file) => { |
||||
|
console.log('file: ', file); |
||||
|
|
||||
|
// 限制允许上传的文件类型
|
||||
|
const allowedTypes = ['xlsx', 'xls', 'doc', 'docx', 'pdf']; |
||||
|
|
||||
|
// 检查文件类型
|
||||
|
const fileType = getFileExtension(file.name) || 'unknown'; |
||||
|
if (!allowedTypes.includes(fileType)) { |
||||
|
// 文件类型不在允许列表中,拒绝上传
|
||||
|
// 可以在这里展示错误信息
|
||||
|
message.warning('文件类型不正确'); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// 其他验证逻辑...
|
||||
|
|
||||
|
// 允许上传
|
||||
|
return true; |
||||
|
}, |
||||
|
}, |
||||
|
componentSlots: { |
||||
|
default: () => ( |
||||
|
<Button> |
||||
|
<UploadOutlined /> 点击上传 |
||||
|
</Button> |
||||
|
), |
||||
|
}, |
||||
|
colProps: { |
||||
|
span: 24, |
||||
|
}, |
||||
|
rules: [{ required: false }], |
||||
|
}, |
||||
|
] as any; |
||||
|
}; |
@ -0,0 +1,363 @@ |
|||||
|
import { debounce } from 'lodash-es'; |
||||
|
import type { TableColumn } from '@/components/core/dynamic-table'; |
||||
|
import { formatToDateTime } from '@/utils/dateUtil'; |
||||
|
import { updateUser } from '@/api/user'; |
||||
|
import { h } from 'vue'; |
||||
|
import { Switch } from 'ant-design-vue'; |
||||
|
import { sexTypeList } from './data'; |
||||
|
export type TableListItem = API.UserInfoType; |
||||
|
export type TableColumnItem = TableColumn<TableListItem>; |
||||
|
// 数据项类型
|
||||
|
// export type ListItemType = typeof tableData[number];
|
||||
|
// 使用TableColumn<ListItemType> 将会限制dataIndex的类型,但换来的是dataIndex有类型提示
|
||||
|
export const baseColumns: TableColumnItem[] = [ |
||||
|
{ |
||||
|
title: '账号', |
||||
|
align: 'center', |
||||
|
dataIndex: 'account', |
||||
|
// sorter: true,
|
||||
|
width: 150, |
||||
|
resizable: true, |
||||
|
formItemProps: { |
||||
|
defaultValue: '', |
||||
|
required: false, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
title: '姓名', |
||||
|
align: 'center', |
||||
|
dataIndex: 'username', |
||||
|
width: 150, |
||||
|
resizable: true, |
||||
|
formItemProps: { |
||||
|
defaultValue: '', |
||||
|
required: false, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
title: '手机号码', |
||||
|
align: 'center', |
||||
|
dataIndex: 'mobile', |
||||
|
width: 150, |
||||
|
formItemProps: { |
||||
|
defaultValue: '', |
||||
|
required: false, |
||||
|
}, |
||||
|
}, |
||||
|
|
||||
|
{ |
||||
|
title: '性别', |
||||
|
align: 'center', |
||||
|
dataIndex: 'sex', |
||||
|
width: 100, |
||||
|
hideInSearch: true, |
||||
|
formItemProps: { |
||||
|
defaultValue: '', |
||||
|
required: false, |
||||
|
component: 'Select', |
||||
|
label: '性别', |
||||
|
componentProps: { |
||||
|
mode: 'single', |
||||
|
request: async () => { |
||||
|
// const data = await getSexList();
|
||||
|
return sexTypeList; |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
customRender: ({ record }) => { |
||||
|
const text = sexTypeList.find((e) => e.value === record.sex)?.label; |
||||
|
return <div>{text}</div>; |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
title: '帐号状态', |
||||
|
align: 'center', |
||||
|
width: 100, |
||||
|
dataIndex: 'state', |
||||
|
hideInSearch: true, |
||||
|
formItemProps: { |
||||
|
component: 'Select', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ |
||||
|
label: '启用', |
||||
|
value: 1, |
||||
|
}, |
||||
|
{ |
||||
|
label: '禁用', |
||||
|
value: 0, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
}, |
||||
|
customRender: ({ record }) => { |
||||
|
const onChange = (checked: boolean) => { |
||||
|
console.log('checked: ', checked); |
||||
|
record.pendingStatus = true; |
||||
|
const newState = checked ? 1 : 0; |
||||
|
record.state = newState; |
||||
|
updateUser(record) |
||||
|
.then(() => { |
||||
|
record.state = newState; |
||||
|
}) |
||||
|
.catch(() => {}) |
||||
|
.finally(() => { |
||||
|
record.pendingStatus = false; |
||||
|
}); |
||||
|
}; |
||||
|
// return (
|
||||
|
// <a-switch
|
||||
|
// v-model:checked={record.state}
|
||||
|
// v-model:loading={record.pendingStatus}
|
||||
|
// onChange={onChange}
|
||||
|
// ></a-switch>
|
||||
|
// );
|
||||
|
// 渲染函数写法
|
||||
|
return h(Switch, { |
||||
|
checked: record.state === 1 ? true : false, |
||||
|
loading: record.pendingStatus, |
||||
|
onChange, |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
title: '是否管理员', |
||||
|
align: 'center', |
||||
|
width: 100, |
||||
|
dataIndex: 'isAdmin', |
||||
|
hideInSearch: true, |
||||
|
formItemProps: { |
||||
|
component: 'Select', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ |
||||
|
label: '是', |
||||
|
value: 1, |
||||
|
}, |
||||
|
{ |
||||
|
label: '否', |
||||
|
value: 0, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
}, |
||||
|
customRender: ({ record }) => { |
||||
|
const onChange = (checked: boolean) => { |
||||
|
console.log('checked: ', checked); |
||||
|
record.pendingStatus = true; |
||||
|
const newState = checked ? 1 : 0; |
||||
|
record.isAdmin = newState; |
||||
|
updateUser(record) |
||||
|
.then(() => { |
||||
|
record.isAdmin = newState; |
||||
|
}) |
||||
|
.catch(() => {}) |
||||
|
.finally(() => { |
||||
|
record.pendingStatus = false; |
||||
|
}); |
||||
|
}; |
||||
|
// return (
|
||||
|
// <a-switch
|
||||
|
// v-model:checked={record.state}
|
||||
|
// v-model:loading={record.pendingStatus}
|
||||
|
// onChange={onChange}
|
||||
|
// ></a-switch>
|
||||
|
// );
|
||||
|
// 渲染函数写法
|
||||
|
return h(Switch, { |
||||
|
checked: record.isAdmin === 1 ? true : false, |
||||
|
loading: record.pendingStatus, |
||||
|
onChange, |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
title: '创建时间', |
||||
|
align: 'center', |
||||
|
width: 200, |
||||
|
dataIndex: 'createTime', |
||||
|
formItemProps: { |
||||
|
defaultValue: '', |
||||
|
required: false, |
||||
|
component: 'RangePicker', |
||||
|
}, |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
export const getBaseColumns = (tableInstance) => { |
||||
|
return [ |
||||
|
{ |
||||
|
title: '账号', |
||||
|
align: 'center', |
||||
|
dataIndex: 'account', |
||||
|
// sorter: true,
|
||||
|
width: 150, |
||||
|
resizable: true, |
||||
|
formItemProps: { |
||||
|
defaultValue: '', |
||||
|
required: false, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
title: '姓名', |
||||
|
align: 'center', |
||||
|
dataIndex: 'username', |
||||
|
width: 150, |
||||
|
resizable: true, |
||||
|
formItemProps: { |
||||
|
defaultValue: '', |
||||
|
required: false, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
title: '手机号码', |
||||
|
align: 'center', |
||||
|
dataIndex: 'mobile', |
||||
|
width: 150, |
||||
|
formItemProps: { |
||||
|
defaultValue: '', |
||||
|
required: false, |
||||
|
}, |
||||
|
}, |
||||
|
|
||||
|
{ |
||||
|
title: '性别', |
||||
|
align: 'center', |
||||
|
dataIndex: 'sex', |
||||
|
width: 100, |
||||
|
hideInSearch: true, |
||||
|
formItemProps: { |
||||
|
defaultValue: '', |
||||
|
required: false, |
||||
|
component: 'Select', |
||||
|
label: '性别', |
||||
|
componentProps: { |
||||
|
mode: 'single', |
||||
|
request: async () => { |
||||
|
// const data = await getSexList();
|
||||
|
return sexTypeList; |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
customRender: ({ record }) => { |
||||
|
const text = sexTypeList.find((e) => e.value === record.sex)?.label; |
||||
|
return <div>{text}</div>; |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
title: '帐号状态', |
||||
|
align: 'center', |
||||
|
width: 100, |
||||
|
dataIndex: 'state', |
||||
|
hideInSearch: true, |
||||
|
formItemProps: { |
||||
|
component: 'Select', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ |
||||
|
label: '启用', |
||||
|
value: 1, |
||||
|
}, |
||||
|
{ |
||||
|
label: '禁用', |
||||
|
value: 0, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
}, |
||||
|
customRender: ({ record }) => { |
||||
|
const onChange = (checked: boolean) => { |
||||
|
console.log('checked: ', checked); |
||||
|
record.pendingStatus = true; |
||||
|
const newState = checked ? 1 : 0; |
||||
|
record.state = newState; |
||||
|
updateUser(record) |
||||
|
.then(() => { |
||||
|
record.state = newState; |
||||
|
}) |
||||
|
.catch(() => {}) |
||||
|
.finally(() => { |
||||
|
record.pendingStatus = false; |
||||
|
tableInstance && tableInstance?.reload(); |
||||
|
}); |
||||
|
}; |
||||
|
// return (
|
||||
|
// <a-switch
|
||||
|
// v-model:checked={record.state}
|
||||
|
// v-model:loading={record.pendingStatus}
|
||||
|
// onChange={onChange}
|
||||
|
// ></a-switch>
|
||||
|
// );
|
||||
|
// 渲染函数写法
|
||||
|
return h(Switch, { |
||||
|
checked: record.state === 1 ? true : false, |
||||
|
loading: record.pendingStatus, |
||||
|
onChange, |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
title: '是否管理员', |
||||
|
align: 'center', |
||||
|
width: 100, |
||||
|
dataIndex: 'isAdmin', |
||||
|
hideInSearch: true, |
||||
|
formItemProps: { |
||||
|
component: 'Select', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ |
||||
|
label: '是', |
||||
|
value: 1, |
||||
|
}, |
||||
|
{ |
||||
|
label: '否', |
||||
|
value: 0, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
}, |
||||
|
customRender: ({ record }) => { |
||||
|
const onChange = (checked: boolean) => { |
||||
|
console.log('checked: ', checked); |
||||
|
record.pendingStatus = true; |
||||
|
const newState = checked ? 1 : 0; |
||||
|
record.isAdmin = newState; |
||||
|
updateUser(record) |
||||
|
.then(() => { |
||||
|
record.isAdmin = newState; |
||||
|
}) |
||||
|
.catch(() => {}) |
||||
|
.finally(() => { |
||||
|
record.pendingStatus = false; |
||||
|
tableInstance && tableInstance?.reload(); |
||||
|
}); |
||||
|
}; |
||||
|
// return (
|
||||
|
// <a-switch
|
||||
|
// v-model:checked={record.state}
|
||||
|
// v-model:loading={record.pendingStatus}
|
||||
|
// onChange={onChange}
|
||||
|
// ></a-switch>
|
||||
|
// );
|
||||
|
// 渲染函数写法
|
||||
|
return h(Switch, { |
||||
|
checked: record.isAdmin === 1 ? true : false, |
||||
|
loading: record.pendingStatus, |
||||
|
onChange, |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
title: '创建时间', |
||||
|
align: 'center', |
||||
|
width: 200, |
||||
|
dataIndex: 'createTime', |
||||
|
formItemProps: { |
||||
|
defaultValue: '', |
||||
|
required: false, |
||||
|
component: 'RangePicker', |
||||
|
}, |
||||
|
}, |
||||
|
]; |
||||
|
}; |
@ -0,0 +1,14 @@ |
|||||
|
export const sexTypeList:any = [ |
||||
|
{ |
||||
|
label: '男', |
||||
|
value: 1, |
||||
|
}, |
||||
|
{ |
||||
|
label: '女', |
||||
|
value: 2, |
||||
|
}, |
||||
|
{ |
||||
|
label: '未知', |
||||
|
value: 3, |
||||
|
}, |
||||
|
]; |
@ -0,0 +1,123 @@ |
|||||
|
/* |
||||
|
* @Author: AaronWu 2463371514@qq.com |
||||
|
* @Date: 2025-04-01 09:08:06 |
||||
|
* @LastEditors: AaronWu 2463371514@qq.com |
||||
|
* @LastEditTime: 2025-04-01 16:48:50 |
||||
|
* @FilePath: /IssueSupportManage/src/views/system/user/formSchemas.ts |
||||
|
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||
|
*/ |
||||
|
import type { FormSchema } from '@/components/core/schema-form/'; |
||||
|
import { sexTypeList } from './data'; |
||||
|
|
||||
|
export const userSchemas: FormSchema<API.CreateUserParams>[] = [ |
||||
|
{ |
||||
|
field: 'account', |
||||
|
component: 'Input', |
||||
|
label: '账号', |
||||
|
colProps: { |
||||
|
span: 12, |
||||
|
}, |
||||
|
rules: [{ required: true }], |
||||
|
}, |
||||
|
{ |
||||
|
field: 'username', |
||||
|
component: 'Input', |
||||
|
label: '用户名', |
||||
|
colProps: { |
||||
|
span: 12, |
||||
|
}, |
||||
|
rules: [{ required: true }], |
||||
|
}, |
||||
|
{ |
||||
|
field: 'password', |
||||
|
component: 'Input', |
||||
|
label: '密码', |
||||
|
colProps: { |
||||
|
span: 12, |
||||
|
}, |
||||
|
rules: [{ required: true }], |
||||
|
}, |
||||
|
{ |
||||
|
field: 'mobile', |
||||
|
component: 'Input', |
||||
|
label: '手机号码', |
||||
|
colProps: { |
||||
|
span: 12, |
||||
|
}, |
||||
|
rules: [ |
||||
|
{ |
||||
|
required: true, |
||||
|
message: '请输入正确格式的电话号码', |
||||
|
pattern: /^1(3[0-9]|4[01456879]|5[0-3,5-9]|6[2567]|7[0-8]|8[0-9]|9[0-3,5-9])\d{8}$/, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
|
||||
|
{ |
||||
|
field: 'sex', |
||||
|
component: 'Select', |
||||
|
label: '性别', |
||||
|
colProps: { |
||||
|
span: 12, |
||||
|
}, |
||||
|
componentProps: { |
||||
|
mode: 'single', |
||||
|
request: async () => { |
||||
|
// const data = await getSexList();
|
||||
|
return sexTypeList; |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
|
||||
|
{ |
||||
|
field: 'state', |
||||
|
component: 'RadioGroup', |
||||
|
label: '帐号状态', |
||||
|
defaultValue: 1, |
||||
|
colProps: { |
||||
|
span: 12, |
||||
|
}, |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ |
||||
|
label: '启用', |
||||
|
value: 1, |
||||
|
}, |
||||
|
{ |
||||
|
label: '禁用', |
||||
|
value: 0, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
// required:true,
|
||||
|
rules: [{ required: true, type: 'number' }], |
||||
|
}, |
||||
|
{ |
||||
|
field: 'isAdmin', |
||||
|
component: 'RadioGroup', |
||||
|
label: '是否管理员', |
||||
|
defaultValue: 0, |
||||
|
colProps: { |
||||
|
span: 12, |
||||
|
}, |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ |
||||
|
label: '是', |
||||
|
value: 1, |
||||
|
}, |
||||
|
{ |
||||
|
label: '否', |
||||
|
value: 0, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
// required:true,
|
||||
|
rules: [{ required: true, type: 'number' }], |
||||
|
}, |
||||
|
{ |
||||
|
field: 'remark', |
||||
|
component: 'InputTextArea', |
||||
|
label: '备注', |
||||
|
}, |
||||
|
]; |
@ -0,0 +1,241 @@ |
|||||
|
<!-- |
||||
|
功能:功能描述 |
||||
|
作者:Aaron.Wu |
||||
|
时间:2023年05月25日 17:00:26 |
||||
|
版本:v1.0 |
||||
|
修改记录: |
||||
|
修改内容: |
||||
|
修改人员: |
||||
|
修改时间: |
||||
|
--> |
||||
|
<template> |
||||
|
<DynamicTable |
||||
|
size="small" |
||||
|
showIndex |
||||
|
headerTitle="管理员列表" |
||||
|
titleTooltip="" |
||||
|
:data-request="loadData" |
||||
|
:columns="columns" |
||||
|
row-key="id" |
||||
|
@resize-column="handleResizeColumn" |
||||
|
:row-selection="rowSelection" |
||||
|
:scroll="{ x: '100vw' }" |
||||
|
> |
||||
|
<template v-if="isCheckRows" #title> |
||||
|
<Alert class="w-full" type="info" show-icon> |
||||
|
<template #message> |
||||
|
已选 {{ isCheckRows }} 项 |
||||
|
<a-button type="link" @click="rowSelection.selectedRowKeys = []">取消选择</a-button> |
||||
|
</template> |
||||
|
</Alert> |
||||
|
</template> |
||||
|
<template #toolbar> |
||||
|
<!-- <a-button type="primary" @click="openUserModal({})">新增</a-button> --> |
||||
|
<a-button |
||||
|
type="danger" |
||||
|
:disabled="!isCheckRows" |
||||
|
@click="delRowConfirm(rowSelection.selectedRowKeys)" |
||||
|
> |
||||
|
<DeleteOutlined /> 删除 |
||||
|
</a-button> |
||||
|
</template> |
||||
|
</DynamicTable> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="tsx" setup> |
||||
|
import { type TableListItem, getBaseColumns } from './columns'; |
||||
|
import { useTable, type OnChangeCallbackParams } from '@/components/core/dynamic-table'; |
||||
|
import { |
||||
|
fetchUserList, |
||||
|
fetchUserPageList, |
||||
|
createUser, |
||||
|
updateUser, |
||||
|
findOneById, |
||||
|
deleteUserById, |
||||
|
deleteBatchUserById, |
||||
|
} from '@/api/user'; |
||||
|
import { computed, reactive, ref, toRaw } from 'vue'; |
||||
|
import { Modal, message, Alert } from 'ant-design-vue'; |
||||
|
|
||||
|
import { useFormModal } from '@/hooks/useModal/index'; |
||||
|
import { userSchemas } from './formSchemas'; |
||||
|
import { ExclamationCircleOutlined, DeleteOutlined } from '@ant-design/icons-vue'; |
||||
|
|
||||
|
defineOptions({ |
||||
|
name: 'tanant-user', |
||||
|
}); |
||||
|
|
||||
|
const [showModal] = useFormModal(); |
||||
|
|
||||
|
const [DynamicTable, dynamicTableInstance] = useTable(); |
||||
|
|
||||
|
const columns = [ |
||||
|
...getBaseColumns(dynamicTableInstance), |
||||
|
{ |
||||
|
title: '操作', |
||||
|
width: 200, |
||||
|
dataIndex: 'ACTION', |
||||
|
hideInSearch: true, |
||||
|
align: 'center', |
||||
|
fixed: 'right', |
||||
|
actions: ({ record }) => [ |
||||
|
{ |
||||
|
icon: 'searchoutlined', |
||||
|
color: '#3b82f6', |
||||
|
label: '查看', |
||||
|
onClick: () => handleShow(record), |
||||
|
}, |
||||
|
// { |
||||
|
// icon: 'edit', |
||||
|
// color: '#3b82f6', |
||||
|
// size: '15', |
||||
|
// label: '修改', |
||||
|
// onClick: () => handleEdit(record), |
||||
|
// }, |
||||
|
{ |
||||
|
icon: 'delete', |
||||
|
color: '#ec6f6f', |
||||
|
label: '删除', |
||||
|
popConfirm: { |
||||
|
title: '确定要删除吗?', |
||||
|
onConfirm: () => handleDelete(record.id), |
||||
|
}, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
]; |
||||
|
/** |
||||
|
* @description 打开用户弹窗 |
||||
|
*/ |
||||
|
const openUserModal = async (record: Partial<TableListItem> = {}, isReadOnly = false) => { |
||||
|
const [formRef] = await showModal<any>({ |
||||
|
modalProps: { |
||||
|
title: `${isReadOnly ? '查看' : record.id ? '编辑' : '新增'}用户`, |
||||
|
width: 700, |
||||
|
onFinish: async (values) => { |
||||
|
console.log('新增/编辑用户', values); |
||||
|
values.id = record.id; |
||||
|
await (record.id ? updateUser : createUser)(values); |
||||
|
message.success(`${record.id ? '编辑' : '新增'}成功`); |
||||
|
dynamicTableInstance?.reload(); |
||||
|
}, |
||||
|
footer: isReadOnly ? null : undefined, |
||||
|
}, |
||||
|
formProps: { |
||||
|
labelWidth: 100, |
||||
|
schemas: userSchemas as any, |
||||
|
autoSubmitOnEnter: true, |
||||
|
disabled: isReadOnly, |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
formRef?.setFieldsValue(record); |
||||
|
// if (record?.id) { |
||||
|
// const { roles } = await getUserInfo({ userId: record.id }); |
||||
|
// formRef?.setFieldsValue({ roles }); |
||||
|
// } |
||||
|
}; |
||||
|
|
||||
|
const handleEdit = (record: TableListItem) => { |
||||
|
openUserModal(record); |
||||
|
}; |
||||
|
|
||||
|
const handleShow = (record: TableListItem) => { |
||||
|
openUserModal(record, true); |
||||
|
}; |
||||
|
|
||||
|
const handleDelete = (id: string) => { |
||||
|
delRowConfirm([id]); |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* @description 表格删除行 |
||||
|
*/ |
||||
|
const delRowConfirm = async (ids: string[]) => { |
||||
|
Modal.confirm({ |
||||
|
title: '确定要删除所选的用户吗?', |
||||
|
icon: <ExclamationCircleOutlined />, |
||||
|
centered: true, |
||||
|
onOk: async () => { |
||||
|
await deleteBatchUserById(ids).finally(dynamicTableInstance?.reload); |
||||
|
}, |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const rowSelection = ref<any>({ |
||||
|
selectedRowKeys: [] as string[], |
||||
|
onChange: (selectedRowKeys: string[], selectedRows: TableListItem[]) => { |
||||
|
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows); |
||||
|
rowSelection.value.selectedRowKeys = selectedRowKeys; |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
// 是否勾选了表格行 |
||||
|
const isCheckRows = computed(() => rowSelection.value.selectedRowKeys.length); |
||||
|
|
||||
|
const loadData = async ( |
||||
|
params, |
||||
|
onChangeParams?: OnChangeCallbackParams, |
||||
|
): Promise<API.TableListResult> => { |
||||
|
console.log('params', params); |
||||
|
console.log('onChangeParams', onChangeParams); |
||||
|
// 手动设置搜索表单的搜索项 |
||||
|
// dynamicTableInstance?.getQueryFormRef()?.updateSchema?.([ |
||||
|
// { |
||||
|
// field: 'price', |
||||
|
// componentProps: { |
||||
|
// options: [ |
||||
|
// { |
||||
|
// label: '0-199', |
||||
|
// value: '0-199', |
||||
|
// }, |
||||
|
// { |
||||
|
// label: '200-999', |
||||
|
// value: '200-999', |
||||
|
// }, |
||||
|
// ], |
||||
|
// }, |
||||
|
// }, |
||||
|
// ]); |
||||
|
|
||||
|
// return new Promise((resolve) => { |
||||
|
// setTimeout(() => { |
||||
|
// resolve({ |
||||
|
// list: [ |
||||
|
// { |
||||
|
// id: '1', |
||||
|
// name: '1', |
||||
|
// }, |
||||
|
// ], |
||||
|
// ...params, |
||||
|
// }); |
||||
|
// }, 500); |
||||
|
// }); |
||||
|
const res = await fetchUserPageList({ |
||||
|
...params, |
||||
|
isAdmin: 1, |
||||
|
current: params.page, |
||||
|
size: params.limit, |
||||
|
}); |
||||
|
console.log('res: ', res); |
||||
|
rowSelection.value.selectedRowKeys = []; |
||||
|
|
||||
|
return { |
||||
|
list: res.data.records, |
||||
|
pagination: { |
||||
|
total: Number(res.data.total), |
||||
|
...params, |
||||
|
}, |
||||
|
}; |
||||
|
}; |
||||
|
const handleResizeColumn = (w, col) => { |
||||
|
// console.log('w', w, col); |
||||
|
col.width = w; |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style lang="less" scoped> |
||||
|
.action-divider { |
||||
|
margin: 0 5px; |
||||
|
} |
||||
|
</style> |
Loading…
Reference in new issue