feat(user-management-relation): 在用户管理页面集成用户带人关系组件,并修复相关的诸多BUG和样式问题

This commit is contained in:
dk
2026-04-14 16:33:47 +08:00
parent 9b6f5955c3
commit a6fc7b48dc
7 changed files with 187 additions and 98 deletions

View File

@@ -1,10 +1,10 @@
<script setup lang="tsx">
import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue';
import type { TableInstance } from 'element-plus';
import { ElButton, ElPopconfirm, ElSwitch, ElTag } from 'element-plus';
import {computed, nextTick, onMounted, reactive, ref, watch} from 'vue';
import type {TableInstance} from 'element-plus';
import {ElButton, ElPopconfirm, ElSwitch, ElTag} from 'element-plus';
import dayjs from 'dayjs';
import type { FlatResponseData } from '@sa/axios';
import { userGenderRecord } from '@/constants/business';
import type {FlatResponseData} from '@sa/axios';
import {userGenderRecord} from '@/constants/business';
import {
fetchBatchDeleteUser,
fetchDeleteDept,
@@ -17,10 +17,11 @@ import {
fetchUpdateUser,
fetchUpdateUserStatus
} from '@/service/api';
import { useUIPaginatedTable } from '@/hooks/common/table';
import {useUIPaginatedTable} from '@/hooks/common/table';
import BusinessTableActionCell from '@/components/custom/business-table-action-cell';
import { $t } from '@/locales';
import { buildMenuTree } from '@/views/system/shared/menu-tree';
import BusinessFormDialog from '@/components/custom/business-form-dialog.vue';
import {$t} from '@/locales';
import {buildMenuTree} from '@/views/system/shared/menu-tree';
import UserOperateDialog from './modules/user-operate-dialog.vue';
import UserOrgLeaderDialog from './modules/user-org-leader-dialog.vue';
import UserOrgOperateDialog from './modules/user-org-operate-dialog.vue';
@@ -28,8 +29,9 @@ import UserOrgPanel from './modules/user-org-panel.vue';
import UserResignedDialog from './modules/user-resigned-dialog.vue';
import UserResetPasswordDialog from './modules/user-reset-password-dialog.vue';
import UserSearch from './modules/user-search.vue';
import UserManagementRelation from '@/views/system/user-management-relation/index.vue';
defineOptions({ name: 'UserManage' });
defineOptions({name: 'UserManage'});
function getInitSearchParams(): Api.SystemManage.UserSearchParams {
return {
@@ -146,12 +148,13 @@ const editingDeptData = ref<Api.SystemManage.Dept | null>(null);
const orgParentId = ref<number | null>(0);
const orgLeaderVisible = ref(false);
const leaderDeptData = ref<Api.SystemManage.Dept | null>(null);
const userManagementRelationVisible = ref(false);
const deptTree = computed(() => buildMenuTree(deptList.value));
const currentDept = computed(() => deptList.value.find(item => item.id === currentDeptId.value) ?? null);
const deptCount = computed(() => deptList.value.length);
const { columns, columnChecks, data, loading, getDataByPage, mobilePagination } = useUIPaginatedTable<
const {columns, columnChecks, data, loading, getDataByPage, mobilePagination} = useUIPaginatedTable<
FlatResponseData<any, Api.SystemManage.UserList>,
Api.SystemManage.User
>({
@@ -175,9 +178,9 @@ const { columns, columnChecks, data, loading, getDataByPage, mobilePagination }
searchParams.pageSize = params.pageSize ?? 10;
},
columns: () => [
{ prop: 'selection', type: 'selection', width: 48 },
{ prop: 'index', type: 'index', label: $t('common.index'), width: 64 },
{ prop: 'username', label: $t('page.system.user.userName'), minWidth: 140, showOverflowTooltip: true },
{prop: 'selection', type: 'selection', width: 48},
{prop: 'index', type: 'index', label: $t('common.index'), width: 64},
{prop: 'username', label: $t('page.system.user.userName'), minWidth: 140, showOverflowTooltip: true},
{
prop: 'nickname',
label: $t('page.system.user.nickName'),
@@ -257,9 +260,9 @@ const { columns, columnChecks, data, loading, getDataByPage, mobilePagination }
formatter: row => {
const state = getUserResignedState(row);
const stateMap: Record<UserResignedState, { type: UI.ThemeColor; label: App.I18n.I18nKey }> = {
active: { type: 'success', label: 'page.system.user.resignedStateEnum.active' },
pending: { type: 'warning', label: 'page.system.user.resignedStateEnum.pending' },
resigned: { type: 'info', label: 'page.system.user.resignedStateEnum.resigned' }
active: {type: 'success', label: 'page.system.user.resignedStateEnum.active'},
pending: {type: 'warning', label: 'page.system.user.resignedStateEnum.pending'},
resigned: {type: 'info', label: 'page.system.user.resignedStateEnum.resigned'}
};
return <ElTag type={stateMap[state].type}>{$t(stateMap[state].label)}</ElTag>;
@@ -320,7 +323,7 @@ const { columns, columnChecks, data, loading, getDataByPage, mobilePagination }
async function loadDeptTree() {
deptLoading.value = true;
const { error, data: deptItems } = await fetchGetDeptList({
const {error, data: deptItems} = await fetchGetDeptList({
status: 0
});
@@ -422,7 +425,7 @@ function openOrgLeader(row: Api.SystemManage.Dept) {
}
async function handleDeleteDeptAction(row: Api.SystemManage.Dept) {
const { error } = await fetchDeleteDept(row.id);
const {error} = await fetchDeleteDept(row.id);
if (error) {
return;
@@ -447,7 +450,7 @@ async function handleDeleteAction(row: Api.SystemManage.User) {
return;
}
const { error } = await fetchDeleteUser(row.id);
const {error} = await fetchDeleteUser(row.id);
if (error) {
return;
@@ -466,7 +469,7 @@ async function updateUserResignedAt(userId: number, value: number | null) {
const user = detailResult.data;
const { error } = await fetchUpdateUser({
const {error} = await fetchUpdateUser({
id: userId,
username: user.username,
nickname: user.nickname ?? null,
@@ -518,7 +521,7 @@ async function handleBatchDelete() {
return;
}
const { error } = await fetchBatchDeleteUser(userCheckedRowKeys.value);
const {error} = await fetchBatchDeleteUser(userCheckedRowKeys.value);
if (error) {
return;
@@ -531,7 +534,7 @@ async function handleBatchDelete() {
async function handleToggleStatus(row: Api.SystemManage.User, enabled: boolean) {
statusLoadingIds.value = [...statusLoadingIds.value, row.id];
const { error } = await fetchUpdateUserStatus({
const {error} = await fetchUpdateUserStatus({
id: row.id,
status: enabled ? 0 : 1
});
@@ -640,15 +643,21 @@ onMounted(async () => {
<template #default>
<ElButton plain type="primary" :disabled="!currentDept" @click="openAdd">
<template #icon>
<icon-ic-round-plus class="text-icon" />
<icon-ic-round-plus class="text-icon"/>
</template>
{{ $t('common.add') }}
</ElButton>
<ElButton plain type="primary" :disabled="!currentDept" @click="userManagementRelationVisible = true">
<template #icon>
<icon-ic-round-plus class="text-icon"/>
</template>
带人关系
</ElButton>
<ElPopconfirm :title="$t('common.confirmDelete')" @confirm="handleBatchDelete">
<template #reference>
<ElButton type="danger" plain :disabled="userCheckedRowKeys.length === 0">
<template #icon>
<icon-ic-round-delete class="text-icon" />
<icon-ic-round-delete class="text-icon"/>
</template>
{{ $t('common.batchDelete') }}
</ElButton>
@@ -670,7 +679,7 @@ onMounted(async () => {
:data="data"
@selection-change="handleUserSelectionChange"
>
<ElTableColumn v-for="col in columns" :key="String(col.prop)" v-bind="col" />
<ElTableColumn v-for="col in columns" :key="String(col.prop)" v-bind="col"/>
</ElTable>
</div>
<div class="mt-20px flex justify-end">
@@ -685,7 +694,7 @@ onMounted(async () => {
</template>
<div v-else class="h-full flex items-center justify-center">
<ElEmpty :description="$t('page.system.user.emptyOrg')" />
<ElEmpty :description="$t('page.system.user.emptyOrg')"/>
</div>
</ElCard>
</div>
@@ -724,7 +733,17 @@ onMounted(async () => {
@submitted="handleDeptSubmitted"
/>
<UserOrgLeaderDialog v-model:visible="orgLeaderVisible" :dept="leaderDeptData" />
<UserOrgLeaderDialog v-model:visible="orgLeaderVisible" :dept="leaderDeptData"/>
<BusinessFormDialog
v-model="userManagementRelationVisible"
title="用户带人关系"
preset="lg"
:show-footer="false"
max-body-height="70vh"
>
<UserManagementRelation :fromUserIndex="true" :deptId="currentDeptId"/>
</BusinessFormDialog>
</div>
</template>
@@ -734,4 +753,9 @@ onMounted(async () => {
display: flex;
flex-direction: column;
}
// 带人关系对话框内的搜索框样式优化
:deep(.business-form-dialog) {
width: 800px;
}
</style>