From deda039c963d68604bbc510c9cb57e4be2512d3b Mon Sep 17 00:00:00 2001 From: fengsilin Date: Tue, 24 Mar 2026 11:38:13 +0800 Subject: [PATCH] feat: add PricingTagManager component --- .../pages/Setting/Ratio/PricingTagManager.jsx | 216 ++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 web/src/pages/Setting/Ratio/PricingTagManager.jsx diff --git a/web/src/pages/Setting/Ratio/PricingTagManager.jsx b/web/src/pages/Setting/Ratio/PricingTagManager.jsx new file mode 100644 index 0000000..5ab1711 --- /dev/null +++ b/web/src/pages/Setting/Ratio/PricingTagManager.jsx @@ -0,0 +1,216 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import React, { useState, useEffect, useCallback, useRef } from 'react'; +import { + Button, + Table, + Modal, + Form, + Input, + Space, + Popconfirm, + Typography, + Tag as SemiTag, +} from '@douyinfe/semi-ui'; +import { IconPlus, IconEdit, IconDelete } from '@douyinfe/semi-icons'; +import { useTranslation } from 'react-i18next'; +import { pricingTagApi } from '../../../helpers/api'; +import { showError, showSuccess } from '../../../helpers'; + +const PricingTagManager = () => { + const { t } = useTranslation(); + const [tags, setTags] = useState([]); + const [loading, setLoading] = useState(false); + const [modalVisible, setModalVisible] = useState(false); + const [editingTag, setEditingTag] = useState(null); + const formRef = useRef(); + + const loadTags = useCallback(async () => { + setLoading(true); + try { + const res = await pricingTagApi.getAll(); + if (res.data.success) { + setTags(res.data.data); + } + } catch (e) { + showError(e); + } finally { + setLoading(false); + } + }, []); + + useEffect(() => { + loadTags(); + }, [loadTags]); + + const handleCreate = () => { + setEditingTag(null); + setModalVisible(true); + }; + + const handleEdit = (record) => { + setEditingTag(record); + setModalVisible(true); + }; + + const handleDelete = async (id) => { + try { + const res = await pricingTagApi.delete(id); + if (res.data.success) { + showSuccess(t('删除成功')); + loadTags(); + } + } catch (e) { + showError(e); + } + }; + + const handleSubmit = async () => { + try { + const values = await formRef.current.validate(); + if (editingTag) { + const res = await pricingTagApi.update(editingTag.id, values); + if (res.data.success) { + showSuccess(t('更新成功')); + setModalVisible(false); + loadTags(); + } + } else { + const res = await pricingTagApi.create(values); + if (res.data.success) { + showSuccess(t('创建成功')); + setModalVisible(false); + loadTags(); + } + } + } catch (e) { + showError(e); + } + }; + + const columns = [ + { + title: t('标签名称'), + dataIndex: 'name', + key: 'name', + render: (text, record) => ( + + {text} + + ), + }, + { + title: t('颜色'), + dataIndex: 'color', + key: 'color', + render: (color) => ( +
+
+ {color} +
+ ), + }, + { + title: t('描述'), + dataIndex: 'description', + key: 'description', + }, + { + title: t('排序'), + dataIndex: 'sort_order', + key: 'sort_order', + width: 80, + }, + { + title: t('操作'), + key: 'action', + width: 150, + render: (_, record) => ( + + +
+ + + + setModalVisible(false)} + onOk={handleSubmit} + > +
(formRef.current = api)} initValues={editingTag}> + + + + + +
+ + ); +}; + +export default PricingTagManager;