/** * 评查点列表组件 * * 功能概述: * - 展示评查结果统计信息(总计、通过、警告、错误数量) * - 提供评查点过滤功能(按状态和搜索文本) * - 显示评查点详细信息(标题、状态、内容、建议修改等) * - 支持评查点操作(一键替换、人工审核等) * * 组件结构: * - 统计区域: 显示评查点数量统计 * - 搜索区域: 提供文本搜索功能 * - 评查点列表: 展示所有评查点 * - 评查点卡片: 展示单个评查点详情 * - 评查点头部: 显示标题和状态 * - 评查点内容: 显示当前内容和问题 * - 建议修改区域: 显示建议的修改内容 * - 操作按钮: 提供一键替换和人工审核功能 */ import { useState, useEffect } from 'react'; import { toastService } from '../ui/Toast'; // import { toastService } from '../ui/Toast'; /** * 比较方法映射 * 将后端返回的比较方法英文值映射为友好的中文显示 */ const compareMethodMap: Record = { 'exact': '精确匹配', 'contains': '包含关系', 'semantic': '大模型语义匹配', // 可以根据需要添加更多映射 }; /** * 获取比较方法的中文显示 * @param method 比较方法的原始值 * @returns 映射后的中文显示文本 */ const getCompareMethodText = (method?: string): string => { if (!method) return '相等'; const text = compareMethodMap[method] || method; // 确保返回的是字符串类型 return typeof text === 'string' ? text : String(text); }; /** * 规则类型映射 * 将后端返回的规则类型英文值映射为友好的中文显示 */ const ruleTypeMap: Record = { 'exists': '有无判断', 'format': '格式判断', 'logic': '逻辑判断', 'regex': '正则表达式', // 可以根据需要添加更多映射 }; /** * 获取规则类型的中文显示 * @param type 规则类型的原始值 * @returns 映射后的中文显示文本 */ const getRuleTypeText = (type?: string): string => { if (!type) return ''; return ruleTypeMap[type] || type; }; /** * 评查点类型定义 * 用于展示单个评查结果 */ export interface ReviewPoint { id: string; documentId?: string; pointId?: string; editAuditStatusId?: string | number; editAuditStatus: number; pointName: string; title: string; groupName: string; status: string; content: Record; suggestion: string; needsHumanReview?: boolean; humanReviewNote?: string; humanReviewBy?: string; humanReviewTime?: string; contentPage?: Record; position?: { section: string; index: number; }; result?: boolean; legalBasis?: { name?: string; content?: string; articles?: Array; [key: string]: unknown; }; postAction?: string; actionContent?: string; evaluationConfig?: { rules?: Array<{ type: string; config?: { fields?: string[]; pairs?: Array<{ sourceField?: string; targetField?: string }>; logic?: string; }; }>; }; evaluatedPointResultsLog?: { rules: Array<{ id: string; type: string; config: Record; }>; }; } // 统计数据类型 interface Statistics { total: number; success: number; warning: number; error: number; score: number; } // 统一规则的类型 // interface pointRule { // id: string; // type: string; // config: Record; // } interface ReviewPointsListProps { reviewPoints: ReviewPoint[]; statistics: Statistics; activeReviewPointResultId: string | null; onReviewPointSelect: (id: string, page?: number) => void; onStatusChange: (id: string, editAuditStatusId: string | number, status: string, message: string) => void; } export function ReviewPointsList({ reviewPoints, statistics, activeReviewPointResultId, onReviewPointSelect, onStatusChange }: ReviewPointsListProps) { // 状态管理 const [editingReviewPoint, setEditingReviewPoint] = useState(null); // 当前正在编辑的评查点ID const [searchText, setSearchText] = useState(''); // 搜索文本 const [statusFilter, setStatusFilter] = useState(null); // 状态过滤 // const [suggestionTexts, setSuggestionTexts] = useState>({}); // 存储每个评查点的建议文本 // 添加重新审核意见的状态/ 用户输入的修改内容 / 用户提前写好的修改内容 const [manualReviewNotes, setManualReviewNotes] = useState>({}); // 存放属于有无判断,格式判断,逻辑判断,正则表达式这一类的评查点规则设置 // const [otherRule, setOtherRule] = useState[]>([]); // 初始化建议文本 useEffect(() => { // 将所有评查点的建议文本存储到状态中 const suggestions: Record = {}; reviewPoints.forEach(point => { suggestions[point.id] = point.suggestion || ''; }); // setSuggestionTexts(suggestions); // 使用函数式更新,不再需要外部 manualReviewNotes 变量 setManualReviewNotes(prev => { const notes = { ...prev }; reviewPoints.forEach(point => { notes[point.id] = point.actionContent || ''; }); return notes; }); }, [reviewPoints]); // 处理建议文本变更 // const handleSuggestionChange = (reviewPointId: string, text: string) => { // setSuggestionTexts(prev => ({ // ...prev, // [reviewPointId]: text // })); // }; /** * 处理评查点审核操作 * @param reviewPointResultId 评查点结果ID * @param editAuditStatusId 审核状态记录ID * @param action 操作类型: 'approve' 通过 / 'reject' 不通过 / 'review' 重新审核 * @param message 用户输入的审核内容 */ const handleReviewAction = (reviewPointResultId: string, editAuditStatusId: string | number | undefined, action: 'approve' | 'reject' | 'review', message: string) => { // 更新评查点状态 // console.log('handleReviewAction-------', reviewPointResultId, editAuditStatusId, action, message); if(message.trim() === ''){ toastService.error('请输入审核意见'); return; } if (action === 'review') { // 重新审核时,不更新结果状态,只更新审核意见和审核状态 // console.log('重新审核-------', reviewPointResultId, editAuditStatusId || '', 'review', message); onStatusChange(reviewPointResultId, editAuditStatusId || '', 'review', message); // 找到当前评查点并更新其editAuditStatus为0,使其立即显示通过/不通过按钮 const updatedReviewPoint = reviewPoints.find(point => point.id === reviewPointResultId); if (updatedReviewPoint) { updatedReviewPoint.editAuditStatus = 0; } } else { // 通过/不通过时,更新结果状态和审核意见 // console.log('通过/不通过-------', reviewPointResultId, editAuditStatusId || '', action === 'approve' ? 'true' : 'false', message); onStatusChange(reviewPointResultId, editAuditStatusId || '', action === 'approve' ? 'true' : 'false', message); } // 将参数输出到控制台 // console.log('评查点审核操作', { // id: reviewPointResultId, // editAuditStatusId: editAuditStatusId, // action: action, // content: message, // status: action === 'approve' ? 'true' : (action === 'reject' ? 'false' : 'review') // }); // 清除编辑状态 setEditingReviewPoint(null); }; /** * 过滤评查点 * 根据搜索文本和状态过滤条件筛选评查点 */ const filteredReviewPoints = reviewPoints.filter(point => { // 匹配搜索文本 const matchesSearch = searchText === '' || point.pointName.toLowerCase().includes(searchText.toLowerCase()) || point.title.toLowerCase().includes(searchText.toLowerCase()) || // point.groupName.toLowerCase().includes(searchText.toLowerCase()) || JSON.stringify(point.content).toLowerCase().includes(searchText.toLowerCase()) // 处理状态过滤 let matchesStatus = false; if (statusFilter === null) { // 未选择过滤条件时显示所有 matchesStatus = true; } else if (statusFilter === 'success') { // 过滤"通过"状态 matchesStatus = point.result === true; } else if (statusFilter === 'warning') { // 过滤"警告"状态 matchesStatus = point.result === false && (point.status === 'warning' || point.status === 'info'); } else if (statusFilter === 'error') { // 过滤"错误"状态 matchesStatus = point.result === false && point.status === 'error'; } // console.log('筛选point', point); return matchesSearch && matchesStatus; }); // console.log('筛选filteredReviewPoints', filteredReviewPoints); /** * 处理一键替换操作 * @param reviewPointId 评查点ID */ const handleReplace = (reviewPointId: string) => { // 在实际应用中,这里应该调用API进行内容替换 // 模拟替换操作 alert(`将为评查点 ${reviewPointId} 执行一键替换操作`); // 更新评查点状态为成功 // onStatusChange(reviewPointId, 'success'); }; /** * 渲染评查统计信息 * 显示总计、通过、警告、错误数量 */ 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' || point.status === 'info') ).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 (
{/* 总计数量 */}
{/* 通过数量 */}
{/* 警告数量 */}
{/* 错误数量 */}
); }; /** * 渲染搜索框 * 用于按文本搜索评查点 */ const renderSearchBar = () => { return (
setSearchText(e.target.value)} /> {searchText && ( )}
); }; /** * 渲染评查点状态标签 * @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 ( 通过 ); case 'warning': return ( 警告 ); case 'error': return ( 不通过 ); case 'processing': return ( 处理中 ); default: return ( 警告 ); } }; /** * 渲染人工审核标记 * @param reviewPoint 评查点 * @returns 人工审核标记组件 */ const renderHumanReviewBadge = (reviewPoint: ReviewPoint) => { if (reviewPoint.postAction === 'manual') { return ( 需人工 ); } return null; }; /** * 渲染人工审核注释 * @param reviewPoint 评查点 * @returns 人工审核注释组件 */ // const renderHumanReviewNote = (reviewPoint: ReviewPoint) => { // // 目前needsHumanReview和humanReviewNote都为空,所以不显示 // if (reviewPoint.needsHumanReview && reviewPoint.humanReviewNote) { // return ( //
// {reviewPoint.humanReviewNote} // {reviewPoint.humanReviewBy && reviewPoint.humanReviewTime && ( //
// 审核人:{reviewPoint.humanReviewBy} | 时间:{reviewPoint.humanReviewTime} //
// )} //
// ); // } // return null; // }; /** * 渲染评查点主要内容 * @param reviewPoint 评查点 * @returns 评查点主要内容组件 */ const renderContent = (reviewPoint: ReviewPoint, otherRules: Array>) => { return ( <> {/* 渲染其他规则分组 */} {otherRules.map((rule, index) => { return
{renderOtherRule(rule, reviewPoint)}
; })} {/*
*/} {/* 渲染各个一致性的规则分组 */} {reviewPoint.evaluatedPointResultsLog?.rules?.map((rule, index) => { // console.log('rule-------', rule); if (rule.type === 'consistency') { // console.log('rule-------', rule); return
{renderConsistencyRule(rule, reviewPoint)}
; } if (rule.type === 'ai') { return
{renderModelRule(rule, reviewPoint)}
; } // return ( // <> // {/* 渲染组内内容 */} // {entries.map(([key, value], index) => // !(result && value.value?.toString().trim() == '') && ( //
{ // e.stopPropagation(); // console.log(`单独点击${key}----`, reviewPoint); // const valuePage = parseInt(value.page as string); // const contentPage = parseInt(reviewPoint.contentPage?.[key] as string); // // 检查value中的page属性是否存在,优先取value中的page // if (valuePage > 0) { // console.log(`存在page且不为空:单独点击${key}---------->evaluated_results内的页码:`, valuePage); // onReviewPointSelect(reviewPoint.id, valuePage); // } else if(contentPage && contentPage > 0) { // console.log(`存在page且为空:单独点击${key}---------->ocr_result内的页码:`, contentPage); // onReviewPointSelect(reviewPoint.id, contentPage); // }else { // toastService.error(`无法找到"${key}"对应的索引内容`); // console.log(`单独点击${key}--------没有对应页码`); // } // }} // onKeyDown={(e) => { // if (e.key === 'Enter' || e.key === ' ') { // e.preventDefault(); // const valuePage = parseInt(value.page as string); // const contentPage = parseInt(reviewPoint.contentPage?.[key] as string); // // 检查value中的page属性是否存在,优先取value中的page // if (valuePage > 0) { // onReviewPointSelect(reviewPoint.id, valuePage); // } else if(contentPage && contentPage > 0) { // onReviewPointSelect(reviewPoint.id, contentPage); // } else { // toastService.error(`无法找到"${key}"对应的索引内容`); // console.log(`单独点击${key}--------没有对应页码`); // } // } // }} // role="button" // tabIndex={0} // aria-label={`查看${key}内容详情`} // onMouseLeave={(e) => { // // 获取容器内的滚动区域元素 // const scrollContainer = e.currentTarget.querySelector('.text-container'); // if (scrollContainer) { // // 在文本缩回之前重置滚动位置 // scrollContainer.scrollTop = 0; // } // }} // > // {/*
*/} //
// // {key} // // // {parseInt(value.page as string)>0 || parseInt(reviewPoint.contentPage?.[key] as string)>0 ? '' : } // {value.value?.toString().trim() ? '' : '缺失'} // //
//
//

// {(value.value?.toString().trim() === '') // ? "" // : value.value?.toString() || ''} //

//
//
// ))} // // ); })} ); }; /** * 渲染评查点一致性的规则的样式 * @param singleReviewPoint 评查点 * @returns 评查点一致性的规则的样式 */ const renderConsistencyRule = (singleReviewPoint: Record,reviewPoint: ReviewPoint) => { if (!singleReviewPoint || Object.keys(singleReviewPoint).length === 0) { return null; } // console.log('singleReviewPoint-------', singleReviewPoint); // 检查是否存在配置和pairs数组 const config = singleReviewPoint.config as { logic?: string; pairs?: Array<{ sourceField: Record; targetField: Record; res: boolean; compareMethod?: string; }>; selectedFields?: string[] } | undefined; if (!config || !config.pairs || !Array.isArray(config.pairs) || config.pairs.length === 0) { return null; } // 处理配对数据 const pairs = config.pairs; // 查找链条关系 const findChains = () => { type ChainItem = { field: string; data: { key: string; page: number; value: string }; res: boolean; compareMethod?: string; }; const chains: Array> = []; const visited = new Set(); // 构建字段映射关系 const fieldMap = new Map>(); pairs.forEach(pair => { // 提取源字段和目标字段的名称 const sourceFieldKey = Object.keys(pair.sourceField)[0]; const targetFieldKey = Object.keys(pair.targetField)[0]; if (!fieldMap.has(sourceFieldKey)) { fieldMap.set(sourceFieldKey, []); } fieldMap.get(sourceFieldKey)?.push({ targetField: targetFieldKey, data: { source: { key: sourceFieldKey, ...pair.sourceField[sourceFieldKey] }, target: { key: targetFieldKey, ...pair.targetField[targetFieldKey] } }, res: pair.res, compareMethod: pair.compareMethod }); }); // console.log('fieldMap-------', fieldMap); // 查找链条的起始点(只作为源不作为目标的字段) const startPoints = new Set(); for (const [key] of fieldMap.entries()) { let isTarget = false; for (const pair of pairs) { const targetFieldKey = Object.keys(pair.targetField)[0]; if (targetFieldKey === key) { isTarget = true; break; } } if (!isTarget) { startPoints.add(key); } } // console.log('startPoints-------', startPoints); // 从每个起始点开始构建链条 for (const startPoint of startPoints) { if (visited.has(startPoint)) continue; const tempChain: Array = []; let currentField = startPoint; // 向后构建链条 while (fieldMap.has(currentField)) { const targets = fieldMap.get(currentField); if (!targets || targets.length === 0) break; // 找到第一个未访问的目标 let nextTarget = null; for (const target of targets) { if (!visited.has(target.targetField)) { nextTarget = target; break; } } if (!nextTarget) break; // 添加源字段到链条 if (tempChain.length === 0) { tempChain.push({ field: currentField, data: nextTarget.data.source, res: nextTarget.res, compareMethod: nextTarget.compareMethod }); } // 添加目标字段到链条 tempChain.push({ field: nextTarget.targetField, data: nextTarget.data.target, res: nextTarget.res, compareMethod: nextTarget.compareMethod }); // 标记为已访问 visited.add(currentField); visited.add(nextTarget.targetField); // 移动到下一个字段 currentField = nextTarget.targetField; } // console.log('tempChain-------', tempChain); // 检查是否有链条,并处理链条断点 if (tempChain.length > 0) { // 如果链条长度大于1 if (tempChain.length > 1) { // 存储所有拆分后的链条 const splittedChains: Array> = []; // 从后往前遍历,检查每个相邻元素之间的连接 let endIndex = tempChain.length - 1; // 从倒数第一个元素开始往前遍历 for (let i = tempChain.length - 1; i > 0; i--) { // 检查当前元素与前一个元素的连接是否为false // 当前元素为tempChain[i],前一个元素为tempChain[i-1] // 连接结果存储在当前元素(tempChain[i])的result中 const connectionResult = tempChain[i].res; // 如果连接为false,或已到达起始位置,拆分链条 if (!connectionResult) { // 从当前断点到结束索引构建一个新链条 const newChain = tempChain.slice(i, endIndex + 1); if (newChain.length > 1) { splittedChains.push(newChain); // 将当前断点的前一个元素和后一个元素组成一个新链条 const newChain_before = tempChain.slice(i-1, i+1); // console.log('newChain_before-------', newChain_before); splittedChains.push(newChain_before); } // 更新结束索引为当前位置的前一个 endIndex = i - 1; } // 当到达第一个元素前一个位置时,需要处理剩余的链条 if (i === 1) { // 处理剩余部分 (0 到 endIndex) const remainingChain = tempChain.slice(0, endIndex + 1); if (remainingChain.length > 1) { splittedChains.push(remainingChain); } } } // 如果没有任何断点,添加整个链条 if (splittedChains.length === 0) { splittedChains.push([...tempChain]); } // 将拆分的链条添加到结果中 splittedChains.reverse().forEach(chain => { chains.push(chain); }); } else { // 如果链条长度为1,直接添加 chains.push([...tempChain]); } } } // console.log('chains-------', chains); // 处理没有找到的孤立对(这种情况只要规则配置是没问题的,就一定不会存在孤立的情况) for (const pair of pairs) { const sourceFieldKey = Object.keys(pair.sourceField)[0]; const targetFieldKey = Object.keys(pair.targetField)[0]; if (!visited.has(sourceFieldKey) || !visited.has(targetFieldKey)) { const isolatedPair: Array = [ { field: sourceFieldKey, data: { key: sourceFieldKey, ...pair.sourceField[sourceFieldKey] }, res: pair.res }, { field: targetFieldKey, data: { key: targetFieldKey, ...pair.targetField[targetFieldKey] }, res: pair.res } ]; chains.push(isolatedPair); visited.add(sourceFieldKey); visited.add(targetFieldKey); } } return chains; }; const chains = findChains(); return (
{chains.map((chain, chainIndex) => { const isLongChain = chain.length > 2; const res = chain[1].res; // 获取compareMethod // const compareMethod = chain[1].compareMethod || ''; // 转换为友好的显示文本 // const compareMethodText = getCompareMethodText(compareMethod); // 确定样式类名 const itemClassName = res ? "comparison-item match" : "comparison-item mismatch"; // console.log('currentchain-------', chain); // 如果是长链(3个或以上元素) if (isLongChain) { // console.log('currentlongchain-------', chain); return (
{ e.stopPropagation(); // 遍历chain找到第一个有效的page let hasPage = false; for (const item of chain) { if (item.data.page && typeof onReviewPointSelect === 'function') { hasPage = true; onReviewPointSelect(reviewPoint.id, Number(item.data.page)); break; } } if (!hasPage) { toastService.error('没有找到有效的页码'); } }} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); // 遍历chain找到第一个有效的page for (const item of chain) { if (item.data.page && typeof onReviewPointSelect === 'function') { onReviewPointSelect(reviewPoint.id, Number(item.data.page)); break; } } } }} role="button" tabIndex={0} >
{chain.map((item, idx) => ( {item.field} {idx < chain.length - 1 && ( {typeof chain[idx+1].compareMethod === 'object' ? '' : getCompareMethodText(chain[idx+1].compareMethod)} )} ))}
{chain.map((item, idx) => ( ))}
{res ? ( ) : ( )} {/* 悬停提示框 - 横向布局 */}
{/*
规则检查结果
*/}
{chain.map((item, idx) => idx >= 1 ? (
{typeof item.compareMethod === 'object' ? '' : getCompareMethodText(item.compareMethod)}
{res ? '通过' : '不通过'}
) : null )}
); } // 如果是标准的成对比较(2个元素) return (
{chain[0].field.split('-').pop()}
{res ? ( ) : ( )} {/* 悬停提示框 - 横向布局 */}
{typeof chain[1].compareMethod === 'object' ? '' : getCompareMethodText(chain[1].compareMethod)}
{res ? '通过' : '不通过'}
); })}
); }; /** * 渲染评查点有无判断,格式判断,逻辑判断,正则表达式的规则的样式 * @param otherRule 评查点规则数据 * @param reviewPoint 关联的评查点 * @returns 评查点有无判断,格式判断,逻辑判断,正则表达式的规则的样式 */ const renderOtherRule = (otherRule: Record, reviewPoint: ReviewPoint) => { const fieldKey = otherRule.fieldKey as string; const fieldValue = otherRule.fieldValue as { type: Record; }; // 获取res的综合结果 // 如果存在res=false,则整体结果为false,否则为true const hasFailure = Object.values(fieldValue?.type || {}).some(item => item.res === false); const overallResult = !hasFailure; // 找到res为false的条目,用于主要显示 const failedTypeEntry = Object.entries(fieldValue?.type || {}).find(([, item]) => item.res === false); // 如果没有失败的条目,则使用第一个条目 const mainTypeEntry = failedTypeEntry || Object.entries(fieldValue?.type || {})[0]; // 如果没有任何条目,则返回空 if (!mainTypeEntry) return null; const [, mainTypeValue] = mainTypeEntry; return ( ))}
)} */} {/* 主要值显示 */} {mainTypeValue.value && ( )}
{overallResult ? ( ) : ( )} {/* 悬停提示框 - 横向布局 */}
{/*
规则检查结果
*/}
{Object.entries(fieldValue?.type || {}).map(([typeKey, typeValue]) => (
{getRuleTypeText(typeKey)}
{typeValue.res ? '通过' : '不通过'}
))}
); }; /** * 渲染评查点大模型判断的规则的样式 * @param aiRule 评查点大模型判断的规则 * @param reviewPoint 关联的评查点 * @returns 评查点大模型判断的规则的样式 */ const renderModelRule = (aiRule: Record, reviewPoint: ReviewPoint) => { // console.log('aiRule-------', aiRule); const config = aiRule.config as { model?: string; fields?: Record; message?: string; res?: boolean; } | undefined; if (!config) return null; // 创建一个数组来存储需要渲染的JSX元素 const fieldElements: JSX.Element[] = []; // 先存放一条粗的横线 // fieldElements.push( //
// ); // 遍历fields,获取每个字段的值并生成对应的JSX元素 if (config.fields) { Object.entries(config.fields).forEach(([key, value], index) => { const res = value.value.trim() !== ''; fieldElements.push( )}
{res ? ( ) : ( )} {/* 悬停提示框 - 横向布局 */}
{/*
规则检查结果
*/}
大模型判断
{res ? '通过' : '不通过'}
); }); } // 后处理message if (config.message) { // 检查message是否为对象,如果是则转换为字符串 const messageContent = typeof config.message === 'object' ? JSON.stringify(config.message) : String(config.message); fieldElements.push(

{messageContent}

); } // 返回包含所有元素的React片段 return <>{fieldElements}; }; /** * 过滤评查点中的规则,把type是exist、format、logic、regex的规则中重复的进行去重 * @param reviewPoint 评查点 * @returns 合并后的规则数组 */ const filterOtherRule = (reviewPoint: ReviewPoint) => { // 遍历这些评查点中的规则evaluatedPointResultsLog,把type是exist、format、logic、regex的规则添加到allRule中 interface RuleFieldValue { page?: number | string; value?: string; type: Record; } const allRule: Array<{ fieldKey: string; fieldValue: RuleFieldValue; }> = []; for (const rule of reviewPoint.evaluatedPointResultsLog?.rules || []) { if (rule.type === 'exists') { // 使用类型断言获取config对象的具体结构 const config = rule.config as { res: boolean; fields: Record; logic?: string; }; // 如果res为true,则遍历fields,提取不为空的字段 if (config.res) { // 遍历fields对象的每个属性 Object.entries(config.fields).forEach(([key, fieldValue]) => { // 只处理值不为空的字段 if (fieldValue.value && fieldValue.value.trim() !== '') { // 创建新对象并添加type标记 const newItem = { fieldKey: key, fieldValue: { ...fieldValue, type: { exists: true } } }; allRule.push(newItem); } }); } else { // 如果res为false,则遍历fields,提取所有字段 Object.entries(config.fields).forEach(([key, fieldValue]) => { // 根据值是否为空添加不同的type标记 const isValueEmpty = !fieldValue.value || fieldValue.value.trim() === ''; // 创建新对象并添加type标记 const newItem = { fieldKey: key, fieldValue: { ...fieldValue, type: { exists: isValueEmpty ? false : true } } }; allRule.push(newItem); }); } } if (rule.type === 'format') { // 使用类型断言获取config对象的具体结构 const config = rule.config as { res: boolean; field: Record; formatType?: string; parameters?: string; }; // 从config中获取field对象 // 注意:根据示例,format类型中是field而不是fields if (config.field) { // 获取field中唯一的键值对 const entries = Object.entries(config.field); if (entries.length > 0) { const [key, fieldValue] = entries[0]; // 创建新对象并添加type标记 const newItem = { fieldKey: key, fieldValue: { ...fieldValue, type: { format: config.res } } }; allRule.push(newItem); } } } if (rule.type === 'logic') { // 使用类型断言获取config对象的具体结构 const config = rule.config as { logic: string; conditions: Array<{ field: Record; value: string; operator: string; res: boolean; }>; }; // 遍历conditions数组 if (config.conditions && Array.isArray(config.conditions)) { config.conditions.forEach(condition => { // 从condition中获取field对象 const entries = Object.entries(condition.field); if (entries.length > 0) { const [key, fieldValue] = entries[0]; // 创建新对象并添加type标记 const newItem = { fieldKey: key, fieldValue: { ...fieldValue, type: { logic: condition.res } } }; allRule.push(newItem); } }); } } if (rule.type === 'regex') { // 使用类型断言获取config对象的具体结构 const config = rule.config as { res: boolean; field: Record; pattern?: string; matchType?: string; selectedFields?: string[]; }; if (config.field) { const entries = Object.entries(config.field); if (entries.length > 0) { const [key, fieldValue] = entries[0]; // 创建新对象并添加type标记 const newItem = { fieldKey: key, fieldValue: { ...fieldValue, type: { regex: config.res } } }; allRule.push(newItem); } } } } // console.log('allRule-------', allRule); // 对allRule进行去重和合并 const mergedRules: Array<{ fieldKey: string; fieldValue: { type: Record; }; }> = []; // 使用对象存储相同fieldKey的项 const fieldKeyMap: Record; }; }> = {}; // 第一步:按fieldKey分组 allRule.forEach(item => { const fieldKey = item.fieldKey; const fieldValue = item.fieldValue; const typeKey = Object.keys(fieldValue.type)[0]; // 获取类型名称(exists/logic/regex/format) const typeValue = fieldValue.type[typeKey]; // 获取类型值(true/false) // 提取页码和值 const page = fieldValue.page; const value = fieldValue.value; // 如果是第一次遇到这个fieldKey if (!fieldKeyMap[fieldKey]) { // 创建新的结构 fieldKeyMap[fieldKey] = { fieldKey, fieldValue: { type: {} } }; } // 将类型信息添加到type对象中 fieldKeyMap[fieldKey].fieldValue.type[typeKey] = { res: typeValue, page, value }; }); // 将合并后的对象转换为数组 for (const key in fieldKeyMap) { mergedRules.push(fieldKeyMap[key]); } // console.log('合并后的规则:', mergedRules); // setOtherRule(mergedRules); return mergedRules; }; /** * 渲染评查点内容与建议 * @param reviewPoint 评查点 * @returns 评查点内容与建议组件 */ const renderReviewPointContent = (reviewPoint: ReviewPoint) => { const mergedRules = filterOtherRule(reviewPoint); // console.log('mergedRules1-------', mergedRules); const handleManualReviewNotesChange = (reviewPointId: string, text: string) => { setManualReviewNotes(prev => ({ ...prev, [reviewPointId]: text })); }; // 如果当前评查点不处于编辑状态 TODO delete if (editingReviewPoint !== reviewPoint.id) { // 根据result和status决定渲染哪种样式 if (reviewPoint.result === true) { // 已通过的评查点只显示基本信息和人工审核注释 // 处理 result=true 且 postAction=manual 的情况 if (reviewPoint.postAction === 'manual') { const note = manualReviewNotes[reviewPoint.id] || ''; // 处理重新审核意见的输入 const handleNoteChange = (reviewPointId: string, text: string) => { setManualReviewNotes(prev => ({ ...prev, [reviewPointId]: text })); }; return ( <> {checkContentPage(reviewPoint).pageIndex === 0 && (

该评查点无法找到索引内容,无法自动定位到对应页面。

)}
{/* {reviewPoint.suggestion && (

{reviewPoint.suggestion}

)} */} {/* 评查点内容显示区域 */} {reviewPoint.content && Object.entries(reviewPoint.content).length > 0 && (
{/* 修改评查结果的结构之后,显示新的结构 */} {renderContent(reviewPoint, mergedRules)}
)} {/* 额外的文本输入框区域 */}
{reviewPoint.editAuditStatus === 0 ? (
) : ( )}
); } // 处理 result=true 且 postAction!=manual 的情况 return ( <> {checkContentPage(reviewPoint).pageIndex === 0 && (

该评查点无法找到索引内容,无法自动定位到对应页面。

)} {/* 评查点内容显示区域 */} {reviewPoint.content && Object.entries(reviewPoint.content).length > 0 && (
{/* 修改评查结果的结构之后,显示新的结构 */} {renderContent(reviewPoint, mergedRules)}
)} ); } return (
{/* 没有索引内容提示 */} {checkContentPage(reviewPoint).pageIndex === 0 && (

该评查点无法找到索引内容,无法自动定位到对应页面。

)} {/* 建议内容显示区域 */} {reviewPoint.suggestion && (

{reviewPoint.suggestion}

)} {/* 法律依据内容 */} {reviewPoint.legalBasis && (typeof reviewPoint.legalBasis === 'object') && ( (reviewPoint.legalBasis.name || reviewPoint.legalBasis.content || (reviewPoint.legalBasis.articles && Array.isArray(reviewPoint.legalBasis.articles) && reviewPoint.legalBasis.articles.length > 0)) && (
法律依据
{reviewPoint.legalBasis.name && (

{reviewPoint.legalBasis.name}

)} {reviewPoint.legalBasis.content && (

条款内容:{reviewPoint.legalBasis.content}

)} {reviewPoint.legalBasis.articles && Array.isArray(reviewPoint.legalBasis.articles) && reviewPoint.legalBasis.articles.length > 0 && (

相关条款:

    {reviewPoint.legalBasis.articles.map((item, index) => (
  • {typeof item === 'string' ? item : typeof item === 'object' && item !== null ? (item.name ? `${item.name}: ${item.content || ''}` : item.content || JSON.stringify(item)) : String(item)}
  • ))}
)}
) )} {reviewPoint.content !== null && Object.keys(reviewPoint.content).length > 0 && ( <> {/* 内容显示区域 */}
{/* 修改评查结果的结构之后,显示新的结构 */} {renderContent(reviewPoint, mergedRules)}
)} {/* 建议修改区域 */} {/* {((reviewPoint.postAction === 'manual') || (reviewPoint.content !== null && Object.keys(reviewPoint.content).length > 0)) && ( */} {(reviewPoint.postAction === 'manual') && (
{reviewPoint.postAction === 'manual' ? "审核意见:" : "建议修改为:"} {/* 符合规范 */}