112 lines
2.8 KiB
TypeScript
112 lines
2.8 KiB
TypeScript
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<BackendUser> & Record<string, unknown>
|
||
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<string, unknown>
|
||
const message = payload.message || payload.detail || payload.error
|
||
if (typeof message === 'string' && message.trim()) return message
|
||
}
|
||
return fallback
|
||
}
|
||
|
||
function request<T>(url: string, data: unknown): Promise<T> {
|
||
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<string, unknown> | 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<LoginResponse>
|
||
const tokens = payload.tokens as Partial<LoginResponse['tokens']> | undefined
|
||
|
||
return Boolean(
|
||
payload.tokens &&
|
||
typeof tokens?.access === 'string' &&
|
||
typeof tokens?.refresh === 'string'
|
||
)
|
||
}
|
||
|
||
export function sendLoginCode(phone: string, scene: SendCodePayload['scene'] = 'login'): Promise<SendCodeResponse> {
|
||
return request<SendCodeResponse>('/user/auth/send-code/', {
|
||
phone,
|
||
scene
|
||
})
|
||
}
|
||
|
||
export function loginWithCode(payload: LoginCodePayload): Promise<LoginResponse> {
|
||
return request<LoginResponse>('/user/auth/login-code/', payload).then(response => {
|
||
if (isLoginResponse(response)) return response
|
||
throw new Error('登录接口返回数据格式异常')
|
||
})
|
||
}
|