Просмотр исходного кода

🚀 feat: Enhance table UX & fix reset actions across Users / Tokens / Redemptions

Users table (UsersColumnDefs.js)
• Merged “Status” into the “Statistics” tag: unified text-color logic, removed duplicate renderStatus / renderOverallStatus helpers.
• Switch now disabled for deleted users.
• Replaced dropdown “More” menu with explicit action buttons (Edit / Promote / Demote / Delete) and set column width to 200 px.
• Deleted unused Dropdown & IconMore imports and tidied redundant code.

Users filters & hooks
• UsersFilters.jsx – store formApi in a ref; reset button clears form then reloads data after 100 ms.
• useUsersData.js – call setLoading(true) at the start of loadUsers so the Query button shows loading on reset / reload.

TokensFilters.jsx & RedemptionsFilters.jsx
• Same ref-based reset pattern with 100 ms debounce to restore working “Reset” buttons.

Other clean-ups
• Removed repeated status strings and unused helper functions.
• Updated import lists to reflect component changes.

Result
– Reset buttons now reliably clear filters and reload data with proper loading feedback.
– Users table shows concise status information and all operation buttons without extra clicks.
t0ng7u 7 месяцев назад
Родитель
Сommit
252fddf3de

+ 2 - 2
web/src/components/layout/SiderBar.js

@@ -128,13 +128,13 @@ const SiderBar = ({ onNavigate = () => { } }) => {
   const adminItems = useMemo(
     () => [
       {
-        text: t('渠道'),
+        text: t('渠道管理'),
         itemKey: 'channel',
         to: '/channel',
         className: isAdmin() ? '' : 'tableHiddle',
       },
       {
-        text: t('兑换码'),
+        text: t('兑换码管理'),
         itemKey: 'redemption',
         to: '/redemption',
         className: isAdmin() ? '' : 'tableHiddle',

+ 14 - 11
web/src/components/table/redemptions/RedemptionsFilters.jsx

@@ -17,7 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 For commercial licensing, please contact support@quantumnous.com
 */
 
-import React from 'react';
+import React, { useRef } from 'react';
 import { Form, Button } from '@douyinfe/semi-ui';
 import { IconSearch } from '@douyinfe/semi-icons';
 
@@ -31,20 +31,23 @@ const RedemptionsFilters = ({
 }) => {
 
   // Handle form reset and immediate search
-  const handleReset = (formApi) => {
-    if (formApi) {
-      formApi.reset();
-      // Reset and search immediately
-      setTimeout(() => {
-        searchRedemptions();
-      }, 100);
-    }
+  const formApiRef = useRef(null);
+
+  const handleReset = () => {
+    if (!formApiRef.current) return;
+    formApiRef.current.reset();
+    setTimeout(() => {
+      searchRedemptions();
+    }, 100);
   };
 
   return (
     <Form
       initValues={formInitValues}
-      getFormApi={(api) => setFormApi(api)}
+      getFormApi={(api) => {
+        setFormApi(api);
+        formApiRef.current = api;
+      }}
       onSubmit={searchRedemptions}
       allowEmpty={true}
       autoComplete="off"
@@ -76,7 +79,7 @@ const RedemptionsFilters = ({
           </Button>
           <Button
             type="tertiary"
-            onClick={(_, formApi) => handleReset(formApi)}
+            onClick={handleReset}
             className="flex-1 md:flex-initial md:w-auto"
             size="small"
           >

+ 14 - 11
web/src/components/table/tokens/TokensFilters.jsx

@@ -17,7 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 For commercial licensing, please contact support@quantumnous.com
 */
 
-import React from 'react';
+import React, { useRef } from 'react';
 import { Form, Button } from '@douyinfe/semi-ui';
 import { IconSearch } from '@douyinfe/semi-icons';
 
@@ -30,20 +30,23 @@ const TokensFilters = ({
   t,
 }) => {
   // Handle form reset and immediate search
-  const handleReset = (formApi) => {
-    if (formApi) {
-      formApi.reset();
-      // Reset and search immediately
-      setTimeout(() => {
-        searchTokens();
-      }, 100);
-    }
+  const formApiRef = useRef(null);
+
+  const handleReset = () => {
+    if (!formApiRef.current) return;
+    formApiRef.current.reset();
+    setTimeout(() => {
+      searchTokens();
+    }, 100);
   };
 
   return (
     <Form
       initValues={formInitValues}
-      getFormApi={(api) => setFormApi(api)}
+      getFormApi={(api) => {
+        setFormApi(api);
+        formApiRef.current = api;
+      }}
       onSubmit={searchTokens}
       allowEmpty={true}
       autoComplete="off"
@@ -88,7 +91,7 @@ const TokensFilters = ({
 
           <Button
             type='tertiary'
-            onClick={(_, formApi) => handleReset(formApi)}
+            onClick={handleReset}
             className="flex-1 md:flex-initial md:w-auto"
             size="small"
           >

+ 14 - 12
web/src/components/table/users/UsersFilters.jsx

@@ -17,7 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 For commercial licensing, please contact support@quantumnous.com
 */
 
-import React from 'react';
+import React, { useRef } from 'react';
 import { Form, Button } from '@douyinfe/semi-ui';
 import { IconSearch } from '@douyinfe/semi-icons';
 
@@ -34,21 +34,23 @@ const UsersFilters = ({
   t
 }) => {
 
-  // Handle form reset and immediate search
-  const handleReset = (formApi) => {
-    if (formApi) {
-      formApi.reset();
-      // Reset and search immediately
-      setTimeout(() => {
-        loadUsers(1, pageSize);
-      }, 100);
-    }
+  const formApiRef = useRef(null);
+
+  const handleReset = () => {
+    if (!formApiRef.current) return;
+    formApiRef.current.reset();
+    setTimeout(() => {
+      loadUsers(1, pageSize);
+    }, 100);
   };
 
   return (
     <Form
       initValues={formInitValues}
-      getFormApi={(api) => setFormApi(api)}
+      getFormApi={(api) => {
+        setFormApi(api);
+        formApiRef.current = api;
+      }}
       onSubmit={() => {
         searchUsers(1, pageSize);
       }}
@@ -99,7 +101,7 @@ const UsersFilters = ({
           </Button>
           <Button
             type='tertiary'
-            onClick={(_, formApi) => handleReset(formApi)}
+            onClick={handleReset}
             className="flex-1 md:flex-initial md:w-auto"
             size="small"
           >

+ 1 - 0
web/src/hooks/users/useUsersData.js

@@ -71,6 +71,7 @@ export const useUsersData = () => {
 
   // Load users data
   const loadUsers = async (startIdx, pageSize) => {
+    setLoading(true);
     const res = await API.get(`/api/user/?p=${startIdx}&page_size=${pageSize}`);
     const { success, message, data } = res.data;
     if (success) {

+ 3 - 2
web/src/i18n/locales/en.json

@@ -165,7 +165,8 @@
   "操作失败,重定向至登录界面中...": "Operation failed, redirecting to login page...",
   "出现错误,第 ${count} 次重试中...": "Error occurred, retry attempt ${count}...",
   "首页": "Home",
-  "渠道": "Channels",
+  "渠道": "Channel",
+  "渠道管理": "Channels",
   "令牌": "Tokens",
   "兑换": "Redeem",
   "充值": "Recharge",
@@ -1487,7 +1488,7 @@
   "收益": "Earnings",
   "无邀请人": "No Inviter",
   "邀请人": "Inviter",
-  "兑换码管理": "Redemption Code Management",
+  "兑换码管理": "Redemption Code",
   "设置兑换码的基本信息": "Set redemption code basic information",
   "设置兑换码的额度和数量": "Set redemption code quota and quantity",
   "编辑用户": "Edit User",