浏览代码

用户浏览记录

zhengjinyi 2 年之前
父节点
当前提交
fd3f1ea2ee

+ 4 - 4
App.vue

@@ -1,9 +1,9 @@
 <script>
-	
+	// import cmSysMixins from '@/mixins/cmSysMixins.js'
 	import appMixins from '@/mixins/appMixins.js'
 	export default {
 		mixins: [appMixins],
-		onLaunch: function() {
+		onLaunch() {
 			//小程序热更新代码
 			const updateManager = uni.getUpdateManager()
 			updateManager.onCheckForUpdate(function(res) {
@@ -23,10 +23,10 @@
 			this.initSetSystemInfo()
 			this.appUpdataRefresh()
 		},
-		onShow: function() {
+		onShow() {
 			
 		},
-		onHide: function() {
+		onHide() {
 			console.log('App Hide')
 		},
 	}

+ 38 - 0
js_sdk/pocky-route-gurads/lib/hackRoute.js

@@ -0,0 +1,38 @@
+/**
+ * hack uniapp的路由函数b
+ * @param {Function} callback
+ * @return {never}
+ */
+export const hackUniRoute = function (callback) {
+    // 路由跳转的函数key值
+    const UNI_ROUTE_ACTIONS = ['navigateTo', 'redirectTo', 'reLaunch', 'switchTab', 'navigateBack'];
+
+    // 函数缓存容器
+    const cacheFunc = {};
+
+    // 保存原函数引用
+    UNI_ROUTE_ACTIONS.forEach((key) => {
+        cacheFunc[key] = uni[key];
+    });
+
+    // 重写方法
+    UNI_ROUTE_ACTIONS.forEach((key) => {
+        uni[key] = (opts, routeGuardsOpts) => {
+            // 取消拦截并直接运行
+            if (routeGuardsOpts === false) {
+                cacheFunc[key](opts);
+            } else {
+                // 处理所有钩子
+                const defaultOpts = { action: key };
+                const newOpts = Object.assign(defaultOpts, opts);
+                const actionFunc = function (customOpts) {
+                    const lastOpts = Object.assign(newOpts, customOpts);
+
+                    cacheFunc[lastOpts.action](lastOpts);
+                };
+
+                callback.call(this, newOpts, actionFunc);
+            }
+        };
+    });
+};

+ 124 - 0
js_sdk/pocky-route-gurads/lib/handleHooks.js

@@ -0,0 +1,124 @@
+import { isError, getCurStack, print } from './utils';
+
+/**
+ * 处理 全局钩子队列
+ * @param {Object} to
+ * @param {Function} uniRunRoute 被hack的uniapp路由方法
+ */
+export const handleGlobalHooksQueue = function (to, uniRunRoute) {
+    // 跳过 h5环境中, 调用系统的tabbar功能('tabbar')或系统的navbar上的返回功能('backbutton'), 会触发uni的路由方法
+    if (['tabBar', 'backbutton'].includes(to.from)) return uniRunRoute();
+
+    // 获取当前路由栈信息
+    const from = getCurStack();
+
+    // 跳过 app端 首次进入页面会调用uni路由方法, 导致获取当前路由栈(from)为空,所有直接运行,不进行拦截
+    if (from === false) return uniRunRoute();
+
+    iteratorHook(
+        this.beforeHooks,
+        handleNextPipe.bind(this),
+        () => {
+            uniRunRoute();
+            handleAfterHook.call(this, to, from);
+        },
+        {
+            to,
+            from,
+            uniRunRoute
+        }
+    );
+};
+
+/**
+ * 处理 全局后置钩子
+ * @param {Object} to
+ * @param {Object} from
+ */
+const handleAfterHook = function (to, from) {
+    this.afterHooks.forEach((hook) => {
+        hook(to, from);
+    });
+};
+
+/**
+ * 处理 错误信息
+ * @param {Object|string} err 错误信息、错误栈
+ */
+const handleAbort = function (err) {
+    if (this.errorCbs.length > 0) {
+        this.errorCbs.forEach((cb) => {
+            cb(err);
+        });
+    } else {
+        print('error:' + err, 'error');
+    }
+};
+
+/**
+ * 遍历并运行 钩子
+ * @param {Function[]} hookQueue 钩子队列
+ * @param {Function} everyCb 每次遍历都会运行的回调函数
+ * @param {Function} endCb 队列运行结束后运行的回调函数
+ * @param {Object} hookOpts 钩子运行需要的参数
+ */
+const iteratorHook = function (hookQueue, everyCb, endCb, hookOpts) {
+    const step = (i) => {
+        // 队列运行结束,运行回调函数
+        if (i >= hookQueue.length) {
+            endCb.call(this);
+        } else {
+            // 遍历运行钩子
+            everyCb.call(this, hookQueue[i], hookOpts, (val) => {
+                // 结束钩子遍历
+                if (val === false) return;
+
+                step(++i);
+            });
+        }
+    };
+
+    step(0);
+};
+
+/**
+ * 处理 有next参数的钩子(前置钩子)
+ * @param {Function} hookCb 钩子函数
+ * @param {Object} hookOpts 钩子运行需要的参数
+ * @param {Function} iteratorNextHook 运行下一个钩子
+ */
+const handleNextPipe = function (hookCb, hookOpts, iteratorNextHook) {
+    hookCb(hookOpts.to, hookOpts.from, (nextVal) => {
+        try {
+            // next(false) or next(new Error('xxx')) 中断当前的路径跳转,或中断且注册错误回调
+            if (nextVal === false || isError(nextVal)) {
+                handleAbort.call(this, nextVal);
+            }
+
+            // next('/pages/a') or next({ url: '/pages/a' }) 修改 路由
+            else if (
+                typeof nextVal === 'string' ||
+                (typeof nextVal === 'object' && typeof nextVal.url === 'string')
+            ) {
+                // 处理字符串路径
+                typeof nextVal === 'string' && (nextVal = { url: nextVal });
+
+                hookOpts.uniRunRoute(nextVal);
+                handleAfterHook.call(this, hookOpts.to, hookOpts.from);
+
+                // 更新引用,替换原来的`url`字段数据
+                hookOpts.to = Object.assign(hookOpts.to, nextVal);
+
+                // 结束钩子遍历
+                iteratorNextHook(false);
+            }
+
+            // next() 运行下一个管道(next)
+            else {
+                iteratorNextHook();
+            }
+        } catch (err) {
+            handleAbort.call(this, err);
+        }
+    });
+};

+ 41 - 0
js_sdk/pocky-route-gurads/lib/index.js

@@ -0,0 +1,41 @@
+import { install } from './install';
+import { hackUniRoute } from './hackRoute';
+import { handleGlobalHooksQueue } from './handleHooks';
+import { registerHook } from './utils';
+
+export default class uniRouteGuards {
+    constructor() {
+        // 初始化数据
+        this.beforeHooks = [];
+        this.afterHooks = [];
+        this.errorCbs = [];
+        hackUniRoute.call(this, handleGlobalHooksQueue);
+    }
+
+    /**
+     * 注册 全局前置守卫
+     * @param {Function} callback 回调函数
+     */
+    beforeEach(callback) {
+        return registerHook(this.beforeHooks, callback);
+    }
+
+    /**
+     * 注册 全局后置守卫
+     * @param {Function} callback 回调函数
+     */
+    afterEach(callback) {
+        return registerHook(this.afterHooks, callback);
+    }
+
+    /**
+     * 注册 错误回调
+     * @param {Function} errCb 错误回调函数
+     */
+    onError(errCb) {
+        return registerHook(this.errorCbs, errCb);
+    }
+}
+
+// 添加 Vue.use 功能
+uniRouteGuards.install = install;

+ 6 - 0
js_sdk/pocky-route-gurads/lib/install.js

@@ -0,0 +1,6 @@
+/**
+ * Vue.use 插件安装
+ * @param {Object} Vue
+ * @param {*} opts
+ */
+export function install(Vue, opts = {}) {}

+ 53 - 0
js_sdk/pocky-route-gurads/lib/utils.js

@@ -0,0 +1,53 @@
+/**
+ * 控制台打印内容
+ * @param {string} msg 内容
+ * @param {string} action ['log'] 打印类型
+ * @param {never}
+ */
+export const print = function (msg, action = 'log') {
+    console[action]('[route-guards] ' + msg);
+};
+
+/**
+ * 判断错误对象是否是由`Error`对象实例化出来的
+ * @param {Error|Object} errObj
+ * @return {boolean}
+ */
+export const isError = function (errObj) {
+    return Object.prototype.toString.call(errObj).includes('Error');
+};
+
+/**
+ * 获取并封装当前路由栈的信息
+ * @return {Object}
+ */
+export const getCurStack = function () {
+    const stackAll = getCurrentPages();
+    const stackLen = stackAll.length;
+
+    // 跳过路由栈为空的情况(App端)
+    if (stackLen === 0) {
+        return false;
+    }
+
+    const curStack = stackAll[stackLen - 1];
+    const from = { url: '/' + curStack.route };
+
+    return from;
+};
+
+/**
+ * 注册 钩子
+ * @param {Function[]} list 钩子列表
+ * @param {Function} callback 回调函数
+ * @returns {Function} 用于注销当前注册钩子的闭包函数
+ */
+export const registerHook = function (list, callback) {
+    list.push(callback);
+
+    return () => {
+        const index = list.indexOf(callback);
+
+        if (index !== -1) list.splice(index, 1);
+    };
+};

+ 5 - 0
main.js

@@ -4,6 +4,9 @@ import App from './App'
 import './services/index.js'
 import * as Api from '@/common/config/caimeiApi.js'
 import * as Regs from '@/common/config/common.js'
+import cmSysMixins from '@/mixins/cmSysMixins.js'
+import './utils/router.js'
+
 // 友盟
 import Uma from './plugins/uma'
 
@@ -15,6 +18,7 @@ import cmCustom from './components/cm-custom/cm-custom.vue'
 import scrollTop from '@/components/cm-module/scrollTop/scrollTop.vue'
 import CityPicker from '@/components/mpvue-citypicker/mpvueCityPicker.vue' //全局注册地址组件
 
+
 Vue.component('cu-custom', cuCustom)
 Vue.component('au-custom', auCustom)
 Vue.component('cm-custom', cmCustom)
@@ -44,6 +48,7 @@ App.mpType = 'app'
 // 使用插件
 Vue.use(Uma)
 
+
 const app = new Vue({
     ...App
 })

+ 72 - 34
mixins/cmSysMixins.js

@@ -1,48 +1,86 @@
 // 统计数据
-// 统计类型 1:首页banner;2:直播模块;3:最新活动;4:热门文章;5:新品橱窗;6:活动列表
 import Vue from 'vue'
-const cmSysVitaMixins = {
+const defaultParams = {
+    pagePath: '', //页面路径
+    accessDuration: 0, //浏览时长初始值为 0
+    pageType: '', //页面类型
+    pageLabel: '', //页面标签
+    userId: 0, //用户Id
+    productId: 0 //商品Id
+}
+const cmSysMixins = {
     data() {
-	    return {
-            rowseTime: 0,  // 浏览时长初始值为 0
+        return {
+            cmSysParams:Object.assign({}, defaultParams),
             clearTimeSet: null,
-	    }
+            enterTime:null,
+            outTime:null
+        }
     },
-    mounted(){
-        this.setTime() // 页面加载完成后开始计时
+    onLoad() {
+        let that = this
+        // this.cmSysVitaSetTime() // 页面加载完成后开始计时
+        // uni.addInterceptor('navigateTo', { //监听跳转
+        //     success(e) {
+        //         console.log('navigateTo============')
+        //         that.cmSysVitaMixins()
+        //     }
+        // })
+        // uni.addInterceptor('redirectTo', { //监听关闭本页面跳转
+        //     success(e) {
+        //         console.log('redirectTo============')
+        //         that.cmSysVitaMixins()
+        //     }
+        // })
+        // uni.addInterceptor('switchTab', { //监听tabBar跳转
+        //     success(e) {
+        //         console.log('switchTab============')
+        //         that.cmSysVitaMixins()
+        //     }
+        // })
+        // uni.addInterceptor('navigateBack', { //监听tabBar跳转
+        //     success(e) {
+        //         console.log('navigateBack============')
+        //         that.cmSysVitaMixins()
+        //     }
+        // })
     },
     methods: {
-        setTime() {
+        async cmSysVitaSetTime() {
             //设置定时器
+            const userInfo = await this.$api.getStorage()
+            const pages = getCurrentPages()
+            const currentPage = pages[pages.length - 1]
+            this.cmSysParams.pagePath = `/${currentPage.route}`
+            this.cmSysParams.userId = userInfo ? userInfo.userId : 0
             this.clearTimeSet = setInterval(() => {
-                this.browseTime++
-                console.log(this.browseTime, '时长累计')
+                this.cmSysParams.accessDuration++
             }, 1000)
         },
-        cmSysVitaMixins(cmsSysType,productId) {
-            this.ProductService.sYsStatisticsTypesSatisticsNumber({typeId:cmsSysType,productId:productId})
-                .then(response => {
-                    const map = {
-					    1: '首页轮播',
-					    2: '直播模块',
-					    3: '最新活动',
-					    4: '热门文章',
-					    5: '新品橱窗',
-					    6: '活动列表'
-                    }
-                    const sYsText = map[cmsSysType]
-                    console.log(`<-------${sYsText}统计数据成功------>`)
-                })
-                .catch(error => {
-                    console.log('<-------上送用户行为记录异常------>')
-                })
+        cmSysVitaMixins() { // 上送后台接口,将浏览时长等信息传到后台,离开当前路由后调用
+            console.log(`页面路径:${this.cmSysParams.pagePath}`, `停留:${this.cmSysParams.accessDuration}s`,
+                `标签:${this.cmSysParams.pageLabel}`)
+            console.log('上送用户参数', this.cmSysParams)
+            // this.userRecordStatistics(this.cmSysParams)
+            this.cmSysParams = Object.assign({}, defaultParams)
+            clearInterval(this.clearTimeSet) // 离开页面后清除定时器
         },
-    },
-    onUnload() {
-        debugger
-        clearInterval(this.clearTimeSet) // 离开页面后清除定时器
-        this.cmSysVitaMixins() // 上送后台接口,将浏览时长等信息传到后台,离开当前路由后调用
-    },
+        userRecordStatistics(cmSysParams){// 上送用户行为记录接口
+            this.UserService.userRecordStatistics(cmSysParams)
+			    .then(response => {
+			        console.log('<-------上送用户行为记录成功------>')
+			    })
+			    .catch(error => {
+			        console.log('<-------上送用户行为记录异常------>')
+			    })
+        },
+    //     onHide(){
+			 // this.cmSysVitaMixins()
+    //     },
+    //     onUnload(){
+    //         this.cmSysVitaMixins()
+    //     }
+    }
 }
 
-export default cmSysVitaMixins
+export default cmSysMixins

+ 6 - 2
pages/goods/good-hot.vue

@@ -257,8 +257,9 @@
 import { mapState, mapMutations } from 'vuex'
 import uniGrader from '@/components/uni-grade/uni-grade.vue'
 import cmsMixins from '@/mixins/cmsMixins.js'
+import cmSysMixins from '@/mixins/cmSysMixins.js'
 export default{
-	mixins: [cmsMixins],
+	mixins: [cmsMixins,cmSysMixins],
 	components: {
 		uniGrader
 	},
@@ -478,7 +479,10 @@ export default{
 			this.OnReachBottomData()
 		}
 	},
-	onShow() {}
+	onShow() {
+		this.cmSysParams.pageType = '新品橱窗'
+		this.cmSysParams.pageLabel = '新品'
+	}
 }
 </script>
 

+ 10 - 2
pages/goods/product.vue

@@ -685,10 +685,11 @@ import authorize from '@/common/config/authorize.js'
 import wxLogin from '@/common/config/wxLogin.js'
 import { debounce } from '@/common/config/common.js'
 import payMixins from '@/mixins/payMixins.js'
+import cmSysMixins from '@/mixins/cmSysMixins.js'
 import thorui from '@/components/clipboard/clipboard.thorui.js'
 var isPreviewImg
 export default {
-	mixins: [payMixins],
+	mixins: [payMixins, cmSysMixins],
 	components: {
 		customP,
 		parser,
@@ -848,7 +849,9 @@ export default {
 	},
 	onLoad(option) {
 		this.productId = this.couponParam.productId = option.id //获取商品ID
-		this.typeId = option.typeId
+		if (option.typeId) {
+			this.typeId = option.typeId
+		}
 		this.opentype = option.open
 		this.isShareType = option.type
 		this.linkPath = option.path
@@ -856,6 +859,8 @@ export default {
 		if (option.page == 2) {
 			this.backPage = option.page
 		}
+		this.cmSysParams.pageType = '新商品详情'
+		this.cmSysParams.productId = this.productId
 		this.getWinHeight()
 	},
 	onReady() {
@@ -906,6 +911,9 @@ export default {
 					this.shop = response.data.shop
 					this.shopId = response.data.shopId
 					this.product = response.data
+					this.cmSysParams.pageLabel = `${this.product.smallTypeName ? this.product.smallTypeName : ''}${
+						this.product.brandName ? this.product.brandName : ''
+					}` //设置统计数据标签
 					if (this.product.shopType === 2) {
 						this.isShowCaimeiShop = true
 					}

+ 7 - 3
pages/search/search-supplier.vue

@@ -72,19 +72,20 @@
 </template>
 
 <script>
+	import wxLogin from '@/common/config/wxLogin.js'
+	import { mapState } from 'vuex'
 	import tuiLoadmore from '@/components/tui-components/loadmore/loadmore'
 	import tuiNomore from '@/components/tui-components/nomore/nomore'
 	import uniStars from '@/components/uni-stars/uni-stars.vue'
 	import authorize from '@/common/config/authorize.js'	
-	import wxLogin from '@/common/config/wxLogin.js'
-	import { mapState } from 'vuex'
-	
+	import cmSysMixins from '@/mixins/cmSysMixins.js'
 	export default {
 		components:{
 			tuiLoadmore,
 			tuiNomore,
 			uniStars
 		},
+		mixins: [cmSysMixins],
 		data() {
 			return {
 				iconClass:'icon-aixin',
@@ -126,6 +127,8 @@
 					this.listQuery.keyword = option.keyWord
 					this.GetSearchSupplierList()
 				}
+				this.cmSysParams.pageType = '供应商搜索'
+				
 			},	
 			searchsupplierList(){//搜索
 				this.listQuery.pageNum=1
@@ -190,6 +193,7 @@
 				}else{					
 					this.isShowClose = false
 					this.listQuery.pageNum=1
+					this.cmSysParams.pageLabel = this.listQuery.keyword
 					this.GetSearchSupplierList()
 				}
 			},

+ 4 - 1
pages/search/search.vue

@@ -449,12 +449,13 @@ import modalLayer from '@/components/modal-layer'
 import uniGrader from '@/components/uni-grade/uni-grade.vue'
 import authorize from '@/common/config/authorize.js'
 import wxLogin from '@/common/config/wxLogin.js'
-
+import cmSysMixins from '@/mixins/cmSysMixins.js'
 export default {
 	components: {
 		modalLayer,
 		uniGrader
 	},
+	mixins: [cmSysMixins],
 	data() {
 		return {
 			CustomBar: this.CustomBar, // 顶部导航栏高度
@@ -560,6 +561,7 @@ export default {
 				this.isFocus = true
 				this.initGetSerachRecord()
 			}
+			this.cmSysParams.pageType = '商品搜索'
 		},
 		GetHomeHotSearchTerms() {
 			//金刚区分类
@@ -612,6 +614,7 @@ export default {
 					case 1:
 						this.listData = []
 						this.brandParam.keyword = this.listQuery.keyword
+						this.cmSysParams.pageLabel = this.listQuery.keyword
 						this.setSearchHistoryAdd()
 						this.getCommoditySearchQUeryBrand()
 						this.getListFromServer()

+ 5 - 2
pages/second/form/form.vue

@@ -284,13 +284,14 @@
 </template>
 
 <script>
+	import { mapState,mapMutations } from 'vuex'
 	import mpvueCityPicker from '@/components/mpvue-citypicker/mpvueCityPicker.vue'
 	import { uploadFileImage , uploadFilePdf } from '@/services/public.js'
 	import authorize from '@/common/config/authorize.js'
 	import $reg from '@/common/config/common.js'
-	import { mapState,mapMutations } from 'vuex'
+	import cmSysMixins from '@/mixins/cmSysMixins.js'
 	export default{
-		name:'secondHandrelease',
+		mixins: [cmSysMixins],
 		components:{
 			mpvueCityPicker,
 		},
@@ -582,6 +583,8 @@
 		},
 		onShow() {
 			this.getBrandList()
+			this.cmSysParams.pageType = '发布二手'
+			this.cmSysParams.pageLabel = '发布二手'
 			this.$api.getComStorage('userInfo').then((resolve) =>{
 				this.userIdentity = resolve.userIdentity
 				console.log(this.userIdentity)

+ 17 - 12
pages/second/product/product-details.vue

@@ -117,7 +117,7 @@
 						<!-- 相关推荐 -->
 						<view class="title"><view class="title-tab">相关推荐</view></view>
 						<view class="content hot">
-							<recommend :query-productid="product.productId" v-if="isRequest" ></recommend>
+							<recommend :query-productId="product.productId" v-if="isRequest" ></recommend>
 						</view>
 					</view>
 					<!-- 商品参数 -->
@@ -150,8 +150,10 @@
 	import cmParameter from './components/secondParameters.vue' //相关参数
 	import wxLogin from '@/common/config/wxLogin.js'
 	import { debounce } from '@/common/config/common.js'
+	import cmSysMixins from '@/mixins/cmSysMixins.js'
 	var isPreviewImg
 	export default{
+		mixins: [cmSysMixins],
 		components:{
 			uniStars,
 			customP,
@@ -184,7 +186,7 @@
 				isNoneDisabled:false,
 				tabCurrentIndex:0,
 				userId:'',
-				productID:0,
+				productId:0,
 				userIdentity:'',//用户类型
 				goodsData:{},//自定义数据
 				shop:{},//供应商信息
@@ -214,24 +216,27 @@
 			...mapState(['hasLogin','userInfo','isWxAuthorize'])
 		},
 		onLoad(option) {
-			this.productID = option.id//获取商品ID
-			this.isShareType = option.type
-			this.linkPath = option.path
-			this.isHeaderPoduct = true
-			if(option.page == 2){
-				this.backPage = option.page
-			}
 			if(this.isShareType =='share'){
 				wxLogin.wxLoginAuthorize()
 			}
+			if(option.page == 2){
+				this.backPage = option.page
+			}
+			this.productId = option.id//获取商品ID
+			this.isShareType = option.type
+			this.linkPath = option.path
+			this.isHeaderPoduct = true
+			this.cmSysParams.pageType = '二手商品详情';
+			this.cmSysParams.productId = this.productId
 		},
 		methods:{
 			initData(){// 初始化商品详情查询
-				this.SecondService.ProductDetail({productId:this.productID,userId:this.userId}).then(response =>{
+				this.SecondService.ProductDetail({productId:this.productId,userId:this.userId}).then(response =>{
 					this.skeletonShow = false
 					this.productImage=[]
 					this.shop = response.data.shop
 					this.product = response.data
+					this.cmSysParams.pageLabel = `${response.data.brandName}`;	
 					//处理商品图片列表
 					this.product.imageList.forEach(item =>{
 						this.productImage.push(item)
@@ -304,7 +309,7 @@
 			    }
 				return {
 				  title: `${this.product.name}`,
-				  path: `second/pages/product/product-details?type=share&id=${this.productID}`,
+				  path: `second/pages/product/product-details?type=share&id=${this.productId}`,
 				  imageUrl:`${this.product.imageList[0]}`
 				}
 			},
@@ -411,7 +416,7 @@
 		    }
 			return {
 			  title: `${this.product.name}`,
-			  path: `second/pages/product/product-details?type=share&id=${this.productID}`,
+			  path: `second/pages/product/product-details?type=share&id=${this.productId}`,
 			  imageUrl:`${this.product.imageList[0]}`
 			}
 		},

+ 5 - 3
pages/second/product/product-list.vue

@@ -104,12 +104,13 @@
 </template>
 
 <script>
+	import { mapState,mapMutations } from 'vuex'
 	import authorize from '@/common/config/authorize.js'
 	import wxLogin from '@/common/config/wxLogin.js'
 	import modalLayer from '@/components/modal-layer'
-	import { mapState,mapMutations } from 'vuex'
+	import cmSysMixins from '@/mixins/cmSysMixins.js'
 	export default{
-		name:'secondList',
+		mixins: [cmSysMixins],
 		components:{
 			modalLayer
 		},
@@ -300,7 +301,8 @@
 			}
 		},	
 		onShow() {
-				
+			this.cmSysParams.pageType = '二手市场'
+			this.cmSysParams.pageLabel = '二手市场'
 		}
 	}
 </script>

+ 0 - 1
pages/supplier/user/my-shop.vue

@@ -538,7 +538,6 @@ export default {
 			this.ShopService.GetSupplierHomeProduct({ shopId: this.supplierId, identity: this.identity })
 				.then(response => {
 					let data = response.data
-					console.log('主推商品', data)
 					if (data.length > 0) {
 						this.isHomeProduct = false
 						this.QueryProductPrice(data)

+ 16 - 0
services/user.service.js

@@ -822,5 +822,21 @@ export default class UserService {
 	        isLoading: false,
 	    })
     }
+    /**
+	 *@上送用户浏览行为
+	 *@param userId:  登录用户userId 默认 :0
+	 *@param pagePath:页面路径
+	 *@param pageType:页面类型
+	 *@param pageLabel:页面标签
+	 *@param productId:商品Id
+	 *@param accessDuration:浏览时长
+	 */
+    userRecordStatistics(data = {}) {
+	    return this.AjaxService.get({
+	        url: '/user/record/Statistics',
+	        data,
+	        isLoading: false,
+	    })
+    }
 	
 }

+ 12 - 0
utils/router.config.js

@@ -0,0 +1,12 @@
+// 配置需要统计的路径
+export const includeList = [
+    { url:'/pages/goods/product', pageType:'新商品详情' },
+    { url:'/pages/goods/good-hot', pageType:'新品橱窗' },
+    { url:'/pages/second/form/form', pageType:'发布二手' },
+    { url:'/pages/second/product/product-list', pageType:'二手市场' },
+    { url:'/pages/second/product/product-details', pageType:'二手商品详情' },
+    { url:'/pages/search/search', pageType:'商品搜索' },
+    { url:'/pages/search/search-supplier', pageType:'供应商搜索' },
+    { url:'/pages/goods/goods-classify', pageType:'分类列表' },
+]
+

+ 114 - 0
utils/router.js

@@ -0,0 +1,114 @@
+import Vue from 'vue'
+import UniRouteGuards from '../js_sdk/pocky-route-gurads/lib/index.js' //  路由导航守卫
+import { includeList } from './router.config.js' // 配置信息
+import ajaxService from '@/services/ajax.service.js'
+import UserService from '@/services/user.service'
+const UserApi = new UserService(ajaxService)
+// 路由导航守卫
+Vue.use(UniRouteGuards)
+
+const map = new Map()
+
+const bucketStack = []
+
+const guard = new UniRouteGuards()
+// 截取路径参数
+const getUrlParams = (appPath) => {
+    const queryArr = appPath.split('?')
+    const queryStr = queryArr[1]
+    let query = queryStr.split('&')
+    let params = {}
+    for (let i = 0; i < query.length; i++) {
+        let q = query[i].split('=')
+        console.log(q, 'q')
+        if (q.length === 2) {
+            params[q[0]] = q[1]
+        }
+    }
+    return params
+}
+// 校验是否为配置的路径
+const isInclude = (url) => {
+    if (!url) return false
+    return includeList.some(item => url.indexOf(item.url) > -1)
+}
+
+// 参数
+const userSync = uni.getStorageSync('userInfo')
+const defaultParams = {
+    pagePath: '', //页面路径
+    accessDuration: 0, //浏览时长初始值为 0
+    pageType: '', //页面类型
+    pageLabel: '', //页面标签
+    userId: userSync ? userSync.userId : 0, //用户Id
+    productId: 0 //商品Id
+}
+// 上送接口Api
+const userRecordStatistics = (params) => {
+    UserApi.userRecordStatistics(params)
+        .then(response => {
+            console.log('<=上送用户行为记录成功=>',response.msg)
+        })
+        .catch(error => {
+            console.log('<=上送用户行为记录异常=>',error.msg)
+            return
+        })
+}
+
+// 跳过路由白名单拦截
+guard.beforeEach((to, from, next) => {
+    console.log('\n')
+    console.log('============')
+    console.log('guard.beforeEach')
+    console.log('to:', to)
+    console.log('from:', from)
+    console.log('页面拦截状态:', isInclude(to.url))
+    // if (to.action !== 'navigateBack') {
+    //     bucketStack.push(to.url)
+    //     console.log('入栈:', to.url)
+    // }
+	
+    if (isInclude(to.url)) {
+        console.log('stay time started')
+        map.set(to.url.split('?')[0], Date.now())
+        defaultParams.pagePath = to.url
+        console.log('pagePath', defaultParams.pagePath)
+        const urlParams = getUrlParams(to.url)
+        if(urlParams){
+            defaultParams.productId = urlParams ? urlParams.id : 0
+            console.log('defaultParams', defaultParams)
+        }
+    }
+    // map.set(to.url.split('?')[0], Date.now())
+    console.log('============')
+    console.log('\n')
+    next()
+})
+
+guard.afterEach((to, from) => {
+    console.log('\n')
+    console.log('============')
+    console.log('guard.afterEach')
+    console.log('to:', to)
+    console.log('from:', from)
+    // if (to.action === 'navigateBack') {
+    //     const lastUrl = bucketStack.pop()
+    //     map.set(lastUrl.split('?')[0], Date.now())
+    //     const current = bucketStack[bucketStack.length - 1]
+    //     if(current){
+    //         map.set(current.split('?')[0], Date.now())
+    //     }
+    //     console.log('未关闭页面栈列表:', bucketStack)
+    // }
+
+    if (map.has(from.url)) {
+        const beginTime = map.get(from.url)
+        defaultParams.accessDuration = Date.now() - beginTime
+        console.log('页面停留时间:', (Date.now() - beginTime), '秒')
+        // api
+        console.log('api is action ...')
+        userRecordStatistics(defaultParams)
+    }
+    console.log('============')
+    console.log('\n')
+})