diff --git a/package.json b/package.json index 718dc69..ea80943 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,6 @@ "@zebra-ui/swiper": "^2.2.8", "crypto-js": "^4.2.0", "dayjs": "^1.11.13", - "gdt-jsapi": "^1.9.51", "luch-request": "^3.1.1", "pinia": "^2.2.6", "qrcode": "^1.5.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a2a0a73..0b6dd02 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -65,9 +65,6 @@ importers: dayjs: specifier: ^1.11.13 version: 1.11.13 - gdt-jsapi: - specifier: ^1.9.51 - version: 1.9.51 luch-request: specifier: ^3.1.1 version: 3.1.1 @@ -1304,9 +1301,6 @@ packages: '@polka/url@1.0.0-next.28': resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} - '@remax/mini-types@0.1.0': - resolution: {integrity: sha512-bVDcbUrp6p0PZwfS0xGVQS6k9f8B35BtZaYt/W/IGKh7VALYQ+tS2KcytLRmIJ/Vmohaw5ikIRN89I+frPdh4g==} - '@rollup/pluginutils@5.1.4': resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} engines: {node: '>=14.0.0'} @@ -2426,9 +2420,6 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - gdt-jsapi@1.9.51: - resolution: {integrity: sha512-VN1iIK7kJU2g2oxY/n8waCREhWxcVwR8qHAE1keVnUJHI6mTdgTelICzq++niRRCaLqUVWC1pYvftEVgk4sq8A==} - generic-names@4.0.0: resolution: {integrity: sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==} @@ -6021,8 +6012,6 @@ snapshots: '@polka/url@1.0.0-next.28': {} - '@remax/mini-types@0.1.0': {} - '@rollup/pluginutils@5.1.4(rollup@4.34.2)': dependencies: '@types/estree': 1.0.6 @@ -7275,11 +7264,6 @@ snapshots: function-bind@1.1.2: {} - gdt-jsapi@1.9.51: - dependencies: - '@babel/runtime': 7.26.7 - '@remax/mini-types': 0.1.0 - generic-names@4.0.0: dependencies: loader-utils: 3.3.1 diff --git a/src/App.vue b/src/App.vue index 572ef15..73eca76 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,7 +1,6 @@ diff --git a/src/pages/integrated/feedback/index.vue b/src/pages/integrated/feedback/index.vue deleted file mode 100644 index 7deea6d..0000000 --- a/src/pages/integrated/feedback/index.vue +++ /dev/null @@ -1,337 +0,0 @@ - - - - - diff --git a/src/pages/pay/scanPay.vue b/src/pages/pay/scanPay.vue index 085cdba..781a58b 100644 --- a/src/pages/pay/scanPay.vue +++ b/src/pages/pay/scanPay.vue @@ -28,7 +28,7 @@ - 支付 + 支 付 @@ -38,15 +38,15 @@ - - - - diff --git a/src/pages/wallet/detail.vue b/src/pages/wallet/detail.vue index 14238af..234e88b 100644 --- a/src/pages/wallet/detail.vue +++ b/src/pages/wallet/detail.vue @@ -85,5 +85,3 @@ const doTab = (e: any) => { - - diff --git a/src/pages/wallet/list.vue b/src/pages/wallet/list.vue index 421180f..f0955f4 100644 --- a/src/pages/wallet/list.vue +++ b/src/pages/wallet/list.vue @@ -7,7 +7,7 @@ import { hooks, router } from "@@/index" import { walletApi } from "@@/api" import { filePath } from "@@/utils/file" -import { useTransferMoney } from "@/sheep/stores/transferMoney" +import { usePayStore } from "@/sheep/stores/pay" const state = reactive({ showBindDialog: false, @@ -129,7 +129,7 @@ const doFreeze = async () => { // 转账 const doTransferMoney = (v: any) => { if (v.walletTypeId) { - useTransferMoney().setSourceWalletType(v) + usePayStore().setSourceWalletData(v) router.jump("/pages/pay/transferMoney") return } diff --git a/src/pages/tabbar/tabSearch.vue b/src/sheep/components/tabSearch.vue similarity index 100% rename from src/pages/tabbar/tabSearch.vue rename to src/sheep/components/tabSearch.vue diff --git a/src/sheep/components/verifyDeviceImpModel/verifyDeviceImpModel.ts b/src/sheep/components/verifyDeviceImpModel/verifyDeviceImpModel.ts index 82b0a70..043c552 100644 --- a/src/sheep/components/verifyDeviceImpModel/verifyDeviceImpModel.ts +++ b/src/sheep/components/verifyDeviceImpModel/verifyDeviceImpModel.ts @@ -7,10 +7,10 @@ const showVerifyDeviceImpModel = (onClose: () => any = () => null) => { return new Promise((resolve, reject) => { if (VerifyDeviceImpModelInstance) return - const close = () => { + const close = async () => { render(null, document.body) VerifyDeviceImpModelInstance = false - onClose() + await onClose() } const vnode = h(VerifyDeviceImpModel, { diff --git a/src/sheep/constant/img-constant.ts b/src/sheep/constant/img-constant.ts deleted file mode 100644 index 2d52e58..0000000 --- a/src/sheep/constant/img-constant.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default { - logo: "/static/constant/logo.png" -} \ No newline at end of file diff --git a/src/sheep/constant/index.ts b/src/sheep/constant/index.ts index 949adc3..534ff66 100644 --- a/src/sheep/constant/index.ts +++ b/src/sheep/constant/index.ts @@ -1,5 +1,3 @@ -export { default as imgConstant } from "./img-constant"; +export { default as serviceEnum } from "./service-enum" -export { default as serviceEnum } from "./service-enum"; - -export { default as storageConstant } from "./storage-constant"; +export { default as storageConstant } from "./storage-constant" diff --git a/src/sheep/hooks/use-token.ts b/src/sheep/hooks/use-token.ts index 3061588..d55b76b 100644 --- a/src/sheep/hooks/use-token.ts +++ b/src/sheep/hooks/use-token.ts @@ -1,6 +1,6 @@ import storageConstant from "../constant/storage-constant" import { jump } from "../router/index" -import isDevEnv from "../utils/isDevEnv" +import { isDevEnv } from "../utils/app" export const useToken = () => { const tokenKey = storageConstant.TOKEN @@ -41,7 +41,7 @@ export const useCheckLogin = async (): Promise => { confirmText: "去登录", success: async (res) => { if (res.confirm) { - jump("/pages/test/login", {}, 3) + jump("/pages/user/login", {}, 3) return } if (!res.confirm) { diff --git a/src/sheep/stores/index.ts b/src/sheep/stores/index.ts index f09bd2e..b884215 100644 --- a/src/sheep/stores/index.ts +++ b/src/sheep/stores/index.ts @@ -1,8 +1,3 @@ -// https://pinia.vuejs.org/ import { createPinia } from "pinia" - -// 创建 const pinia = createPinia() - -// 导出 export default pinia diff --git a/src/sheep/stores/pay.ts b/src/sheep/stores/pay.ts index 5b4937c..e82da98 100644 --- a/src/sheep/stores/pay.ts +++ b/src/sheep/stores/pay.ts @@ -1,14 +1,20 @@ import { defineStore } from "pinia" export const usePayStore = defineStore("pay", { - state: (): { payData: { id?: string; name?: string; customPrice?: number } } => { + state: (): { payData: { id?: string; name?: string; customPrice?: number }; sourceWalletData: any } => { return { payData: {}, + sourceWalletData: {}, } }, actions: { + // 支付 setPayData(data: any) { this.payData = data }, + // 转账 + setSourceWalletData(data: any) { + this.sourceWalletData = data + }, }, }) diff --git a/src/sheep/stores/transferMoney.ts b/src/sheep/stores/transferMoney.ts deleted file mode 100644 index a33f46a..0000000 --- a/src/sheep/stores/transferMoney.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { defineStore } from "pinia" - -export const useTransferMoney = defineStore("transferMoney", { - state: (): any => { - return { - sourceWalletType: {}, - } - }, - actions: { - setSourceWalletType(data: any) { - this.sourceWalletType = data - }, - }, -}) diff --git a/src/sheep/utils/app.ts b/src/sheep/utils/app.ts new file mode 100644 index 0000000..3fd5d82 --- /dev/null +++ b/src/sheep/utils/app.ts @@ -0,0 +1,26 @@ +// app运行环境 +// export default () => import.meta.env.VITE_DEV_ENV === "dev" +export const isDevEnv = (): boolean => process.env.NODE_ENV === "development" + +// 获取启动参数 +export const getLaunchParam = (): "canteen" | "selfMerchant" | "coopMerchant" | "thirdApp" | null => { + return new URL(window.location.href).searchParams.get("launchParam") as "canteen" | "selfMerchant" | "coopMerchant" | "thirdApp" | null +} + +// 检测app信息判断运行环境 +export const getAppInfo = async (): Promise => { + try { + const res = await (window as any).CP2.getAppInfo() + // 浙政钉环境 + if (res.code === 0) { + console.log("环境:zzd") + return "zzd" + } else { + // 诗画环境 + console.log("环境:sh") + return "sh" + } + } catch (error) { + return "unknown" + } +} diff --git a/src/sheep/utils/file.ts b/src/sheep/utils/file.ts index ff8384e..12e7aa1 100644 --- a/src/sheep/utils/file.ts +++ b/src/sheep/utils/file.ts @@ -1,4 +1,4 @@ -import isDevEnv from "./isDevEnv" +import { isDevEnv } from "./app" export const filePath = (path?: string) => { const imageBaseUrl = isDevEnv() ? import.meta.env.VITE_IMAGE_DEV_PATH : import.meta.env.VITE_APP_PROD_IMAGE diff --git a/src/sheep/utils/getAppInfo.ts b/src/sheep/utils/getAppInfo.ts deleted file mode 100644 index 9e23f22..0000000 --- a/src/sheep/utils/getAppInfo.ts +++ /dev/null @@ -1,17 +0,0 @@ -// 检测app信息判断运行环境 -export const getAppInfo = async (): Promise => { - try { - const res = await (window as any).CP2.getAppInfo() - // 浙政钉环境 - if (res.code === 0) { - console.log("环境:zzd") - return "zzd" - } else { - // 诗画环境 - console.log("环境:sh") - return "sh" - } - } catch (error) { - return "unknown" - } -} diff --git a/src/sheep/utils/getLaunchParam.ts b/src/sheep/utils/getLaunchParam.ts deleted file mode 100644 index ac5c39e..0000000 --- a/src/sheep/utils/getLaunchParam.ts +++ /dev/null @@ -1,6 +0,0 @@ -// 获取启动参数 -const getLaunchParam = (): "canteen" | "selfMerchant" | "coopMerchant" | "thirdApp" | null => { - return new URL(window.location.href).searchParams.get("launchParam") as "canteen" | "selfMerchant" | "coopMerchant" | "thirdApp" | null -} - -export default getLaunchParam diff --git a/src/sheep/utils/isDevEnv.ts b/src/sheep/utils/isDevEnv.ts deleted file mode 100644 index a081bbe..0000000 --- a/src/sheep/utils/isDevEnv.ts +++ /dev/null @@ -1,2 +0,0 @@ -// export default () => import.meta.env.VITE_DEV_ENV === "dev" -export default () => process.env.NODE_ENV === "development" diff --git a/src/sheep/utils/request.ts b/src/sheep/utils/request.ts index 340349f..8395988 100644 --- a/src/sheep/utils/request.ts +++ b/src/sheep/utils/request.ts @@ -2,12 +2,33 @@ import Request from "luch-request" import { router, constant } from "@@/index" import { userApi } from "../api" import { isEmpty } from "radash" -import isDevEnv from "./isDevEnv" -import { getAppInfo } from "@@/utils/getAppInfo" +import { isDevEnv } from "./app" +import { getAppInfo } from "@@/utils/app" import showVerifyDeviceImpModel from "../components/verifyDeviceImpModel/verifyDeviceImpModel" const TOKEN_KEY = constant.storageConstant.TOKEN const USER_INFO_KEY = constant.storageConstant.USERINFO +const SKIP_AUTH_URLS = ["/thirdparty/thirdPartyOAth2", "/sys/auth/refresh-token", "/auth/oauth2/token"] + +let isRefreshing = false +// 队列存储发送失败的请求 +let failedQueue: any[] = [] +// 存储刷新token的Promise +let refreshTokenPromise: Promise | null = null + +// 处理队列中的请求 +const processQueue = (error: any, token: any = null) => { + failedQueue.forEach((prom) => { + if (error) { + prom.reject(error) + } else { + prom.resolve(token) + } + }) + if (!error) { + failedQueue = [] + } +} // 读取token并处理Authorization请求头 const getAuthHeader = (tokenStorage: any) => { @@ -20,7 +41,7 @@ const getAuthHeader = (tokenStorage: any) => { // 浙政钉登录 登录成功返回true,否则返回false async function handleZzdLogin(): Promise { try { - uni.showLoading({ title: "加载中...", mask: true }) + uni.showLoading({ title: "登录中...", mask: true }) const token = new URL(window.location.href).searchParams.get("uabaseToken") if (!token) { @@ -57,15 +78,15 @@ async function handleShLogin(): Promise { try { uni.showLoading({ title: "登录中...", mask: true }) - // const userInfo = await (window as any).CP2.getUserInfo() - // if (userInfo.code == 0 || !userInfo.data.accountId || !userInfo.data.sessionId) { - // uni.showToast({ title: "获取诗画用户信息失败", icon: "none" }) - // return false - // } + const userInfo = await (window as any).CP2.getUserInfo() + if (userInfo.code == 0 || !userInfo.data.accountId || !userInfo.data.sessionId) { + uni.showToast({ title: "获取诗画用户信息失败", icon: "none" }) + return false + } - // const { accountId, sessionId } = userInfo.data - // const response = await userApi.authsh({ accountId, sessionId }) - const response = await userApi.authsh({ accountId: "67e790d6a95d5a7b507e53dd", sessionId: "68215b03a95d5a4899d20cb4" }) // 测试 + const { accountId, sessionId } = userInfo.data + const response = await userApi.authsh({ accountId, sessionId }) + // const response = await userApi.authsh({ accountId: "67e790d6a95d5a7b507e53dd", sessionId: "68215b03a95d5a4899d20cb4" }) // 测试 if (response.code == 0) { uni.setStorageSync(TOKEN_KEY, { accessToken: response.data.accessToken }) @@ -81,13 +102,9 @@ async function handleShLogin(): Promise { return false } + // 如果是设备未验证,保存响应数据 if (response.data == -1) { - uni.showToast({ title: "您的设备需要信任验证", icon: "none" }) - await showVerifyDeviceImpModel(async () => { - await autoLogin() - uni.reLaunch({ url: window.location.href.split("#")[1] }) - }) - return false + uni.setStorageSync(TOKEN_KEY, { data: -1 }) } uni.showToast({ title: response.msg || "登录失败", icon: "none" }) @@ -118,6 +135,56 @@ async function autoLogin(): Promise { } } +// token刷新 +async function refreshToken(): Promise { + if (refreshTokenPromise) { + return refreshTokenPromise + } + + if (!isRefreshing) { + isRefreshing = true + refreshTokenPromise = (async () => { + try { + const loginResult = await autoLogin() + if (loginResult) { + const newTokenStorage = uni.getStorageSync(TOKEN_KEY) + processQueue(null, newTokenStorage) + return newTokenStorage + } else { + // 检查是否需要设备验证 + const tokenStorage = uni.getStorageSync(TOKEN_KEY) + if (tokenStorage?.data == -1) { + // 显示设备验证弹窗 + await showVerifyDeviceImpModel(async () => { + // 验证完成后重新登录 + const newLoginResult = await autoLogin() + if (newLoginResult) { + const newTokenStorage = uni.getStorageSync(TOKEN_KEY) + processQueue(null, newTokenStorage) + return newTokenStorage + } else { + processQueue(new Error("登录失败"), null) + throw new Error("登录失败") + } + }) + } else { + processQueue(new Error("登录失败"), null) + throw new Error("登录失败") + } + } + } catch (error) { + processQueue(error, null) + throw error + } finally { + isRefreshing = false + refreshTokenPromise = null + } + })() + } + + return refreshTokenPromise +} + // token过期刷新检查 async function checkAndRefreshToken(tokenStorage: any) { const { accessToken } = tokenStorage @@ -125,13 +192,9 @@ async function checkAndRefreshToken(tokenStorage: any) { const expiresDate = new Date(accessToken.expiresAt).getTime() - // console.log("过期时间", expiresDate) - // console.log("现在时间", new Date().getTime()) - // console.log("现在时间大于过期时间吗", new Date().getTime() >= expiresDate) - // token已过期,尝试刷新 if (new Date().getTime() >= expiresDate) { - await autoLogin() + return await refreshToken() } } @@ -157,8 +220,6 @@ const http = new Request({ // 请求拦截器 http.interceptors.request.use(async (config) => { - // console.log("config", config) - const tokenStorage = uni.getStorageSync(TOKEN_KEY) const config_header: any = config.header || {} @@ -166,25 +227,25 @@ http.interceptors.request.use(async (config) => { config_header["TENANT-ID"] = "1" if (import.meta.env.VITE_IS_TOC === "true") config_header["CLIENT-TOC"] = "Y" - // 不需要设置认证头的接口路径 - const skipAuthUrls = ["/thirdparty/thirdPartyOAth2", "/sys/auth/refresh-token", "/auth/oauth2/token"] - // 判断是否需要设置认证头 - if (!skipAuthUrls.some((url) => config.url?.startsWith(url))) { + if (!SKIP_AUTH_URLS.some((url) => config.url?.startsWith(url))) { if (!isEmpty(tokenStorage)) { // token存在,token过期刷新检查 - await checkAndRefreshToken(tokenStorage) - - const authHeader = getAuthHeader(tokenStorage) - if (authHeader) config_header.Authorization = authHeader + const newTokenStorage = await checkAndRefreshToken(tokenStorage) + if (newTokenStorage) { + const authHeader = getAuthHeader(newTokenStorage) + if (authHeader) config_header.Authorization = authHeader + } else { + const authHeader = getAuthHeader(tokenStorage) + if (authHeader) config_header.Authorization = authHeader + } } else { - // token不存在,则发起登录 - await autoLogin() - - // 登录后重新获取token - const newTokenStorage = uni.getStorageSync(TOKEN_KEY) - const authHeader = getAuthHeader(newTokenStorage) - if (authHeader) config_header.Authorization = authHeader + // token不存在,刷新token + const newTokenStorage = await refreshToken() + if (newTokenStorage) { + const authHeader = getAuthHeader(newTokenStorage) + if (authHeader) config_header.Authorization = authHeader + } } } @@ -194,8 +255,6 @@ http.interceptors.request.use(async (config) => { // 响应拦截器 http.interceptors.response.use( async (response) => { - // console.log("response", response) - // 账号密码登录响应结果特殊处理 if (response.config.url === "/auth/oauth2/token") { return Promise.resolve({ @@ -208,8 +267,6 @@ http.interceptors.response.use( return Promise.resolve(response.data) }, async (error) => { - // console.log("error", error) - // 处理 424 错误(token过期) if (error.statusCode === 424) { if (isDevEnv()) { @@ -217,9 +274,21 @@ http.interceptors.response.use( uni.removeStorageSync(TOKEN_KEY) uni.removeStorageSync(USER_INFO_KEY) uni.showToast({ title: "登录已过期,请重新登录", icon: "none" }) - router.jump("/pages/test/login") + router.jump("/pages/user/login") } else { - await autoLogin() + try { + const newTokenStorage = await refreshToken() + if (newTokenStorage) { + // 重新发起失败的请求 + const config = error.config + const authHeader = getAuthHeader(newTokenStorage) + if (authHeader && config.header) config.header.Authorization = authHeader + return http.request(config) + } + } catch (err) { + // 错误已在refreshToken中处理 + return Promise.reject(err) + } } }