🎨 refactor(TokensTable): refactor TokensTable UI & UX for clearer data and inline actions

This commit overhauls the `TokensTable` component to deliver a cleaner, more intuitive experience.

Key changes
1. Quota
   • Merged “Used” & “Remaining” into a single “Quota” column.
   • Uses a circular `Progress` with %-label; full details shown on tooltip.

2. Status
   • Tag now embeds a small `Switch` (prefixIcon) to enable/disable a token in-place.
   • Removed enable/disable actions from the old dropdown.

3. Columns & layout
   • Added dedicated “Group” column (moved from Status).
   • Added “Key” column:
     – Read-only `Input` styled like Home page base-URL field.
     – Masked value (`sk-abc********xyz`) by default.
     – Eye button toggles reveal/hide; Copy button copies full key (without modal).
   • Dropped “More” menu; Delete is now a direct button in the action area.

4. Model limits
   • Shows vendor icons inside an `AvatarGroup`; tooltip lists the exact models.

5. IP restriction
   • Displays first IP, extra count as “+N” Tag with tooltip.
   • Unlimited shows white Tag.

6. Cleanup / misc.
   • Removed unused helpers (`getQuotaPerUnit`), icons (`IconMore`, eye/copy duplicates, etc.).
   • Replaced legacy modal view of key with inline input behaviour.
   • Tweaked paddings, themes, sizes to align with design system.

BREAKING CHANGE: Table column order & names have changed; update any tests or docs referencing the old structure.
This commit is contained in:
t0ng7u
2025-07-12 03:35:19 +08:00
parent cf711d55a5
commit 7c4b83a430
14 changed files with 394 additions and 311 deletions

View File

@@ -63,7 +63,6 @@ const ChannelsTable = () => {
}
return (
<Tag
size='large'
color={type2label[type]?.color}
shape='circle'
prefixIcon={getChannelIcon(type)}
@@ -77,7 +76,6 @@ const ChannelsTable = () => {
return (
<Tag
color='light-blue'
size='large'
shape='circle'
type='light'
>
@@ -90,25 +88,25 @@ const ChannelsTable = () => {
switch (status) {
case 1:
return (
<Tag size='large' color='green' shape='circle'>
<Tag color='green' shape='circle'>
{t('已启用')}
</Tag>
);
case 2:
return (
<Tag size='large' color='red' shape='circle'>
<Tag color='red' shape='circle'>
{t('已禁用')}
</Tag>
);
case 3:
return (
<Tag size='large' color='yellow' shape='circle'>
<Tag color='yellow' shape='circle'>
{t('自动禁用')}
</Tag>
);
default:
return (
<Tag size='large' color='grey' shape='circle'>
<Tag color='grey' shape='circle'>
{t('未知状态')}
</Tag>
);
@@ -120,31 +118,31 @@ const ChannelsTable = () => {
time = time.toFixed(2) + t(' 秒');
if (responseTime === 0) {
return (
<Tag size='large' color='grey' shape='circle'>
<Tag color='grey' shape='circle'>
{t('未测试')}
</Tag>
);
} else if (responseTime <= 1000) {
return (
<Tag size='large' color='green' shape='circle'>
<Tag color='green' shape='circle'>
{time}
</Tag>
);
} else if (responseTime <= 3000) {
return (
<Tag size='large' color='lime' shape='circle'>
<Tag color='lime' shape='circle'>
{time}
</Tag>
);
} else if (responseTime <= 5000) {
return (
<Tag size='large' color='yellow' shape='circle'>
<Tag color='yellow' shape='circle'>
{time}
</Tag>
);
} else {
return (
<Tag size='large' color='red' shape='circle'>
<Tag color='red' shape='circle'>
{time}
</Tag>
);
@@ -331,7 +329,7 @@ const ChannelsTable = () => {
<div>
<Space spacing={1}>
<Tooltip content={t('已用额度')}>
<Tag color='white' type='ghost' size='large' shape='circle'>
<Tag color='white' type='ghost' shape='circle'>
{renderQuota(record.used_quota)}
</Tag>
</Tooltip>
@@ -339,7 +337,6 @@ const ChannelsTable = () => {
<Tag
color='white'
type='ghost'
size='large'
shape='circle'
onClick={() => updateChannelBalance(record)}
>
@@ -352,7 +349,7 @@ const ChannelsTable = () => {
} else {
return (
<Tooltip content={t('已用额度')}>
<Tag color='white' type='ghost' size='large' shape='circle'>
<Tag color='white' type='ghost' shape='circle'>
{renderQuota(record.used_quota)}
</Tag>
</Tooltip>
@@ -1240,7 +1237,7 @@ const ChannelsTable = () => {
tab={
<span className="flex items-center gap-2">
{t('全部')}
<Tag color={activeTypeKey === 'all' ? 'red' : 'grey'} size='small' shape='circle'>
<Tag color={activeTypeKey === 'all' ? 'red' : 'grey'} shape='circle'>
{channelTypeCounts['all'] || 0}
</Tag>
</span>
@@ -1258,7 +1255,7 @@ const ChannelsTable = () => {
<span className="flex items-center gap-2">
{getChannelIcon(option.value)}
{option.label}
<Tag color={activeTypeKey === key ? 'red' : 'grey'} size='small' shape='circle'>
<Tag color={activeTypeKey === key ? 'red' : 'grey'} shape='circle'>
{count}
</Tag>
</span>
@@ -1461,7 +1458,7 @@ const ChannelsTable = () => {
const fixChannelsAbilities = async () => {
const res = await API.post(`/api/channel/fix`);
const { success, message, data } = res.data;
const { success, message, data } = res.data;
if (success) {
showSuccess(t('已修复 ${success} 个通道,失败 ${fails} 个通道。').replace('${success}', data.success).replace('${fails}', data.fails));
await refresh();
@@ -2033,7 +2030,7 @@ const ChannelsTable = () => {
if (isTesting) {
return (
<Tag size='large' color='blue' shape='circle'>
<Tag color='blue' shape='circle'>
{t('测试中')}
</Tag>
);
@@ -2041,7 +2038,7 @@ const ChannelsTable = () => {
if (!testResult) {
return (
<Tag size='large' color='grey' shape='circle'>
<Tag color='grey' shape='circle'>
{t('未开始')}
</Tag>
);
@@ -2050,7 +2047,6 @@ const ChannelsTable = () => {
return (
<div className="flex items-center gap-2">
<Tag
size='large'
color={testResult.success ? 'green' : 'red'}
shape='circle'
>