feat(admin+api): 列表页子路由重构、结算历史与充值截图清理
赛事/代理管理从表格展开改为子路由详情页;结算页增加预览弹窗与历史记录;媒体库支持截图存储统计与自动/手动清理;Player 端充值截图压缩为 WebP 300KB。
This commit is contained in:
@@ -7,10 +7,39 @@ export interface AdminBreadcrumbItem {
|
||||
export function resolveAdminBreadcrumb(
|
||||
path: string,
|
||||
t: (key: string) => string,
|
||||
query: Record<string, unknown> = {},
|
||||
): AdminBreadcrumbItem[] | null {
|
||||
if (/^\/settlement\/[^/]+/.test(path)) {
|
||||
if (/^\/users\/agents\/[^/]+\/players/.test(path)) {
|
||||
return [
|
||||
{ label: t('nav.agents_players'), to: '/users' },
|
||||
{ label: t('breadcrumb.agent_direct_players') },
|
||||
];
|
||||
}
|
||||
if (path === '/users/settings') {
|
||||
return [
|
||||
{ label: t('nav.agents_players'), to: '/users' },
|
||||
{ label: t('user.page_settings') },
|
||||
];
|
||||
}
|
||||
if (/^\/matches\/leagues\/[^/]+/.test(path)) {
|
||||
return [
|
||||
{ label: t('nav.matches'), to: '/matches' },
|
||||
{ label: t('breadcrumb.league_fixtures') },
|
||||
];
|
||||
}
|
||||
if (/^\/matches\/outrights\/leagues\/[^/]+/.test(path)) {
|
||||
return [
|
||||
{ label: t('nav.matches'), to: '/matches/outrights' },
|
||||
{ label: t('breadcrumb.league_outrights') },
|
||||
];
|
||||
}
|
||||
if (/^\/settlement\/[^/]+/.test(path)) {
|
||||
const returnTo =
|
||||
typeof query.returnTo === 'string' && query.returnTo.startsWith('/')
|
||||
? query.returnTo
|
||||
: '/matches';
|
||||
return [
|
||||
{ label: t('nav.matches'), to: returnTo },
|
||||
{ label: t('breadcrumb.settlement') },
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
/** 赛事列表 UI 状态(返回列表时恢复展开等) */
|
||||
/** 赛事列表 UI 状态(返回列表时恢复筛选与分页) */
|
||||
|
||||
const STORAGE_KEY = 'admin_matches_list_ui';
|
||||
export const MAX_EXPANDED_LEAGUES = 3;
|
||||
|
||||
export type MatchesListUiState = {
|
||||
expandedLeagueIds: string[];
|
||||
page: number;
|
||||
pageSize: number;
|
||||
filterStatus: string;
|
||||
@@ -13,7 +11,6 @@ export type MatchesListUiState = {
|
||||
|
||||
function defaultState(): MatchesListUiState {
|
||||
return {
|
||||
expandedLeagueIds: [],
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
filterStatus: '',
|
||||
@@ -21,44 +18,21 @@ function defaultState(): MatchesListUiState {
|
||||
};
|
||||
}
|
||||
|
||||
function capExpanded(ids: string[]): string[] {
|
||||
return ids.slice(0, MAX_EXPANDED_LEAGUES);
|
||||
}
|
||||
|
||||
export function readMatchesListUiState(): MatchesListUiState | null {
|
||||
try {
|
||||
const raw = sessionStorage.getItem(STORAGE_KEY);
|
||||
if (!raw) return null;
|
||||
const parsed = JSON.parse(raw) as MatchesListUiState;
|
||||
if (!Array.isArray(parsed.expandedLeagueIds)) return null;
|
||||
return {
|
||||
...parsed,
|
||||
expandedLeagueIds: capExpanded(parsed.expandedLeagueIds),
|
||||
};
|
||||
return JSON.parse(raw) as MatchesListUiState;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function writeMatchesListUiState(state: MatchesListUiState) {
|
||||
sessionStorage.setItem(
|
||||
STORAGE_KEY,
|
||||
JSON.stringify({
|
||||
...state,
|
||||
expandedLeagueIds: capExpanded(state.expandedLeagueIds),
|
||||
}),
|
||||
);
|
||||
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(state));
|
||||
}
|
||||
|
||||
export function patchMatchesListUiState(patch: Partial<MatchesListUiState>) {
|
||||
const base = readMatchesListUiState() ?? defaultState();
|
||||
writeMatchesListUiState({ ...base, ...patch });
|
||||
}
|
||||
|
||||
/** 从子页返回前确保该赛事行处于展开记录中 */
|
||||
export function ensureLeagueExpanded(leagueId: string) {
|
||||
if (!leagueId) return;
|
||||
const base = readMatchesListUiState() ?? defaultState();
|
||||
const ids = capExpanded([...new Set([...base.expandedLeagueIds, leagueId])]);
|
||||
writeMatchesListUiState({ ...base, expandedLeagueIds: ids });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user