feat(admin,api,player): 代理层级管理、额度上下分与玩家钱包详情
新增代理管理器与二级代理体系,完善信用额度/上下分上下文与冻结策略;代理端玩家与子代理管理增强;玩家端新增钱包详情页与交易筛选优化。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,28 +1,101 @@
|
||||
import axios from 'axios';
|
||||
import router from './router';
|
||||
import { clearStaffSession } from './stores/auth';
|
||||
import { clearStaffSession, reconcileStaffSessionFromToken, useAuthStore } from './stores/auth';
|
||||
import { ensureStaffSession, resetStaffSessionHydration } from './utils/session-hydrate';
|
||||
|
||||
const api = axios.create({ baseURL: '/api' });
|
||||
|
||||
let handling401 = false;
|
||||
let handling403Portal = false;
|
||||
|
||||
const PORTAL_MISMATCH_MESSAGES = new Set(['Admin access only', 'Agent access only']);
|
||||
|
||||
function requestPath(config: { url?: string; baseURL?: string } | undefined): string {
|
||||
if (!config?.url) return '';
|
||||
const base = config.baseURL ?? '';
|
||||
return `${base}${config.url}`;
|
||||
}
|
||||
|
||||
api.interceptors.request.use((config) => {
|
||||
const t = localStorage.getItem('manage_token');
|
||||
if (t) config.headers.Authorization = `Bearer ${t}`;
|
||||
|
||||
reconcileStaffSessionFromToken();
|
||||
const auth = useAuthStore();
|
||||
const path = requestPath(config);
|
||||
|
||||
if (path.includes('/admin/') && auth.isAgent.value) {
|
||||
return Promise.reject(
|
||||
Object.assign(new Error('Agent portal blocked admin API'), {
|
||||
isPortalMismatch: true,
|
||||
blockedPath: path,
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (path.includes('/agent/') && auth.isAdmin.value) {
|
||||
return Promise.reject(
|
||||
Object.assign(new Error('Admin portal blocked agent API'), {
|
||||
isPortalMismatch: true,
|
||||
blockedPath: path,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return config;
|
||||
});
|
||||
|
||||
api.interceptors.response.use(
|
||||
(res) => res,
|
||||
async (err) => {
|
||||
if (err.isPortalMismatch) {
|
||||
await ensureStaffSession();
|
||||
if (router.currentRoute.value.path !== '/login') {
|
||||
await router.replace('/');
|
||||
}
|
||||
return Promise.reject(err);
|
||||
}
|
||||
|
||||
if (err.response?.status === 401 && !handling401) {
|
||||
handling401 = true;
|
||||
clearStaffSession();
|
||||
resetStaffSessionHydration();
|
||||
if (router.currentRoute.value.path !== '/login') {
|
||||
await router.replace('/login');
|
||||
}
|
||||
handling401 = false;
|
||||
}
|
||||
|
||||
if (
|
||||
err.response?.status === 403 &&
|
||||
!handling403Portal &&
|
||||
PORTAL_MISMATCH_MESSAGES.has(err.response?.data?.message)
|
||||
) {
|
||||
handling403Portal = true;
|
||||
await ensureStaffSession();
|
||||
handling403Portal = false;
|
||||
|
||||
const auth = useAuthStore();
|
||||
const path = requestPath(err.config);
|
||||
const isAdminApi = path.includes('/admin/');
|
||||
const isAgentApi = path.includes('/agent/');
|
||||
|
||||
if ((isAdminApi && auth.isAgent.value) || (isAgentApi && auth.isAdmin.value)) {
|
||||
if (router.currentRoute.value.path !== '/login') {
|
||||
await router.replace('/');
|
||||
}
|
||||
return Promise.reject(err);
|
||||
}
|
||||
|
||||
if (err.config) {
|
||||
return api.request(err.config);
|
||||
}
|
||||
|
||||
clearStaffSession();
|
||||
if (router.currentRoute.value.path !== '/login') {
|
||||
await router.replace('/login');
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.reject(err);
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user