131 lines
3.8 KiB
TypeScript
131 lines
3.8 KiB
TypeScript
// 手动切换后端地址,部署时改成线上域名即可
|
|
// const BASE_URL = 'http://localhost:3000'
|
|
const BASE_URL = 'http://115.190.188.216:2850'
|
|
|
|
export { BASE_URL }
|
|
|
|
interface RequestOptions {
|
|
url: string
|
|
method?: 'GET' | 'POST' | 'PUT' | 'DELETE'
|
|
data?: Record<string, unknown>
|
|
header?: Record<string, string>
|
|
}
|
|
|
|
interface ApiResponse<T = unknown> {
|
|
code: number
|
|
data: T
|
|
message: string
|
|
}
|
|
|
|
/** 将下划线命名转换为驼峰命名 */
|
|
function toCamelCase(obj: any): any {
|
|
if (obj === null || typeof obj !== 'object') return obj
|
|
|
|
if (Array.isArray(obj)) {
|
|
return obj.map(item => toCamelCase(item))
|
|
}
|
|
|
|
const result: any = {}
|
|
for (const key in obj) {
|
|
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
const camelKey = key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase())
|
|
result[camelKey] = toCamelCase(obj[key])
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
function getToken(): string {
|
|
return uni.getStorageSync('token') || ''
|
|
}
|
|
|
|
export function request<T = unknown>(options: RequestOptions): Promise<T> {
|
|
const { url, method = 'GET', data, header = {} } = options
|
|
const token = getToken()
|
|
|
|
return new Promise((resolve, reject) => {
|
|
uni.request({
|
|
url: `${BASE_URL}${url}`,
|
|
method,
|
|
data,
|
|
header: {
|
|
'Content-Type': 'application/json',
|
|
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
...header,
|
|
},
|
|
success(res) {
|
|
const statusCode = res.statusCode
|
|
if (statusCode === 401) {
|
|
uni.removeStorageSync('token')
|
|
uni.showToast({ title: '请重新登录', icon: 'none' })
|
|
autoLogin()
|
|
reject(new Error('未授权'))
|
|
return
|
|
}
|
|
if (statusCode >= 200 && statusCode < 300) {
|
|
const body = res.data as ApiResponse<T>
|
|
if (body.code === 0) {
|
|
// 将下划线命名转换为驼峰命名
|
|
const camelData = toCamelCase(body.data)
|
|
resolve(camelData)
|
|
} else {
|
|
uni.showToast({ title: body.message || '请求失败', icon: 'none' })
|
|
reject(new Error(body.message))
|
|
}
|
|
} else {
|
|
uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' })
|
|
reject(new Error(`HTTP ${statusCode}`))
|
|
}
|
|
},
|
|
fail(err) {
|
|
uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' })
|
|
reject(err)
|
|
},
|
|
})
|
|
})
|
|
}
|
|
|
|
/** 微信小程序自动登录 */
|
|
export function autoLogin(): Promise<void> {
|
|
return new Promise((resolve, reject) => {
|
|
uni.login({
|
|
provider: 'weixin',
|
|
success: async (loginRes) => {
|
|
if (loginRes.code) {
|
|
try {
|
|
const data = await request<{ token: string; userId: number }>({
|
|
url: '/api/auth/wx-login',
|
|
method: 'POST',
|
|
data: { code: loginRes.code },
|
|
})
|
|
uni.setStorageSync('token', data.token)
|
|
resolve()
|
|
} catch (err) {
|
|
console.error('登录接口调用失败:', err)
|
|
reject(err)
|
|
}
|
|
} else {
|
|
console.error('微信登录获取 code 失败')
|
|
reject(new Error('获取微信 code 失败'))
|
|
}
|
|
},
|
|
fail: (err) => {
|
|
console.error('uni.login 失败:', err)
|
|
reject(err)
|
|
},
|
|
})
|
|
})
|
|
}
|
|
|
|
export const get = <T = unknown>(url: string, data?: Record<string, unknown>) =>
|
|
request<T>({ url, method: 'GET', data })
|
|
|
|
export const post = <T = unknown>(url: string, data?: Record<string, unknown>) =>
|
|
request<T>({ url, method: 'POST', data })
|
|
|
|
export const put = <T = unknown>(url: string, data?: Record<string, unknown>) =>
|
|
request<T>({ url, method: 'PUT', data })
|
|
|
|
export const del = <T = unknown>(url: string, data?: Record<string, unknown>) =>
|
|
request<T>({ url, method: 'DELETE', data })
|