feat: app功能基本实现
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
import Taro from '@tarojs/taro'
|
||||
import { getToken, redirectToLogin } from './auth'
|
||||
import type { ResponseData } from '@/api/types'
|
||||
|
||||
type RequestMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'
|
||||
|
||||
interface RequestOptions {
|
||||
method: RequestMethod
|
||||
url: string
|
||||
data?: unknown
|
||||
params?: object
|
||||
showLoading?: boolean
|
||||
}
|
||||
|
||||
interface UploadOptions {
|
||||
url: string
|
||||
filePath: string
|
||||
fileName?: string
|
||||
name?: string
|
||||
formData?: Record<string, string | number | boolean>
|
||||
showLoading?: boolean
|
||||
}
|
||||
|
||||
const baseURL = process.env.TARO_APP_API_BASE || 'http://localhost:8080'
|
||||
|
||||
export async function request<T>(options: RequestOptions) {
|
||||
if (options.showLoading !== false) {
|
||||
Taro.showLoading({ title: '加载中', mask: true })
|
||||
}
|
||||
try {
|
||||
return await sendRequest<T>(options)
|
||||
} finally {
|
||||
if (options.showLoading !== false) {
|
||||
Taro.hideLoading()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function sendRequest<T>(options: RequestOptions) {
|
||||
const response = await Taro.request<ResponseData<T>>({
|
||||
url: buildUrl(options.url, options.params),
|
||||
method: options.method,
|
||||
data: options.data,
|
||||
header: buildHeaders()
|
||||
})
|
||||
return handleResponse(response.data)
|
||||
}
|
||||
|
||||
export async function uploadFile<T>(options: UploadOptions) {
|
||||
if (options.showLoading !== false) {
|
||||
Taro.showLoading({ title: '上传中', mask: true })
|
||||
}
|
||||
try {
|
||||
return await sendUpload<T>(options)
|
||||
} finally {
|
||||
if (options.showLoading !== false) {
|
||||
Taro.hideLoading()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function sendUpload<T>(options: UploadOptions) {
|
||||
const response = await Taro.uploadFile({
|
||||
url: buildUrl(options.url),
|
||||
filePath: options.filePath,
|
||||
name: options.name || 'file',
|
||||
fileName: options.fileName,
|
||||
formData: options.formData,
|
||||
header: buildUploadHeaders()
|
||||
})
|
||||
validateUploadStatus(response.statusCode, response.data)
|
||||
return handleResponse(parseUploadData<T>(response.data))
|
||||
}
|
||||
|
||||
function validateUploadStatus(statusCode: number, data: string) {
|
||||
if (statusCode >= 200 && statusCode < 300) return
|
||||
const message = getUploadErrorMessage(data) || `上传失败(${statusCode})`
|
||||
throw new Error(message)
|
||||
}
|
||||
|
||||
function buildUrl(url: string, params?: object) {
|
||||
const target = `${baseURL}${url}`
|
||||
const query = new URLSearchParams()
|
||||
Object.entries(params || {}).forEach(([key, value]) => appendQuery(query, key, value))
|
||||
const queryString = query.toString()
|
||||
return queryString ? `${target}?${queryString}` : target
|
||||
}
|
||||
|
||||
function appendQuery(query: URLSearchParams, key: string, value: unknown) {
|
||||
if (value === undefined || value === null || value === '') return
|
||||
query.append(key, String(value))
|
||||
}
|
||||
|
||||
function buildHeaders() {
|
||||
return { ...buildUploadHeaders(), 'Content-Type': 'application/json' }
|
||||
}
|
||||
|
||||
function buildUploadHeaders() {
|
||||
const token = getToken()
|
||||
const headers: Record<string, string> = {
|
||||
Accept: 'application/json, text/plain, */*'
|
||||
}
|
||||
if (token) {
|
||||
headers.Authorization = `Bearer ${token}`
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
function parseUploadData<T>(data: string | object) {
|
||||
if (typeof data !== 'string') return data as ResponseData<T>
|
||||
try {
|
||||
return JSON.parse(data) as ResponseData<T>
|
||||
} catch {
|
||||
throw new Error(getUploadErrorMessage(data) || '服务器返回数据结构有误')
|
||||
}
|
||||
}
|
||||
|
||||
function getUploadErrorMessage(data: string) {
|
||||
try {
|
||||
return (JSON.parse(data) as { msg?: string }).msg || ''
|
||||
} catch {
|
||||
return data.slice(0, 60)
|
||||
}
|
||||
}
|
||||
|
||||
function handleResponse<T>(data: ResponseData<T>) {
|
||||
if (!data || data.code === undefined) {
|
||||
throw new Error('服务器返回数据结构有误')
|
||||
}
|
||||
if (data.code === 106) {
|
||||
redirectToLogin()
|
||||
throw new Error(data.msg || '登录状态已过期')
|
||||
}
|
||||
if (data.code !== 0) {
|
||||
Taro.showToast({ title: data.msg || '请求失败', icon: 'none' })
|
||||
throw new Error(data.msg || '请求失败')
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user