From d07224e658b01082f23a8413904dd9002496e306 Mon Sep 17 00:00:00 2001 From: t0ng7u Date: Fri, 27 Jun 2025 07:25:46 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=81=20refactor(ui/redemption):=20migra?= =?UTF-8?q?te=20EditRedemption=20page=20to=20Semi=20Form=20&=20enhance=20U?= =?UTF-8?q?X?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SUMMARY • Re-implemented `web/src/pages/Redemption/EditRedemption.js` with Semi Form components, removing legacy local-state handling. • Added `formApiRef` for centralized control; external “Submit” button now triggers `formApi.submitForm()`. • Replaced `Input/AutoComplete/DatePicker` etc. with `` fields, leveraging built-in validation & accessibility. • Field validations: – `name` (create only), `quota`, `count` → required with localized messages. • Expiration-time flow: – Default value `null` (no more 1970-01-01). – When loading data, convert 0 → null, timestamp → Date. – On submit, Date → unix seconds; empty → 0. • Responsive grid layout (`Row/Col`) for tidy alignment. • Added helpful `showClear` & full-width styling for inputs; quota presets retained. • Cleaned unused imports & handlers; fixed linter issues. RESULT The Redemption form now benefits from higher performance, clearer validation, and a cleaner codebase consistent with Semi Design best practices. --- web/src/i18n/locales/en.json | 4 +- web/src/pages/Redemption/EditRedemption.js | 271 +++++++++++---------- 2 files changed, 146 insertions(+), 129 deletions(-) diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json index 2cbb10e9..596285af 100644 --- a/web/src/i18n/locales/en.json +++ b/web/src/i18n/locales/en.json @@ -1745,5 +1745,7 @@ "已复制 ${count} 个模型": "Copied ${count} models", "复制失败,请手动复制": "Copy failed, please copy manually", "快捷设置": "Quick settings", - "批量创建时会在名称后自动添加随机后缀": "When creating in batches, a random suffix will be automatically added to the name" + "批量创建时会在名称后自动添加随机后缀": "When creating in batches, a random suffix will be automatically added to the name", + "额度必须大于0": "Quota must be greater than 0", + "生成数量必须大于0": "Generation quantity must be greater than 0" } \ No newline at end of file diff --git a/web/src/pages/Redemption/EditRedemption.js b/web/src/pages/Redemption/EditRedemption.js index 81cdaa4d..b13d7251 100644 --- a/web/src/pages/Redemption/EditRedemption.js +++ b/web/src/pages/Redemption/EditRedemption.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { API, @@ -7,12 +7,10 @@ import { showError, showSuccess, renderQuota, - renderQuotaWithPrompt + renderQuotaWithPrompt, } from '../../helpers'; import { - AutoComplete, Button, - Input, Modal, SideSheet, Space, @@ -21,8 +19,9 @@ import { Card, Tag, Form, - DatePicker, Avatar, + Row, + Col, } from '@douyinfe/semi-ui'; import { IconCreditCard, @@ -37,30 +36,30 @@ const EditRedemption = (props) => { const { t } = useTranslation(); const isEdit = props.editingRedemption.id !== undefined; const [loading, setLoading] = useState(isEdit); + const formApiRef = useRef(null); - const originInputs = { + const getInitValues = () => ({ name: '', quota: 100000, count: 1, - expired_time: 0, - }; - const [inputs, setInputs] = useState(originInputs); - const { name, quota, count, expired_time } = inputs; + expired_time: null, + }); const handleCancel = () => { props.handleClose(); }; - const handleInputChange = (name, value) => { - setInputs((inputs) => ({ ...inputs, [name]: value })); - }; - const loadRedemption = async () => { setLoading(true); let res = await API.get(`/api/redemption/${props.editingRedemption.id}`); const { success, message, data } = res.data; if (success) { - setInputs(data); + if (data.expired_time === 0) { + data.expired_time = null; + } else { + data.expired_time = new Date(data.expired_time * 1000); + } + formApiRef.current?.setValues({ ...getInitValues(), ...data }); } else { showError(message); } @@ -68,28 +67,30 @@ const EditRedemption = (props) => { }; useEffect(() => { - if (isEdit) { - loadRedemption().then(() => { - // console.log(inputs); - }); - } else { - setInputs(originInputs); + if (formApiRef.current) { + if (isEdit) { + loadRedemption(); + } else { + formApiRef.current.setValues(getInitValues()); + } } }, [props.editingRedemption.id]); - const submit = async () => { - let name = inputs.name; - if (!isEdit && inputs.name === '') { - // set default name - name = renderQuota(quota); + const submit = async (values) => { + let name = values.name; + if (!isEdit && values.name === '') { + + name = renderQuota(values.quota); } setLoading(true); - let localInputs = inputs; - localInputs.count = parseInt(localInputs.count); - localInputs.quota = parseInt(localInputs.quota); + let localInputs = { ...values }; + localInputs.count = parseInt(localInputs.count) || 0; + localInputs.quota = parseInt(localInputs.quota) || 0; localInputs.name = name; - if (localInputs.expired_time === null || localInputs.expired_time === undefined) { + if (!localInputs.expired_time) { localInputs.expired_time = 0; + } else { + localInputs.expired_time = Math.floor(localInputs.expired_time.getTime() / 1000); } let res; if (isEdit) { @@ -110,8 +111,8 @@ const EditRedemption = (props) => { props.handleClose(); } else { showSuccess(t('兑换码创建成功!')); - setInputs(originInputs); props.refresh(); + formApiRef.current?.setValues(getInitValues()); props.handleClose(); } } else { @@ -131,7 +132,7 @@ const EditRedemption = (props) => { ), onOk: () => { - downloadTextAsFile(text, `${inputs.name}.txt`); + downloadTextAsFile(text, `${localInputs.name}.txt`); }, }); } @@ -166,7 +167,7 @@ const EditRedemption = (props) => {