diff --git a/app/api/evaluation_points/reviews.ts b/app/api/evaluation_points/reviews.ts index 4ce2043..32749a4 100644 --- a/app/api/evaluation_points/reviews.ts +++ b/app/api/evaluation_points/reviews.ts @@ -33,6 +33,10 @@ interface EvaluationResult { data?: string; [key: string]: unknown; }; + evaluated_point_results_log?: { + rules?: unknown[]; + [key: string]: unknown; + }; [key: string]: unknown; } @@ -73,6 +77,8 @@ interface ReviewPointResult { suggestion: string; result?: boolean; score: number; + // evaluatedPointResultsLog: Record>>; + evaluatedPointResultsLog: Record; } // 定义统计数据类型 @@ -241,6 +247,11 @@ export async function getReviewPoints(fileId: string) { const point = pointsMap.get(result.evaluation_point_id) || {} as EvaluationPoint; const group = groupsMap.get(point.evaluation_point_groups_id || 0) || {} as EvaluationPointGroup; const editAuditStatus = editAuditStatusMap.get(result.evaluation_point_id) || {id: '', status: 0}; + + // 评查结果内容改成由evaluated_point_results_log中获取 + const evaluatedPointResultsLog = result.evaluated_point_results_log || {}; + // console.log('evaluatedPointResultsLog-------', evaluatedPointResultsLog); + // 从 evaluated_results 中提取数据 let message = ''; @@ -287,48 +298,254 @@ export async function getReviewPoints(fileId: string) { } return { - id: result.id, - documentId: fileId, - pointId: point.id, - editAuditStatusId: editAuditStatus.id, - editAuditStatus: editAuditStatus.status, - title: message, - pointName: point.name || '', - groupName: group.name || '', + id: result.id, + documentId: fileId, + pointId: point.id, + editAuditStatusId: editAuditStatus.id, + editAuditStatus: editAuditStatus.status, + title: message, + pointName: point.name || '', + groupName: group.name || '', - status: point.suggestion_message_type || '', //评查点的评查结果状态 - // status: 'error', //评查点的评查结果状态 + status: point.suggestion_message_type || '', //评查点的评查结果状态 + // status: 'error', //评查点的评查结果状态 - content: data, + content: data, - contentPage: contentPage, + contentPage: contentPage, - suggestion: point.suggestion_message || '', - // suggestion: '只是给建议的修改内容', + suggestion: point.suggestion_message || '', + // suggestion: '只是给建议的修改内容', - result: result.evaluated_results?.result, // 记录评查结果,用于统计 - score: point.score || 0, + result: result.evaluated_results?.result, // 记录评查结果,用于统计 + score: point.score || 0, - postAction: point.post_action || '', - // postAction: 'manual', + postAction: point.post_action || '', + // postAction: 'manual', - actionContent: point.action_config || '', - // actionContent: '用户提前在评查点输入过的修改内容', + actionContent: point.action_config || '', + // actionContent: '用户提前在评查点输入过的修改内容', - legalBasis: point.references_laws || {}, - // legalBasis: { - // name: '中华人民共和国食品安全法', - // content: '中华人民共和国食品安全法', - // article: [ - // { - // name: '中华人民共和国食品安全法', - // content: '中华人民共和国食品安全法' - // } - // ] - // } + legalBasis: point.references_laws || {}, + // legalBasis: { + // name: '中华人民共和国食品安全法', + // content: '中华人民共和国食品安全法', + // article: [ + // { + // name: '中华人民共和国食品安全法', + // content: '中华人民共和国食品安全法' + // } + // ] + // } - // 评查配置: point.evaluation_config - evaluationConfig: point.evaluation_config || {} + // 评查配置: point.evaluation_config + evaluationConfig: point.evaluation_config || {}, + + evaluatedPointResultsLog: evaluatedPointResultsLog || {} + // evaluatedPointResultsLog: { + // rules:[ + // { + // "id": "1", + // "type": "consistency", + // "config": { + // "logic": "and", + // "pairs": [ + // { + // "sourceField": {"a":{page: 1,value: '张三拉萨看得见佛i啊是觉得离开房间啊善良的是的链接发了上帝就发垃圾袋的时间佛爱上立刻就阿拉山口大家分厘卡即使灯笼裤飞机啊顺利打开解放拉萨酱豆腐立刻阿萨到了经历多空双方叫阿里的肌肤垃圾收到了看见螺丝钉解放了啊撒旦解放垃圾的等级分类教师劳动纠纷爱丽丝的开发教师的肌肤啊撒旦解放考虑进来阿斯兰的看法骄傲'}}, + // "targetField": {"b":{page: 1,value: '张三'}}, + // "compareMethod": "exact", + // "res": true + // }, + // { + // "sourceField": {"b":{page: 1,value: '张三'}}, + // "targetField": {"c":{page: 1,value: '张三拉萨看得见佛i啊是觉得离开房间啊善良的是的链接发了上帝就发垃圾袋的时间佛爱上立刻就阿拉山口大家分厘卡即使灯笼裤飞机啊顺利打开解放拉萨酱豆腐立刻阿萨到了经历多空双方叫阿里的肌肤垃圾收到了看见螺丝钉解放了啊撒旦解放垃圾的等级分类教师劳动纠纷爱丽丝的开发教师的肌肤啊撒旦解放考虑进来阿斯兰的看法骄傲'}}, + // "compareMethod": "exact", + // "res": false + // }, + // { + // "sourceField": {"c":{page: 1,value: '张三'}}, + // "targetField": {"d":{page: 1,value: '张三'}}, + // "compareMethod": "contains", + // "res": true + // }, + // { + // "sourceField": {"d":{page: 1,value: '张三'}}, + // "targetField": {"e":{page: 1,value: '张三'}}, + // "compareMethod": "exact", + // "res": true + // }, + // { + // "sourceField": {"现场笔录-被检查人名称":{page: 1,value: '张三'}}, + // "targetField": {"证据复制(提取)单-营业执照-名称":{page: 1,value: '张三'}}, + // "compareMethod": "exact", + // "res": true + // }, + // { + // "sourceField": {"证据复制(提取)单-营业执照-名称":{page: 1,value: '张三'}}, + // "targetField": {"证据复制(提取)单-营业执照-目录-名称":{page: 1,value: '张三'}}, + // "compareMethod": "exact", + // "res": true + // }, + // { + // "sourceField": {"现场笔录-法定代表人(负责人)":{page: 1,value: '张三'}}, + // "targetField": {"证据复制(提取)单-营业执照-法定代表人":{page: 1,value: '张三'}}, + // "compareMethod": "exact", + // "res": true + // }, + // { + // "sourceField": {"现场笔录-烟草专卖许可证号码":{page: 1,value: '张三'}}, + // "targetField": {"证据复制(提取)单-烟草专卖零售许可证-许可证号":{page: 1,value: '张三'}}, + // "compareMethod": "exact", + // "res": true + // }, + // { + // "sourceField": {"证据复制(提取)单-烟草专卖零售许可证-企业名称":{page: 1,value: '张三'}}, + // "targetField": {"证据复制(提取)单-营业执照-名称":{page: 1,value: '张三拉萨看得见佛i啊是觉得离开房间啊善良的是的链接发了上帝就发垃圾袋的时间佛爱上立刻就阿拉山口大家分厘卡即使灯笼裤飞机啊顺利打开解放拉萨酱豆腐立刻阿萨到了经历多空双方叫阿里的肌肤垃圾收到了看见螺丝钉解放了啊撒旦解放垃圾的等级分类教师劳动纠纷爱丽丝的开发教师的肌肤啊撒旦解放考虑进来阿斯兰的看法骄傲'}}, + // "compareMethod": "exact", + // "res": false + // }, + // { + // "sourceField": {"证据复制(提取)单-烟草专卖零售许可证-负责人姓名":{page: 1,value: '张三'}}, + // "targetField": {"证据复制(提取)单-营业执照-法定代表人":{page: 1,value: '张三'}}, + // "compareMethod": "exact", + // "res": true + // }, + // { + // "sourceField": {"立案报告表-当事人-单位-名称":{page: 1,value: '张三'}}, + // "targetField": {"证据复制(提取)单-营业执照-名称":{page: 1,value: '张三'}}, + // "compareMethod": "exact", + // "res": true + // }, + // { + // "sourceField": {"立案报告表-当事人-单位-法定代表人(负责人)":{page: 1,value: '张三拉萨看得见佛i啊是觉得离开房间啊善良的是的链接发了上帝就发垃圾袋的时间佛爱上立刻就阿拉山口大家分厘卡即使灯笼裤飞机啊顺利打开解放拉萨酱豆腐立刻阿萨到了经历多空双方叫阿里的肌肤垃圾收到了看见螺丝钉解放了啊撒旦解放垃圾的等级分类教师劳动纠纷爱丽丝的开发教师的肌肤啊撒旦解放考虑进来阿斯兰的看法骄傲'}}, + // "targetField": {"证据复制(提取)单-营业执照-法定代表人":{page: 1,value: '张三'}}, + // "compareMethod": "exact", + // "res": true + // }, + // { + // "sourceField": {"立案报告表-当事人-单位-地址":{page: 1,value: '张三'}}, + // "targetField": {"证据复制(提取)单-营业执照-住所":{page: 1,value: '张三'}}, + // "compareMethod": "exact", + // "res": true + // } + // ], + // "selectedFields": [] + // } + // }, + // { + // "id": "2", + // "type": "exists", + // "config": { + // "logic": "all", + // "res": true, + // "fields": { + // "证据先行登记保存批准书-负责人意见并签名-时间": {page: 1,value: ''}, + // "证据先行登记保存批准书-负责人意见并签名-签名": {page: 2,value: '有无判断类型'} + // }, + // } + // }, + // { + // "id": "3", + // "type": "exists", + // "config": { + // "logic": "all", + // "res": false, + // "fields": { + // "证据先行登记-负责人意见并签名-时间": {page: 1,value: ''}, + // "证据先行登记-负责人意见并签名-签名": {page: 2,value: '有无判断类型'} + // }, + // } + // }, + // { + // "id": "4", + // "type": "logic", + // "config": { + // "logic": "all", + // "conditions": [ + // { + // "field": { + // "送达回证-送达方式": { + // "page": 5, + // "value": "逻辑判断" + // } + // }, + // "value": "直接送达", + // "operator": "eq", + // "res": true + // }, + // { + // "field": { + // "犯罪证据-犯罪方式": { + // "page": 6, + // "value": "逻辑判断" + // } + // }, + // "value": "直接送达", + // "operator": "eq", + // "res": false + // } + // ], + // "selectedFields": [] + // } + // }, + // { + // "id": "5", + // "type": "regex", + // "config": { + // "res": true, + // "field": { + // "广东省没收、收缴、追缴财务收据-标题":{ + // page: 1,value: 'asdasdasd' + // } + // }, + // "pattern": "^(.*广东省没收.*财务收据.*)", + // "matchType": "match", + // "selectedFields": [] + // } + // }, + // { + // "id": "6", + // "type": "format", + // "config": { + // "field": { + // "广东省没收、收缴、追缴财务收据-标题": { + // "value": "", + // "page": 8 + // } + // }, + // "formatType": "date", + // "parameters": "YYYY-MM-DD", + // "selectedFields": [], + // "res": false + // } + // }, + // { + // "id": "7", + // "type": "ai", + // "config": { + // "res": false, + // "model": "qwen14b", + // "fields": { + // "涉案物件核价表-涉案物品价格-品种规格、单价": { + // "page": 1, + // "value": "规则和单价你都无法想象" + // }, + // "涉案物件核价表-涉案物品种": { + // "page": 1, + // "value": "什么都有" + // }, + // "涉案物件核价表-涉案": { + // "page": 19, + // "value": "" + // } + // }, + // "prompt": "请判断以下{涉案物件核价表-涉案物品价格-品种规格、单价}各品种规格的数量、单价计算的合计金额是否正确,各品种规格合计金额计算总计金额是否正确,仅回答\"符合\"或\"不符合\",并简要说明理由。", + // "message": "缺少字段: 涉案物件核价表-涉案物品价格-品种规格、单价", + // "temperature": 0.1, + // "selectedFields": [] + // } + // } + // ]} }; }); diff --git a/app/components/reviews/ReviewPointsList.tsx b/app/components/reviews/ReviewPointsList.tsx index 2787342..f8b684c 100644 --- a/app/components/reviews/ReviewPointsList.tsx +++ b/app/components/reviews/ReviewPointsList.tsx @@ -21,6 +21,51 @@ 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; +}; + /** * 评查点类型定义 * 用于展示单个评查结果 @@ -65,6 +110,13 @@ export interface ReviewPoint { }; }>; }; + evaluatedPointResultsLog?: { + rules: Array<{ + id: string; + type: string; + config: Record; + }>; + }; } // 统计数据类型 @@ -76,6 +128,13 @@ interface Statistics { score: number; } +// 统一规则的类型 +// interface pointRule { +// id: string; +// type: string; +// config: Record; +// } + interface ReviewPointsListProps { reviewPoints: ReviewPoint[]; statistics: Statistics; @@ -101,6 +160,9 @@ export function ReviewPointsList({ // 添加重新审核意见的状态/ 用户输入的修改内容 / 用户提前写好的修改内容 const [manualReviewNotes, setManualReviewNotes] = useState>({}); + // 存放属于有无判断,格式判断,逻辑判断,正则表达式这一类的评查点规则设置 + // const [otherRule, setOtherRule] = useState[]>([]); + // 初始化建议文本 useEffect(() => { // 将所有评查点的建议文本存储到状态中 @@ -160,13 +222,13 @@ export function ReviewPointsList({ } // 将参数输出到控制台 - console.log('评查点审核操作', { - id: reviewPointResultId, - editAuditStatusId: editAuditStatusId, - action: action, - content: message, - status: action === 'approve' ? 'true' : (action === 'reject' ? 'false' : 'review') - }); + // console.log('评查点审核操作', { + // id: reviewPointResultId, + // editAuditStatusId: editAuditStatusId, + // action: action, + // content: message, + // status: action === 'approve' ? 'true' : (action === 'reject' ? 'false' : 'review') + // }); // 清除编辑状态 setEditingReviewPoint(null); @@ -200,11 +262,11 @@ export function ReviewPointsList({ // 过滤"错误"状态 matchesStatus = point.result === false && point.status === 'error'; } - console.log('筛选point', point); + // console.log('筛选point', point); return matchesSearch && matchesStatus; }); - console.log('筛选filteredReviewPoints', filteredReviewPoints); + // console.log('筛选filteredReviewPoints', filteredReviewPoints); /** * 处理一键替换操作 @@ -420,7 +482,7 @@ export function ReviewPointsList({ const renderHumanReviewBadge = (reviewPoint: ReviewPoint) => { if (reviewPoint.postAction === 'manual') { return ( - + 需人工 ); @@ -433,323 +495,1140 @@ export function ReviewPointsList({ * @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; - }; + // 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, result?: boolean) => { - // 获取evaluationConfig中type为consistency的规则 评查点一致性规则组的规则 - const consistencyRules = reviewPoint.evaluationConfig?.rules?.filter(rule => rule.type === 'consistency') || []; - - // 获取所有consistency规则中的fields - const allConsistencyFields: string[][] = []; - - // 存储 sourceField 和 targetField 的映射关系 - const pairsMapping: Record = {}; - - consistencyRules.forEach(rule => { - if (rule.config?.fields) { - allConsistencyFields.push(rule.config.fields); - } else if (rule.config?.pairs) { - // 处理pairs情况,提取sourceField和targetField - const fields: string[] = []; - rule.config.pairs.forEach(pair => { - if (pair.sourceField) fields.push(pair.sourceField); - if (pair.targetField) fields.push(pair.targetField); - - // 记录 sourceField 和 targetField 的映射关系 - if (pair.sourceField && pair.targetField) { - pairsMapping[pair.sourceField] = pair.targetField; - } - }); - if (fields.length > 0) { - allConsistencyFields.push(fields); - } - } - }); - - // 对content进行排序 - const contentEntries = Object.entries(reviewPoint.content); - - // 按照consistency规则分组 - const groupedContent: Record> = { - 'default': [] // 默认组,存放不属于任何consistency规则的项 - }; - - // 为每个consistency规则创建分组 - allConsistencyFields.forEach((fields, index) => { - groupedContent[`consistency_${index}`] = []; - }); - - // 将content按照规则分组 - contentEntries.forEach(entry => { - const [key, value] = entry; - - // 检查是否属于某个consistency规则 - let assigned = false; - allConsistencyFields.forEach((fields, index) => { - if (fields.includes(key)) { - groupedContent[`consistency_${index}`].push(entry); - assigned = true; - } - }); - - // 如果不属于任何规则,放入默认组 - if (!assigned) { - groupedContent['default'].push(entry); - } - }); - - // 对每个分组内的条目按照 sourceField 和 targetField 的关系进行排序 - Object.keys(groupedContent).forEach(groupKey => { - if (groupKey !== 'default' && groupedContent[groupKey].length > 1) { - // 创建一个新数组用于存储排序后的结果 - const sortedEntries: Array<[string, { page?: number | string, value?: object }]> = []; - const entriesMap = new Map(groupedContent[groupKey]); - - // 找出所有的源字段和目标字段对 - const processed = new Set(); - - // 构建一个字段之间的连接关系图,用于处理嵌套关系 - const fieldChains: Array = []; - - // 遍历所有映射关系,构建字段链 - const buildFieldChains = () => { - // 创建一个图结构,记录每个字段的后继字段 - const graph: Record = {}; - - // 根据映射关系建立图 - Object.entries(pairsMapping).forEach(([source, target]) => { - if (!graph[source]) graph[source] = []; - graph[source].push(target); - - // 确保目标字段在图中有一个空数组 - if (!graph[target]) graph[target] = []; - }); - - // 查找所有在当前分组中的字段 - const fieldsInGroup = new Set(Array.from(entriesMap.keys())); - - // 找出入度为0的节点(即只作为sourceField而不是任何targetField的字段) - const startNodes: string[] = []; - for (const field of fieldsInGroup) { - // 检查该字段是否作为targetField存在 - const isTarget = Object.values(pairsMapping).includes(field); - // 如果该字段是sourceField但不是targetField,则为起始节点 - if (!isTarget && field in pairsMapping) { - startNodes.push(field); - } - } - - // 从每个起始节点开始,使用DFS构建字段链 - for (const startNode of startNodes) { - const chain: string[] = []; - const dfs = (node: string) => { - // 如果该节点不在当前分组中,则跳过 - if (!fieldsInGroup.has(node)) return; - - chain.push(node); - // 遍历所有后继节点 - for (const nextNode of graph[node] || []) { - dfs(nextNode); - } - }; - - dfs(startNode); - - // 如果链不为空,则添加到字段链列表中 - if (chain.length > 0) { - fieldChains.push(chain); - } - } - - // 处理环形依赖或没有入度为0的节点的情况 - // 找出未被处理的字段 - const processedInChains = new Set(fieldChains.flat()); - const remainingFields = Array.from(fieldsInGroup).filter(f => !processedInChains.has(f)); - - // 将剩余字段按照pairsMapping的关系组织成链 - while (remainingFields.length > 0) { - // !的作用是确保remainingFields.shift()不会返回undefined - const field = remainingFields.shift()!; - - // 如果该字段已经在某个链中,则跳过 - if (processedInChains.has(field)) continue; - - const chain: string[] = [field]; - processedInChains.add(field); - - // 向后查找链 - let currentField = field; - while (currentField in pairsMapping) { - const nextField = pairsMapping[currentField]; - // 如果下一个字段不在分组中或已处理,则中断 - if (!fieldsInGroup.has(nextField) || processedInChains.has(nextField)) break; - - chain.push(nextField); - processedInChains.add(nextField); - currentField = nextField; - - // 从剩余字段中移除 - const index = remainingFields.indexOf(nextField); - if (index !== -1) { - remainingFields.splice(index, 1); - } - } - - if (chain.length > 0) { - fieldChains.push(chain); - } - } - }; - - buildFieldChains(); - - // 根据字段链构建排序后的结果 - fieldChains.forEach(chain => { - chain.forEach(field => { - if (entriesMap.has(field) && !processed.has(field)) { - sortedEntries.push([field, entriesMap.get(field)!]); - processed.add(field); - } - }); - }); - - // 添加剩余未处理的字段 - for (const [key] of groupedContent[groupKey]) { - if (!processed.has(key)) { - sortedEntries.push([key, entriesMap.get(key)!]); - } - } - - // 用排序后的结果替换原数组 - groupedContent[groupKey] = sortedEntries; - } - }); - + const renderContent = (reviewPoint: ReviewPoint, otherRules: Array>) => { return ( <> - {/* 渲染各个分组 */} - {Object.entries(groupedContent).map(([groupKey, entries]) => { - if (entries.length === 0) return null; + {/* 渲染其他规则分组 */} + {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)} +
; + } - // 非默认组添加边框 - const isDefaultGroup = groupKey === 'default'; - return ( -
- {/* 分组标题,只有非默认组显示 */} - {/* {!isDefaultGroup && ( -
- 规则组 {groupIndex} -
- )} */} + // 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; - {/* 渲染组内内容 */} - {entries.map(([key, value], index) => - !(result && value.value?.toString().trim() == '') && ( -
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(); - 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}--------没有对应页码`); + // 遍历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(); - 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}--------没有对应页码`); + // 遍历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} - 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() || ''} -

+
+
+
+ {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; + }; + + /** * 渲染评查点内容与建议 @@ -757,6 +1636,9 @@ export function ReviewPointsList({ * @returns 评查点内容与建议组件 */ const renderReviewPointContent = (reviewPoint: ReviewPoint) => { + + const mergedRules = filterOtherRule(reviewPoint); + // console.log('mergedRules1-------', mergedRules); const handleManualReviewNotesChange = (reviewPointId: string, text: string) => { setManualReviewNotes(prev => ({ @@ -786,23 +1668,23 @@ export function ReviewPointsList({ return ( <> {checkContentPage(reviewPoint).pageIndex === 0 && ( -

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

+

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

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

{reviewPoint.suggestion}

- )} + )} */} {/* 评查点内容显示区域 */} {reviewPoint.content && Object.entries(reviewPoint.content).length > 0 && (
{/* 修改评查结果的结构之后,显示新的结构 */} - {renderContent(reviewPoint, true)} + {renderContent(reviewPoint, mergedRules)}
)} @@ -853,13 +1735,13 @@ export function ReviewPointsList({ return ( <> {checkContentPage(reviewPoint).pageIndex === 0 && ( -

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

+

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

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

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

+

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

)} {/* 建议内容显示区域 */} @@ -926,7 +1808,7 @@ export function ReviewPointsList({
{/* 修改评查结果的结构之后,显示新的结构 */} - {renderContent(reviewPoint,false)} + {renderContent(reviewPoint, mergedRules)}
@@ -1038,23 +1920,23 @@ export function ReviewPointsList({ // 如果评查点存在 if (reviewPoint) { - // 使用checkContentPage方法获取页码和key - const { pageIndex, key } = checkContentPage(reviewPoint); + // // 使用checkContentPage方法获取页码和key + // const { pageIndex, key } = checkContentPage(reviewPoint); - // 如果有有效页码,传递ID和页码 - if (pageIndex > 0) { - console.log(`跳转到页面 ${pageIndex},对应内容 ${key || '未知'}`); - onReviewPointSelect(id, pageIndex); - return; - } + // // 如果有有效页码,传递ID和页码 + // if (pageIndex > 0) { + // console.log(`跳转到页面 ${pageIndex},对应内容 ${key || '未知'}`); + // onReviewPointSelect(id, pageIndex); + // return; + // } - // 没有有效页码,只传递ID + // // 没有有效页码,只传递ID onReviewPointSelect(id); - console.log(`没有有效页码---评查点ID:${reviewPoint.pointId},评查点结果ID:${id}`); + // console.log(`没有有效页码---评查点ID:${reviewPoint.pointId},评查点结果ID:${id}`); } else { - // 没有找到评查点,只传递ID + // // 没有找到评查点,只传递ID onReviewPointSelect(id); - console.log(`没有找到评查点---评查点结果ID:${id}`); + // console.log(`没有找到评查点---评查点结果ID:${id}`); } }; @@ -1105,43 +1987,49 @@ export function ReviewPointsList({ filteredReviewPoints.map(reviewPoint => (
handleReviewPointClick(reviewPoint.id)} + className={`rounded-md review-point-item ${activeReviewPointResultId === reviewPoint.id ? 'active border-l-4 border-l-[#00684a] shadow-md' : 'border-l-4 border-l-transparent'} + transition-all duration-300 ease-in-out + hover:shadow-lg hover:-translate-x-0.5 hover:bg-[rgba(0,0,0,0.02)] my-2`} + role="button" + tabIndex={0} + style={{ userSelect: 'text' }} + onClick={() => { + // console.log('reviewPoint', reviewPoint); + handleReviewPointClick(reviewPoint.id); + }} onKeyDown={(e) => { if (e.key === 'Enter') { handleReviewPointClick(reviewPoint.id); } }} - role="button" - tabIndex={0} - style={{ userSelect: 'text' }} > {/* 评查点标题和状态 */} {/* 评查点名称 pointName*/} -
{reviewPoint.pointName}
-
-
{reviewPoint.title}
- {/* 评查点所属分组 */} - {/*
- - - {reviewPoint.groupName} - -
*/} +
+
+
{reviewPoint.pointName}
+
+
{reviewPoint.title}
+ {/* 评查点所属分组 */} + {/*
+ + + {reviewPoint.groupName} + +
*/} +
+
{renderStatusBadge(reviewPoint.status, reviewPoint.result)} {renderHumanReviewBadge(reviewPoint)}
- {/* 人工审核注释 */} - {renderHumanReviewNote(reviewPoint)} - {/* 评查点内容和操作 */} {renderReviewPointContent(reviewPoint)}
diff --git a/app/routes/reviews.tsx b/app/routes/reviews.tsx index 1b8f518..5c051ee 100644 --- a/app/routes/reviews.tsx +++ b/app/routes/reviews.tsx @@ -593,7 +593,7 @@ export default function ReviewDetails() { {activeTab === 'preview' && (
{/* 左侧:文件预览 */} -
+
{/* 右侧:评查结果 */} -
+
+ + + + + 评查结果 - 卡片对比版 + + + + + +
+ +
+

评查结果

+

烟草专卖行政执法案件评查报告

+
+ + +
+
+ 55 + 总计 +
+
+ 49 + 通过 +
+
+ 6 + 警告 +
+
+ 0 + 错误 +
+
+ + +
+ + + + +
+ +
+
+
+ + 当事人基本情况记载完整、准确 +
+
+ + 通过 +
+
+
+ +
+ + +
+ +
+
+
立案报告表-姓名
+
江小妹
+
+
+
身份证-姓名
+
江小妹
+
+
+
+ + 一致 +
+
+ +
+ +
+
+
立案报告表-性别
+
+
+
+
身份证-性别
+
+
+
+
+ + 一致 +
+
+ +
+ +
+
+
立案报告表-民族
+
汉人
+
+
+
身份证-民族
+
汉族
+
+
+
+ + 不一致 +
+
+ +
+ +
+
+
立案报告表-身份证号
+
445322198602014328
+
+
+
身份证-身份证号
+
445322198602014328
+
+
+
+ + 一致 +
+
+ +
+ +
+
+
立案报告表-住址 身份证-住址
+
广东省云浮市郁南县宋桂镇宋桂村委尾一村6号
+
+
+
广东省云浮市郁南县宋桂镇宋桂村委尾一村6号
+
+
+
+ + 一致 +
+
+
+ + +
+
+ + 单位信息对比 +
+ +
+ +
+
+
立案报告表-单位名称 营业执照-单位名称
+
郁南县连滩镇领航烟酒商行
+
+
+
郁南县连滩镇领航烟酒商行
+
+
+
+ + 一致 +
+
+ +
+ +
+
+
立案报告表-地址 营业执照-住所
+
郁南县连滩镇中华路106号一楼
+
+
+
郁南县连滩镇中华路106号一楼
+
+
+
+ + 一致 +
+
+
+ + +
+ + +
+
法定代表人
+
江小妹
+
+ + 已填写 +
+
+ +
+
年龄
+
38
+
+ + 已填写 +
+
+ +
+
联系电话
+
13430472175
+
+ + 已填写 +
+
+
+ + +
+
+ + 检查总结 +
+
+ 检查结果:当事人基本情况记录完整,与身份证信息基本一致。
+ 发现问题:民族字段存在细微差异("汉人" vs "汉族"),建议统一表述。
+ 建议:将立案报告表中的"汉人"修改为"汉族"以保持一致性。 +
+
+
+
+
+ + +
+ + +
+
+
+ + + + \ No newline at end of file