You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
452 lines
13 KiB
452 lines
13 KiB
<template>
|
|
<div class="full-height page-container">
|
|
<SmartLayoutSeparate :show-line="false" first-size="280px" class="full-height">
|
|
<template #first>
|
|
<div class="full-height dept-container">
|
|
<SysDeptTree async show-search @select="handleDeptSelected" />
|
|
</div>
|
|
</template>
|
|
<template #second>
|
|
<SmartTable @register="registerTable" :size="getTableSize">
|
|
<template #table-operation="{ row }">
|
|
<SmartVxeTableAction :actions="getTableActions(row)" />
|
|
</template>
|
|
<template #table-userType="{ row }">
|
|
<span>
|
|
{{ getUserTypeMap[row.userType] }}
|
|
</span>
|
|
</template>
|
|
<template #search-userType="{ model, size }">
|
|
<a-select style="width: 100px" :size="size" v-model:value="model.userType" allowClear>
|
|
<a-select-option
|
|
v-for="item in userTypeListRef"
|
|
:key="'userType_' + item.dictItemCode"
|
|
:value="item.dictItemCode"
|
|
>
|
|
{{ item.dictItemName }}
|
|
</a-select-option>
|
|
</a-select>
|
|
</template>
|
|
<template #table-accountStatus="{ row }">
|
|
<a-tooltip :title="getLockedMessage(row.userAccount?.accountStatus)">
|
|
<span
|
|
:style="{
|
|
color: getAccountData(row.userAccount?.accountStatus).color,
|
|
fontWeight: 'bold',
|
|
}"
|
|
>
|
|
{{ getAccountData(row.userAccount?.accountStatus).label }}
|
|
</span>
|
|
</a-tooltip>
|
|
</template>
|
|
</SmartTable>
|
|
</template>
|
|
</SmartLayoutSeparate>
|
|
<UserAccountUpdateModal @register="registerAccountModal" />
|
|
<UserSetRole @register="registerSetRoleModal" />
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { computed, ref, unref } from 'vue';
|
|
import { useI18n } from '@/hooks/web/useI18n';
|
|
|
|
import { useLoadDictItem } from '@/modules/smart-system/hooks/SysDictHooks';
|
|
import { useSizeSetting } from '@/hooks/setting/UseSizeSetting';
|
|
import { hasPermission } from '@/utils/auth';
|
|
import { useModal } from '@/components/Modal';
|
|
|
|
import { SmartLayoutSeparate } from '@/components/SmartLayoutSeparate';
|
|
import SysDeptTree from '@/modules/smart-system/components/SysDept/SysDeptTree.vue';
|
|
import { useMessage } from '@/hooks/web/useMessage';
|
|
|
|
import {
|
|
SmartTable,
|
|
useSmartTable,
|
|
SmartVxeTableAction,
|
|
ActionItem,
|
|
} from '@/components/SmartTable';
|
|
import UserAccountUpdateModal from './account/UserAccountUpdateModal.vue';
|
|
import UserSetRole from './components/UserSetRole.vue';
|
|
|
|
import { getAddEditFormSchemas, getSearchSchemas, getTableColumns } from './UserListView.config';
|
|
import {
|
|
listApi,
|
|
deleteApi,
|
|
saveUpdateWithDataScopeApi,
|
|
getByIdWithDataScopeApi,
|
|
setUseYnApi,
|
|
createAccountApi,
|
|
unlockUserAccountApi,
|
|
resetPassword,
|
|
} from './UserListView.api';
|
|
import {
|
|
SYS_USER_TYPE,
|
|
SystemPermissions,
|
|
} from '@/modules/smart-system/constants/SystemConstants';
|
|
import { copyText } from '@/utils/copyTextToClipboard';
|
|
|
|
const { t } = useI18n();
|
|
const { warnMessage, errorMessage, createConfirm, successMessage } = useMessage();
|
|
const { getTableSize } = useSizeSetting();
|
|
|
|
const { dictData: userTypeListRef } = useLoadDictItem(ref('SYSTEM_USER_TYPE'));
|
|
const getUserTypeMap = computed(() => {
|
|
const result: { [index: string]: string } = {};
|
|
result[SYS_USER_TYPE] = '系统用户';
|
|
for (let userType of unref(userTypeListRef)) {
|
|
result[userType.dictItemCode] = userType.dictItemName;
|
|
}
|
|
return result;
|
|
});
|
|
|
|
const accountLockedMessage = {
|
|
LOGIN_FAIL_LOCKED: '多次登录失败锁定',
|
|
LONG_TIME_LOCKED: '超出指定时间未登录锁定',
|
|
LONG_TIME_PASSWORD_MODIFY_LOCKED: '超出指定时间未修改密码锁定',
|
|
};
|
|
|
|
const [registerSetRoleModal, { openModal: openSetRoleModal }] = useModal();
|
|
|
|
const getLockedMessage = (status: string | null | undefined) => {
|
|
if (!status || status === 'NORMAL') {
|
|
return '正常';
|
|
}
|
|
return accountLockedMessage[status];
|
|
};
|
|
|
|
/**
|
|
* 账户状态
|
|
*/
|
|
const accountStatusMap = {
|
|
empty: {
|
|
label: '未创建',
|
|
color: '#A9A9A9',
|
|
},
|
|
NORMAL: {
|
|
label: '正常',
|
|
color: '#228B22',
|
|
},
|
|
LOCKED: {
|
|
label: '锁定',
|
|
color: 'red',
|
|
},
|
|
};
|
|
|
|
const getAccountData = (status: string | null | undefined) => {
|
|
if (status === undefined || status === null) {
|
|
return accountStatusMap.empty;
|
|
}
|
|
if (status === 'NORMAL') {
|
|
return accountStatusMap.NORMAL;
|
|
}
|
|
return accountStatusMap.LOCKED;
|
|
};
|
|
|
|
/**
|
|
* 权限处理
|
|
*/
|
|
const permissions = SystemPermissions.user;
|
|
const hasPermissionUpdateSystemUser = hasPermission('sys:systemUser:update');
|
|
const hasSystemUserUpdate = (type: string) => {
|
|
return hasPermissionUpdateSystemUser || type !== SYS_USER_TYPE;
|
|
};
|
|
|
|
/**
|
|
* 选中组织架构操作
|
|
* @param selectedKeys
|
|
*/
|
|
const currentDeptId = ref<number | null>(null);
|
|
const handleDeptSelected = (selectedKeys: Array<number>) => {
|
|
if (selectedKeys.length > 0) {
|
|
currentDeptId.value = selectedKeys[0];
|
|
} else {
|
|
currentDeptId.value = null;
|
|
}
|
|
// 重新加载数据
|
|
query();
|
|
};
|
|
|
|
/**
|
|
* 账户弹窗
|
|
*/
|
|
const [registerAccountModal, { openModal }] = useModal();
|
|
|
|
/**
|
|
* table行按钮
|
|
*/
|
|
const getTableActions = (row): ActionItem[] => {
|
|
return [
|
|
{
|
|
label: t('common.button.edit'),
|
|
onClick: () => editByRowModal(row),
|
|
disabled: !hasPermission(permissions.update) || !hasSystemUserUpdate(row.userType),
|
|
},
|
|
{
|
|
label: t('system.views.user.button.showAccount'),
|
|
disabled: !hasPermission('sys:account:query') || !hasSystemUserUpdate(row.userType),
|
|
onClick: () => openModal(true, row),
|
|
},
|
|
{
|
|
label: t('system.views.user.button.unlockUserAccount'),
|
|
auth: permissions.unlockUserAccount,
|
|
disabled:
|
|
!hasPermission(permissions.unlockUserAccount) ||
|
|
(row.userAccount && row.userAccount.accountStatus === 'NORMAL'),
|
|
onClick: () => handleUnlockUserAccount(row.userId),
|
|
},
|
|
];
|
|
};
|
|
|
|
const handleUnlockUserAccount = (id: number) => {
|
|
createConfirm({
|
|
iconType: 'warning',
|
|
content: t('system.views.user.message.confirmUnlockUserAccount'),
|
|
onOk: async () => {
|
|
await unlockUserAccountApi(id);
|
|
successMessage(t('system.views.user.message.unlockUserAccountSuccess'));
|
|
await query();
|
|
},
|
|
});
|
|
};
|
|
|
|
/**
|
|
* 用户操作验证
|
|
* @param userList
|
|
*/
|
|
const validateOperateUser = (userList: Array<any>) => {
|
|
if (userList.length === 0) {
|
|
warnMessage({
|
|
message: t('system.views.user.validate.selectUser'),
|
|
});
|
|
return false;
|
|
}
|
|
if (!hasPermissionUpdateSystemUser) {
|
|
// 如果没有修改系统用户的权限,判断用户中是否有系统用户
|
|
const hasSysUser = userList.some(({ userType }: any) => userType === SYS_USER_TYPE);
|
|
if (hasSysUser) {
|
|
errorMessage(t('system.views.user.validate.noSysUserUpdatePermission'));
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* 创建账户
|
|
*/
|
|
const handleCreateAccount = () => {
|
|
const userList = getCheckboxRecords(false);
|
|
if (userList.length === 0) {
|
|
warnMessage({
|
|
message: t('system.views.user.validate.selectUser'),
|
|
});
|
|
return false;
|
|
}
|
|
if (!hasPermissionUpdateSystemUser) {
|
|
// 如果没有修改系统用户的权限,判断用户中是否有系统用户
|
|
const hasSysUser = userList.some(({ userType }: any) => userType === SYS_USER_TYPE);
|
|
if (hasSysUser) {
|
|
errorMessage(t('system.views.user.validate.noSysUserUpdatePermission'));
|
|
return false;
|
|
}
|
|
}
|
|
// 判断是否有停用用户
|
|
const hasNoUse = userList.some((item) => item.useYn === false);
|
|
if (hasNoUse) {
|
|
warnMessage(t('system.views.user.message.noUseUserNotCreateAccount'));
|
|
return false;
|
|
}
|
|
createConfirm({
|
|
iconType: 'warning',
|
|
title: t('system.views.user.validate.createAccountConfirm'),
|
|
onOk: () => createAccountApi(userList),
|
|
});
|
|
};
|
|
|
|
const [
|
|
registerTable,
|
|
{ editByRowModal, getCheckboxRecords, query, deleteByCheckbox, showAddModal },
|
|
] = useSmartTable({
|
|
columns: getTableColumns(),
|
|
stripe: true,
|
|
height: 'auto',
|
|
border: true,
|
|
align: 'left',
|
|
rowConfig: {
|
|
isHover: true,
|
|
},
|
|
pagerConfig: true,
|
|
useSearchForm: true,
|
|
sortConfig: {
|
|
remote: true,
|
|
defaultSort: {
|
|
field: 'seq',
|
|
order: 'asc',
|
|
},
|
|
},
|
|
searchFormConfig: {
|
|
layout: 'inline',
|
|
schemas: getSearchSchemas(t),
|
|
colon: true,
|
|
searchWithSymbol: true,
|
|
actionColOptions: {
|
|
span: undefined,
|
|
},
|
|
compact: true,
|
|
},
|
|
addEditConfig: {
|
|
modalConfig: {
|
|
width: '700px',
|
|
},
|
|
formConfig: {
|
|
colon: true,
|
|
schemas: getAddEditFormSchemas(t, userTypeListRef),
|
|
labelCol: {
|
|
span: 4,
|
|
},
|
|
wrapperCol: {
|
|
span: 19,
|
|
},
|
|
baseColProps: {
|
|
span: 24,
|
|
},
|
|
},
|
|
},
|
|
proxyConfig: {
|
|
ajax: {
|
|
query: ({ ajaxParameter }) => {
|
|
const parameter = {
|
|
...ajaxParameter,
|
|
};
|
|
const deptId = unref(currentDeptId);
|
|
if (deptId) {
|
|
parameter.deptIdList = [deptId];
|
|
}
|
|
return listApi(parameter);
|
|
},
|
|
delete: deleteApi,
|
|
save: saveUpdateWithDataScopeApi,
|
|
getById: getByIdWithDataScopeApi,
|
|
useYn: setUseYnApi,
|
|
},
|
|
},
|
|
toolbarConfig: {
|
|
refresh: true,
|
|
resizable: true,
|
|
buttons: [
|
|
{
|
|
code: 'ModalAdd',
|
|
auth: permissions.add,
|
|
props: {
|
|
onClick: () => {
|
|
showAddModal({ deptId: unref(currentDeptId) });
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: t('system.views.user.button.createAccount'),
|
|
customRender: 'ant',
|
|
auth: permissions.createAccount,
|
|
props: {
|
|
onClick: () => handleCreateAccount(),
|
|
type: 'primary',
|
|
},
|
|
},
|
|
{
|
|
code: 'delete',
|
|
props: {
|
|
onClick: () => {
|
|
const userList = getCheckboxRecords(false);
|
|
// 验证用户
|
|
const result = validateOperateUser(userList);
|
|
if (!result) {
|
|
return false;
|
|
}
|
|
// 验证是否包含系统用户
|
|
const sysUserValidate = userList.some((item: any) => item.userType === SYS_USER_TYPE);
|
|
if (sysUserValidate) {
|
|
errorMessage(t('system.views.user.validate.sysUserNoDelete'));
|
|
return false;
|
|
}
|
|
// 执行删除操作
|
|
deleteByCheckbox();
|
|
},
|
|
},
|
|
},
|
|
{
|
|
code: 'useYnTrue',
|
|
},
|
|
{
|
|
code: 'useYnFalse',
|
|
},
|
|
{
|
|
name: t('system.views.user.button.resetPassword'),
|
|
auth: permissions.unlockPassword,
|
|
customRender: 'ant',
|
|
props: {
|
|
type: 'primary',
|
|
preIcon: 'ant-design:unlock-outlined',
|
|
onClick: () => {
|
|
const selectRows = getCheckboxRecords(false);
|
|
if (selectRows.length !== 1) {
|
|
warnMessage('请选择一条数据');
|
|
return;
|
|
}
|
|
createConfirm({
|
|
iconType: 'warning',
|
|
title: t('system.views.user.button.resetPassword'),
|
|
content: t('system.views.user.validate.resetPassword'),
|
|
onOk: async () => {
|
|
const newPassword = await resetPassword(selectRows[0].userId);
|
|
createConfirm({
|
|
iconType: 'warning',
|
|
okText: t('system.views.user.button.copyPassword'),
|
|
onOk: () => {
|
|
copyText(newPassword);
|
|
},
|
|
title: t('system.views.user.message.resetSavePassword'),
|
|
content: newPassword,
|
|
});
|
|
},
|
|
});
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: t('system.views.user.button.setRole'),
|
|
auth: permissions.setRole,
|
|
customRender: 'ant',
|
|
props: {
|
|
type: 'primary',
|
|
preIcon: 'ant-design:team-outlined',
|
|
onClick: () => {
|
|
const selectRows = getCheckboxRecords(false);
|
|
if (selectRows.length !== 1) {
|
|
warnMessage('请选择一条数据');
|
|
return;
|
|
}
|
|
openSetRoleModal(true, { userId: selectRows[0].userId });
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<style scoped lang="less">
|
|
.page-container {
|
|
:deep(.smart-search-container) {
|
|
.ant-col {
|
|
//padding: 0 5px;
|
|
}
|
|
}
|
|
}
|
|
|
|
.dept-container {
|
|
margin-right: 5px;
|
|
padding: 10px;
|
|
background: white;
|
|
}
|
|
</style>
|
|
|