From 3b4596315737a0c5d64833a6ecd9e0c0a14a9f71 Mon Sep 17 00:00:00 2001 From: zjf <1799650030@qq.com> Date: Thu, 7 May 2026 12:09:37 +0800 Subject: [PATCH 01/13] .. --- .env | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env b/.env index 235df28..added0b 100644 --- a/.env +++ b/.env @@ -27,8 +27,8 @@ VITE_APP_DEV_SERVICE = http://127.0.0.1:9999 # 邓-本地 # VITE_IMAGE_DEV_PATH = https://stgl.pj.gov.cn/api # 域名线上 #VITE_IMAGE_DEV_PATH = http://59.202.170.152:81/api # 信创线上 # VITE_IMAGE_DEV_PATH = http://192.168.101.174:9999 # 邓-本地 -#VITE_IMAGE_DEV_PATH = http://127.0.0.1:9999 -VITE_IMAGE_DEV_PATH = http://123.157.250.162:8089/api # 测试线上 +VITE_IMAGE_DEV_PATH = http://127.0.0.1:9999 +#VITE_IMAGE_DEV_PATH = http://123.157.250.162:8089/api # 测试线上 # --------------------------- 生产环境 api地址 ---------------------------------- VITE_APP_PROD_SERVICE = https://stgl.pj.gov.cn/api # 域名线上 From b8d0379467166de99442eaa7390e3fe20a6484b4 Mon Sep 17 00:00:00 2001 From: zjf <1799650030@qq.com> Date: Fri, 8 May 2026 22:24:46 +0800 Subject: [PATCH 02/13] zzd --- package.json | 1 + src/App.vue | 8 ++ src/env.d.ts | 5 + src/pages.json | 7 ++ src/pages/tabbar/index.vue | 5 +- src/pages/tabbar/my.vue | 2 +- src/pages/user/zzdSmsVerify.vue | 106 ++++++++++++++++++ src/sheep/api/user.ts | 19 +++- src/sheep/utils/app.ts | 3 + src/sheep/utils/dingAuthCode.ts | 188 ++++++++++++++++++++++++++++++++ src/sheep/utils/loadScript.ts | 10 ++ src/sheep/utils/request.ts | 76 +++++++++++-- 12 files changed, 417 insertions(+), 13 deletions(-) create mode 100644 src/pages/user/zzdSmsVerify.vue create mode 100644 src/sheep/utils/dingAuthCode.ts create mode 100644 src/sheep/utils/loadScript.ts diff --git a/package.json b/package.json index c9270c2..9b3772a 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "@zebra-ui/swiper": "^2.2.8", "crypto-js": "^4.2.0", "dayjs": "^1.11.13", + "gdt-jsapi": "^1.9.55-beta.14", "luch-request": "^3.1.1", "pinia": "^2.2.6", "qrcode": "^1.5.4", diff --git a/src/App.vue b/src/App.vue index 2511212..9b24feb 100644 --- a/src/App.vue +++ b/src/App.vue @@ -164,6 +164,14 @@ const setTabbar = (launchParam?: string, auth?: string) => { } export default { + async onLaunch() { + try { + const { tryZzdEntryLogin } = await import("@/sheep/utils/request") + await tryZzdEntryLogin() + } catch (e) { + console.warn("[App.onLaunch] tryZzdEntryLogin", e) + } + }, methods: { async _initTabbar() { const launchParam = getLaunchParam() diff --git a/src/env.d.ts b/src/env.d.ts index cffc168..d3e9c77 100644 --- a/src/env.d.ts +++ b/src/env.d.ts @@ -1,5 +1,10 @@ /// +declare module "gdt-jsapi" { + const dd: { getAuthCode: (opts: { corpId?: string }) => Promise } + export default dd +} + declare module "*.vue" { import { DefineComponent } from "vue" // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types diff --git a/src/pages.json b/src/pages.json index fcbd993..5b7b364 100644 --- a/src/pages.json +++ b/src/pages.json @@ -383,6 +383,13 @@ "navigationBarTitleText": "用户身份", "disableScroll": true } + }, + { + "path": "zzdSmsVerify", + "style": { + "navigationBarTitleText": "手机号核验", + "disableScroll": true + } } ] }, diff --git a/src/pages/tabbar/index.vue b/src/pages/tabbar/index.vue index 7f7d1ef..7f33c2d 100644 --- a/src/pages/tabbar/index.vue +++ b/src/pages/tabbar/index.vue @@ -69,8 +69,11 @@ const jumpByParam = async () => { const appInfo = await getAppInfo() // 环境判断 const launchParam = getLaunchParam() // 获取启动参数 - // 浙政钉环境 + // 浙政钉环境(诗画不走此分支) if (appInfo == APPENV.ZZD) { + const { tryZzdEntryLogin } = await import("@/sheep/utils/request") + const zzdR = await tryZzdEntryLogin() + if (zzdR !== "ok") return switch (launchParam) { case "canteen": // 食堂 uni.setStorageSync("launchParam", launchParam) diff --git a/src/pages/tabbar/my.vue b/src/pages/tabbar/my.vue index 8c2c3b5..9141a88 100644 --- a/src/pages/tabbar/my.vue +++ b/src/pages/tabbar/my.vue @@ -242,7 +242,7 @@ const login = { if (isEmpty(tokenStorage) || isEmpty(userStorage)) { try { uni.showLoading({ title: "登录中...", mask: true }) - const res = await userApi.auth(token) + const res = await userApi.auth({ token }) if (res.code == 0) { storage.saveToken(res.data) diff --git a/src/pages/user/zzdSmsVerify.vue b/src/pages/user/zzdSmsVerify.vue new file mode 100644 index 0000000..6865182 --- /dev/null +++ b/src/pages/user/zzdSmsVerify.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/src/sheep/api/user.ts b/src/sheep/api/user.ts index e1d8de8..4cfb042 100644 --- a/src/sheep/api/user.ts +++ b/src/sheep/api/user.ts @@ -12,12 +12,25 @@ export default { method: "GET", }), - // 浙政钉授权登录 - auth: (token: string): Promise => + // 浙政钉授权登录(token:旧 uabaseToken;authCode:开放平台 H5 getAuthCode) + auth: (payload: { token?: string; authCode?: string }): Promise => request({ url: "/thirdparty/thirdPartyOAth2/zzdsso", method: "POST", - data: { token }, + data: payload, + }), + + zzdLoginSms: (mobilePhone: string): Promise => + request({ + url: `/thirdparty/thirdPartyOAth2/loginSms?mobilePhone=${encodeURIComponent(mobilePhone.trim())}`, + method: "POST", + }), + + zzdSsoConfirmPhone: (data: { bindSessionId: string; mobilePhone: string; smsCode: string }): Promise => + request({ + url: "/thirdparty/thirdPartyOAth2/zzdsso/confirmPhone", + method: "POST", + data, }), // 诗画授权登录 diff --git a/src/sheep/utils/app.ts b/src/sheep/utils/app.ts index 051bf54..739bd6b 100644 --- a/src/sheep/utils/app.ts +++ b/src/sheep/utils/app.ts @@ -12,6 +12,9 @@ export const getLaunchParam = (): string => { // 检测app信息判断运行环境 export const getAppInfo = async (): Promise => { + if (import.meta.env.VITE_DEV_FORCE_ZZD === "true") { + return APPENV.ZZD + } try { const res = await (window as any).CP2.getAppInfo() // 浙政钉环境 diff --git a/src/sheep/utils/dingAuthCode.ts b/src/sheep/utils/dingAuthCode.ts new file mode 100644 index 0000000..1deffbe --- /dev/null +++ b/src/sheep/utils/dingAuthCode.ts @@ -0,0 +1,188 @@ +import { loadScript } from "./loadScript" + +const JSAPI_LOAD_TIMEOUT_MS = 45000 +/** 仅在不注入 dd 的环境(如普通浏览器)按需拉取;浙政钉内通常自带 window.dd */ +const DEFAULT_OPEN_JS_URL = "https://g.alicdn.com/dingding/dingtalk-jsapi/3.0.12/dingtalk.open.js" +/** 微应用需 dd.config 完成后 ready 才会回调;超时则不再盲调 requestAuthCode */ +const DD_READY_TIMEOUT_MS = 30000 + +let ddErrorCallbackRegistered = false + +declare global { + interface Window { + dd?: { + env?: { platform?: string } + /** 政务钉钉 / 专有钉钉:JSAPI 鉴权(ticket 来自开放平台 get_jsapi_token) */ + authConfig?: (opts: { ticket: string; jsApiList: string[] }) => Promise + config?: (opts: { + agentId: string + corpId: string + timeStamp: string + nonceStr: string + signature: string + type?: number + jsApiList: string[] + }) => void + /** 专有钉钉 / 浙政钉文档:获取登录授权码(Promise),移动端返回 code,PC 返回 auth_code */ + getAuthCode?: (opts: { corpId?: string }) => Promise<{ + code?: string + auth_code?: string + expiresln?: number + expires_in?: number + }> + ready: (cb: () => void) => void + /** 鉴权/配置失败时回调,便于排查未触发取码的原因 */ + error?: (cb: (err: unknown) => void) => void + runtime: { + permission: { + requestAuthCode: (opts: { + corpId: string + onSuccess: (info: { code: string }) => void + onFail?: (err: unknown) => void + }) => void + } + } + } + } +} + +function registerDdErrorOnce() { + const dd = window.dd + if (!dd || ddErrorCallbackRegistered || typeof dd.error !== "function") return + ddErrorCallbackRegistered = true + try { + dd.error((err: unknown) => { + console.error("[dd.error]", typeof err === "string" ? err : err) + }) + } catch { + /* ignore */ + } +} + +function injectWaitMs(): number { + const v = import.meta.env.VITE_DD_INJECT_WAIT_MS + if (v === undefined || v === "") return 5000 + const n = parseInt(String(v), 10) + return Number.isFinite(n) && n >= 0 ? n : 5000 +} + +/** 部分 IRS/扫码场景下容器晚于首屏注入 dd,短轮询避免误判 */ +function waitForNativeDd(maxMs: number): Promise { + if (maxMs <= 0) return Promise.resolve(!!window.dd) + if (window.dd) return Promise.resolve(true) + return new Promise((resolve) => { + const t0 = Date.now() + const id = setInterval(() => { + if (window.dd) { + clearInterval(id) + resolve(true) + } else if (Date.now() - t0 >= maxMs) { + clearInterval(id) + resolve(false) + } + }, 80) + }) +} + +/** + * 浙政钉 / 钉钉容器内需在 dd.ready 之后再调 getAuthCode / requestAuthCode,否则 Android 上常见无回调。 + */ +export function ensureDdReady(): Promise { + return new Promise((resolve, reject) => { + const dd = window.dd + if (!dd) { + reject(new Error("window.dd 不存在")) + return + } + if (typeof dd.ready !== "function") { + resolve() + return + } + let settled = false + const to = setTimeout(() => { + if (settled) return + settled = true + const msg = `dd.ready 超时(${DD_READY_TIMEOUT_MS / 1000}s)。完整单点需先 dd.authConfig;或调试时跳过 ready 直接 getAuthCode。` + reject(new Error(msg)) + }, DD_READY_TIMEOUT_MS) + try { + dd.ready(() => { + if (settled) return + settled = true + clearTimeout(to) + resolve() + }) + } catch (e) { + clearTimeout(to) + if (!settled) { + settled = true + reject(e instanceof Error ? e : new Error(String(e))) + } + } + }) +} + +/** + * 1) 优先用容器自带的 `window.dd`(浙政钉内嵌常见)。 + * 2) 若首屏没有 dd:先等待 `VITE_DD_INJECT_WAIT_MS`(默认 5s)以兼容延迟注入。 + * 3) 仍没有时:默认自动拉 g.alicdn open.js(IRS 测试、扫码开系统浏览器等);纯内嵌且绝不拉脚本可设 `VITE_DD_NO_OPEN_JS_FALLBACK=true`。 + * 4) 显式 `VITE_DD_LOAD_OPEN_JS=true` 时跳过等待立即拉脚本(本地 Chrome 调试可配合 .env.development)。 + */ +export async function loadDingTalkOpenJsapi() { + if (window.dd) { + registerDdErrorOnce() + return + } + const forceScript = import.meta.env.VITE_DD_LOAD_OPEN_JS === "true" + const noFallback = import.meta.env.VITE_DD_NO_OPEN_JS_FALLBACK === "true" + if (!forceScript) { + const waitMs = injectWaitMs() + if (waitMs > 0) { + const ok = await waitForNativeDd(waitMs) + if (ok) { + registerDdErrorOnce() + return + } + } + if (noFallback) { + const msg = + "等待后仍无 window.dd。请确认链接在浙政钉内置 WebView 打开;或去掉 VITE_DD_NO_OPEN_JS_FALLBACK、或设 VITE_DD_LOAD_OPEN_JS=true" + throw new Error(msg) + } + } + const scriptUrl = (import.meta.env.VITE_DD_JSAPI_URL || "").trim() || DEFAULT_OPEN_JS_URL + await Promise.race([ + loadScript(scriptUrl), + new Promise((_, rej) => + setTimeout( + () => rej(new Error(`钉钉 JSAPI 脚本加载超时(${JSAPI_LOAD_TIMEOUT_MS / 1000}s)`)), + JSAPI_LOAD_TIMEOUT_MS, + ), + ), + ]) + if (!window.dd) { + throw new Error("脚本已执行但 window.dd 仍不存在") + } + registerDdErrorOnce() +} + +/** gdt-jsapi 容器返回:code / auth_code / authCode(与 zzdhome `src/App.vue` 中 `authCodeFromGetAuthResult` 一致) */ +export function authCodeFromGdtResult(res: unknown): string | null { + if (!res || typeof res !== "object") return null + const o = res as Record + const c = o.code ?? o.auth_code ?? o.authCode + if (typeof c === "string" && c.trim()) return c.trim() + return null +} + +/** + * 与 zzdhome `App.vue` 的 `runZzdLogin` 一致:`loadDingTalkOpenJsapi` 后使用 `gdt-jsapi` 的 `getAuthCode`,不再单独用 window.dd 包一层 Promise。 + */ +export async function requestZzdAuthCodeViaGdt(corpId: string): Promise { + const dd = (await import("gdt-jsapi")).default + await loadDingTalkOpenJsapi() + const res = await dd.getAuthCode({ corpId: (corpId || "").trim() }) + const code = authCodeFromGdtResult(res) + if (!code) throw new Error("getAuthCode 未返回有效 code(请核对 gdt 返回字段)") + return code +} diff --git a/src/sheep/utils/loadScript.ts b/src/sheep/utils/loadScript.ts new file mode 100644 index 0000000..a2c20c4 --- /dev/null +++ b/src/sheep/utils/loadScript.ts @@ -0,0 +1,10 @@ +export function loadScript(src: string): Promise { + return new Promise((resolve, reject) => { + const el = document.createElement("script") + el.src = src + el.async = true + el.onload = () => resolve() + el.onerror = () => reject(new Error(`脚本加载失败: ${src}`)) + document.head.appendChild(el) + }) +} diff --git a/src/sheep/utils/request.ts b/src/sheep/utils/request.ts index 63e1bf2..3a32012 100644 --- a/src/sheep/utils/request.ts +++ b/src/sheep/utils/request.ts @@ -219,39 +219,99 @@ const autoLogin = async (): Promise => { return false } -// 浙政钉登录 -async function loginByZzd(): Promise { +function isZzdNeedSmsVerify(data: unknown): data is { needSmsVerify: true; bindSessionId: string; displayName?: string } { + if (!data || typeof data !== "object") return false + const o = data as Record + return o.needSmsVerify === true && typeof o.bindSessionId === "string" +} + +function goZzdSmsVerify(data: { bindSessionId: string; displayName?: string }) { + const name = typeof data.displayName === "string" ? data.displayName : "" + const q = `bindSessionId=${encodeURIComponent(data.bindSessionId)}&displayName=${encodeURIComponent(name)}` + uni.reLaunch({ url: `/pages/user/zzdSmsVerify?${q}` }) +} + +/** + * 浙政钉专用:校验本地 token → 无效则 getAuthCode→zzdsso → 需绑手机则去短信页 → 否则换 token。 + * @returns ok 已可带 token 请求;sms 已跳转核验页;failed 未登录 + */ +async function zzdLoginCore(): Promise<"ok" | "sms" | "failed"> { try { uni.showLoading({ title: "登录中...", mask: true }) - const token = new URL(window.location.href).searchParams.get("uabaseToken") + const tokenStorage = uni.getStorageSync(TOKEN_KEY) + if (!isEmpty(tokenStorage) && !isTokenExpires(tokenStorage) && getTokenValue(tokenStorage)) { + uni.hideLoading() + return "ok" + } + + if (typeof window !== "undefined") { + try { + const { requestZzdAuthCodeViaGdt } = await import("./dingAuthCode") + const corpId = (import.meta.env.VITE_ZZD_CORP_ID || "").trim() + const authCode = await requestZzdAuthCodeViaGdt(corpId) + const res: any = await userApi.auth({ authCode }) + if (res?.code == 0) { + if (isZzdNeedSmsVerify(res.data)) { + goZzdSmsVerify(res.data) + return "sms" + } + uni.setStorageSync(TOKEN_KEY, res.data) + const { data: userData } = await userApi.userInfo() + uni.setStorageSync(USER_INFO_KEY, userData) + return "ok" + } + if (res?.msg) { + uni.showToast({ title: res.msg, icon: "none", duration: 4000 }) + } + } catch (e) { + console.warn("[loginByZzd] authCode 登录未成功,尝试 uabaseToken", e) + } + } + + const token = + typeof window !== "undefined" ? new URL(window.location.href).searchParams.get("uabaseToken") : null if (!token) { uni.showToast({ title: "用户凭证已失效,请重新进入智慧后勤应用", icon: "none", duration: 6000 }) - return false + return "failed" } - const res = await userApi.auth(token) + const res = await userApi.auth({ token }) if (res?.code == 0) { uni.setStorageSync(TOKEN_KEY, res.data) const { data: userData } = await userApi.userInfo() uni.setStorageSync(USER_INFO_KEY, userData) - return true + return "ok" } else { uni.removeStorageSync(TOKEN_KEY) uni.removeStorageSync(USER_INFO_KEY) if (res.msg == "token已失效") { uni.showToast({ title: "用户凭证已失效,请退出并重新进入智慧后勤应用", icon: "none", duration: 6000 }) } - return false + return "failed" } } catch (error: any) { uni.showToast({ title: error, icon: "none" }) - return false + return "failed" } finally { uni.hideLoading() } } +async function loginByZzd(): Promise { + const r = await zzdLoginCore() + return r === "ok" +} + +/** + * 从门户/常用入口进入 H5 时主动跑浙政钉单点。非浙政钉环境立即返回 ok,不调用 zzdsso、不碰诗画逻辑。 + */ +export async function tryZzdEntryLogin(): Promise<"ok" | "sms" | "failed"> { + const appInfo = await getAppInfo() + if (appInfo !== APPENV.ZZD) return "ok" + return await zzdLoginCore() +} + // 诗画登录 async function loginBySh(): Promise { try { From 22e0aaf610aa57f71300904793a2a592ad364da6 Mon Sep 17 00:00:00 2001 From: zjf <1799650030@qq.com> Date: Fri, 8 May 2026 22:36:14 +0800 Subject: [PATCH 03/13] zzd --- src/sheep/utils/app.ts | 17 ++++++++++++++++- src/sheep/utils/request.ts | 5 ++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/sheep/utils/app.ts b/src/sheep/utils/app.ts index 739bd6b..f2db66f 100644 --- a/src/sheep/utils/app.ts +++ b/src/sheep/utils/app.ts @@ -5,9 +5,24 @@ import { APPENV } from "../constant" // export default () => import.meta.env.VITE_DEV_ENV === "dev" export const isDevEnv = (): boolean => process.env.NODE_ENV === "development" +/** + * 读取当前页 URL 查询参数(H5)。兼容 hash 路由:`/h5/#/?launchParam=canteen` 中参数在 hash 段,不在 location.search。 + */ +export const getUrlQueryParam = (name: string): string => { + if (typeof window === "undefined") return "" + const u = new URL(window.location.href) + const fromSearch = u.searchParams.get(name) + if (fromSearch) return fromSearch + const hash = window.location.hash || "" + const qi = hash.indexOf("?") + if (qi < 0) return "" + const fromHash = new URLSearchParams(hash.slice(qi + 1)).get(name) + return fromHash || "" +} + // 获取启动参数 export const getLaunchParam = (): string => { - return new URL(window.location.href).searchParams.get("launchParam") || uni.getStorageSync("launchParam") || "" + return getUrlQueryParam("launchParam") || uni.getStorageSync("launchParam") || "" } // 检测app信息判断运行环境 diff --git a/src/sheep/utils/request.ts b/src/sheep/utils/request.ts index 3a32012..7f8289d 100644 --- a/src/sheep/utils/request.ts +++ b/src/sheep/utils/request.ts @@ -1,7 +1,7 @@ import Request from "luch-request" import { router, constant } from "@@/index" import { isEmpty } from "radash" -import { getAppInfo, isDevEnv } from "@@/utils/app" +import { getAppInfo, getUrlQueryParam, isDevEnv } from "@@/utils/app" import { userApi } from "../api" import showVerifyDeviceImpModel from "../components/verifyDeviceImpModel/verifyDeviceImpModel" import { APPENV } from "../constant" @@ -268,8 +268,7 @@ async function zzdLoginCore(): Promise<"ok" | "sms" | "failed"> { } } - const token = - typeof window !== "undefined" ? new URL(window.location.href).searchParams.get("uabaseToken") : null + const token = typeof window !== "undefined" ? getUrlQueryParam("uabaseToken") || null : null if (!token) { uni.showToast({ title: "用户凭证已失效,请重新进入智慧后勤应用", icon: "none", duration: 6000 }) From 4df8ee27da04f5d0737ea644efea595b903747d2 Mon Sep 17 00:00:00 2001 From: zjf <1799650030@qq.com> Date: Fri, 8 May 2026 22:46:40 +0800 Subject: [PATCH 04/13] zzd --- src/App.vue | 6 +++++- src/pages/tabbar/index.vue | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/App.vue b/src/App.vue index 9b24feb..78ba379 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,5 +1,5 @@ - - diff --git a/package.json b/package.json index 9b3772a..1168979 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "qrcode": "^1.5.4", "qs": "^6.13.1", "radash": "^12.1.0", + "vconsole": "^3.15.1", "vue": "^3.3.11", "vue-i18n": "^9.1.9", "vue-waterfall-plugin-next": "^2.6.5", @@ -91,4 +92,4 @@ "vite": "5.2.8", "vue-tsc": "^1.0.24" } -} \ No newline at end of file +} diff --git a/src/env.d.ts b/src/env.d.ts index d3e9c77..67f2f1f 100644 --- a/src/env.d.ts +++ b/src/env.d.ts @@ -1,5 +1,13 @@ /// +interface ImportMetaEnv { + readonly VITE_VCONSOLE?: string +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} + declare module "gdt-jsapi" { const dd: { getAuthCode: (opts: { corpId?: string }) => Promise } export default dd diff --git a/src/main.ts b/src/main.ts index 9b3e559..5e7005b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -5,6 +5,13 @@ import pinia from "../src/sheep/stores/index" import App from "./App.vue" import tmUi from "./uni_modules/tm-ui" +// #ifdef H5 +import VConsole from "vconsole" +if (import.meta.env.VITE_VCONSOLE === "true") { + new VConsole() +} +// #endif + export function createApp() { const app = createSSRApp(App) From c2b57e7acac2a0370c34834fa91c96d3c17e5ded Mon Sep 17 00:00:00 2001 From: zjf <1799650030@qq.com> Date: Fri, 8 May 2026 23:11:47 +0800 Subject: [PATCH 06/13] zzd --- package.json | 1 + vite.config.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 1168979..b01a1ac 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "type-check": "vue-tsc --noEmit" }, "dependencies": { + "@babel/runtime": "^7.26.0", "@dcloudio/uni-app": "3.0.0-4020920240930001", "@dcloudio/uni-app-harmony": "3.0.0-4020920240930001", "@dcloudio/uni-app-plus": "3.0.0-4020920240930001", diff --git a/vite.config.ts b/vite.config.ts index 4ef4276..d94d052 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -4,7 +4,7 @@ import { defineConfig, loadEnv } from "vite" import uni from "@dcloudio/vite-plugin-uni" import Unocss from "unocss/vite" -import { useRouter } from "./src/sheep" +import { useRouter } from "./src/sheep/plugs/use-router/vite-router-plug" export default defineConfig(({ mode }) => { const { NODE_ENV, VITE_APP_DEV_SERVICE, VITE_APP_PROD_SERVICE, VITE_IMAGE_DEV_PATH } = loadEnv(mode, process.cwd(), "") From d88b995791203c3bb60ea8474a479ebeadcd3ec9 Mon Sep 17 00:00:00 2001 From: zjf <1799650030@qq.com> Date: Fri, 8 May 2026 23:20:57 +0800 Subject: [PATCH 07/13] zzd --- src/sheep/utils/dingAuthCode.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sheep/utils/dingAuthCode.ts b/src/sheep/utils/dingAuthCode.ts index 1deffbe..118742d 100644 --- a/src/sheep/utils/dingAuthCode.ts +++ b/src/sheep/utils/dingAuthCode.ts @@ -1,3 +1,4 @@ +import gdtJsapi from "gdt-jsapi" import { loadScript } from "./loadScript" const JSAPI_LOAD_TIMEOUT_MS = 45000 @@ -179,9 +180,8 @@ export function authCodeFromGdtResult(res: unknown): string | null { * 与 zzdhome `App.vue` 的 `runZzdLogin` 一致:`loadDingTalkOpenJsapi` 后使用 `gdt-jsapi` 的 `getAuthCode`,不再单独用 window.dd 包一层 Promise。 */ export async function requestZzdAuthCodeViaGdt(corpId: string): Promise { - const dd = (await import("gdt-jsapi")).default await loadDingTalkOpenJsapi() - const res = await dd.getAuthCode({ corpId: (corpId || "").trim() }) + const res = await gdtJsapi.getAuthCode({ corpId: (corpId || "").trim() }) const code = authCodeFromGdtResult(res) if (!code) throw new Error("getAuthCode 未返回有效 code(请核对 gdt 返回字段)") return code From 26fc9d27ed3eac366697b306397abfc73494b093 Mon Sep 17 00:00:00 2001 From: zjf <1799650030@qq.com> Date: Fri, 8 May 2026 23:36:04 +0800 Subject: [PATCH 08/13] zzd --- src/pages/user/zzdSmsVerify.vue | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/pages/user/zzdSmsVerify.vue b/src/pages/user/zzdSmsVerify.vue index 6865182..b98e1b6 100644 --- a/src/pages/user/zzdSmsVerify.vue +++ b/src/pages/user/zzdSmsVerify.vue @@ -4,6 +4,9 @@ import { onLoad } from "@dcloudio/uni-app" import { constant } from "@@/index" import { userApi } from "@@/api" +/** 与后端 ThirdPartyZzdBizCodes.SYS_USER_NOT_FOUND_FOR_ZZD_BIND 一致 */ +const CODE_ZZD_SYS_USER_NOT_FOUND = 46001 + const bindSessionId = ref("") const displayName = ref("") const mobile = ref("") @@ -47,7 +50,17 @@ async function confirm() { smsCode: code, }) if (r?.code !== 0) { - uni.showToast({ title: r?.msg || "核验失败", icon: "none" }) + if (r?.code === CODE_ZZD_SYS_USER_NOT_FOUND) { + uni.showModal({ + title: "暂无系统账号", + content: + r?.msg || + "本系统暂无该手机号对应的用户,请联系管理员申请开通账号后,再使用本机号码完成浙政钉绑定登录。", + showCancel: false, + }) + } else { + uni.showToast({ title: r?.msg || "核验失败", icon: "none" }) + } return } const tokenKey = constant.storageConstant.TOKEN From df64d5cbc3df9dee91e4228453426ae9fd2f7948 Mon Sep 17 00:00:00 2001 From: zjf <1799650030@qq.com> Date: Fri, 8 May 2026 23:56:46 +0800 Subject: [PATCH 09/13] zzd --- src/sheep/utils/request.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/sheep/utils/request.ts b/src/sheep/utils/request.ts index 7f8289d..bae2c13 100644 --- a/src/sheep/utils/request.ts +++ b/src/sheep/utils/request.ts @@ -222,12 +222,17 @@ const autoLogin = async (): Promise => { function isZzdNeedSmsVerify(data: unknown): data is { needSmsVerify: true; bindSessionId: string; displayName?: string } { if (!data || typeof data !== "object") return false const o = data as Record - return o.needSmsVerify === true && typeof o.bindSessionId === "string" + const need = + o.needSmsVerify === true || o.needSmsVerify === "true" || o.needSmsVerify === 1 || o.needSmsVerify === "1" + const sid = o.bindSessionId + const sidStr = typeof sid === "string" ? sid : sid != null ? String(sid) : "" + return need && sidStr.length > 0 } function goZzdSmsVerify(data: { bindSessionId: string; displayName?: string }) { + const sid = typeof data.bindSessionId === "string" ? data.bindSessionId : String(data.bindSessionId || "") const name = typeof data.displayName === "string" ? data.displayName : "" - const q = `bindSessionId=${encodeURIComponent(data.bindSessionId)}&displayName=${encodeURIComponent(name)}` + const q = `bindSessionId=${encodeURIComponent(sid)}&displayName=${encodeURIComponent(name)}` uni.reLaunch({ url: `/pages/user/zzdSmsVerify?${q}` }) } @@ -252,9 +257,14 @@ async function zzdLoginCore(): Promise<"ok" | "sms" | "failed"> { const res: any = await userApi.auth({ authCode }) if (res?.code == 0) { if (isZzdNeedSmsVerify(res.data)) { - goZzdSmsVerify(res.data) + goZzdSmsVerify(res.data as { bindSessionId: string; displayName?: string }) return "sms" } + const d = res.data + if (!d || typeof d !== "object" || (!d.accessToken && !d.refreshToken)) { + uni.showToast({ title: "登录返回数据异常,请重试", icon: "none", duration: 4000 }) + return "failed" + } uni.setStorageSync(TOKEN_KEY, res.data) const { data: userData } = await userApi.userInfo() uni.setStorageSync(USER_INFO_KEY, userData) @@ -263,6 +273,7 @@ async function zzdLoginCore(): Promise<"ok" | "sms" | "failed"> { if (res?.msg) { uni.showToast({ title: res.msg, icon: "none", duration: 4000 }) } + return "failed" } catch (e) { console.warn("[loginByZzd] authCode 登录未成功,尝试 uabaseToken", e) } From b546cc861c81627a5b5fcc84cbc3b2f5af3cfde0 Mon Sep 17 00:00:00 2001 From: zjf <1799650030@qq.com> Date: Sat, 9 May 2026 00:45:57 +0800 Subject: [PATCH 10/13] zzd --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index 165c62c..58809f5 100644 --- a/.env +++ b/.env @@ -1,5 +1,5 @@ # H5:true 时在页面加载 vConsole(浙政钉内可看 Network/Log);稳定上线后改为 false -VITE_VCONSOLE=true +VITE_VCONSOLE=false #是否是TOC应用 VITE_IS_TOC=true From d7f5f1a6561aec943bafb0586e2d0493315d84cc Mon Sep 17 00:00:00 2001 From: zjf <1799650030@qq.com> Date: Sat, 9 May 2026 14:50:21 +0800 Subject: [PATCH 11/13] zzd --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index 58809f5..165c62c 100644 --- a/.env +++ b/.env @@ -1,5 +1,5 @@ # H5:true 时在页面加载 vConsole(浙政钉内可看 Network/Log);稳定上线后改为 false -VITE_VCONSOLE=false +VITE_VCONSOLE=true #是否是TOC应用 VITE_IS_TOC=true From fd068aeaf229d95ff6f402f15cc3d17d02df884a Mon Sep 17 00:00:00 2001 From: zjf <1799650030@qq.com> Date: Sat, 9 May 2026 15:03:18 +0800 Subject: [PATCH 12/13] shjn --- src/pages/tabbar/my.vue | 3 +++ src/sheep/utils/request.ts | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/pages/tabbar/my.vue b/src/pages/tabbar/my.vue index 9141a88..8b2facc 100644 --- a/src/pages/tabbar/my.vue +++ b/src/pages/tabbar/my.vue @@ -233,6 +233,9 @@ const login = { if (response.msg == "token已失效") { uni.showToast({ title: "用户凭证已失效,请退出并重新进入智慧后勤应用", icon: "none", duration: 6000 }) } else { + if (response.code == -1) { + storage.saveToken({ data: -1 }) + } uni.showToast({ title: response.msg || "登录失败", icon: "none" }) } } diff --git a/src/sheep/utils/request.ts b/src/sheep/utils/request.ts index bae2c13..a8fdb28 100644 --- a/src/sheep/utils/request.ts +++ b/src/sheep/utils/request.ts @@ -351,8 +351,8 @@ async function loginBySh(): Promise { return false } - // 如果是设备未验证,保存响应数据 - if (response.data == -1) { + // 设备未信任:后端 R.failed(-1, msg) 业务码在 code,data 为 null + if (response.code == -1) { uni.setStorageSync(TOKEN_KEY, { data: -1 }) } From d0621ba995abc2528559b286285506ec91025078 Mon Sep 17 00:00:00 2001 From: zjf <1799650030@qq.com> Date: Sat, 9 May 2026 15:14:34 +0800 Subject: [PATCH 13/13] shjn --- .env | 3 ++- src/pages/tabbar/my.vue | 14 ++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 165c62c..4d20a67 100644 --- a/.env +++ b/.env @@ -1,5 +1,6 @@ # H5:true 时在页面加载 vConsole(浙政钉内可看 Network/Log);稳定上线后改为 false -VITE_VCONSOLE=true +#VITE_VCONSOLE=true +VITE_VCONSOLE=false #是否是TOC应用 VITE_IS_TOC=true diff --git a/src/pages/tabbar/my.vue b/src/pages/tabbar/my.vue index 8b2facc..4196706 100644 --- a/src/pages/tabbar/my.vue +++ b/src/pages/tabbar/my.vue @@ -1,8 +1,8 @@