暂存
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||||
|
|||||||
@@ -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
@@ -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合同及卷宗审核系统" },
|
||||||
@@ -67,6 +70,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;
|
||||||
|
}, []);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取评查点数据
|
* 获取评查点数据
|
||||||
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user