111 lines
5.1 KiB
TypeScript
111 lines
5.1 KiB
TypeScript
import { useEffect, useMemo, useState } from 'react';
|
|
import { Plus, Search } from 'lucide-react';
|
|
import { adminApi, type AdminChannel, type ChannelReportField } from '@/api/adminApi';
|
|
import { Breadcrumb, Button, Input, Modal, Select, Table, Textarea, Tag, type TableColumn } from '@/components/ui';
|
|
|
|
export function AdminChannelReportPage() {
|
|
const [channels, setChannels] = useState<AdminChannel[]>([]);
|
|
const [fields, setFields] = useState<ChannelReportField[]>([]);
|
|
const [channelId, setChannelId] = useState('');
|
|
const [keyword, setKeyword] = useState('');
|
|
const [modalOpen, setModalOpen] = useState(false);
|
|
const [code, setCode] = useState('');
|
|
const [name, setName] = useState('');
|
|
const [fieldType, setFieldType] = useState('string');
|
|
const [description, setDescription] = useState('');
|
|
const [error, setError] = useState('');
|
|
|
|
function loadData(nextChannelId = channelId) {
|
|
Promise.all([adminApi.listChannels(), adminApi.listChannelReportFields(nextChannelId || undefined)])
|
|
.then(([channelItems, fieldItems]) => {
|
|
setChannels(channelItems.filter((item) => item.status !== 'deleted'));
|
|
setFields(fieldItems);
|
|
setError('');
|
|
})
|
|
.catch((failure: Error) => setError(failure.message || '通道报备配置加载失败'));
|
|
}
|
|
|
|
useEffect(() => {
|
|
loadData('');
|
|
}, []);
|
|
|
|
const filteredFields = useMemo(() => fields.filter((field) => !keyword || [field.code, field.name, field.fieldType, field.description].join(' ').includes(keyword)), [fields, keyword]);
|
|
|
|
function createField() {
|
|
adminApi.createChannelReportField({ channelId, code, name, fieldType, description, status: 'active' })
|
|
.then(() => {
|
|
setModalOpen(false);
|
|
setCode('');
|
|
setName('');
|
|
setFieldType('string');
|
|
setDescription('');
|
|
loadData();
|
|
})
|
|
.catch((failure: Error) => setError(failure.message || '报备字段保存失败'));
|
|
}
|
|
|
|
const columns: Array<TableColumn<ChannelReportField>> = [
|
|
{ key: 'channel', title: '通道', width: '220px', render: (record) => channels.find((item) => item.id === record.channelId)?.name ?? record.channelId },
|
|
{ key: 'code', title: '字段代码', width: '160px', render: (record) => <strong>{record.code}</strong> },
|
|
{ key: 'name', title: '字段名称', width: '160px', render: (record) => record.name },
|
|
{ key: 'type', title: '字段类型', width: '120px', render: (record) => record.fieldType },
|
|
{ key: 'required', title: '必填', width: '90px', render: (record) => <Tag tone={record.required ? 'warning' : 'info'}>{record.required ? '是' : '否'}</Tag> },
|
|
{ key: 'description', title: '说明', render: (record) => record.description ?? '-' },
|
|
];
|
|
|
|
return (
|
|
<section className="page-stack admin-system-page admin-drainage-page">
|
|
<div className="page-heading">
|
|
<div>
|
|
<Breadcrumb items={['报备管理', '通道报备配置']} />
|
|
<h1>通道报备配置</h1>
|
|
</div>
|
|
<Button disabled={!channelId} icon={<Plus size={16} />} onClick={() => setModalOpen(true)}>新增字段</Button>
|
|
</div>
|
|
{error ? <p className="form-error">{error}</p> : null}
|
|
|
|
<div className="surface admin-drainage-toolbar">
|
|
<Select
|
|
onChange={(event) => {
|
|
setChannelId(event.target.value);
|
|
loadData(event.target.value);
|
|
}}
|
|
options={[{ label: '全部通道', value: '' }, ...channels.map((item) => ({ label: item.name, value: item.id }))]}
|
|
value={channelId}
|
|
/>
|
|
<Input onChange={(event) => setKeyword(event.target.value)} placeholder="搜索字段代码、名称或说明" prefix={<Search size={16} />} value={keyword} />
|
|
<Button icon={<Search size={16} />} onClick={() => loadData()}>查询</Button>
|
|
</div>
|
|
|
|
<div className="surface admin-system-table-card admin-drainage-table-card">
|
|
<Table columns={columns} data={filteredFields} emptyText="暂无通道报备字段" rowKey="id" />
|
|
</div>
|
|
|
|
<Modal
|
|
footer={<><Button onClick={() => setModalOpen(false)} variant="ghost">取消</Button><Button disabled={!channelId || !code || !name} onClick={createField}>保存</Button></>}
|
|
onClose={() => setModalOpen(false)}
|
|
open={modalOpen}
|
|
title="新增通道报备字段"
|
|
>
|
|
<div className="admin-system-modal-form">
|
|
<Input label="字段代码" onChange={(event) => setCode(event.target.value)} value={code} />
|
|
<Input label="字段名称" onChange={(event) => setName(event.target.value)} value={name} />
|
|
<Select
|
|
label="字段类型"
|
|
onChange={(event) => setFieldType(event.target.value)}
|
|
options={[
|
|
{ label: '字符串', value: 'string' },
|
|
{ label: '数字', value: 'number' },
|
|
{ label: '文件', value: 'file' },
|
|
{ label: '图片', value: 'image' },
|
|
{ label: '网址', value: 'url' },
|
|
]}
|
|
value={fieldType}
|
|
/>
|
|
<Textarea label="说明" onChange={(event) => setDescription(event.target.value)} rows={4} value={description} />
|
|
</div>
|
|
</Modal>
|
|
</section>
|
|
);
|
|
}
|