Merge pull request #4279 from bestony/agent/0268b42f/bes-21-groups-id-column

feat(admin): /admin/groups 列表设置新增 ID 列
This commit is contained in:
Wesley Liddick
2026-07-15 09:38:46 +08:00
committed by GitHub
4 changed files with 117 additions and 9 deletions
@@ -757,6 +757,7 @@ export default {
public: 'Public',
columns: {
name: 'Name',
id: 'ID',
platform: 'Platform',
rateMultiplier: 'Rate Multiplier',
rpmOverride: 'RPM Override',
@@ -750,6 +750,7 @@ export default {
"确定要删除订阅分组 '{name}' 吗?此操作会让所有绑定此订阅的用户的 API Key 失效,并删除所有相关的订阅记录。此操作无法撤销。",
columns: {
name: '名称',
id: 'ID',
platform: '平台',
rateMultiplier: '费率倍数',
rpmOverride: 'RPM 覆盖',
+61 -7
View File
@@ -128,6 +128,12 @@
}}</span>
</template>
<template #cell-id="{ value }">
<span class="font-mono text-xs text-gray-500 dark:text-gray-400"
>#{{ value }}</span
>
</template>
<template #cell-platform="{ value }">
<span
:class="[
@@ -3612,10 +3618,19 @@ const appStore = useAppStore();
const onboardingStore = useOnboardingStore();
const ALWAYS_VISIBLE_COLUMNS = new Set(["name", "actions"]);
// Default hidden columns (hidden on first load / after schema bumps).
const DEFAULT_HIDDEN_COLUMNS = ["id"];
const HIDDEN_COLUMNS_KEY = "group-hidden-columns";
// Bump when adding new default-hidden columns so existing admins pick them up once.
const COLUMN_SETTINGS_VERSION_KEY = "group-column-settings-version";
const COLUMN_SETTINGS_VERSION = 2;
const VERSION_NEW_HIDDEN_COLUMNS: Record<number, string[]> = {
2: ["id"],
};
const allColumns = computed<Column[]>(() => [
{ key: "name", label: t("admin.groups.columns.name"), sortable: true },
{ key: "id", label: t("admin.groups.columns.id"), sortable: true },
{
key: "platform",
label: t("admin.groups.columns.platform"),
@@ -3665,16 +3680,51 @@ const loadSavedColumns = () => {
hiddenColumns.clear();
try {
const saved = localStorage.getItem(HIDDEN_COLUMNS_KEY);
if (!saved) return;
const parsed = JSON.parse(saved);
if (!Array.isArray(parsed)) return;
const validKeys = getValidHiddenColumnKeys();
parsed
.filter((key): key is string => typeof key === "string" && validKeys.has(key))
.forEach((key) => hiddenColumns.add(key));
if (saved) {
const parsed = JSON.parse(saved);
if (Array.isArray(parsed)) {
parsed
.filter(
(key): key is string =>
typeof key === "string" && validKeys.has(key),
)
.forEach((key) => hiddenColumns.add(key));
}
// Existing admins: auto-hide columns newly added as default-hidden.
const storedVersion = Number(
localStorage.getItem(COLUMN_SETTINGS_VERSION_KEY) ?? "1",
);
if (storedVersion < COLUMN_SETTINGS_VERSION) {
let mutated = false;
for (let v = storedVersion + 1; v <= COLUMN_SETTINGS_VERSION; v++) {
for (const key of VERSION_NEW_HIDDEN_COLUMNS[v] ?? []) {
if (validKeys.has(key) && !hiddenColumns.has(key)) {
hiddenColumns.add(key);
mutated = true;
}
}
}
if (mutated) {
saveColumnsToStorage();
} else {
localStorage.setItem(
COLUMN_SETTINGS_VERSION_KEY,
String(COLUMN_SETTINGS_VERSION),
);
}
}
} else {
DEFAULT_HIDDEN_COLUMNS.forEach((key) => {
if (validKeys.has(key)) hiddenColumns.add(key);
});
saveColumnsToStorage();
}
} catch (error) {
console.error("Failed to load group column settings:", error);
DEFAULT_HIDDEN_COLUMNS.forEach((key) => hiddenColumns.add(key));
}
};
@@ -3683,6 +3733,10 @@ const saveColumnsToStorage = () => {
const validKeys = getValidHiddenColumnKeys();
const keys = [...hiddenColumns].filter((key) => validKeys.has(key));
localStorage.setItem(HIDDEN_COLUMNS_KEY, JSON.stringify(keys));
localStorage.setItem(
COLUMN_SETTINGS_VERSION_KEY,
String(COLUMN_SETTINGS_VERSION),
);
} catch (error) {
console.error("Failed to save group column settings:", error);
}
@@ -31,6 +31,7 @@ const {
const messages: Record<string, string> = {
'admin.groups.columnSettings': 'Column Settings',
'admin.groups.columns.name': 'Name',
'admin.groups.columns.id': 'ID',
'admin.groups.columns.platform': 'Platform',
'admin.groups.columns.billingType': 'Billing Type',
'admin.groups.columns.rateMultiplier': 'Rate Multiplier',
@@ -251,7 +252,7 @@ describe('admin GroupsView column settings', () => {
localStorage.clear()
})
it('renders all group columns by default in the current order', async () => {
it('hides the id column by default while keeping other group columns visible', async () => {
const wrapper = await mountView()
expect(columnKeys(wrapper)).toEqual([
@@ -266,6 +267,8 @@ describe('admin GroupsView column settings', () => {
'status',
'actions',
])
expect(localStorage.getItem('group-hidden-columns')).toBe(JSON.stringify(['id']))
expect(localStorage.getItem('group-column-settings-version')).toBe('2')
})
it('applies saved hidden columns on mount and ignores unknown keys', async () => {
@@ -273,6 +276,26 @@ describe('admin GroupsView column settings', () => {
'group-hidden-columns',
JSON.stringify(['usage', 'capacity', 'removed_column', 'name', 'actions']),
)
localStorage.setItem('group-column-settings-version', '2')
const wrapper = await mountView()
expect(columnKeys(wrapper)).toEqual([
'name',
'id',
'platform',
'billing_type',
'rate_multiplier',
'is_exclusive',
'account_count',
'status',
'actions',
])
})
it('auto-hides id for existing saved column prefs after version bump', async () => {
localStorage.setItem('group-hidden-columns', JSON.stringify(['usage']))
// No version key → treated as version 1, migrate to 2 and hide id.
const wrapper = await mountView()
@@ -283,9 +306,14 @@ describe('admin GroupsView column settings', () => {
'rate_multiplier',
'is_exclusive',
'account_count',
'capacity',
'status',
'actions',
])
expect(JSON.parse(localStorage.getItem('group-hidden-columns')!)).toEqual(
expect.arrayContaining(['usage', 'id']),
)
expect(localStorage.getItem('group-column-settings-version')).toBe('2')
})
it('toggles a column and persists hidden column keys', async () => {
@@ -305,7 +333,31 @@ describe('admin GroupsView column settings', () => {
'status',
'actions',
])
expect(localStorage.getItem('group-hidden-columns')).toBe(JSON.stringify(['usage']))
expect(JSON.parse(localStorage.getItem('group-hidden-columns')!)).toEqual(
expect.arrayContaining(['id', 'usage']),
)
})
it('can show the id column from column settings', async () => {
const wrapper = await mountView()
await openColumnSettings(wrapper)
await clickColumnToggle(wrapper, 'ID')
expect(columnKeys(wrapper)).toEqual([
'name',
'id',
'platform',
'billing_type',
'rate_multiplier',
'is_exclusive',
'account_count',
'capacity',
'usage',
'status',
'actions',
])
expect(localStorage.getItem('group-hidden-columns')).toBe(JSON.stringify([]))
})
it('skips usage and capacity fetches until consuming columns are shown', async () => {