This commit is contained in:
2025-04-10 02:06:56 +08:00
parent 90317d2b4b
commit f99a1f05d4
4 changed files with 759 additions and 1294 deletions
File diff suppressed because it is too large Load Diff
+128 -91
View File
@@ -1,14 +1,7 @@
import React, { useState, useEffect, useContext, useCallback, useRef } from 'react'; import React, { useState, useEffect, useContext, useCallback, useRef } from 'react';
import { SimpleCodeEditor } from './SimpleCodeEditor'; import { SimpleCodeEditor } from './SimpleCodeEditor';
import { RuleContext } from '~/contexts/RuleContext'; import { RuleContext } from '~/contexts/RuleContext';
import { processFieldNames, areArraysDifferent, getArrayDifference, debounce } from '~/utils'; import { processFieldNames, areArraysDifferent, getArrayDifference } from '~/utils';
import type {
Rule as ModelRule,
RuleType as ModelRuleType,
LogicType,
SuggestionMessageType,
PostActionType
} from '~/models/evaluation_points';
interface RuleType { interface RuleType {
id: string; id: string;
@@ -60,15 +53,6 @@ interface ReviewSettingsProps {
export function ReviewSettings({ export function ReviewSettings({
onChange, onChange,
initialData, initialData,
ruleTypeOptions = [],
logicTypeOptions = [],
logicOperatorOptions = [],
compareMethodOptions = [],
formatTypeOptions = [],
comparisonOperatorOptions = [],
matchTypeOptions = [],
suggestionMessageTypeOptions = [],
postActionOptions = []
}: ReviewSettingsProps) { }: ReviewSettingsProps) {
const [rules, setRules] = useState<RuleType[]>([ const [rules, setRules] = useState<RuleType[]>([
{ id: '1', type: '', config: {} } { id: '1', type: '', config: {} }
@@ -227,7 +211,7 @@ export function ReviewSettings({
// 只在字段列表实际发生变化时更新 // 只在字段列表实际发生变化时更新
if (areArraysDifferent(uniqueFields, availableFields)) { if (areArraysDifferent(uniqueFields, availableFields)) {
// 检查删除和新增的字段 // 检查删除和新增的字段
const { added, removed } = getArrayDifference(uniqueFields, availableFields); const { removed } = getArrayDifference(uniqueFields, availableFields);
// 处理删除的字段 // 处理删除的字段
if (removed.length > 0) { if (removed.length > 0) {
@@ -467,67 +451,73 @@ export function ReviewSettings({
const handleRuleTypeChange = (id: string, type: string) => { const handleRuleTypeChange = (id: string, type: string) => {
const newRules = rules.map(rule => { const newRules = rules.map(rule => {
if (rule.id === id) { if (rule.id === id) {
// 查找原始规则以获取现有配置
const originalRule = rules.find(r => r.id === id);
const originalConfig = originalRule ? originalRule.config : {};
// 为新类型初始化配置 // 为新类型初始化配置
let initialConfig: Record<string, unknown> = {}; let initialConfig: Record<string, unknown> = {};
// 如果类型没变,保留原配置 // 如果类型没变,保留原配置
if (type === rule.type) { if (type === rule.type) {
initialConfig = { ...rule.config }; initialConfig = { ...originalConfig };
} else { } else {
// 根据类型设置初始配置 // 根据类型设置初始配置
switch(type) { switch(type) {
case 'exists': case 'exists':
initialConfig = { initialConfig = {
fields: [], // 使用fields替代selectedFields fields: Array.isArray(originalConfig.fields) ? originalConfig.fields : [],
logic: 'and', // 使用logic替代existsLogic logic: originalConfig.logic || originalConfig.logicRelation || 'and',
availableFields: availableFields availableFields: availableFields
}; };
break; break;
case 'consistency': case 'consistency':
initialConfig = { initialConfig = {
pairs: [], pairs: Array.isArray(originalConfig.pairs) ? originalConfig.pairs : [],
logic: 'and', // 使用logic替代logicRelation logic: originalConfig.logic || originalConfig.logicRelation || 'and',
availableFields: availableFields availableFields: availableFields
}; };
break; break;
case 'format': case 'format':
initialConfig = { initialConfig = {
field: '', // 用于内部运算 field: originalConfig.field || '',
checkField: '', // 用于UI展示 checkField: originalConfig.checkField || originalConfig.field || '',
formatType: '', formatType: originalConfig.formatType || '',
formatParams: '', formatParams: originalConfig.formatParams || originalConfig.parameters || '',
availableFields: availableFields availableFields: availableFields
}; };
break; break;
case 'logic': case 'logic':
initialConfig = { initialConfig = {
conditions: [], conditions: Array.isArray(originalConfig.conditions) ? originalConfig.conditions : [],
logic: 'and', // 使用logic替代logicRelation logic: originalConfig.logic || originalConfig.logicRelation || 'and',
availableFields: availableFields availableFields: availableFields
}; };
break; break;
case 'regex': case 'regex':
initialConfig = { initialConfig = {
field: '', // 用于内部运算 field: originalConfig.field || '',
checkField: '', // 用于UI展示 checkField: originalConfig.checkField || originalConfig.field || '',
pattern: '', pattern: originalConfig.pattern || '',
regexPattern: '', // 用于UI展示 regexPattern: originalConfig.regexPattern || originalConfig.pattern || '',
matchType: 'match', // 默认为必须匹配 matchType: originalConfig.matchType || 'match',
availableFields: availableFields availableFields: availableFields
}; };
break; break;
case 'ai': case 'ai':
initialConfig = { initialConfig = {
model: 'qwen14b', model: originalConfig.model || 'qwen14b',
temperature: 0.1, temperature: typeof originalConfig.temperature === 'number' ? originalConfig.temperature : 0.1,
prompt: '', prompt: originalConfig.prompt || `请判断以下{字段}内容是否符合规范要求,仅回答"符合"或"不符合",并简要说明理由。
{字段内容}`,
availableFields: availableFields availableFields: availableFields
}; };
break; break;
case 'code': case 'code':
initialConfig = { initialConfig = {
language: 'javascript', language: originalConfig.language || 'javascript',
code: '', code: originalConfig.code || '',
availableFields: availableFields availableFields: availableFields
}; };
break; break;
@@ -595,7 +585,10 @@ export function ReviewSettings({
// 渲染字段标签,确保已选择的字段即使在新的字段列表中不存在也会显示 // 渲染字段标签,确保已选择的字段即使在新的字段列表中不存在也会显示
const renderFieldTags = (ruleId: string, config: Record<string, unknown>) => { const renderFieldTags = (ruleId: string, config: Record<string, unknown>) => {
// 获取规则的当前已选字段 // 获取规则的当前已选字段
const selectedFields = Array.isArray(config.selectedFields) ? config.selectedFields as string[] : []; // 修复:对于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) ? const fieldsToRender = Array.isArray(config.availableFields) ?
@@ -960,8 +953,15 @@ export function ReviewSettings({
name={`logicRelation_${id}`} name={`logicRelation_${id}`}
className="form-radio" className="form-radio"
value="and" value="and"
checked={!config.logicRelation || config.logicRelation === 'and'} checked={!config.logic && !config.logicRelation ? true : (config.logic === 'and' || config.logicRelation === 'and')}
onChange={(e) => handleRuleConfigChange(id, { logicRelation: e.target.value })} onChange={(e) => {
handleRuleConfigChange(id, {
logicRelation: e.target.value,
logic: e.target.value
});
// 触发配置更新
generateEvaluationConfig();
}}
/> />
<span>AND</span> <span>AND</span>
</label> </label>
@@ -971,8 +971,15 @@ export function ReviewSettings({
name={`logicRelation_${id}`} name={`logicRelation_${id}`}
className="form-radio" className="form-radio"
value="or" value="or"
checked={config.logicRelation === 'or'} checked={config.logic === 'or' || config.logicRelation === 'or'}
onChange={(e) => handleRuleConfigChange(id, { logicRelation: e.target.value })} onChange={(e) => {
handleRuleConfigChange(id, {
logicRelation: e.target.value,
logic: e.target.value
});
// 触发配置更新
generateEvaluationConfig();
}}
/> />
<span>OR</span> <span>OR</span>
</label> </label>
@@ -1188,9 +1195,12 @@ export function ReviewSettings({
name={`logicRelation_${id}`} name={`logicRelation_${id}`}
className="form-radio" className="form-radio"
value="and" value="and"
checked={!config.logicRelation || config.logicRelation === 'and'} checked={!config.logic && !config.logicRelation ? true : (config.logic === 'and' || config.logicRelation === 'and')}
onChange={(e) => { onChange={(e) => {
handleRuleConfigChange(id, { logicRelation: e.target.value }); handleRuleConfigChange(id, {
logicRelation: e.target.value,
logic: e.target.value
});
// 触发配置更新 // 触发配置更新
generateEvaluationConfig(); generateEvaluationConfig();
}} }}
@@ -1203,9 +1213,12 @@ export function ReviewSettings({
name={`logicRelation_${id}`} name={`logicRelation_${id}`}
className="form-radio" className="form-radio"
value="or" value="or"
checked={config.logicRelation === 'or'} checked={config.logic === 'or' || config.logicRelation === 'or'}
onChange={(e) => { onChange={(e) => {
handleRuleConfigChange(id, { logicRelation: e.target.value }); handleRuleConfigChange(id, {
logicRelation: e.target.value,
logic: e.target.value
});
// 触发配置更新 // 触发配置更新
generateEvaluationConfig(); generateEvaluationConfig();
}} }}
@@ -1302,7 +1315,12 @@ export function ReviewSettings({
<select <select
id={`ai-model-${id}`} id={`ai-model-${id}`}
className="form-select" className="form-select"
onChange={(e) => handleRuleConfigChange(id, { model: e.target.value })} value={config.model as string || 'qwen14b'}
onChange={(e) => {
handleRuleConfigChange(id, { model: e.target.value });
// 直接触发配置更新
generateEvaluationConfig();
}}
> >
<option value="deepseek">DeepSeek</option> <option value="deepseek">DeepSeek</option>
<option value="qwen72b">Qwen72B-VL</option> <option value="qwen72b">Qwen72B-VL</option>
@@ -1316,11 +1334,17 @@ export function ReviewSettings({
id={`ai-temp-${id}`} id={`ai-temp-${id}`}
className="form-input" className="form-input"
placeholder="0.1" placeholder="0.1"
defaultValue="0.1" value={typeof config.temperature === 'number' ? config.temperature : (config.temperature ? parseFloat(String(config.temperature)) : 0.1)}
min="0" min="0"
max="1" max="1"
step="0.1" step="0.1"
onChange={(e) => handleRuleConfigChange(id, { temperature: e.target.value })} onChange={(e) => {
const value = e.target.value;
const numberValue = value === '' ? 0.1 : parseFloat(value);
handleRuleConfigChange(id, { temperature: numberValue });
// 直接触发配置更新
generateEvaluationConfig();
}}
/> />
</div> </div>
<div className="col-span-1 md:col-span-2"> <div className="col-span-1 md:col-span-2">
@@ -1329,9 +1353,13 @@ export function ReviewSettings({
id={`ai-prompt-${id}`} id={`ai-prompt-${id}`}
className="form-textarea" className="form-textarea"
placeholder="请输入提示词,引导模型进行判断" placeholder="请输入提示词,引导模型进行判断"
defaultValue={`请判断以下{字段}内容是否符合规范要求,仅回答"符合"或"不符合",并简要说明理由。 value={
typeof config.prompt === 'string' && config.prompt
? config.prompt
: `请判断以下{字段}内容是否符合规范要求,仅回答"符合"或"不符合",并简要说明理由。
{字段内容}`} {字段内容}`
}
onChange={(e) => handleRuleConfigChange(id, { prompt: e.target.value })} onChange={(e) => handleRuleConfigChange(id, { prompt: e.target.value })}
></textarea> ></textarea>
</div> </div>
@@ -1382,8 +1410,11 @@ export function ReviewSettings({
name={`codeLanguage_${id}`} name={`codeLanguage_${id}`}
className="form-radio" className="form-radio"
value="javascript" value="javascript"
defaultChecked checked={!config.language || config.language === 'javascript'}
onChange={(e) => handleRuleConfigChange(id, { language: e.target.value })} onChange={(e) => {
handleRuleConfigChange(id, { language: e.target.value });
generateEvaluationConfig();
}}
/> />
<span>JavaScript</span> <span>JavaScript</span>
</label> </label>
@@ -1393,7 +1424,11 @@ export function ReviewSettings({
name={`codeLanguage_${id}`} name={`codeLanguage_${id}`}
className="form-radio" className="form-radio"
value="python" value="python"
onChange={(e) => handleRuleConfigChange(id, { language: e.target.value })} checked={config.language === 'python'}
onChange={(e) => {
handleRuleConfigChange(id, { language: e.target.value });
generateEvaluationConfig();
}}
/> />
<span>Python</span> <span>Python</span>
</label> </label>
@@ -1402,10 +1437,15 @@ export function ReviewSettings({
</div> </div>
<div className="mb-4"> <div className="mb-4">
<label className="form-label" htmlFor={`code-editor-${id}`}> <span className="required-mark">*</span></label> <label className="form-label" htmlFor={`code-editor-${id}`}> <span className="required-mark">*</span></label>
<div className="form-tip mb-2">true或false的评查函数使</div>
<SimpleCodeEditor <SimpleCodeEditor
id={`code-editor-${id}`} id={`code-editor-${id}`}
language={rule.config.language as 'javascript' | 'python' || 'javascript'} language={rule.config.language as 'javascript' | 'python' || 'javascript'}
onChange={(value) => handleRuleConfigChange(id, { code: value })} initialValue={rule.config.code as string || ''}
onChange={(value) => {
handleRuleConfigChange(id, { code: value });
generateEvaluationConfig();
}}
/> />
</div> </div>
</div> </div>
@@ -1490,7 +1530,8 @@ export function ReviewSettings({
// 生成完整的评查配置数据并在提交保存时使用 // 生成完整的评查配置数据并在提交保存时使用
const generateEvaluationConfig = useCallback(() => { const generateEvaluationConfig = useCallback(() => {
const config = { // 创建符合数据库模式的evaluation_config对象
const evaluationConfig = {
logicType: combinationLogic, logicType: combinationLogic,
customLogic: combinationLogic === 'custom' ? customLogic : '', customLogic: combinationLogic === 'custom' ? customLogic : '',
rules: rules.map(rule => { rules: rules.map(rule => {
@@ -1506,7 +1547,6 @@ export function ReviewSettings({
delete processedConfig.selectedFields; delete processedConfig.selectedFields;
} }
if (processedConfig.existsLogic) { if (processedConfig.existsLogic) {
console.log(`[调试] exists规则 ${rule.id} 转换: existsLogic=${processedConfig.existsLogic} 映射到 logic`);
processedConfig.logic = processedConfig.existsLogic; processedConfig.logic = processedConfig.existsLogic;
delete processedConfig.existsLogic; delete processedConfig.existsLogic;
} }
@@ -1567,24 +1607,13 @@ export function ReviewSettings({
// 使用setTimeout避免连锁更新 // 使用setTimeout避免连锁更新
setTimeout(() => { setTimeout(() => {
if (onChange) { if (onChange) {
onChange({ // 仅将一个evaluation_config对象传递给父组件
rules: config.rules, onChange({ evaluation_config: evaluationConfig });
combinationLogic: config.logicType,
customLogic: config.customLogic,
pass_message: pass_message,
fail_message: fail_message,
suggestion_message: suggestion_message,
suggestion_message_type: suggestion_message_type,
post_action: post_action,
action_config: action_config,
score: score,
scoreDisplay: scoreDisplay
});
} }
}, 0); }, 0);
return config; return evaluationConfig;
}, [rules, combinationLogic, customLogic, pass_message, fail_message, suggestion_message, suggestion_message_type, post_action, action_config, score, scoreDisplay, onChange]); }, [rules, combinationLogic, customLogic, onChange]);
// 组件初次渲染后,主动发送一次完整配置数据 // 组件初次渲染后,主动发送一次完整配置数据
useEffect(() => { useEffect(() => {
@@ -1610,9 +1639,11 @@ export function ReviewSettings({
} }
if (onChange) { if (onChange) {
onChange({ [`${type}_message`]: value }); // 使用正确的字段名
// 触发完整配置生成以确保数据保存 const fieldName = type === 'pass' ? 'pass_message' :
generateEvaluationConfig(); type === 'fail' ? 'fail_message' :
'suggestion_message';
onChange({ [fieldName]: value });
} }
}; };
@@ -1622,8 +1653,6 @@ export function ReviewSettings({
if (onChange) { if (onChange) {
onChange({ suggestion_message_type: value }); onChange({ suggestion_message_type: value });
// 触发完整配置生成以确保数据保存
generateEvaluationConfig();
} }
}; };
@@ -1632,26 +1661,21 @@ export function ReviewSettings({
// 保存用户输入的显示值 // 保存用户输入的显示值
setScoreDisplay(value); setScoreDisplay(value);
let scoreValue = 0;
// 只在值不为空时更新实际分数 // 只在值不为空时更新实际分数
if (value.trim() !== '') { if (value.trim() !== '') {
const numValue = parseFloat(value); const numValue = parseFloat(value);
if (!isNaN(numValue)) { if (!isNaN(numValue)) {
const validScore = Math.min(Math.max(numValue, 0), 100); scoreValue = Math.min(Math.max(numValue, 0), 100);
setScore(validScore);
} else {
setScore(0);
} }
} else {
setScore(0);
} }
// 更新状态
setScore(scoreValue);
// 通知父组件
if (onChange) { if (onChange) {
if (value.trim() === '') { onChange({ score: scoreValue });
// 空值处理
onChange({ score: 0, scoreDisplay: '' });
} else {
onChange({ score: score, scoreDisplay: value });
}
} }
}; };
@@ -2025,6 +2049,19 @@ export function ReviewSettings({
placeholder="请输入分数 (0-100)" placeholder="请输入分数 (0-100)"
value={scoreDisplay} value={scoreDisplay}
onChange={(e) => handleScoreChange(e.target.value)} onChange={(e) => handleScoreChange(e.target.value)}
onBlur={() => {
// 在失去焦点时,如果显示值为空,则设置为0
if (scoreDisplay.trim() === '') {
setScoreDisplay('0');
setScore(0);
if (onChange) {
onChange({ score: 0 });
}
} else {
// 否则更新为实际分数值的字符串表示
setScoreDisplay(String(score));
}
}}
/> />
<span className="ml-2 text-gray-600"></span> <span className="ml-2 text-gray-600"></span>
</div> </div>
+5 -55
View File
@@ -13,7 +13,7 @@ export function SimpleCodeEditor({
language = 'javascript', language = 'javascript',
onChange onChange
}: SimpleCodeEditorProps) { }: SimpleCodeEditorProps) {
const [code, setCode] = useState(initialValue || getDefaultCode(language)); const [code, setCode] = useState(initialValue);
const [copySuccess, setCopySuccess] = useState(false); const [copySuccess, setCopySuccess] = useState(false);
// 复制代码到剪贴板 // 复制代码到剪贴板
@@ -33,62 +33,12 @@ export function SimpleCodeEditor({
} }
}; };
// 初始示例代码 // 更新初始值
function getDefaultCode(lang: string) {
if (lang === 'javascript') {
return `// 示例代码
function checkRule(data) {
// data 包含抽取的字段
try {
// 在此编写检查逻辑
if (data.fieldName && condition) {
return {
pass: true,
message: "检查通过"
};
} else {
return {
pass: false,
message: "检查不通过,原因:..."
};
}
} catch (error) {
return {
pass: false,
message: "执行出错:" + error.message
};
}
}`;
} else {
return `# 示例代码
def check_rule(data):
# data 包含抽取的字段
try:
# 在此编写检查逻辑
if 'field_name' in data and condition:
return {
'pass': True,
'message': "检查通过"
}
else:
return {
'pass': False,
'message': "检查不通过,原因:..."
}
except Exception as error:
return {
'pass': False,
'message': f"执行出错:{str(error)}"
}`;
}
}
// 当语言变化时更新代码
useEffect(() => { useEffect(() => {
if (!initialValue) { if (initialValue !== undefined) {
setCode(getDefaultCode(language)); setCode(initialValue);
} }
}, [language, initialValue]); }, [initialValue]);
return ( return (
<div> <div>
+201 -43
View File
@@ -40,6 +40,9 @@ import type {
} from "~/models/evaluation_points"; } from "~/models/evaluation_points";
import { EVALUATION_OPTIONS } from "~/models/evaluation_points"; import { EVALUATION_OPTIONS } from "~/models/evaluation_points";
import type { EvaluationPointGroup } from "~/models/evaluation_point_groups"; import type { EvaluationPointGroup } from "~/models/evaluation_point_groups";
// 导入RuleContext上下文
import { RuleContext } from "~/contexts/RuleContext";
export const meta: MetaFunction = () => { export const meta: MetaFunction = () => {
return [ return [
{ title: "评查点管理 - 中国烟草AI合同及卷宗审核系统" }, { title: "评查点管理 - 中国烟草AI合同及卷宗审核系统" },
@@ -68,6 +71,41 @@ export default function RuleNew() {
const [formData, setFormData] = useState<EvaluationPoint>({}); const [formData, setFormData] = useState<EvaluationPoint>({});
const [evaluationPointGroups, setEvaluationPointGroups] = useState<EvaluationPointGroup[]>([]); const [evaluationPointGroups, setEvaluationPointGroups] = useState<EvaluationPointGroup[]>([]);
// 添加用于共享的字段数据状态
const [extractionFields, setExtractionFields] = useState<string[]>([]);
/**
* 从表单数据中提取所有字段
* 用于编辑模式下初始化字段数据
*/
const extractFieldsFromFormData = useCallback((data: EvaluationPoint) => {
if (!data || !data.extraction_config) return [];
const fields: string[] = [];
const config = data.extraction_config;
// 提取LLM字段
if (config.llm && Array.isArray(config.llm.fields)) {
fields.push(...config.llm.fields);
}
// 提取VLM字段
if (config.vlm && Array.isArray(config.vlm.fields)) {
const vlmFields = config.vlm.fields.map((f: string | { name: string, type: string }) =>
typeof f === 'string' ? f : f.name
);
fields.push(...vlmFields);
}
// 提取正则字段
if (config.regex && Array.isArray(config.regex.fields)) {
const regexFields = config.regex.fields.map((f: { field: string, pattern: string }) => f.field).filter(Boolean);
fields.push(...regexFields);
}
return fields;
}, []);
/** /**
* 获取评查点数据 * 获取评查点数据
* 编辑模式下从API获取指定ID的评查点数据 * 编辑模式下从API获取指定ID的评查点数据
@@ -88,6 +126,12 @@ export default function RuleNew() {
if (response.ok) { if (response.ok) {
const data = await response.json(); const data = await response.json();
setFormData(data.data[0]); setFormData(data.data[0]);
// 初始化extractionFields
if (data.data[0]) {
const extractedFields = extractFieldsFromFormData(data.data[0]);
setExtractionFields(extractedFields);
}
} }
} catch (error) { } catch (error) {
console.error('获取评查点数据失败:', error); console.error('获取评查点数据失败:', error);
@@ -97,7 +141,7 @@ export default function RuleNew() {
} finally { } finally {
setIsLoading(false); setIsLoading(false);
} }
}, [navigate]); }, [navigate, extractFieldsFromFormData]);
/** /**
* 获取评查点组数据 * 获取评查点组数据
@@ -127,6 +171,84 @@ export default function RuleNew() {
const handleSave = () => { const handleSave = () => {
console.log("保存评查点", formData); console.log("保存评查点", formData);
// 验证必填字段
if (!formData.name?.trim()) {
alert("评查点名称不能为空");
return;
}
if (!formData.code?.trim()) {
alert("评查点编码不能为空");
return;
}
// 显示保存中状态
setIsLoading(true);
// 根据模式决定是创建还是更新
const apiMethod = isEditMode ? 'PATCH' : 'POST';
const apiUrl = isEditMode
? `http://127.0.0.1:9000/admin/evaluation_points?id=eq.${formData.id}`
: 'http://127.0.0.1:9000/admin/evaluation_points';
// 创建一个符合数据库模式的数据副本
const cleanedData = {
id: formData.id,
name: formData.name,
code: formData.code,
risk: formData.risk,
is_enabled: formData.is_enabled !== undefined ? formData.is_enabled : true,
description: formData.description || '',
references_laws: formData.references_laws,
evaluation_point_groups_pid: formData.evaluation_point_groups_pid,
evaluation_point_groups_id: formData.evaluation_point_groups_id,
extraction_config: formData.extraction_config,
evaluation_config: formData.evaluation_config,
pass_message: formData.pass_message || '文档检查通过,符合规范要求。',
fail_message: formData.fail_message || '文档存在以下问题,请修改后重新提交。',
suggestion_message: formData.suggestion_message || '',
suggestion_message_type: formData.suggestion_message_type || 'warning',
post_action: formData.post_action || 'none',
action_config: formData.action_config || '',
score: formData.score !== undefined ? formData.score : 0
};
// 如果是新建模式,则删除id字段
if (!isEditMode) {
delete cleanedData.id;
}
console.log("准备提交到API的数据:", cleanedData);
// 发送数据到API
fetch(apiUrl, {
method: apiMethod,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(cleanedData)
})
.then(response => {
if (!response.ok) {
throw new Error(`API错误: ${response.status}`);
}
return response.json();
})
.then(data => {
console.log("保存成功:", data);
alert(`评查点${isEditMode ? '更新' : '创建'}成功!`);
// 保存成功后返回列表页
navigate('/rules');
})
.catch(error => {
console.error("保存失败:", error);
alert(`保存失败: ${error.message}`);
})
.finally(() => {
setIsLoading(false);
});
} }
const handleSaveDraft = () => { const handleSaveDraft = () => {
@@ -139,12 +261,63 @@ export default function RuleNew() {
const handleExtractionSettingsChange = (data: Record<string, unknown>) => { const handleExtractionSettingsChange = (data: Record<string, unknown>) => {
setFormData(prev => ({ ...prev, ...data })); setFormData(prev => ({ ...prev, ...data }));
}
// 提取并处理字段数据
const processFields = () => {
// 使用类型断言处理字段访问
const extractionConfig = data.extraction_config as {
llm?: { fields?: string[] };
vlm?: { fields?: Array<string | { name: string, type: string }> };
regex?: { fields?: Array<{ field: string, pattern: string }> };
} | undefined;
if (!extractionConfig) return;
const llmFields = extractionConfig.llm?.fields || [];
const vlmFields = extractionConfig.vlm?.fields || [];
const regexFields = (extractionConfig.regex?.fields || []).map((f: { field: string }) => f.field);
// 合并所有字段
const allFields = [
...llmFields,
...vlmFields.map((f: string | { name: string }) => typeof f === 'string' ? f : f.name),
...regexFields
].filter(Boolean);
setExtractionFields(allFields);
};
// 处理字段数据
if (data.extraction_config) {
processFields();
}
};
const handleReviewSettingsChange = (data: Record<string, unknown>) => { const handleReviewSettingsChange = (data: Record<string, unknown>) => {
setFormData(prev => ({ ...prev, ...data })); setFormData(prev => ({ ...prev, ...data }));
} }
/**
* 添加事件监听,处理抽取字段更新
*/
useEffect(() => {
// 定义事件处理函数
const handleExtractionFieldsUpdated = (event: CustomEvent<{fields: string[]}>) => {
const { fields } = event.detail;
if (Array.isArray(fields) && fields.length > 0) {
// 更新字段数据
setExtractionFields(fields);
}
};
// 添加事件监听
window.addEventListener('extraction-fields-updated', handleExtractionFieldsUpdated as EventListener);
// 清理函数
return () => {
window.removeEventListener('extraction-fields-updated', handleExtractionFieldsUpdated as EventListener);
};
}, []);
/** /**
* 页面加载时初始化处理 * 页面加载时初始化处理
* 1. 检查URL参数,判断是新建还是编辑模式 * 1. 检查URL参数,判断是新建还是编辑模式
@@ -182,7 +355,10 @@ export default function RuleNew() {
<span className="ml-3">...</span> <span className="ml-3">...</span>
</div> </div>
) : ( ) : (
<> <RuleContext.Provider value={{
extractionFields,
updateFields: setExtractionFields
}}>
{/* 评查点基本信息设置 */} {/* 评查点基本信息设置 */}
<div className="mb-8"> <div className="mb-8">
<BasicInfo <BasicInfo
@@ -197,25 +373,7 @@ export default function RuleNew() {
<div className="mb-8"> <div className="mb-8">
<ExtractionSettings <ExtractionSettings
onChange={handleExtractionSettingsChange} onChange={handleExtractionSettingsChange}
initialData={{ initialData={formData}
llm: {
fields: formData.extraction_config?.llm?.fields,
prompt_setting: {
type: formData.extraction_config?.llm?.prompt_setting?.type,
template: formData.extraction_config?.llm?.prompt_setting?.template
}
},
vlm: {
fields: formData.extraction_config?.vlm?.fields,
prompt_setting: {
type: formData.extraction_config?.vlm?.prompt_setting?.type,
template: formData.extraction_config?.vlm?.prompt_setting?.template
}
},
regex: {
fields: formData.extraction_config?.regex?.fields
}
}}
promptTypeOptions={EVALUATION_OPTIONS.promptTypeOptions} promptTypeOptions={EVALUATION_OPTIONS.promptTypeOptions}
vlmFieldTypeOptions={EVALUATION_OPTIONS.vlmFieldTypeOptions} vlmFieldTypeOptions={EVALUATION_OPTIONS.vlmFieldTypeOptions}
/> />
@@ -224,28 +382,28 @@ export default function RuleNew() {
{/* 评查设置 - 配置评查规则、消息等 */} {/* 评查设置 - 配置评查规则、消息等 */}
<div className="mb-8"> <div className="mb-8">
<ReviewSettings <ReviewSettings
key={`review-settings-${isEditMode ? formData.id : 'new'}`} key={`review-settings-${extractionFields.length}-${isEditMode ? formData.id : 'new'}`}
onChange={handleReviewSettingsChange} onChange={handleReviewSettingsChange}
initialData={{ initialData={{
rules: formData.evaluation_config?.rules, rules: formData.evaluation_config?.rules || [],
combinationLogic: formData.evaluation_config?.logicType, combinationLogic: formData.evaluation_config?.logicType || 'and',
customLogic: formData.evaluation_config?.customLogic, customLogic: formData.evaluation_config?.customLogic || '',
pass_message: formData.pass_message, pass_message: formData.pass_message || '',
fail_message: formData.fail_message, fail_message: formData.fail_message || '',
suggestion_message: formData.suggestion_message, suggestion_message: formData.suggestion_message || '',
suggestion_message_type: formData.suggestion_message_type, suggestion_message_type: formData.suggestion_message_type || 'warning',
post_action: formData.post_action, post_action: formData.post_action || 'none',
action_config: formData.action_config, action_config: formData.action_config || '',
score: formData.score score: formData.score || 0
}} }}
ruleTypeOptions={EVALUATION_OPTIONS.ruleTypeOptions} ruleTypeOptions={EVALUATION_OPTIONS.ruleTypeOptions}
logicTypeOptions={EVALUATION_OPTIONS.logicTypeOptions} logicTypeOptions={EVALUATION_OPTIONS.logicTypeOptions}
logicOperatorOptions={EVALUATION_OPTIONS.logicOperatorOptions} logicOperatorOptions={EVALUATION_OPTIONS.logicOperatorOptions}
compareMethodOptions={EVALUATION_OPTIONS.compareMethodOptions} compareMethodOptions={EVALUATION_OPTIONS.compareMethodOptions}
formatTypeOptions={EVALUATION_OPTIONS.formatTypeOptions} formatTypeOptions={EVALUATION_OPTIONS.formatTypeOptions}
comparisonOperatorOptions={EVALUATION_OPTIONS.comparisonOperatorOptions} comparisonOperatorOptions={EVALUATION_OPTIONS.comparisonOperatorOptions}
matchTypeOptions={EVALUATION_OPTIONS.matchTypeOptions} matchTypeOptions={EVALUATION_OPTIONS.matchTypeOptions}
suggestionMessageTypeOptions={EVALUATION_OPTIONS.suggestionMessageTypeOptions} suggestionMessageTypeOptions={EVALUATION_OPTIONS.suggestionMessageTypeOptions}
postActionOptions={EVALUATION_OPTIONS.postActionOptions} postActionOptions={EVALUATION_OPTIONS.postActionOptions}
/> />
</div> </div>
@@ -256,7 +414,7 @@ export default function RuleNew() {
onSaveDraft={handleSaveDraft} onSaveDraft={handleSaveDraft}
isEditMode={isEditMode} isEditMode={isEditMode}
/> />
</> </RuleContext.Provider>
)} )}
</div> </div>
); );