Files
geg-gas-web/src/views/system/user/components/UserModal.vue
‘huanghaiixia’ 03c943e4d6 签报弹框
2025-12-23 17:51:40 +08:00

894 lines
30 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit">
<a-tabs v-model:activeKey="activeKey" :class="{ 'h-full': ['3', '4', '5', '6'].includes(activeKey) }">
<a-tab-pane key="1" tab="基础信息">
<BasicForm @register="registerForm1" :style="{ 'margin-right': '10px' }">
<template #password="{ model, field }">
<a-input v-model:value="model[field]" :type="isShowPwd ? 'text' : 'password'" placeholder="请输入密码" @change="changePwd" allowClear>
<template #suffix>
<div class="input-state" v-if="model[field]">
<a-progress :percent="pwdPercent" :steps="3" :stroke-color="pwdColor" :showInfo="false" />
<span>{{ pwdText }}</span>
</div>
<Icon :icon="isShowPwd ? 'ant-design:eye-outlined' : 'ant-design:eye-invisible-outlined'" color="#00000073" @click="changeState" style="cursor: pointer" />
</template>
</a-input>
</template>
</BasicForm>
</a-tab-pane>
<a-tab-pane key="2" tab="身份信息" force-render>
<BasicForm @register="registerForm2" :style="{ 'margin-right': '10px' }" />
</a-tab-pane>
<a-tab-pane key="3" tab="角色信息" force-render>
<BasicTable @register="registerTable1">
<template #headerCell="{ column }">
<template v-if="column.flag === 'INDEX'">
<plus-outlined :style="{ color: '#5E95FF' }" @click="handleRoleCreate" />
</template>
<template v-else>{{ column.customTitle }}</template>
</template>
<template #action="{ index, record }">
<a-button type="link" danger @click="handleDelete(index, 1, record)">删除</a-button>
</template>
</BasicTable>
</a-tab-pane>
<a-tab-pane key="4" tab="岗位信息" force-render>
<BasicTable @register="registerTable2">
<template #headerCell="{ column }">
<template v-if="column.flag === 'INDEX'">
<plus-outlined :style="{ color: '#5E95FF' }" @click="handlePostCreate" />
</template>
<template v-else>{{ column.customTitle }}</template>
</template>
<template #action="{ index, record }">
<a-button type="link" danger @click="handleDelete(index, 2, record)">删除</a-button>
</template>
</BasicTable>
</a-tab-pane>
<a-tab-pane key="5" tab="负责部门" force-render>
<BasicTable @register="registerTable3">
<template #headerCell="{ column }">
<template v-if="column.flag === 'INDEX'">
<plus-outlined :style="{ color: '#5E95FF' }" @click="handleOrgCreate" />
</template>
<template v-else>{{ column.customTitle }}</template>
</template>
<template #action="{ index, record }">
<a-button type="link" danger @click="handleDelete(index, 3, record)">删除</a-button>
</template>
</BasicTable>
</a-tab-pane>
<a-tab-pane key="6" tab="所属部门" force-render>
<BasicTable @register="registerTable4">
<template #headerCell="{ column }">
<template v-if="column.flag === 'INDEX'">
<plus-outlined :style="{ color: '#5E95FF' }" @click="handleDeptCreate" />
</template>
<template v-else>{{ column.customTitle }}</template>
</template>
<template #action="{ index, record }">
<a-button type="link" danger @click="handleDelete(index, 4, record)">删除</a-button>
</template>
</BasicTable>
</a-tab-pane>
</a-tabs>
<RoleModal @register="registerRoleModal" @success="handleRoleSuccess" />
<PostModal @register="registerPostModal" @success="handlePostSuccess" />
<OrganizationModal @register="registerOrgModal" @success="handleOrgSuccess" />
<OrganizationModal @register="registerDeptModal" @success="handleDeptSuccess" />
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicModal, useModalInner, useModal } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { BasicTable, useTable, FormSchema, BasicColumn } from '/@/components/Table';
import { useMessage } from '/@/hooks/web/useMessage';
import { useI18n } from '/@/hooks/web/useI18n';
import { getDepartmentTree } from '/@/api/system/department';
import { addUser, getUser, updateUser, getUserNamePrefix } from '/@/api/system/user';
import Icon from '/@/components/Icon/index';
import { testPwdState } from '/@/utils/event/design';
import { PlusOutlined } from '@ant-design/icons-vue';
import RoleModal from './RoleModalV2.vue';
import PostModal from './PostModal.vue';
import OrganizationModal from './OrganizationModal.vue';
import { debounce } from 'lodash-es';
const { t } = useI18n();
const accountFormSchema: FormSchema[] = [
{
field: 'userName',
label: '账号',
component: 'Input',
colProps: { span: 12 },
rules: [
{
required: true,
validator: async (_, value) => {
let values = getFieldsValue1();
let prefix = await getUserNamePrefix();
if (!value) {
return Promise.reject('请输入账号');
}
if (values?.isSelfBuild === 'Y' && !value.startsWith(prefix)) {
return Promise.reject('自建用户账号必须带有前缀:' + prefix);
}
return Promise.resolve();
}
}
],
required: true,
componentProps: {
placeholder: '请输入账号'
}
},
{
field: 'name',
label: '用户姓名',
component: 'Input',
required: true,
colProps: { span: 12 },
componentProps: {
placeholder: '请输入用户姓名'
}
},
{
field: 'code',
label: t('编号'),
component: 'Input',
required: true,
colProps: { span: 12 },
componentProps: {
placeholder: '请输入编号'
}
},
{
field: 'departmentIds',
label: t('所属机构'),
component: 'Dept',
componentProps: {
placeholder: '请从所属部门进行修改',
fieldNames: {
label: 'name',
key: 'id',
value: 'id'
},
isArray: true,
multiple: true,
getPopupContainer: () => document.body,
disabled: true
},
//required: true,
colProps: { span: 12 }
},
{
field: 'password',
label: '登录密码',
component: 'Input',
ifShow: false,
slot: 'password',
colProps: { span: 12 },
rules: [
{
required: true,
validator: (_, value) => {
if (!value) {
return Promise.reject('请输入登录密码');
}
if (pwdText.value === '弱') {
return Promise.reject('密码强度设置过低,请至少保证中等强度。');
}
return Promise.resolve();
}
}
]
},
{
field: 'birthDate',
label: '生日',
component: 'DatePicker',
colProps: { span: 12 },
componentProps: {
placeholder: '请选择生日',
format: 'YYYY-MM-DD',
getPopupContainer: () => document.body
}
},
{
label: t('邮箱'),
field: 'email',
component: 'Input',
required: true,
colProps: { span: 12 },
componentProps: {
placeholder: '请输入邮箱'
}
},
{
label: t('手机号码'),
field: 'mobile',
component: 'Input',
required: true,
colProps: { span: 12 },
componentProps: {
placeholder: '请输入手机号码'
}
},
{
label: '电话号码',
field: 'phoneNumber',
component: 'Input',
colProps: { span: 12 },
componentProps: {
placeholder: '请输入电话号码'
}
},
{
field: 'qqNumber',
label: 'QQ号码',
component: 'Input',
colProps: { span: 12 },
componentProps: {
placeholder: '请输入QQ号码'
}
},
{
field: 'wechatNumber',
label: '微信',
component: 'Input',
colProps: { span: 12 },
componentProps: {
placeholder: '请输入微信'
}
},
{
field: 'bindIp',
label: '绑定IP',
component: 'Input',
colProps: { span: 12 },
componentProps: {
placeholder: '请输入绑定IP'
}
},
{
field: 'address',
label: '联系地址',
component: 'Input',
colProps: { span: 12 },
componentProps: {
placeholder: '请输入联系地址'
}
},
{
field: 'sortCode',
label: '排序',
component: 'InputNumber',
colProps: { span: 12 },
componentProps: {
placeholder: '请输入排序'
}
},
{
field: 'isSync',
label: '同步',
component: 'Switch',
colProps: { span: 12 },
helpMessage: '开启同步则会自动修正与域里人员组织数据一致,域里不存在的用户将被删除',
helpComponentProps: { maxWidth: '400px' },
componentProps: {
checkedValue: 'Y',
unCheckedValue: 'N'
}
},
{
field: 'isSelfBuild',
label: '自建用户',
component: 'Switch',
colProps: { span: 12 },
helpComponentProps: { maxWidth: '400px' },
componentProps: ({ formModel, formActionType }) => {
return {
checkedValue: 'Y',
unCheckedValue: 'N',
onChange: debounce((e: ChangeEvent) => {
//fieldInt组件会根据fieldString的组件值 变化 +2 //参考view/code/demo2/data/index.ts
if (formModel.isSelfBuild === 'N') {
formModel.isPushMQ = 'N';
}
}, 500)
};
}
},
{
field: 'isPushMQ',
label: '推送mq',
component: 'Switch',
colProps: { span: 12 },
helpMessage: '开启推送mq系统会将自建用户推送到移动办公',
helpComponentProps: { maxWidth: '400px' },
componentProps: {
checkedValue: 'Y',
unCheckedValue: 'N'
}
},
{
field: 'validityTime',
label: '有效期',
colProps: {
span: 12
},
component: 'RangePicker',
componentProps: {
format: 'YYYY-MM-DD HH:mm',
style: { width: '100%' },
getPopupContainer: () => document.body
}
},
{
label: t('备注'),
field: 'remark',
component: 'InputTextArea',
colProps: { span: 24 },
componentProps: {
placeholder: '请输入备注'
}
}
];
const identityFormSchema: FormSchema[] = [
{
field: 'identityCardNumber',
label: '身份证号',
component: 'Input',
colProps: { span: 12 },
componentProps: {
placeholder: '请输入身份证号'
}
},
{
field: 'dutyPost',
label: '岗位/职务',
component: 'Input',
colProps: { span: 12 },
componentProps: {
placeholder: '请输入岗位职务'
}
},
{
field: 'politicsStatus',
label: '政治面貌',
component: 'DicSelect',
colProps: { span: 12 },
componentProps: {
placeholder: '请选择政治面貌',
itemId: '1737728866478612482',
isShowAdd: false,
getPopupContainer: () => document.body
}
},
{
field: 'administrativePost',
label: '行政职务',
component: 'DicSelect',
colProps: { span: 12 },
componentProps: {
placeholder: '请选择行政职务',
itemId: '1737732631323631617',
isShowAdd: false,
getPopupContainer: () => document.body
}
},
{
field: 'administrativeRank',
label: '行政职级',
component: 'DicSelect',
colProps: { span: 12 },
componentProps: {
placeholder: '请选择行政职级',
itemId: '1737738124947509249',
isShowAdd: false,
getPopupContainer: () => document.body
}
},
{
field: 'secretLevel',
label: '用户密级',
component: 'DicSelect',
colProps: { span: 12 },
componentProps: {
placeholder: '请选择用户密级',
itemId: '1737748310911242241',
isShowAdd: false,
getPopupContainer: () => document.body
}
},
{
field: 'professionalTitleGrade',
label: '职称等级',
component: 'DicSelect',
colProps: { span: 12 },
componentProps: {
placeholder: '请选择职称等级',
itemId: '1737755116874170369',
isShowAdd: false,
getPopupContainer: () => document.body
}
},
{
field: 'technicalPosition',
label: '技术职务',
component: 'DicSelect',
colProps: { span: 12 },
componentProps: {
placeholder: '请选择技术职务',
itemId: '1737758467082878978',
isShowAdd: false,
getPopupContainer: () => document.body
}
},
{
field: 'managerialPosition',
label: '管理职务',
component: 'DicSelect',
colProps: { span: 12 },
componentProps: {
placeholder: '请选择管理职务',
itemId: '1737758998798991362',
isShowAdd: false,
getPopupContainer: () => document.body
}
},
{
field: 'vocationalSkill',
label: '职业技能',
component: 'DicSelect',
colProps: { span: 12 },
componentProps: {
placeholder: '请选择职业技能',
itemId: '1738008457994719233',
isShowAdd: false,
getPopupContainer: () => document.body
}
},
{
field: 'gender',
label: t('性别'),
component: 'RadioGroup',
required: true,
colProps: { span: 12 },
defaultValue: 1,
componentProps: {
options: [
{ label: '男', value: 1 },
{ label: '女', value: 0 }
]
}
}
];
const roleColumns: BasicColumn[] = [
{
title: t('角色编码'),
dataIndex: 'code',
align: 'left'
},
{
title: t('角色名称'),
dataIndex: 'name',
align: 'left'
}
];
const postColumns: BasicColumn[] = [
{
title: t('岗位编码'),
dataIndex: 'code',
align: 'left'
},
{
title: t('岗位名称'),
dataIndex: 'name',
align: 'left'
}
];
const orgColumns: BasicColumn[] = [
{
title: t('组织编码'),
dataIndex: 'code',
align: 'left'
},
{
title: t('组织名称'),
dataIndex: 'name',
align: 'left'
}
];
const deptColumns: BasicColumn[] = [
{
title: t('组织编码'),
dataIndex: 'code',
align: 'left',
width: 120
},
{
title: t('组织名称'),
dataIndex: 'name',
align: 'left',
width: 120
},
{
title: t('组织路径'),
dataIndex: 'hierarchy',
align: 'left'
},
{
dataIndex: 'isSync',
title: '是否同步',
width: 100,
edit: true,
editComponent: 'Switch',
//editRule:false,
helpMessage: '开启同步则会自动修正与域里人员组织数据一致,域里不存在的组织和下级人员组织将被删除',
editComponentProps: {
checkedValue: 'Y',
unCheckedValue: 'N'
},
editValueMap: (value) => {
return value == 'Y' ? '是' : '否';
}
},
{
dataIndex: 'isMain',
title: '是否主部门',
width: 100,
edit: true,
editComponent: 'Switch',
editComponentProps: {
checkedValue: 'Y',
unCheckedValue: 'N'
},
editValueMap: (value) => {
return value == 'Y' ? '是' : '否';
}
},
{
dataIndex: 'sortCode',
title: '排序',
width: 120,
edit: true,
editComponent: 'InputNumber'
}
];
const emit = defineEmits(['success', 'register']);
const { notification } = useMessage();
const isUpdate = ref(true);
const rowId = ref('');
const isShowPwd = ref(false);
const pwdPercent = ref(0);
const pwdColor = ref('#e74242');
const pwdText = ref('弱');
const activeKey = ref('1');
const roleDatasource = ref<any[]>([]);
const postDatasource = ref<any[]>([]);
const orgDatasource = ref<any[]>([]);
const deptDatasource = ref<any[]>([]);
const [registerForm1, { setFieldsValue: setFieldsValue1, getFieldsValue: getFieldsValue1, updateSchema: updateSchema1, resetFields: resetFields1, validate: validate1 }] = useForm({
labelWidth: 100,
schemas: accountFormSchema,
showActionButtonGroup: false,
actionColOptions: {
span: 23
}
});
const [registerForm2, { setFieldsValue: setFieldsValue2, resetFields: resetFields2, validate: validate2 }] = useForm({
labelWidth: 100,
schemas: identityFormSchema,
showActionButtonGroup: false,
actionColOptions: {
span: 23
}
});
const [registerTable1, { setTableData: setTableData1 }] = useTable({
rowKey: 'id',
dataSource: roleDatasource.value,
columns: roleColumns,
striped: false,
actionColumn: {
width: 80,
title: t('操作'),
dataIndex: 'action',
slots: { customRender: 'action' }
}
});
const [registerTable2, { setTableData: setTableData2 }] = useTable({
rowKey: 'id',
dataSource: postDatasource.value,
columns: postColumns,
striped: false,
actionColumn: {
width: 80,
title: t('操作'),
dataIndex: 'action',
slots: { customRender: 'action' }
}
});
const [registerTable3, { setTableData: setTableData3 }] = useTable({
rowKey: 'id',
dataSource: orgDatasource.value,
columns: orgColumns,
striped: false,
actionColumn: {
width: 80,
title: t('操作'),
dataIndex: 'action',
slots: { customRender: 'action' }
}
});
const [registerTable4, { setTableData: setTableData4 }] = useTable({
rowKey: 'id',
dataSource: deptDatasource.value,
columns: deptColumns,
striped: false,
actionColumn: {
width: 80,
title: t('操作'),
dataIndex: 'action',
slots: { customRender: 'action' }
}
});
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
resetFields1();
resetFields2();
setModalProps({ confirmLoading: false, width: 1000, fixedHeight: true, destroyOnClose: true });
activeKey.value = '1';
isUpdate.value = !!data?.isUpdate;
roleDatasource.value = [];
if (unref(isUpdate)) {
rowId.value = data.id;
const record = await getUser(data.id);
const departmentIds = record.departmentIds?.split(',') || [];
let validityTime = [];
if (record.validityStartTime) {
validityTime[0] = record.validityStartTime;
}
if (record.validityEndTime) {
validityTime[1] = record.validityEndTime;
}
if (validityTime.length > 0) {
record.validityTime = validityTime;
}
setFieldsValue1({
...record,
departmentIds
});
setFieldsValue2({
...record
});
roleDatasource.value = record.roles || [];
postDatasource.value = record.posts || [];
orgDatasource.value = record.chargeDepartments || [];
deptDatasource.value = record.departments || [];
setTableData1(roleDatasource.value);
setTableData2(postDatasource.value);
setTableData3(orgDatasource.value);
setTableData4(deptDatasource.value);
} else {
//新增
setFieldsValue1({
isSync: 'N',
isMain: 'N',
isSelfBuild: 'N',
isPushMQ: 'N'
});
getUserNamePrefixName();
}
const treeData = await getDepartmentTree();
updateSchema1([
{
field: 'password',
ifShow: !unref(isUpdate)
},
{
field: 'departmentIds',
componentProps: { treeData }
}
]);
});
const [registerRoleModal, { openModal: openRoleModal }] = useModal();
const [registerPostModal, { openModal: openPostModal }] = useModal();
const [registerOrgModal, { openModal: openOrgModal }] = useModal();
const [registerDeptModal, { openModal: openDeptModal }] = useModal();
const getTitle = computed(() => (!unref(isUpdate) ? t('新增用户') : t('编辑用户')));
const changeState = () => {
isShowPwd.value = !isShowPwd.value;
};
const changePwd = (e) => {
const pwdScore = testPwdState(e.target.value);
if (pwdScore < 50) {
pwdPercent.value = 30;
pwdColor.value = '#e74242';
pwdText.value = '弱';
} else if (pwdScore < 75) {
pwdPercent.value = 60;
pwdColor.value = '#efbd47';
pwdText.value = '中';
} else {
pwdPercent.value = 100;
pwdColor.value = '#55d187';
pwdText.value = '强';
}
};
const handleRoleCreate = () => {
openRoleModal(true, {
roles: roleDatasource.value
});
};
const handlePostCreate = () => {
openPostModal(true, {
posts: postDatasource.value
});
};
const handleOrgCreate = () => {
openOrgModal(true, {
orgs: orgDatasource.value,
pageType: !unref(isUpdate) ? 'add' : 'edit'
});
};
const handleDeptCreate = () => {
openDeptModal(true, {
orgs: deptDatasource.value,
pageType: !unref(isUpdate) ? 'add' : 'edit'
});
};
async function getUserNamePrefixName() {
let userNamePrefix = await getUserNamePrefix();
setFieldsValue1({
userName: userNamePrefix
});
// updateSchema1([{
// field: 'userName',
// defaultValue: userNamePrefix?.value,
// componentProps: { addonBefore: userNamePrefix?.value }
// }])
}
const handleDelete = (index, type, record) => {
// 映射不同类型对应的数据源
const dataSources = {
1: roleDatasource,
2: postDatasource,
3: orgDatasource,
4: deptDatasource
};
// 获取对应的数据源
const dataSource = dataSources[type]?.value;
if (dataSource) {
const index = dataSource.findIndex((item) => item.id === record.id);
if (index !== -1) {
dataSource.splice(index, 1);
}
}
};
const handleRoleSuccess = (data) => {
roleDatasource.value = data;
setTableData1(roleDatasource.value);
};
const handlePostSuccess = (data) => {
postDatasource.value = data;
setTableData2(postDatasource.value);
};
const handleOrgSuccess = (data) => {
orgDatasource.value = data;
setTableData3(orgDatasource.value);
};
const handleDeptSuccess = (data) => {
//重复的保留列表中的值
data.forEach((item) => {
const exitsItem = deptDatasource.value.find((x) => x.id == item.id);
if (exitsItem) {
item.hierarchy = exitsItem.hierarchy;
item.isMain = exitsItem.isMain;
item.isSync = exitsItem.isSync;
item.sortCode = exitsItem.sortCode;
}
});
deptDatasource.value = data;
setTableData4(deptDatasource.value);
};
async function handleSubmit() {
try {
const values = await validate1();
const values2 = await validate2();
const roleIds = roleDatasource.value?.map((x) => x.id);
const postIds = postDatasource.value?.map((x) => x.id);
const chargeDepartmentIds = orgDatasource.value?.map((x) => x.id);
const departments = deptDatasource.value;
const data = {
...values,
...values2,
departmentIds: values.departmentIds?.toString(),
roleIds,
postIds,
chargeDepartmentIds,
departments
};
setModalProps({ confirmLoading: true });
if (data.validityTime) {
data.validityStartTime = data.validityTime[0];
data.validityEndTime = data.validityTime[1];
}
// TODO custom api
if (!unref(isUpdate)) {
//false 新增
await addUser(data);
notification.success({
message: t('新增用户'),
description: t('成功')
}); //提示消息
} else {
data.id = rowId.value;
await updateUser(data);
notification.success({
message: t('编辑用户'),
description: t('成功')
}); //提示消息
}
closeModal();
emit('success');
} catch (error) {
setModalProps({ confirmLoading: false });
}
}
</script>
<style lang="less" scoped>
.pwd-progress {
display: flex;
align-items: center;
position: absolute;
right: 14%;
top: 17%;
width: 90px;
z-index: 999;
}
.input-state {
display: flex;
align-items: center;
color: #b1b1b1;
margin-left: 5px;
span {
margin: 0 10px;
}
}
:deep(.ant-progress-steps-item) {
height: 4px !important;
}
:deep(.ant-tabs-content),
:deep(.vben-basic-table .ant-table-container) {
height: 100%;
}
:deep(.vben-basic-table .ant-table) {
height: calc(100% - 40px);
}
</style>