import { useEffect, useMemo, useState } from 'react'; import { ArrowDown, ArrowUp, Database, Edit3, FileCheck2, Link2, Plus, Search, Trash2 } from 'lucide-react'; import { Breadcrumb, Button, Input, Modal, Select, Textarea, Tag } from '@/components/ui'; import { adminApi, type CommonReportField, type DictionaryItem } from '@/api/adminApi'; type DrainageField = DictionaryItem & { code?: string; name?: string; fieldType?: string; required?: boolean; description?: string | null; usageCount?: number; commonUsageCount?: number; }; type ReportFieldType = 'string' | 'image' | 'file'; const typeOptions = [ { label: '全部类型', value: 'all' }, { label: '字符串', value: 'string' }, { label: '图片', value: 'image' }, { label: '文件', value: 'file' }, ]; const typeLabels: Record = { string: '字符串', image: '图片', file: '文件' }; export function AdminDrainageFieldsPage() { const [fields, setFields] = useState([]); const [commonFields, setCommonFields] = useState([]); const [keyword, setKeyword] = useState(''); const [appliedKeyword, setAppliedKeyword] = useState(''); const [type, setType] = useState('all'); const [appliedType, setAppliedType] = useState('all'); const [creating, setCreating] = useState(false); const [editingField, setEditingField] = useState(null); const [fieldSaving, setFieldSaving] = useState(false); const [code, setCode] = useState(''); const [name, setName] = useState(''); const [fieldType, setFieldType] = useState('string'); const [description, setDescription] = useState(''); const [error, setError] = useState(''); const [deleteTarget, setDeleteTarget] = useState(null); const [configuringCommon, setConfiguringCommon] = useState(false); const [editingCommonId, setEditingCommonId] = useState(); const [commonSaving, setCommonSaving] = useState(false); const [commonFieldId, setCommonFieldId] = useState(''); const [commonReportType, setCommonReportType] = useState<'signature' | 'drainage'>('signature'); const [commonRequired, setCommonRequired] = useState(false); const [commonDeleteTarget, setCommonDeleteTarget] = useState(null); const [commonOrderingId, setCommonOrderingId] = useState(); const codeError = code && !/^[A-Za-z0-9]+$/.test(code) ? '字段代码只能包含阿拉伯数字和英文大小写字母' : ''; function loadData() { Promise.all([adminApi.listDrainageFields(), adminApi.listCommonReportFields()]) .then(([items, commonItems]) => { setFields(items as DrainageField[]); setCommonFields(commonItems); setError(''); }) .catch((failure: Error) => setError(failure.message || '报备字段加载失败')); } useEffect(() => { loadData(); }, []); const filteredFields = useMemo( () => fields.filter((field) => { const matchesKeyword = !appliedKeyword || [field.code, field.name, field.fieldType, field.description].some((value) => String(value ?? '').includes(appliedKeyword), ); const matchesType = appliedType === 'all' || field.fieldType === appliedType; return matchesKeyword && matchesType; }), [appliedKeyword, appliedType, fields], ); function closeFieldModal() { setCreating(false); setEditingField(null); setCode(''); setName(''); setFieldType('string'); setDescription(''); } function openFieldModal(field?: DrainageField) { setEditingField(field ?? null); setCode(field?.code ?? ''); setName(field?.name ?? ''); setFieldType((field?.fieldType as ReportFieldType | undefined) ?? 'string'); setDescription(field?.description ?? ''); setError(''); setCreating(true); } function saveField() { if (fieldSaving) return; setFieldSaving(true); const request = editingField ? adminApi.updateDrainageField(editingField.id, { code, name, fieldType, description }) : adminApi.createDrainageField({ code, name, fieldType, description, status: 'active' }); request .then(() => { closeFieldModal(); loadData(); }) .catch((failure: Error) => setError(failure.message || '报备字段保存失败')) .finally(() => setFieldSaving(false)); } function deleteField() { if (!deleteTarget || (deleteTarget.usageCount ?? 0) > 0 || (deleteTarget.commonUsageCount ?? 0) > 0) return; adminApi .deleteDrainageField(deleteTarget.id) .then(() => { setDeleteTarget(null); loadData(); }) .catch((failure: Error) => setError(failure.message || '报备字段删除失败')); } function createCommonField() { if (!commonFieldId || commonSaving) return; setCommonSaving(true); setError(''); const body = { drainageFieldId: commonFieldId, reportType: commonReportType, required: commonRequired }; const request = editingCommonId ? adminApi.updateCommonReportField(editingCommonId, body) : adminApi.createCommonReportField(body); request .then(() => { setCommonFieldId(''); setCommonReportType('signature'); setCommonRequired(false); setConfiguringCommon(false); loadData(); }) .catch((failure: Error) => setError(failure.message || '通用字段配置失败')) .finally(() => setCommonSaving(false)); } function openCommonField(field?: CommonReportField) { setEditingCommonId(field?.id); setCommonFieldId(field?.drainageFieldId ?? ''); setCommonReportType(field?.reportType ?? 'signature'); setCommonRequired(field?.required ?? false); setError(''); setConfiguringCommon(true); } function deleteCommonField() { if (!commonDeleteTarget) return; adminApi .deleteCommonReportField(commonDeleteTarget.id) .then(() => { setCommonDeleteTarget(null); loadData(); }) .catch((failure: Error) => setError(failure.message || '通用字段删除失败')); } async function moveCommonField(field: CommonReportField, direction: -1 | 1) { if (commonOrderingId) return; const group = commonFields.filter((item) => item.reportType === field.reportType); const currentIndex = group.findIndex((item) => item.id === field.id); const targetIndex = currentIndex + direction; if (currentIndex < 0 || targetIndex < 0 || targetIndex >= group.length) return; const ids = group.map((item) => item.id); [ids[currentIndex], ids[targetIndex]] = [ids[targetIndex], ids[currentIndex]]; setCommonOrderingId(field.id); setError(''); try { await adminApi.reorderCommonReportFields({ reportType: field.reportType, ids }); loadData(); } catch (failure) { setError(failure instanceof Error ? failure.message : '通用字段顺序调整失败'); } finally { setCommonOrderingId(undefined); } } const signatureCommon = commonFields.filter((field) => field.reportType === 'signature'); const drainageCommon = commonFields.filter((field) => field.reportType === 'drainage'); const referencedCount = fields.filter( (field) => (field.usageCount ?? 0) > 0 || (field.commonUsageCount ?? 0) > 0, ).length; return (

报备字段库

统一维护签名和引流信息的资料字段,并配置全平台通用报备要求。

{error ?

{error}

: null}
{fields.length}

字段总数

{commonFields.length}

通用字段配置

{referencedCount}

已被引用字段

setKeyword(event.target.value)} placeholder="搜索字段名称、代码或描述..." prefix={} value={keyword} /> setCommonFieldId(event.target.value)} options={[ { label: '请选择字段', value: '' }, ...fields .filter((field) => field.status !== 'deleted') .map((field) => ({ label: `${field.name}(${field.code})`, value: field.id })), ]} value={commonFieldId} /> setCommonRequired(event.target.value === 'true')} options={[ { label: '选填', value: 'false' }, { label: '必填', value: 'true' }, ]} value={String(commonRequired)} />

修改后用于后续新增、编辑时的资料要求;历史报备资料和要求快照保持不变。

{error ?

{error}

: null}
} onClose={closeFieldModal} open={creating} title={editingField ? '编辑报备字段' : '添加报备字段'} >
0 || (editingField.commonUsageCount ?? 0) > 0), )} error={codeError} label="字段代码" onChange={(event) => setCode(event.target.value)} placeholder="仅允许数字和英文字母" value={code} /> setName(event.target.value)} value={name} />