feat(dc): Complete Phase 1 - Portal workbench page development

Summary:
- Implement DC module Portal page with 3 tool cards
- Create ToolCard component with decorative background and hover animations
- Implement TaskList component with table layout and progress bars
- Implement AssetLibrary component with tab switching and file cards
- Complete database verification (4 tables confirmed)
- Complete backend API verification (6 endpoints ready)
- Optimize UI to match prototype design (V2.html)

Frontend Components (~715 lines):
- components/ToolCard.tsx - Tool cards with animations
- components/TaskList.tsx - Recent tasks table view
- components/AssetLibrary.tsx - Data asset library with tabs
- hooks/useRecentTasks.ts - Task state management
- hooks/useAssets.ts - Asset state management
- pages/Portal.tsx - Main portal page
- types/portal.ts - TypeScript type definitions

Backend Verification:
- Backend API: 1495 lines code verified
- Database: dc_schema with 4 tables verified
- API endpoints: 6 endpoints tested (templates API works)

Documentation:
- Database verification report
- Backend API test report
- Phase 1 completion summary
- UI optimization report
- Development task checklist
- Development plan for Tool B

Status: Phase 1 completed (100%), ready for browser testing
Next: Phase 2 - Tool B Step 1 and 2 development
This commit is contained in:
2025-12-02 21:53:24 +08:00
parent f240aa9236
commit d4d33528c7
83 changed files with 21863 additions and 1601 deletions

View File

@@ -0,0 +1,111 @@
/**
* 全文复筛结果Hook
*
* 功能:
* 1. 获取结果列表
* 2. 分页支持
* 3. 筛选支持
* 4. 人工复核
*/
import { useState } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { message } from 'antd';
import { aslApi } from '../api';
interface UseFulltextResultsOptions {
taskId: string;
page?: number;
pageSize?: number;
filter?: 'all' | 'conflict' | 'pending' | 'reviewed';
enabled?: boolean;
}
export function useFulltextResults({
taskId,
page = 1,
pageSize = 20,
filter = 'all',
enabled = true,
}: UseFulltextResultsOptions) {
const queryClient = useQueryClient();
// 获取结果列表
const {
data,
isLoading,
error,
refetch,
} = useQuery({
queryKey: ['fulltextResults', taskId, page, pageSize, filter],
queryFn: async () => {
const response = await aslApi.getFulltextTaskResults(taskId, {
page,
pageSize,
filter,
});
return response.data;
},
enabled: enabled && !!taskId,
retry: 1,
});
// 人工复核Mutation
const reviewMutation = useMutation({
mutationFn: async ({
resultId,
decision,
note,
}: {
resultId: string;
decision: 'include' | 'exclude';
note?: string;
}) => {
const exclusionReason = decision === 'exclude' ? note || '未提供原因' : undefined;
await aslApi.updateFulltextDecision(resultId, {
finalDecision: decision,
exclusionReason,
reviewNotes: note,
});
},
onSuccess: () => {
message.success('复核提交成功');
// 刷新结果列表
queryClient.invalidateQueries({ queryKey: ['fulltextResults', taskId] });
},
onError: (error: Error) => {
message.error('复核提交失败: ' + error.message);
},
});
const results = data?.results || [];
const total = data?.total || 0;
const summary = data?.summary || {
totalResults: 0,
conflictCount: 0,
pendingReview: 0,
reviewed: 0,
};
return {
results,
total,
summary,
isLoading,
error,
refetch,
review: reviewMutation.mutate,
isReviewing: reviewMutation.isPending,
};
}