|
- /**
- * 统一 API 请求封装,完全对齐 ai_uniapp_v2/utils/request.js
- *
- * 请求路径走 /api 前缀 → server/api/[...].js 服务端代理
- * /api/user/info → 代理到 https://api.jiefuku.com/user/info
- *
- * 自动注入(对齐 V2):
- * Header: { token, timestr, nonce }
- * Body: { token, uid, mac, base_timestamp, client:1, source, client_ios, version, version_code }
- *
- * 后端响应规范:
- * { code: 0, data: {...}, list: [...], msg: '...' } // 成功
- * { code: 1000, data: null, msg: '...' } // 业务异常
- * { code: 1009, data: null, msg: '...' } // 登录失效
- */
- import md5 from '~/utils/md5'
-
- export function useApi() {
- const tokenCookie = useCookie('token', { path: '/' })
- const macCookie = useCookie('mac', { maxAge: 365 * 24 * 3600, path: '/' })
- const openIdCookie = useCookie('open_id', { path: '/' })
- const sourceCookie = useCookie('source', { path: '/' })
-
- // mac 缺失时自动生成
- if (import.meta.client && !macCookie.value) {
- macCookie.value = generateUUID()
- }
-
- function generateUUID() {
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
- const r = (Math.random() * 16) | 0
- const v = c === 'x' ? r : (r & 0x3) | 0x8
- return v.toString(16)
- })
- }
-
- /**
- * 生成 nonce + timestr(对齐 V2 getNonce)
- */
- function getNonce() {
- const timeStr = Date.now().toString()
- const str = md5(timeStr)
- const nonce = str.substring(4, 14)
- return { timeStr, nonce }
- }
-
- /**
- * 发起请求
- */
- async function request(path, options = {}) {
- const { method = 'GET', params, body } = options
-
- // 走 /api 代理,对齐 V2 H5 端的 BASE_URL = '/api'
- const url = '/api' + path
-
- const timestamp = Math.floor(Date.now() / 1000)
- const { timeStr, nonce } = getNonce()
-
- // Header 签名(对齐 V2 header 注入)
- const reqHeaders = {
- 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
- timestr: timeStr,
- nonce,
- }
- const token = tokenCookie.value
- if (token) reqHeaders.token = token
-
- // Body 公共参数(对齐 V2 data 注入)
- const commonParams = {
- token: token || '',
- uid: openIdCookie.value || '',
- mac: macCookie.value || '',
- base_timestamp: timestamp,
- client: 1,
- source: sourceCookie.value || '',
- client_ios: 0,
- version: '1.0.0',
- version_code: 1,
- }
-
- const fetchOptions = {
- method,
- headers: reqHeaders,
- onResponseError({ response }) {
- console.error('[useApi] HTTP Error', response.status, url)
- },
- }
-
- if (method === 'GET') {
- // GET: 参数拼接到 URL
- const allParams = { ...commonParams, ...(params || {}) }
- // 去除空字符串
- Object.keys(allParams).forEach((k) => {
- if (allParams[k] === '') delete allParams[k]
- })
- const queryStr = new URLSearchParams(allParams).toString()
- fetchOptions.query = allParams
- // GET 请求通过 server proxy 时,参数在 query 里
- const finalUrl = url + (queryStr ? '?' + queryStr : '')
- const result = await $fetch(finalUrl, fetchOptions)
- return handleResult(result)
- } else {
- // POST: body 为 x-www-form-urlencoded
- const postBody = { ...commonParams, ...(body || {}) }
- // 去除空字符串
- Object.keys(postBody).forEach((k) => {
- if (postBody[k] === '') delete postBody[k]
- })
- fetchOptions.body = new URLSearchParams(postBody).toString()
-
- const result = await $fetch(url, fetchOptions)
- return handleResult(result)
- }
- }
-
- /**
- * 统一处理响应
- */
- function handleResult(result) {
- if (result.code === 1009) {
- // 登录失效 → 触发登录弹窗
- if (import.meta.client) {
- const { logout } = useUser()
- logout()
- const showLogin = useState('showLogin', () => false)
- showLogin.value = true
- }
- const err = new Error(result.msg || '登录已失效,请重新登录')
- err.code = 1009
- throw err
- }
-
- if (result.code !== 0) {
- const err = new Error(result.msg || '请求失败')
- err.code = result.code || 1000
- throw err
- }
-
- return result
- }
-
- return {
- /** GET 请求 */
- get: (path, params) => request(path, { method: 'GET', params }),
- /** POST 请求 (x-www-form-urlencoded) */
- post: (path, body) => request(path, { method: 'POST', body }),
- /** 通用请求 */
- request,
- }
- }
|