import { useCallback, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { Typography, Button, Table, Popconfirm, message, Card, Modal, Form, Input, Space, } from "antd"; import type { TableProps } from "antd"; import { PlusOutlined, EditOutlined, DeleteOutlined, ReloadOutlined, SearchOutlined, } from "@ant-design/icons"; import type { ConfigForm, ConfigItem } from "@/api/config"; import { addConfig, deleteConfig, getConfig, getConfigPage, updateConfig, } from "@/api/config"; const { Title, Text } = Typography; const { TextArea } = Input; export function ConfigPage() { const { t } = useTranslation(); const [data, setData] = useState([]); const [loading, setLoading] = useState(false); const [submitting, setSubmitting] = useState(false); const [modalOpen, setModalOpen] = useState(false); const [editingKey, setEditingKey] = useState(null); const [total, setTotal] = useState(0); const [keyword, setKeyword] = useState(""); const [query, setQuery] = useState({ page: 1, size: 10, keyword: undefined as string | undefined }); const [form] = Form.useForm(); const fetchData = useCallback(async () => { setLoading(true); try { const res = await getConfigPage(query); setData(res.records); setTotal(res.total); } catch { // handled by request util } finally { setLoading(false); } }, [query]); useEffect(() => { fetchData(); }, [fetchData]); function handleSearch() { setQuery((prev) => ({ ...prev, page: 1, keyword: keyword.trim() || undefined, })); } function handleReset() { setKeyword(""); setQuery({ page: 1, size: 10, keyword: undefined }); } function openAdd() { setEditingKey(null); form.resetFields(); setModalOpen(true); } async function openEdit(record: ConfigItem) { setEditingKey(record.configKey); setModalOpen(true); try { const detail = await getConfig(record.configKey); form.setFieldsValue({ configKey: detail.configKey, configValue: detail.configValue, remark: detail.remark, }); } catch { setModalOpen(false); setEditingKey(null); message.error(t("config.fetchFailed")); } } async function handleSubmit() { try { const values = await form.validateFields(); setSubmitting(true); if (editingKey) { await updateConfig(values); message.success(t("config.updateSuccess")); } else { await addConfig(values); message.success(t("config.addSuccess")); } setModalOpen(false); setEditingKey(null); form.resetFields(); fetchData(); } catch { // validation or request error } finally { setSubmitting(false); } } async function handleDelete(configKey: string) { try { await deleteConfig(configKey); message.success(t("config.deleteSuccess")); fetchData(); } catch { // handled by request util } } const columns: TableProps["columns"] = [ { title: t("config.colKey"), dataIndex: "configKey", width: 220, fixed: "left", render: (val: string) => {val}, }, { title: t("config.colValue"), dataIndex: "configValue", width: 320, render: (val?: string) => (
{val || "—"}
), }, { title: t("config.colRemark"), dataIndex: "remark", width: 240, render: (val?: string) => {val || "—"}, }, { title: t("config.colCreateTime"), dataIndex: "createTime", width: 170, render: (val?: string) => val || "—", }, { title: t("config.colUpdateTime"), dataIndex: "updateTime", width: 170, render: (val?: string) => val || "—", }, { title: t("config.colActions"), key: "actions", width: 140, fixed: "right", align: "center", render: (_, record) => ( handleDelete(record.configKey)} okText={t("common.confirm")} cancelText={t("common.cancel")} > ), }, ]; return (
{t("config.title")}
} value={keyword} onChange={(e) => setKeyword(e.target.value)} onPressEnter={handleSearch} style={{ width: 320 }} allowClear />
{t("config.searchTip")}
rowKey="configKey" columns={columns} dataSource={data} loading={loading} scroll={{ x: 1200 }} size="middle" pagination={{ current: query.page, pageSize: query.size, total, showSizeChanger: true, showQuickJumper: true, showTotal: (count) => t("common.paginationTotal", { total: count }), onChange: (page, size) => setQuery((prev) => ({ ...prev, page, size })), }} /> { setModalOpen(false); setEditingKey(null); form.resetFields(); }} onOk={handleSubmit} confirmLoading={submitting} destroyOnClose >