import { get } from '../axios-client'; import { API_BASE_URL } from '../../config/api-config'; import axios from 'axios'; // 组织路径信息(懒加载接口返回) export interface OrganizationPath { tenant_name: string; dep_name: string; dep_short_name: string; ou_name: string; } // 用户信息接口(新版,匹配 /api/v2/users 响应) export interface UserInfo { id: number; username: string; nick_name: string; area: string; ou_id: string; ou_name: string; is_leader: boolean; status: number; // 以下字段在搜索接口中有值,在懒加载接口中为 null tenant_name: string | null; dep_name: string | null; dep_short_name: string | null; email?: string; phone_number?: string; // 懒加载接口返回的组织路径信息 organization_path?: OrganizationPath | null; } // 组织节点接口(新版,匹配 /api/v2/users/organizations/tree 响应) export interface OrganizationNode { ou_id: string; ou_name: string; parent_ou_id: string | null; level: number; children: OrganizationNode[]; users: UserInfo[]; } // 组织架构响应接口 export interface OrganizationResponse { organizations: OrganizationNode[]; total_organizations: number; total_users: number; } // 用户列表响应接口 export interface UserListResponse { users: UserInfo[]; total: number; } // API响应格式 export interface ApiResponse { success: boolean; data?: T; error?: string; message?: string; status?: number; } /** * 获取组织架构树(新版接口,支持按需加载) * @param includeUsers 是否包含用户信息 * @param rootUuid 指定根节点UUID,不传则查询所有根节点 * @param jwtToken JWT Token * @returns 组织架构树 */ export async function getOrganizationTree( includeUsers: boolean = false, jwtToken?: string, rootUuid?: string ): Promise> { try { // console.log('[getOrganizationTree] 开始调用获取组织架构API:', { includeUsers, rootUuid }); const params: string[] = []; params.push(`include_users=${includeUsers}`); if (rootUuid) { params.push(`root_uuid=${rootUuid}`); } const url = `${API_BASE_URL}/api/v2/users/organizations/tree?${params.join('&')}`; const headers: Record = { 'Content-Type': 'application/json' }; if (jwtToken) { headers['Authorization'] = `Bearer ${jwtToken}`; } const response = await axios.get(url, { headers }); const responseData = response.data; // console.log('[getOrganizationTree] API响应:', responseData); return { success: true, data: responseData }; } catch (error) { console.error('[getOrganizationTree] 获取组织架构失败:', error); let errorMessage = '获取组织架构失败'; if (axios.isAxiosError(error)) { if (error.response?.data?.detail) { errorMessage = error.response.data.detail; } else if (error.response?.data?.message) { errorMessage = error.response.data.message; } } else if (error instanceof Error) { errorMessage = error.message; } return { success: false, error: errorMessage }; } } /** * 搜索用户(新版接口) * @param search 搜索关键词(模糊匹配姓名和工号) * @param page 页码 * @param pageSize 每页数量 * @param jwtToken JWT Token * @returns 用户列表 */ export async function searchUsers( search: string, page: number = 1, pageSize: number = 20, jwtToken?: string ): Promise> { try { // console.log('[searchUsers] 搜索用户:', { search, page, pageSize }); const params: string[] = []; if (search) params.push(`search=${encodeURIComponent(search)}`); params.push(`page=${page}`); params.push(`page_size=${pageSize}`); const url = `${API_BASE_URL}/api/v2/users?${params.join('&')}`; const headers: Record = { 'Content-Type': 'application/json' }; if (jwtToken) { headers['Authorization'] = `Bearer ${jwtToken}`; } const response = await axios.get<{ users: UserInfo[]; total: number }>(url, { headers }); const responseData = response.data; // console.log('[searchUsers] 搜索结果:', { total: responseData.total, count: responseData.users?.length }); return { success: true, data: responseData }; } catch (error) { console.error('[searchUsers] 搜索用户失败:', error); let errorMessage = '搜索用户失败'; if (axios.isAxiosError(error)) { if (error.response?.data?.detail) { errorMessage = error.response.data.detail; } else if (error.response?.data?.message) { errorMessage = error.response.data.message; } } else if (error instanceof Error) { errorMessage = error.message; } return { success: false, error: errorMessage }; } } /** * 获取用户列表 * @param params 查询参数 * @returns 用户列表 */ export async function getUserList(params: { page?: number; page_size?: number; ou_id?: string; is_leader?: boolean; status?: number; search?: string; } = {}): Promise> { try { // console.log('开始调用获取用户列表API,参数:', params); const queryParams = new URLSearchParams(); if (params.page) queryParams.append('page', params.page.toString()); if (params.page_size) queryParams.append('page_size', params.page_size.toString()); if (params.ou_id) queryParams.append('ou_id', params.ou_id); if (params.is_leader !== undefined) queryParams.append('is_leader', params.is_leader.toString()); if (params.status !== undefined) queryParams.append('status', params.status.toString()); if (params.search) queryParams.append('search', params.search); const response = await get( `/admin/users/users?${queryParams.toString()}` ); // console.log('用户列表API响应:', response); if (response.error) { console.error('获取用户列表失败:', response.error); return { success: false, error: response.error }; } return { success: true, data: response.data }; } catch (error) { console.error('获取用户列表失败:', error); return { success: false, error: error instanceof Error ? error.message : '获取用户列表失败' }; } } /** * 在组织架构树中查找指定节点并提取其用户 * @param organizations 组织架构数据 * @param targetOuId 目标节点的 ou_id * @returns 目标节点的用户列表转换为树节点 */ export function extractUsersFromNode(organizations: OrganizationNode[], targetOuId: string): TreeNodeItem[] { // 递归查找目标节点 function findNode(nodes: OrganizationNode[]): OrganizationNode | null { for (const node of nodes) { if (node.ou_id === targetOuId) { return node; } if (node.children && node.children.length > 0) { const found = findNode(node.children); if (found) return found; } } return null; } const targetNode = findNode(organizations); if (!targetNode) { console.warn('[extractUsersFromNode] 未找到目标节点:', targetOuId); return []; } // 将该节点的用户转换为树节点 if (targetNode.users && targetNode.users.length > 0) { return targetNode.users.map(user => convertUserToTreeNode(user)); } return []; } /** * 将组织架构数据转换为前端树形选择器格式 * @param organizations 组织架构数据 * @returns 前端树形选择器格式的数据 */ export function convertToTreeData(organizations: OrganizationNode[]): TreeNodeItem[] { return organizations.map(org => { // 递归处理子组织 const subOrganizations = org.children && org.children.length > 0 ? convertToTreeData(org.children) : []; // 添加该组织下的用户 const userChildren = (org.users && org.users.length > 0) ? org.users.map(user => convertUserToTreeNode(user)) : []; // 合并子组织和用户 const children = [...subOrganizations, ...userChildren]; // 判断是否已加载: // 1. 如果有子组织,说明数据已经完整(初始加载会返回完整的3层结构) // 2. 如果没有子组织但有用户,说明是叶子节点且用户已加载 // 3. 如果既没有子组织也没有用户,说明是叶子节点但用户未加载(需要懒加载) const hasSubOrgs = org.children && org.children.length > 0; const hasUsers = org.users && org.users.length > 0; // hasChildren 为 true 的情况: // - 有子组织(可以展开查看下级) // - 没有用户且没有子组织(可能需要懒加载用户) const canExpand = hasSubOrgs || (!hasSubOrgs && !hasUsers); return { label: org.ou_name, value: org.ou_id, isUser: false, hasChildren: canExpand, isLoaded: hasSubOrgs || hasUsers, // 有子组织或用户的节点视为已加载 children: children.length > 0 ? children : undefined }; }); } /** * 将用户信息转换为树节点格式 * @param user 用户信息 * @returns 树节点 */ export function convertUserToTreeNode(user: UserInfo): TreeNodeItem { return { label: user.nick_name, value: `user_${user.id}`, isUser: true, hasChildren: false, userInfo: user }; } /** * 将搜索结果转换为树节点列表 * @param users 用户列表 * @returns 树节点列表 */ export function convertSearchResultsToTreeNodes(users: UserInfo[]): TreeNodeItem[] { return users.map(user => convertUserToTreeNode(user)); } // 树节点类型(用于 MultiCascader 组件) export interface TreeNodeItem { label: string; value: string; isUser: boolean; hasChildren: boolean; userInfo?: UserInfo; children?: TreeNodeItem[]; } /** * 获取扁平化组织列表 * @param includeUsers 是否包含用户信息 * @returns 扁平化组织列表 */ export async function getFlatOrganizations(includeUsers: boolean = true): Promise> { try { // console.log('开始调用获取扁平化组织列表API'); const response = await get( `/admin/users/organizations/flat?include_users=${includeUsers}` ); // console.log('扁平化组织列表API响应:', response); if (response.error) { console.error('获取扁平化组织列表失败:', response.error); return { success: false, error: response.error }; } return { success: true, data: response.data }; } catch (error) { console.error('获取扁平化组织列表失败:', error); return { success: false, error: error instanceof Error ? error.message : '获取扁平化组织列表失败' }; } }