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

274 lines
7.6 KiB
TypeScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'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>
);
}