Parcourir la source

Merge pull request #1199 from feitianbubu/revert-column-visiblity-settting-channel

feat: add column visibility settings for channels
同語 il y a 9 mois
Parent
commit
a9a284a595
1 fichiers modifiés avec 196 ajouts et 3 suppressions
  1. 196 3
      web/src/components/table/ChannelsTable.js

+ 196 - 3
web/src/components/table/ChannelsTable.js

@@ -41,6 +41,7 @@ import {
   Tag,
   Tag,
   Tooltip,
   Tooltip,
   Typography,
   Typography,
+  Checkbox,
   Card,
   Card,
   Form
   Form
 } from '@douyinfe/semi-ui';
 } from '@douyinfe/semi-ui';
@@ -172,17 +173,108 @@ const ChannelsTable = () => {
     }
     }
   };
   };
 
 
-  // Define all columns
-  const columns = [
+  // Define column keys for selection
+  const COLUMN_KEYS = {
+    ID: 'id',
+    NAME: 'name',
+    GROUP: 'group',
+    TYPE: 'type',
+    STATUS: 'status',
+    RESPONSE_TIME: 'response_time',
+    BALANCE: 'balance',
+    PRIORITY: 'priority',
+    WEIGHT: 'weight',
+    OPERATE: 'operate',
+  };
+
+  // State for column visibility
+  const [visibleColumns, setVisibleColumns] = useState({});
+  const [showColumnSelector, setShowColumnSelector] = useState(false);
+
+  // Load saved column preferences from localStorage
+  useEffect(() => {
+    const savedColumns = localStorage.getItem('channels-table-columns');
+    if (savedColumns) {
+      try {
+        const parsed = JSON.parse(savedColumns);
+        // Make sure all columns are accounted for
+        const defaults = getDefaultColumnVisibility();
+        const merged = { ...defaults, ...parsed };
+        setVisibleColumns(merged);
+      } catch (e) {
+        console.error('Failed to parse saved column preferences', e);
+        initDefaultColumns();
+      }
+    } else {
+      initDefaultColumns();
+    }
+  }, []);
+
+  // Update table when column visibility changes
+  useEffect(() => {
+    if (Object.keys(visibleColumns).length > 0) {
+      // Save to localStorage
+      localStorage.setItem(
+        'channels-table-columns',
+        JSON.stringify(visibleColumns),
+      );
+    }
+  }, [visibleColumns]);
+
+  // Get default column visibility
+  const getDefaultColumnVisibility = () => {
+    return {
+      [COLUMN_KEYS.ID]: true,
+      [COLUMN_KEYS.NAME]: true,
+      [COLUMN_KEYS.GROUP]: true,
+      [COLUMN_KEYS.TYPE]: true,
+      [COLUMN_KEYS.STATUS]: true,
+      [COLUMN_KEYS.RESPONSE_TIME]: true,
+      [COLUMN_KEYS.BALANCE]: true,
+      [COLUMN_KEYS.PRIORITY]: true,
+      [COLUMN_KEYS.WEIGHT]: true,
+      [COLUMN_KEYS.OPERATE]: true,
+    };
+  };
+
+  // Initialize default column visibility
+  const initDefaultColumns = () => {
+    const defaults = getDefaultColumnVisibility();
+    setVisibleColumns(defaults);
+  };
+
+  // Handle column visibility change
+  const handleColumnVisibilityChange = (columnKey, checked) => {
+    const updatedColumns = { ...visibleColumns, [columnKey]: checked };
+    setVisibleColumns(updatedColumns);
+  };
+
+  // Handle "Select All" checkbox
+  const handleSelectAll = (checked) => {
+    const allKeys = Object.keys(COLUMN_KEYS).map((key) => COLUMN_KEYS[key]);
+    const updatedColumns = {};
+
+    allKeys.forEach((key) => {
+      updatedColumns[key] = checked;
+    });
+
+    setVisibleColumns(updatedColumns);
+  };
+
+  // Define all columns with keys
+  const allColumns = [
     {
     {
+      key: COLUMN_KEYS.ID,
       title: t('ID'),
       title: t('ID'),
       dataIndex: 'id',
       dataIndex: 'id',
     },
     },
     {
     {
+      key: COLUMN_KEYS.NAME,
       title: t('名称'),
       title: t('名称'),
       dataIndex: 'name',
       dataIndex: 'name',
     },
     },
     {
     {
+      key: COLUMN_KEYS.GROUP,
       title: t('分组'),
       title: t('分组'),
       dataIndex: 'group',
       dataIndex: 'group',
       render: (text, record, index) => (
       render: (text, record, index) => (
@@ -201,6 +293,7 @@ const ChannelsTable = () => {
       ),
       ),
     },
     },
     {
     {
+      key: COLUMN_KEYS.TYPE,
       title: t('类型'),
       title: t('类型'),
       dataIndex: 'type',
       dataIndex: 'type',
       render: (text, record, index) => {
       render: (text, record, index) => {
@@ -212,6 +305,7 @@ const ChannelsTable = () => {
       },
       },
     },
     },
     {
     {
+      key: COLUMN_KEYS.STATUS,
       title: t('状态'),
       title: t('状态'),
       dataIndex: 'status',
       dataIndex: 'status',
       render: (text, record, index) => {
       render: (text, record, index) => {
@@ -237,6 +331,7 @@ const ChannelsTable = () => {
       },
       },
     },
     },
     {
     {
+      key: COLUMN_KEYS.RESPONSE_TIME,
       title: t('响应时间'),
       title: t('响应时间'),
       dataIndex: 'response_time',
       dataIndex: 'response_time',
       render: (text, record, index) => (
       render: (text, record, index) => (
@@ -244,6 +339,7 @@ const ChannelsTable = () => {
       ),
       ),
     },
     },
     {
     {
+      key: COLUMN_KEYS.BALANCE,
       title: t('已用/剩余'),
       title: t('已用/剩余'),
       dataIndex: 'expired_time',
       dataIndex: 'expired_time',
       render: (text, record, index) => {
       render: (text, record, index) => {
@@ -283,6 +379,7 @@ const ChannelsTable = () => {
       },
       },
     },
     },
     {
     {
+      key: COLUMN_KEYS.PRIORITY,
       title: t('优先级'),
       title: t('优先级'),
       dataIndex: 'priority',
       dataIndex: 'priority',
       render: (text, record, index) => {
       render: (text, record, index) => {
@@ -334,6 +431,7 @@ const ChannelsTable = () => {
       },
       },
     },
     },
     {
     {
+      key: COLUMN_KEYS.WEIGHT,
       title: t('权重'),
       title: t('权重'),
       dataIndex: 'weight',
       dataIndex: 'weight',
       render: (text, record, index) => {
       render: (text, record, index) => {
@@ -385,6 +483,7 @@ const ChannelsTable = () => {
       },
       },
     },
     },
     {
     {
+      key: COLUMN_KEYS.OPERATE,
       title: '',
       title: '',
       dataIndex: 'operate',
       dataIndex: 'operate',
       fixed: 'right',
       fixed: 'right',
@@ -595,6 +694,89 @@ const ChannelsTable = () => {
     searchModel: '',
     searchModel: '',
   };
   };
 
 
+  // Filter columns based on visibility settings
+  const getVisibleColumns = () => {
+    return allColumns.filter((column) => visibleColumns[column.key]);
+  };
+
+  // Column selector modal
+  const renderColumnSelector = () => {
+    return (
+      <Modal
+        title={t('列设置')}
+        visible={showColumnSelector}
+        onCancel={() => setShowColumnSelector(false)}
+        footer={
+          <div className="flex justify-end">
+            <Button
+              theme="light"
+              onClick={() => initDefaultColumns()}
+              className="!rounded-full"
+            >
+              {t('重置')}
+            </Button>
+            <Button
+              theme="light"
+              onClick={() => setShowColumnSelector(false)}
+              className="!rounded-full"
+            >
+              {t('取消')}
+            </Button>
+            <Button
+              type='primary'
+              onClick={() => setShowColumnSelector(false)}
+              className="!rounded-full"
+            >
+              {t('确定')}
+            </Button>
+          </div>
+        }
+        size="middle"
+        centered={true}
+      >
+        <div style={{ marginBottom: 20 }}>
+          <Checkbox
+            checked={Object.values(visibleColumns).every((v) => v === true)}
+            indeterminate={
+              Object.values(visibleColumns).some((v) => v === true) &&
+              !Object.values(visibleColumns).every((v) => v === true)
+            }
+            onChange={(e) => handleSelectAll(e.target.checked)}
+          >
+            {t('全选')}
+          </Checkbox>
+        </div>
+        <div
+          className="flex flex-wrap max-h-96 overflow-y-auto rounded-lg p-4"
+          style={{ border: '1px solid var(--semi-color-border)' }}
+        >
+          {allColumns.map((column) => {
+            // Skip columns without title
+            if (!column.title) {
+              return null;
+            }
+
+            return (
+              <div
+                key={column.key}
+                className="w-1/2 mb-4 pr-2"
+              >
+                <Checkbox
+                  checked={!!visibleColumns[column.key]}
+                  onChange={(e) =>
+                    handleColumnVisibilityChange(column.key, e.target.checked)
+                  }
+                >
+                  {column.title}
+                </Checkbox>
+              </div>
+            );
+          })}
+        </div>
+      </Modal>
+    );
+  };
+
   const removeRecord = (record) => {
   const removeRecord = (record) => {
     let newDataSource = [...channels];
     let newDataSource = [...channels];
     if (record.id != null) {
     if (record.id != null) {
@@ -1397,6 +1579,16 @@ const ChannelsTable = () => {
           >
           >
             {t('刷新')}
             {t('刷新')}
           </Button>
           </Button>
+
+          <Button
+            theme='light'
+            type='tertiary'
+            icon={<IconSetting />}
+            onClick={() => setShowColumnSelector(true)}
+            className="!rounded-full w-full md:w-auto"
+          >
+            {t('列设置')}
+          </Button>
         </div>
         </div>
 
 
         <div className="flex flex-col md:flex-row items-center gap-4 w-full md:w-auto order-1 md:order-2">
         <div className="flex flex-col md:flex-row items-center gap-4 w-full md:w-auto order-1 md:order-2">
@@ -1481,6 +1673,7 @@ const ChannelsTable = () => {
 
 
   return (
   return (
     <>
     <>
+      {renderColumnSelector()}
       <EditTagModal
       <EditTagModal
         visible={showEditTag}
         visible={showEditTag}
         tag={editingTag}
         tag={editingTag}
@@ -1501,7 +1694,7 @@ const ChannelsTable = () => {
         bordered={false}
         bordered={false}
       >
       >
         <Table
         <Table
-          columns={columns}
+          columns={getVisibleColumns()}
           dataSource={pageData}
           dataSource={pageData}
           scroll={{ x: 'max-content' }}
           scroll={{ x: 'max-content' }}
           pagination={{
           pagination={{