import React, { useState, useEffect, useMemo } from 'react'; import { Card, Button, Modal, Form, Input, InputNumber, message, Tag, Popconfirm, Tooltip, Empty } from 'antd'; import { PlusOutlined, DeleteOutlined, FireOutlined, QuestionCircleOutlined, ReloadOutlined, EditOutlined } from '@ant-design/icons'; import { api } from '../api'; // @ts-ignore import PageTitleBar from '../components/PageTitleBar/PageTitleBar'; // @ts-ignore import ListActionBar from '../components/ListActionBar/ListActionBar'; import ListTable from '../components/ListTable/ListTable'; interface HotwordItem { id: number; word: string; pinyin: string; weight: number; } const Hotwords: React.FC = () => { const [hotwords, setHotwords] = useState([]); const [loading, setLoading] = useState(false); const [modalVisible, setModalVisible] = useState(false); const [searchText, setSearchText] = useState(''); const [currentHotword, setCurrentHotword] = useState(null); const [form] = Form.useForm(); const fetchHotwords = async () => { setLoading(true); try { const data = await api.listHotwords(); setHotwords(data); } catch (error) { message.error('获取热词列表失败'); } finally { setLoading(false); } }; useEffect(() => { fetchHotwords(); }, []); const handleSubmit = async () => { try { const values = await form.validateFields(); if (currentHotword) { await api.updateHotword(currentHotword.id, values); message.success('修改成功'); } else { await api.createHotword(values); message.success('添加成功'); } handleModalClose(); fetchHotwords(); } catch (error) { // message.error('操作失败'); } }; const handleDelete = async (id: number) => { try { await api.deleteHotword(id); message.success('删除成功'); fetchHotwords(); } catch (error) { message.error('删除失败'); } }; const handleEdit = (record: HotwordItem) => { setCurrentHotword(record); form.setFieldsValue(record); setModalVisible(true); }; const handleModalClose = () => { setModalVisible(false); setCurrentHotword(null); form.resetFields(); }; const filteredHotwords = useMemo(() => { if (!searchText) return hotwords; return hotwords.filter(item => item.word.includes(searchText) || item.pinyin.toLowerCase().includes(searchText.toLowerCase()) ); }, [hotwords, searchText]); const columns = [ { title: '热词', dataIndex: 'word', key: 'word', width: '30%', render: (t: string) => (
{t}
) }, { title: '拼音', dataIndex: 'pinyin', key: 'pinyin', width: '30%', render: (t: string) => {t} }, { title: '权重', dataIndex: 'weight', key: 'weight', width: '20%', render: (w: number) => { let color = 'default'; if (w >= 5) color = 'red'; else if (w >= 2) color = 'orange'; else if (w >= 1) color = 'green'; return ( {w}x ); } }, { title: '操作', key: 'action', width: 180, render: (_: any, record: HotwordItem) => (
handleDelete(record.id)} okText="删除" cancelText="取消" okButtonProps={{ danger: true }} >
), }, ]; return (
, onClick: () => setModalVisible(true), } ]} search={{ placeholder: "搜索热词或拼音...", value: searchText, onChange: (val: string) => setSearchText(val), width: 320 }} showRefresh onRefresh={fetchHotwords} />
{currentHotword ? '编辑热词' : '添加新热词'}
} open={modalVisible} onCancel={handleModalClose} onOk={handleSubmit} destroyOnClose width={520} okText={currentHotword ? '保存' : '添加'} cancelText="取消" >
热词文本 } rules={[{ required: true, message: '请输入热词' }]} > 权重倍数 } initialValue={2.0} >
使用说明
  • 热词生效需要一定时间,通常在下一次识别会话开始时生效。
  • 系统会自动生成拼音,无需手动输入。
  • 建议权重设置在 2.0 - 5.0 之间,过高可能导致发音相近的词被误识别。
); }; export default Hotwords;