Feat(页面):监听页面打开次数和页面停留时长逻辑初步实现
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
export const pageToWatchData = {
|
||||||
|
'home_index': {
|
||||||
|
count: 0,
|
||||||
|
timer: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
} from "@/config";
|
} from "@/config";
|
||||||
import uView from "uview-ui";
|
import uView from "uview-ui";
|
||||||
import GooSkeleton from '@/components/GooSkeleton/index.vue'
|
import GooSkeleton from '@/components/GooSkeleton/index.vue'
|
||||||
|
import { pageToWatchData } from '@/config/page'
|
||||||
|
|
||||||
Vue.use(uView)
|
Vue.use(uView)
|
||||||
Vue.component('GooSkeleton', GooSkeleton)
|
Vue.component('GooSkeleton', GooSkeleton)
|
||||||
@@ -32,7 +33,8 @@ Vue.prototype.$VUE_APP_RESOURCES_URL = VUE_APP_RESOURCES_URL
|
|||||||
Vue.prototype.$STATIC_RESOURCE_URL = STATIC_RESOURCE_URL
|
Vue.prototype.$STATIC_RESOURCE_URL = STATIC_RESOURCE_URL
|
||||||
Vue.prototype.$VUE_APP_API_URL = VUE_APP_API_URL
|
Vue.prototype.$VUE_APP_API_URL = VUE_APP_API_URL
|
||||||
Vue.prototype.$WX_LIVE_APPID = WX_LIVE_APPID
|
Vue.prototype.$WX_LIVE_APPID = WX_LIVE_APPID
|
||||||
Vue.prototype.$global = global;
|
Vue.prototype.$global = global
|
||||||
|
Vue.prototype.$pageToWatchData = pageToWatchData
|
||||||
|
|
||||||
Vue.prototype.$validator = function (rule) {
|
Vue.prototype.$validator = function (rule) {
|
||||||
return new schema(rule);
|
return new schema(rule);
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import {
|
||||||
|
pageToWatchShowCount,
|
||||||
|
pageToWatchShowTimer
|
||||||
|
} from '@/utils/util'
|
||||||
|
export const pageListenMixins = {
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
pageTimer: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onShow() {
|
||||||
|
this.pageToWatchShowCount(this.pageKeyId, this.pageShowTimerFn())
|
||||||
|
},
|
||||||
|
onHide() {
|
||||||
|
this.clearPageTimerFn()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
pageToWatchShowCount,
|
||||||
|
pageToWatchShowTimer,
|
||||||
|
pageShowTimerFn() {
|
||||||
|
this.pageTimer = setInterval(() => {
|
||||||
|
console.log('----页面监听----%s', this.pageKeyId)
|
||||||
|
this.pageToWatchShowTimer(this.pageKeyId)
|
||||||
|
}, 1000)
|
||||||
|
},
|
||||||
|
clearPageTimerFn() {
|
||||||
|
if (this.pageTimer) {
|
||||||
|
console.log('清除页面监听-----%s', this.pageKeyId)
|
||||||
|
clearInterval(this.pageTimer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -250,6 +250,8 @@ import {getProducts} from "@/api/store";
|
|||||||
import {sharpBannar} from "@/api/goods";
|
import {sharpBannar} from "@/api/goods";
|
||||||
import NP from "number-precision";
|
import NP from "number-precision";
|
||||||
|
|
||||||
|
import { pageListenMixins } from '@/mixins/pageListenMixins'
|
||||||
|
|
||||||
var that;
|
var that;
|
||||||
export default {
|
export default {
|
||||||
name: 'Index',
|
name: 'Index',
|
||||||
@@ -260,8 +262,7 @@ export default {
|
|||||||
CountDown,
|
CountDown,
|
||||||
hxNavbar
|
hxNavbar
|
||||||
},
|
},
|
||||||
computed: mapGetters(["userInfo", 'isLogin']),
|
mixins: [pageListenMixins],
|
||||||
props: {},
|
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
currentIndex: 0,
|
currentIndex: 0,
|
||||||
@@ -378,9 +379,11 @@ export default {
|
|||||||
contentHomestay: {},
|
contentHomestay: {},
|
||||||
contentFestival: {},
|
contentFestival: {},
|
||||||
countyFamous: {},
|
countyFamous: {},
|
||||||
seasonalFood: {}
|
seasonalFood: {},
|
||||||
};
|
pageKeyId: Object.freeze('home_index')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
computed: mapGetters(["userInfo", 'isLogin']),
|
||||||
onLoad: function (options) {
|
onLoad: function (options) {
|
||||||
that = this;
|
that = this;
|
||||||
this.init();
|
this.init();
|
||||||
|
|||||||
+81
-72
@@ -1,8 +1,87 @@
|
|||||||
|
<template>
|
||||||
|
<view class="pkg-product-land-mark" v-if="mapData">
|
||||||
|
<view class="top-box" :style="{'backgroundColor':topBoxBgColor}">
|
||||||
|
<view class="view-box">
|
||||||
|
<view class="search-box flex ai-center">
|
||||||
|
<input
|
||||||
|
v-model="keyword"
|
||||||
|
type="text"
|
||||||
|
placeholder="搜索商品"
|
||||||
|
placeholder-style="color:#999"
|
||||||
|
@confirm="search()"
|
||||||
|
/>
|
||||||
|
<image
|
||||||
|
:src="webUrl+'/20231223183627184005.png'"
|
||||||
|
mode="scaleToFill"
|
||||||
|
style="width:30rpx;height:30rpx"
|
||||||
|
@click="search()"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="map-box">
|
||||||
|
<image class="img-map" :src="mapData.mapImage" mode="widthFix"/>
|
||||||
|
|
||||||
|
<view
|
||||||
|
v-for="(item, index) in mapLocations"
|
||||||
|
:key="index"
|
||||||
|
class="item"
|
||||||
|
:style="{'left':item.gx+'rpx','top':item.gy+'rpx'}"
|
||||||
|
@click="$global.navToGoods(item.productId)"
|
||||||
|
>
|
||||||
|
<view class="round">
|
||||||
|
<view class="line" :class="'line-'+directionClass[item.labelDirection]"></view>
|
||||||
|
</view>
|
||||||
|
<view class="label flex ai-end" :class="'label-'+directionClass[item.labelDirection]">
|
||||||
|
<image class="cover flex-0" :src="item.mapImage" mode="scaleToFill" v-if="item.labelDirection===4"/>
|
||||||
|
<view class="title flex ai-center">{{ item.mapTitle }}</view>
|
||||||
|
<image class="cover flex-0" :src="item.mapImage" mode="scaleToFill" v-if="item.labelDirection!==4"/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="nav flex">
|
||||||
|
<view class="flex flex-0 ai-center" :class="{'active': navIndex===index}" v-for="(item,index) in navList"
|
||||||
|
:key="index" @click="changeNav(index)">{{ item.provinceName }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="main-box" v-if="mapData.recommended.storeImage"
|
||||||
|
@click="$global.navToGoods(mapData.recommended.productId)">
|
||||||
|
<image class="bg-main" :src="mapData.recommended.storeImage" mode="scaleToFill"/>
|
||||||
|
<view class="box-mask flex flex-col jc-end">
|
||||||
|
<view class="one-t bold">{{ mapData.recommended.title }}</view>
|
||||||
|
<view class="more-t">{{ mapData.recommended.description }}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="list-box flex flex-wrap">
|
||||||
|
<view class="item" v-for="item in goods" :key="item.id" @click="$global.navToGoods(item.productId)">
|
||||||
|
<image :src="item.storeImage" mode="scaleToFill"/>
|
||||||
|
<view class="content flex flex-col jc-between">
|
||||||
|
<view class="more-t bold">{{ item.title }}</view>
|
||||||
|
<view class="flex jc-between ai-center">
|
||||||
|
<text class="price">¥{{ item.price }}</text>
|
||||||
|
<image class="btn" :src="webUrl+'/20231114151028082368.png'" mode="scaleToFill"/>
|
||||||
|
<!-- <view class="btn flex jc-center ai-center">立即购买</view>-->
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<image class="img-nodata" :src="webUrl+'/20231023131208675588.png'" mode="scaleToFill"
|
||||||
|
v-if="goods.length===0"/>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {getProvince, getProvinceGoods, getProvinceList} from "@/api/product";
|
import {getProvince, getProvinceGoods, getProvinceList} from "@/api/product";
|
||||||
|
import { pageListenMixins } from '@/mixins/pageListenMixins'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "landMark",
|
name: 'LandMarkPage',
|
||||||
|
mixins: [pageListenMixins],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
webUrl: this.$VUE_APP_RESOURCES_URL,
|
webUrl: this.$VUE_APP_RESOURCES_URL,
|
||||||
@@ -14,6 +93,7 @@ export default {
|
|||||||
mapLocations: [],
|
mapLocations: [],
|
||||||
goods: [],
|
goods: [],
|
||||||
directionClass: ['', 'up', 'right', 'down', 'left'],
|
directionClass: ['', 'up', 'right', 'down', 'left'],
|
||||||
|
pageKeyId: Object.freeze('land_index')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -84,77 +164,6 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
|
||||||
<view class="pkg-product-land-mark" v-if="mapData">
|
|
||||||
<view class="top-box" :style="{'backgroundColor':topBoxBgColor}">
|
|
||||||
<view class="view-box">
|
|
||||||
<view class="search-box flex ai-center">
|
|
||||||
<input
|
|
||||||
v-model="keyword"
|
|
||||||
type="text"
|
|
||||||
placeholder="搜索商品"
|
|
||||||
placeholder-style="color:#999"
|
|
||||||
@confirm="search()"
|
|
||||||
/>
|
|
||||||
<image
|
|
||||||
:src="webUrl+'/20231223183627184005.png'"
|
|
||||||
mode="scaleToFill"
|
|
||||||
style="width:30rpx;height:30rpx"
|
|
||||||
@click="search()"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="map-box">
|
|
||||||
<image class="img-map" :src="mapData.mapImage" mode="widthFix"/>
|
|
||||||
|
|
||||||
<view class="item" :style="{'left':item.gx+'rpx','top':item.gy+'rpx'}" v-for="item in mapLocations" @click="$global.navToGoods(item.productId)">
|
|
||||||
<view class="round">
|
|
||||||
<view class="line" :class="'line-'+directionClass[item.labelDirection]"></view>
|
|
||||||
</view>
|
|
||||||
<view class="label flex ai-end" :class="'label-'+directionClass[item.labelDirection]">
|
|
||||||
<image class="cover flex-0" :src="item.mapImage" mode="scaleToFill" v-if="item.labelDirection===4"/>
|
|
||||||
<view class="title flex ai-center">{{ item.mapTitle }}</view>
|
|
||||||
<image class="cover flex-0" :src="item.mapImage" mode="scaleToFill" v-if="item.labelDirection!==4"/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="nav flex">
|
|
||||||
<view class="flex flex-0 ai-center" :class="{'active': navIndex===index}" v-for="(item,index) in navList"
|
|
||||||
:key="index" @click="changeNav(index)">{{ item.provinceName }}
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="main-box" v-if="mapData.recommended.storeImage"
|
|
||||||
@click="$global.navToGoods(mapData.recommended.productId)">
|
|
||||||
<image class="bg-main" :src="mapData.recommended.storeImage" mode="scaleToFill"/>
|
|
||||||
<view class="box-mask flex flex-col jc-end">
|
|
||||||
<view class="one-t bold">{{ mapData.recommended.title }}</view>
|
|
||||||
<view class="more-t">{{ mapData.recommended.description }}</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="list-box flex flex-wrap">
|
|
||||||
<view class="item" v-for="item in goods" :key="item.id" @click="$global.navToGoods(item.productId)">
|
|
||||||
<image :src="item.storeImage" mode="scaleToFill"/>
|
|
||||||
<view class="content flex flex-col jc-between">
|
|
||||||
<view class="more-t bold">{{ item.title }}</view>
|
|
||||||
<view class="flex jc-between ai-center">
|
|
||||||
<text class="price">¥{{ item.price }}</text>
|
|
||||||
<image class="btn" :src="webUrl+'/20231114151028082368.png'" mode="scaleToFill"/>
|
|
||||||
<!-- <view class="btn flex jc-center ai-center">立即购买</view>-->
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<image class="img-nodata" :src="webUrl+'/20231023131208675588.png'" mode="scaleToFill"
|
|
||||||
v-if="goods.length===0"/>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.pkg-product-land-mark {
|
.pkg-product-land-mark {
|
||||||
background: #F7F3ED;
|
background: #F7F3ED;
|
||||||
|
|||||||
@@ -89,12 +89,12 @@
|
|||||||
<view v-if="list.length === 0" class="no-data">
|
<view v-if="list.length === 0" class="no-data">
|
||||||
暂无数据
|
暂无数据
|
||||||
</view>
|
</view>
|
||||||
<u-loadmore
|
<!-- <u-loadmore
|
||||||
v-if="query.page >= totalPage && list.length > 0"
|
v-if="query.page >= totalPage && list.length > 0"
|
||||||
:line="true"
|
:line="true"
|
||||||
status="nomore"
|
status="nomore"
|
||||||
nomore-text="到底了"
|
nomore-text="到底了"
|
||||||
/>
|
/> -->
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
// 日期格式化
|
// 日期格式化
|
||||||
export function formatterDate(date, flag = '-', mode = 'date') {
|
export function formatterDate(date, flag = '-', mode = 'date') {
|
||||||
const year = new Date(date).getFullYear()
|
const year = new Date(date).getFullYear()
|
||||||
@@ -22,3 +24,36 @@ export function formatContent(html) {
|
|||||||
contentData = contentData.replace(/\<img/gi, '<img style="max-width:100%;height:auto;display:block;margin:0 auto;"')
|
contentData = contentData.replace(/\<img/gi, '<img style="max-width:100%;height:auto;display:block;margin:0 auto;"')
|
||||||
return contentData
|
return contentData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* desc: 监听页面访问次数
|
||||||
|
* auth: lifizer
|
||||||
|
* date: 2024-05-16
|
||||||
|
* @param key-页面唯一标识
|
||||||
|
* @param cb-回调函数
|
||||||
|
* @returns {null}
|
||||||
|
*/
|
||||||
|
export function pageToWatchShowCount(key, cb = '') {
|
||||||
|
if (Vue.prototype.$pageToWatchData[key]) {
|
||||||
|
Vue.prototype.$pageToWatchData[key].count++
|
||||||
|
} else {
|
||||||
|
Vue.prototype.$pageToWatchData[key] = {
|
||||||
|
count: 1,
|
||||||
|
timer: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cb && cb()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* desc: 监听页面访问时长
|
||||||
|
* auth: lifizer
|
||||||
|
* date: 2024-05-16
|
||||||
|
* @param key-页面唯一标识
|
||||||
|
* @returns {null}
|
||||||
|
*/
|
||||||
|
export function pageToWatchShowTimer(key) {
|
||||||
|
if (Vue.prototype.$pageToWatchData[key]) {
|
||||||
|
Vue.prototype.$pageToWatchData[key].timer++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user