feat: 账号列表显示所属分组
- Account模型新增Groups虚拟字段 - 账号列表API预加载Group信息 - 账号管理页面新增分组列,使用GroupBadge展示
This commit is contained in:
@@ -68,7 +68,8 @@ type Account struct {
|
|||||||
AccountGroups []AccountGroup `gorm:"foreignKey:AccountID" json:"account_groups,omitempty"`
|
AccountGroups []AccountGroup `gorm:"foreignKey:AccountID" json:"account_groups,omitempty"`
|
||||||
|
|
||||||
// 虚拟字段 (不存储到数据库)
|
// 虚拟字段 (不存储到数据库)
|
||||||
GroupIDs []int64 `gorm:"-" json:"group_ids,omitempty"`
|
GroupIDs []int64 `gorm:"-" json:"group_ids,omitempty"`
|
||||||
|
Groups []*Group `gorm:"-" json:"groups,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Account) TableName() string {
|
func (Account) TableName() string {
|
||||||
|
|||||||
@@ -78,15 +78,19 @@ func (r *AccountRepository) ListWithFilters(ctx context.Context, params paginati
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := db.Preload("Proxy").Preload("AccountGroups").Offset(params.Offset()).Limit(params.Limit()).Order("id DESC").Find(&accounts).Error; err != nil {
|
if err := db.Preload("Proxy").Preload("AccountGroups.Group").Offset(params.Offset()).Limit(params.Limit()).Order("id DESC").Find(&accounts).Error; err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 填充每个 Account 的 GroupIDs 虚拟字段
|
// 填充每个 Account 的虚拟字段(GroupIDs 和 Groups)
|
||||||
for i := range accounts {
|
for i := range accounts {
|
||||||
accounts[i].GroupIDs = make([]int64, 0, len(accounts[i].AccountGroups))
|
accounts[i].GroupIDs = make([]int64, 0, len(accounts[i].AccountGroups))
|
||||||
|
accounts[i].Groups = make([]*model.Group, 0, len(accounts[i].AccountGroups))
|
||||||
for _, ag := range accounts[i].AccountGroups {
|
for _, ag := range accounts[i].AccountGroups {
|
||||||
accounts[i].GroupIDs = append(accounts[i].GroupIDs, ag.GroupID)
|
accounts[i].GroupIDs = append(accounts[i].GroupIDs, ag.GroupID)
|
||||||
|
if ag.Group != nil {
|
||||||
|
accounts[i].Groups = append(accounts[i].Groups, ag.Group)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -666,6 +666,7 @@ export default {
|
|||||||
status: 'Status',
|
status: 'Status',
|
||||||
schedulable: 'Schedule',
|
schedulable: 'Schedule',
|
||||||
todayStats: "Today's Stats",
|
todayStats: "Today's Stats",
|
||||||
|
groups: 'Groups',
|
||||||
usageWindows: 'Usage Windows',
|
usageWindows: 'Usage Windows',
|
||||||
priority: 'Priority',
|
priority: 'Priority',
|
||||||
lastUsed: 'Last Used',
|
lastUsed: 'Last Used',
|
||||||
|
|||||||
@@ -721,6 +721,9 @@ export default {
|
|||||||
weight: '权重',
|
weight: '权重',
|
||||||
status: '状态',
|
status: '状态',
|
||||||
schedulable: '调度',
|
schedulable: '调度',
|
||||||
|
todayStats: '今日统计',
|
||||||
|
groups: '分组',
|
||||||
|
usageWindows: '用量窗口',
|
||||||
lastUsed: '最近使用',
|
lastUsed: '最近使用',
|
||||||
actions: '操作',
|
actions: '操作',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -324,6 +324,7 @@ export interface Account {
|
|||||||
updated_at: string;
|
updated_at: string;
|
||||||
proxy?: Proxy;
|
proxy?: Proxy;
|
||||||
group_ids?: number[]; // Groups this account belongs to
|
group_ids?: number[]; // Groups this account belongs to
|
||||||
|
groups?: Group[]; // Preloaded group objects
|
||||||
|
|
||||||
// Rate limit & scheduling fields
|
// Rate limit & scheduling fields
|
||||||
schedulable: boolean;
|
schedulable: boolean;
|
||||||
|
|||||||
@@ -123,6 +123,21 @@
|
|||||||
<AccountTodayStatsCell :account="row" />
|
<AccountTodayStatsCell :account="row" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template #cell-groups="{ row }">
|
||||||
|
<div v-if="row.groups && row.groups.length > 0" class="flex flex-wrap gap-1.5">
|
||||||
|
<GroupBadge
|
||||||
|
v-for="group in row.groups"
|
||||||
|
:key="group.id"
|
||||||
|
:name="group.name"
|
||||||
|
:platform="group.platform"
|
||||||
|
:subscription-type="group.subscription_type"
|
||||||
|
:rate-multiplier="group.rate_multiplier"
|
||||||
|
:show-rate="false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span v-else class="text-sm text-gray-400 dark:text-dark-500">-</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template #cell-usage="{ row }">
|
<template #cell-usage="{ row }">
|
||||||
<AccountUsageCell :account="row" />
|
<AccountUsageCell :account="row" />
|
||||||
</template>
|
</template>
|
||||||
@@ -301,6 +316,7 @@ import AccountStatusIndicator from '@/components/account/AccountStatusIndicator.
|
|||||||
import AccountUsageCell from '@/components/account/AccountUsageCell.vue'
|
import AccountUsageCell from '@/components/account/AccountUsageCell.vue'
|
||||||
import AccountTodayStatsCell from '@/components/account/AccountTodayStatsCell.vue'
|
import AccountTodayStatsCell from '@/components/account/AccountTodayStatsCell.vue'
|
||||||
import AccountTestModal from '@/components/account/AccountTestModal.vue'
|
import AccountTestModal from '@/components/account/AccountTestModal.vue'
|
||||||
|
import GroupBadge from '@/components/common/GroupBadge.vue'
|
||||||
import { formatRelativeTime } from '@/utils/format'
|
import { formatRelativeTime } from '@/utils/format'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
@@ -314,6 +330,7 @@ const columns = computed<Column[]>(() => [
|
|||||||
{ key: 'status', label: t('admin.accounts.columns.status'), sortable: true },
|
{ key: 'status', label: t('admin.accounts.columns.status'), sortable: true },
|
||||||
{ key: 'schedulable', label: t('admin.accounts.columns.schedulable'), sortable: true },
|
{ key: 'schedulable', label: t('admin.accounts.columns.schedulable'), sortable: true },
|
||||||
{ key: 'today_stats', label: t('admin.accounts.columns.todayStats'), sortable: false },
|
{ key: 'today_stats', label: t('admin.accounts.columns.todayStats'), sortable: false },
|
||||||
|
{ key: 'groups', label: t('admin.accounts.columns.groups'), sortable: false },
|
||||||
{ key: 'usage', label: t('admin.accounts.columns.usageWindows'), sortable: false },
|
{ key: 'usage', label: t('admin.accounts.columns.usageWindows'), sortable: false },
|
||||||
{ key: 'priority', label: t('admin.accounts.columns.priority'), sortable: true },
|
{ key: 'priority', label: t('admin.accounts.columns.priority'), sortable: true },
|
||||||
{ key: 'last_used_at', label: t('admin.accounts.columns.lastUsed'), sortable: true },
|
{ key: 'last_used_at', label: t('admin.accounts.columns.lastUsed'), sortable: true },
|
||||||
|
|||||||
Reference in New Issue
Block a user