export interface MerchantJwtPayload { user_id: number | string username: string tenant_id: number | string operator_tenant_id?: number | string membership_id: number | string app_code: string client_type?: string exp: number } export class MerchantTokenExpiredError extends Error { constructor() { super('登录状态已过期') this.name = 'MerchantTokenExpiredError' } } function decodeBase64Url(value: string) { const normalized = value.replace(/-/g, '+').replace(/_/g, '/') const padded = normalized.padEnd(Math.ceil(normalized.length / 4) * 4, '=') const binary = atob(padded) const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0)) return new TextDecoder().decode(bytes) } export function decodeMerchantToken(token: string): MerchantJwtPayload { const payloadPart = token.split('.')[1] if (!payloadPart) throw new Error('登录凭证格式无效') try { const value: unknown = JSON.parse(decodeBase64Url(payloadPart)) if (!value || typeof value !== 'object') throw new Error() const payload = value as Partial if (!payload.user_id || !payload.username || !payload.tenant_id || !payload.membership_id || !payload.exp) throw new Error() if (payload.app_code !== 'MERCHANT') throw new Error('账号不属于当前应用端') if (payload.exp * 1000 <= Date.now()) throw new MerchantTokenExpiredError() return payload as MerchantJwtPayload } catch (error) { if (error instanceof Error && error.message === '账号不属于当前应用端') throw error if (error instanceof MerchantTokenExpiredError) throw error throw new Error('登录凭证无法解析,请重新登录') } }