1、增加消息推送的前台横幅显示
2、增加apikey的整体配额增加和修改记录显示
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Modal, Radio, InputNumber, Input, Select, Space, Typography, Tag, Divider, message,
|
||||
} from 'antd';
|
||||
import { adjustApiKeyQuota } from '../api';
|
||||
|
||||
interface QuotaAdjustModalProps {
|
||||
open: boolean;
|
||||
keyId: string;
|
||||
companyName: string;
|
||||
quotaLimit: number | null;
|
||||
quotaUsed: number;
|
||||
quotaCycle: string | null;
|
||||
onCancel: () => void;
|
||||
onSuccess: () => void;
|
||||
}
|
||||
|
||||
const QuotaAdjustModal: React.FC<QuotaAdjustModalProps> = ({
|
||||
open, keyId, companyName, quotaLimit, quotaUsed, quotaCycle, onCancel, onSuccess,
|
||||
}) => {
|
||||
const [action, setAction] = useState<'adjust' | 'reset_usage' | 'set_limit' | 'change_cycle'>('adjust');
|
||||
const [delta, setDelta] = useState<number>(0);
|
||||
const [newLimit, setNewLimit] = useState<number | null>(quotaLimit);
|
||||
const [newCycle, setNewCycle] = useState<string | null>(quotaCycle);
|
||||
const [reason, setReason] = useState<string>('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const cycleLabel = (cycle: string | null) => {
|
||||
const map: Record<string, string> = { daily: '每日', monthly: '每月', one_time: '一次性' };
|
||||
return cycle ? map[cycle] || cycle : '无限';
|
||||
};
|
||||
|
||||
const handleOk = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const payload: any = { action, reason: reason || undefined };
|
||||
if (action === 'adjust') payload.quotaLimitDelta = delta;
|
||||
if (action === 'set_limit') payload.quotaLimit = newLimit;
|
||||
if (action === 'change_cycle') payload.quotaCycle = newCycle;
|
||||
|
||||
await adjustApiKeyQuota(keyId, payload);
|
||||
message.success('配额调整成功');
|
||||
onSuccess();
|
||||
} catch (e: any) {
|
||||
message.error(e?.response?.data?.detail || '调整失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
setAction('adjust');
|
||||
setDelta(0);
|
||||
setNewLimit(quotaLimit);
|
||||
setNewCycle(quotaCycle);
|
||||
setReason('');
|
||||
onCancel();
|
||||
};
|
||||
|
||||
// 预览计算
|
||||
const previewLimit = action === 'adjust'
|
||||
? round((quotaLimit || 0) + delta)
|
||||
: action === 'set_limit'
|
||||
? newLimit
|
||||
: quotaLimit;
|
||||
|
||||
function round(n: number) {
|
||||
return Math.round(n * 100) / 100;
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="调整配额"
|
||||
open={open}
|
||||
onOk={handleOk}
|
||||
onCancel={handleCancel}
|
||||
okText="确认调整"
|
||||
cancelText="取消"
|
||||
confirmLoading={loading}
|
||||
width={480}
|
||||
>
|
||||
<Space direction="vertical" size="middle" style={{ width: '100%' }}>
|
||||
<div>
|
||||
<Typography.Text type="secondary">公司:</Typography.Text>
|
||||
<Typography.Text strong>{companyName}</Typography.Text>
|
||||
</div>
|
||||
<div>
|
||||
<Typography.Text type="secondary">当前:</Typography.Text>
|
||||
<Tag color="blue">已用 {quotaUsed.toFixed(2)} 元</Tag>
|
||||
<Tag color="green">限额 {quotaLimit != null ? `${quotaLimit.toFixed(2)} 元` : '无限'}</Tag>
|
||||
<Tag color="purple">{cycleLabel(quotaCycle)}</Tag>
|
||||
</div>
|
||||
|
||||
<Divider style={{ margin: '8px 0' }} />
|
||||
|
||||
<Radio.Group value={action} onChange={e => setAction(e.target.value)} style={{ width: '100%' }}>
|
||||
<Space direction="vertical" size={12} style={{ width: '100%' }}>
|
||||
<Radio value="adjust">
|
||||
<Space>
|
||||
<Typography.Text>增加总额</Typography.Text>
|
||||
{action === 'adjust' && (
|
||||
<InputNumber
|
||||
min={0}
|
||||
step={10}
|
||||
value={delta}
|
||||
onChange={v => setDelta(v || 0)}
|
||||
addonAfter="元"
|
||||
style={{ width: 160 }}
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
</Radio>
|
||||
|
||||
<Radio value="reset_usage">
|
||||
<Space>
|
||||
<Typography.Text>重置已用</Typography.Text>
|
||||
{action === 'reset_usage' && (
|
||||
<Typography.Text type="secondary">
|
||||
({quotaUsed.toFixed(2)} → 0.00 元)
|
||||
</Typography.Text>
|
||||
)}
|
||||
</Space>
|
||||
</Radio>
|
||||
|
||||
<Radio value="set_limit">
|
||||
<Space>
|
||||
<Typography.Text>设置限额</Typography.Text>
|
||||
{action === 'set_limit' && (
|
||||
<>
|
||||
<InputNumber
|
||||
min={0}
|
||||
step={10}
|
||||
value={newLimit}
|
||||
onChange={setNewLimit}
|
||||
addonAfter="元"
|
||||
placeholder="留空=无限"
|
||||
style={{ width: 160 }}
|
||||
/>
|
||||
<Typography.Text type="secondary">
|
||||
(当前:{quotaLimit != null ? `${quotaLimit.toFixed(2)} 元` : '无限'})
|
||||
</Typography.Text>
|
||||
</>
|
||||
)}
|
||||
</Space>
|
||||
</Radio>
|
||||
|
||||
<Radio value="change_cycle">
|
||||
<Space>
|
||||
<Typography.Text>修改周期</Typography.Text>
|
||||
{action === 'change_cycle' && (
|
||||
<Select
|
||||
value={newCycle}
|
||||
onChange={setNewCycle}
|
||||
allowClear
|
||||
placeholder="选择周期"
|
||||
style={{ width: 140 }}
|
||||
options={[
|
||||
{ label: '每日', value: 'daily' },
|
||||
{ label: '每月', value: 'monthly' },
|
||||
{ label: '一次性', value: 'one_time' },
|
||||
{ label: '无限', value: null },
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
</Radio>
|
||||
</Space>
|
||||
</Radio.Group>
|
||||
|
||||
{action === 'adjust' && delta > 0 && (
|
||||
<div style={{ padding: '8px 12px', background: '#f0f5ff', borderRadius: 6, fontSize: 13 }}>
|
||||
调整后总额:<strong style={{ color: '#1677ff' }}>{previewLimit != null ? `${previewLimit.toFixed(2)} 元` : '无限'}</strong>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<Typography.Text type="secondary" style={{ fontSize: 12 }}>调整原因(可选)</Typography.Text>
|
||||
<Input.TextArea
|
||||
value={reason}
|
||||
onChange={e => setReason(e.target.value)}
|
||||
placeholder="请输入调整原因..."
|
||||
rows={2}
|
||||
maxLength={500}
|
||||
style={{ marginTop: 4 }}
|
||||
/>
|
||||
</div>
|
||||
</Space>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default QuotaAdjustModal;
|
||||
Reference in New Issue
Block a user