Browse Source

完善令牌界面

CaIon 2 years ago
parent
commit
9eb8ad6786
2 changed files with 229 additions and 163 deletions
  1. 34 8
      web/src/components/TokensTable.js
  2. 195 155
      web/src/pages/Token/EditToken.js

+ 34 - 8
web/src/components/TokensTable.js

@@ -5,6 +5,7 @@ import {API, copy, isAdmin, showError, showSuccess, showWarning, timestamp2strin
 import {ITEMS_PER_PAGE} from '../constants';
 import {renderQuota, stringToColor} from '../helpers/render';
 import {Avatar, Tag, Table, Button, Popover, Form, Modal, Popconfirm} from "@douyinfe/semi-ui";
+import EditToken from "../pages/Token/EditToken";
 
 const {Column} = Table;
 
@@ -77,7 +78,7 @@ const TokensTable = () => {
             render: (text, record, index) => {
                 return (
                     <div>
-                        {renderQuota(parseInt(text))}
+                        {record.unlimited_quota ? <Tag size={'large'} color={'white'}>无限制</Tag> : <Tag size={'large'} color={'light-blue'}>{renderQuota(parseInt(text))}</Tag>}
                     </div>
                 );
             },
@@ -95,11 +96,11 @@ const TokensTable = () => {
         },
         {
             title: '过期时间',
-            dataIndex: 'accessed_time',
+            dataIndex: 'expired_time',
             render: (text, record, index) => {
                 return (
                     <div>
-                        {renderTimestamp(text)}
+                        {record.expired_time === -1 ? "永不过期" : renderTimestamp(text)}
                     </div>
                 );
             },
@@ -159,12 +160,18 @@ const TokensTable = () => {
                                 }
                             }>启用</Button>
                     }
-                    <Button theme='light' type='tertiary' style={{marginRight: 1}}>编辑</Button>
+                    <Button theme='light' type='tertiary' style={{marginRight: 1}} onClick={
+                        () => {
+                            setEditingToken(record);
+                            setShowEdit(true);
+                        }
+                    }>编辑</Button>
                 </div>
             ),
         },
     ];
 
+    const [showEdit, setShowEdit] = useState(false);
     const [tokens, setTokens] = useState([]);
     const [selectedKeys, setSelectedKeys] = useState([]);
     const [tokenCount, setTokenCount] = useState(ITEMS_PER_PAGE);
@@ -174,6 +181,16 @@ const TokensTable = () => {
     const [searching, setSearching] = useState(false);
     const [showTopUpModal, setShowTopUpModal] = useState(false);
     const [targetTokenIdx, setTargetTokenIdx] = useState(0);
+    const [editingToken, setEditingToken] = useState({
+        id: undefined,
+    });
+
+    const closeEdit = () => {
+        setShowEdit(false);
+        setEditingToken({
+            id: undefined,
+        });
+    }
 
     const setTokensFormat = (tokens) => {
         setTokens(tokens);
@@ -409,19 +426,17 @@ const TokensTable = () => {
 
     const rowSelection = {
         onSelect: (record, selected) => {
-            // console.log(`select row: ${selected}`, record);
         },
         onSelectAll: (selected, selectedRows) => {
-            // console.log(`select all rows: ${selected}`, selectedRows);
         },
         onChange: (selectedRowKeys, selectedRows) => {
-            // console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
             setSelectedKeys(selectedRows);
         },
     };
 
     return (
         <>
+            <EditToken refresh={refresh} editingToken={editingToken} visiable={showEdit} handleClose={closeEdit}></EditToken>
             <Form layout='horizontal' style={{marginTop: 10}} labelPosition={'left'}>
                 <Form.Input
                     field="keyword"
@@ -443,9 +458,20 @@ const TokensTable = () => {
                 onPageChange: handlePageChange,
             }} loading={loading} rowSelection={rowSelection}>
             </Table>
-            <Button theme='light' type='primary' style={{marginRight: 8}}>添加令牌</Button>
+            <Button theme='light' type='primary' style={{marginRight: 8}} onClick={
+                () => {
+                    setEditingToken({
+                        id: undefined,
+                    });
+                    setShowEdit(true);
+                }
+            }>添加令牌</Button>
             <Button label='复制所选令牌' type="warning" onClick={
                 async () => {
+                    if (selectedKeys.length === 0) {
+                        showError('请至少选择一个令牌!');
+                        return;
+                    }
                     let keys = "";
                     for (let i = 0; i < selectedKeys.length; i++) {
                         keys += selectedKeys[i].name + "    sk-" + selectedKeys[i].key + "\n";

+ 195 - 155
web/src/pages/Token/EditToken.js

@@ -1,164 +1,204 @@
-import React, { useEffect, useState } from 'react';
-import { Button, Form, Header, Message, Segment } from 'semantic-ui-react';
-import { useParams, useNavigate } from 'react-router-dom';
-import { API, showError, showSuccess, timestamp2string } from '../../helpers';
-import { renderQuota, renderQuotaWithPrompt } from '../../helpers/render';
+import React, {useEffect, useRef, useState} from 'react';
+// import {Button, Form, Header, Message, Segment} from 'semantic-ui-react';
+import {useParams, useNavigate} from 'react-router-dom';
+import {API, isMobile, showError, showSuccess, timestamp2string} from '../../helpers';
+import {renderQuota, renderQuotaWithPrompt} from '../../helpers/render';
+import {Layout, SideSheet, Button, Space, Spin, Banner, Input, DatePicker, AutoComplete, Typography} from "@douyinfe/semi-ui";
+import Title from "@douyinfe/semi-ui/lib/es/typography/title";
+import {Divider} from "semantic-ui-react";
 
-const EditToken = () => {
-  const params = useParams();
-  const tokenId = params.id;
-  const isEdit = tokenId !== undefined;
-  const [loading, setLoading] = useState(isEdit);
-  const originInputs = {
-    name: '',
-    remain_quota: isEdit ? 0 : 500000,
-    expired_time: -1,
-    unlimited_quota: false
-  };
-  const [inputs, setInputs] = useState(originInputs);
-  const { name, remain_quota, expired_time, unlimited_quota } = inputs;
-  const navigate = useNavigate();
-  const handleInputChange = (e, { name, value }) => {
-    setInputs((inputs) => ({ ...inputs, [name]: value }));
-  };
-  const handleCancel = () => {
-    navigate("/token");
-  }
-  const setExpiredTime = (month, day, hour, minute) => {
-    let now = new Date();
-    let timestamp = now.getTime() / 1000;
-    let seconds = month * 30 * 24 * 60 * 60;
-    seconds += day * 24 * 60 * 60;
-    seconds += hour * 60 * 60;
-    seconds += minute * 60;
-    if (seconds !== 0) {
-      timestamp += seconds;
-      setInputs({ ...inputs, expired_time: timestamp2string(timestamp) });
-    } else {
-      setInputs({ ...inputs, expired_time: -1 });
+const EditToken = (props) => {
+    const isEdit = props.editingToken.id !== undefined;
+    const [loading, setLoading] = useState(isEdit);
+    const originInputs = {
+        name: '',
+        remain_quota: isEdit ? 0 : 500000,
+        expired_time: -1,
+        unlimited_quota: false
+    };
+    const [inputs, setInputs] = useState(originInputs);
+    const {name, remain_quota, expired_time, unlimited_quota} = inputs;
+    // const [visible, setVisible] = useState(false);
+    const navigate = useNavigate();
+    const handleInputChange = (name, value) => {
+        setInputs((inputs) => ({...inputs, [name]: value}));
+    };
+    const handleCancel = () => {
+        props.handleClose();
     }
-  };
+    const setExpiredTime = (month, day, hour, minute) => {
+        let now = new Date();
+        let timestamp = now.getTime() / 1000;
+        let seconds = month * 30 * 24 * 60 * 60;
+        seconds += day * 24 * 60 * 60;
+        seconds += hour * 60 * 60;
+        seconds += minute * 60;
+        if (seconds !== 0) {
+            timestamp += seconds;
+            setInputs({...inputs, expired_time: timestamp2string(timestamp)});
+        } else {
+            setInputs({...inputs, expired_time: -1});
+        }
+    };
 
-  const setUnlimitedQuota = () => {
-    setInputs({ ...inputs, unlimited_quota: !unlimited_quota });
-  };
+    const setUnlimitedQuota = () => {
+        setInputs({...inputs, unlimited_quota: !unlimited_quota});
+    };
 
-  const loadToken = async () => {
-    let res = await API.get(`/api/token/${tokenId}`);
-    const { success, message, data } = res.data;
-    if (success) {
-      if (data.expired_time !== -1) {
-        data.expired_time = timestamp2string(data.expired_time);
-      }
-      setInputs(data);
-    } else {
-      showError(message);
-    }
-    setLoading(false);
-  };
-  useEffect(() => {
-    if (isEdit) {
-      loadToken().then();
-    }
-  }, []);
+    const loadToken = async () => {
+        setLoading(true);
+        let res = await API.get(`/api/token/${props.editingToken.id}`);
+        const {success, message, data} = res.data;
+        if (success) {
+            if (data.expired_time !== -1) {
+                data.expired_time = timestamp2string(data.expired_time);
+            }
+            setInputs(data);
+        } else {
+            showError(message);
+        }
+        setLoading(false);
+    };
+    useEffect(() => {
+        if (isEdit) {
+            loadToken().then(
+                () => {
+                    console.log(inputs);
+                }
+            );
+        } else {
+            setInputs(originInputs);
+        }
+    }, [props.editingToken.id]);
 
-  const submit = async () => {
-    if (!isEdit && inputs.name === '') return;
-    let localInputs = inputs;
-    localInputs.remain_quota = parseInt(localInputs.remain_quota);
-    if (localInputs.expired_time !== -1) {
-      let time = Date.parse(localInputs.expired_time);
-      if (isNaN(time)) {
-        showError('过期时间格式错误!');
-        return;
-      }
-      localInputs.expired_time = Math.ceil(time / 1000);
-    }
-    let res;
-    if (isEdit) {
-      res = await API.put(`/api/token/`, { ...localInputs, id: parseInt(tokenId) });
-    } else {
-      res = await API.post(`/api/token/`, localInputs);
-    }
-    const { success, message } = res.data;
-    if (success) {
-      if (isEdit) {
-        showSuccess('令牌更新成功!');
-      } else {
-        showSuccess('令牌创建成功,请在列表页面点击复制获取令牌!');
-        setInputs(originInputs);
-      }
-    } else {
-      showError(message);
-    }
-  };
+    const submit = async () => {
+        setLoading(true);
+        if (!isEdit && inputs.name === '') return;
+        let localInputs = inputs;
+        localInputs.remain_quota = parseInt(localInputs.remain_quota);
+        if (localInputs.expired_time !== -1) {
+            let time = Date.parse(localInputs.expired_time);
+            if (isNaN(time)) {
+                showError('过期时间格式错误!');
+                return;
+            }
+            localInputs.expired_time = Math.ceil(time / 1000);
+        }
+        let res;
+        if (isEdit) {
+            res = await API.put(`/api/token/`, {...localInputs, id: parseInt(props.editingToken.id)});
+        } else {
+            res = await API.post(`/api/token/`, localInputs);
+        }
+        const {success, message} = res.data;
+        if (success) {
+            if (isEdit) {
+                showSuccess('令牌更新成功!');
+                props.refresh();
+                props.handleClose();
+            } else {
+                showSuccess('令牌创建成功,请在列表页面点击复制获取令牌!');
+                setInputs(originInputs);
+                props.refresh();
+                props.handleClose();
+            }
+        } else {
+            showError(message);
+        }
+        setLoading(false);
+    };
+
+
+    return (
+        <>
+            <SideSheet
+                title={<Title level={3}>{isEdit ? '更新令牌信息' : '创建新的令牌'}</Title>}
+                headerStyle={{borderBottom: '1px solid var(--semi-color-border)'}}
+                bodyStyle={{borderBottom: '1px solid var(--semi-color-border)'}}
+                visible={props.visiable}
+                footer={
+                    <div style={{display: 'flex', justifyContent: 'flex-end'}}>
+                        <Space>
+                            <Button theme='solid' size={'large'} onClick={submit}>提交</Button>
+                            <Button theme='solid' size={'large'} type={'tertiary'} onClick={handleCancel}>取消</Button>
+                        </Space>
+                    </div>
+                }
+                closeIcon={null}
+                onCancel={() => handleCancel()}
+                width={isMobile() ? '100%' : 600}
+            >
+                <Spin spinning={loading}>
+                    <Input
+                        style={{ marginTop: 20 }}
+                        label='名称'
+                        name='name'
+                        placeholder={'请输入名称'}
+                        onChange={(value) => handleInputChange('name', value)}
+                        value={name}
+                        autoComplete='new-password'
+                        required={!isEdit}
+                    />
+                    <Divider/>
+                    <DatePicker
+                        label='过期时间'
+                        name='expired_time'
+                        placeholder={'请选择过期时间'}
+                        onChange={(value) => handleInputChange('expired_time', value)}
+                        value={expired_time}
+                        autoComplete='new-password'
+                        type='dateTime'
+                    />
+                    <div style={{ marginTop: 20 }}>
+                        <Space>
+                            <Button type={'tertiary'} onClick={() => {
+                                setExpiredTime(0, 0, 0, 0);
+                            }}>永不过期</Button>
+                            <Button type={'tertiary'} onClick={() => {
+                                setExpiredTime(0, 0, 1, 0);
+                            }}>一小时</Button>
+                            <Button type={'tertiary'} onClick={() => {
+                                setExpiredTime(1, 0, 0, 0);
+                            }}>一个月</Button>
+                            <Button type={'tertiary'} onClick={() => {
+                                setExpiredTime(0, 1, 0, 0);
+                            }}>一天</Button>
+                        </Space>
+                    </div>
 
-  return (
-    <>
-      <Segment loading={loading}>
-        <Header as='h3'>{isEdit ? '更新令牌信息' : '创建新的令牌'}</Header>
-        <Form autoComplete='new-password'>
-          <Form.Field>
-            <Form.Input
-              label='名称'
-              name='name'
-              placeholder={'请输入名称'}
-              onChange={handleInputChange}
-              value={name}
-              autoComplete='new-password'
-              required={!isEdit}
-            />
-          </Form.Field>
-          <Form.Field>
-            <Form.Input
-              label='过期时间'
-              name='expired_time'
-              placeholder={'请输入过期时间,格式为 yyyy-MM-dd HH:mm:ss,-1 表示无限制'}
-              onChange={handleInputChange}
-              value={expired_time}
-              autoComplete='new-password'
-              type='datetime-local'
-            />
-          </Form.Field>
-          <div style={{ lineHeight: '40px' }}>
-            <Button type={'button'} onClick={() => {
-              setExpiredTime(0, 0, 0, 0);
-            }}>永不过期</Button>
-            <Button type={'button'} onClick={() => {
-              setExpiredTime(1, 0, 0, 0);
-            }}>一个月后过期</Button>
-            <Button type={'button'} onClick={() => {
-              setExpiredTime(0, 1, 0, 0);
-            }}>一天后过期</Button>
-            <Button type={'button'} onClick={() => {
-              setExpiredTime(0, 0, 1, 0);
-            }}>一小时后过期</Button>
-            <Button type={'button'} onClick={() => {
-              setExpiredTime(0, 0, 0, 1);
-            }}>一分钟后过期</Button>
-          </div>
-          <Message>注意,令牌的额度仅用于限制令牌本身的最大额度使用量,实际的使用受到账户的剩余额度限制。</Message>
-          <Form.Field>
-            <Form.Input
-              label={`额度${renderQuotaWithPrompt(remain_quota)}`}
-              name='remain_quota'
-              placeholder={'请输入额度'}
-              onChange={handleInputChange}
-              value={remain_quota}
-              autoComplete='new-password'
-              type='number'
-              disabled={unlimited_quota}
-            />
-          </Form.Field>
-          <Button type={'button'} onClick={() => {
-            setUnlimitedQuota();
-          }}>{unlimited_quota ? '取消无限额度' : '设为无限额度'}</Button>
-          <Button floated='right' positive onClick={submit}>提交</Button>
-          <Button floated='right' onClick={handleCancel}>取消</Button>
-        </Form>
-      </Segment>
-    </>
-  );
+                    <Divider/>
+                    <Banner type={'warning'} description={'注意,令牌的额度仅用于限制令牌本身的最大额度使用量,实际的使用受到账户的剩余额度限制。'}></Banner>
+                    <div style={{ marginTop: 20 }}>
+                        <Typography.Text>{`额度${renderQuotaWithPrompt(remain_quota)}`}</Typography.Text>
+                    </div>
+                    <AutoComplete
+                        style={{ marginTop: 8 }}
+                        name='remain_quota'
+                        placeholder={'请输入额度'}
+                        onChange={(value) => handleInputChange('remain_quota', value)}
+                        value={remain_quota}
+                        autoComplete='new-password'
+                        type='number'
+                        position={'top'}
+                        data={[
+                            {value: 500000, label: '1$'},
+                            {value: 5000000, label: '10$'},
+                            {value: 25000000, label: '50$'},
+                            {value: 50000000, label: '100$'},
+                            {value: 250000000, label: '500$'},
+                            {value: 500000000, label: '1000$'},
+                        ]}
+                        disabled={unlimited_quota}
+                    />
+                    <div>
+                        <Button style={{ marginTop: 8 }} type={'warning'} onClick={() => {
+                            setUnlimitedQuota();
+                        }}>{unlimited_quota ? '取消无限额度' : '设为无限额度'}</Button>
+                    </div>
+                </Spin>
+            </SideSheet>
+        </>
+    );
 };
 
 export default EditToken;