feat(rules): VLM 字段补齐多实体逐字段开关,对齐 LLM 字段行为

- 多实体总开关开启后,VLM 字段可点击单独切换 multi_entity(绿色=已开启)
- 新增 VLM 字段时默认写入 multi_entity: false
- 删除按钮 stopPropagation 避免触发多实体切换

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-31 15:12:17 +08:00
parent cd852ee721
commit f525707358
@@ -232,12 +232,14 @@ export function ExtractionSettings({
newFields.push({ newFields.push({
name: input, name: input,
type: selectedVlmFieldType as VLMFieldType, type: selectedVlmFieldType as VLMFieldType,
template: customVlmPrompt template: customVlmPrompt,
multi_entity: false,
}); });
} else { } else {
newFields.push({ newFields.push({
name: input, name: input,
type: selectedVlmFieldType as VLMFieldType type: selectedVlmFieldType as VLMFieldType,
multi_entity: false,
}); });
} }
} }
@@ -289,6 +291,18 @@ export function ExtractionSettings({
setHasPendingChanges(true); setHasPendingChanges(true);
}; };
// 切换 VLM 字段的多实体状态
const toggleVLMFieldMultiEntity = (index: number) => {
if (!multiEntityEnabled) return; // 多实体未开启时不允许切换
const newFields = [...fields.vlm];
const field = newFields[index];
if (typeof field === 'object') {
newFields[index] = { ...field, multi_entity: !field.multi_entity };
setFields({ ...fields, vlm: newFields });
setHasPendingChanges(true);
}
};
// 获取VLM字段信息 // 获取VLM字段信息
const getFieldInfo = (field: string | { name: string, type: string, template?: string }) => { const getFieldInfo = (field: string | { name: string, type: string, template?: string }) => {
let fieldName, fieldType, typeName, badgeClass; let fieldName, fieldType, typeName, badgeClass;
@@ -885,18 +899,27 @@ export function ExtractionSettings({
<div className="chips-container" id="fields-container-vlm"> <div className="chips-container" id="fields-container-vlm">
{fields.vlm.map((field, index) => { {fields.vlm.map((field, index) => {
const { fieldName, fieldType, typeName, badgeClass } = getFieldInfo(field); const { fieldName, fieldType, typeName, badgeClass } = getFieldInfo(field);
const isMulti = typeof field === 'object' && field.multi_entity === true;
return ( return (
<div className="chip" key={`vlm-field-${index}`}> <div
className="chip"
key={`vlm-field-${index}`}
style={multiEntityEnabled && isMulti ? { backgroundColor: '#00684a', color: '#fff', borderColor: '#00684a' } : undefined}
onClick={() => toggleVLMFieldMultiEntity(index)}
role={multiEntityEnabled ? 'button' : undefined}
title={multiEntityEnabled ? (isMulti ? '点击关闭多实体展开' : '点击开启多实体展开') : fieldName}
>
{fieldName} {fieldName}
<span <span
className={`badge ${badgeClass} text-xs ml-1`} className={`badge ${badgeClass} text-xs ml-1`}
data-type={fieldType} data-type={fieldType}
style={multiEntityEnabled && isMulti ? { backgroundColor: 'rgba(255,255,255,0.25)', color: '#fff' } : undefined}
> >
{typeName} {typeName}
</span> </span>
<span <span
className="close-btn" className="close-btn"
onClick={() => removeField("vlm", index)} onClick={(e) => { e.stopPropagation(); removeField("vlm", index); }}
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") if (e.key === "Enter" || e.key === " ")
removeField("vlm", index); removeField("vlm", index);
@@ -904,6 +927,7 @@ export function ExtractionSettings({
role="button" role="button"
tabIndex={0} tabIndex={0}
aria-label={`删除字段 ${fieldName}`} aria-label={`删除字段 ${fieldName}`}
style={multiEntityEnabled && isMulti ? { color: 'rgba(255,255,255,0.8)' } : undefined}
> >
× ×
</span> </span>