Add WeChat in-app JSAPI recharge for g2.tkmind.cn.

Use JSAPI with bound openid inside WeChat instead of QR long-press, and include related auth redirect and admin UX fixes.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-06-16 16:20:04 +08:00
parent bb70634a96
commit f818dd0307
15 changed files with 260 additions and 32 deletions
+20 -6
View File
@@ -111,9 +111,21 @@ async function parseErrorResponse(res: Response) {
}
let unauthorizedHandler: (() => void) | null = null;
let unauthorizedHandling = false;
export function setUnauthorizedHandler(handler: (() => void) | null) {
unauthorizedHandler = handler;
if (handler) unauthorizedHandling = false;
}
export function resetUnauthorizedGuard() {
unauthorizedHandling = false;
}
function notifyUnauthorized() {
if (!unauthorizedHandler || unauthorizedHandling) return;
unauthorizedHandling = true;
unauthorizedHandler();
}
async function portalFetch<T>(path: string, init?: RequestInit): Promise<T> {
@@ -131,7 +143,7 @@ async function portalFetch<T>(path: string, init?: RequestInit): Promise<T> {
}
if (res.status === 401) {
unauthorizedHandler?.();
notifyUnauthorized();
const text = await res.text().catch(() => '');
throw new ApiError(401, text || '未授权,请重新登录');
}
@@ -173,7 +185,7 @@ async function apiFetch<T>(path: string, init?: RequestInit): Promise<T> {
}
if (res.status === 401) {
unauthorizedHandler?.();
notifyUnauthorized();
const text = await res.text().catch(() => '');
throw new ApiError(401, text || '未授权,请重新登录');
}
@@ -258,6 +270,7 @@ export async function checkAuth(): Promise<AuthStatus> {
const response = await fetch('/auth/status');
if (!response.ok) return { authenticated: false };
const status = (await response.json()) as AuthStatus;
if (status.authenticated) resetUnauthorizedGuard();
if (status.authenticated && status.mode === 'user' && !status.capabilities) {
try {
const me = await getMe();
@@ -303,7 +316,7 @@ export async function getBillingConfig(): Promise<BillingConfig> {
export async function createRechargeOrder(input: {
amountCents: number;
payScene: 'native' | 'h5';
payScene: 'native' | 'h5' | 'jsapi';
}): Promise<RechargeOrder> {
const result = await portalFetch<{ order: RechargeOrder }>('/auth/billing/recharge-orders', {
method: 'POST',
@@ -565,7 +578,7 @@ export async function fetchPreviewAsset(path: string): Promise<string> {
throw new ApiError(0, formatNetworkError(err));
}
if (res.status === 401) {
unauthorizedHandler?.();
notifyUnauthorized();
throw new ApiError(401, '未授权,请重新登录');
}
if (!res.ok) {
@@ -699,7 +712,7 @@ export async function fetchMindSpacePageDraftPreview(
throw new ApiError(0, formatNetworkError(err));
}
if (res.status === 401) {
unauthorizedHandler?.();
notifyUnauthorized();
throw new ApiError(401, '未授权,请重新登录');
}
if (!res.ok) {
@@ -1178,6 +1191,7 @@ export async function login(username: string, password: string): Promise<PortalU
if (!response.ok) {
throw new ApiError(response.status, body?.message ?? '登录失败');
}
resetUnauthorizedGuard();
if (body?.user) {
try {
const me = await getMe();
@@ -1734,7 +1748,7 @@ export function subscribeSessionEvents(
});
if (res.status === 401) {
unauthorizedHandler?.();
notifyUnauthorized();
throw new ApiError(401, 'SSE 未授权');
}