li.shaoyi преди 2 години
родител
ревизия
49b9841dff

+ 2 - 1
src/business/common/index.ts

@@ -13,8 +13,9 @@ export async function checkToken() {
             LoginID: loginId,
             Token: token,
         })
-    } catch {
+    } catch (err) {
         eventBus.$emit('LogoutNotify')
+        return Promise.reject(err)
     }
 }
 

+ 3 - 3
src/hooks/request/index.ts

@@ -1,5 +1,5 @@
 import { ref, onUnmounted, UnwrapRef } from 'vue'
-import { CommonResult } from '@/services/http/interface'
+import { CommonResult } from '@/services/http/types'
 import { useDataTable } from '../datatable'
 
 interface RequestOptions<TParams, TResponse> {
@@ -23,7 +23,7 @@ const isCommonResult = (obj: unknown): obj is CommonResult => {
     return false
 }
 
-export function useRequest<TParams extends object, TResponse>(request: (params: TParams) => Promise<TResponse>, options?: RequestOptions<TParams, TResponse>) {
+export function useRequest<TParams extends object, TResponse>(asyncFun: (params: TParams) => Promise<TResponse>, options?: RequestOptions<TParams, TResponse>) {
     const { params, localPagination, manual, onBefore, onSuccess, onError, onFinally } = options ?? {}
 
     type Result = TResponse extends CommonResult ? TResponse['data'] : TResponse // 获取返回值的类型
@@ -44,7 +44,7 @@ export function useRequest<TParams extends object, TResponse>(request: (params:
             params.pagesize = pageSize.value
         }
         onBefore && await onBefore()
-        const res = await request({ ...params, ...payload } as TParams)
+        const res = await asyncFun({ ...params, ...payload } as TParams)
         if (isCommonResult(res)) {
             total.value = res.total
             if (Array.isArray(res.data)) {

+ 2 - 2
src/packages/mobile/components/layouts/page/index.vue

@@ -33,11 +33,11 @@ const getRouteKey = (route: RouteLocationNormalized) => {
 }
 
 const onLeave = () => {
-  http.loading = true
+  http.pending = true
 }
 
 const onAfterEnter = () => {
-  http.loading = false
+  http.pending = false
 }
 </script>
 

+ 16 - 17
src/services/http/index.ts

@@ -3,7 +3,7 @@ import axios, { AxiosRequestConfig } from 'axios'
 //import cryptojs from 'crypto-js'
 //import { addPending, removePending } from './pending'
 import { useLoginStore } from '@/stores'
-import { CommonResult, ResultCode } from './interface'
+import { CommonResult, ResultCode } from './types'
 import service from '@/services'
 
 export default new (class {
@@ -12,11 +12,10 @@ export default new (class {
     })
 
     constructor() {
-        const loginStore = useLoginStore()
-
         // 请求拦截器
         this.axiosInstance.interceptors.request.use(
             (config) => {
+                const loginStore = useLoginStore()
                 //addPending(config) //将当前请求添加到列表中
                 //请求头签名
                 const sign = {
@@ -65,25 +64,25 @@ export default new (class {
         )
     }
 
+    /** 请求响应集合 */
+    private resultMap = new Set<() => void>()
+
     /** 
-     * 是否启用响应延时
-     * 可防止在动画过程中同时请求数据,数据请求先于动画完成,双绑数据的页面会重新渲染,导致动画卡顿的问题
+     * 建议在过渡动画中启用,动画结束时禁用
+     * 可防止在动画过程中同时请求数据,数据请求先于动画完成,双绑数据的页面会实时渲染,导致动画卡顿的问题
      */
-    private delay = false
-
-    /** 如果启用响应延时,将响应回调添加到该集合中 */
-    private resultMap = new Set<() => void>()
+    private _pending = false
 
-    /** 请求时的 loading 状态 */
-    get loading() {
-        return this.delay
+    /** 全局 pending 状态 */
+    get pending() {
+        return this._pending
     }
 
-    /** 在动画开始时设置一个 loading 状态,在动画结束后取消 loading 状态,后返回请求结果 */
-    set loading(status: boolean) {
-        this.delay = status
+    /** 在动画开始时设置一个 pending 状态,在动画结束后取消 pending 状态 */
+    set pending(status: boolean) {
+        this._pending = status
         if (!status) {
-            // 当 loading 状态为 false 时返回所有延时请求的回调
+            // 当 pending 状态为 false 时返回所有请求的回调
             this.resultMap.forEach((fn) => {
                 fn()
                 this.resultMap.delete(fn)
@@ -100,7 +99,7 @@ export default new (class {
     request<T>(config: AxiosRequestConfig, errMsg?: string) {
         return new Promise<T>((resolve, reject) => {
             this.axiosInstance(config).then((res) => {
-                if (this.delay) {
+                if (this.pending) {
                     this.resultMap.add(() => resolve(res.data))
                 } else {
                     resolve(res.data)

+ 11 - 11
src/services/http/pending/index.ts → src/services/http/pending.ts

@@ -4,9 +4,9 @@ import qs from 'qs'
 /**
  * 缓存请求列表,防止重复请求
  */
-const pending = new Map()
+const pendingMap = new Map()
 
-const getRequestKey = (config: AxiosRequestConfig) => {
+const getRequestId = (config: AxiosRequestConfig) => {
     return [
         config.method,
         config.url,
@@ -20,13 +20,13 @@ const getRequestKey = (config: AxiosRequestConfig) => {
  */
 export function addPending(config: AxiosRequestConfig) {
     removePending(config) //在请求开始前,对之前的请求做检查取消操作
-    const key = getRequestKey(config)
+    const requestId = getRequestId(config)
     config.cancelToken =
         config.cancelToken ||
         new axios.CancelToken((cancel) => {
-            if (!pending.has(key)) {
+            if (!pendingMap.has(requestId)) {
                 //如果列表中不存在当前请求,则添加进去
-                pending.set(key, cancel)
+                pendingMap.set(requestId, cancel)
             }
         })
 }
@@ -35,12 +35,12 @@ export function addPending(config: AxiosRequestConfig) {
  * 移除请求
  */
 export function removePending(config: AxiosRequestConfig) {
-    const key = getRequestKey(config)
-    if (pending.has(key)) {
+    const key = getRequestId(config)
+    if (pendingMap.has(key)) {
         //如果在列表中存在当前请求,需要取消当前请求,并且移除
-        const cancel = pending.get(key)
+        const cancel = pendingMap.get(key)
         cancel(key)
-        pending.delete(key)
+        pendingMap.delete(key)
     }
 }
 
@@ -48,8 +48,8 @@ export function removePending(config: AxiosRequestConfig) {
  * 清空等待中的请求(在路由跳转时调用)
  */
 export function clearPending() {
-    for (const [key, cancel] of pending) {
+    for (const [key, cancel] of pendingMap) {
         cancel(key)
     }
-    pending.clear()
+    pendingMap.clear()
 }

+ 0 - 0
src/services/http/interface.ts → src/services/http/types.ts


+ 10 - 11
src/services/index.ts

@@ -47,27 +47,26 @@ export default new (class {
      */
     private onload = Promise.resolve(this.config)
 
-    /**
-     * 重试次数
-     */
+    /** 重试次数 */
     private retryCount = 0
 
-    /**
+    /** 限制重试次数,0 = 无限制 */
+    private retryLimit = 5
+
+    /** 
      * 失败时重新尝试初始化,直到成功为止
      */
     private tryinit = () => {
         return new Promise<typeof this.config>((resolve, reject) => {
-            if (this.retryCount >= 5) {
-                this.retryCount = 0
-                this.isPending = false
-                reject('服务加载失败,请稍后再试')
-            } else {
+            if (this.retryLimit === 0 || this.retryCount < this.retryLimit) {
                 this.retryCount++
-                // 自动计算每次重试的延时,重试次数越多,延时越大
-                // const delay = this.retryCount * 3000
                 setTimeout(() => {
                     resolve(this.init())
                 }, 3000)
+            } else {
+                this.retryCount = 0
+                this.isPending = false
+                reject('服务加载失败,请稍后再试')
             }
         })
     }

+ 3 - 3
src/services/socket/quote/index.ts

@@ -96,12 +96,12 @@ export default new (class {
      * @returns 
      */
     addSubscribe = (goodsCodes: string[], key?: string) => {
-        const { token } = useLoginStore()
+        const loginStore = useLoginStore()
         const uuid = key ?? v4()
         const value = this.quoteSubscribeMap.get(uuid) ?? []
 
         const start = () => {
-            if (token) {
+            if (loginStore.token) {
                 // 对相同 key 订阅的商品进行合并处理
                 this.quoteSubscribeMap.set(uuid, [...value, ...goodsCodes])
                 this.quoteSubscribe()
@@ -116,7 +116,7 @@ export default new (class {
                 if (flag) {
                     console.log('删除订阅', uuid)
                 }
-                if (token) {
+                if (loginStore.token) {
                     this.quoteSubscribe()
                 }
                 return flag

+ 18 - 24
src/utils/storage/base.ts

@@ -1,4 +1,4 @@
-import { shallowRef, watch } from 'vue'
+import { shallowRef, computed } from 'vue'
 
 /**
  * 本地存储类(基础版)
@@ -8,8 +8,12 @@ export default class <T> {
         this.storage = storage
         this.storageKey = key
         this.source = value
-        this.state = shallowRef(this.getValue())
-        this.observe()
+        this.state = shallowRef(value)
+
+        const storageValue = this.storage.getItem(this.storageKey)
+        if (storageValue) {
+            this.state.value = JSON.parse(storageValue)
+        }
     }
 
     private readonly source // 原始数据
@@ -18,30 +22,11 @@ export default class <T> {
     private state
 
     /**
-     * 监听数据变化
-     */
-    private observe() {
-        watch(this.state, (value) => {
-            if (value === undefined || value === null) {
-                this.storage.removeItem(this.storageKey)
-            } else {
-                const storageValue = JSON.stringify(value) // 注意数值长度过长会被自动转换为 String 类型
-                this.storage.setItem(this.storageKey, storageValue)
-            }
-        })
-    }
-
-    /**
      * 获取数据
      * @returns 
      */
     getValue() {
-        const storageValue = this.storage.getItem(this.storageKey)
-        if (storageValue !== 'undefined' && storageValue !== null) {
-            return JSON.parse(storageValue) as T
-        } else {
-            return this.source
-        }
+        return this.state.value
     }
 
     /**
@@ -49,6 +34,12 @@ export default class <T> {
      * @param value 
      */
     setValue(value: T) {
+        if (value === undefined || value === null) {
+            this.storage.removeItem(this.storageKey)
+        } else {
+            const storageValue = JSON.stringify(value) // 注意数值长度过长会被自动转换为 String 类型
+            this.storage.setItem(this.storageKey, storageValue)
+        }
         this.state.value = value
     }
 
@@ -57,7 +48,10 @@ export default class <T> {
      * @returns 
      */
     getRef() {
-        return this.state
+        return computed({
+            get: () => this.getValue(),
+            set: (val) => this.setValue(val)
+        })
     }
 
     /**

+ 33 - 39
src/utils/storage/index.ts

@@ -1,54 +1,36 @@
-import { shallowRef, ShallowRef, watch } from 'vue'
+import { reactive, UnwrapNestedRefs, WritableComputedRef, computed } from 'vue'
 
 /**
  * 本地存储类
  */
 export default class <T extends object> {
     constructor(storage: Storage, source: T, prefix = '') {
-        this.prefix = prefix
         this.storage = storage
         this.source = source
+        this.prefix = prefix
+        this.state = reactive({ ...source })
 
         // 读取本地数据
-        for (const key in source) {
-            const storageValue = this.getValue(key)
-            this.state[key] = shallowRef(storageValue)
-            this.observe(key)
+        for (const key in this.state) {
+            const storageValue = this.storage.getItem(this.prefix + key.toString())
+            if (storageValue) {
+                this.state[key] = JSON.parse(storageValue)
+            }
         }
     }
 
     private readonly storage: Storage
     private readonly source // 初始数据
     private readonly prefix // 防止命名冲突
-    private state = {} as { [K in keyof T]: ShallowRef<T[K]> }
-
-    /**
-     * 监听数据变化
-     * @param key 
-     */
-    private observe<K extends keyof T>(key: K) {
-        watch(this.getRef(key), (value) => {
-            if (value === undefined || value === null) {
-                this.storage.removeItem(this.prefix + key.toString())
-            } else {
-                const strValue = JSON.stringify(value) // 注意数值长度过长会被自动转换为 String 类型
-                this.storage.setItem(this.prefix + key.toString(), strValue)
-            }
-        })
-    }
+    private state
 
     /**
      * 获取数据
      * @param key 
      * @returns 
      */
-    getValue<K extends keyof T>(key: K) {
-        const storageValue = this.storage.getItem(this.prefix + key.toString())
-        if (storageValue !== 'undefined' && storageValue !== null) {
-            return JSON.parse(storageValue) as T[K]
-        } else {
-            return this.source[key]
-        }
+    getValue<K extends keyof UnwrapNestedRefs<T>>(key: K) {
+        return this.state[key]
     }
 
     /**
@@ -56,9 +38,14 @@ export default class <T extends object> {
      * @param key 
      * @param value 
      */
-    setValue<K extends keyof T>(key: K, value: T[K]) {
-        const state = this.getRef(key)
-        state.value = value
+    setValue<K extends keyof UnwrapNestedRefs<T>>(key: K, value: UnwrapNestedRefs<T>[K]) {
+        if (value === undefined || value === null) {
+            this.storage.removeItem(this.prefix + key.toString())
+        } else {
+            const strValue = JSON.stringify(value) // 注意数值长度过长会被自动转换为 String 类型
+            this.storage.setItem(this.prefix + key.toString(), strValue)
+        }
+        this.state[key] = value
     }
 
     /**
@@ -66,7 +53,11 @@ export default class <T extends object> {
      * @returns 
      */
     getRefs() {
-        return this.state
+        const refs: { [K in keyof UnwrapNestedRefs<T>]: WritableComputedRef<UnwrapNestedRefs<T>[K]> } = Object.create(null)
+        for (const key in this.state) {
+            refs[key] = this.getRef(key)
+        }
+        return refs
     }
 
     /**
@@ -74,23 +65,26 @@ export default class <T extends object> {
      * @param key 
      * @returns 
      */
-    getRef<K extends keyof T>(key: K) {
-        return this.state[key]
+    getRef<K extends keyof Record<keyof UnwrapNestedRefs<T>, T>>(key: K) {
+        return computed({
+            get: () => this.getValue(key),
+            set: (val) => this.setValue(key, val)
+        })
     }
 
     /**
      * 重置数据
      * @param keys 
      */
-    reset<K extends keyof T>(...keys: K[]) {
+    reset<K extends keyof UnwrapNestedRefs<T>>(...keys: K[]) {
+        const _state = Object.create(this.source)
         if (keys.length) {
             keys.forEach((key) => {
-                const state = this.getRef(key)
-                state.value = this.source[key]
+                this.setValue(key, _state[key])
             })
         } else {
             for (const key in this.state) {
-                this.state[key].value = this.source[key]
+                this.setValue(key, _state[key])
             }
         }
     }