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 Condition { field: string; operator: string; value: string; } interface ReviewSettingsProps { onChange?: (data: Record) => void; initialData?: { rules?: RuleType[]; combinationLogic?: string; customLogic?: string; pass_message?: string; fail_message?: string; suggestion_message?: string; suggestion_message_type?: string; post_action?: string; action_config?: string; }; } // 创建全局上下文以便在不同组件间共享数据 interface RuleContextType { extractionFields: string[]; updateFields: (fields: string[]) => void; } // 创建全局Context对象 export const RuleContext = createContext({ extractionFields: [], updateFields: () => {} }); export function ReviewSettings({ onChange, initialData }: ReviewSettingsProps) { const [rules, setRules] = useState([ { id: '1', type: '', config: {} } ]); const [combinationLogic, setCombinationLogic] = useState('and'); const [customLogic, setCustomLogic] = useState(''); const [showCustomLogic, setShowCustomLogic] = useState(false); // 添加评查后动作相关状态 const [post_action, setPostAction] = useState('none'); const [action_config, setActionConfig] = useState(''); // 获取抽取字段的上下文 const { extractionFields } = useContext(RuleContext); // 初始化评查通过/不通过/建议信息 const [pass_message, setPassMessage] = useState('文档检查通过,符合规范要求。'); const [fail_message, setFailMessage] = useState('文档存在以下问题,请修改后重新提交。'); const [suggestion_message, setSuggestMessage] = useState(''); // 提示类型 const [suggestion_message_type, setSuggestionMessageType] = useState('warning'); // 保存最近一次可用的字段列表 const [availableFields, setAvailableFields] = useState(extractionFields || []); // 加载初始数据 useEffect(() => { if (initialData) { // 设置规则 if (initialData.rules && initialData.rules.length > 0) { setRules(initialData.rules); } // 设置组合逻辑 if (initialData.combinationLogic) { setCombinationLogic(initialData.combinationLogic); if (initialData.combinationLogic === 'custom') { setShowCustomLogic(true); } } // 设置自定义逻辑 if (initialData.customLogic) { setCustomLogic(initialData.customLogic); } // 设置通过/不通过消息 if (initialData.pass_message) { setPassMessage(initialData.pass_message); } if (initialData.fail_message) { setFailMessage(initialData.fail_message); } // 设置建议消息 if (initialData.suggestion_message) { setSuggestMessage(initialData.suggestion_message); } if (initialData.suggestion_message_type) { setSuggestionMessageType(initialData.suggestion_message_type); } // 设置后处理动作 if (initialData.post_action) { setPostAction(initialData.post_action); } if (initialData.action_config) { setActionConfig(initialData.action_config); } } }, [initialData]); // 监听extractionFields的变化 useEffect(() => { if (extractionFields && extractionFields.length > 0) { const newFields = [...extractionFields]; // 只在字段列表实际发生变化时更新 if (JSON.stringify(newFields) !== JSON.stringify(availableFields)) { setAvailableFields(newFields); } } }, [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; // 检查是否有实际变化 if (JSON.stringify(incomingFields) !== JSON.stringify(availableFields)) { // 检查是否有字段被删除 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]); // 检查并更新字段(仍然保留此函数供需要时手动触发) // eslint-disable-next-line @typescript-eslint/no-unused-vars const checkAndUpdateFields = () => { 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) { console.log('Updating fields in checkAndUpdateFields - deleted:', deletedFields, 'new:', newFields); // 设置最新的可用字段列表 setAvailableFields(extractionFields); // 处理规则中已删除的字段 if (deletedFields.length > 0) { handleDeletedFields(deletedFields); } // 使用最新的字段列表更新规则配置 updateRulesWithNewFields(extractionFields); return true; // 表示字段已更新 } } return false; // 表示字段未更新 }; // 初始化评查配置 useEffect(() => { // 生成并更新评查配置 generateEvaluationConfig(); }, []); // 处理已删除字段的函数 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); setShowCustomLogic(logic === 'custom'); if (onChange) { const updatedData: Record = { logicType: logic }; onChange(updatedData); } }; const handleCustomLogicChange = (e: React.ChangeEvent) => { const value = e.target.value; setCustomLogic(value); if (onChange) { onChange({ customLogic: value }); } }; 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 newRules = rules.map(rule => { if (rule.id === id) { // 为新类型初始化配置 let initialConfig: Record = {}; // 如果类型没变,保留原配置 if (type === rule.type) { initialConfig = { ...rule.config }; } else { // 根据类型设置初始配置 switch(type) { case 'exists': initialConfig = { fields: [], logic: 'and', availableFields: availableFields }; break; case 'consistency': initialConfig = { pairs: [], logic: 'and', availableFields: availableFields }; break; case 'format': initialConfig = { field: '', formatType: '', parameters: '', availableFields: availableFields }; break; case 'logic': initialConfig = { conditions: [], logic: 'and', availableFields: availableFields }; break; case 'regex': initialConfig = { field: '', pattern: '', matchType: 'match', availableFields: availableFields }; break; case 'ai': initialConfig = { model: 'qwen14b', temperature: 0.1, prompt: '', availableFields: availableFields }; break; case 'code': initialConfig = { language: 'javascript', code: '', availableFields: availableFields }; break; default: initialConfig = { availableFields: availableFields }; } } return { ...rule, type, config: initialConfig }; } return rule; }); setRules(newRules); if (onChange) { onChange({ rules: newRules }); } // 更新评查配置 generateEvaluationConfig(); }; // 处理规则配置变更 const handleRuleConfigChange = (id: string, configChanges: Record) => { const newRules = rules.map(rule => { if (rule.id === id) { return { ...rule, config: { ...rule.config, ...configChanges } }; } return rule; }); setRules(newRules); if (onChange) { onChange({ rules: newRules }); } // 更新评查配置 generateEvaluationConfig(); }; // 渲染字段标签,确保已选择的字段即使在新的字段列表中不存在也会显示 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)) || !(config.availableFields as string[]).every((field) => availableFields.includes(field))))) { // 延迟更新以避免在渲染过程中修改状态 setTimeout(() => { console.log('Updating rule config with new available fields:', availableFields); 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 (
{Array.isArray(config.conditions) && config.conditions.length > 0 ? ( config.conditions.map((condition, conditionIndex) => (
{ const currentConditions = Array.isArray(config.conditions) ? [...(config.conditions as Condition[])] : []; currentConditions[conditionIndex] = { ...currentConditions[conditionIndex], value: e.target.value }; handleRuleConfigChange(id, { conditions: currentConditions }); }} />
)) ) : (
{ // 获取field和operator的值 const field = document.getElementById(`field-${id}-0`) ? (document.getElementById(`field-${id}-0`) as HTMLSelectElement).value : ''; const operator = document.getElementById(`operator-${id}-0`) ? (document.getElementById(`operator-${id}-0`) as HTMLSelectElement).value : 'eq'; const firstCondition = { field, operator, value: e.target.value }; handleRuleConfigChange(id, { conditions: [firstCondition] }); }} />
)}
逻辑关系 *
); 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 generateEvaluationConfig = () => { const config = { logicType: combinationLogic, customLogic: combinationLogic === 'custom' ? customLogic : '', rules: rules.map(rule => ({ id: rule.id, type: rule.type, config: rule.config })) }; if (onChange) { onChange({ evaluation_config: config }); } return config; }; // 处理评查结果消息变更 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) => { setSuggestionMessageType(value); if (onChange) { onChange({ suggestion_message_type: value }); } }; return (

评查设置

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

尚未添加任何规则

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

) : (
{rules.map((rule) => (
规则 #{rule.id}
选择评查类型后将显示对应的配置项
{renderRuleConfig(rule)}
))}
)}
{/* 评查结果提示信息 */}

评查结果提示信息

{/* 建议信息类别 */}

建议信息类别

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