feat(user-management-relation): 在用户管理页面集成用户带人关系组件,并修复相关的诸多BUG和样式问题
This commit is contained in:
@@ -318,6 +318,15 @@ export function fetchGetUserPage(params?: Api.SystemManage.UserSearchParams) {
|
||||
/** 为兼容旧代码保留原函数名 */
|
||||
export const fetchGetUserList = fetchGetUserPage;
|
||||
|
||||
/** 通过部门id获取用户详情 */
|
||||
export function fetchGetUserListByDeptId(deptId: any) {
|
||||
return request<Api.SystemManage.UserSimple[]>({
|
||||
url: `${USER_PREFIX}/list-by-dept-id`,
|
||||
method: 'get',
|
||||
params: { deptId }
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取用户详情 */
|
||||
export function fetchGetUser(id: number) {
|
||||
return request<Api.SystemManage.User>({
|
||||
@@ -487,10 +496,11 @@ export function fetchAssignUserRoles(data: Api.SystemManage.AssignUserRoleParams
|
||||
* - 中间节点:有上级也有下级
|
||||
* - 叶子节点:基层员工,没有下级
|
||||
*/
|
||||
export function fetchGetUserManagementRelationTree() {
|
||||
export function fetchGetUserManagementRelationTree(query: UserManagementRelationQueryReqVO) {
|
||||
return request<Api.SystemManage.UserManagementRelationTreeRespVO[]>({
|
||||
url: `${USER_MANAGEMENT_RELATION_PREFIX}/tree`,
|
||||
method: 'get'
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
7
src/typings/api/system-manage.d.ts
vendored
7
src/typings/api/system-manage.d.ts
vendored
@@ -387,7 +387,12 @@ declare namespace Api {
|
||||
* 对应后端 UserManagementRelationQueryReqVO
|
||||
*/
|
||||
type UserManagementRelationQueryReqVO = CommonType.RecordNullable<
|
||||
Pick<UserManagementRelation, 'managerUserId' | 'subordinateUserId'>
|
||||
Pick<UserManagementRelation, 'managerUserId' | 'subordinateUserId'> & {
|
||||
/** 是否来自带人关系的index组件 */
|
||||
fromUserIndex: boolean;
|
||||
/** 部门ID */
|
||||
deptId?: number | null;
|
||||
}
|
||||
>;
|
||||
|
||||
/**
|
||||
|
||||
@@ -325,4 +325,8 @@ getMenuTreeData();
|
||||
:deep(.el-table__row.current-row > td.el-table__cell) {
|
||||
background-color: rgb(64 158 255 / 8%);
|
||||
}
|
||||
|
||||
:deep(.el-row) {
|
||||
margin: 0 0 -15px 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -21,16 +21,28 @@ import { ElButton, ElPopconfirm, ElTag } from 'element-plus';
|
||||
import {useBoolean} from '@sa/hooks';
|
||||
import {
|
||||
fetchBatchDeleteUserManagementRelation,
|
||||
fetchDeleteUserManagementRelation,
|
||||
fetchDeleteUserManagementRelation, fetchGetUserListByDeptId,
|
||||
fetchGetUserManagementRelationQuery,
|
||||
fetchGetUserManagementRelationTree,
|
||||
fetchGetUserSimpleList
|
||||
} from '@/service/api';
|
||||
import RelationOperateDialog from './modules/relation-operate-dialog.vue';
|
||||
import RelationSearch from './modules/relation-search.vue';
|
||||
|
||||
defineOptions({name: 'UserManagementRelation'});
|
||||
|
||||
/**
|
||||
* 组件 userQuery 定义
|
||||
*
|
||||
* @param fromUserIndex 是否不是从带人关系 index 页面访问(从 user 页面访问时为 true)
|
||||
*/
|
||||
interface userQuery {
|
||||
fromUserIndex?: boolean;
|
||||
deptId?: number | null;
|
||||
}
|
||||
|
||||
//从user的index组件访问带人关系,fromUserIndex为true,否则false; dept=100是灿能电力的id
|
||||
const {fromUserIndex = false, deptId = 100} = defineProps<userQuery>()
|
||||
|
||||
/**
|
||||
* 初始化搜索参数
|
||||
*
|
||||
@@ -74,7 +86,7 @@ const treeProps: any = {
|
||||
* 获取用户简单列表,供搜索组件和对话框组件共享使用
|
||||
*/
|
||||
async function loadUserList() {
|
||||
const { data, error } = await fetchGetUserSimpleList();
|
||||
const {data, error} = await fetchGetUserListByDeptId(deptId);
|
||||
if (!error) {
|
||||
userList.value = data || [];
|
||||
}
|
||||
@@ -89,7 +101,12 @@ async function loadTreeData() {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const { data, error } = await fetchGetUserManagementRelationTree();
|
||||
// 默认不是来自user的index组件访问且deptId=100,查询灿能电力及其以下所有部门的用户的带人关系
|
||||
const query: Api.SystemManage.UserManagementRelationQueryReqVO = {
|
||||
fromUserIndex: fromUserIndex,
|
||||
deptId: deptId
|
||||
};
|
||||
const {data, error} = await fetchGetUserManagementRelationTree(query);
|
||||
|
||||
if (!error) {
|
||||
treeData.value = data || [];
|
||||
@@ -143,13 +160,13 @@ async function handleSearch() {
|
||||
|
||||
// 判断是否有搜索条件
|
||||
const hasSearchCondition = searchParams.subordinateUserId !== undefined && searchParams.subordinateUserId !== null;
|
||||
|
||||
if (hasSearchCondition) {
|
||||
// 有搜索条件,调用查询接口
|
||||
const query: Api.SystemManage.UserManagementRelationQueryReqVO = {
|
||||
subordinateUserId: searchParams.subordinateUserId
|
||||
subordinateUserId: searchParams.subordinateUserId,
|
||||
fromUserIndex: fromUserIndex,
|
||||
deptId: deptId
|
||||
};
|
||||
console.log('查询参数 query:', query);
|
||||
await loadTreeDataByQuery(query);
|
||||
} else {
|
||||
// 无搜索条件,加载完整树
|
||||
@@ -287,6 +304,25 @@ function hasChildren(node: Api.SystemManage.UserManagementRelationTreeRespVO): b
|
||||
return Boolean(node.children && node.children.length > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算树形数据中所有节点的数量
|
||||
*
|
||||
* 递归遍历树形结构,统计所有节点总数
|
||||
*
|
||||
* @param nodes 树形数据数组
|
||||
* @returns 节点总数
|
||||
*/
|
||||
function countTreeNodes(nodes: Api.SystemManage.UserManagementRelationTreeRespVO[]): number {
|
||||
let count = 0;
|
||||
for (const node of nodes) {
|
||||
count += 1;
|
||||
if (node.children && node.children.length > 0) {
|
||||
count += countTreeNodes(node.children);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await loadUserList();
|
||||
await reloadTreeData();
|
||||
@@ -309,7 +345,7 @@ onMounted(async () => {
|
||||
<div class="flex items-center justify-between gap-12px">
|
||||
<div class="flex items-center gap-10px">
|
||||
<p>用户带人关系树</p>
|
||||
<ElTag effect="plain">{{ treeData.length }}</ElTag>
|
||||
<ElTag effect="plain">{{ countTreeNodes(treeData) }}</ElTag>
|
||||
</div>
|
||||
<div class="flex items-center gap-10px">
|
||||
<ElButton plain type="primary" @click="openAdd()">
|
||||
@@ -318,16 +354,16 @@ onMounted(async () => {
|
||||
</template>
|
||||
新增
|
||||
</ElButton>
|
||||
<ElPopconfirm title="确认删除选中的关系吗?" @confirm="handleBatchDelete">
|
||||
<template #reference>
|
||||
<ElButton type="danger" plain :disabled="checkedNodeKeys.length === 0">
|
||||
<template #icon>
|
||||
<icon-ic-round-delete class="text-icon" />
|
||||
</template>
|
||||
批量删除
|
||||
</ElButton>
|
||||
</template>
|
||||
</ElPopconfirm>
|
||||
<!-- <ElPopconfirm title="确认删除选中的关系吗?" @confirm="handleBatchDelete">-->
|
||||
<!-- <template #reference>-->
|
||||
<!-- <ElButton type="danger" plain :disabled="checkedNodeKeys.length === 0">-->
|
||||
<!-- <template #icon>-->
|
||||
<!-- <icon-ic-round-delete class="text-icon"/>-->
|
||||
<!-- </template>-->
|
||||
<!-- 批量删除-->
|
||||
<!-- </ElButton>-->
|
||||
<!-- </template>-->
|
||||
<!-- </ElPopconfirm>-->
|
||||
<ElButton @click="reloadTreeData">
|
||||
<template #icon>
|
||||
<icon-ic-round-refresh class="text-icon"/>
|
||||
@@ -346,7 +382,6 @@ onMounted(async () => {
|
||||
:data="treeData"
|
||||
:props="treeProps"
|
||||
node-key="userId"
|
||||
show-checkbox
|
||||
default-expand-all
|
||||
:expand-on-click-node="false"
|
||||
@check="handleNodeCheck"
|
||||
@@ -355,7 +390,7 @@ onMounted(async () => {
|
||||
<div class="flex flex-1 items-center justify-between">
|
||||
<span class="flex items-center gap-8px">
|
||||
<span>{{ node.label }}</span>
|
||||
<ElTag v-if="data.managerNickname" size="small" type="info">上级:{{ data.managerNickname }}</ElTag>
|
||||
<!-- <ElTag v-if="data.managerNickname" size="small" type="info">上级:{{ data.managerNickname }}</ElTag>-->
|
||||
</span>
|
||||
<div class="flex items-center">
|
||||
<ElButton link type="primary" size="default" @click.stop="openAdd(data)">
|
||||
@@ -384,8 +419,7 @@ onMounted(async () => {
|
||||
</ElButton>
|
||||
</template>
|
||||
</ElPopconfirm>
|
||||
<ElTag v-else-if="hasChildren(data)" size="small" type="info" style="margin-left: 6px">有下级</ElTag>
|
||||
<ElTag v-else size="small" type="warning">不可删除</ElTag>
|
||||
<span v-else-if="hasChildren(data)" style="margin-left: 56px"></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -281,28 +281,34 @@ watch(visible, value => {
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ElRow :gutter="16">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="生效开始时间" prop="effectiveFrom">
|
||||
<ElFormItem label="生效开始时间" prop="effectiveFrom" style="width:100%">
|
||||
<ElDatePicker
|
||||
v-model="model.effectiveFrom"
|
||||
class="w-full"
|
||||
type="datetime"
|
||||
placeholder="请选择生效开始时间"
|
||||
value-format="x"
|
||||
style="width:100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="生效结束时间" prop="effectiveUntil">
|
||||
<ElFormItem label="生效结束时间" prop="effectiveUntil" style="width:100%">
|
||||
<ElDatePicker
|
||||
v-model="model.effectiveUntil"
|
||||
class="w-full"
|
||||
type="datetime"
|
||||
placeholder="请选择生效结束时间"
|
||||
value-format="x"
|
||||
style="width:100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ElRow :gutter="16">
|
||||
<ElCol :span="24">
|
||||
<ElFormItem label="备注" prop="remark">
|
||||
<ElInput v-model="model.remark" type="textarea" :rows="4" placeholder="请输入备注" />
|
||||
@@ -313,4 +319,6 @@ watch(visible, value => {
|
||||
</BusinessFormDialog>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -81,7 +81,7 @@ function search() {
|
||||
<!-- </ElFormItem>-->
|
||||
<!-- </ElCol>-->
|
||||
<ElCol :lg="8" :md="12" :sm="12">
|
||||
<ElFormItem label="用户名" prop="subordinateUserId">
|
||||
<ElFormItem label="用户名" prop="subordinateUserId" style="margin-left: -50px">
|
||||
<ElSelect v-model="model.subordinateUserId" class="w-full" placeholder="请选择用户名" clearable filterable>
|
||||
<ElOption v-for="user in userList" :key="user.id" :label="user.nickname" :value="user.id"/>
|
||||
</ElSelect>
|
||||
@@ -94,4 +94,8 @@ function search() {
|
||||
:deep(.el-form-item__label) {
|
||||
width: 100px !important;
|
||||
}
|
||||
|
||||
:deep(.el-row) {
|
||||
margin: 0 0 -15px 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
} from '@/service/api';
|
||||
import {useUIPaginatedTable} from '@/hooks/common/table';
|
||||
import BusinessTableActionCell from '@/components/custom/business-table-action-cell';
|
||||
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';
|
||||
@@ -28,6 +29,7 @@ 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'});
|
||||
|
||||
@@ -146,6 +148,7 @@ 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);
|
||||
@@ -644,6 +647,12 @@ onMounted(async () => {
|
||||
</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">
|
||||
@@ -725,6 +734,16 @@ onMounted(async () => {
|
||||
/>
|
||||
|
||||
<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>
|
||||
|
||||
Reference in New Issue
Block a user