import React, { useState, useEffect, useContext, useCallback, useRef } from 'react'; import { SimpleCodeEditor } from './SimpleCodeEditor'; import { RuleContext } from '~/contexts/RuleContext'; import { processFieldNames, areArraysDifferent, getArrayDifference } from '~/utils'; 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; score?: number; scoreDisplay?: string; }; // 添加选项数据参数 ruleTypeOptions?: Array<{ value: string; label: string }>; logicTypeOptions?: Array<{ value: string; label: string }>; logicOperatorOptions?: Array<{ value: string; label: string }>; compareMethodOptions?: Array<{ value: string; label: string }>; formatTypeOptions?: Array<{ value: string; label: string }>; comparisonOperatorOptions?: Array<{ value: string; label: string }>; matchTypeOptions?: Array<{ value: string; label: string }>; suggestionMessageTypeOptions?: Array<{ value: string; label: string }>; postActionOptions?: Array<{ value: string; label: string }>; } 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 [score, setScore] = useState(0); const [scoreDisplay, setScoreDisplay] = 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( // 初始化时就处理字段,去掉类型后缀 processFieldNames(extractionFields || []) ); // 使用useRef跟踪是否已经初始化过 const initializedRef = useRef(false); // 保存初始数据的引用,用于检测是否有实际变更 const initialDataRef = useRef(null); // 生成评查配置并发送给父组件 const generateEvaluationConfig = useCallback(() => { // 构建评查配置对象 const evaluationConfig = { logicType: combinationLogic, customLogic: customLogic, rules: rules .filter(rule => rule.type) // 过滤掉没有选择类型的规则 .map(rule => { // 处理不同规则类型的特殊配置 const processedConfig = { ...rule.config }; switch(rule.type) { case 'exists': // 确保fields字段是数组 if (!Array.isArray(processedConfig.fields)) { processedConfig.fields = []; } // 确保logic字段有值 if (!processedConfig.logic) { processedConfig.logic = 'and'; } break; case 'consistency': // 确保pairs字段是数组 if (!Array.isArray(processedConfig.pairs)) { processedConfig.pairs = []; } // 确保logic字段有值 if (!processedConfig.logic) { processedConfig.logic = 'and'; } break; case 'format': // 确保field字段正确设置 if (processedConfig.checkField) { processedConfig.field = processedConfig.checkField; delete processedConfig.checkField; } // 确保field字段有值 if (!processedConfig.field) { processedConfig.field = ''; } if (processedConfig.formatParams) { processedConfig.parameters = processedConfig.formatParams; delete processedConfig.formatParams; } // 确保formatType字段有值 if (!processedConfig.formatType) { processedConfig.formatType = ''; } // 确保parameters字段有值 if (!processedConfig.parameters) { processedConfig.parameters = ''; } break; case 'regex': // 确保field和pattern字段正确设置 if (processedConfig.checkField) { processedConfig.field = processedConfig.checkField; delete processedConfig.checkField; } // 确保field字段有值 if (!processedConfig.field) { processedConfig.field = ''; } if (processedConfig.regexPattern) { processedConfig.pattern = processedConfig.regexPattern; delete processedConfig.regexPattern; } // 确保pattern字段有值 if (!processedConfig.pattern) { processedConfig.pattern = ''; } // 确保matchType字段有值 if (!processedConfig.matchType) { processedConfig.matchType = 'match'; } break; case 'ai': // 确保model字段有值 if (!processedConfig.model) { processedConfig.model = 'qwen14b'; } // 确保temperature字段是数字 if (typeof processedConfig.temperature !== 'number') { processedConfig.temperature = 0.1; } // 确保prompt字段有值 if (!processedConfig.prompt) { processedConfig.prompt = ''; } break; case 'code': // 确保language字段有值 if (!processedConfig.language) { processedConfig.language = 'javascript'; } // 确保code字段有值 if (!processedConfig.code) { processedConfig.code = ''; } break; } // 移除辅助用的UI字段 delete processedConfig.availableFields; return { id: rule.id, type: rule.type, config: processedConfig }; }) }; // 使用setTimeout避免连锁更新 setTimeout(() => { if (onChange) { // 仅将一个evaluation_config对象传递给父组件 onChange({ evaluation_config: evaluationConfig }); } }, 0); return evaluationConfig; }, [rules, combinationLogic, customLogic, onChange]); // 加载初始数据 useEffect(() => { // 如果已经初始化过,则跳过此次处理 if (initializedRef.current) { // console.log("ReviewSettings已初始化,跳过后续初始化处理"); return; } // 记录初始化处理 console.log("ReviewSettings开始初始化,数据:", initialData); // 保存初始数据引用,用于后续比较 initialDataRef.current = JSON.parse(JSON.stringify(initialData)); // 设置已初始化标记 initializedRef.current = true; // 只有在有initialData时才进行初始化设置 if (initialData) { // 处理初始规则数据 if (initialData.rules && Array.isArray(initialData.rules) && initialData.rules.length > 0) { console.log("设置初始规则数据:", initialData.rules); const validRules = initialData.rules.map(rule => { // 确保每个规则都有id if (!rule.id) { rule.id = `rule_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } // 确保配置对象存在 if (!rule.config) { rule.config = {}; } // 添加可用字段 if (availableFields.length > 0) { rule.config.availableFields = availableFields; } return rule; }); // 如果没有规则或规则为空,添加一个默认规则 if (validRules.length === 0) { validRules.push({ id: '1', type: '', config: { availableFields } }); } setRules(validRules); } else { // 如果rules为空或不是数组,添加一个默认规则 setRules([{ id: '1', type: '', config: { availableFields } }]); } // 设置组合逻辑 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); } // 设置分数 if (initialData.score !== undefined) { setScore(initialData.score); } // 设置分数显示值 if (initialData.scoreDisplay) { setScoreDisplay(initialData.scoreDisplay); } else if (initialData.score !== undefined && initialData.score > 0) { setScoreDisplay(String(initialData.score)); } // 数据加载完成后,生成一次完整的评查配置 setTimeout(() => { generateEvaluationConfig(); }, 0); } // 移除availableFields依赖,避免死循环 }, [initialData, availableFields, generateEvaluationConfig]); // 监听extractionFields的变化 useEffect(() => { if (extractionFields && extractionFields.length > 0) { // 使用工具函数处理字段 const uniqueFields = processFieldNames(extractionFields); // 只在字段列表实际发生变化时更新 if (areArraysDifferent(uniqueFields, availableFields)) { // 检查删除和新增的字段 const { removed } = getArrayDifference(uniqueFields, availableFields); // 处理删除的字段 if (removed.length > 0) { handleDeletedFields(removed); } // 更新可用字段 setAvailableFields(uniqueFields); // 使用最新的字段更新规则 updateRulesWithNewFields(uniqueFields); } } }, [extractionFields, availableFields]); // 检查并更新字段(仍然保留此函数供需要时手动触发) // eslint-disable-next-line @typescript-eslint/no-unused-vars const checkAndUpdateFields = () => { if (extractionFields.length > 0) { // 处理字段,去掉类型后缀 const processedFields = extractionFields.map(field => { if (field.includes('_')) { return field.split('_')[0]; // 只保留类型前面的字段名 } return field; }); // 去重 const uniqueFields = [...new Set(processedFields)]; // 检查是否有字段被删除 const deletedFields = availableFields.filter(field => !uniqueFields.includes(field)); // 处理新增的字段 const newFields = uniqueFields.filter((field: string) => !availableFields.includes(field)); if (newFields.length > 0 || deletedFields.length > 0) { console.log('Updating fields in checkAndUpdateFields - deleted:', deletedFields, 'new:', newFields); // 设置最新的可用字段列表 setAvailableFields(uniqueFields); // 处理规则中已删除的字段 if (deletedFields.length > 0) { handleDeletedFields(deletedFields); } // 使用最新的字段列表更新规则配置 updateRulesWithNewFields(uniqueFields); return true; // 表示字段已更新 } } return false; // 表示字段未更新 }; // 初始化评查配置 useEffect(() => { // 生成并更新评查配置 generateEvaluationConfig(); }, [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字段 // 处理字段,只保留字段名,去掉类型后缀 const processedFields = newFields.map(field => { if (field.includes('_')) { return field.split('_')[0]; // 只保留类型前面的字段名 } return field; }); // 去重 const uniqueFields = [...new Set(processedFields)]; updatedConfig.availableFields = uniqueFields; // 根据规则类型更新其他相关字段 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 updateData = { combinationLogic: logic, // 如果切换到自定义逻辑,同时传递自定义逻辑内容 customLogic: logic === 'custom' ? customLogic : '' }; onChange(updateData); // 生成完整的评查配置 setTimeout(() => generateEvaluationConfig(), 0); } }; 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) { // 查找原始规则以获取现有配置 const originalRule = rules.find(r => r.id === id); const originalConfig = originalRule ? originalRule.config : {}; // 为新类型初始化配置 let initialConfig: Record = {}; // 如果类型没变,保留原配置 if (type === rule.type) { initialConfig = { ...originalConfig }; } else { // 根据类型设置初始配置 switch(type) { case 'exists': initialConfig = { fields: Array.isArray(originalConfig.fields) ? originalConfig.fields : [], logic: originalConfig.logic || originalConfig.logicRelation || 'and', availableFields: availableFields }; break; case 'consistency': initialConfig = { pairs: Array.isArray(originalConfig.pairs) ? originalConfig.pairs : [], logic: originalConfig.logic || originalConfig.logicRelation || 'and', availableFields: availableFields }; break; case 'format': initialConfig = { field: originalConfig.field || '', checkField: originalConfig.checkField || originalConfig.field || '', formatType: originalConfig.formatType || 'date', parameters: originalConfig.parameters || '', formatParams: originalConfig.formatParams || originalConfig.parameters || '', availableFields: availableFields }; break; case 'logic': initialConfig = { conditions: Array.isArray(originalConfig.conditions) ? originalConfig.conditions : [], logic: originalConfig.logic || originalConfig.logicRelation || 'and', initialField: '', initialOperator: 'eq', initialValue: '', availableFields: availableFields }; break; case 'regex': initialConfig = { field: originalConfig.field || '', checkField: originalConfig.checkField || originalConfig.field || '', pattern: originalConfig.pattern || '', regexPattern: originalConfig.regexPattern || originalConfig.pattern || '', matchType: originalConfig.matchType || 'match', availableFields: availableFields }; break; case 'ai': initialConfig = { model: originalConfig.model || 'qwen14b', temperature: typeof originalConfig.temperature === 'number' ? originalConfig.temperature : 0.1, prompt: originalConfig.prompt || `请判断以下{字段}内容是否符合规范要求,仅回答"符合"或"不符合",并简要说明理由。 {字段内容}`, availableFields: availableFields }; break; case 'code': initialConfig = { language: originalConfig.language || 'javascript', code: originalConfig.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) { // 处理特殊的字段映射,确保不同名称的字段保持同步 const processedChanges = { ...configChanges }; // 对于格式判断,确保checkField和field字段同步 if (rule.type === 'format' && 'checkField' in configChanges) { processedChanges.field = configChanges.checkField; } // 对于正则判断,确保字段名和模式保持同步 if (rule.type === 'regex') { if ('checkField' in configChanges) { processedChanges.field = configChanges.checkField; } if ('regexPattern' in configChanges) { processedChanges.pattern = configChanges.regexPattern; } } return { ...rule, config: { ...rule.config, ...processedChanges } }; } return rule; }); setRules(newRules); if (onChange) { // 立即触发父组件的onChange回调,确保数据能保存到父组件 onChange({ rules: newRules }); } }; // 渲染字段标签,确保已选择的字段即使在新的字段列表中不存在也会显示 const renderFieldTags = (ruleId: string, config: Record) => { // 获取规则的当前已选字段 // 修复:对于exists类型规则,应该使用fields而不是selectedFields const selectedFields = Array.isArray(config.fields) ? config.fields as string[] : (Array.isArray(config.selectedFields) ? config.selectedFields as string[] : []); // 优先使用配置中存储的可用字段,如果没有则使用当前可用字段 const fieldsToRender = Array.isArray(config.availableFields) ? config.availableFields as string[] : availableFields; return (
{fieldsToRender.map((field, index) => { // 使用includes方法检查选中状态 const isSelected = selectedFields.includes(field); return (
{ // 切换选中状态 const newSelectedFields = isSelected ? selectedFields.filter(f => f !== field) : [...selectedFields, field]; // 更新规则配置 handleRuleConfigChange(ruleId, { fields: newSelectedFields }); // 直接触发配置更新 generateEvaluationConfig(); }} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { const newSelectedFields = isSelected ? selectedFields.filter(f => f !== field) : [...selectedFields, field]; handleRuleConfigChange(ruleId, { fields: newSelectedFields }); // 直接触发配置更新 generateEvaluationConfig(); } }} 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 }); // 触发配置更新 generateEvaluationConfig(); }} />
)) ) : (
{ // 获取field和operator的值 const field = (config.initialField as string) || ''; const operator = (config.initialOperator as string) || 'eq'; const value = e.target.value; // 如果已经设置了字段,则创建条件 if (field) { handleRuleConfigChange(id, { initialValue: value, conditions: [{ field, operator, value }] }); } else { // 否则只保存值 handleRuleConfigChange(id, { initialValue: value }); } // 触发配置更新 generateEvaluationConfig(); }} />
)}
逻辑关系 *
); case 'regex': return (
{ handleRuleConfigChange(id, { regexPattern: e.target.value, pattern: e.target.value // 同步更新内部字段 }); // 直接触发配置更新 generateEvaluationConfig(); }} />
输入标准正则表达式,例如: "^[a-zA-Z0-9]+$" 表示仅允许字母和数字
); case 'ai': return (
{ const value = e.target.value; const numberValue = value === '' ? 0.1 : parseFloat(value); handleRuleConfigChange(id, { temperature: numberValue }); // 直接触发配置更新 generateEvaluationConfig(); }} />
{availableFields.map((field, idx) => ( ))}
); case 'code': return (
代码语言 *
编写返回true或false的评查函数,可以使用字段变量进行判断
{ handleRuleConfigChange(id, { code: value }); generateEvaluationConfig(); }} />
); case 'format': return (
{ handleRuleConfigChange(id, { formatParams: e.target.value, parameters: e.target.value }); // 直接触发配置更新 generateEvaluationConfig(); }} />
根据格式类型传入特定参数,如日期格式可传入"YYYY-MM-DD"
); default: return (

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

); } }; // 组件初次渲染后,主动发送一次完整配置数据 useEffect(() => { // 如果有初始数据,在组件挂载后主动发送一次完整规则配置 if (initialDataRef.current && onChange) { // console.log("组件挂载后发送初始完整配置"); setTimeout(() => generateEvaluationConfig(), 100); } }, [generateEvaluationConfig, onChange]); // 处理评查结果消息变更 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) { // 使用正确的字段名 const fieldName = type === 'pass' ? 'pass_message' : type === 'fail' ? 'fail_message' : 'suggestion_message'; onChange({ [fieldName]: value }); } }; // 处理严重程度变更 const handleSeverityChange = (value: string) => { setSuggestionMessageType(value); if (onChange) { onChange({ suggestion_message_type: value }); } }; // 处理分数变更 const handleScoreChange = (value: string) => { // 保存用户输入的显示值 setScoreDisplay(value); let scoreValue = 0; // 只在值不为空时更新实际分数 if (value.trim() !== '') { const numValue = parseFloat(value); if (!isNaN(numValue)) { scoreValue = Math.min(Math.max(numValue, 0), 100); } } // 更新状态 setScore(scoreValue); // 通知父组件 if (onChange) { onChange({ score: scoreValue }); } }; 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' && (
)}
不同类别会影响问题的展示方式和处理流程
{/* 评查后动作 */}
{/* 分数设置 */}
handleScoreChange(e.target.value)} onBlur={() => { // 在失去焦点时,如果显示值为空,则设置为0 if (scoreDisplay.trim() === '') { setScoreDisplay('0'); setScore(0); if (onChange) { onChange({ score: 0 }); } } else { // 否则更新为实际分数值的字符串表示 setScoreDisplay(String(score)); } }} />
该评查点的分值,范围0-100
{/* 动作描述区域 */} {post_action && post_action !== 'none' && (
)}
); }