import React, { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { API, isMobile, showError, showSuccess, timestamp2string, } from '../../helpers'; import { renderGroupOption, renderQuotaWithPrompt } from '../../helpers/render'; import { AutoComplete, Banner, Button, Checkbox, DatePicker, Input, Select, SideSheet, Space, Spin, TextArea, Typography } from '@douyinfe/semi-ui'; import Title from '@douyinfe/semi-ui/lib/es/typography/title'; import { Divider } from 'semantic-ui-react'; import { useTranslation } from 'react-i18next'; const EditToken = (props) => { const [isEdit, setIsEdit] = useState(false); const [loading, setLoading] = useState(isEdit); const originInputs = { name: '', remain_quota: isEdit ? 0 : 500000, expired_time: -1, unlimited_quota: false, model_limits_enabled: false, model_limits: [], allow_ips: '', group: '', }; const [inputs, setInputs] = useState(originInputs); const { name, remain_quota, expired_time, unlimited_quota, model_limits_enabled, model_limits, allow_ips, group } = inputs; // const [visible, setVisible] = useState(false); const [models, setModels] = useState([]); const [groups, setGroups] = useState([]); const navigate = useNavigate(); const { t } = useTranslation(); 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 loadModels = async () => { let res = await API.get(`/api/user/models`); const { success, message, data } = res.data; if (success) { let localModelOptions = data.map((model) => ({ label: model, value: model, })); setModels(localModelOptions); } else { showError(t(message)); } }; const loadGroups = async () => { let res = await API.get(`/api/user/self/groups`); const { success, message, data } = res.data; if (success) { let localGroupOptions = Object.entries(data).map(([group, info]) => ({ label: info.desc, value: group, ratio: info.ratio })); setGroups(localGroupOptions); } else { showError(t(message)); } }; 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); } if (data.model_limits !== '') { data.model_limits = data.model_limits.split(','); } else { data.model_limits = []; } setInputs(data); } else { showError(message); } setLoading(false); }; useEffect(() => { setIsEdit(props.editingToken.id !== undefined); }, [props.editingToken.id]); useEffect(() => { if (!isEdit) { setInputs(originInputs); } else { loadToken().then(() => { // console.log(inputs); }); } loadModels(); loadGroups(); }, [isEdit]); // 新增 state 变量 tokenCount 来记录用户想要创建的令牌数量,默认为 1 const [tokenCount, setTokenCount] = useState(1); // 新增处理 tokenCount 变化的函数 const handleTokenCountChange = (value) => { // 确保用户输入的是正整数 const count = parseInt(value, 10); if (!isNaN(count) && count > 0) { setTokenCount(count); } }; // 生成一个随机的四位字母数字字符串 const generateRandomSuffix = () => { const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; let result = ''; for (let i = 0; i < 6; i++) { result += characters.charAt( Math.floor(Math.random() * characters.length), ); } return result; }; const submit = async () => { setLoading(true); if (isEdit) { // 编辑令牌的逻辑保持不变 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(t('过期时间格式错误!')); setLoading(false); return; } localInputs.expired_time = Math.ceil(time / 1000); } localInputs.model_limits = localInputs.model_limits.join(','); let res = await API.put(`/api/token/`, { ...localInputs, id: parseInt(props.editingToken.id), }); const { success, message } = res.data; if (success) { showSuccess(t('令牌更新成功!')); props.refresh(); props.handleClose(); } else { showError(t(message)); } } else { // 处理新增多个令牌的情况 let successCount = 0; // 记录成功创建的令牌数量 for (let i = 0; i < tokenCount; i++) { let localInputs = { ...inputs }; if (i !== 0) { // 如果用户想要创建多个令牌,则给每个令牌一个序号后缀 localInputs.name = `${inputs.name}-${generateRandomSuffix()}`; } localInputs.remain_quota = parseInt(localInputs.remain_quota); if (localInputs.expired_time !== -1) { let time = Date.parse(localInputs.expired_time); if (isNaN(time)) { showError(t('过期时间格式错误!')); setLoading(false); break; } localInputs.expired_time = Math.ceil(time / 1000); } localInputs.model_limits = localInputs.model_limits.join(','); let res = await API.post(`/api/token/`, localInputs); const { success, message } = res.data; if (success) { successCount++; } else { showError(t(message)); break; // 如果创建失败,终止循环 } } if (successCount > 0) { showSuccess( t('令牌创建成功,请在列表页面点击复制获取令牌!') ); props.refresh(); props.handleClose(); } } setLoading(false); setInputs(originInputs); // 重置表单 setTokenCount(1); // 重置数量为默认值 }; return ( <> {isEdit ? t('更新令牌信息') : t('创建新的令牌')} } headerStyle={{ borderBottom: '1px solid var(--semi-color-border)' }} bodyStyle={{ borderBottom: '1px solid var(--semi-color-border)' }} visible={props.visiable} footer={
} closeIcon={null} onCancel={() => handleCancel()} width={isMobile() ? '100%' : 600} > handleInputChange('name', value)} value={name} autoComplete='new-password' required={!isEdit} /> handleInputChange('expired_time', value)} value={expired_time} autoComplete='new-password' type='dateTime' />
{`${t('额度')}${renderQuotaWithPrompt(remain_quota)}`}
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} /> {!isEdit && ( <>
{t('新建数量')}
handleTokenCountChange(value)} onSelect={(value) => handleTokenCountChange(value)} value={tokenCount.toString()} autoComplete='off' type='number' data={[ { value: 10, label: t('10个') }, { value: 20, label: t('20个') }, { value: 30, label: t('30个') }, { value: 100, label: t('100个') }, ]} disabled={unlimited_quota} /> )}
{t('IP白名单(请勿过度信任此功能)')}