Files
geg-gas-web/src/views/system/user/components/UserModal.vue

828 lines
23 KiB
Vue

<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 } 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 './RoleModal.vue';
import PostModal from './PostModal.vue';
import OrganizationModal from './OrganizationModal.vue';
const { t } = useI18n();
const accountFormSchema: FormSchema[] = [
{
field: 'userName',
label: '账号',
component: 'Input',
required: true,
colProps: { span: 12 },
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',
}
},
{
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,
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(',')||[];
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);
}
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,
});
};
const handleDeptCreate = () => {
openDeptModal(true, {
orgs: deptDatasource.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 });
// 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>