Преглед на файлове

feat:请求封装的接入

YunaiV преди 4 месеца
родител
ревизия
6a4c78f0a9
променени са 5 файла, в които са добавени 74 реда и са изтрити 34 реда
  1. 17 4
      env/.env
  2. 20 14
      src/http/http.ts
  3. 23 8
      src/http/interceptor.ts
  4. 8 7
      src/http/types.ts
  5. 6 1
      src/utils/toLoginPage.ts

+ 17 - 4
env/.env

@@ -1,4 +1,4 @@
-VITE_APP_TITLE = 'unibest'
+VITE_APP_TITLE = '芋道管理系统'
 VITE_APP_PORT = 9000
 
 VITE_UNI_APPID = '__UNI__D1E5001'
@@ -10,7 +10,8 @@ VITE_WX_APPID = 'wxa2abb91f64032a2b'
 VITE_APP_PUBLIC_BASE=/
 
 # 后台请求地址
-VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run'
+VITE_SERVER_BASEURL = 'http://localhost:48080/admin-api'
+VITE_UPLOAD_BASEURL = 'http://localhost:48080/upload'
 # 备注:如果后台带统一前缀,则也要加到后面,eg: https://ukw0y1.laf.run/api
 
 # 注意,如果是微信小程序,还有一套请求地址的配置,根据 develop、trial、release 分别设置上传地址,见 `src/utils/index.ts`。
@@ -18,13 +19,25 @@ VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run'
 # h5是否需要配置代理
 VITE_APP_PROXY_ENABLE = false
 # 下面的不用修改,只要不跟你后台的统一前缀冲突就行。如果修改了,记得修改 `nginx` 里面的配置
-VITE_APP_PROXY_PREFIX = '/fg-api'
+VITE_APP_PROXY_PREFIX = '/admin-api'
+
+# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务
+VITE_UPLOAD_TYPE=server
 
 # 第二个请求地址 (目前alova中可以使用)
 VITE_SERVER_BASEURL_SECONDARY = 'https://ukw0y1.laf.run'
 
 # 认证模式,'single' | 'double' ==> 单token | 双token
-VITE_AUTH_MODE = 'single'
+VITE_AUTH_MODE = 'double'
 
 # 原生插件资源复制开关,控制是否启用 copy-native-resources 插件
 VITE_COPY_NATIVE_RES_ENABLE = false
+
+# 租户开关
+VITE_APP_TENANT_ENABLE=true
+# 验证码的开关
+VITE_APP_CAPTCHA_ENABLE=true
+# 默认账户密码
+VITE_APP_DEFAULT_LOGIN_TENANT_ID = 1
+VITE_APP_DEFAULT_LOGIN_USERNAME = admin
+VITE_APP_DEFAULT_LOGIN_PASSWORD = admin123

+ 20 - 14
src/http/http.ts

@@ -2,7 +2,7 @@ import type { IDoubleTokenRes } from '@/api/types/login'
 import type { CustomRequestOptions, IResponse } from '@/http/types'
 import { nextTick } from 'vue'
 import { useTokenStore } from '@/store/token'
-import { isDoubleTokenMode } from '@/utils'
+import { getLastPage, isDoubleTokenMode } from '@/utils'
 import { toLoginPage } from '@/utils/toLoginPage'
 import { ResultEnum } from './tools/enum'
 
@@ -55,11 +55,12 @@ export function http<T>(options: CustomRequestOptions) {
               refreshing = false
               nextTick(() => {
                 // 关闭其他弹窗
-                uni.hideToast()
-                uni.showToast({
-                  title: 'token 刷新成功',
-                  icon: 'none',
-                })
+                // 注释 by 芋艿:刷新 token 成功,是后台静默操作,没必要提示用户
+                // uni.hideToast()
+                // uni.showToast({
+                //   title: 'token 刷新成功',
+                //   icon: 'none',
+                // })
               })
               // 将任务队列的所有任务重新请求
               taskQueue.forEach(task => task())
@@ -80,7 +81,14 @@ export function http<T>(options: CustomRequestOptions) {
               await tokenStore.logout()
               // 跳转到登录页
               setTimeout(() => {
-                toLoginPage()
+                // 优化 by 芋艿:跳转登录页时,携带上次浏览的页面地址,登录成功后可以跳回去
+                const lastPage = getLastPage()
+                let queryString = ''
+                if (lastPage) {
+                  const fullPath = lastPage.$page?.fullPath || `/${lastPage.route}`
+                  queryString = `?redirect=${encodeURIComponent(fullPath)}`
+                }
+                toLoginPage({ queryString })
               }, 2000)
             }
             finally {
@@ -96,10 +104,14 @@ export function http<T>(options: CustomRequestOptions) {
         if (res.statusCode >= 200 && res.statusCode < 300) {
           // 处理业务逻辑错误
           if (code !== ResultEnum.Success0 && code !== ResultEnum.Success200) {
-            uni.showToast({
+            // add by 芋艿:后端返回的 msg 提示
+            !options.hideErrorToast
+            && uni.showToast({
               icon: 'none',
               title: responseData.msg || responseData.message || '请求错误',
             })
+            // add by 芋艿:reject 替代原本的 resolve,避免调用的地方以为请求成功
+            return reject(responseData)
           }
           return resolve(responseData.data)
         }
@@ -191,9 +203,3 @@ http.get = httpGet
 http.post = httpPost
 http.put = httpPut
 http.delete = httpDelete
-
-// 支持与 alovaJS 类似的API调用
-http.Get = httpGet
-http.Post = httpPost
-http.Put = httpPut
-http.Delete = httpDelete

+ 23 - 8
src/http/interceptor.ts

@@ -1,20 +1,22 @@
 import type { CustomRequestOptions } from '@/http/types'
-import { useTokenStore } from '@/store'
+import { useTokenStore, useUserStore } from '@/store'
 import { getEnvBaseUrl } from '@/utils'
 import { stringifyQuery } from './tools/queryString'
 
 // 请求基准地址
 const baseUrl = getEnvBaseUrl()
+const tenantEnable = import.meta.env.VITE_APP_TENANT_ENABLE
+
+const whiteList: string[] = [
+  '/login',
+  '/refresh-token',
+  '/system/tenant/get-id-by-name',
+] // 白名单列表,不需要传递 token 字段
 
 // 拦截器配置
 const httpInterceptor = {
   // 拦截前触发
   invoke(options: CustomRequestOptions) {
-    // 如果您使用了alova,则请把下面的代码放开注释
-    // alova 执行流程:alova beforeRequest --> 本拦截器 --> alova responded
-    // return options
-
-    // 非 alova 请求,正常执行
     // 接口请求支持通过 query 参数配置 queryString
     if (options.query) {
       const queryStr = stringifyQuery(options.query)
@@ -51,10 +53,23 @@ const httpInterceptor = {
     // 3. 添加 token 请求头标识
     const tokenStore = useTokenStore()
     const token = tokenStore.validToken
-
-    if (token) {
+    let isToken = (options!.header || {}).isToken === false
+    whiteList.some((v) => {
+      if (options.url && options.url.indexOf(v) > -1) {
+        return (isToken = false)
+      }
+    })
+    if (!isToken && token) {
       options.header.Authorization = `Bearer ${token}`
     }
+
+    // 4. 添加租户标识
+    if (tenantEnable && tenantEnable === 'true') {
+      const tenantId = useUserStore().tenantId
+      if (tenantId) {
+        options.header['tenant-id'] = tenantId
+      }
+    }
     return options
   },
 }

+ 8 - 7
src/http/types.ts

@@ -20,17 +20,18 @@ export type IResponse<T = any> = {
   [key: string]: any // 允许额外属性
 }
 
-// 分页请求参数
-export interface PageParams {
-  page: number
+/** 分页参数 */
+export interface PageParam {
+  pageNo: number
   pageSize: number
-  [key: string]: any
+  [key: string]: any // 允许额外属性
 }
 
-// 分页响应数据
+/** 分页结果 */
 export interface PageResult<T> {
   list: T[]
   total: number
-  page: number
-  pageSize: number
 }
+
+/** 加载状态枚举 - 从 wot-design-uni 重新导出 */
+export type { LoadMoreState } from 'wot-design-uni/components/wd-loadmore/types'

+ 6 - 1
src/utils/toLoginPage.ts

@@ -23,7 +23,12 @@ const LOGIN_PAGE = '/pages/login/index'
  * 如果要立即跳转,不做延时,可以使用 `toLoginPage.flush()` 方法
  */
 export const toLoginPage = debounce((options: ToLoginPageOptions = {}) => {
-  const { mode = 'navigateTo', queryString = '' } = options
+  let { mode = 'navigateTo', queryString = '' } = options
+  // add by 芋艿:如果有查询参数,强制使用 reLaunch 模式。
+  // 原因:携带 redirect 参数,登录成功后可以跳回去。避免使用 navigateTo 导致页面数据不会刷新
+  if (queryString) {
+    mode = 'reLaunch'
+  }
 
   const url = `${LOGIN_PAGE}${queryString}`