import { AkReq } from '@/uni_modules/ak-req/index.uts' import type { UserProfile } from '@/types/mall-types.uts' import type { DeliveryInfoType } from '@/types/delivery.uts' import { getDeliveryProfileByUserId } from '@/api/delivery.uts' import supa from '@/components/supadb/aksupainstance.uts' import { getCurrentUser, setIsLoggedIn, setUserProfile } from '@/utils/store.uts' export type DeliveryAuthOptions = { redirectOnFail?: boolean toastOnFail?: boolean redirect?: string message?: string } export type DeliveryAuthResult = { ok: boolean message: string userInfo: UserProfile | null deliveryInfo: DeliveryInfoType | null } const DELIVERY_LOGIN_PATH = '/pages/user/login' const DELIVERY_LOGIN_TARGET = '/pages/user/login?mode=delivery' const DELIVERY_HOME_PATH = '/pages/mall/delivery/home/index' const DELIVERY_USER_KEY = 'delivery_user_info' const DELIVERY_INFO_KEY = 'delivery_info' const DELIVERY_TOKEN_KEY = 'delivery_token' const DELIVERY_ROLE = 'delivery' const DELIVERY_ROLE_ALIAS = 'Deliverer' let redirectingToDeliveryLogin = false function hasText(value: string | null): boolean { return value != null && value !== '' } function shouldShowToast(enabled: boolean | null): boolean { return enabled == null || enabled === true } function shouldRedirect(enabled: boolean | null): boolean { return enabled == null || enabled === true } function getCurrentRoute(): string { try { const pages = getCurrentPages() as Array if (pages.length === 0) { return '' } const currentPage = pages[pages.length - 1] const route = currentPage['route'] if (route != null) { return '/' + route } } catch (e) {} return '' } function buildFailureResult(message: string, userInfo: UserProfile | null = null): DeliveryAuthResult { return { ok: false, message, userInfo, deliveryInfo: null } } function parseUserInfo(raw: string): UserProfile | null { try { return JSON.parse(raw) as UserProfile } catch (e) { return null } } function parseDeliveryInfo(raw: string): DeliveryInfoType | null { try { return JSON.parse(raw) as DeliveryInfoType } catch (e) { return null } } function persistUserInfo(userInfo: UserProfile): void { uni.setStorageSync(DELIVERY_USER_KEY, JSON.stringify(userInfo)) } function persistDeliveryInfo(info: DeliveryInfoType): void { uni.setStorageSync(DELIVERY_INFO_KEY, JSON.stringify(info)) } export function setDeliveryInfo(info: DeliveryInfoType): void { persistDeliveryInfo(info) } export function clearDeliveryInfo(): void { uni.removeStorageSync(DELIVERY_INFO_KEY) } export function saveDeliverySession(token: string, userInfo: UserProfile, deliveryInfo: DeliveryInfoType | null): void { AkReq.setToken(token, '', Date.now() + 24 * 60 * 60 * 1000) uni.setStorageSync(DELIVERY_TOKEN_KEY, token) persistUserInfo(userInfo) setIsLoggedIn(true) setUserProfile(userInfo) if (deliveryInfo != null) { persistDeliveryInfo(deliveryInfo) } else { uni.removeStorageSync(DELIVERY_INFO_KEY) } } export function getToken(): string { const stored = uni.getStorageSync(DELIVERY_TOKEN_KEY) as string | null if (stored != null && stored != '') { return stored } const token = AkReq.getToken() return token != null ? token : '' } export function getUserInfo(): UserProfile | null { const raw = uni.getStorageSync(DELIVERY_USER_KEY) as string | null if (!hasText(raw)) { return null } return parseUserInfo(raw as string) } async function resolveUserInfo(): Promise { const cached = getUserInfo() if (cached != null) { return cached } try { const profile = await getCurrentUser() if (profile != null) { persistUserInfo(profile) } return profile } catch (e) { return null } } export function getDeliveryInfo(): DeliveryInfoType | null { const raw = uni.getStorageSync(DELIVERY_INFO_KEY) as string | null if (!hasText(raw)) { return null } return parseDeliveryInfo(raw as string) } export function isLoggedIn(): boolean { if (hasText(getToken()) && getUserInfo() != null) { return true } try { const session = supa.getSession() return session != null && session.user != null } catch (e) { return false } } export function isDelivererRole(userInfo: UserProfile | null): boolean { if (userInfo == null) { return false } const role = userInfo.role != null ? userInfo.role : '' return role == DELIVERY_ROLE || role == DELIVERY_ROLE_ALIAS } export async function checkDeliveryAccount(userInfo: UserProfile): Promise { const userId = userInfo.id != null ? userInfo.id : '' if (!hasText(userId)) { return null } return await getDeliveryProfileByUserId(userId) } export function clearDeliveryAuth(): void { try { AkReq.clearToken() } catch (e) {} uni.removeStorageSync(DELIVERY_TOKEN_KEY) uni.removeStorageSync(DELIVERY_USER_KEY) uni.removeStorageSync('user_id') clearDeliveryInfo() setIsLoggedIn(false) setUserProfile({ username: '', email: '' } as UserProfile) } export async function logoutDelivery(): Promise { clearDeliveryAuth() try { await supa.signOut() } catch (e) {} } function getRedirectTarget(explicitRedirect: string | null): string { if (hasText(explicitRedirect)) { return explicitRedirect as string } const currentRoute = getCurrentRoute() if (hasText(currentRoute) && currentRoute !== DELIVERY_LOGIN_PATH) { return currentRoute } return DELIVERY_HOME_PATH } export function redirectToDeliveryLogin(redirect?: string): void { const currentRoute = getCurrentRoute() if (currentRoute == DELIVERY_LOGIN_PATH) { return } if (redirectingToDeliveryLogin) { return } redirectingToDeliveryLogin = true let targetUrl = DELIVERY_LOGIN_TARGET const redirectTarget = getRedirectTarget(redirect != null ? redirect : null) if (hasText(redirectTarget)) { targetUrl = DELIVERY_LOGIN_TARGET + '&redirect=' + encodeURIComponent(redirectTarget) } uni.reLaunch({ url: targetUrl, complete: () => { setTimeout(() => { redirectingToDeliveryLogin = false }, 300) } }) } export function goDeliveryHome(): void { uni.reLaunch({ url: DELIVERY_HOME_PATH }) } export function isCurrentDeliveryPage(): boolean { return getCurrentRoute().startsWith('/pages/mall/delivery/') } export function handleDeliveryUnauthorized(message?: string, redirect?: string): void { clearDeliveryAuth() redirectToDeliveryLogin(redirect) if (message != null && message != '') { uni.showToast({ title: message, icon: 'none' }) } } function handleFailure(message: string, options?: DeliveryAuthOptions, userInfo: UserProfile | null = null): DeliveryAuthResult { clearDeliveryAuth() if (shouldShowToast(options?.toastOnFail ?? null) && hasText(message)) { uni.showToast({ title: message, icon: 'none' }) } if (shouldRedirect(options?.redirectOnFail ?? null)) { redirectToDeliveryLogin(getRedirectTarget(options?.redirect ?? null)) } return buildFailureResult(message, userInfo) } export async function requireDeliveryAuth(options?: DeliveryAuthOptions): Promise { const currentRoute = getCurrentRoute() const onLoginPage = currentRoute == DELIVERY_LOGIN_PATH const effectiveOptions: DeliveryAuthOptions = { redirectOnFail: onLoginPage ? false : options?.redirectOnFail, toastOnFail: options?.toastOnFail, redirect: options?.redirect, message: options?.message } if (!isLoggedIn()) { return handleFailure(options?.message != null ? options.message : '请先登录服务人员账号', effectiveOptions) } const userInfo = await resolveUserInfo() if (userInfo == null) { return handleFailure('登录状态已失效,请重新登录', effectiveOptions) } if (!isDelivererRole(userInfo)) { return handleFailure('当前账号不是上门服务人员账号', effectiveOptions, userInfo) } const deliveryInfo = await checkDeliveryAccount(userInfo) if (deliveryInfo == null) { return handleFailure('当前账号未绑定服务人员档案', effectiveOptions, userInfo) } if (deliveryInfo.status == 'disabled' || deliveryInfo.status == 'locked' || deliveryInfo.status == 'suspended') { return handleFailure('账号不可接单', effectiveOptions, userInfo) } if (deliveryInfo.usesMock && (!hasText(deliveryInfo.organizationId) || !hasText(deliveryInfo.organizationName))) { return handleFailure('当前账号未绑定服务机构', effectiveOptions, userInfo) } if (deliveryInfo.usesMock && deliveryInfo.certificateStatus == 'expired') { return handleFailure('资质已过期,请联系管理员', effectiveOptions, userInfo) } persistUserInfo(userInfo) persistDeliveryInfo(deliveryInfo) return { ok: true, message: '', userInfo, deliveryInfo } }