shish 2 bulan lalu
induk
melakukan
6d82762bf0

+ 10 - 10
mallApp/src/App.vue

@@ -1,16 +1,15 @@
 <script>
 import { mapMutations, mapActions, mapGetters } from "vuex";
-// 这个导入在小程序环境中是不需要的,因为小程序环境已经有全局的 setTimeout 函数
-// import { setTimeout } from "timers";
 import { getUser, wxLoginFn } from "@/utils/auth";
 import {
   TOKEN_STORAGE_KEY,
   LEGACY_TOKEN_STORAGE_KEY,
 } from "@/constant/storageKeys";
+import { tryReLaunchFromScanEnter } from "@/utils/launchScene";
 export default {
-  // 全端,数据共享,还可以解决页面初始化模板访问不到值得问题
-  // 有坑 分包里的页面访问不到
-  globalData: {},
+  globalData: {
+    lastLaunchKey: "",
+  },
   onLaunch () {
     const legacyToken = uni.getStorageSync(LEGACY_TOKEN_STORAGE_KEY);
     const currentToken = uni.getStorageSync(TOKEN_STORAGE_KEY);
@@ -19,20 +18,15 @@ export default {
       uni.removeStorageSync(LEGACY_TOKEN_STORAGE_KEY);
     }
 
-    // this.getAllOptions()
-    // 删除缓存
     if (process.env.NODE_ENV == "production") {
       uni.removeStorageSync("shopUser");
     }
     // #ifdef MP-WEIXIN
-    // wxLoginFn()
-    // uni.clearStorage()
     const extConfig = wx.getExtConfigSync ? wx.getExtConfigSync() : {};
     uni.setStorageSync("account", extConfig.account);
     // #endif
 
     // #ifdef H5
-    // H5开发环境无法微信授权,使用固定的用户 shish 2020.4.30
     if (process.env.NODE_ENV == "development") {
       uni.setStorageSync(
         TOKEN_STORAGE_KEY,
@@ -42,6 +36,12 @@ export default {
     }
     // #endif
   },
+  onShow () {
+    // #ifdef MP-WEIXIN
+    // 热启动扫太阳码:页面栈可能保留,onLoad 不执行;在此 reLaunch 展开 scene 并清栈
+    tryReLaunchFromScanEnter(this.globalData);
+    // #endif
+  },
   onHide () { },
   onError (err) {
     console.error(err, "错误捕获");

+ 55 - 83
mallApp/src/mixins/globalMixins.js

@@ -1,83 +1,55 @@
-import { pageTo, isLogin } from '@/utils/util.js'
-import { wxLoginFn } from '@/utils/auth'
-import { mapGetters } from 'vuex'
-import { TOKEN_STORAGE_KEY } from '@/constant/storageKeys'
-export default {
-	data() {
-		return {
-			option: null,
-			constant: this.$constant,
-			$util: this.$util,
-			pageTo: pageTo,
-			//0没有登录 1有登录
-			globalLoginStyle :0
-		}
-	},
-	computed: {
-		...mapGetters({ loginInfo: "getLoginInfo" })
-	},
-	// 页面生命周期才触发
-	onLoad: function (option) {
-		let that = this
-		this.option = option || null
-		if (option.token) {
-			uni.setStorageSync(TOKEN_STORAGE_KEY, option.token)
-		}
-
-		//扫客户注册码、客户充值码
-		if(option.scene){
-			const scene = decodeURIComponent(option.scene)
-			var theRequest = new Object();
-			var strs = scene.split("&");
-			for (var i = 0; i < strs.length; i++) {
-				theRequest[strs[i].split('=')[0]] = decodeURI(strs[i].split('=')[1]);
-			}
-			if(theRequest.s){
-				option.account = theRequest.s
-			}
-		}
-
-		//扫门店收款二维码打开小程序付款页
-		//https://shop.theflorist.cn/#/pages/pay/index?account=36123
-		if(option.q){
-			let currentUrl = decodeURIComponent(option.q);
-			let thisAccount = currentUrl.substring(currentUrl.lastIndexOf("account=") + 8)
-			console.log('扫码获取account',thisAccount)
-			option.account = thisAccount
-		}
-
-		if (option.account) {
-			uni.setStorageSync('account', option.account)
-		}else{
-			uni.setStorageSync('account', 0)
-		}
-		if (option.hdId) {
-			uni.setStorageSync('hdId', option.hdId)
-		}else{
-			uni.setStorageSync('hdId', 0)
-		}
-
-		uni.setStorageSync('currentQuery', JSON.stringify(option))
-
-		//线上检查小程序的登录态是否有效 checkSession
-		//checkSession开发环境无效,在真机调试有效
-		if (process.env.NODE_ENV == "production") {
-			uni.checkSession({
-				success() {
-					console.log('checkSession success')
-				},
-				fail() {
-					uni.removeStorageSync(TOKEN_STORAGE_KEY);
-				}
-			})
-		}
-		if (that.$util.isEmpty(that.getLoginInfo)) {
-			wxLoginFn().then(wxRes=>{
-				that.init()
-			})
-		}else{
-			that.init()
-		}
-	}
-
-}
+import { pageTo } from '@/utils/util.js'

+import { wxLoginFn } from '@/utils/auth'

+import { mapGetters } from 'vuex'

+import { TOKEN_STORAGE_KEY } from '@/constant/storageKeys'

+import { applyLaunchQuery, persistLaunchStorage } from '@/utils/launchScene'

+

+export default {

+	data() {

+		return {

+			option: null,

+			constant: this.$constant,

+			$util: this.$util,

+			pageTo: pageTo,

+			//0没有登录 1有登录

+			globalLoginStyle :0

+		}

+	},

+	computed: {

+		...mapGetters({ loginInfo: "getLoginInfo" })

+	},

+	// 页面生命周期才触发

+	onLoad: function (option) {

+		let that = this

+		option = applyLaunchQuery(option || {})

+		this.option = option

+

+		if (option.token) {

+			uni.setStorageSync(TOKEN_STORAGE_KEY, option.token)

+		}

+

+		persistLaunchStorage(option)

+

+		//线上检查小程序的登录态是否有效 checkSession

+		//checkSession开发环境无效,在真机调试有效

+		if (process.env.NODE_ENV == "production") {

+			uni.checkSession({

+				success() {

+					console.log('checkSession success')

+				},

+				fail() {

+					uni.removeStorageSync(TOKEN_STORAGE_KEY);

+				}

+			})

+		}

+		if (that.$util.isEmpty(that.getLoginInfo)) {

+			wxLoginFn().then(wxRes=>{

+				that.init()

+			})

+		}else{

+			that.init()

+		}

+	}

+

+}

+

+ 16 - 32
mallApp/src/pages/item/detail.vue

@@ -116,42 +116,26 @@ export default {
     init() {
       let that = this
 
-      if(this.option.hdId && Number(this.option.hdId) > 0){
+      if (this.option.hdId && Number(this.option.hdId) > 0) {
         this.hdId = this.option.hdId
       }
 
-			//扫码进来
-			if(this.option.scene){
-				const scene = decodeURIComponent(this.option.scene);
-				var sceneItem = scene.split("&");
-				var arr, name, value;
-				var sceneArray = new Array();
-				for (var i = 0, l = sceneItem.length; i < l; i++) {
-					arr = sceneItem[i].split("=");
-					name = arr[0];
-					value = arr[1];
-					sceneArray[name] = value;
-				}
-        let id = sceneArray.id ? sceneArray.id : 0
-        let account = sceneArray.a ? sceneArray.a : 0
-        this.option.account = account
-        if(Number(id)>0 && Number(account)>0){
-          uni.setStorageSync('account',account)
-          getHdInfo().then(res=>{
-            if(res.code == 1){
-              if(res.data.hd && res.data.hd.id){
-                this.hdId = res.data.hd.id
-              }
-              that.getItemDetail(id,account)
+      const id = this.option.id ? this.option.id : 0
+      const account = this.option.account ? this.option.account : 0
+
+      // 太阳码参数已在 App / globalMixins 中展开为 account、id
+      if (Number(id) > 0 && Number(account) > 0) {
+        uni.setStorageSync('account', account)
+        getHdInfo().then(res => {
+          if (res.code == 1) {
+            if (res.data.hd && res.data.hd.id) {
+              this.hdId = res.data.hd.id
             }
-          })
-        }else{
-          that.$msg('二维码错误')
-        }
-			}else{
-        let id = this.option.id ? this.option.id : 0
-        let account = this.option.account ? this.option.account : 0
-        that.getItemDetail(id,account)
+            that.getItemDetail(id, account)
+          }
+        })
+      } else {
+        that.getItemDetail(id, account)
       }
     },
     getItemDetail(id,account){

+ 5 - 26
mallApp/src/pages/member/recharge.vue

@@ -247,33 +247,12 @@ export default {
 			this.beginInit()
 		},
 		beginInit() {
-			//如果有就获取这二个参数
-			this.account = this.option.account?this.option.account:0
-			this.hdId = this.option.hdId?this.option.hdId:0
-			//这个获取小程序码扫码后的参数
-			if(this.option.scene){
-				const scene = decodeURIComponent(this.option.scene);
-				var sceneItem = scene.split("&");
-				var arr, name, value;
-				var sceneArray = new Array();
-				for (var i = 0, l = sceneItem.length; i < l; i++) {
-					arr = sceneItem[i].split("=");
-					name = arr[0];
-					value = arr[1];
-					sceneArray[name] = value;
-				}
-				if(sceneArray.s){
-					this.account = sceneArray.s
-					//将account保存到storage,下面的getHdInfo需要使用,因为是扫码进来的要加这一层
-					uni.setStorageSync('account', this.account)
-					this.hdId = 0
-				}
-				if(sceneArray.a){
-					//预留参数,后面使用
-					let staffId = sceneArray.a
-				}
+			this.account = this.option.account ? this.option.account : 0
+			this.hdId = this.option.hdId ? this.option.hdId : 0
+			if (this.account) {
+				uni.setStorageSync('account', this.account)
 			}
-			
+
 			getHdInfo({id:this.hdId}).then(res=>{
 				let that = this
 				if(res.code == 1){

+ 159 - 0
mallApp/src/utils/launchScene.js

@@ -0,0 +1,159 @@
+/**
+ * 太阳码 / 扫码进入参数解析(冷启动 onLoad + 热启动 App.onShow 共用)
+ */
+
+/** 微信「扫小程序码 / 长按识别 / 相册选取」等进入场景值 */
+export const SCAN_ENTRY_SCENES = [1011, 1012, 1013, 1047, 1048, 1049]
+
+/**
+ * 解析 scene 字符串为键值对,如 s=123&a=456&id=789
+ */
+export function parseSceneString(sceneRaw) {
+	if (!sceneRaw) {
+		return {}
+	}
+	const scene = decodeURIComponent(String(sceneRaw))
+	const params = {}
+	scene.split('&').forEach((pair) => {
+		if (!pair) {
+			return
+		}
+		const eq = pair.indexOf('=')
+		if (eq === -1) {
+			params[pair] = ''
+			return
+		}
+		const key = pair.slice(0, eq)
+		const val = pair.slice(eq + 1)
+		if (key) {
+			params[key] = val != null ? decodeURI(val) : ''
+		}
+	})
+	return params
+}
+
+/**
+ * 将 scene 内字段展开为页面 query(account / hdId / id 等)
+ */
+export function sceneParamsToQuery(sceneParams, baseQuery) {
+	const q = Object.assign({}, baseQuery || {})
+	if (sceneParams.s) {
+		q.account = sceneParams.s
+	}
+	if (sceneParams.a) {
+		if (!q.account) {
+			q.account = sceneParams.a
+		}
+		q.staffId = sceneParams.a
+	}
+	if (sceneParams.id) {
+		q.id = sceneParams.id
+	}
+	if (sceneParams.hdId) {
+		q.hdId = sceneParams.hdId
+	}
+	delete q.scene
+	return q
+}
+
+/**
+ * 合并 onLoad 的 option:scene 展开 + 普通二维码 q 参数
+ */
+export function applyLaunchQuery(option) {
+	const merged = Object.assign({}, option || {})
+	if (merged.scene) {
+		const sceneParams = parseSceneString(merged.scene)
+		Object.assign(merged, sceneParamsToQuery(sceneParams, merged))
+		delete merged.scene
+	}
+	if (merged.q) {
+		const currentUrl = decodeURIComponent(String(merged.q))
+		const marker = 'account='
+		const idx = currentUrl.lastIndexOf(marker)
+		if (idx >= 0) {
+			let account = currentUrl.substring(idx + marker.length)
+			const amp = account.indexOf('&')
+			if (amp >= 0) {
+				account = account.substring(0, amp)
+			}
+			merged.account = account
+		}
+	}
+	return merged
+}
+
+/**
+ * 拼 reLaunch 地址
+ */
+export function buildLaunchUrl(path, query) {
+	const normalizedPath = path && path.indexOf('/') === 0 ? path : '/' + (path || '')
+	const parts = []
+	const q = query || {}
+	Object.keys(q).forEach((key) => {
+		const val = q[key]
+		if (val !== undefined && val !== null && val !== '') {
+			parts.push(key + '=' + encodeURIComponent(val))
+		}
+	})
+	return parts.length ? normalizedPath + '?' + parts.join('&') : normalizedPath
+}
+
+/**
+ * 写入 account / hdId / currentQuery(与原 globalMixins 一致)
+ */
+export function persistLaunchStorage(option) {
+	if (option.account) {
+		uni.setStorageSync('account', option.account)
+	} else {
+		uni.setStorageSync('account', 0)
+	}
+	if (option.hdId) {
+		uni.setStorageSync('hdId', option.hdId)
+	} else {
+		uni.setStorageSync('hdId', 0)
+	}
+	uni.setStorageSync('currentQuery', JSON.stringify(option))
+}
+
+/**
+ * 热启动:根据 getEnterOptionsSync 判断是否需要 reLaunch 到展开 query 的目标页
+ * @returns {boolean} 是否已触发 reLaunch
+ */
+export function tryReLaunchFromScanEnter(globalData) {
+	if (!uni.getEnterOptionsSync) {
+		return false
+	}
+	const enter = uni.getEnterOptionsSync()
+	if (!enter || !enter.query || !enter.query.scene) {
+		return false
+	}
+
+	const launchKey = (enter.path || '') + '|' + enter.query.scene
+	const sceneCode = Number(enter.scene)
+	const isScanEntry = SCAN_ENTRY_SCENES.indexOf(sceneCode) >= 0
+
+	if (!isScanEntry && globalData.lastLaunchKey === launchKey) {
+		return false
+	}
+
+	const sceneParams = parseSceneString(enter.query.scene)
+	const expandedQuery = sceneParamsToQuery(sceneParams, Object.assign({}, enter.query))
+	const targetUrl = buildLaunchUrl(enter.path, expandedQuery)
+	const targetRoute = (enter.path || '').replace(/^\//, '')
+
+	const pages = getCurrentPages()
+	const current = pages.length ? pages[pages.length - 1] : null
+	if (current) {
+		const curRoute = current.route || ''
+		const curOpts = current.options || {}
+		// 已在目标页且参数已展开(无 scene),无需重复 reLaunch
+		if (curRoute === targetRoute && !curOpts.scene && (curOpts.account || curOpts.id || curOpts.hdId)) {
+			globalData.lastLaunchKey = launchKey
+			return false
+		}
+	}
+
+	globalData.lastLaunchKey = launchKey
+	uni.reLaunch({ url: targetUrl })
+	return true
+}