feat: sync rule management and review ui fixes
This commit is contained in:
+213
-51
@@ -222,6 +222,7 @@ function emptyFieldDraft(group = '基础信息'): FieldDraft {
|
||||
name: '',
|
||||
type: 'verbatim',
|
||||
multipleEntities: false,
|
||||
allowed: [],
|
||||
requiredFrom: 'draft',
|
||||
description: '',
|
||||
};
|
||||
@@ -245,9 +246,13 @@ function emptyVisualDraft(type = '签章'): VisualDraft {
|
||||
name: '',
|
||||
type,
|
||||
required: 'true',
|
||||
requiredFrom: '',
|
||||
signerRoles: [],
|
||||
signatureTypes: [],
|
||||
privateSealRestricted: false,
|
||||
expectedMatchField: '',
|
||||
expectedMatchAlternatives: [],
|
||||
prompt: '',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -507,6 +512,7 @@ export default function RulesTestDetail() {
|
||||
const [fieldDraft, setFieldDraft] = useState<FieldDraft>(emptyFieldDraft(pack.fields[0]?.group || '基础信息'));
|
||||
const [documentDraft, setDocumentDraft] = useState<DocumentDraft>(emptyDocumentDraft());
|
||||
const [visualDraft, setVisualDraft] = useState<VisualDraft>(emptyVisualDraft(pack.visualElements[0]?.type || '签章'));
|
||||
const [versionItems, setVersionItems] = useState<RuleVersionItem[]>(versions);
|
||||
const [selectedRollbackVersionId, setSelectedRollbackVersionId] = useState('');
|
||||
const [dependencyDialogOpen, setDependencyDialogOpen] = useState(false);
|
||||
const [dependencySearch, setDependencySearch] = useState('');
|
||||
@@ -524,6 +530,7 @@ export default function RulesTestDetail() {
|
||||
setFields(pack.fields);
|
||||
setSubDocuments(pack.subDocuments);
|
||||
setVisualElements(pack.visualElements);
|
||||
setVersionItems(versions);
|
||||
setSelectedRuleKey(requestedRuleId || ruleKey(pack.rules[0] || { id: '', ruleId: '' }));
|
||||
setEditor(null);
|
||||
setDependencyDialogOpen(false);
|
||||
@@ -535,7 +542,7 @@ export default function RulesTestDetail() {
|
||||
setDraftSaved(false);
|
||||
setSaveMessage('');
|
||||
setSaveError('');
|
||||
}, [pack.id, requestedRuleId]);
|
||||
}, [pack.currentVersionId, pack.fallbackVersionId, pack.id, pack.resolvedVersionId, pack.yamlSource, requestedRuleId, versions]);
|
||||
|
||||
const currentRule = useMemo(() => {
|
||||
return rules.find(rule => rule.id === selectedRuleKey || rule.ruleId === selectedRuleKey) || rules[0];
|
||||
@@ -640,46 +647,47 @@ export default function RulesTestDetail() {
|
||||
const rulesById = useMemo(() => new Map(rules.map(rule => [rule.ruleId || rule.id, rule])), [rules]);
|
||||
const saveButtonBusy = saveFetcher.state !== 'idle';
|
||||
const latestDraftVersion = useMemo(
|
||||
() => versions.find((item) => !['published', 'rollback'].includes(item.status)),
|
||||
[versions],
|
||||
() => versionItems.find((item) => !['published', 'rollback'].includes(item.status)),
|
||||
[versionItems],
|
||||
);
|
||||
const rollbackVersionOptions = useMemo(
|
||||
() => versions,
|
||||
[versions],
|
||||
() => versionItems,
|
||||
[versionItems],
|
||||
);
|
||||
const rollbackOptions = useMemo(
|
||||
() => rollbackVersionOptions.filter((item) => item.id !== pack.currentVersionId),
|
||||
[rollbackVersionOptions, pack.currentVersionId],
|
||||
);
|
||||
const rollbackTargetVersion = useMemo(
|
||||
() => rollbackOptions.find((item) => String(item.id) === selectedRollbackVersionId) || rollbackOptions[0] || null,
|
||||
[rollbackOptions, selectedRollbackVersionId],
|
||||
);
|
||||
const packFilterMainType = pack.businessType || pack.mainType;
|
||||
const currentResolvedVersion = useMemo(
|
||||
() => {
|
||||
if (pack.currentVersionId) {
|
||||
return versions.find((item) => item.id === pack.currentVersionId) || null;
|
||||
return versionItems.find((item) => item.id === pack.currentVersionId) || null;
|
||||
}
|
||||
if (pack.fallbackVersionId) {
|
||||
return versions.find((item) => item.id === pack.fallbackVersionId) || null;
|
||||
return versionItems.find((item) => item.id === pack.fallbackVersionId) || null;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
[pack.currentVersionId, pack.fallbackVersionId, versions],
|
||||
[pack.currentVersionId, pack.fallbackVersionId, versionItems],
|
||||
);
|
||||
const versionStatusLabel = (status: string | undefined) => {
|
||||
const normalized = String(status || '').trim().toLowerCase();
|
||||
if (normalized === 'published') return '已发布';
|
||||
if (normalized === 'rollback') return '回滚版本';
|
||||
if (normalized === 'rollback') return '被回滚替换';
|
||||
if (normalized === 'draft') return '草稿';
|
||||
if (normalized === 'deprecated') return '已废弃';
|
||||
if (normalized === 'deprecated') return '历史废弃版本';
|
||||
return status || '-';
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedRollbackVersionId('');
|
||||
}, [pack.id, pack.currentVersionId, versions.length]);
|
||||
const hasSelectedVersion = rollbackOptions.some((item) => String(item.id) === selectedRollbackVersionId);
|
||||
const selectedIsCurrent = selectedRollbackVersionId !== '' && String(pack.currentVersionId || '') === selectedRollbackVersionId;
|
||||
if (hasSelectedVersion && !selectedIsCurrent) {
|
||||
return;
|
||||
}
|
||||
setSelectedRollbackVersionId(rollbackOptions[0] ? String(rollbackOptions[0].id) : '');
|
||||
}, [pack.currentVersionId, rollbackOptions, selectedRollbackVersionId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!saveFetcher.data) return;
|
||||
@@ -687,12 +695,35 @@ export default function RulesTestDetail() {
|
||||
setDraftSaved(saveFetcher.data.intent === 'save');
|
||||
setSaveError('');
|
||||
if (saveFetcher.data.intent === 'save') {
|
||||
if (saveFetcher.data.versionId) {
|
||||
setVersionItems((current) => {
|
||||
const nextVersion: RuleVersionItem = {
|
||||
id: saveFetcher.data?.versionId || 0,
|
||||
ruleSetId: current[0]?.ruleSetId || 0,
|
||||
versionNo: saveFetcher.data?.versionNo || '-',
|
||||
status: 'draft',
|
||||
ossUrl: current.find((item) => item.id === saveFetcher.data?.versionId)?.ossUrl || '',
|
||||
changeNote: 'rulesTest.detail 保存评查点草稿',
|
||||
publishedAt: current.find((item) => item.id === saveFetcher.data?.versionId)?.publishedAt || null,
|
||||
};
|
||||
const existed = current.some((item) => item.id === nextVersion.id);
|
||||
if (existed) {
|
||||
return current.map((item) => (item.id === nextVersion.id ? { ...item, ...nextVersion } : item));
|
||||
}
|
||||
return [nextVersion, ...current];
|
||||
});
|
||||
}
|
||||
setSaveMessage(saveFetcher.data.versionNo
|
||||
? `规则草稿已保存为版本 ${saveFetcher.data.versionNo}`
|
||||
: saveFetcher.data.message || '规则草稿已保存');
|
||||
} else {
|
||||
setSaveMessage(saveFetcher.data.message || (saveFetcher.data.intent === 'publish' ? '规则版本已发布' : '规则版本已回滚'));
|
||||
return;
|
||||
}
|
||||
if (saveFetcher.data.intent === 'publish') {
|
||||
setSaveMessage(saveFetcher.data.message || (saveFetcher.data.intent === 'publish' ? '规则版本已发布' : '规则版本已回滚'));
|
||||
revalidator.revalidate();
|
||||
return;
|
||||
}
|
||||
setSaveMessage(saveFetcher.data.message || '规则版本已回滚');
|
||||
revalidator.revalidate();
|
||||
return;
|
||||
}
|
||||
@@ -839,6 +870,7 @@ export default function RulesTestDetail() {
|
||||
group: fieldDraft.group || '未分组',
|
||||
requiredFrom: fieldDraft.requiredFrom || 'draft',
|
||||
type: fieldDraft.type || 'verbatim',
|
||||
allowed: fieldDraft.type === 'enum' ? (fieldDraft.allowed || []).map((item) => String(item || '').trim()).filter(Boolean) : [],
|
||||
description: fieldDraft.description || '',
|
||||
};
|
||||
setFields((current) => editor.mode === 'edit'
|
||||
@@ -879,6 +911,7 @@ export default function RulesTestDetail() {
|
||||
group: field.group || '未分组',
|
||||
requiredFrom: field.requiredFrom || '-',
|
||||
type: field.type || 'verbatim',
|
||||
allowed: field.type === 'enum' ? (field.allowed || []).map((item) => String(item || '').trim()).filter(Boolean) : [],
|
||||
})),
|
||||
};
|
||||
setSubDocuments((current) => editor.mode === 'edit'
|
||||
@@ -927,6 +960,7 @@ export default function RulesTestDetail() {
|
||||
name: '',
|
||||
type: 'verbatim',
|
||||
multipleEntities: false,
|
||||
allowed: [],
|
||||
requiredFrom: '-',
|
||||
description: '',
|
||||
},
|
||||
@@ -951,15 +985,20 @@ export default function RulesTestDetail() {
|
||||
const previousVisual = editor.mode === 'edit'
|
||||
? visualElements.find((item) => item.id === editor.id)
|
||||
: undefined;
|
||||
const normalizedType = visualDraft.type || '签章';
|
||||
const normalizedVisual: VisualElementSummary = {
|
||||
...visualDraft,
|
||||
id: visualDraft.id || makeId('visual'),
|
||||
name: visualDraft.name || visualDraft.id,
|
||||
type: visualDraft.type || '签章',
|
||||
type: normalizedType,
|
||||
required: visualDraft.required || 'true',
|
||||
signerRoles: (visualDraft.signerRoles || []).filter(Boolean),
|
||||
requiredFrom: visualDraft.requiredFrom || '',
|
||||
signerRoles: normalizedType === '签名' ? (visualDraft.signerRoles || []).filter(Boolean) : [],
|
||||
signatureTypes: (visualDraft.signatureTypes || []).filter(Boolean),
|
||||
privateSealRestricted: Boolean(visualDraft.privateSealRestricted),
|
||||
privateSealRestricted: normalizedType === '签名' ? Boolean(visualDraft.privateSealRestricted) : false,
|
||||
expectedMatchField: visualDraft.expectedMatchField || '',
|
||||
expectedMatchAlternatives: (visualDraft.expectedMatchAlternatives || []).filter(Boolean),
|
||||
prompt: normalizedType === '骑缝章' ? (visualDraft.prompt || '') : '',
|
||||
};
|
||||
setVisualElements((current) => editor.mode === 'edit'
|
||||
? current.map((item) => (item.id === editor.id ? normalizedVisual : item))
|
||||
@@ -974,7 +1013,7 @@ export default function RulesTestDetail() {
|
||||
previousVisual ? { from: `visual.${previousVisual.id}`, to: `visual.${normalizedVisual.id}` } : null,
|
||||
previousVisual ? { from: `visual.${previousVisual.name || previousVisual.id}`, to: `visual.${normalizedVisual.name || normalizedVisual.id}` } : null,
|
||||
].filter(Boolean) as Array<{ from: string; to: string }>,
|
||||
[`visual.${normalizedVisual.id}`],
|
||||
[`visual.${normalizedVisual.name || normalizedVisual.id}`],
|
||||
);
|
||||
setEditor(null);
|
||||
};
|
||||
@@ -1027,6 +1066,7 @@ export default function RulesTestDetail() {
|
||||
};
|
||||
|
||||
const rollbackRuleVersion = () => {
|
||||
const rollbackTargetVersion = rollbackOptions.find((item) => String(item.id) === selectedRollbackVersionId) || null;
|
||||
if (!rollbackTargetVersion) {
|
||||
setSaveError('当前没有可回滚的历史可用版本。');
|
||||
setSaveMessage('');
|
||||
@@ -1119,7 +1159,7 @@ export default function RulesTestDetail() {
|
||||
</button>
|
||||
<select
|
||||
className="rules-version-select"
|
||||
value={rollbackTargetVersion ? String(rollbackTargetVersion.id) : selectedRollbackVersionId}
|
||||
value={selectedRollbackVersionId}
|
||||
onChange={(event) => setSelectedRollbackVersionId(event.target.value)}
|
||||
disabled={saveButtonBusy || rollbackVersionOptions.length === 0}
|
||||
>
|
||||
@@ -1131,11 +1171,11 @@ export default function RulesTestDetail() {
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<button type="button" className="ant-btn ant-btn-default" disabled={saveButtonBusy || !rollbackTargetVersion} onClick={rollbackRuleVersion}>
|
||||
<button type="button" className="ant-btn ant-btn-default" disabled={saveButtonBusy || !selectedRollbackVersionId} onClick={rollbackRuleVersion}>
|
||||
<i className="ri-history-line mr-1.5"></i>回滚版本
|
||||
</button>
|
||||
<button type="button" className="ant-btn ant-btn-primary" disabled={!currentRule} onClick={() => currentRule && openRuleEditor(currentRule)}>
|
||||
<i className="ri-edit-line mr-1.5"></i>编辑评查点
|
||||
<button type="button" className="ant-btn ant-btn-primary" onClick={() => currentRule ? openRuleEditor(currentRule) : openRuleEditor()}>
|
||||
<i className={`${currentRule ? 'ri-edit-line' : 'ri-add-line'} mr-1.5`}></i>{currentRule ? '编辑评查点' : '新增评查点'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1305,7 +1345,7 @@ export default function RulesTestDetail() {
|
||||
<div key={item.id} className="config-item-card">
|
||||
<div className="config-item-main">
|
||||
<strong>{item.name || item.id}</strong>
|
||||
<span>{item.type} / {item.id}</span>
|
||||
<span>{item.type}</span>
|
||||
<span>{requiredFromLabel(String(item.required))}{item.signatureTypes && item.signatureTypes.length > 0 ? ` · ${item.signatureTypes.join('、')}` : ''}</span>
|
||||
</div>
|
||||
<div className="config-item-actions">
|
||||
@@ -1421,9 +1461,101 @@ export default function RulesTestDetail() {
|
||||
</Card>
|
||||
</>
|
||||
) : (
|
||||
<Card className="ant-card">
|
||||
<div className="empty-state">当前链接没有匹配到评查点,请返回列表重新进入。</div>
|
||||
</Card>
|
||||
<>
|
||||
<Card className="ant-card">
|
||||
<div className="empty-state">
|
||||
当前子类型还没有正式评查点。你可以先新增评查点,或先维护抽取字段 / 子文档 / 视觉要素后再回到这里补规则。
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card className="ant-card" title="抽取字段">
|
||||
<div className="config-section-tools">
|
||||
<span className="config-section-tip">这里维护当前子类型可复用的抽取字段;新增评查点后再在“依赖字段”中引用。</span>
|
||||
<button type="button" className="ant-btn ant-btn-default" onClick={() => openFieldEditor()}>
|
||||
<i className="ri-add-line mr-1.5"></i>新增字段
|
||||
</button>
|
||||
</div>
|
||||
{fields.length > 0 ? (
|
||||
<div className="config-item-list">
|
||||
{fields.map((field) => (
|
||||
<div key={field.id} className="config-item-card">
|
||||
<div className="config-item-main">
|
||||
<strong>{field.name}</strong>
|
||||
<span>{field.group || '未分组'} / {fieldTypeLabel(field.type)}</span>
|
||||
<span>
|
||||
{requiredFromLabel(field.requiredFrom || '-')}
|
||||
{field.type === 'enum' && field.allowed && field.allowed.length > 0 ? ` · ${field.allowed.join('、')}` : ''}
|
||||
{field.description ? ` · ${field.description}` : ''}
|
||||
</span>
|
||||
</div>
|
||||
<div className="config-item-actions">
|
||||
<button type="button" className="ant-btn ant-btn-default" onClick={() => openFieldEditor(field)}>编辑</button>
|
||||
<button type="button" className="ant-btn ant-btn-default" onClick={() => removeField(field.id)}>删除</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="empty-state">当前还没有配置抽取字段。</div>
|
||||
)}
|
||||
</Card>
|
||||
|
||||
<Card className="ant-card" title="子文档 / 文书">
|
||||
<div className="config-section-tools">
|
||||
<span className="config-section-tip">案卷场景可先把常用文书与内部字段配好,后续评查点直接引用。</span>
|
||||
<button type="button" className="ant-btn ant-btn-default" onClick={() => openDocumentEditor()}>
|
||||
<i className="ri-add-line mr-1.5"></i>新增子文档
|
||||
</button>
|
||||
</div>
|
||||
{subDocuments.length > 0 ? (
|
||||
<div className="config-item-list">
|
||||
{subDocuments.map((document) => (
|
||||
<div key={document.id} className="config-item-card">
|
||||
<div className="config-item-main">
|
||||
<strong>{document.name}</strong>
|
||||
<span>{document.id} / {requiredFromLabel(document.required || '-')}</span>
|
||||
<span>{document.fields.length} 个字段{document.groups.length > 0 ? ` · ${document.groups.join('、')}` : ''}</span>
|
||||
</div>
|
||||
<div className="config-item-actions">
|
||||
<button type="button" className="ant-btn ant-btn-default" onClick={() => openDocumentEditor(document)}>编辑</button>
|
||||
<button type="button" className="ant-btn ant-btn-default" onClick={() => removeDocument(document.id)}>删除</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="empty-state">当前还没有配置子文档。</div>
|
||||
)}
|
||||
</Card>
|
||||
|
||||
<Card className="ant-card" title="视觉要素">
|
||||
<div className="config-section-tools">
|
||||
<span className="config-section-tip">这里维护签章、签名、骑缝章等可复用视觉要素,新增评查点后再按需引用。</span>
|
||||
<button type="button" className="ant-btn ant-btn-default" onClick={() => openVisualEditor()}>
|
||||
<i className="ri-add-line mr-1.5"></i>新增视觉要素
|
||||
</button>
|
||||
</div>
|
||||
{visualElements.length > 0 ? (
|
||||
<div className="config-item-list">
|
||||
{visualElements.map((item) => (
|
||||
<div key={item.id} className="config-item-card">
|
||||
<div className="config-item-main">
|
||||
<strong>{item.name || item.id}</strong>
|
||||
<span>{item.type}</span>
|
||||
<span>{requiredFromLabel(String(item.required))}{item.signatureTypes && item.signatureTypes.length > 0 ? ` · ${item.signatureTypes.join('、')}` : ''}</span>
|
||||
</div>
|
||||
<div className="config-item-actions">
|
||||
<button type="button" className="ant-btn ant-btn-default" onClick={() => openVisualEditor(item)}>编辑</button>
|
||||
<button type="button" className="ant-btn ant-btn-default" onClick={() => removeVisual(item.id)}>删除</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="empty-state">当前还没有配置视觉要素。</div>
|
||||
)}
|
||||
</Card>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1603,7 +1735,7 @@ export default function RulesTestDetail() {
|
||||
<div className="drawer-grid">
|
||||
<label>
|
||||
<span>字段类型</span>
|
||||
<select value={fieldDraft.type} onChange={(event) => setFieldDraft({ ...fieldDraft, type: event.target.value })}>
|
||||
<select value={fieldDraft.type} onChange={(event) => setFieldDraft({ ...fieldDraft, type: event.target.value, allowed: event.target.value === 'enum' ? (fieldDraft.allowed || []) : [] })}>
|
||||
{['verbatim', 'string', 'money', 'date', 'enum', 'number'].map((type) => <option key={type} value={type}>{fieldTypeLabel(type)}</option>)}
|
||||
</select>
|
||||
</label>
|
||||
@@ -1614,6 +1746,16 @@ export default function RulesTestDetail() {
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
{fieldDraft.type === 'enum' && (
|
||||
<label>
|
||||
<span>可选值</span>
|
||||
<input
|
||||
value={(fieldDraft.allowed || []).join(',')}
|
||||
onChange={(event) => setFieldDraft({ ...fieldDraft, allowed: event.target.value.split(/[,,]/).map((item) => item.trim()).filter(Boolean) })}
|
||||
placeholder="如:有,无;男,女"
|
||||
/>
|
||||
</label>
|
||||
)}
|
||||
<label>
|
||||
<span>字段说明</span>
|
||||
<textarea value={fieldDraft.description} onChange={(event) => setFieldDraft({ ...fieldDraft, description: event.target.value })} placeholder="描述字段如何抽取、给规则如何引用" />
|
||||
@@ -1658,12 +1800,19 @@ export default function RulesTestDetail() {
|
||||
/>
|
||||
<select
|
||||
value={field.type || 'verbatim'}
|
||||
onChange={(event) => updateDocumentField(field.id, { type: event.target.value })}
|
||||
onChange={(event) => updateDocumentField(field.id, { type: event.target.value, allowed: event.target.value === 'enum' ? (field.allowed || []) : [] })}
|
||||
>
|
||||
{['verbatim', 'string', 'money', 'date', 'enum', 'number'].map((type) => (
|
||||
<option key={type} value={type}>{fieldTypeLabel(type)}</option>
|
||||
))}
|
||||
</select>
|
||||
{field.type === 'enum' && (
|
||||
<input
|
||||
value={(field.allowed || []).join(',')}
|
||||
onChange={(event) => updateDocumentField(field.id, { allowed: event.target.value.split(/[,,]/).map((item) => item.trim()).filter(Boolean) })}
|
||||
placeholder="可选值"
|
||||
/>
|
||||
)}
|
||||
<input
|
||||
value={field.description || ''}
|
||||
onChange={(event) => updateDocumentField(field.id, { description: event.target.value })}
|
||||
@@ -1697,7 +1846,16 @@ export default function RulesTestDetail() {
|
||||
<div className="drawer-grid">
|
||||
<label>
|
||||
<span>要素类型</span>
|
||||
<select value={visualDraft.type} onChange={(event) => setVisualDraft({ ...visualDraft, type: event.target.value })}>
|
||||
<select
|
||||
value={visualDraft.type}
|
||||
onChange={(event) => setVisualDraft((current) => ({
|
||||
...current,
|
||||
type: event.target.value,
|
||||
signerRoles: event.target.value === '签名' ? current.signerRoles || [] : [],
|
||||
privateSealRestricted: event.target.value === '签名' ? Boolean(current.privateSealRestricted) : false,
|
||||
prompt: event.target.value === '骑缝章' ? current.prompt || '' : '',
|
||||
}))}
|
||||
>
|
||||
{['签章', '签名', '骑缝章'].map((type) => <option key={type} value={type}>{type}</option>)}
|
||||
</select>
|
||||
</label>
|
||||
@@ -1709,29 +1867,33 @@ export default function RulesTestDetail() {
|
||||
</label>
|
||||
</div>
|
||||
<label>
|
||||
<span>签章类型(逗号分隔)</span>
|
||||
<span>{visualDraft.type === '签名' ? '签名类型(逗号分隔)' : '签章类型(逗号分隔)'}</span>
|
||||
<input
|
||||
value={(visualDraft.signatureTypes || []).join(',')}
|
||||
onChange={(event) => setVisualDraft({ ...visualDraft, signatureTypes: event.target.value.split(/[,,]/).map((item) => item.trim()).filter(Boolean) })}
|
||||
placeholder="如:合同专用章,公章"
|
||||
placeholder={visualDraft.type === '签名' ? '如:签名,私章' : '如:合同专用章,公章'}
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
<span>签署角色(逗号分隔)</span>
|
||||
<input
|
||||
value={(visualDraft.signerRoles || []).join(',')}
|
||||
onChange={(event) => setVisualDraft({ ...visualDraft, signerRoles: event.target.value.split(/[,,]/).map((item) => item.trim()).filter(Boolean) })}
|
||||
placeholder="如:甲方,乙方,承办人"
|
||||
/>
|
||||
</label>
|
||||
<label className="drawer-checkbox-row">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={Boolean(visualDraft.privateSealRestricted)}
|
||||
onChange={(event) => setVisualDraft({ ...visualDraft, privateSealRestricted: event.target.checked })}
|
||||
/>
|
||||
<span>限制为私章 / 私人签章场景</span>
|
||||
</label>
|
||||
{visualDraft.type === '签名' && (
|
||||
<>
|
||||
<label>
|
||||
<span>签署角色(逗号分隔)</span>
|
||||
<input
|
||||
value={(visualDraft.signerRoles || []).join(',')}
|
||||
onChange={(event) => setVisualDraft({ ...visualDraft, signerRoles: event.target.value.split(/[,,]/).map((item) => item.trim()).filter(Boolean) })}
|
||||
placeholder="如:甲方,乙方,承办人"
|
||||
/>
|
||||
</label>
|
||||
<label className="drawer-checkbox-row">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={Boolean(visualDraft.privateSealRestricted)}
|
||||
onChange={(event) => setVisualDraft({ ...visualDraft, privateSealRestricted: event.target.checked })}
|
||||
/>
|
||||
<span>限制为私章 / 私人签章场景</span>
|
||||
</label>
|
||||
</>
|
||||
)}
|
||||
<div className="drawer-actions">
|
||||
<Button type="default" onClick={() => setEditor(null)}>取消</Button>
|
||||
<Button type="primary" onClick={saveVisual}>保存视觉要素</Button>
|
||||
|
||||
Reference in New Issue
Block a user