diff --git a/.gitignore b/.gitignore index 6aef0f8..535c399 100644 --- a/.gitignore +++ b/.gitignore @@ -24,7 +24,7 @@ pnpm-debug.log* .idea .svn # .vscode -*.suo +*.suo· *.ntvs* *.njsproj *.sln diff --git a/src/components/jeecg/JVxeTable/src/hooks/useMethods.ts b/src/components/jeecg/JVxeTable/src/hooks/useMethods.ts index bbb9df4..341dac9 100644 --- a/src/components/jeecg/JVxeTable/src/hooks/useMethods.ts +++ b/src/components/jeecg/JVxeTable/src/hooks/useMethods.ts @@ -129,10 +129,15 @@ export function useMethods(props: JVxeTableProps, { emit }, data: JVxeDataProps, } // 显示详细信息 + console.log('qqq'); if (column.params?.showDetails) { refs.detailsModalRef.value?.open(event); } else if (refs.subPopoverRef.value) { - refs.subPopoverRef.value.toggle(event); + if (column.params?.showSub !== false) { + refs.subPopoverRef.value.toggle(event); + } + // if (column.params?.showSub !== undefined) { + // } } else if (props.clickSelectRow) { let className = $event.target.className || ''; className = isString(className) ? className : className.toString(); diff --git a/src/views/dashboard/Analysis/api.ts b/src/views/dashboard/Analysis/api.ts index 0f40443..c7ee830 100644 --- a/src/views/dashboard/Analysis/api.ts +++ b/src/views/dashboard/Analysis/api.ts @@ -3,6 +3,7 @@ import { defHttp } from '/@/utils/http/axios'; enum Api { loginfo = '/sys/loginfo', visitInfo = '/sys/visitInfo', + logStatistics = '/sys/logStatistics', } /** * 日志统计信息 @@ -14,3 +15,5 @@ export const getLoginfo = (params) => defHttp.get({ url: Api.loginfo, params }, * @param params */ export const getVisitInfo = (params) => defHttp.get({ url: Api.visitInfo, params }, { isTransformResponse: false }); + +export const getLogStatistics = (params) => defHttp.post({ url: Api.logStatistics, params }, { isTransformResponse: false }); diff --git a/src/views/dashboard/Analysis/components/SaleTabCard.vue b/src/views/dashboard/Analysis/components/SaleTabCard.vue index 3f4b9d4..84f7948 100644 --- a/src/views/dashboard/Analysis/components/SaleTabCard.vue +++ b/src/views/dashboard/Analysis/components/SaleTabCard.vue @@ -4,26 +4,31 @@ - - - - - + + + + + - + diff --git a/src/views/system/frontUser/UserRecycleBinModal.vue b/src/views/system/frontUser/UserRecycleBinModal.vue new file mode 100644 index 0000000..486f799 --- /dev/null +++ b/src/views/system/frontUser/UserRecycleBinModal.vue @@ -0,0 +1,138 @@ + + diff --git a/src/views/system/frontUser/index.vue b/src/views/system/frontUser/index.vue new file mode 100644 index 0000000..0f6f1b3 --- /dev/null +++ b/src/views/system/frontUser/index.vue @@ -0,0 +1,355 @@ + + + + + diff --git a/src/views/system/frontUser/user.api.ts b/src/views/system/frontUser/user.api.ts new file mode 100644 index 0000000..662a98f --- /dev/null +++ b/src/views/system/frontUser/user.api.ts @@ -0,0 +1,242 @@ +import { defHttp } from '/@/utils/http/axios'; +import { Modal } from 'ant-design-vue'; + +enum Api { + listNoCareTenant = '/sys/user/listAll', + list = '/sys/user/list', + save = '/sys/user/add', + edit = '/sys/user/edit', + agentSave = '/sys/sysUserAgent/add', + agentEdit = '/sys/sysUserAgent/edit', + getUserRole = '/sys/user/queryUserRole', + duplicateCheck = '/sys/duplicate/check', + deleteUser = '/sys/user/delete', + deleteBatch = '/sys/user/deleteBatch', + importExcel = '/sys/user/importExcel', + exportXls = '/sys/user/exportXls', + recycleBinList = '/sys/user/recycleBin', + putRecycleBin = '/sys/user/putRecycleBin', + deleteRecycleBin = '/sys/user/deleteRecycleBin', + allRolesList = '/sys/role/queryall', + allRolesListNoByTenant = '/sys/role/queryallNoByTenant', + allTenantList = '/sys/tenant/queryList', + allPostList = '/sys/position/list', + userDepartList = '/sys/user/userDepartList', + changePassword = '/sys/user/changePassword', + frozenBatch = '/sys/user/frozenBatch', + getUserAgent = '/sys/sysUserAgent/queryByUserName', + userQuitAgent = '/sys/user/userQuitAgent', + getQuitList = '/sys/user/getQuitList', + putCancelQuit = '/sys/user/putCancelQuit', + updateUserTenantStatus='/sys/tenant/updateUserTenantStatus', + getUserTenantPageList='/sys/tenant/getUserTenantPageList', +} +/** + * 导出api + * @param params + */ +export const getExportUrl = Api.exportXls; +/** + * 导入api + */ +export const getImportUrl = Api.importExcel; +/** + * 列表接口(查询用户,通过租户隔离) + * @param params + */ +export const list = (params) => defHttp.get({ url: Api.list, params }); + +/** + * 列表接口(查询全部用户,不通过租户隔离) + * @param params + */ +export const listNoCareTenant = (params) => defHttp.get({ url: Api.listNoCareTenant, params }); + +/** + * 用户角色接口 + * @param params + */ +export const getUserRoles = (params) => defHttp.get({ url: Api.getUserRole, params }, { errorMessageMode: 'none' }); + +/** + * 删除用户 + */ +export const deleteUser = (params, handleSuccess) => { + return defHttp.delete({ url: Api.deleteUser, params }, { joinParamsToUrl: true }).then(() => { + handleSuccess(); + }); +}; +/** + * 批量删除用户 + * @param params + */ +export const batchDeleteUser = (params, handleSuccess) => { + Modal.confirm({ + title: '确认删除', + content: '是否删除选中数据', + okText: '确认', + cancelText: '取消', + onOk: () => { + return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => { + handleSuccess(); + }); + }, + }); +}; +/** + * 保存或者更新用户 + * @param params + */ +export const saveOrUpdateUser = (params, isUpdate) => { + let url = isUpdate ? Api.edit : Api.save; + return defHttp.post({ url: url, params }); +}; +/** + * 唯一校验 + * @param params + */ +export const duplicateCheck = (params) => defHttp.get({ url: Api.duplicateCheck, params }, { isTransformResponse: false }); + +/** + * 20231215 + * liaozhiyang + * 唯一校验( 延迟【防抖】) + * @param params + */ +let timer; +export const duplicateCheckDelay = (params) => { + return new Promise((resove, rejected) => { + clearTimeout(timer); + timer = setTimeout(() => { + defHttp + .get({ url: Api.duplicateCheck, params }, { isTransformResponse: false }) + .then((res: any) => { + resove(res as any); + }) + .catch((error) => { + rejected(error); + }); + }, 500); + }); +}; +/** + * 获取全部角色(租户隔离) + * @param params + */ +export const getAllRolesList = (params) => defHttp.get({ url: Api.allRolesList, params }); +/** + * 获取全部角色(不租户隔离) + * @param params + */ +export const getAllRolesListNoByTenant = (params) => defHttp.get({ url: Api.allRolesListNoByTenant, params }); +/** + * 获取全部租户 + */ +export const getAllTenantList = (params) => defHttp.get({ url: Api.allTenantList, params }); +/** + * 获取指定用户负责部门 + */ +export const getUserDepartList = (params) => defHttp.get({ url: Api.userDepartList, params }, { successMessageMode: 'none' }); +/** + * 获取全部职务 + */ +export const getAllPostList = (params) => { + return new Promise((resolve) => { + defHttp.get({ url: Api.allPostList, params }).then((res) => { + resolve(res.records); + }); + }); +}; +/** + * 回收站列表 + * @param params + */ +export const getRecycleBinList = (params) => defHttp.get({ url: Api.recycleBinList, params }); +/** + * 回收站还原 + * @param params + */ +export const putRecycleBin = (params, handleSuccess) => { + return defHttp.put({ url: Api.putRecycleBin, params }).then(() => { + handleSuccess(); + }); +}; +/** + * 回收站删除 + * @param params + */ +export const deleteRecycleBin = (params, handleSuccess) => { + return defHttp.delete({ url: Api.deleteRecycleBin, params }, { joinParamsToUrl: true }).then(() => { + handleSuccess(); + }); +}; +/** + * 修改密码 + * @param params + */ +export const changePassword = (params) => { + return defHttp.put({ url: Api.changePassword, params }); +}; +/** + * 冻结解冻 + * @param params + */ +export const frozenBatch = (params, handleSuccess) => { + return defHttp.put({ url: Api.frozenBatch, params }).then(() => { + handleSuccess(); + }); +}; +/** + * 获取用户代理 + * @param params + */ +export const getUserAgent = (params) => defHttp.get({ url: Api.getUserAgent, params }, { isTransformResponse: false }); +/** + * 保存或者更新用户代理 + * @param params + */ +export const saveOrUpdateAgent = (params) => { + let url = params.id ? Api.agentEdit : Api.agentSave; + return defHttp.post({ url: url, params }); +}; + +/** + * 用户离职(新增代理人和用户状态变更操作) + * @param params + */ +export const userQuitAgent = (params) => { + return defHttp.put({ url: Api.userQuitAgent, params }); +}; + +/** + * 用户离职列表 + * @param params + */ +export const getQuitList = (params) => { + return defHttp.get({ url: Api.getQuitList, params }); +}; + +/** + * 取消离职 + * @param params + */ +export const putCancelQuit = (params, handleSuccess) => { + return defHttp.put({ url: Api.putCancelQuit, params }, { joinParamsToUrl: true }).then(() => { + handleSuccess(); + }); +}; + +/** + * 待审批获取列表数据 + */ +export const getUserTenantPageList = (params) => { + return defHttp.get({ url: Api.getUserTenantPageList, params }); +}; + +/** + * 更新租户状态 + * @param params + */ +export const updateUserTenantStatus = (params) => { + return defHttp.put({ url: Api.updateUserTenantStatus, params }, { joinParamsToUrl: true, isTransformResponse: false }); +}; diff --git a/src/views/system/frontUser/user.data.ts b/src/views/system/frontUser/user.data.ts new file mode 100644 index 0000000..c89ed1d --- /dev/null +++ b/src/views/system/frontUser/user.data.ts @@ -0,0 +1,557 @@ +import { BasicColumn } from '/@/components/Table'; +import { FormSchema } from '/@/components/Table'; +import { getAllRolesListNoByTenant, getAllTenantList } from './user.api'; +import { rules } from '/@/utils/helper/validator'; +import { render } from '/@/utils/common/renderUtils'; +export const columns: BasicColumn[] = [ + { + title: '用户账号', + dataIndex: 'username', + width: 120, + }, + { + title: '用户姓名', + dataIndex: 'realname', + width: 100, + }, + { + title: '头像', + dataIndex: 'avatar', + width: 120, + customRender: render.renderAvatar, + }, + { + title: '性别', + dataIndex: 'sex', + width: 80, + sorter: true, + customRender: ({ text }) => { + return render.renderDict(text, 'sex'); + }, + }, + /*{ + title: '生日', + dataIndex: 'birthday', + width: 100, + },*/ + { + title: '手机号', + dataIndex: 'phone', + width: 100, + }, + { + title: '部门', + width: 150, + dataIndex: 'orgCodeTxt', + }, + /*{ + title: '负责部门', + width: 150, + dataIndex: 'departIds_dictText', + },*/ + { + title: '状态', + dataIndex: 'status_dictText', + width: 80, + }, +]; + +export const recycleColumns: BasicColumn[] = [ + { + title: '用户账号', + dataIndex: 'username', + width: 100, + }, + { + title: '用户姓名', + dataIndex: 'realname', + width: 100, + }, + { + title: '头像', + dataIndex: 'avatar', + width: 80, + customRender: render.renderAvatar, + }, + { + title: '性别', + dataIndex: 'sex', + width: 80, + sorter: true, + customRender: ({ text }) => { + return render.renderDict(text, 'sex'); + }, + }, +]; + +export const searchFormSchema: FormSchema[] = [ + { + label: '账号', + field: 'username', + component: 'JInput', + //colProps: { span: 6 }, + }, + { + label: '名字', + field: 'realname', + component: 'JInput', + //colProps: { span: 6 }, + }, + { + label: '性别', + field: 'sex', + component: 'JDictSelectTag', + componentProps: { + dictCode: 'sex', + placeholder: '请选择性别', + stringToNumber: true, + }, + //colProps: { span: 6 }, + }, + { + label: '手机号码', + field: 'phone', + component: 'Input', + //colProps: { span: 6 }, + }, + { + label: '用户状态', + field: 'status', + component: 'JDictSelectTag', + componentProps: { + dictCode: 'user_status', + placeholder: '请选择状态', + stringToNumber: true, + }, + //colProps: { span: 6 }, + }, +]; + +export const formSchema: FormSchema[] = [ + { + label: '', + field: 'id', + component: 'Input', + show: false, + }, + { + label: '用户账号', + field: 'username', + component: 'Input', + dynamicDisabled: ({ values }) => { + return !!values.id; + }, + dynamicRules: ({ model, schema }) => rules.duplicateCheckRule('sys_user', 'username', model, schema, true), + }, + { + label: '登录密码', + field: 'password', + component: 'StrengthMeter', + rules: [ + { + required: true, + message: '请输入登录密码', + }, + /*{ + pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,./]).{8,}$/, + message: '密码由8位数字、大小写字母和特殊符号组成!', + },*/ + ], + }, + { + label: '确认密码', + field: 'confirmPassword', + component: 'InputPassword', + dynamicRules: ({ values }) => rules.confirmPassword(values, true), + }, + { + label: '用户姓名', + field: 'realname', + required: true, + component: 'Input', + }, + { + label: '工号', + field: 'workNo', + required: false, + component: 'Input', + dynamicRules: ({ model, schema }) => rules.duplicateCheckRule('sys_user', 'work_no', model, schema, true), + }, + /*{ + label: '职务', + field: 'post', + required: false, + component: 'JSelectPosition', + componentProps: { + labelKey: 'name', + }, + },*/ + { + label: '角色', + field: 'selectedroles', + component: 'ApiSelect', + componentProps: { + mode: 'multiple', + api: getAllRolesListNoByTenant, + labelField: 'roleName', + valueField: 'id', + immediate: false, + }, + }, + { + label: '所属部门', + field: 'selecteddeparts', + component: 'JSelectDept', + componentProps: ({ formActionType, formModel }) => { + return { + sync: false, + checkStrictly: true, + defaultExpandLevel: 2, + + onSelect: (options, values) => { + const { updateSchema } = formActionType; + //所属部门修改后更新负责部门下拉框数据 + updateSchema([ + { + field: 'departIds', + componentProps: { options }, + }, + ]); + //所属部门修改后更新负责部门数据 + formModel.departIds && (formModel.departIds = formModel.departIds.filter((item) => values.value.indexOf(item) > -1)); + }, + }; + }, + }, + { + label: '租户', + field: 'relTenantIds', + component: 'ApiSelect', + componentProps: { + mode: 'multiple', + api: getAllTenantList, + numberToString: true, + labelField: 'name', + valueField: 'id', + immediate: false, + }, + }, + { + label: '身份', + field: 'userIdentity', + component: 'RadioGroup', + defaultValue: 1, + componentProps: ({ formModel }) => { + return { + options: [ + { label: '普通用户', value: 1, key: '1' }, + { label: '上级', value: 2, key: '2' }, + ], + onChange: () => { + formModel.userIdentity == 1 && (formModel.departIds = []); + }, + }; + }, + }, + { + label: '负责部门', + field: 'departIds', + component: 'Select', + componentProps: { + mode: 'multiple', + }, + ifShow: ({ values }) => values.userIdentity == 2, + }, + { + label: '头像', + field: 'avatar', + component: 'JImageUpload', + componentProps: { + fileMax: 1, + }, + }, + { + label: '生日', + field: 'birthday', + component: 'DatePicker', + }, + { + label: '性别', + field: 'sex', + component: 'JDictSelectTag', + componentProps: { + dictCode: 'sex', + placeholder: '请选择性别', + stringToNumber: true, + }, + }, + { + label: '邮箱', + field: 'email', + component: 'Input', + dynamicRules: ({ model, schema }) => { + return [ + { ...rules.duplicateCheckRule('sys_user', 'email', model, schema, true)[0], trigger: 'blur' }, + { ...rules.rule('email', false)[0], trigger: 'blur' }, + ]; + }, + }, + { + label: '手机号码', + field: 'phone', + component: 'Input', + dynamicRules: ({ model, schema }) => { + return [ + { ...rules.duplicateCheckRule('sys_user', 'phone', model, schema, true)[0], trigger: 'blur' }, + { pattern: /^1[3456789]\d{9}$/, message: '手机号码格式有误', trigger: 'blur' }, + ]; + }, + }, + { + label: '座机', + field: 'telephone', + component: 'Input', + rules: [{ pattern: /^0\d{2,3}-[1-9]\d{6,7}$/, message: '请输入正确的座机号码' }], + }, + { + label: '工作流引擎', + field: 'activitiSync', + defaultValue: 1, + component: 'JDictSelectTag', + componentProps: { + dictCode: 'activiti_sync', + type: 'radio', + stringToNumber: true, + }, + }, +]; + +export const formPasswordSchema: FormSchema[] = [ + { + label: '用户账号', + field: 'username', + component: 'Input', + componentProps: { readOnly: true }, + }, + { + label: '登录密码', + field: 'password', + component: 'StrengthMeter', + componentProps: { + placeholder: '请输入登录密码', + }, + rules: [ + { + required: true, + message: '请输入登录密码', + }, + /*{ + pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,./]).{8,}$/, + message: '密码由8位数字、大小写字母和特殊符号组成!', + },*/ + ], + }, + { + label: '确认密码', + field: 'confirmPassword', + component: 'InputPassword', + dynamicRules: ({ values }) => rules.confirmPassword(values, true), + }, +]; + +export const formAgentSchema: FormSchema[] = [ + { + label: '', + field: 'id', + component: 'Input', + show: false, + }, + { + field: 'userName', + label: '用户名', + component: 'Input', + componentProps: { + readOnly: true, + allowClear: false, + }, + }, + { + field: 'agentUserName', + label: '代理人用户名', + required: true, + component: 'JSelectUser', + componentProps: { + rowKey: 'username', + labelKey: 'realname', + maxSelectCount: 10, + }, + }, + { + field: 'startTime', + label: '代理开始时间', + component: 'DatePicker', + required: true, + componentProps: { + showTime: true, + valueFormat: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择代理开始时间', + getPopupContainer: () => document.body, + }, + }, + { + field: 'endTime', + label: '代理结束时间', + component: 'DatePicker', + required: true, + componentProps: { + showTime: true, + valueFormat: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择代理结束时间', + getPopupContainer: () => document.body, + }, + }, + { + field: 'status', + label: '状态', + component: 'JDictSelectTag', + defaultValue: '1', + componentProps: { + dictCode: 'valid_status', + type: 'radioButton', + }, + }, +]; + +export const formQuitAgentSchema: FormSchema[] = [ + { + label: '', + field: 'id', + component: 'Input', + show: false, + }, + { + field: 'userName', + label: '用户名', + component: 'Input', + componentProps: { + readOnly: true, + allowClear: false, + }, + }, + { + field: 'agentUserName', + label: '交接人员', + required: true, + component: 'JSelectUser', + componentProps: { + rowKey: 'username', + labelKey: 'realname', + maxSelectCount: 1, + }, + }, + { + field: 'startTime', + label: '交接开始时间', + component: 'DatePicker', + required: true, + componentProps: { + showTime: true, + valueFormat: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择交接开始时间', + getPopupContainer: () => document.body, + }, + }, + { + field: 'endTime', + label: '交接结束时间', + component: 'DatePicker', + required: true, + componentProps: { + showTime: true, + valueFormat: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择交接结束时间', + getPopupContainer: () => document.body, + }, + }, + { + field: 'status', + label: '状态', + component: 'JDictSelectTag', + defaultValue: '1', + componentProps: { + dictCode: 'valid_status', + type: 'radioButton', + }, + }, +]; + +//租户用户列表 +export const userTenantColumns: BasicColumn[] = [ + { + title: '用户账号', + dataIndex: 'username', + width: 120, + }, + { + title: '用户姓名', + dataIndex: 'realname', + width: 100, + }, + { + title: '头像', + dataIndex: 'avatar', + width: 120, + customRender: render.renderAvatar, + }, + { + title: '手机号', + dataIndex: 'phone', + width: 100, + }, + { + title: '部门', + width: 150, + dataIndex: 'orgCodeTxt', + }, + { + title: '状态', + dataIndex: 'status', + width: 80, + customRender: ({ text }) => { + if (text === '1') { + return '正常'; + } else if (text === '3') { + return '审批中'; + } else { + return '已拒绝'; + } + }, + }, +]; + +//用户租户搜索表单 +export const userTenantFormSchema: FormSchema[] = [ + { + label: '账号', + field: 'username', + component: 'Input', + colProps: { span: 6 }, + }, + { + label: '名字', + field: 'realname', + component: 'Input', + colProps: { span: 6 }, + }, + { + label: '性别', + field: 'sex', + component: 'JDictSelectTag', + componentProps: { + dictCode: 'sex', + placeholder: '请选择性别', + stringToNumber: true, + }, + colProps: { span: 6 }, + }, +]; diff --git a/src/views/system/frontUser/userDetails.vue b/src/views/system/frontUser/userDetails.vue new file mode 100644 index 0000000..c0a8cd4 --- /dev/null +++ b/src/views/system/frontUser/userDetails.vue @@ -0,0 +1,54 @@ + + diff --git a/src/views/system/tenant/tenant.data.ts b/src/views/system/tenant/tenant.data.ts index cdeb861..867711d 100644 --- a/src/views/system/tenant/tenant.data.ts +++ b/src/views/system/tenant/tenant.data.ts @@ -452,9 +452,9 @@ export const tenantUserSchema: FormSchema[] = [ field: 'workNo', label: '工号', component: 'Input', - dynamicRules: ({ model, schema }) => { + /*dynamicRules: ({ model, schema }) => { return [{ required: true, message: '请输入工号' }, { ...rules.duplicateCheckRule('sys_user', 'work_no', model, schema, false)[0] }]; - }, + },*/ }, { field: 'relTenantIds', label: '租户', component: 'Input',show:false }, { field: 'selectedroles', label: '角色', component: 'Input',show:false }, diff --git a/src/views/system/user-old/PasswordModal.vue b/src/views/system/user-old/PasswordModal.vue new file mode 100644 index 0000000..d638c86 --- /dev/null +++ b/src/views/system/user-old/PasswordModal.vue @@ -0,0 +1,42 @@ + + diff --git a/src/views/system/user-old/UserAgentModal.vue b/src/views/system/user-old/UserAgentModal.vue new file mode 100644 index 0000000..4f3c50d --- /dev/null +++ b/src/views/system/user-old/UserAgentModal.vue @@ -0,0 +1,45 @@ + + diff --git a/src/views/system/user-old/UserDrawer.vue b/src/views/system/user-old/UserDrawer.vue new file mode 100644 index 0000000..e5112b8 --- /dev/null +++ b/src/views/system/user-old/UserDrawer.vue @@ -0,0 +1,160 @@ + + diff --git a/src/views/system/user-old/UserQuitAgentModal.vue b/src/views/system/user-old/UserQuitAgentModal.vue new file mode 100644 index 0000000..a1bc4d3 --- /dev/null +++ b/src/views/system/user-old/UserQuitAgentModal.vue @@ -0,0 +1,81 @@ + + diff --git a/src/views/system/user-old/UserQuitModal.vue b/src/views/system/user-old/UserQuitModal.vue new file mode 100644 index 0000000..7822269 --- /dev/null +++ b/src/views/system/user-old/UserQuitModal.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/src/views/system/user-old/UserRecycleBinModal.vue b/src/views/system/user-old/UserRecycleBinModal.vue new file mode 100644 index 0000000..486f799 --- /dev/null +++ b/src/views/system/user-old/UserRecycleBinModal.vue @@ -0,0 +1,138 @@ + + diff --git a/src/views/system/user-old/index.vue b/src/views/system/user-old/index.vue new file mode 100644 index 0000000..8970f7e --- /dev/null +++ b/src/views/system/user-old/index.vue @@ -0,0 +1,299 @@ + + + + + diff --git a/src/views/system/user-old/user.api.ts b/src/views/system/user-old/user.api.ts new file mode 100644 index 0000000..662a98f --- /dev/null +++ b/src/views/system/user-old/user.api.ts @@ -0,0 +1,242 @@ +import { defHttp } from '/@/utils/http/axios'; +import { Modal } from 'ant-design-vue'; + +enum Api { + listNoCareTenant = '/sys/user/listAll', + list = '/sys/user/list', + save = '/sys/user/add', + edit = '/sys/user/edit', + agentSave = '/sys/sysUserAgent/add', + agentEdit = '/sys/sysUserAgent/edit', + getUserRole = '/sys/user/queryUserRole', + duplicateCheck = '/sys/duplicate/check', + deleteUser = '/sys/user/delete', + deleteBatch = '/sys/user/deleteBatch', + importExcel = '/sys/user/importExcel', + exportXls = '/sys/user/exportXls', + recycleBinList = '/sys/user/recycleBin', + putRecycleBin = '/sys/user/putRecycleBin', + deleteRecycleBin = '/sys/user/deleteRecycleBin', + allRolesList = '/sys/role/queryall', + allRolesListNoByTenant = '/sys/role/queryallNoByTenant', + allTenantList = '/sys/tenant/queryList', + allPostList = '/sys/position/list', + userDepartList = '/sys/user/userDepartList', + changePassword = '/sys/user/changePassword', + frozenBatch = '/sys/user/frozenBatch', + getUserAgent = '/sys/sysUserAgent/queryByUserName', + userQuitAgent = '/sys/user/userQuitAgent', + getQuitList = '/sys/user/getQuitList', + putCancelQuit = '/sys/user/putCancelQuit', + updateUserTenantStatus='/sys/tenant/updateUserTenantStatus', + getUserTenantPageList='/sys/tenant/getUserTenantPageList', +} +/** + * 导出api + * @param params + */ +export const getExportUrl = Api.exportXls; +/** + * 导入api + */ +export const getImportUrl = Api.importExcel; +/** + * 列表接口(查询用户,通过租户隔离) + * @param params + */ +export const list = (params) => defHttp.get({ url: Api.list, params }); + +/** + * 列表接口(查询全部用户,不通过租户隔离) + * @param params + */ +export const listNoCareTenant = (params) => defHttp.get({ url: Api.listNoCareTenant, params }); + +/** + * 用户角色接口 + * @param params + */ +export const getUserRoles = (params) => defHttp.get({ url: Api.getUserRole, params }, { errorMessageMode: 'none' }); + +/** + * 删除用户 + */ +export const deleteUser = (params, handleSuccess) => { + return defHttp.delete({ url: Api.deleteUser, params }, { joinParamsToUrl: true }).then(() => { + handleSuccess(); + }); +}; +/** + * 批量删除用户 + * @param params + */ +export const batchDeleteUser = (params, handleSuccess) => { + Modal.confirm({ + title: '确认删除', + content: '是否删除选中数据', + okText: '确认', + cancelText: '取消', + onOk: () => { + return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => { + handleSuccess(); + }); + }, + }); +}; +/** + * 保存或者更新用户 + * @param params + */ +export const saveOrUpdateUser = (params, isUpdate) => { + let url = isUpdate ? Api.edit : Api.save; + return defHttp.post({ url: url, params }); +}; +/** + * 唯一校验 + * @param params + */ +export const duplicateCheck = (params) => defHttp.get({ url: Api.duplicateCheck, params }, { isTransformResponse: false }); + +/** + * 20231215 + * liaozhiyang + * 唯一校验( 延迟【防抖】) + * @param params + */ +let timer; +export const duplicateCheckDelay = (params) => { + return new Promise((resove, rejected) => { + clearTimeout(timer); + timer = setTimeout(() => { + defHttp + .get({ url: Api.duplicateCheck, params }, { isTransformResponse: false }) + .then((res: any) => { + resove(res as any); + }) + .catch((error) => { + rejected(error); + }); + }, 500); + }); +}; +/** + * 获取全部角色(租户隔离) + * @param params + */ +export const getAllRolesList = (params) => defHttp.get({ url: Api.allRolesList, params }); +/** + * 获取全部角色(不租户隔离) + * @param params + */ +export const getAllRolesListNoByTenant = (params) => defHttp.get({ url: Api.allRolesListNoByTenant, params }); +/** + * 获取全部租户 + */ +export const getAllTenantList = (params) => defHttp.get({ url: Api.allTenantList, params }); +/** + * 获取指定用户负责部门 + */ +export const getUserDepartList = (params) => defHttp.get({ url: Api.userDepartList, params }, { successMessageMode: 'none' }); +/** + * 获取全部职务 + */ +export const getAllPostList = (params) => { + return new Promise((resolve) => { + defHttp.get({ url: Api.allPostList, params }).then((res) => { + resolve(res.records); + }); + }); +}; +/** + * 回收站列表 + * @param params + */ +export const getRecycleBinList = (params) => defHttp.get({ url: Api.recycleBinList, params }); +/** + * 回收站还原 + * @param params + */ +export const putRecycleBin = (params, handleSuccess) => { + return defHttp.put({ url: Api.putRecycleBin, params }).then(() => { + handleSuccess(); + }); +}; +/** + * 回收站删除 + * @param params + */ +export const deleteRecycleBin = (params, handleSuccess) => { + return defHttp.delete({ url: Api.deleteRecycleBin, params }, { joinParamsToUrl: true }).then(() => { + handleSuccess(); + }); +}; +/** + * 修改密码 + * @param params + */ +export const changePassword = (params) => { + return defHttp.put({ url: Api.changePassword, params }); +}; +/** + * 冻结解冻 + * @param params + */ +export const frozenBatch = (params, handleSuccess) => { + return defHttp.put({ url: Api.frozenBatch, params }).then(() => { + handleSuccess(); + }); +}; +/** + * 获取用户代理 + * @param params + */ +export const getUserAgent = (params) => defHttp.get({ url: Api.getUserAgent, params }, { isTransformResponse: false }); +/** + * 保存或者更新用户代理 + * @param params + */ +export const saveOrUpdateAgent = (params) => { + let url = params.id ? Api.agentEdit : Api.agentSave; + return defHttp.post({ url: url, params }); +}; + +/** + * 用户离职(新增代理人和用户状态变更操作) + * @param params + */ +export const userQuitAgent = (params) => { + return defHttp.put({ url: Api.userQuitAgent, params }); +}; + +/** + * 用户离职列表 + * @param params + */ +export const getQuitList = (params) => { + return defHttp.get({ url: Api.getQuitList, params }); +}; + +/** + * 取消离职 + * @param params + */ +export const putCancelQuit = (params, handleSuccess) => { + return defHttp.put({ url: Api.putCancelQuit, params }, { joinParamsToUrl: true }).then(() => { + handleSuccess(); + }); +}; + +/** + * 待审批获取列表数据 + */ +export const getUserTenantPageList = (params) => { + return defHttp.get({ url: Api.getUserTenantPageList, params }); +}; + +/** + * 更新租户状态 + * @param params + */ +export const updateUserTenantStatus = (params) => { + return defHttp.put({ url: Api.updateUserTenantStatus, params }, { joinParamsToUrl: true, isTransformResponse: false }); +}; diff --git a/src/views/system/user-old/user.data.ts b/src/views/system/user-old/user.data.ts new file mode 100644 index 0000000..c89ed1d --- /dev/null +++ b/src/views/system/user-old/user.data.ts @@ -0,0 +1,557 @@ +import { BasicColumn } from '/@/components/Table'; +import { FormSchema } from '/@/components/Table'; +import { getAllRolesListNoByTenant, getAllTenantList } from './user.api'; +import { rules } from '/@/utils/helper/validator'; +import { render } from '/@/utils/common/renderUtils'; +export const columns: BasicColumn[] = [ + { + title: '用户账号', + dataIndex: 'username', + width: 120, + }, + { + title: '用户姓名', + dataIndex: 'realname', + width: 100, + }, + { + title: '头像', + dataIndex: 'avatar', + width: 120, + customRender: render.renderAvatar, + }, + { + title: '性别', + dataIndex: 'sex', + width: 80, + sorter: true, + customRender: ({ text }) => { + return render.renderDict(text, 'sex'); + }, + }, + /*{ + title: '生日', + dataIndex: 'birthday', + width: 100, + },*/ + { + title: '手机号', + dataIndex: 'phone', + width: 100, + }, + { + title: '部门', + width: 150, + dataIndex: 'orgCodeTxt', + }, + /*{ + title: '负责部门', + width: 150, + dataIndex: 'departIds_dictText', + },*/ + { + title: '状态', + dataIndex: 'status_dictText', + width: 80, + }, +]; + +export const recycleColumns: BasicColumn[] = [ + { + title: '用户账号', + dataIndex: 'username', + width: 100, + }, + { + title: '用户姓名', + dataIndex: 'realname', + width: 100, + }, + { + title: '头像', + dataIndex: 'avatar', + width: 80, + customRender: render.renderAvatar, + }, + { + title: '性别', + dataIndex: 'sex', + width: 80, + sorter: true, + customRender: ({ text }) => { + return render.renderDict(text, 'sex'); + }, + }, +]; + +export const searchFormSchema: FormSchema[] = [ + { + label: '账号', + field: 'username', + component: 'JInput', + //colProps: { span: 6 }, + }, + { + label: '名字', + field: 'realname', + component: 'JInput', + //colProps: { span: 6 }, + }, + { + label: '性别', + field: 'sex', + component: 'JDictSelectTag', + componentProps: { + dictCode: 'sex', + placeholder: '请选择性别', + stringToNumber: true, + }, + //colProps: { span: 6 }, + }, + { + label: '手机号码', + field: 'phone', + component: 'Input', + //colProps: { span: 6 }, + }, + { + label: '用户状态', + field: 'status', + component: 'JDictSelectTag', + componentProps: { + dictCode: 'user_status', + placeholder: '请选择状态', + stringToNumber: true, + }, + //colProps: { span: 6 }, + }, +]; + +export const formSchema: FormSchema[] = [ + { + label: '', + field: 'id', + component: 'Input', + show: false, + }, + { + label: '用户账号', + field: 'username', + component: 'Input', + dynamicDisabled: ({ values }) => { + return !!values.id; + }, + dynamicRules: ({ model, schema }) => rules.duplicateCheckRule('sys_user', 'username', model, schema, true), + }, + { + label: '登录密码', + field: 'password', + component: 'StrengthMeter', + rules: [ + { + required: true, + message: '请输入登录密码', + }, + /*{ + pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,./]).{8,}$/, + message: '密码由8位数字、大小写字母和特殊符号组成!', + },*/ + ], + }, + { + label: '确认密码', + field: 'confirmPassword', + component: 'InputPassword', + dynamicRules: ({ values }) => rules.confirmPassword(values, true), + }, + { + label: '用户姓名', + field: 'realname', + required: true, + component: 'Input', + }, + { + label: '工号', + field: 'workNo', + required: false, + component: 'Input', + dynamicRules: ({ model, schema }) => rules.duplicateCheckRule('sys_user', 'work_no', model, schema, true), + }, + /*{ + label: '职务', + field: 'post', + required: false, + component: 'JSelectPosition', + componentProps: { + labelKey: 'name', + }, + },*/ + { + label: '角色', + field: 'selectedroles', + component: 'ApiSelect', + componentProps: { + mode: 'multiple', + api: getAllRolesListNoByTenant, + labelField: 'roleName', + valueField: 'id', + immediate: false, + }, + }, + { + label: '所属部门', + field: 'selecteddeparts', + component: 'JSelectDept', + componentProps: ({ formActionType, formModel }) => { + return { + sync: false, + checkStrictly: true, + defaultExpandLevel: 2, + + onSelect: (options, values) => { + const { updateSchema } = formActionType; + //所属部门修改后更新负责部门下拉框数据 + updateSchema([ + { + field: 'departIds', + componentProps: { options }, + }, + ]); + //所属部门修改后更新负责部门数据 + formModel.departIds && (formModel.departIds = formModel.departIds.filter((item) => values.value.indexOf(item) > -1)); + }, + }; + }, + }, + { + label: '租户', + field: 'relTenantIds', + component: 'ApiSelect', + componentProps: { + mode: 'multiple', + api: getAllTenantList, + numberToString: true, + labelField: 'name', + valueField: 'id', + immediate: false, + }, + }, + { + label: '身份', + field: 'userIdentity', + component: 'RadioGroup', + defaultValue: 1, + componentProps: ({ formModel }) => { + return { + options: [ + { label: '普通用户', value: 1, key: '1' }, + { label: '上级', value: 2, key: '2' }, + ], + onChange: () => { + formModel.userIdentity == 1 && (formModel.departIds = []); + }, + }; + }, + }, + { + label: '负责部门', + field: 'departIds', + component: 'Select', + componentProps: { + mode: 'multiple', + }, + ifShow: ({ values }) => values.userIdentity == 2, + }, + { + label: '头像', + field: 'avatar', + component: 'JImageUpload', + componentProps: { + fileMax: 1, + }, + }, + { + label: '生日', + field: 'birthday', + component: 'DatePicker', + }, + { + label: '性别', + field: 'sex', + component: 'JDictSelectTag', + componentProps: { + dictCode: 'sex', + placeholder: '请选择性别', + stringToNumber: true, + }, + }, + { + label: '邮箱', + field: 'email', + component: 'Input', + dynamicRules: ({ model, schema }) => { + return [ + { ...rules.duplicateCheckRule('sys_user', 'email', model, schema, true)[0], trigger: 'blur' }, + { ...rules.rule('email', false)[0], trigger: 'blur' }, + ]; + }, + }, + { + label: '手机号码', + field: 'phone', + component: 'Input', + dynamicRules: ({ model, schema }) => { + return [ + { ...rules.duplicateCheckRule('sys_user', 'phone', model, schema, true)[0], trigger: 'blur' }, + { pattern: /^1[3456789]\d{9}$/, message: '手机号码格式有误', trigger: 'blur' }, + ]; + }, + }, + { + label: '座机', + field: 'telephone', + component: 'Input', + rules: [{ pattern: /^0\d{2,3}-[1-9]\d{6,7}$/, message: '请输入正确的座机号码' }], + }, + { + label: '工作流引擎', + field: 'activitiSync', + defaultValue: 1, + component: 'JDictSelectTag', + componentProps: { + dictCode: 'activiti_sync', + type: 'radio', + stringToNumber: true, + }, + }, +]; + +export const formPasswordSchema: FormSchema[] = [ + { + label: '用户账号', + field: 'username', + component: 'Input', + componentProps: { readOnly: true }, + }, + { + label: '登录密码', + field: 'password', + component: 'StrengthMeter', + componentProps: { + placeholder: '请输入登录密码', + }, + rules: [ + { + required: true, + message: '请输入登录密码', + }, + /*{ + pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,./]).{8,}$/, + message: '密码由8位数字、大小写字母和特殊符号组成!', + },*/ + ], + }, + { + label: '确认密码', + field: 'confirmPassword', + component: 'InputPassword', + dynamicRules: ({ values }) => rules.confirmPassword(values, true), + }, +]; + +export const formAgentSchema: FormSchema[] = [ + { + label: '', + field: 'id', + component: 'Input', + show: false, + }, + { + field: 'userName', + label: '用户名', + component: 'Input', + componentProps: { + readOnly: true, + allowClear: false, + }, + }, + { + field: 'agentUserName', + label: '代理人用户名', + required: true, + component: 'JSelectUser', + componentProps: { + rowKey: 'username', + labelKey: 'realname', + maxSelectCount: 10, + }, + }, + { + field: 'startTime', + label: '代理开始时间', + component: 'DatePicker', + required: true, + componentProps: { + showTime: true, + valueFormat: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择代理开始时间', + getPopupContainer: () => document.body, + }, + }, + { + field: 'endTime', + label: '代理结束时间', + component: 'DatePicker', + required: true, + componentProps: { + showTime: true, + valueFormat: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择代理结束时间', + getPopupContainer: () => document.body, + }, + }, + { + field: 'status', + label: '状态', + component: 'JDictSelectTag', + defaultValue: '1', + componentProps: { + dictCode: 'valid_status', + type: 'radioButton', + }, + }, +]; + +export const formQuitAgentSchema: FormSchema[] = [ + { + label: '', + field: 'id', + component: 'Input', + show: false, + }, + { + field: 'userName', + label: '用户名', + component: 'Input', + componentProps: { + readOnly: true, + allowClear: false, + }, + }, + { + field: 'agentUserName', + label: '交接人员', + required: true, + component: 'JSelectUser', + componentProps: { + rowKey: 'username', + labelKey: 'realname', + maxSelectCount: 1, + }, + }, + { + field: 'startTime', + label: '交接开始时间', + component: 'DatePicker', + required: true, + componentProps: { + showTime: true, + valueFormat: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择交接开始时间', + getPopupContainer: () => document.body, + }, + }, + { + field: 'endTime', + label: '交接结束时间', + component: 'DatePicker', + required: true, + componentProps: { + showTime: true, + valueFormat: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择交接结束时间', + getPopupContainer: () => document.body, + }, + }, + { + field: 'status', + label: '状态', + component: 'JDictSelectTag', + defaultValue: '1', + componentProps: { + dictCode: 'valid_status', + type: 'radioButton', + }, + }, +]; + +//租户用户列表 +export const userTenantColumns: BasicColumn[] = [ + { + title: '用户账号', + dataIndex: 'username', + width: 120, + }, + { + title: '用户姓名', + dataIndex: 'realname', + width: 100, + }, + { + title: '头像', + dataIndex: 'avatar', + width: 120, + customRender: render.renderAvatar, + }, + { + title: '手机号', + dataIndex: 'phone', + width: 100, + }, + { + title: '部门', + width: 150, + dataIndex: 'orgCodeTxt', + }, + { + title: '状态', + dataIndex: 'status', + width: 80, + customRender: ({ text }) => { + if (text === '1') { + return '正常'; + } else if (text === '3') { + return '审批中'; + } else { + return '已拒绝'; + } + }, + }, +]; + +//用户租户搜索表单 +export const userTenantFormSchema: FormSchema[] = [ + { + label: '账号', + field: 'username', + component: 'Input', + colProps: { span: 6 }, + }, + { + label: '名字', + field: 'realname', + component: 'Input', + colProps: { span: 6 }, + }, + { + label: '性别', + field: 'sex', + component: 'JDictSelectTag', + componentProps: { + dictCode: 'sex', + placeholder: '请选择性别', + stringToNumber: true, + }, + colProps: { span: 6 }, + }, +]; diff --git a/src/views/system/user-old/userDetails.vue b/src/views/system/user-old/userDetails.vue new file mode 100644 index 0000000..c0a8cd4 --- /dev/null +++ b/src/views/system/user-old/userDetails.vue @@ -0,0 +1,54 @@ + + diff --git a/src/views/system/user/user.data.ts b/src/views/system/user/user.data.ts index 9e95ecf..c89ed1d 100644 --- a/src/views/system/user/user.data.ts +++ b/src/views/system/user/user.data.ts @@ -29,11 +29,11 @@ export const columns: BasicColumn[] = [ return render.renderDict(text, 'sex'); }, }, - { + /*{ title: '生日', dataIndex: 'birthday', width: 100, - }, + },*/ { title: '手机号', dataIndex: 'phone', @@ -44,11 +44,11 @@ export const columns: BasicColumn[] = [ width: 150, dataIndex: 'orgCodeTxt', }, - { + /*{ title: '负责部门', width: 150, dataIndex: 'departIds_dictText', - }, + },*/ { title: '状态', dataIndex: 'status_dictText', @@ -173,11 +173,11 @@ export const formSchema: FormSchema[] = [ { label: '工号', field: 'workNo', - required: true, + required: false, component: 'Input', dynamicRules: ({ model, schema }) => rules.duplicateCheckRule('sys_user', 'work_no', model, schema, true), }, - { + /*{ label: '职务', field: 'post', required: false, @@ -185,7 +185,7 @@ export const formSchema: FormSchema[] = [ componentProps: { labelKey: 'name', }, - }, + },*/ { label: '角色', field: 'selectedroles', diff --git a/src/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnroll.api.ts b/src/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnroll.api.ts index 8c69f29..54cf751 100644 --- a/src/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnroll.api.ts +++ b/src/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnroll.api.ts @@ -3,15 +3,30 @@ import { useMessage } from "/@/hooks/web/useMessage"; const { createConfirm } = useMessage(); + enum Api { list = '/yx/yxHistoryMajorEnroll/list', - save='/yx/yxHistoryMajorEnroll/add', - edit='/yx/yxHistoryMajorEnroll/edit', + getData = '/yx/yxHistoryMajorEnroll/list', + // 模拟保存单行数据(即时保存) + saveRow = '/yx/yxHistoryMajorEnroll/edit', + // 模拟保存整个表格的数据 + saveAll = '/yx/yxHistoryMajorEnroll/saveBatch', + save = '/yx/yxHistoryMajorEnroll/add', + edit = '/yx/yxHistoryMajorEnroll/edit', deleteOne = '/yx/yxHistoryMajorEnroll/delete', deleteBatch = '/yx/yxHistoryMajorEnroll/deleteBatch', importExcel = '/yx/yxHistoryMajorEnroll/importExcel', exportXls = '/yx/yxHistoryMajorEnroll/exportXls', + // exportXls = '/yx/yxHistoryMajorEnroll/exportXlsBySchoolMajor', + renewControlLine = '/yx/yxHistoryMajorEnroll/renewControlLine' } + +export const getData = Api.getData; +export const saveRow = Api.saveRow; +export const saveAll = Api.saveAll; +export const deleteBatch = Api.deleteBatch; +export const renewControlLine = Api.renewControlLine; + /** * 导出api * @param params diff --git a/src/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnroll.data.ts b/src/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnroll.data.ts index b22d272..8c9644d 100644 --- a/src/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnroll.data.ts +++ b/src/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnroll.data.ts @@ -2,6 +2,154 @@ import {BasicColumn} from '/@/components/Table'; import {FormSchema} from '/@/components/Table'; import { rules} from '/@/utils/helper/validator'; import { render } from '/@/utils/common/renderUtils'; +import {JVxeColumn, JVxeTypes} from '/@/components/jeecg/JVxeTable/types'; +import { ref } from 'vue'; + +export const columnsN = ref([ + /*{ key: 'num', title: '序号', width: 80, type: JVxeTypes.normal },*/ + { + title: '学校代码', + key: 'schoolCode', + width: 100, + type: JVxeTypes.input, + }, + { + title: '院校代码', + key: 'institutionCode', + width: 100, + type: JVxeTypes.input, + }, + { + title: '学校名称', + key: 'schoolName', + width: 150, + type: JVxeTypes.input, + }, + { + title: '专业代码', + key: 'majorCode', + width: 100, + type: JVxeTypes.input, + }, + { + title: '专业名称', + key: 'majorName', + width: 200, + type: JVxeTypes.textarea, + }, + { + title: '招生代码', + key: 'enrollmentCode', + width: 100, + type: JVxeTypes.input, + }, + { + title: '专业类型', + key: 'majorType', + width: 130, + type: JVxeTypes.input, + }, + { + title: '专业类别子级', + key: 'majorTypeChild', + width: 130, + type: JVxeTypes.input, + }, + { + title: '主考科目', + key: 'mainSubjects', + width: 130, + type: JVxeTypes.input, + }, + { + title: '年份', + key: 'year', + width: 100, + type: JVxeTypes.inputNumber, + }, + { + title: '科类(文科/理科)', + key: 'category', + width: 100, + type: JVxeTypes.input, + }, + { + title: '批次', + key: 'batch', + width: 100, + type: JVxeTypes.input, + }, + { + title: '录取方式(文*x+专*y)', + key: 'rulesEnrollProbability', + width: 150, + type: JVxeTypes.input, + }, + { + title: '录取概率计算规则运算符', + key: 'probabilityOperator', + width: 150, + type: JVxeTypes.input, + }, + { + title: '省控线', + key: 'controlLine', + width: 100, + type: JVxeTypes.inputNumber, + }, + { + title: '录取线', + key: 'admissionLine', + width: 100, + type: JVxeTypes.inputNumber, + }, + { + title: '招生人数', + key: 'enrollNum', + width: 100, + type: JVxeTypes.inputNumber, + }, + { + title: '实际投档人数', + key: 'actualPitcherNum', + width: 100, + type: JVxeTypes.inputNumber, + }, + { + title: '录取数', + key: 'admissionNum', + width: 100, + type: JVxeTypes.inputNumber, + }, + { + title: '一志愿录取数', + key: 'oneVolunteerAdmissionNum', + width: 100, + type: JVxeTypes.inputNumber, + }, + { + title: '最低分数差', + key: 'scoreLineDifference', + width: 100, + type: JVxeTypes.inputNumber, + }, + { + title: '学费', + key: 'tuition', + width: 200, + type: JVxeTypes.input, + }, + { + title: '备注', + key: 'detail', + width: 200, + type: JVxeTypes.textarea, + } + +]); + + + //列表数据 export const columns: BasicColumn[] = [ { diff --git a/src/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnrollList.vue b/src/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnrollList.vue index 5bc845e..4fcdb15 100644 --- a/src/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnrollList.vue +++ b/src/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnrollList.vue @@ -59,8 +59,8 @@ 查询 重置 - 刷新省控线 - 导出 + + 导出 导入 @@ -94,7 +94,9 @@ import {defHttp} from '/@/utils/http/axios'; import {JVxeColumn, JVxeTypes} from '/@/components/jeecg/JVxeTable/types'; import {useMessage} from '/@/hooks/web/useMessage'; import {useListPage} from "@/hooks/system/useListPage"; -import {getExportUrl, getImportUrl, list} from "@/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnroll.api"; + +import {columnsN } from "@/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnroll.data"; +import {getData,saveRow,saveAll,deleteBatch,getExportUrl,getImportUrl,renewControlLine} from "@/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnroll.api"; import {XLSX_FILE_SUFFIX, XLSX_MIME_TYPE} from "@/hooks/system/useMethods"; const { createMessage, createConfirm, createSuccessModal, createInfoModal, createErrorModal, createWarningModal, notification } = useMessage(); const labelCol = reactive({ @@ -119,6 +121,7 @@ const queryParam = reactive({ majorType: '',//专业类别 category: '',//文理分科 year: '',//年份 + batch:'',//批次 }) // 分页器参数 const pagination = reactive({ @@ -136,148 +139,7 @@ const selectedRows = ref([]); // 数据源,控制表格的数据 const dataSource = ref([]); // 列配置,控制表格显示的列 -const columns = ref([ - /*{ key: 'num', title: '序号', width: 80, type: JVxeTypes.normal },*/ - { - title: '学校代码', - key: 'schoolCode', - width: 100, - type: JVxeTypes.input, - }, - { - title: '院校代码', - key: 'institutionCode', - width: 100, - type: JVxeTypes.input, - }, - { - title: '学校名称', - key: 'schoolName', - width: 150, - type: JVxeTypes.input, - }, - { - title: '专业代码', - key: 'majorCode', - width: 100, - type: JVxeTypes.input, - }, - { - title: '专业名称', - key: 'majorName', - width: 200, - type: JVxeTypes.textarea, - }, - { - title: '招生代码', - key: 'enrollmentCode', - width: 100, - type: JVxeTypes.input, - }, - { - title: '专业类型', - key: 'majorType', - width: 130, - type: JVxeTypes.input, - }, - { - title: '专业类别子级', - key: 'majorTypeChild', - width: 130, - type: JVxeTypes.input, - }, - { - title: '主考科目', - key: 'mainSubjects', - width: 130, - type: JVxeTypes.input, - }, - { - title: '年份', - key: 'year', - width: 100, - type: JVxeTypes.inputNumber, - }, - { - title: '科类(文科/理科)', - key: 'category', - width: 100, - type: JVxeTypes.input, - }, - { - title: '批次', - key: 'batch', - width: 100, - type: JVxeTypes.input, - }, - { - title: '录取方式(文*x+专*y)', - key: 'rulesEnrollProbability', - width: 150, - type: JVxeTypes.input, - }, - { - title: '录取概率计算规则运算符', - key: 'probabilityOperator', - width: 150, - type: JVxeTypes.input, - }, - { - title: '省控线', - key: 'controlLine', - width: 100, - type: JVxeTypes.inputNumber, - }, - { - title: '录取线', - key: 'admissionLine', - width: 100, - type: JVxeTypes.inputNumber, - }, - { - title: '招生人数', - key: 'enrollNum', - width: 100, - type: JVxeTypes.inputNumber, - }, - { - title: '实际投档人数', - key: 'actualPitcherNum', - width: 100, - type: JVxeTypes.inputNumber, - }, - { - title: '录取数', - key: 'admissionNum', - width: 100, - type: JVxeTypes.inputNumber, - }, - { - title: '一志愿录取数', - key: 'oneVolunteerAdmissionNum', - width: 100, - type: JVxeTypes.inputNumber, - }, - { - title: '最低分数差', - key: 'scoreLineDifference', - width: 100, - type: JVxeTypes.inputNumber, - }, - { - title: '学费', - key: 'tuition', - width: 200, - type: JVxeTypes.input, - }, - { - title: '备注', - key: 'detail', - width: 200, - type: JVxeTypes.textarea, - } - -]); +const columns = columnsN; const [messageApi, contextHolder] = message.useMessage(); const { prefixCls,tableContext,onImportXls } = useListPage({ tableProps:{ @@ -291,18 +153,6 @@ const { prefixCls,tableContext,onImportXls } = useListPage({ }) // 查询url地址 -enum Api { - getData = '/yx/yxHistoryMajorEnroll/list', - // 模拟保存单行数据(即时保存) - saveRow = '/yx/yxHistoryMajorEnroll/edit', - // 模拟保存整个表格的数据 - saveAll = '/yx/yxHistoryMajorEnroll/saveBatch', - deleteBatch = '/yx/yxHistoryMajorEnroll/deleteBatch', - importExcel = '/yx/yxHistoryMajorEnroll/importExcel', - exportXls = '/yx/yxHistoryMajorEnroll/exportXls', - renewControlLine = '/yx/yxHistoryMajorEnroll/renewControlLine' -} - loadData(); async function searchQuery() { @@ -318,6 +168,7 @@ async function searchReset() { queryParam.majorType = ''//专业类别 queryParam.category = ''//文理分科 queryParam.year = '' + queryParam.batch = '' loadData() } @@ -328,7 +179,7 @@ async function loadData() { await defHttp .get({ // 请求地址 - url: Api.getData, + url: getData, // 封装查询条件 params: { schoolCode: queryParam.schoolCode ? '*' + queryParam.schoolCode + '*' : '', @@ -336,6 +187,7 @@ async function loadData() { majorType: queryParam.majorType, category: queryParam.category, year: queryParam.year, + batch: queryParam.batch, pageNo: pagination.current, pageSize: pagination.pageSize, }, @@ -355,7 +207,7 @@ async function loadData() { } //刷新省控线 -async function renewControlLine(){ +async function handleRenewControlLine(){ console.log('刷新省控线') let selections = '' if (selectedRows.value) { @@ -376,7 +228,7 @@ async function renewControlLine(){ return new Promise((resolve, reject) => { defHttp .post({ - url: Api.renewControlLine, + url: renewControlLine, params: {id:selections}, }) .then((res) => { @@ -419,7 +271,7 @@ function handleTableSave({$table, target}) { loading.value = true; defHttp .post({ - url: Api.saveAll, + url: saveAll, params: tableData, }) .then(() => { @@ -444,7 +296,7 @@ function handleTableRemove(event) { window.setTimeout(() => { defHttp .delete({ - url: Api.deleteBatch, data: {ids: deleteIds.join(',')} + url: deleteBatch, data: {ids: deleteIds.join(',')} }, {joinParamsToUrl: true}) .then((res) => { createMessage.success('删除成功'); @@ -472,7 +324,7 @@ function handleEditClosed(event) { console.log('即时保存数据:', row); defHttp .put({ - url: Api.saveRow, + url: saveRow, params: row, }) .then((res) => { @@ -514,7 +366,7 @@ function handleSelectRowChange(event) { * @param name * @param url */ -async function exportXls(isXlsx = false) { +async function onExportXls(isXlsx = false) { let name = '' let selections = '' if (selectedRows.value) { @@ -523,7 +375,7 @@ async function exportXls(isXlsx = false) { }) console.log(selectedRows.value) } - const data = await defHttp.get({ url: Api.exportXls, params: {selections:selections}, responseType: 'blob', timeout: 60000 }, { isTransformResponse: false }); + const data = await defHttp.get({ url: getExportUrl, params: {selections:selections}, responseType: 'blob', timeout: 60000 }, { isTransformResponse: false }); if (!data) { createMessage.warning('文件下载失败'); return; diff --git a/src/views/yx/yxOrder/YxOrder.api.ts b/src/views/yx/yxOrder/YxOrder.api.ts index fd60f92..533dfdf 100644 --- a/src/views/yx/yxOrder/YxOrder.api.ts +++ b/src/views/yx/yxOrder/YxOrder.api.ts @@ -11,6 +11,7 @@ enum Api { deleteBatch = '/yx/yxOrder/deleteBatch', importExcel = '/yx/yxOrder/importExcel', exportXls = '/yx/yxOrder/exportXls', + refundUrl = '/yx/yxOrder/refund', } /** * 导出api @@ -62,3 +63,8 @@ export const saveOrUpdate = (params, isUpdate) => { let url = isUpdate ? Api.edit : Api.save; return defHttp.post({url: url, params}); } + + +export const refund = (params)=>{ + return defHttp.post({url: Api.refundUrl, params}); +} diff --git a/src/views/yx/yxOrder/YxOrder.data.ts b/src/views/yx/yxOrder/YxOrder.data.ts index 01002b3..f62de86 100644 --- a/src/views/yx/yxOrder/YxOrder.data.ts +++ b/src/views/yx/yxOrder/YxOrder.data.ts @@ -21,22 +21,41 @@ export const columns: BasicColumn[] = [ return '未知'; }, }, + { + title: '退款金额', + align: "center", + dataIndex: 'refundAmount', + customRender: ({text}) => { + if(text){ + return parseFloat(text)/100 + } + return ''; + }, + }, { title: '商品编号', align: "center", dataIndex: 'skuCode', customRender: ({text}) => { if (text === '1001') { - return '体验卡'; + return '艺体志愿宝-体验卡'; }else if(text ==='1002'){ - return 'VIP'; + return '艺体志愿宝-VIP'; }else if(text ==='9999'){ - return '管理员'; + return '艺体志愿宝-管理员'; + }else if(text ==='2002'){ + return '体育志愿宝-VIP'; }else{ return '未知'; } }, }, + { + title: '操作平台', + //1借记卡、2信用卡、3微信、4支付宝、5现金 + align: "center", + dataIndex: 'provider', + }, { title: '支付方式', //1借记卡、2信用卡、3微信、4支付宝、5现金 @@ -68,6 +87,14 @@ export const columns: BasicColumn[] = [ sorter: { multiple: 2 } + },{ + title: '退款时间', + align: "center", + dataIndex: 'refundTime',//paymentUserId + resizable: true, + sorter: { + multiple: 2 + } }, ]; //查询数据 diff --git a/src/views/yx/yxOrder/YxOrderList.vue b/src/views/yx/yxOrder/YxOrderList.vue index fd810ff..8124b0f 100644 --- a/src/views/yx/yxOrder/YxOrderList.vue +++ b/src/views/yx/yxOrder/YxOrderList.vue @@ -11,14 +11,36 @@ allowClear="true"> - + 请选择 - 体验卡 - VIP - 管理员 + 艺体志愿宝-体验卡 + 艺体志愿宝-VIP + 艺体志愿宝-管理员 + 体育志愿宝-VIP + + + + + + + 请选择 + 微信 + 抖音 + + + + + + + 请选择 + 微信 + 抖音 + 支付宝 @@ -29,10 +51,13 @@ 请选择 {{getStatusText("1")}} {{getStatusText("2")}} + {{getStatusText("8")}} {{getStatusText("-1")}} + + 查询 重置 @@ -61,29 +86,42 @@ + - - - diff --git a/src/views/yx/yxSchool/YxSchoolList2.vue b/src/views/yx/yxSchool/YxSchoolList2.vue new file mode 100644 index 0000000..ea7ff8b --- /dev/null +++ b/src/views/yx/yxSchool/YxSchoolList2.vue @@ -0,0 +1,217 @@ + + + + + diff --git a/src/views/yx/yxSchool/components/NotSchoolModal.vue b/src/views/yx/yxSchool/components/NotSchoolModal.vue new file mode 100644 index 0000000..0106fe4 --- /dev/null +++ b/src/views/yx/yxSchool/components/NotSchoolModal.vue @@ -0,0 +1,79 @@ + + diff --git a/src/views/yx/yxSchool/components/YxSchoolForm.vue b/src/views/yx/yxSchool/components/YxSchoolForm.vue index c6cc003..581d394 100644 --- a/src/views/yx/yxSchool/components/YxSchoolForm.vue +++ b/src/views/yx/yxSchool/components/YxSchoolForm.vue @@ -1,70 +1,327 @@ - \ No newline at end of file + } + + /** + * 提交数据 + */ + async function submitForm() { + // 触发表单验证 + await validate(); + confirmLoading.value = true; + const isUpdate = ref(false); + //时间格式化 + let model = formData; + if (model.id) { + isUpdate.value = true; + } + //循环数据 + for (let data in model) { + //如果该数据是数组并且是字符串类型 + if (model[data] instanceof Array) { + let valueType = getValueType(formRef.value.getProps, data); + //如果是字符串类型的需要变成以逗号分割的字符串 + if (valueType === 'string') { + model[data] = model[data].join(','); + } + } + } + await saveOrUpdate(model, isUpdate.value) + .then((res) => { + if (res.success) { + createMessage.success(res.message); + emit('ok'); + } else { + createMessage.warning(res.message); + } + }) + .finally(() => { + confirmLoading.value = false; + }); + } + + + defineExpose({ + add, + edit, + submitForm, + }); + + + diff --git a/src/views/yx/yxSchool/components/YxSchoolModal.vue b/src/views/yx/yxSchool/components/YxSchoolModal.vue index 9c9a87a..27d83cc 100644 --- a/src/views/yx/yxSchool/components/YxSchoolModal.vue +++ b/src/views/yx/yxSchool/components/YxSchoolModal.vue @@ -1,66 +1,75 @@ - \ No newline at end of file + diff --git a/src/views/yx/yxSchoolMajor/YxSchoolMajorList.vue b/src/views/yx/yxSchoolMajor/YxSchoolMajorList.vue index 6315bbd..5b46327 100644 --- a/src/views/yx/yxSchoolMajor/YxSchoolMajorList.vue +++ b/src/views/yx/yxSchoolMajor/YxSchoolMajorList.vue @@ -51,10 +51,23 @@ - + + + + 请选择 + 停招 + 招生 + 新增 + + + + + + 查询 - 导出 重置 + 导出 + 导入 @@ -67,8 +80,8 @@ + > + + + + + + @@ -93,6 +134,10 @@ import {JVxeColumn, JVxeTypes} from '/@/components/jeecg/JVxeTable/types'; import {useMessage} from '/@/hooks/web/useMessage'; import { useListPage } from '/@/hooks/system/useListPage'; import {XLSX_FILE_SUFFIX, XLSX_MIME_TYPE} from "@/hooks/system/useMethods"; +import {columnsN } from "@/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnroll.data"; +import { getImportUrl } from "@/views/yx/yxSchoolMajor/YxSchoolMajor.api"; +import {getData as getHistoryData,saveRow as saveHistoryRow} from "@/views/yx/yxHistoryMajorEnroll/YxHistoryMajorEnroll.api"; + const labelCol = reactive({ xs: {span: 24}, sm: {span: 7}, @@ -107,22 +152,29 @@ const toolbarConfig = reactive({ // add 新增按钮;remove 删除按钮;clearSelection 清空选择按钮 btn: ['add', 'save', 'remove', 'clearSelection'], }); +const subToolbarConfig = reactive({ + // add 新增按钮;remove 删除按钮;clearSelection 清空选择按钮 + btn: ['add'], +}); // 列表页面公共参数、方法 const { onExportXls, onImportXls } = useListPage({ - designScope: 'basic-table', - tableProps: { - showActionColumn: false, - useSearchForm: false, - }, - exportConfig: { - name: '示例列表', - url: '/test/jeecgDemo/exportXls', - }, - importConfig: { - url: '/test/jeecgDemo/importExcel', + tableProps:{ + title: '院校招录专业表', + canResize:false, }, + importConfig:{ + url: getImportUrl, + success: handleSuccess + } }); +/** + * 成功回调 + */ +function handleSuccess() { + loadData(); +} + // 是否正在加载 const loading = ref(false); // 查询参数 @@ -132,6 +184,7 @@ const queryParam = reactive({ majorType: '',//专业类别 category: '',//文理分科 batch:'',//批次 + state:'',//数据状态 }) // 分页器参数 const pagination = reactive({ @@ -146,11 +199,50 @@ const pagination = reactive({ }); // 选择的行 const selectedRows = ref([]); + +// 子表的信息 +const subTable = reactive({ + currentRowId: null, + loading: false, + pagination: { current: 1, pageSize: 0, pageSizeOptions: ['100', '200'], total: 0 }, + selectedRows: [], + dataSource: [] as any, + dataSource2: [] as any, + columns: columnsN, +}); // 数据源,控制表格的数据 const dataSource = ref([]); // 列配置,控制表格显示的列 const columns = ref([ /*{ key: 'num', title: '序号', width: 80, type: JVxeTypes.normal },*/ + { + title: '操作', + key: 'action', + type: JVxeTypes.slot, + fixed: 'right', + minWidth: 120, + align: 'center', + slotName: 'myAction', + }, + { + // 列的标题 + title: '数据状态', + // 字段key,跟后台数据的字段名匹配 + key: 'state', + // 列的宽度 + width: 100, + // 如果加上了该属性,就代表当前单元格是可编辑的,type就是表单的类型,input就是简单的输入框 + type: JVxeTypes.select, + // 下拉选项 + options: [ + { title: '停招', value: '0' }, + { title: '招生', value: '1' }, + { title: '新增', value: '2' } + ], + // allowInput: true, + allowSearch: true, + placeholder: '请选择', + }, { // 列的标题 title: '学校代码', @@ -323,6 +415,7 @@ enum Api { saveAll = '/yx/yxSchoolMajor/saveBatch', deleteBatch = '/yx/yxSchoolMajor/deleteBatch', exportXls = '/yx/yxSchoolMajor/exportXls', + importExcel = '/yx/yxSchoolMajor/importExcel', } loadData(); @@ -339,6 +432,7 @@ async function searchReset() { queryParam.majorType = '' queryParam.category = '' queryParam.batch = '' + queryParam.state = '' loadData() } @@ -357,6 +451,7 @@ async function loadData() { majorType:queryParam.majorType, category:queryParam.category, batch:queryParam.batch, + state:queryParam.state, pageNo: pagination.current, pageSize: pagination.pageSize, }, @@ -477,6 +572,94 @@ function handleSelectRowChange(event) { selectedRows.value = event.selectedRows; } + +function onLookRowHistoryScore(props) { + // createMessage.success('请在控制台查看输出'); + // console.log('查看: ', { props }); +} + +// 查询子表数据 +function loadSubData(row) { + if (row) { + // 这里一定要做限制,限制不能重复查询,否者会出现死循环 + if (subTable.currentRowId === row.id) { + return true; + } + subTable.currentRowId = row.id; + subTable.loading = true; + defHttp + .get({ + url: getHistoryData, + params: { + pageNo: 1, + pageSize: 30, + schoolCode: row.schoolCode, + majorName:row.majorName, + category:row.category, + batch:row.batch + }, + }) + .then((result) => { + // 将查询的数据赋值给 dataSource + subTable.dataSource = result.records; + subTable.dataSource2 = result.records; + }) + .finally(() => { + // 这里是无论成功或失败都会执行的方法,在这里关闭loading + subTable.loading = false; + }); + return true; + } else { + return false; + } +} + +// 子表单元格编辑完成之后触发的事件 +function handleHistoryScoreEditClosed(event) { + let {$table, row, column} = event; + let field = column.property; + console.log(event) + + // 判断单元格值是否被修改 + + if(subTable.dataSource2){ + let index = 0 + for(let i = 0;i { + // 校验通过 + if (!errMap) { + // 【模拟保存】 + let hideLoading = createMessage.loading(`正在保存"${column.title}"`, 0); + console.log('即时保存数据:', row); + defHttp + .put({ + url: saveHistoryRow, + params: row, + }) + .then((res) => { + createMessage.success(`"${column.title}"保存成功!`); + // 局部更新单元格为已保存状态 + $table.reloadRow(row, null, field); + subTable.dataSource[index] = row + subTable.dataSource2 = subTable.dataSource + }) + .finally(() => { + hideLoading(); + }); + } + }); + } +} + + + /** * 导出xls * @param name @@ -522,3 +705,4 @@ async function exportXls(isXlsx = false) { + diff --git a/src/views/yx/yxVipCard/YxVipCard.data.ts b/src/views/yx/yxVipCard/YxVipCard.data.ts index 6ba2815..d8322c1 100644 --- a/src/views/yx/yxVipCard/YxVipCard.data.ts +++ b/src/views/yx/yxVipCard/YxVipCard.data.ts @@ -27,6 +27,11 @@ export const columns: BasicColumn[] = [ return !text?"":(text.length>10?text.substr(0,10):text) }, },*/ + { + title: '所属应用', + align: 'center', + dataIndex: 'programType', + }, { title: '对应商品', align: "center", @@ -63,6 +68,11 @@ export const formSchema: FormSchema[] = [ field: 'validTime', component: 'InputNumber', }, + { + label: '所属应用', + field: 'programType', + component: 'Input', + }, /*{ label: '有效日期', field: 'validDate', diff --git a/src/views/yx/yxVipCard/YxVipCardList.vue b/src/views/yx/yxVipCard/YxVipCardList.vue index 2c7ad9f..29fd5e2 100644 --- a/src/views/yx/yxVipCard/YxVipCardList.vue +++ b/src/views/yx/yxVipCard/YxVipCardList.vue @@ -22,6 +22,16 @@ + + + + 请选择 + 艺体志愿宝 + 体育志愿宝 + + +