From ebdf97aebf7d6072f65e883d3700bc1c9d662a8c Mon Sep 17 00:00:00 2001 From: awen Date: Wed, 9 Apr 2025 01:34:14 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9F=BA=E7=A1=80=E7=BB=84=E4=BB=B6=E5=AE=8C?= =?UTF-8?q?=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/components/rules/new/BasicInfo.tsx | 330 ++-- .../rules/new/ExtractionSettings.tsx | 130 +- app/components/rules/new/ReviewSettings.tsx | 31 +- app/models/evaluation_point_groups.ts | 15 + app/models/evaluation_points.ts | 308 ++++ app/routes/rules.new.tsx | 1582 ++--------------- app/routes/rules.new1.tsx | 1539 ++++++++++++++++ html/评查点-新增.html | 2 +- test-api.js | 158 ++ test-api2.js | 108 ++ test-rules-api.js | 162 ++ 11 files changed, 2673 insertions(+), 1692 deletions(-) create mode 100644 app/models/evaluation_point_groups.ts create mode 100644 app/models/evaluation_points.ts create mode 100644 app/routes/rules.new1.tsx create mode 100644 test-api.js create mode 100644 test-api2.js create mode 100644 test-rules-api.js diff --git a/app/components/rules/new/BasicInfo.tsx b/app/components/rules/new/BasicInfo.tsx index a532ee3..0c7d21d 100644 --- a/app/components/rules/new/BasicInfo.tsx +++ b/app/components/rules/new/BasicInfo.tsx @@ -1,182 +1,57 @@ import React, { useState, useEffect } from 'react'; - +import type { EvaluationPoint } from '~/models/evaluation_points'; +import type { EvaluationPointGroup } from '~/models/evaluation_point_groups'; interface BasicInfoProps { onChange?: (data: Record) => void; - initialData?: FormDataType; - evaluationPointGroups?: Array<{id: number, pid: number, code: string, name: string, is_enabled: boolean}>; + initialData?: EvaluationPoint; + evaluationPointGroups?: EvaluationPointGroup[]; + riskOptions?: Array<{value: string, label: string}>; } -// 定义表单数据类型 -interface FormDataType { - name: string; - code: string; - risk: string; - is_enabled: boolean; - description: string; - references_laws: { - name: string; - articles: string[]; - content: string; - }; - evaluation_point_groups_id: number | null; - evaluation_point_groups_pid: number | null; - type: string; - id?: number; -} - -export function BasicInfo({ onChange, initialData, evaluationPointGroups = [] }: BasicInfoProps) { - const [formData, setFormData] = useState({ - name: '', - code: '', - risk: 'medium', - is_enabled: true, - description: '', - references_laws: { - name: '', - articles: [], - content: '' - }, - evaluation_point_groups_id: null, - evaluation_point_groups_pid: null, - type: '' +// 评查点基本信息组件 +export function BasicInfo({ onChange, initialData, evaluationPointGroups = [], riskOptions = [] }: BasicInfoProps) { + const [formData, setFormData] = useState({ + risk: 'medium', // 风险等级 默认中风险 + is_enabled: true, // 是否启用 默认启用 + ...(initialData || {}) // 合并初始数据 }); + // 找到当前评查点类型对应的code + const getCheckpointTypeCode = () => { + if (!formData.evaluation_point_groups_pid) return ""; + + const typeGroup = evaluationPointGroups.find( + group => group.id === formData.evaluation_point_groups_pid && group.pid === 0 + ); + + return typeGroup?.code || ""; + }; + + // 评查点描述与法律依据 展开状态 const [isDescExpanded, setIsDescExpanded] = useState(false); - const [lawArticlesInput, setLawArticlesInput] = useState(''); - const [filteredRuleGroups, setFilteredRuleGroups] = useState>([]); + + // 条款号临时输入字符串(不会触发自动分割) + const [lawArticlesText, setLawArticlesText] = useState(''); - // 当initialData变化时更新表单数据 - useEffect(() => { - if (initialData) { - const newFormData = { - name: initialData.name || '', - code: initialData.code || '', - risk: initialData.risk || 'medium', - is_enabled: initialData.is_enabled !== undefined ? initialData.is_enabled : true, - description: initialData.description || '', - references_laws: initialData.references_laws || { - name: '', - articles: [], - content: '' - }, - evaluation_point_groups_id: initialData.evaluation_point_groups_id || null, - evaluation_point_groups_pid: initialData.evaluation_point_groups_pid || null, - type: initialData.type || '' - }; - - setFormData(newFormData); - - // 更新法律条款输入框 - if (initialData.references_laws && Array.isArray(initialData.references_laws.articles)) { - setLawArticlesInput(initialData.references_laws.articles.join(',')); - } - - // 如果有描述或法律依据,默认展开详细信息 - if (initialData.description || - (initialData.references_laws && - (initialData.references_laws.name || - initialData.references_laws.content || - (initialData.references_laws.articles && initialData.references_laws.articles.length > 0)))) { - setIsDescExpanded(true); - } - } - }, [initialData]); - - // 当评查点类型或评查点组数据变化时,过滤规则组列表 - useEffect(() => { - if (evaluationPointGroups && evaluationPointGroups.length > 0) { - console.log("评查点组数据更新,当前类型:", formData.type); - console.log("评查点组数据:", evaluationPointGroups); - - if (formData.type) { - // 获取所选评查点类型的组ID - const typeGroup = evaluationPointGroups.find(group => - group.pid === 0 && - group.code === formData.type - ); - - console.log("找到的类型组:", typeGroup); - - if (typeGroup) { - // 更新评查点类型组ID - if (formData.evaluation_point_groups_pid !== typeGroup.id) { - const newData = { - ...formData, - evaluation_point_groups_pid: typeGroup.id - }; - setFormData(newData); - if (onChange) onChange(newData); - } - - // 过滤出属于该类型的规则组(pid等于类型组ID的项) - const groups = evaluationPointGroups.filter(group => - group.pid === typeGroup.id && - group.is_enabled - ); - console.log("过滤后的规则组:", groups); - setFilteredRuleGroups(groups); - - // 如果当前选择的规则组不在过滤结果中,重置选择 - if (formData.evaluation_point_groups_id && - !groups.some(group => group.id === formData.evaluation_point_groups_id)) { - console.log("当前选择的规则组不在过滤结果中,重置选择"); - const newData = { - ...formData, - evaluation_point_groups_id: null - }; - setFormData(newData); - if (onChange) onChange(newData); - } - } else { - console.log("未找到对应的类型组"); - setFilteredRuleGroups([]); - - // 重置评查点类型组ID - if (formData.evaluation_point_groups_pid !== null) { - const newData = { - ...formData, - evaluation_point_groups_pid: null - }; - setFormData(newData); - if (onChange) onChange(newData); - } - } - } else { - console.log("未选择评查点类型"); - setFilteredRuleGroups([]); - - // 重置评查点类型组ID - if (formData.evaluation_point_groups_pid !== null) { - const newData = { - ...formData, - evaluation_point_groups_pid: null - }; - setFormData(newData); - if (onChange) onChange(newData); - } - } - } - }, [formData.type, evaluationPointGroups, formData.evaluation_point_groups_id, formData.evaluation_point_groups_pid, onChange]); + // 根据选择的评查点类型筛选可用的规则组 + const filteredRuleGroups = evaluationPointGroups.filter(group => + formData.evaluation_point_groups_pid && + group.pid === formData.evaluation_point_groups_pid && + group.is_enabled + ); // 获取评查点类型选项(pid=0的数据) const getCheckpointTypeOptions = () => { if (!evaluationPointGroups || evaluationPointGroups.length === 0) { - console.log("无评查点组数据,使用默认类型选项"); return ( <> - - - - - ); } const typeGroups = evaluationPointGroups.filter(group => group.pid === 0 && group.is_enabled); - console.log("可用的评查点类型:", typeGroups); - + return ( <> @@ -189,14 +64,15 @@ export function BasicInfo({ onChange, initialData, evaluationPointGroups = [] }: ); }; + // 评查点描述与法律依据 展开状态 const handleToggleDescription = () => { setIsDescExpanded(!isDescExpanded); }; + // 处理表单输入变化 const handleInputChange = (e: React.ChangeEvent) => { const { id, value } = e.target; const newData = { ...formData }; - // 映射id到表单字段名 switch(id) { case 'rule-name': @@ -214,32 +90,32 @@ export function BasicInfo({ onChange, initialData, evaluationPointGroups = [] }: case 'rule-description': newData.description = value; break; - case 'law-name': - newData.references_laws.name = value; + case 'law-name': + newData.references_laws = { + ...formData.references_laws, + name: value + }; break; - case 'law-content': - newData.references_laws.content = value; - break; - case 'law-articles': - setLawArticlesInput(value); + case 'law-content': + newData.references_laws = { + ...formData.references_laws, + content: value + }; break; case 'evaluation-point-group': newData.evaluation_point_groups_id = value ? parseInt(value) : null; break; case 'checkpoint-type': - newData.type = value; - // 重置规则组选择 - newData.evaluation_point_groups_id = null; - - // 设置评查点类型组ID + // 处理评查点类型选择 if (value) { - const typeGroup = evaluationPointGroups.find(group => - group.pid === 0 && - group.code === value - ); - newData.evaluation_point_groups_pid = typeGroup ? typeGroup.id : null; + // 找到选中的类型组 + const selectedType = evaluationPointGroups.find(group => group.code === value && group.pid === 0); + if (selectedType) { + newData.evaluation_point_groups_pid = selectedType.id; + } } else { newData.evaluation_point_groups_pid = null; + newData.evaluation_point_groups_id = null; // 清空规则组选择 } break; } @@ -251,18 +127,32 @@ export function BasicInfo({ onChange, initialData, evaluationPointGroups = [] }: } }; - const handleLawArticlesChange = (value: string) => { - setLawArticlesInput(value); - const articles = value.split(',') + // 处理条款号输入框变化 + const handleLawArticlesChange = (e: React.ChangeEvent) => { + // 设置临时字符串状态,这样不会触发任何处理 + setLawArticlesText(e.target.value); + }; + + // 处理条款号输入框失去焦点 + const handleLawArticlesBlur = () => { + if (!lawArticlesText) return; + + // 将输入的文本转换为数组 + const articles = lawArticlesText + .split(',') .map(article => article.trim()) .filter(article => article !== ''); - + + // 创建一个新的引用法律对象,保留现有字段 + const referencesLaws = { + ...(formData.references_laws || {}), + articles: articles.length > 0 ? articles : [] + }; + + // 更新表单数据 const newData = { ...formData, - references_laws: { - ...formData.references_laws, - articles - } + references_laws: referencesLaws }; setFormData(newData); @@ -272,6 +162,33 @@ export function BasicInfo({ onChange, initialData, evaluationPointGroups = [] }: } }; + // 初始化条款号文本字段 + useEffect(() => { + if (formData.references_laws?.articles && formData.references_laws.articles.length > 0) { + setLawArticlesText(formData.references_laws.articles.join(',')); + } + }, [formData.references_laws?.articles]); + + // 检查是否需要自动展开描述区域 + useEffect(() => { + // 如果描述或法律依据相关字段有值,则自动展开 + if ( + formData.description || + formData.references_laws?.name || + (formData.references_laws?.articles && formData.references_laws.articles.length > 0) || + formData.references_laws?.content + ) { + setIsDescExpanded(true); + } + }, [formData]); + + useEffect(() => { + // 可以在这里通知父组件 + if (onChange && filteredRuleGroups.length === 1) { + onChange({ evaluation_point_groups_id: filteredRuleGroups[0].id }); + } + }, [filteredRuleGroups, onChange]); + return (
@@ -317,9 +234,19 @@ export function BasicInfo({ onChange, initialData, evaluationPointGroups = [] }: value={formData.risk} onChange={handleInputChange} > - - - + {riskOptions.length > 0 ? ( + riskOptions.map(option => ( + + )) + ) : ( + <> + + + + + )}
请定义评查点的风险等级
@@ -330,7 +257,7 @@ export function BasicInfo({ onChange, initialData, evaluationPointGroups = [] }: @@ -360,7 +287,7 @@ export function BasicInfo({ onChange, initialData, evaluationPointGroups = [] }: ))}
- {!formData.type ? "请先选择评查点类型" : + {!formData.evaluation_point_groups_pid ? "请先选择评查点类型" : filteredRuleGroups.length === 0 ? "该类型下暂无可用规则组" : "选择评查点所属的规则组"}
@@ -420,20 +347,23 @@ export function BasicInfo({ onChange, initialData, evaluationPointGroups = [] }: className="form-input" placeholder="例如:《中华人民共和国民法典》" id="law-name" - value={formData.references_laws.name} + value={formData.references_laws?.name || ''} onChange={handleInputChange} />
- + handleLawArticlesChange(e.target.value)} + value={lawArticlesText} + onChange={handleLawArticlesChange} + onBlur={handleLawArticlesBlur} />
多个条款用逗号分隔,将自动转换为数组格式
@@ -445,7 +375,7 @@ export function BasicInfo({ onChange, initialData, evaluationPointGroups = [] }: style={{ minHeight: '60px' }} placeholder="例如:当事人应当按照约定全面履行自己的义务。" id="law-content" - value={formData.references_laws.content} + value={formData.references_laws?.content || ''} onChange={handleInputChange} > @@ -459,10 +389,10 @@ export function BasicInfo({ onChange, initialData, evaluationPointGroups = [] }:
预览效果
- {formData.references_laws.name || '《中华人民共和国民法典》'} + {formData.references_laws?.name || '《中华人民共和国民法典》'}
- {formData.references_laws.articles.length > 0 ? + {formData.references_laws?.articles && formData.references_laws.articles.length > 0 ? formData.references_laws.articles.map((article, index) => ( {article} )) : ( @@ -473,7 +403,7 @@ export function BasicInfo({ onChange, initialData, evaluationPointGroups = [] }: )}
- {formData.references_laws.content || '当事人应当按照约定全面履行自己的义务。'} + {formData.references_laws?.content || '当事人应当按照约定全面履行自己的义务。'}
diff --git a/app/components/rules/new/ExtractionSettings.tsx b/app/components/rules/new/ExtractionSettings.tsx index d433f1c..e8e8b3a 100644 --- a/app/components/rules/new/ExtractionSettings.tsx +++ b/app/components/rules/new/ExtractionSettings.tsx @@ -1,6 +1,7 @@ import { useState, KeyboardEvent, FormEvent, useContext, useEffect, useCallback, useRef } from 'react'; import { RuleContext } from '~/contexts/RuleContext'; import { processFieldName } from '~/utils'; +import type { PromptType, VLMFieldType } from '~/models/evaluation_points'; // 定义通知函数的类型 type NotifyFn = (data: Record) => void; @@ -41,7 +42,7 @@ interface RegexField { interface VlmField { name: string; - type: string; + type: VLMFieldType | string; } interface PromptTemplate { @@ -72,9 +73,16 @@ interface ExtractionSettingsProps { fields?: RegexField[]; }; }; + promptTypeOptions?: Array<{value: string, label: string}>; + vlmFieldTypeOptions?: Array<{value: string, label: string}>; } -export function ExtractionSettings({ onChange, initialData }: ExtractionSettingsProps) { +export function ExtractionSettings({ + onChange, + initialData, + promptTypeOptions = [], + vlmFieldTypeOptions = [] +}: ExtractionSettingsProps) { const ruleContext = useContext(RuleContext); const lastUpdateTimeRef = useRef(0); // 添加一个ref来记录上次更新时间 const lastEventFieldsRef = useRef([]); @@ -884,6 +892,62 @@ export function ExtractionSettings({ onChange, initialData }: ExtractionSettings setSelectedFieldType(e.currentTarget.value); }; + // 在渲染选择模态字段类型的下拉列表时使用vlmFieldTypeOptions + const renderVlmFieldTypeSelect = (field: string, index: number) => { + return ( + + ); + }; + + // 在渲染提示词类型的选择器时使用promptTypeOptions + const renderPromptTypeSelect = (type: string, promptType: 'llm' | 'vlm') => { + return ( + + ); + }; + return (
@@ -970,28 +1034,7 @@ export function ExtractionSettings({ onChange, initialData }: ExtractionSettings 提示词设置
- - + {renderPromptTypeSelect(promptType.llm, 'llm')}
handleFieldInputChange(e, 'vlm')} onKeyDown={(e) => handleKeyDown(e, 'vlm')} /> - + {renderVlmFieldTypeSelect(inputValue.vlm, 0)}