You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

116 lines
2.9 KiB

import { useAuthStore } from '~/stores/auth'
interface ApiResponse<T = unknown> {
code: number
msg: string
data: T
}
async function request<T = unknown>(
url: string,
body: unknown,
extraHeaders?: Record<string, string>
): Promise<T> {
const auth = useAuthStore()
const router = useRouter()
const headers: Record<string, string> = {
'Content-Type': 'application/json',
}
if (auth.token) {
headers['Authorization'] = auth.token
}
if (extraHeaders) {
Object.assign(headers, extraHeaders)
}
const response = await fetch(url, {
method: 'POST',
headers,
body: JSON.stringify(body),
})
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`)
}
const result: ApiResponse<T> = await response.json()
if (result.code === 18) {
auth.logout()
router.push('/')
throw new Error(result.msg || 'Unauthorized')
}
if (result.code !== 0) {
throw new Error(result.msg || 'Unknown error')
}
return result.data
}
// 读操作前缀:以这些开头的 api 方法视为只读,不触发处理中遮罩;其余(add/update/del/save/create…)视为写操作。
const READONLY_RE = /^(get|list|load|query|fetch|search|count|stat|export|check)/i
function isMutating(method: string): boolean {
return !READONLY_RE.test(method)
}
export function useApi() {
const auth = useAuthStore()
const { begin, end } = useLoading() // setup 期捕获全局遮罩控制
// 写操作(addproduct/updateproduct/delproduct/addproductversion… 及厂家/账号等增删改)
// 统一套全屏遮罩:请求期间挡住整页、拦截点击,从根上杜绝重复提交/误点。只读 getXxx 不遮罩。
async function webApi<T = unknown>(method: string, data?: unknown): Promise<T> {
const extraHeaders: Record<string, string> = {}
if (auth.currentAppId) {
extraHeaders['X-App-Id'] = String(auth.currentAppId)
}
if (!isMutating(method)) {
return request<T>(`/web/api/api_${method}`, data ?? {}, extraHeaders)
}
begin()
try {
return await request<T>(`/web/api/api_${method}`, data ?? {}, extraHeaders)
} finally {
end()
}
}
async function consoleApi<T = unknown>(path: string, data?: unknown): Promise<T> {
return request<T>(`/console/api/${path}`, data ?? {})
}
async function uploadFile(file: File, path: string): Promise<string> {
const cosToken = await webApi<{
upload_url?: string
url?: string
}>('getcostoken', { path })
const uploadUrl = cosToken.upload_url || cosToken.url || ''
const putResponse = await fetch(uploadUrl, {
method: 'PUT',
headers: {
'Content-Type': file.type || 'application/octet-stream',
},
body: file,
})
if (!putResponse.ok) {
throw new Error(`Upload failed: ${putResponse.status}`)
}
return uploadUrl.split('?')[0]
}
return {
webApi,
consoleApi,
uploadFile,
}
}