const apiBaseUrl = '/server/api' export const API_BASE_URL = apiBaseUrl export type SendCodePayload = { phone: string scene: 'register' | 'login' | 'reset' } export type SendCodeResponse = { message: string } export type LoginCodePayload = { phone: string code: string institution_code: string institution_name: string } export type BackendUser = { id: number username: string phone: string real_name: string role_type: string institution: string | null department: string | null } export type LoginResponse = { message: string user?: Partial & Record tokens: { access: string refresh: string } } export class ApiRequestError extends Error { code?: string statusCode?: number constructor(message: string, code?: string, statusCode?: number) { super(message) this.name = 'ApiRequestError' this.code = code this.statusCode = statusCode } } function readErrorMessage(data: unknown, fallback: string) { if (data && typeof data === 'object') { const payload = data as Record const message = payload.message || payload.detail || payload.error if (typeof message === 'string' && message.trim()) return message } return fallback } function request(url: string, data: unknown): Promise { return new Promise((resolve, reject) => { uni.request({ url: `${API_BASE_URL}${url}`, method: 'POST', timeout: 10000, header: { 'Content-Type': 'application/json' }, data, success: response => { if (response.statusCode >= 200 && response.statusCode < 300) { resolve(response.data as T) return } const payload = response.data as Record | undefined const code = typeof payload?.code === 'string' ? payload.code : undefined reject(new ApiRequestError(readErrorMessage(response.data, `请求失败(${response.statusCode})`), code, response.statusCode)) }, fail: error => { reject(new ApiRequestError(error.errMsg || '无法连接服务')) } }) }) } function isLoginResponse(data: unknown): data is LoginResponse { if (!data || typeof data !== 'object') return false const payload = data as Partial const tokens = payload.tokens as Partial | undefined return Boolean( payload.tokens && typeof tokens?.access === 'string' && typeof tokens?.refresh === 'string' ) } export function sendLoginCode(phone: string, scene: SendCodePayload['scene'] = 'login'): Promise { return request('/user/auth/send-code/', { phone, scene }) } export function loginWithCode(payload: LoginCodePayload): Promise { return request('/user/auth/login-code/', payload).then(response => { if (isLoginResponse(response)) return response throw new Error('登录接口返回数据格式异常') }) }