From 9a9ce5fa55e23cc4da5a97d4fcfa6f39bd25a5fc Mon Sep 17 00:00:00 2001 From: yorn <1057707203@qq.com> Date: Tue, 15 Apr 2025 23:24:32 +0800 Subject: [PATCH] fixed --- app/api/client.ts | 6 +- app/api/evaluation_points/reviews.ts | 237 +++++++++++++ app/api/evaluation_points/rules-files.ts | 371 ++++++++++++++++++++ app/api/files/documents.ts | 22 +- app/components/reviews/FileInfo.tsx | 7 +- app/components/reviews/ReviewPointsList.tsx | 366 +++++++++++++++---- app/components/reviews/index.ts | 1 + app/routes/_index.tsx | 110 ++---- app/routes/documents._index.tsx | 9 +- app/routes/files.upload.tsx | 18 +- app/routes/prompts._index.tsx | 10 +- app/routes/prompts.new.tsx | 19 +- app/routes/reviews.tsx | 147 +++++--- app/routes/rules-files.tsx | 368 ++++++------------- app/routes/rules._index.tsx | 4 +- app/styles/components/table.css | 2 +- app/styles/pages/documents_index.css | 7 +- app/styles/reviews.css | 9 + json.txt | 252 +++++++++---- 19 files changed, 1405 insertions(+), 560 deletions(-) create mode 100644 app/api/evaluation_points/reviews.ts diff --git a/app/api/client.ts b/app/api/client.ts index c9b6575..a4607d3 100644 --- a/app/api/client.ts +++ b/app/api/client.ts @@ -14,9 +14,9 @@ export type ApiResponse = { export type QueryParams = Record; // 获取 API 基础 URL -// const API_BASE_URL = '172.18.0.100:3000'; -// const API_BASE_URL = '172.16.0.119:9000/admin'; -export const API_BASE_URL = 'http://nas.7bm.co:3000'; +const API_BASE_URL = 'http://172.18.0.100:3000'; +// const API_BASE_URL = 'http://172.16.0.119:9000/admin'; +// export const API_BASE_URL = 'http://nas.7bm.co:3000'; // 是否使用模拟数据(开发环境使用) const USE_MOCK_DATA = false; // 设置为true使用模拟数据,避免API连接问题 diff --git a/app/api/evaluation_points/reviews.ts b/app/api/evaluation_points/reviews.ts new file mode 100644 index 0000000..b196a4d --- /dev/null +++ b/app/api/evaluation_points/reviews.ts @@ -0,0 +1,237 @@ +import { postgrestGet, type PostgrestParams } from "../postgrest-client"; +import dayjs from 'dayjs'; + +/** + * 格式化日期 + * @param dateString 日期字符串 + * @returns 格式化后的日期字符串 + */ +function formatDate(dateString: string): string { + if (!dateString) return ''; + try { + return dayjs(dateString).format('YYYY-MM-DD HH:mm:ss'); + } catch (error) { + console.error('日期格式化失败:', error); + return dateString; + } + } + +/** + * 从不同格式的 API 响应中提取数据 + * @param responseData API 响应数据 + * @returns 提取后的数据或 null + */ +function extractApiData(responseData: unknown): T | null { +if (!responseData) return null; + +// 格式1: { code: number, msg: string, data: T } +if (typeof responseData === 'object' && responseData !== null && + 'code' in responseData && + 'data' in responseData && + (responseData as { data: unknown }).data) { + return (responseData as { data: T }).data; +} + +// 格式2: 直接是数据对象 +return responseData as T; +} + +// 定义评查结果类型 +interface EvaluationResult { + id: string | number; + document_id: string | number; + evaluation_point_id: string | number; + evaluated_results?: { + result?: boolean; + message?: string; + data?: string; + [key: string]: unknown; + }; + [key: string]: unknown; +} + +// 定义评查点类型 +interface EvaluationPoint { + id: string | number; + evaluation_point_groups_id: string | number; + suggestion_message_type?: string; + suggestion_message?: string; + score?: number; + [key: string]: unknown; +} + +// 定义评查点组类型 +interface EvaluationPointGroup { + id: string | number; + name?: string; + [key: string]: unknown; +} + +// 定义前端使用的评查点结果类型 +interface ReviewPointResult { + id: string | number; + title: string; + groupName: string; + status: string; + content: string; + suggestion: string; + result?: boolean; + score: number; +} + +// 定义统计数据类型 +interface StatsData { + total: number; + success: number; + warning: number; + error: number; + score: number; +} + +/** + * 获取当前评查文件的所有评查点结果 + * @param fileId 评查文件ID + * @returns 评查点结果列表和统计数据 + */ +export async function getReviewPoints(fileId: string) { + // 步骤1:根据fileId查询evaluation_results表 + const evaluationResultsParams: PostgrestParams = { + select: '*', + filter: { + 'document_id': `eq.${fileId}` + } + }; + const evaluationResultsResponse = await postgrestGet('evaluation_results', evaluationResultsParams); + + if (evaluationResultsResponse.error) { + return { error: evaluationResultsResponse.error, status: evaluationResultsResponse.status }; + } + + const evaluationResultsData = extractApiData(evaluationResultsResponse.data); + + if (!evaluationResultsData || !Array.isArray(evaluationResultsData)) { + return { data: [], stats: { total: 0, success: 0, warning: 0, error: 0, score: 0 } }; + } + + // 收集所有评查点ID,用于查询评查点详情 + const evaluationPointIds = evaluationResultsData.map(item => item.evaluation_point_id).filter(Boolean); + + if (evaluationPointIds.length === 0) { + return { data: [], stats: { total: 0, success: 0, warning: 0, error: 0, score: 0 } }; + } + + // 步骤2:根据evaluation_point_id查询evaluation_points表 + const evaluationPointsParams: PostgrestParams = { + select: '*', + filter: { + 'id': `in.(${evaluationPointIds.join(',')})` + } + }; + const evaluationPointsResponse = await postgrestGet('evaluation_points', evaluationPointsParams); + + if (evaluationPointsResponse.error) { + return { error: evaluationPointsResponse.error, status: evaluationPointsResponse.status }; + } + + const evaluationPointsData = extractApiData(evaluationPointsResponse.data); + + if (!evaluationPointsData || !Array.isArray(evaluationPointsData)) { + return { data: [], stats: { total: 0, success: 0, warning: 0, error: 0, score: 0 } }; + } + + // 收集所有评查点组ID,用于查询评查点组详情 + const groupIds = evaluationPointsData.map(item => item.evaluation_point_groups_id).filter(Boolean); + + if (groupIds.length === 0) { + return { data: [], stats: { total: 0, success: 0, warning: 0, error: 0, score: 0 } }; + } + + // 查询评查点组 + const groupsParams: PostgrestParams = { + select: '*', + filter: { + 'id': `in.(${groupIds.join(',')})` + } + }; + const groupsResponse = await postgrestGet('evaluation_point_groups', groupsParams); + + if (groupsResponse.error) { + return { error: groupsResponse.error, status: groupsResponse.status }; + } + + const groupsData = extractApiData(groupsResponse.data); + + if (!groupsData || !Array.isArray(groupsData)) { + return { data: [], stats: { total: 0, success: 0, warning: 0, error: 0, score: 0 } }; + } + + // 创建映射关系以便快速查找 + const pointsMap = new Map(); + evaluationPointsData.forEach(point => { + pointsMap.set(point.id, point); + }); + + // console.log('pointsMap-------', pointsMap); + + const groupsMap = new Map(); + groupsData.forEach(group => { + groupsMap.set(group.id, group); + }); + + // console.log('groupsMap-------', groupsMap); + + // 构建前端所需的数据格式 + const resultData: ReviewPointResult[] = evaluationResultsData.map(result => { + const point = pointsMap.get(result.evaluation_point_id) || {} as EvaluationPoint; + const group = groupsMap.get(point.evaluation_point_groups_id || 0) || {} as EvaluationPointGroup; + + // 从 evaluated_results 中提取数据 + let message = ''; + let data = ''; + + if (result.evaluated_results && typeof result.evaluated_results === 'object') { + message = result.evaluated_results.message || ''; + data = result.evaluated_results.data || ''; + } + + return { + id: result.id, + title: message, + groupName: group.name || '', + status: point.suggestion_message_type || '', + content: data, + suggestion: point.suggestion_message || '', + result: result.evaluated_results?.result, // 记录评查结果,用于统计 + score: point.score || 0 + }; + }); + + // 统计数据 + const stats: StatsData = { + total: evaluationResultsData.length, + success: 0, + warning: 0, + error: 0, + score: 0 + }; + + // 计算统计数据 + resultData.forEach(item => { + // 成功数量统计 + if (item.result === true) { + stats.success += 1; + } else if (item.result === false) { + // 警告和错误数量统计 + if (item.status === 'warning') { + stats.warning += 1; + } else if (item.status === 'error') { + stats.error += 1; + } + } + + // 分数统计 + stats.score += item.score || 0; + }); + + return { data: resultData, stats }; +} diff --git a/app/api/evaluation_points/rules-files.ts b/app/api/evaluation_points/rules-files.ts index e69de29..78df771 100644 --- a/app/api/evaluation_points/rules-files.ts +++ b/app/api/evaluation_points/rules-files.ts @@ -0,0 +1,371 @@ +import { postgrestGet, postgrestPut, type PostgrestParams } from '../postgrest-client'; +import dayjs from 'dayjs'; +import { getDocumentTypes } from '../document-types/document-types'; +import type { DocumentTypeUI } from '../document-types/document-types'; +import weekday from 'dayjs/plugin/weekday'; +import updateLocale from 'dayjs/plugin/updateLocale'; + +// 配置 dayjs +dayjs.extend(weekday); +dayjs.extend(updateLocale); +// 设置一周的第一天为周一 +dayjs.updateLocale('en', { + weekStart: 1 +}); + +// 文档数据库表接口 +export interface Document { + id: number; + user_id: number | null; + type_id: number; + name: string; + document_number: string; + path: string; + storage_type: string; + file_size: number; + upload_time: string; + is_test_document: boolean; + evaluation_level: string; + status: string; + ocr_result: Record; + extracted_results: Record | null; + sumary: string | null; + remark: string; + created_at: string; + updated_at: string; + evaluations_status: number | null; + audit_status: number | null; +} + +// 文档类型接口 +export interface DocumentType { + id: number; + name: string; + description: string | null; + status: number; + created_at: string; + updated_at: string; +} + +// 评查文件UI接口 +export interface ReviewFileUI { + id: string; + fileName: string; + fileCode: string; + fileType: string; + fileTypeId: number; + fileSize: number; + uploadTime: string; + reviewStatus: string; + reviewStatusCode: number; + issueCount: number; + issues: Array<{ + severity: 'info' | 'warning' | 'error' | 'critical'; + message: string; + }>; + createdBy: string; +} + +// 文件列表搜索参数 +export interface DocumentSearchParams { + fileType?: string; // 文件类型ID + reviewStatus?: string; // 评查状态 + dateRange?: string; // 日期范围 + keyword?: string; // 搜索关键字 + sortOrder?: string; // 排序方式 + page?: number; // 当前页码 + pageSize?: number; // 每页条数 +} + +/** + * 格式化日期 + * @param dateString 日期字符串 + * @returns 格式化后的日期字符串 + */ +function formatDate(dateString: string): string { + if (!dateString) return ''; + try { + return dayjs(dateString).format('YYYY-MM-DD HH:mm:ss'); + } catch (error) { + console.error('日期格式化失败:', error); + return dateString; + } +} + +/** + * 从不同格式的 API 响应中提取数据 + * @param responseData API 响应数据 + * @returns 提取后的数据或 null + */ +function extractApiData(responseData: unknown): T | null { + if (!responseData) return null; + + // 格式1: { code: number, msg: string, data: T } + if (typeof responseData === 'object' && responseData !== null && + 'code' in responseData && + 'data' in responseData && + (responseData as { data: unknown }).data) { + return (responseData as { data: T }).data; + } + + // 格式2: 直接是数据对象 + return responseData as T; +} + +/** + * 将评查状态代码映射到UI状态 + * @param status 评查状态代码 + * @returns UI状态 + */ +export function mapReviewStatusToUI(status: number | null): string { + switch(status) { + case 1: return 'pass'; + case 2: return 'warning'; + case -1: return 'fail'; + case 0: return 'pending'; + default: return 'pending'; + } +} + +/** + * 将UI状态映射到评查状态代码 + * @param status UI状态 + * @returns 评查状态代码 + */ +export function mapUIToReviewStatus(status: string): number { + switch(status) { + case 'pass': return 1; + case 'warning': return 2; + case 'fail': return -1; + case 'pending': return 0; + default: return 0; + } +} + +/** + * 获取文件扩展名 + * @param fileName 文件名 + * @returns 文件扩展名 + */ +export function getFileExtension(fileName: string): string { + return fileName.split('.').pop()?.toLowerCase() || ''; +} + +/** + * 将数据库文档转换为UI文件对象 + * @param document 数据库文档 + * @param documentTypeName 文档类型名称 + * @returns UI文件对象 + */ +export function convertToReviewFileUI(document: Document, documentTypeName: string): ReviewFileUI { + const reviewStatus = mapReviewStatusToUI(document.evaluations_status); + + const reviewFileUI: ReviewFileUI = { + id: document.id.toString(), + fileName: document.name, + fileCode: document.document_number, + fileType: documentTypeName, + fileTypeId: document.type_id, + fileSize: document.file_size, + uploadTime: formatDate(document.created_at), + reviewStatus: reviewStatus, + reviewStatusCode: document.evaluations_status || 0, + issueCount: 0, + issues: [], + createdBy: document.user_id?.toString() || '系统' + }; + +// console.log('reviewFileUI-----',reviewFileUI); + + return reviewFileUI; +} + +/** + * 获取评查文件列表 + * @param searchParams 搜索参数 + * @returns 评查文件列表和总数 + */ +export async function getReviewFiles(searchParams: DocumentSearchParams = {}): Promise<{ + data?: { files: ReviewFileUI[], total: number }; + error?: string; + status?: number; +}> { + try { + const page = searchParams.page || 1; + const pageSize = searchParams.pageSize || 10; + + // 构建查询参数 + const params: PostgrestParams = { + select: '*', + order: 'created_at.desc', + headers: { + 'Prefer': 'count=exact' + }, + limit: pageSize, + offset: (page - 1) * pageSize, + filter: {} as Record + }; + + // 根据排序方式设置排序 + if (searchParams.sortOrder) { + switch (searchParams.sortOrder) { + case 'upload_time_desc': + params.order = 'created_at.desc'; + break; + case 'upload_time_asc': + params.order = 'created_at.asc'; + break; + // 其他排序方式可以在这里添加 + } + } + + // 添加筛选条件 + const filter: Record = {}; + + if (searchParams.fileType) { + filter['type_id'] = `eq.${searchParams.fileType}`; + } + + if (searchParams.reviewStatus) { + const statusValue = mapUIToReviewStatus(searchParams.reviewStatus); + filter['evaluations_status'] = `eq.${statusValue}`; + } + + if (searchParams.keyword) { + filter['or'] = `(name.ilike.%${searchParams.keyword}%,document_number.ilike.%${searchParams.keyword}%)`; + } + + // 处理日期范围筛选 + if (searchParams.dateRange) { + const now = dayjs(); + const today = now.startOf('day').format('YYYY-MM-DD HH:mm:ss'); + switch (searchParams.dateRange) { + case 'today': + filter['created_at'] = `gte.${today}`; + break; + case 'week': { + const weekStart = now.startOf('week').format('YYYY-MM-DD HH:mm:ss'); + filter['created_at'] = `gte.${weekStart}`; + break; + } + case 'month': { + const monthStart = now.startOf('month').format('YYYY-MM-DD HH:mm:ss'); + filter['created_at'] = `gte.${monthStart}`; + break; + } + } + } + + // console.log('filter-----',filter); + params.filter = filter; + + // 发送API请求获取文档列表 + const response = await postgrestGet('documents', params); + + if (response.error) { + return { error: response.error, status: response.status }; + } + + // 提取API返回的数据 + const extractedDocuments = extractApiData(response.data); + + if (!extractedDocuments) { + return { error: '获取评查文件数据失败', status: 500 }; + } + + // 从响应头中获取总数 + let totalCount = 0; + const responseWithHeaders = response as { data: Document[]; headers: Record }; + if(responseWithHeaders.headers){ + const rangeHeader = responseWithHeaders.headers['content-range']; + if(rangeHeader){ + const total = rangeHeader.split('/')[1]; + if(total !== '*'){ + totalCount = parseInt(total, 10); + } + } + } + + // 获取文档类型数据,用于查找文档类型名称 + const documentTypesResponse = await getDocumentTypes({pageSize: 500}); + const documentTypes = documentTypesResponse.data?.types || []; + + // 创建文档类型ID到名称的映射 + const typeNameMap: Record = {}; + documentTypes.forEach((type: DocumentTypeUI) => { + typeNameMap[type.id] = type.name; + }); + + // 将文档数据转换为UI文件对象 + const reviewFiles = extractedDocuments.map(doc => { + const typeName = typeNameMap[doc.type_id] || '未知类型'; + return convertToReviewFileUI(doc, typeName); + }); + + return { + data: { + files: reviewFiles, + total: totalCount + } + }; + } catch (error) { + console.error('获取评查文件列表失败:', error); + return { + error: error instanceof Error ? error.message : '获取评查文件列表失败', + status: 500 + }; + } +} + +/** + * 更新文件的评查状态 + * @param id 文件ID + * @param status 评查状态 + * @returns 更新后的文件信息 + */ +export async function updateReviewStatus(id: string, status: string): Promise<{ + data?: ReviewFileUI; + error?: string; + status?: number; +}> { + try { + if (!id) { + return { error: '文件ID不能为空', status: 400 }; + } + + const statusValue = mapUIToReviewStatus(status); + + const response = await postgrestPut>( + 'documents', + { evaluations_status: statusValue }, + { id: parseInt(id) } + ); + + if (response.error) { + return { error: response.error, status: response.status }; + } + + const extractedData = extractApiData(response.data); + + if (!extractedData) { + return { error: '更新评查状态失败', status: 500 }; + } + + // 获取文档类型,用于查找文档类型名称 + const documentTypesResponse = await getDocumentTypes({pageSize: 500}); + const documentTypes = documentTypesResponse.data?.types || []; + + // 查找文档类型名称 + const docType = documentTypes.find((type: DocumentTypeUI) => type.id === extractedData.type_id); + const typeName = docType ? docType.name : '未知类型'; + + return { data: convertToReviewFileUI(extractedData, typeName) }; + } catch (error) { + console.error('更新评查状态失败:', error); + return { + error: error instanceof Error ? error.message : '更新评查状态失败', + status: 500 + }; + } +} + diff --git a/app/api/files/documents.ts b/app/api/files/documents.ts index affa2c5..4b7a02f 100644 --- a/app/api/files/documents.ts +++ b/app/api/files/documents.ts @@ -71,10 +71,14 @@ export interface Document { status: 'pass' | 'warning' | 'waiting' | 'processing' | 'fail'; file_status: 'Waiting' | 'Cutting' | 'Extractioning' | 'Evaluationing' | 'Processed'; audit_status: number; // -1: 不通过, 0: 待审核, 1: 通过, 2: 警告, 3: 审核中 - ocr_result: unknown; - extracted_results: unknown; - summary: unknown; - remark: string; + ocr_result?: { + __meta?: { + page_count?: number; + } + }; + extracted_results?: unknown; + summary?: unknown; + remark?: string; created_at: string; updated_at: string; } @@ -96,6 +100,8 @@ export interface DocumentUI { fileType: string; path: string; isTest: boolean; + updatedAt?: string; + pageCount?: number; } /** @@ -124,13 +130,15 @@ async function convertToUIDocument(doc: Document): Promise { type: doc.type_id.toString(), typeName: docType?.name || '未知类型', size: doc.file_size, - auditStatus: doc.audit_status, + auditStatus: doc.audit_status || 0, fileStatus: doc.status || '', // 默认为'' issues: 0, // 固定为0 uploadTime: formatDate(doc.updated_at), fileType: getFileExtension(doc.name), path: doc.path, - isTest: doc.is_test_document + isTest: doc.is_test_document, + updatedAt: formatDate(doc.updated_at), + pageCount: doc.ocr_result?.__meta?.page_count || 0 }; } @@ -204,7 +212,7 @@ export async function getDocuments(searchParams: DocumentSearchParams = {}): Pro } } - console.log('filter-----', filter); + // console.log('filter-----', filter); params.filter = filter; // 发送请求 diff --git a/app/components/reviews/FileInfo.tsx b/app/components/reviews/FileInfo.tsx index ecb8546..55abbb2 100644 --- a/app/components/reviews/FileInfo.tsx +++ b/app/components/reviews/FileInfo.tsx @@ -1,17 +1,14 @@ -/** - * 文件信息组件 - * 显示文件名称、状态信息以及操作按钮(下载原文件、导出评查报告、确认评查结果) - */ interface FileInfoProps { fileInfo: { fileName: string; contractNumber: string; - fileSize?: string; + fileSize?: string; fileFormat?: string; pageCount?: number; uploadTime?: string; uploadUser?: string; + auditStatus?: number; }; onConfirmResults: () => void; } diff --git a/app/components/reviews/ReviewPointsList.tsx b/app/components/reviews/ReviewPointsList.tsx index 065d71c..335ee25 100644 --- a/app/components/reviews/ReviewPointsList.tsx +++ b/app/components/reviews/ReviewPointsList.tsx @@ -1,16 +1,34 @@ /** * 评查点列表组件 - * 显示评查结果统计和所有评查点列表 + * + * 功能概述: + * - 展示评查结果统计信息(总计、通过、警告、错误数量) + * - 提供评查点过滤功能(按状态和搜索文本) + * - 显示评查点详细信息(标题、状态、内容、建议修改等) + * - 支持评查点操作(一键替换、人工审核等) + * + * 组件结构: + * - 统计区域: 显示评查点数量统计 + * - 搜索区域: 提供文本搜索功能 + * - 评查点列表: 展示所有评查点 + * - 评查点卡片: 展示单个评查点详情 + * - 评查点头部: 显示标题和状态 + * - 评查点内容: 显示当前内容和问题 + * - 建议修改区域: 显示建议的修改内容 + * - 操作按钮: 提供一键替换和人工审核功能 */ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; -// 评查点类型定义 -interface ReviewPoint { +/** + * 评查点类型定义 + * 用于展示单个评查结果 + */ +export interface ReviewPoint { id: string; title: string; - location: string; + groupName: string; status: string; - content: string; + content: string | Record; suggestion: string; needsHumanReview?: boolean; humanReviewNote?: string; @@ -20,6 +38,7 @@ interface ReviewPoint { section: string; index: number; }; + result?: boolean; } // 统计数据类型 @@ -41,29 +60,75 @@ interface ReviewPointsListProps { export function ReviewPointsList({ reviewPoints, - statistics, + statistics, activeReviewPointId, onReviewPointSelect, onStatusChange }: ReviewPointsListProps) { - const [editingReviewPoint, setEditingReviewPoint] = useState(null); - const [userInputText, setUserInputText] = useState(''); - const [searchText, setSearchText] = useState(''); - const [statusFilter, setStatusFilter] = useState(null); + // 状态管理 + const [editingReviewPoint, setEditingReviewPoint] = useState(null); // 当前正在编辑的评查点ID + const [userInputText, setUserInputText] = useState(''); // 用户输入的审核意见文本 + const [searchText, setSearchText] = useState(''); // 搜索文本 + const [statusFilter, setStatusFilter] = useState(null); // 状态过滤 + const [suggestionTexts, setSuggestionTexts] = useState>({}); // 存储每个评查点的建议文本 - // 过滤评查点 + // 初始化建议文本 + useEffect(() => { + // 将所有评查点的建议文本存储到状态中 + const suggestions: Record = {}; + reviewPoints.forEach(point => { + suggestions[point.id] = point.suggestion || ''; + }); + setSuggestionTexts(suggestions); + }, [reviewPoints]); + + // 处理建议文本变更 + const handleSuggestionChange = (reviewPointId: string, text: string) => { + setSuggestionTexts(prev => ({ + ...prev, + [reviewPointId]: text + })); + }; + + /** + * 过滤评查点 + * 根据搜索文本和状态过滤条件筛选评查点 + */ const filteredReviewPoints = reviewPoints.filter(point => { + // 匹配搜索文本 const matchesSearch = searchText === '' || point.title.toLowerCase().includes(searchText.toLowerCase()) || - point.location.toLowerCase().includes(searchText.toLowerCase()) || - point.content.toLowerCase().includes(searchText.toLowerCase()); + point.groupName.toLowerCase().includes(searchText.toLowerCase()) || + (typeof point.content === 'string' && point.content.toLowerCase().includes(searchText.toLowerCase())) || + (typeof point.content === 'object' && point.content !== null && + Object.values(point.content).some(value => + typeof value === 'string' && value.toLowerCase().includes(searchText.toLowerCase()) + )); - const matchesStatus = statusFilter === null || point.status === statusFilter; + // 处理状态过滤 + let matchesStatus = false; + + if (statusFilter === null) { + // 未选择过滤条件时显示所有 + matchesStatus = true; + } else if (statusFilter === 'success') { + // 过滤"通过"状态 + matchesStatus = point.result === true || (point.result === undefined && point.status === 'success'); + } else if (statusFilter === 'warning') { + // 过滤"警告"状态 + matchesStatus = point.result === false && point.status === 'warning'; + } else if (statusFilter === 'error') { + // 过滤"错误"状态 + matchesStatus = point.result === false && point.status === 'error'; + } return matchesSearch && matchesStatus; }); - // 处理点击"一键替换"按钮 + /** + * 处理一键替换操作 + * @param reviewPointId 评查点ID + */ const handleReplace = (reviewPointId: string) => { // 在实际应用中,这里应该调用API进行内容替换 // 模拟替换操作 @@ -73,7 +138,11 @@ export function ReviewPointsList({ onStatusChange(reviewPointId, 'success'); }; - // 处理评查点审核操作 + /** + * 处理评查点审核操作 + * @param reviewPointId 评查点ID + * @param action 操作类型: 'approve' 通过 / 'reject' 不通过 + */ const handleReviewAction = (reviewPointId: string, action: 'approve' | 'reject') => { // 更新评查点状态 onStatusChange(reviewPointId, action === 'approve' ? 'success' : 'error'); @@ -85,7 +154,10 @@ export function ReviewPointsList({ alert(`${action === 'approve' ? '通过' : '不通过'}了评查点 ${reviewPointId}`); }; - // 显示评查点详情编辑界面 + /** + * 显示评查点详情编辑界面 + * @param reviewPointId 评查点ID + */ const handleEditReviewPoint = (reviewPointId: string) => { setEditingReviewPoint(reviewPointId); @@ -96,18 +168,51 @@ export function ReviewPointsList({ } }; - // 渲染评查统计信息 + /** + * 渲染评查统计信息 + * 显示总计、通过、警告、错误数量 + */ const renderStatistics = () => { + // 确保传入的statistics存在,否则使用计算值 + const statsToUse = statistics || { + total: reviewPoints.length, + success: 0, + warning: 0, + error: 0, + score: 0 + }; + + // 计算各个状态的评查点数量 + const successCount = reviewPoints.filter( + point => point.result === true || (point.result === undefined && point.status === 'success') + ).length; + + const warningCount = reviewPoints.filter( + point => point.result === false && point.status === 'warning' + ).length; + + const errorCount = reviewPoints.filter( + point => point.result === false && point.status === 'error' + ).length; + + // 如果没有计算值,则使用传入的统计值 + const totalToShow = statsToUse.total === 0 ? reviewPoints.length : statsToUse.total; + const successToShow = successCount || statsToUse.success; + const warningToShow = warningCount || statsToUse.warning; + const errorToShow = errorCount || statsToUse.error; + return (
+ {/* 总计数量 */}
- {statistics.total} + {totalToShow}
总计
+ {/* 通过数量 */}
通过
+ {/* 警告数量 */}
警告
+ {/* 错误数量 */}
错误
@@ -148,7 +255,10 @@ export function ReviewPointsList({ ); }; - // 渲染搜索框 + /** + * 渲染搜索框 + * 用于按文本搜索评查点 + */ const renderSearchBar = () => { return (
@@ -174,8 +284,40 @@ export function ReviewPointsList({ ); }; - // 渲染评查点状态标签 - const renderStatusBadge = (status: string) => { + /** + * 渲染评查点状态标签 + * @param status 状态文本 + * @param result 评查结果 + * @returns 状态标签组件 + */ + const renderStatusBadge = (status: string, result?: boolean) => { + // 优先根据result判断是否通过 + if (result === true) { + return ( + + 通过 + + ); + } + + // 当result为false时,根据status决定显示警告还是错误 + if (result === false) { + if (status === 'warning') { + return ( + + 警告 + + ); + } else if (status === 'error') { + return ( + + 不通过 + + ); + } + } + + // 兼容旧版逻辑,当没有result时,仍按status判断 switch (status) { case 'success': return ( @@ -210,7 +352,11 @@ export function ReviewPointsList({ } }; - // 渲染人工审核标记 + /** + * 渲染人工审核标记 + * @param reviewPoint 评查点 + * @returns 人工审核标记组件 + */ const renderHumanReviewBadge = (reviewPoint: ReviewPoint) => { if (reviewPoint.needsHumanReview) { return ( @@ -222,7 +368,11 @@ export function ReviewPointsList({ return null; }; - // 渲染人工审核注释 + /** + * 渲染人工审核注释 + * @param reviewPoint 评查点 + * @returns 人工审核注释组件 + */ const renderHumanReviewNote = (reviewPoint: ReviewPoint) => { if (reviewPoint.needsHumanReview && reviewPoint.humanReviewNote) { return ( @@ -239,11 +389,16 @@ export function ReviewPointsList({ return null; }; - // 渲染评查点内容与建议 + /** + * 渲染评查点内容与建议 + * @param reviewPoint 评查点 + * @returns 评查点内容组件 + */ const renderReviewPointContent = (reviewPoint: ReviewPoint) => { // 如果当前评查点不处于编辑状态,只显示简单信息 if (editingReviewPoint !== reviewPoint.id) { - if (reviewPoint.status === 'success') { + // 根据result和status决定渲染哪种样式 + if (reviewPoint.result === true || (reviewPoint.result === undefined && reviewPoint.status === 'success')) { // 已通过的评查点只显示基本信息和人工审核注释 if (reviewPoint.needsHumanReview && reviewPoint.humanReviewNote) { return ( @@ -262,39 +417,62 @@ export function ReviewPointsList({ return null; } + // 非通过状态,显示内容和修改建议 + const isErrorStatus = reviewPoint.result === false && reviewPoint.status === 'error'; + return (
-
-
- 当前值 - - {reviewPoint.status === 'error' ? '不符合规范' : '需优化'} - -
-

{reviewPoint.content || '(内容为空)'}

- - {reviewPoint.suggestion && ( -
+ {/* 内容显示区域 */} +
+ {/* 移除顶部的"当前值"标题,在每个内容项中显示 */} + {typeof reviewPoint.content === 'object' && reviewPoint.content !== null ? ( + // 当 content 是对象时的渲染方式 +
+ {Object.entries(reviewPoint.content).map(([key, value], index) => ( +
+ {/* 使用flex布局使key和状态标签左右对齐 */} +
+ {key} + + {isErrorStatus ? '不符合规范' : '需优化'} + +
+

{value || '(内容为空)'}

+
+ ))} +
+ ) : ( + // 当 content 是字符串时的渲染方式 + <> + {/* 为字符串内容也添加标题和状态 */}
- 建议修改为 - - 符合规范 + 当前值 + + {isErrorStatus ? '不符合规范' : '需优化'}
-