|
|
@@ -35,6 +35,7 @@ const EditToken = (props) => {
|
|
|
model_limits_enabled: false,
|
|
|
model_limits: [],
|
|
|
allow_ips: '',
|
|
|
+ group: '',
|
|
|
};
|
|
|
const [inputs, setInputs] = useState(originInputs);
|
|
|
const {
|
|
|
@@ -44,10 +45,12 @@ const EditToken = (props) => {
|
|
|
unlimited_quota,
|
|
|
model_limits_enabled,
|
|
|
model_limits,
|
|
|
- allow_ips
|
|
|
+ allow_ips,
|
|
|
+ group
|
|
|
} = inputs;
|
|
|
// const [visible, setVisible] = useState(false);
|
|
|
const [models, setModels] = useState({});
|
|
|
+ const [groups, setGroups] = useState([]);
|
|
|
const navigate = useNavigate();
|
|
|
const handleInputChange = (name, value) => {
|
|
|
setInputs((inputs) => ({ ...inputs, [name]: value }));
|
|
|
@@ -88,6 +91,22 @@ const EditToken = (props) => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+ const loadGroups = async () => {
|
|
|
+ let res = await API.get(`/api/user/groups`);
|
|
|
+ const { success, message, data } = res.data;
|
|
|
+ if (success) {
|
|
|
+ // return data is a map, key is group name, value is group description
|
|
|
+ // label is group description, value is group name
|
|
|
+ let localGroupOptions = Object.keys(data).map((group) => ({
|
|
|
+ label: data[group],
|
|
|
+ value: group,
|
|
|
+ }));
|
|
|
+ setGroups(localGroupOptions);
|
|
|
+ } else {
|
|
|
+ showError(message);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
const loadToken = async () => {
|
|
|
setLoading(true);
|
|
|
let res = await API.get(`/api/token/${props.editingToken.id}`);
|
|
|
@@ -120,6 +139,7 @@ const EditToken = (props) => {
|
|
|
});
|
|
|
}
|
|
|
loadModels();
|
|
|
+ loadGroups();
|
|
|
}, [isEdit]);
|
|
|
|
|
|
// 新增 state 变量 tokenCount 来记录用户想要创建的令牌数量,默认为 1
|
|
|
@@ -253,150 +273,150 @@ const EditToken = (props) => {
|
|
|
>
|
|
|
<Spin spinning={loading}>
|
|
|
<Input
|
|
|
- style={{ marginTop: 20 }}
|
|
|
- label='名称'
|
|
|
- name='name'
|
|
|
- placeholder={'请输入名称'}
|
|
|
- onChange={(value) => handleInputChange('name', value)}
|
|
|
- value={name}
|
|
|
- autoComplete='new-password'
|
|
|
- required={!isEdit}
|
|
|
+ style={{marginTop: 20}}
|
|
|
+ label='名称'
|
|
|
+ name='name'
|
|
|
+ placeholder={'请输入名称'}
|
|
|
+ onChange={(value) => handleInputChange('name', value)}
|
|
|
+ value={name}
|
|
|
+ autoComplete='new-password'
|
|
|
+ required={!isEdit}
|
|
|
/>
|
|
|
- <Divider />
|
|
|
+ <Divider/>
|
|
|
<DatePicker
|
|
|
- label='过期时间'
|
|
|
- name='expired_time'
|
|
|
- placeholder={'请选择过期时间'}
|
|
|
- onChange={(value) => handleInputChange('expired_time', value)}
|
|
|
- value={expired_time}
|
|
|
- autoComplete='new-password'
|
|
|
- type='dateTime'
|
|
|
+ label='过期时间'
|
|
|
+ name='expired_time'
|
|
|
+ placeholder={'请选择过期时间'}
|
|
|
+ onChange={(value) => handleInputChange('expired_time', value)}
|
|
|
+ value={expired_time}
|
|
|
+ autoComplete='new-password'
|
|
|
+ type='dateTime'
|
|
|
/>
|
|
|
- <div style={{ marginTop: 20 }}>
|
|
|
+ <div style={{marginTop: 20}}>
|
|
|
<Space>
|
|
|
<Button
|
|
|
- type={'tertiary'}
|
|
|
- onClick={() => {
|
|
|
- setExpiredTime(0, 0, 0, 0);
|
|
|
- }}
|
|
|
+ type={'tertiary'}
|
|
|
+ onClick={() => {
|
|
|
+ setExpiredTime(0, 0, 0, 0);
|
|
|
+ }}
|
|
|
>
|
|
|
永不过期
|
|
|
</Button>
|
|
|
<Button
|
|
|
- type={'tertiary'}
|
|
|
- onClick={() => {
|
|
|
- setExpiredTime(0, 0, 1, 0);
|
|
|
- }}
|
|
|
+ type={'tertiary'}
|
|
|
+ onClick={() => {
|
|
|
+ setExpiredTime(0, 0, 1, 0);
|
|
|
+ }}
|
|
|
>
|
|
|
一小时
|
|
|
</Button>
|
|
|
<Button
|
|
|
- type={'tertiary'}
|
|
|
- onClick={() => {
|
|
|
- setExpiredTime(1, 0, 0, 0);
|
|
|
- }}
|
|
|
+ type={'tertiary'}
|
|
|
+ onClick={() => {
|
|
|
+ setExpiredTime(1, 0, 0, 0);
|
|
|
+ }}
|
|
|
>
|
|
|
一个月
|
|
|
</Button>
|
|
|
<Button
|
|
|
- type={'tertiary'}
|
|
|
- onClick={() => {
|
|
|
- setExpiredTime(0, 1, 0, 0);
|
|
|
- }}
|
|
|
+ type={'tertiary'}
|
|
|
+ onClick={() => {
|
|
|
+ setExpiredTime(0, 1, 0, 0);
|
|
|
+ }}
|
|
|
>
|
|
|
一天
|
|
|
</Button>
|
|
|
</Space>
|
|
|
</div>
|
|
|
|
|
|
- <Divider />
|
|
|
+ <Divider/>
|
|
|
<Banner
|
|
|
- type={'warning'}
|
|
|
- description={
|
|
|
- '注意,令牌的额度仅用于限制令牌本身的最大额度使用量,实际的使用受到账户的剩余额度限制。'
|
|
|
- }
|
|
|
+ type={'warning'}
|
|
|
+ description={
|
|
|
+ '注意,令牌的额度仅用于限制令牌本身的最大额度使用量,实际的使用受到账户的剩余额度限制。'
|
|
|
+ }
|
|
|
></Banner>
|
|
|
- <div style={{ marginTop: 20 }}>
|
|
|
+ <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}
|
|
|
+ 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}
|
|
|
/>
|
|
|
|
|
|
{!isEdit && (
|
|
|
- <>
|
|
|
- <div style={{ marginTop: 20 }}>
|
|
|
- <Typography.Text>新建数量</Typography.Text>
|
|
|
- </div>
|
|
|
- <AutoComplete
|
|
|
- style={{ marginTop: 8 }}
|
|
|
- label='数量'
|
|
|
- placeholder={'请选择或输入创建令牌的数量'}
|
|
|
- onChange={(value) => handleTokenCountChange(value)}
|
|
|
- onSelect={(value) => handleTokenCountChange(value)}
|
|
|
- value={tokenCount.toString()}
|
|
|
- autoComplete='off'
|
|
|
- type='number'
|
|
|
- data={[
|
|
|
- { value: 10, label: '10个' },
|
|
|
- { value: 20, label: '20个' },
|
|
|
- { value: 30, label: '30个' },
|
|
|
- { value: 100, label: '100个' },
|
|
|
- ]}
|
|
|
- disabled={unlimited_quota}
|
|
|
- />
|
|
|
- </>
|
|
|
+ <>
|
|
|
+ <div style={{marginTop: 20}}>
|
|
|
+ <Typography.Text>新建数量</Typography.Text>
|
|
|
+ </div>
|
|
|
+ <AutoComplete
|
|
|
+ style={{marginTop: 8}}
|
|
|
+ label='数量'
|
|
|
+ placeholder={'请选择或输入创建令牌的数量'}
|
|
|
+ onChange={(value) => handleTokenCountChange(value)}
|
|
|
+ onSelect={(value) => handleTokenCountChange(value)}
|
|
|
+ value={tokenCount.toString()}
|
|
|
+ autoComplete='off'
|
|
|
+ type='number'
|
|
|
+ data={[
|
|
|
+ {value: 10, label: '10个'},
|
|
|
+ {value: 20, label: '20个'},
|
|
|
+ {value: 30, label: '30个'},
|
|
|
+ {value: 100, label: '100个'},
|
|
|
+ ]}
|
|
|
+ disabled={unlimited_quota}
|
|
|
+ />
|
|
|
+ </>
|
|
|
)}
|
|
|
|
|
|
<div>
|
|
|
<Button
|
|
|
- style={{ marginTop: 8 }}
|
|
|
- type={'warning'}
|
|
|
- onClick={() => {
|
|
|
- setUnlimitedQuota();
|
|
|
- }}
|
|
|
+ style={{marginTop: 8}}
|
|
|
+ type={'warning'}
|
|
|
+ onClick={() => {
|
|
|
+ setUnlimitedQuota();
|
|
|
+ }}
|
|
|
>
|
|
|
{unlimited_quota ? '取消无限额度' : '设为无限额度'}
|
|
|
</Button>
|
|
|
</div>
|
|
|
- <Divider />
|
|
|
- <div style={{ marginTop: 10 }}>
|
|
|
+ <Divider/>
|
|
|
+ <div style={{marginTop: 10}}>
|
|
|
<Typography.Text>IP白名单(请勿过度信任此功能)</Typography.Text>
|
|
|
</div>
|
|
|
<TextArea
|
|
|
- label='IP白名单'
|
|
|
- name='allow_ips'
|
|
|
- placeholder={'允许的IP,一行一个'}
|
|
|
- onChange={(value) => {
|
|
|
- handleInputChange('allow_ips', value);
|
|
|
- }}
|
|
|
- value={inputs.allow_ips}
|
|
|
- style={{ fontFamily: 'JetBrains Mono, Consolas' }}
|
|
|
+ label='IP白名单'
|
|
|
+ name='allow_ips'
|
|
|
+ placeholder={'允许的IP,一行一个'}
|
|
|
+ onChange={(value) => {
|
|
|
+ handleInputChange('allow_ips', value);
|
|
|
+ }}
|
|
|
+ value={inputs.allow_ips}
|
|
|
+ style={{fontFamily: 'JetBrains Mono, Consolas'}}
|
|
|
/>
|
|
|
- <div style={{ marginTop: 10, display: 'flex' }}>
|
|
|
+ <div style={{marginTop: 10, display: 'flex'}}>
|
|
|
<Space>
|
|
|
<Checkbox
|
|
|
- name='model_limits_enabled'
|
|
|
- checked={model_limits_enabled}
|
|
|
- onChange={(e) =>
|
|
|
- handleInputChange('model_limits_enabled', e.target.checked)
|
|
|
- }
|
|
|
+ name='model_limits_enabled'
|
|
|
+ checked={model_limits_enabled}
|
|
|
+ onChange={(e) =>
|
|
|
+ handleInputChange('model_limits_enabled', e.target.checked)
|
|
|
+ }
|
|
|
></Checkbox>
|
|
|
<Typography.Text>
|
|
|
启用模型限制(非必要,不建议启用)
|
|
|
@@ -405,19 +425,36 @@ const EditToken = (props) => {
|
|
|
</div>
|
|
|
|
|
|
<Select
|
|
|
- style={{ marginTop: 8 }}
|
|
|
- placeholder={'请选择该渠道所支持的模型'}
|
|
|
- name='models'
|
|
|
- required
|
|
|
- multiple
|
|
|
- selection
|
|
|
- onChange={(value) => {
|
|
|
- handleInputChange('model_limits', value);
|
|
|
- }}
|
|
|
- value={inputs.model_limits}
|
|
|
- autoComplete='new-password'
|
|
|
- optionList={models}
|
|
|
- disabled={!model_limits_enabled}
|
|
|
+ style={{marginTop: 8}}
|
|
|
+ placeholder={'请选择该渠道所支持的模型'}
|
|
|
+ name='models'
|
|
|
+ required
|
|
|
+ multiple
|
|
|
+ selection
|
|
|
+ onChange={(value) => {
|
|
|
+ handleInputChange('model_limits', value);
|
|
|
+ }}
|
|
|
+ value={inputs.model_limits}
|
|
|
+ autoComplete='new-password'
|
|
|
+ optionList={models}
|
|
|
+ disabled={!model_limits_enabled}
|
|
|
+ />
|
|
|
+
|
|
|
+ <div style={{marginTop: 10}}>
|
|
|
+ <Typography.Text>令牌分组,不选为默认分组</Typography.Text>
|
|
|
+ </div>
|
|
|
+ <Select
|
|
|
+ style={{marginTop: 8}}
|
|
|
+ placeholder={'令牌分组,不选为默认分组'}
|
|
|
+ name='gruop'
|
|
|
+ required
|
|
|
+ selection
|
|
|
+ onChange={(value) => {
|
|
|
+ handleInputChange('group', value);
|
|
|
+ }}
|
|
|
+ value={inputs.group}
|
|
|
+ autoComplete='new-password'
|
|
|
+ optionList={groups}
|
|
|
/>
|
|
|
</Spin>
|
|
|
</SideSheet>
|