import React, { useState, useEffect, useContext, createContext } from 'react'; import { SimpleCodeEditor } from './SimpleCodeEditor'; interface RuleType { id: string; type: string; config: Record; } // 为配置项添加类型定义 interface ComparisonPair { sourceField: string; targetField: string; compareMethod: string; } interface ReviewSettingsProps { onChange?: (data: Record) => void; } // 创建全局上下文以便在不同组件间共享数据 interface RuleContextType { extractionFields: string[]; updateExtractionFields: (fields: string[]) => void; } // 创建全局Context对象 export const RuleContext = createContext({ extractionFields: [], updateExtractionFields: () => {} }); export function ReviewSettings({ onChange }: ReviewSettingsProps) { const [rules, setRules] = useState([ { id: '1', type: '', config: {} } ]); const [combinationLogic, setCombinationLogic] = useState('and'); const [customLogic, setCustomLogic] = useState(''); const [showCustomLogic, setShowCustomLogic] = useState(false); // 添加评查后动作相关状态 const [actionType, setActionType] = useState('none'); const [actionDescription, setActionDescription] = useState(''); // 获取抽取字段的上下文 const { extractionFields } = useContext(RuleContext); // 初始化评查通过/不通过/建议信息 const [passMessage, setPassMessage] = useState('文档检查通过,符合规范要求。'); const [failMessage, setFailMessage] = useState('文档存在以下问题,请修改后重新提交。'); const [suggestMessage, setSuggestMessage] = useState(''); // 错误严重程度 const [errorSeverity, setErrorSeverity] = useState('error'); // 保存最近一次可用的字段列表 const [availableFields, setAvailableFields] = useState(extractionFields || []); // 监听抽取设置中的字段变化 useEffect(() => { // 当Context中的字段发生变化时,更新可用字段但保留已有配置 if (extractionFields.length > 0) { // 检查是否有字段被删除 const deletedFields = availableFields.filter(field => !extractionFields.includes(field)); // 处理新增的字段 const newFields = extractionFields.filter((field: string) => !availableFields.includes(field)); if (newFields.length > 0 || deletedFields.length > 0) { // 设置最新的可用字段列表 setAvailableFields(extractionFields); // 处理规则中已删除的字段 if (deletedFields.length > 0) { handleDeletedFields(deletedFields); } // 使用最新的字段列表更新规则配置 updateRulesWithNewFields(extractionFields); } } // 监听抽取设置的变化 - 用于捕获非Context更新的情况 const handleExtractionChange = (event: Event) => { if (event instanceof CustomEvent && event.detail && Array.isArray(event.detail.fields)) { const incomingFields = event.detail.fields; // 检查是否有字段被删除 const deletedFields = availableFields.filter(field => !incomingFields.includes(field)); // 识别新增的字段 const newFields = incomingFields.filter((field: string) => !availableFields.includes(field)); if (newFields.length > 0 || deletedFields.length > 0) { // 设置最新的可用字段列表 setAvailableFields(incomingFields); // 处理规则中已删除的字段 if (deletedFields.length > 0) { handleDeletedFields(deletedFields); } // 使用最新的字段列表更新规则配置 updateRulesWithNewFields(incomingFields); } } }; // 添加事件监听器,监听抽取设置中的字段变化 document.addEventListener('extraction-fields-updated', handleExtractionChange); // 组件卸载时移除事件监听 return () => { document.removeEventListener('extraction-fields-updated', handleExtractionChange); }; }, [extractionFields, availableFields]); // 处理已删除字段的函数 const handleDeletedFields = (deletedFields: string[]) => { setRules(prevRules => { return prevRules.map(rule => { const updatedConfig = { ...rule.config }; switch (rule.type) { case 'exists': case 'logic': case 'regex': // 从已选字段中移除被删除的字段 if (Array.isArray(updatedConfig.selectedFields)) { updatedConfig.selectedFields = (updatedConfig.selectedFields as string[]).filter( field => !deletedFields.includes(field) ); } break; case 'consistency': // 从配对字段中移除被删除的字段 if (Array.isArray(updatedConfig.pairs)) { updatedConfig.pairs = (updatedConfig.pairs as ComparisonPair[]).filter( pair => !deletedFields.includes(pair.sourceField) && !deletedFields.includes(pair.targetField) ); } break; case 'format': // 如果判断字段被删除,则清空字段 if (updatedConfig.checkField && deletedFields.includes(updatedConfig.checkField as string)) { updatedConfig.checkField = ''; } break; default: break; } // 更新可用字段列表,移除被删除的字段 if (Array.isArray(updatedConfig.availableFields)) { updatedConfig.availableFields = (updatedConfig.availableFields as string[]).filter( field => !deletedFields.includes(field) ); } return { ...rule, config: updatedConfig }; }); }); }; // 更新规则配置中的可用字段但保留已选择的字段和规则配置 const updateRulesWithNewFields = (newFields: string[]) => { // 更新每个规则的可用字段列表,但保留现有配置 setRules(prevRules => { return prevRules.map(rule => { const updatedConfig = { ...rule.config }; // 对所有规则类型都更新availableFields字段 updatedConfig.availableFields = newFields; // 根据规则类型更新其他相关字段 if (rule.type) { switch (rule.type) { case 'field_validation': // 保留已有的字段选择,只添加新字段 if (!updatedConfig.fields) { updatedConfig.fields = []; } break; case 'field_comparison': // 保留已配置的比较项 if (!updatedConfig.pairs) { updatedConfig.pairs = []; } break; case 'field_regex': // 保留正则表达式配置 break; case 'custom_code': break; default: // 对于所有类型规则,确保selectedFields字段存在 if (!updatedConfig.selectedFields) { updatedConfig.selectedFields = []; } break; } } return { ...rule, config: updatedConfig }; }); }); }; const handleLogicChange = (logic: string) => { setCombinationLogic(logic); if (logic === 'custom') { setShowCustomLogic(true); } else { setShowCustomLogic(false); } if (onChange) { onChange({ combinationLogic: logic, showCustomLogic: logic === 'custom', customLogic }); } }; const handleCustomLogicChange = (e: React.ChangeEvent) => { setCustomLogic(e.target.value); if (onChange) { onChange({ customLogic: e.target.value }); } }; const handleActionTypeChange = (type: string) => { setActionType(type); if (onChange) { onChange({ actionType: type }); } }; const handleAddRule = () => { const newId = `${rules.length + 1}`; const newRule = { id: newId, type: '', config: {} }; setRules([...rules, newRule]); if (onChange) { onChange({ rules: [...rules, newRule] }); } }; const handleRemoveRule = (id: string) => { // 如果只有一个规则,不允许删除 if (rules.length <= 1) { return; } const newRules = rules.filter(rule => rule.id !== id); setRules(newRules); // 重新编号规则 const reindexedRules = newRules.map((rule, index) => ({ ...rule, id: `${index + 1}` })); setRules(reindexedRules); if (onChange) { onChange({ rules: reindexedRules }); } }; const handleRuleTypeChange = (id: string, type: string) => { // 更新规则类型 const updatedRules = rules.map(rule => { if (rule.id === id) { // 为新类型初始化配置 let initialConfig: Record = {}; // 根据类型设置初始配置 switch(type) { case 'exists': case 'logic': case 'regex': initialConfig = { selectedFields: [], availableFields: availableFields // 使用当前最新的可用字段列表 }; break; case 'consistency': initialConfig = { pairs: [], availableFields: availableFields // 使用当前最新的可用字段列表 }; break; case 'format': initialConfig = { formatType: '', formatParams: '', availableFields: availableFields // 使用当前最新的可用字段列表 }; break; default: // 确保所有规则类型都包含availableFields initialConfig = { availableFields: availableFields }; break; } return { ...rule, type, config: initialConfig }; } return rule; }); setRules(updatedRules); if (onChange) { onChange({ rules: updatedRules }); } }; const handleRuleConfigChange = (id: string, configChanges: Record) => { const updatedRules = rules.map(rule => { if (rule.id === id) { // 合并现有配置和变更 const updatedConfig = { ...rule.config, ...configChanges }; // 确保availableFields字段存在 if (!updatedConfig.availableFields) { updatedConfig.availableFields = availableFields; } return { ...rule, config: updatedConfig }; } return rule; }); setRules(updatedRules); if (onChange) { onChange({ rules: updatedRules }); } }; // 渲染字段标签,确保已选择的字段即使在新的字段列表中不存在也会显示 const renderFieldTags = (ruleId: string, config: Record) => { // 获取规则的当前已选字段 const selectedFields = Array.isArray(config.selectedFields) ? config.selectedFields as string[] : []; // 优先使用配置中存储的可用字段,如果没有则使用当前可用字段 const fieldsToRender = Array.isArray(config.availableFields) ? config.availableFields as string[] : availableFields; return (
{fieldsToRender.map((field, index) => (
{ // 切换选中状态 const newSelectedFields = selectedFields.includes(field) ? selectedFields.filter(f => f !== field) : [...selectedFields, field]; handleRuleConfigChange(ruleId, { selectedFields: newSelectedFields }); }} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { const newSelectedFields = selectedFields.includes(field) ? selectedFields.filter(f => f !== field) : [...selectedFields, field]; handleRuleConfigChange(ruleId, { selectedFields: newSelectedFields }); } }} role="button" tabIndex={0} > {field}
))}
); }; // 获取规则类型的Badge样式 const getRuleTypeBadgeClass = (type: string) => { switch(type) { case 'exists': return 'bg-green-500'; case 'consistency': return 'bg-blue-500'; case 'format': return 'bg-purple-500'; case 'logic': return 'bg-yellow-500'; case 'regex': return 'bg-red-500'; case 'ai': return 'bg-indigo-500'; case 'code': return 'bg-gray-700'; default: return 'bg-primary'; } }; // 渲染规则配置区域 const renderRuleConfig = (rule: RuleType) => { const { id, type, config } = rule; // 如果规则中的availableFields不是最新的,则更新它 if (type && config && (!config.availableFields || (Array.isArray(config.availableFields) && !availableFields.every((field) => (config.availableFields as string[]).includes(field))))) { // 延迟更新以避免在渲染过程中修改状态 setTimeout(() => { const updatedConfig = { ...config, availableFields: availableFields }; handleRuleConfigChange(id, updatedConfig); }, 0); } if (!type) { return (

请先选择评查类型

); } switch(type) { case 'exists': return (
{renderFieldTags(id, config)}
点击选择需要判断是否存在的字段,已选中的字段会高亮显示
); case 'consistency': return (
{Array.isArray(config.pairs) && config.pairs.length > 0 ? ( config.pairs.map((pair, pairIndex) => (
)) ) : (
)}
逻辑关系 *
); case 'logic': return (
{ const currentConditions = Array.isArray(config.conditions) ? [...config.conditions] : []; currentConditions[0] = { ...currentConditions[0], value: e.target.value }; handleRuleConfigChange(id, { conditions: currentConditions }); }} />
逻辑关系 *
); case 'regex': return (
匹配类型 *
); case 'ai': return (
handleRuleConfigChange(id, { temperature: e.target.value })} />
{availableFields.map((field, idx) => ( ))}
); case 'code': return (
代码语言 *
handleRuleConfigChange(id, { code: value })} />
); case 'format': return (
handleRuleConfigChange(id, { formatParams: e.target.value })} />
); default: return (

已选择 {type} 类型规则,请继续配置。

); } }; // 处理评查结果消息变更 const handleMessageChange = (type: string, value: string) => { switch(type) { case 'pass': setPassMessage(value); break; case 'fail': setFailMessage(value); break; case 'suggest': setSuggestMessage(value); break; } if (onChange) { onChange({ [`${type}Message`]: value }); } }; // 处理严重程度变更 const handleSeverityChange = (value: string) => { setErrorSeverity(value); if (onChange) { onChange({ errorSeverity: value }); } }; return (

评查设置

{showCustomLogic && (
使用规则编号和逻辑运算符(AND、OR、NOT)组合
)}
已添加 {rules.length} 条规则
{rules.length === 0 ? (

尚未添加任何规则

点击“添加规则”按钮开始创建评查规则

) : (
{rules.map((rule) => (
规则 #{rule.id}
选择评查类型后将显示对应的配置项
{renderRuleConfig(rule)}
))}
)}
建议在消息中说明问题出现的原因及建议的解决方案
{actionType === 'notification' && (
)}
{/* 评查结果提示信息 */}

评查结果提示信息

{/* 不通过提示类别 */}

建议信息类别

handleSeverityChange('info')} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { handleSeverityChange('info'); } }} role="radio" aria-checked={errorSeverity === 'info'} tabIndex={0} > handleSeverityChange('info')} />
提示 (Info)
提示性信息,不影响
{errorSeverity === 'info' && (
)}
handleSeverityChange('warning')} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { handleSeverityChange('warning'); } }} role="radio" aria-checked={errorSeverity === 'warning'} tabIndex={0} > handleSeverityChange('warning')} />
警告 (Warning)
警告信息,建议修改但不强制
{errorSeverity === 'warning' && (
)}
handleSeverityChange('error')} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { handleSeverityChange('error'); } }} role="radio" aria-checked={errorSeverity === 'error'} tabIndex={0} > handleSeverityChange('error')} />
错误 (Error)
严重错误,必须修正
{errorSeverity === 'error' && (
)}
不同类别会影响问题的展示方式和处理流程
{/* 评查后动作 */}
{/* 动作描述区域 */} {actionType && actionType !== 'none' && (
)}
); }