casualroom/apps/fenghuo/web/components/profile/profile-overview.tsx

274 lines
7.6 KiB
TypeScript
Raw Permalink Normal View History

2025-07-28 07:50:50 +08:00
'use client';
import { ProfileDataTable } from './profile-data-table';
import { useProfile } from './profile-provider';
import { useTRPC } from '@fenghuo/client';
import { useState, useEffect, useMemo } from 'react';
import { useQuery } from '@tanstack/react-query';
interface PaginationInfo {
page: number;
pageSize: number;
totalPages: number;
totalCount: number;
hasNextPage: boolean;
hasPreviousPage: boolean;
}
export function ProfileOverview() {
const {
handleAddEmployee,
handleViewDetail,
handleDeleteEmployee,
registerRefetch,
} = useProfile();
const [currentPage, setCurrentPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
const [searchValue, setSearchValue] = useState('');
const [debouncedSearchValue, setDebouncedSearchValue] = useState('');
const [selectedOrganizationIds, setSelectedOrganizationIds] = useState<string[]>([]);
const [sortBy, setSortBy] = useState<string>('default');
// 使用 useEffect 实现防抖
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedSearchValue(searchValue);
}, 300);
return () => clearTimeout(timer);
}, [searchValue]);
const trpc = useTRPC();
// 修改搜索条件构建逻辑
const searchConditions = useMemo(() => {
const conditions: any = {};
// 部门筛选条件 - 使用组织路径查询包含子组织
if (selectedOrganizationIds.length > 0) {
const organizationConditions = selectedOrganizationIds.flatMap(organizationId => [
// 直接匹配当前组织
{ organizationId: organizationId },
// 匹配所有子组织通过路径包含当前组织ID
{
organization: {
path: {
contains: organizationId
}
}
}
]);
conditions.OR = organizationConditions;
}
// 搜索条件
if (debouncedSearchValue.trim()) {
const searchTerm = debouncedSearchValue.trim();
const baseConditions: any[] = [
{ name: { contains: searchTerm, mode: 'insensitive' as const } },
// 身份证号搜索
{ idNum: { contains: searchTerm, mode: 'insensitive' as const } },
// 证件号搜索
{ paperId: { contains: searchTerm, mode: 'insensitive' as const } },
// 身份搜索
{ identity: { contains: searchTerm, mode: 'insensitive' as const } },
// 等级搜索
{ level: { contains: searchTerm, mode: 'insensitive' as const } },
// 职务名称搜索
{ dutyName: { contains: searchTerm, mode: 'insensitive' as const } },
// 职务代码搜索
{ dutyCode: { contains: searchTerm, mode: 'insensitive' as const } },
// 组织名称搜索
{ organization: { name: { contains: searchTerm, mode: 'insensitive' as const } } },
// 代理职务
{ metadata: { path: ['proxyDuty'], string_contains: searchTerm } },
// 政治面貌搜索
{ metadata: { path: ['politicalStatus'], string_contains: searchTerm } },
// 党派职务搜索
{ metadata: { path: ['partyPosition'], string_contains: searchTerm } },
// 学历搜索
{ metadata: { path: ['education'], string_contains: searchTerm } },
// 学历形式搜索
{ metadata: { path: ['educationForm'], string_contains: searchTerm } },
// 学校专业搜索
{ metadata: { path: ['schoolMajor'], string_contains: searchTerm } },
// 籍贯搜索
{ metadata: { path: ['native', 'province'], string_contains: searchTerm } },
// 籍贯城市搜索
{ metadata: { path: ['native', 'city'], string_contains: searchTerm } },
// 籍贯县区搜索
{ metadata: { path: ['native', 'county'], string_contains: searchTerm } },
];
// 性别搜索:支持"男"、"女"关键词
if (searchTerm === '男' || searchTerm.toLowerCase() === 'male') {
baseConditions.push({
gender: {
equals: 1,
},
});
} else if (searchTerm === '女' || searchTerm.toLowerCase() === 'female') {
baseConditions.push({
gender: {
not: 1,
},
});
}
// 如果同时有部门筛选和搜索条件,需要合并条件
if (selectedOrganizationIds.length > 0) {
const organizationConditions = selectedOrganizationIds.flatMap(organizationId => [
// 直接匹配当前组织
{ organizationId: organizationId },
// 匹配所有子组织通过路径包含当前组织ID
{
organization: {
path: {
contains: organizationId
}
}
}
]);
conditions.AND = [
{
OR: organizationConditions
},
{
OR: baseConditions
}
];
} else {
conditions.OR = baseConditions;
}
}
return conditions;
}, [debouncedSearchValue, selectedOrganizationIds]);
// 构建排序条件
const orderByCondition = useMemo(() => {
switch (sortBy) {
case 'dutyLevelDown':
return { dutyLevel: 'desc' as const };
case 'dutyLevelUp':
return { dutyLevel: 'asc' as const };
case 'hireDateDown':
return { hireDate: 'desc' as const };
case 'hireDateUp':
return { hireDate: 'asc' as const };
case 'birthdayDown':
return { birthday: 'desc' as const };
case 'birthdayUp':
return { birthday: 'asc' as const };
default:
return { createdAt: 'desc' as const };
}
}, [sortBy]);
const { data: profileResponse, isLoading: profilesLoading, refetch } = useQuery({
...trpc.profile.findManyWithPagination.queryOptions({
where: {
deletedAt: null,
...searchConditions,
},
page: currentPage,
pageSize: pageSize,
orderBy: orderByCondition,
include: {
organization: {
include: {
children: true,
parent: true,
terms: {
include: {
taxonomy: true,
}
}
},
},
},
}),
});
// 注册refetch函数到provider
useEffect(() => {
registerRefetch(refetch);
}, [registerRefetch, refetch]);
// 搜索时重置到第一页
useEffect(() => {
if (debouncedSearchValue !== searchValue) {
setCurrentPage(1);
}
}, [debouncedSearchValue, searchValue]);
// 部门筛选时重置到第一页
useEffect(() => {
if (selectedOrganizationIds.length > 0) {
setCurrentPage(1);
}
}, [selectedOrganizationIds]);
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
const handlePageSizeChange = (size: number) => {
setPageSize(size);
setCurrentPage(1);
};
// 处理部门筛选变化
const handleOrganizationChange = (organizationIds: string[]) => {
setSelectedOrganizationIds(organizationIds);
setCurrentPage(1); // 筛选时重置到第一页
};
// 修改现有的搜索变化处理
const handleSearchChange = (value: string) => {
setSearchValue(value);
setCurrentPage(1); // 搜索时重置到第一页
};
// 处理排序变化
const handleSortChange = (value: string) => {
setSortBy(value);
setCurrentPage(1); // 排序时重置到第一页
};
const pagination: PaginationInfo = {
page: currentPage,
pageSize: pageSize,
totalPages: profileResponse?.totalPages || 0,
totalCount: profileResponse?.totalCount || 0,
hasNextPage: profileResponse?.hasNextPage || false,
hasPreviousPage: profileResponse?.hasPreviousPage || false,
};
return (
<div className="w-full">
<ProfileDataTable
data={profileResponse?.items || []}
pagination={pagination}
onPageChange={handlePageChange}
onPageSizeChange={handlePageSizeChange}
onAddEmployee={handleAddEmployee}
onViewDetail={handleViewDetail}
onDeleteEmployee={(profileId: string) => handleDeleteEmployee(profileId, refetch)}
isLoading={profilesLoading}
searchValue={searchValue}
onSearchChange={handleSearchChange}
// 添加部门筛选相关属性
selectedOrganizationIds={selectedOrganizationIds}
onOrganizationChange={handleOrganizationChange}
// 添加排序相关属性
sortBy={sortBy}
onSortChange={handleSortChange}
/>
</div>
);
}