feat: wire admin workflows to real APIs

This commit is contained in:
hectorzhao
2026-07-02 13:50:09 +08:00
parent f8c9b78c21
commit ab421cf8a7
42 changed files with 2596 additions and 250 deletions
+82 -3
View File
@@ -1,6 +1,6 @@
import { useMemo, useState } from 'react';
import { Trash2 } from 'lucide-react';
import { Breadcrumb, Button, Table, Tag, type TableColumn } from '@/components/ui';
import { Plus, Search, Trash2 } from 'lucide-react';
import { Breadcrumb, Button, Input, Modal, Select, Table, Tag, type TableColumn } from '@/components/ui';
type SensitiveLevel = 'low' | 'medium' | 'high';
@@ -32,8 +32,28 @@ const initialItems: SensitiveWordItem[] = [
{ id: 'SW20260630004', word: '免费领取', category: '普通营销', level: 'low', createdAt: '2026-06-17 17:06:51', updatedAt: '2026-06-21 09:05:14' },
];
const levelOptions = [
{ label: '低', value: 'low' },
{ label: '中', value: 'medium' },
{ label: '高', value: 'high' },
];
function nowText() {
return new Date().toLocaleString('zh-CN', { hour12: false }).replace(/\//g, '-');
}
export function AdminSensitiveWordsPage() {
const [items, setItems] = useState(initialItems);
const [keyword, setKeyword] = useState('');
const [word, setWord] = useState('');
const [category, setCategory] = useState('');
const [level, setLevel] = useState<SensitiveLevel>('medium');
const [modalOpen, setModalOpen] = useState(false);
const filteredItems = useMemo(() => items.filter((item) => {
const text = [item.word, item.category, levelLabelMap[item.level]].join(' ');
return !keyword || text.includes(keyword);
}), [items, keyword]);
const columns = useMemo<Array<TableColumn<SensitiveWordItem>>>(() => [
{ key: 'word', title: '敏感词', width: '180px', render: (record) => <strong>{record.word}</strong> },
@@ -54,6 +74,27 @@ export function AdminSensitiveWordsPage() {
},
], []);
function resetForm() {
setWord('');
setCategory('');
setLevel('medium');
}
function addItem() {
const time = nowText();
const nextItem: SensitiveWordItem = {
id: `SW${Date.now()}`,
word: word || '待补充敏感词',
category: category || '未分类',
level,
createdAt: time,
updatedAt: time,
};
setItems((current) => [nextItem, ...current]);
resetForm();
setModalOpen(false);
}
return (
<section className="page-stack admin-security-page">
<div className="page-heading">
@@ -61,11 +102,49 @@ export function AdminSensitiveWordsPage() {
<Breadcrumb items={['安全控制', '敏感词管理']} />
<h1></h1>
</div>
<Button icon={<Plus size={16} />} onClick={() => setModalOpen(true)}></Button>
</div>
<div className="surface admin-security-filter">
<Input
label="搜索"
onChange={(event) => setKeyword(event.target.value)}
placeholder="搜索敏感词、分类或级别"
prefix={<Search size={16} />}
value={keyword}
/>
<div className="admin-security-filter__actions">
<Button icon={<Search size={16} />}></Button>
<Button onClick={() => setKeyword('')} variant="ghost"></Button>
</div>
</div>
<div className="surface admin-security-table-card">
<Table columns={columns} data={items} emptyText="暂无敏感词记录" rowKey="id" />
<Table columns={columns} data={filteredItems} emptyText="暂无敏感词记录" rowKey="id" />
</div>
<Modal
footer={(
<>
<Button onClick={() => setModalOpen(false)} variant="ghost"></Button>
<Button onClick={addItem}></Button>
</>
)}
onClose={() => setModalOpen(false)}
open={modalOpen}
title="添加敏感词"
>
<div className="admin-security-form">
<Input label="敏感词" onChange={(event) => setWord(event.target.value)} placeholder="请输入敏感词" value={word} />
<Input label="分类" onChange={(event) => setCategory(event.target.value)} placeholder="请输入分类" value={category} />
<Select
label="风险级别"
onChange={(event) => setLevel(event.target.value as SensitiveLevel)}
options={levelOptions}
value={level}
/>
</div>
</Modal>
</section>
);
}