194 lines
7.7 KiB
TypeScript
194 lines
7.7 KiB
TypeScript
|
|
'use client';
|
|||
|
|
|
|||
|
|
import * as React from 'react';
|
|||
|
|
import { useQuery } from '@tanstack/react-query';
|
|||
|
|
import { useTRPC, useTRPCClient } from '@fenghuo/client';
|
|||
|
|
import { EliteDataTable } from './elite-data-table';
|
|||
|
|
import { EliteSheet } from './elite-sheet';
|
|||
|
|
import { useProfile } from './profile-provider';
|
|||
|
|
import { toast } from '@nice/ui/components/sonner';
|
|||
|
|
import { exportEliteFormToExcel } from '@/lib/profile/utils';;
|
|||
|
|
import type { RouterOutputs } from '@fenghuo/client';
|
|||
|
|
|
|||
|
|
type ExportEliteFormResult = RouterOutputs['profile']['findElite'];
|
|||
|
|
|
|||
|
|
export function ProfileElite() {
|
|||
|
|
const trpc = useTRPC();
|
|||
|
|
const trpcClient = useTRPCClient();
|
|||
|
|
const { handleViewDetail, handleAddEmployee } = useProfile();
|
|||
|
|
|
|||
|
|
// Sheet 状态管理 - 修改状态结构
|
|||
|
|
const [sheetOpen, setSheetOpen] = React.useState(false);
|
|||
|
|
const [sheetTitle, setSheetTitle] = React.useState<string>('');
|
|||
|
|
const [sheetProfessionId, setSheetProfessionId] = React.useState<string | undefined>();
|
|||
|
|
const [sheetStationId, setSheetStationId] = React.useState<string | undefined>();
|
|||
|
|
|
|||
|
|
// 筛选状态
|
|||
|
|
const [selectedProfessionIds, setSelectedProfessionIds] = React.useState<string[]>([]);
|
|||
|
|
const [selectedStationIds, setSelectedStationIds] = React.useState<string[]>([]);
|
|||
|
|
const [selectedDutyLevels, setSelectedDutyLevels] = React.useState<number[]>([]);
|
|||
|
|
const [searchKeyword, setSearchKeyword] = React.useState<string>('');
|
|||
|
|
|
|||
|
|
// 分页状态
|
|||
|
|
const [currentPage, setCurrentPage] = React.useState(1);
|
|||
|
|
const [pageSize, setPageSize] = React.useState(5);
|
|||
|
|
|
|||
|
|
// 导出状态
|
|||
|
|
const [isExporting, setIsExporting] = React.useState(false);
|
|||
|
|
|
|||
|
|
// 使用tRPC调用findElite获取数据,传入筛选和分页参数
|
|||
|
|
const { data: eliteData, isLoading, error } = useQuery({
|
|||
|
|
...trpc.profile.findElite.queryOptions({
|
|||
|
|
professionIds: selectedProfessionIds.length > 0 ? selectedProfessionIds : undefined,
|
|||
|
|
stationIds: selectedStationIds.length > 0 ? selectedStationIds : undefined,
|
|||
|
|
dutyLevels: selectedDutyLevels.length > 0 ? selectedDutyLevels : undefined,
|
|||
|
|
searchKeyword: searchKeyword.trim() || undefined,
|
|||
|
|
page: currentPage,
|
|||
|
|
pageSize: pageSize,
|
|||
|
|
}),
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 当筛选条件改变时,重置到第一页
|
|||
|
|
React.useEffect(() => {
|
|||
|
|
setCurrentPage(1);
|
|||
|
|
}, [selectedProfessionIds, selectedStationIds, selectedDutyLevels, searchKeyword]);
|
|||
|
|
|
|||
|
|
// 处理查看详情的点击事件
|
|||
|
|
const handleViewPersonDetail = (personId: string) => {
|
|||
|
|
handleViewDetail(personId);
|
|||
|
|
// setSheetOpen(false);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 处理专业点击事件 - 修改为使用专业ID
|
|||
|
|
const handleProfessionClick = (professionName: string, professionId: string) => {
|
|||
|
|
setSheetTitle(professionName);
|
|||
|
|
setSheetProfessionId(professionId);
|
|||
|
|
setSheetStationId(undefined); // 清除台站ID
|
|||
|
|
setSheetOpen(true);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 处理台站点击事件 - 新增
|
|||
|
|
const handleStationClick = (professionName: string, stationId: string, professionId: string) => {
|
|||
|
|
setSheetTitle(professionName);
|
|||
|
|
setSheetProfessionId(professionId);
|
|||
|
|
setSheetStationId(stationId);
|
|||
|
|
setSheetOpen(true);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 处理分页变化
|
|||
|
|
const handlePageChange = (page: number) => {
|
|||
|
|
setCurrentPage(page);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 处理每页大小变化
|
|||
|
|
const handlePageSizeChange = (newPageSize: number) => {
|
|||
|
|
setPageSize(newPageSize);
|
|||
|
|
setCurrentPage(1); // 重置到第一页
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 处理导出全部数据
|
|||
|
|
const handleExportTable = async () => {
|
|||
|
|
if (isExporting) return;
|
|||
|
|
setIsExporting(true);
|
|||
|
|
toast.loading('正在导出表格...', { id: 'export-all-loading' });
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 使用专门的导出接口获取所有数据
|
|||
|
|
const result: ExportEliteFormResult = await trpcClient.profile.findElite.query({
|
|||
|
|
page: 1,
|
|||
|
|
pageSize: 1000
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 使用前端工具函数导出 Excel
|
|||
|
|
await exportEliteFormToExcel(result.data, result.columns);
|
|||
|
|
|
|||
|
|
toast.success(`导出全部数据成功`, { id: 'export-all-loading' });
|
|||
|
|
} catch (error: any) {
|
|||
|
|
toast.error(`导出失败: ${error.message}`, { id: 'export-all-loading' });
|
|||
|
|
} finally {
|
|||
|
|
setIsExporting(false);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const handleExportFilteredTable = async () => {
|
|||
|
|
if (isExporting) return;
|
|||
|
|
setIsExporting(true);
|
|||
|
|
toast.loading('正在导出表格...', { id: 'export-filtered-loading' });
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 使用专门的导出接口获取所有数据
|
|||
|
|
const result: ExportEliteFormResult = await trpcClient.profile.findElite.query({
|
|||
|
|
page: 1,
|
|||
|
|
pageSize: 1000,
|
|||
|
|
professionIds: selectedProfessionIds.length > 0 ? selectedProfessionIds : undefined,
|
|||
|
|
stationIds: selectedStationIds.length > 0 ? selectedStationIds : undefined,
|
|||
|
|
dutyLevels: selectedDutyLevels.length > 0 ? selectedDutyLevels : undefined,
|
|||
|
|
searchKeyword: searchKeyword.trim() || undefined
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 使用前端工具函数导出 Excel
|
|||
|
|
await exportEliteFormToExcel(result.data, result.columns);
|
|||
|
|
|
|||
|
|
toast.success(`导出筛选数据成功`, { id: 'export-filtered-loading' });
|
|||
|
|
} catch (error: any) {
|
|||
|
|
toast.error(`导出失败: ${error.message}`, { id: 'export-filtered-loading' });
|
|||
|
|
} finally {
|
|||
|
|
setIsExporting(false);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (error) {
|
|||
|
|
return (
|
|||
|
|
<div className="flex items-center justify-center h-64">
|
|||
|
|
<div className="text-center">
|
|||
|
|
<p className="text-red-500 mb-2">加载失败</p>
|
|||
|
|
<p className="text-sm text-muted-foreground">{error.message}</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div>
|
|||
|
|
<EliteDataTable
|
|||
|
|
data={eliteData?.data || []}
|
|||
|
|
isLoading={isLoading}
|
|||
|
|
onViewDetail={handleViewPersonDetail}
|
|||
|
|
onProfessionClick={handleProfessionClick}
|
|||
|
|
onStationClick={handleStationClick} // 新增台站点击处理
|
|||
|
|
onAddEmployee={handleAddEmployee}
|
|||
|
|
onExportTable={handleExportTable}
|
|||
|
|
onExportFilteredTable={handleExportFilteredTable}
|
|||
|
|
isExporting={isExporting}
|
|||
|
|
// 筛选相关props
|
|||
|
|
selectedProfessionIds={selectedProfessionIds}
|
|||
|
|
onProfessionIdsChange={setSelectedProfessionIds}
|
|||
|
|
selectedStationIds={selectedStationIds}
|
|||
|
|
onStationIdsChange={setSelectedStationIds}
|
|||
|
|
selectedDutyLevels={selectedDutyLevels}
|
|||
|
|
onDutyLevelsChange={setSelectedDutyLevels}
|
|||
|
|
// 搜索相关props
|
|||
|
|
searchKeyword={searchKeyword}
|
|||
|
|
onSearchKeywordChange={setSearchKeyword}
|
|||
|
|
// 分页相关props
|
|||
|
|
currentPage={eliteData?.currentPage || 1}
|
|||
|
|
totalPages={eliteData?.totalPages || 1}
|
|||
|
|
totalCount={eliteData?.totalCount || 0}
|
|||
|
|
pageSize={eliteData?.pageSize || 10}
|
|||
|
|
hasNextPage={eliteData?.hasNextPage || false}
|
|||
|
|
hasPreviousPage={eliteData?.hasPreviousPage || false}
|
|||
|
|
onPageChange={handlePageChange}
|
|||
|
|
onPageSizeChange={handlePageSizeChange}
|
|||
|
|
/>
|
|||
|
|
|
|||
|
|
<EliteSheet
|
|||
|
|
open={sheetOpen}
|
|||
|
|
onOpenChange={setSheetOpen}
|
|||
|
|
title={sheetTitle}
|
|||
|
|
professionId={sheetProfessionId}
|
|||
|
|
stationId={sheetStationId}
|
|||
|
|
onViewDetail={handleViewPersonDetail}
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
}
|