import { appId, BASE_URL } from "../../env"; import { LoginRes } from "./login.d"; import { wxLogin, wxRequest } from "../../utils/wx-api"; const app = getApp(); const defaultAvatarUrl = "https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0"; type LoginDisplayConfig = { showLoginImage: boolean; }; type PartialLoginDisplayConfig = Partial; const loginConfigKeys = [ "login", "loginConfig", "loginPage", "auth", "authConfig", "authPage", ]; const WXROOM_REDIRECT_PATH_KEY = "wxroomRedirectPath"; function isPlainObject(value: unknown): value is Record { return Object.prototype.toString.call(value) === "[object Object]"; } function hasOwnValue(source: Record, keys: string[]) { return keys.some((key) => source[key] !== undefined && source[key] !== null); } function normalizeString(value: unknown) { return typeof value === "string" ? value.trim() : ""; } function normalizeBoolean(value: unknown) { if (typeof value === "boolean") return value; if (typeof value === "number") return value > 0; if (typeof value !== "string") return undefined; const normalized = value.trim().toLowerCase(); if (["1", "true", "yes", "show", "visible", "enabled"].includes(normalized)) { return true; } if (["0", "false", "no", "hide", "hidden", "disabled"].includes(normalized)) { return false; } return undefined; } function normalizeSwitchValue(value: unknown) { const normalized = normalizeBoolean(value); if (normalized !== undefined) return normalized; if (typeof value === "string") return value.trim().length > 0; if (Array.isArray(value)) return value.length > 0; if (isPlainObject(value)) { const innerToggle = getBooleanValue(value, ["show", "visible", "enabled", "value"]); if (innerToggle !== undefined) return innerToggle; return !!getStringValue(value, [ "url", "src", "image", "imageUrl", "background", "backgroundImage", ]); } return undefined; } function getObjectValue(source: Record, keys: string[]) { for (const key of keys) { const value = source[key]; if (value !== undefined && value !== null && value !== "") { return value; } } return undefined; } function getStringValue(source: Record, keys: string[]):string { const value = getObjectValue(source, keys); if (value === undefined) return ""; if (isPlainObject(value)) { return getStringValue(value, [ "url", "src", "image", "imageUrl", "background", "backgroundImage", ]); } return normalizeString(value); } function getBooleanValue(source: Record, keys: string[]) { const value = getObjectValue(source, keys); return normalizeBoolean(value); } function pushConfigCandidate(list: Record[], value: unknown) { if (isPlainObject(value)) { list.push(value); } } function collectLoginConfigCandidates(template: unknown) { const candidates: Record[] = []; if (!isPlainObject(template)) return candidates; if ( hasOwnValue(template, [ "showLoginImage", "showLoginBackground", "showBackgroundImage", "showImage", "imageSwitch", "backgroundSwitch", "loginImage", "heroImage", "loginBg", "loginBackground", "backgroundImage", "backgroundUrl", "background", "image", ]) ) { candidates.push(template); } loginConfigKeys.forEach((key) => { pushConfigCandidate(candidates, template[key]); pushConfigCandidate(candidates, template.pageConfig?.[key]); pushConfigCandidate(candidates, template.pages?.[key]); pushConfigCandidate(candidates, template.property?.[key]); }); if (Array.isArray(template.pages?.login)) { template.pages.login.forEach((item: any) => { pushConfigCandidate(candidates, item); pushConfigCandidate(candidates, item?.props); }); } Object.entries(template).forEach(([key, value]) => { if (!/login|auth/i.test(key)) return; if (Array.isArray(value)) { value.forEach((item) => { if (!isPlainObject(item)) return; pushConfigCandidate(candidates, item); pushConfigCandidate(candidates, item.props); }); return; } pushConfigCandidate(candidates, value); }); return candidates; } function readLoginImageSwitch(source: Record) { const imageValue = getObjectValue(source, [ "showLoginImage", "showLoginBackground", "showBackgroundImage", "showImage", "imageSwitch", "backgroundSwitch", "loginImage", "heroImage", "loginBackground", "loginBg", "backgroundImage", "backgroundUrl", "background", "image", "imageUrl", ]); return normalizeSwitchValue(imageValue); } function resolveLoginDisplayConfigFromSource(source: unknown): PartialLoginDisplayConfig { if (!isPlainObject(source)) return {}; const showLoginImage = readLoginImageSwitch(source); return { ...(showLoginImage !== undefined ? { showLoginImage } : {}), }; } function mergeLoginDisplayConfig( current: PartialLoginDisplayConfig, next: PartialLoginDisplayConfig ) { return { ...current, ...(next.showLoginImage !== undefined ? { showLoginImage: next.showLoginImage } : {}), }; } Page({ data: { back: "", agree: false, nickFocus: true, showPopup: false, safeBottom: app.globalData.safeBottom, showLoginImage: false, userInfo: { avatarUrl: defaultAvatarUrl, nickName: "微信用户", }, }, applyLoginDisplayConfig(options: Record = {}) { const template = app.globalData.template as Record | null; const config = collectLoginConfigCandidates(template).reduce( (result, item) => mergeLoginDisplayConfig(result, resolveLoginDisplayConfigFromSource(item)), {} as PartialLoginDisplayConfig ); const optionConfig = resolveLoginDisplayConfigFromSource(options); const merged = mergeLoginDisplayConfig(config, optionConfig); this.setData({ showLoginImage: merged.showLoginImage ?? false, }); }, async onChooseAvatar(e: any) { const { avatarUrl } = e.detail; wx.uploadFile({ url: `${BASE_URL}/api/operation/sys-media/upload-oss`, filePath: avatarUrl, name: "media", success: (res: any) => { const { data } = JSON.parse(res.data); this.setData({ userInfo: { ...this.data.userInfo, avatarUrl: data, }, }); }, fail: () => { wx.showToast({ title: "上传头像失败", icon: "none", }); }, }); }, buildQueryString(params: Record): string { return Object.entries(params) .map( ([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}` ) .join("&"); }, redirectUrl() { const self = this; let fullPath = ""; const tabPages = [ "/pages/tab-bar/medicine-box/index", "/pages/tab-bar/shopping-cart/shopping-cart", "/pages/tab-bar/course/course", "/pages/tab-bar/user/user", "/pages/tab-bar/points-mall/points-mall", "/pages/tab-bar/category/category", ]; if (self.data.back) { if (self.data.back === "wxroom") { fullPath = wx.getStorageSync(WXROOM_REDIRECT_PATH_KEY) || "/package-live/wxroom/index"; wx.removeStorageSync(WXROOM_REDIRECT_PATH_KEY); } else { const store = app.globalData.store; const state = wx.getStorageSync("state") ?? undefined; const code = wx.getStorageSync("code") ?? undefined; const groupId = wx.getStorageSync("groupId") ?? undefined; if (state && !code) { if (self.data.back === "video") { const storeParams = typeof store === "string" ? store : this.buildQueryString(store); fullPath = `/pages/live/video/video?${storeParams}`; } else if (self.data.back === "red") { fullPath = `/pages/common/red/red`; } else if (self.data.back === "user") { fullPath = `/pages/tab-bar/user/user`; } else { fullPath = `/pages/live/registration/registration?state=${state}`; } } else if (!state && code) { if (self.data.back === "video") { const storeParams = typeof store === "string" ? store : this.buildQueryString(store); fullPath = `/pages/live/video/video?${storeParams}`; } else if (self.data.back === "red") { fullPath = `/pages/common/red/red`; } else if (self.data.back === "user") { fullPath = `/pages/tab-bar/user/user`; } else { fullPath = `/pages/live/registration/registration?code=${code}`; } } else { if (self.data.back === "room") { fullPath = `/pages/live/room/room?groupId=${groupId}`; } else if (self.data.back === "red") { fullPath = `/pages/common/red/red`; } else if (self.data.back === "user") { fullPath = `/pages/tab-bar/user/user`; } } } } else { const pages = getCurrentPages(); const currentPage = pages[pages.length - 2]; if (!currentPage) { // 如果没有上一页,跳转到第一个可用 tab,而不是硬编码的 index const tabbarItems = app.globalData.tabbarItems; if (tabbarItems && tabbarItems.length > 0) { wx.switchTab({ url: tabbarItems[0].pagePath }); } else { wx.switchTab({ url: "/pages/tab-bar/medicine-box/index" }); } return; } const route = `/${currentPage.route}`; const options = currentPage.options || {}; const query = this.buildQueryString(options); fullPath = query ? `${route}?${query}` : route; if (tabPages.includes(route)) { wx.switchTab({ url: route }); return; } wx.redirectTo({ url: route }); return; } if (tabPages.includes(fullPath)) { wx.switchTab({ url: fullPath }); } else { wx.redirectTo({ url: fullPath }); } }, async handleLogin() { if (!this.data.agree) { wx.showModal({ title: "请先勾选用户协议和隐私政策", icon: "none", success: (options) => { if (options.confirm) { this.setData({ agree: true }); } }, }); if (!this.data.agree) return; } try { wx.showLoading({ title: "登录中" }); const loginRes = await wxLogin(); if (!loginRes.code) throw new Error(loginRes.errMsg); const { avatarUrl, nickName } = this.data.userInfo; const state = wx.getStorageSync("state"); let loginResult: LoginRes; if (state) { const reqData: Record = { state: wx.getStorageSync("state") ?? undefined, ...(nickName && nickName !== "微信用户" ? { nickName } : {}), ...(avatarUrl && avatarUrl !== defaultAvatarUrl ? { avatarUrl } : {}), }; loginResult = await wxRequest({ url: `${BASE_URL}/api/auth/app-login?appId=${appId}&code=${loginRes.code}`, method: "POST", data: reqData, }); } else { const reqData: Record = { state: wx.getStorageSync("code") ?? undefined, ...(nickName && nickName !== "微信用户" ? { nickName } : {}), ...(avatarUrl && avatarUrl !== defaultAvatarUrl ? { avatarUrl } : {}), }; loginResult = await wxRequest({ url: `${BASE_URL}/api/auth/app-auth?appId=${appId}&code=${loginRes.code}`, method: "POST", data: reqData, }); } if ( loginResult?.statusCode !== 200 || (loginResult.data.code && loginResult.data.code !== 200) ) { throw new Error(loginResult?.data?.msg || "登录失败"); } const { mpUserId, id, openId, unionId, nickName: resNickName, avatarUrl: resAvatarUrl, } = loginResult.data; const storageData = { openId, userId: mpUserId, mbuId: id, unionId, userName: resNickName, avatarUrl: resAvatarUrl, }; Object.entries(storageData).forEach(([key, value]) => { wx.setStorageSync(key, value); }); app.globalData.isLogin = true; this.triggerEvent("loginSuccess", { userName: resNickName, avatarUrl: resAvatarUrl, }); wx.showToast({ title: "登录成功", duration: 2000, }); this.redirectUrl(); } catch (err: any) { console.log("登录失败:", err); app.globalData.isLogin = false; wx.showToast({ title: `登录失败:${err.message || err.errMsg}`, icon: "none", }); } finally { setTimeout(() => wx.hideToast(), 3000); } }, handleToggleAgree() { this.setData({ agree: !this.data.agree }); }, openPrivacyContract() { // @ts-ignore wx.openPrivacyContract(); }, onLoad(options: any) { if (options.back) { this.setData({ back: options.back }); } this.applyLoginDisplayConfig(options); }, onShow() { setTimeout(() => { this.setData({ nickFocus: true }); }, 200); }, });