chore: 入库生产基线(2026-10-26 工作树快照)
- 含首页壳/容器页/授权页/分享图/首页配置等此前未入库的在途改动 - 新增未跟踪的 pages/index/mall.vue(第 5 个 tabBar 页,pages.json 已引用) - 排除本地备份文件(*.bak* / *.origin-bak) Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,129 +0,0 @@
|
||||
<template>
|
||||
<view class="skeleton">
|
||||
<!-- #ifdef MP || APP -->
|
||||
<view class="blank"></view>
|
||||
<!-- #endif -->
|
||||
<view class="header acea-row row-between-wrapper">
|
||||
<view class="left"></view>
|
||||
<view class="right"></view>
|
||||
</view>
|
||||
<view class="tabNav acea-row row-between-wrapper">
|
||||
<view class="item"></view>
|
||||
<view class="item"></view>
|
||||
<view class="item"></view>
|
||||
<view class="item"></view>
|
||||
</view>
|
||||
<view class="swipers"></view>
|
||||
<view class="nav acea-row row-between-wrapper">
|
||||
<view class="item"></view>
|
||||
<view class="item"></view>
|
||||
<view class="item"></view>
|
||||
<view class="item"></view>
|
||||
<view class="item"></view>
|
||||
</view>
|
||||
<view class="nav acea-row row-between-wrapper">
|
||||
<view class="item"></view>
|
||||
<view class="item"></view>
|
||||
<view class="item"></view>
|
||||
<view class="item"></view>
|
||||
<view class="item"></view>
|
||||
</view>
|
||||
<view class="header acea-row row-between-wrapper">
|
||||
<view class="left"></view>
|
||||
<view class="right"></view>
|
||||
</view>
|
||||
<view class="coupon acea-row row-between-wrapper">
|
||||
<view class="item"></view>
|
||||
<view class="item"></view>
|
||||
</view>
|
||||
<view class="goodList">
|
||||
<view class="item acea-row row-between row-top">
|
||||
<view class="pictrue"></view>
|
||||
<view class="text">
|
||||
<view class="name"></view>
|
||||
<view class="money"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.skeleton{
|
||||
padding: 0 30rpx;
|
||||
.blank{
|
||||
width: 100%;
|
||||
height: 150rpx;
|
||||
background-color: #F5F5F5;
|
||||
}
|
||||
.header{
|
||||
.left{
|
||||
width: 200rpx;
|
||||
height: 50rpx;
|
||||
background-color: #e9e9e9;
|
||||
}
|
||||
.right{
|
||||
width: 460rpx;
|
||||
height: 50rpx;
|
||||
background-color: #e9e9e9;
|
||||
}
|
||||
}
|
||||
.tabNav{
|
||||
margin-top: 20rpx;
|
||||
.item{
|
||||
width: 150rpx;
|
||||
height: 50rpx;
|
||||
background-color: #e9e9e9;
|
||||
}
|
||||
}
|
||||
.swipers{
|
||||
margin-top: 20rpx;
|
||||
width: 100%;
|
||||
height: 400rpx;
|
||||
background-color: #e9e9e9;
|
||||
}
|
||||
.nav{
|
||||
margin: 20rpx 0;
|
||||
.item{
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #e9e9e9;
|
||||
}
|
||||
}
|
||||
.coupon{
|
||||
margin-top: 20rpx;
|
||||
.item{
|
||||
width: 330rpx;
|
||||
height: 120rpx;
|
||||
background-color: #e9e9e9;
|
||||
}
|
||||
}
|
||||
.goodList{
|
||||
margin-top: 20rpx;
|
||||
.item{
|
||||
.pictrue{
|
||||
width: 220rpx;
|
||||
height: 220rpx;
|
||||
background-color: #e9e9e9;
|
||||
}
|
||||
.text{
|
||||
.name{
|
||||
width: 440rpx;
|
||||
height: 76rpx;
|
||||
background-color: #e9e9e9;
|
||||
}
|
||||
.money{
|
||||
width: 100rpx;
|
||||
height: 34rpx;
|
||||
background-color: #e9e9e9;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -5,11 +5,12 @@
|
||||
本页替代了 CRMEB 原装修首页(原文件完整备份在同目录
|
||||
index.vue.origin-bak,恢复方法见本文件底部注释)。
|
||||
|
||||
链路(2026-09 起:mama-box 不再是 box_app 的「应用」,URL 硬编码):
|
||||
onLoad → loadMamaBox()
|
||||
→ webUrl = https://mp.yizhezhe.com/mama-box/ + #openid=xxx(buildWebUrl)
|
||||
链路(2026-10-08 起:首页地址后台可定制,不再写死):
|
||||
onLoad → _homeUrlReady()(拉 box_app GET /api/mp/public/home/config;
|
||||
本地缓存兜底,都没有才用内置默认 MAMA_HOME)
|
||||
→ loadMamaBox() → webUrl = 生效首页地址(默认 /mama-box/)+ #openid=xxx(buildWebUrl)
|
||||
→ <web-view> 加载该 H5
|
||||
(更新首页 = 直接改服务端 box_app/mama-box/ 目录,无需发版即可刷新内容)
|
||||
(更新首页内容 = 改服务端对应 H5 目录;换首页地址 = 管理后台「首页配置」,均无需发版)
|
||||
|
||||
两个坑(都来自 app_03 前一次接入的实测结论):
|
||||
1. 微信 web-view 首次加载会丢弃 URL 的 query string(?a=b),
|
||||
@@ -68,8 +69,18 @@
|
||||
|
||||
const app = getApp();
|
||||
|
||||
// mama-box H5 托管地址(硬编码;更新首页 = 改服务端 box_app/mama-box/ 目录)
|
||||
// 内置兜底首页地址(2026-10-08 起不再是唯一来源):
|
||||
// 生效地址 = box_app 后台配置(GET /api/mp/public/home/config)→ 本地缓存 → 这里。
|
||||
// 管理后台清空配置 = 回到本值;后端 DEFAULT_HOME_URL 与此保持一致。
|
||||
const MAMA_HOME = 'https://mp.yizhezhe.com/mama-box/';
|
||||
// 首页地址配置接口(box_app 免登录面;保留名见 docs/api-naming-convention.md 第四节)
|
||||
const HOME_CONFIG_API = 'https://mp.yizhezhe.com/api/mp/public/home/config';
|
||||
// 生效首页地址的本地缓存(离线/弱网时用上次拿到的地址,不回退默认)
|
||||
const HOME_URL_CACHE_KEY = 'MP_HOME_URL_CACHE';
|
||||
// 与后端校验同口径:只要 https 且无空白;域名合法性由微信「web-view 业务域名」白名单兜底
|
||||
function isValidHomeUrl(u) {
|
||||
return typeof u === 'string' && /^https:\/\//i.test(u) && !/\s/.test(u);
|
||||
}
|
||||
|
||||
/* 剥离分享链接里的身份/缓存参数。分享出去的链接必须干净:
|
||||
① 不能把分享者的 openid/unionid 泄露给接收者;
|
||||
@@ -119,6 +130,7 @@
|
||||
if (this.loadError) return '请检查网络后重试';
|
||||
if (this.identityFail) return '请检查网络后点下方重试,或退出小程序重新进入';
|
||||
if (this.identityPending) return '马上就好,请稍候(不会加载空数据的页面)';
|
||||
if (this.restoring) return '正在回到你上次使用的应用';
|
||||
return '正在为你打开「兜爸心选」';
|
||||
},
|
||||
fallbackEmoji() {
|
||||
@@ -127,11 +139,15 @@
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
webUrl: '', // web-view 地址(硬编码 + #openid/#unionid)
|
||||
webUrl: '', // web-view 地址(首页地址/当前 H5 + #openid/#unionid)
|
||||
_homeUrl: '', // 生效首页地址(后台配置;非响应式内部字段,见 _homeUrlReady)
|
||||
_homeUrlTask: null, // 「拉首页地址配置」的单飞 Promise(一次冷启动只请求一次)
|
||||
requesting: false, // 防重入
|
||||
_shownOnce: false, // 首次展示标记(避免首次 onShow 重复加载)
|
||||
_idAttempts: 0, // 「取到 openid 才加载」的自动重试计数(见 fetchIdentityThenLoad)
|
||||
loadError: false, // web-view 加载失败(显示「重新加载」)
|
||||
restoring: false, // 冷启动正在判定/打开「上次进入的 H5 应用」(只影响兜底屏文案)
|
||||
_noRestore: false, // 本次加载 mama-box 是否要带 #norestore=1(禁止 H5 兜底再把用户送回应用)
|
||||
identityPending: false, // 正在获取 openid(此期间**不加载 H5**,见 fetchIdentityThenLoad)
|
||||
identityFail: false, // 多次仍未拿到 openid → 停在兜底屏,给「重新获取身份」入口
|
||||
shareInfo: {}, // CRMEB 后台「分享设置」(标题/图,无 App 匹配时兜底)
|
||||
@@ -142,6 +158,20 @@
|
||||
};
|
||||
},
|
||||
onLoad(options) {
|
||||
/* 诊断日志(过滤关键字 enter-app):首页壳每次「冷启动」都会打这一行;
|
||||
如果重进时**看不到它**,说明是热启动(onShow),恢复走的是「保持不动」那条路。 */
|
||||
try {
|
||||
console.log('[enter-app] ===== 首页壳 onLoad(冷启动)===== options=' + JSON.stringify(options || {}));
|
||||
} catch (e) {}
|
||||
/* 消费「本次冷启动是否允许恢复」标记(App.onLaunch 置位,见其注释)。
|
||||
放在最前面就消费:后面任何提前 return(商户/管理员跳工作台、显式落地)都不该把标记留给下次。 */
|
||||
let restoreArmed = false;
|
||||
try {
|
||||
restoreArmed = !!(app && app.globalData && app.globalData.restoreArmed);
|
||||
if (app && app.globalData) app.globalData.restoreArmed = false;
|
||||
} catch (e) {}
|
||||
console.log('[enter-app] restoreArmed=' + restoreArmed +
|
||||
'(true=冷启动落在首页,可恢复;false=显式落地或从应用内回首页,不恢复)');
|
||||
// #ifdef MP
|
||||
// 开启「转发给好友 / 分享到朋友圈」两项菜单(onShareTimeline 需要它)
|
||||
uni.showShareMenu({ menus: ['shareAppMessage', 'shareTimeline'] });
|
||||
@@ -152,6 +182,9 @@
|
||||
this.getTemlIds();
|
||||
getShare().then(res => { this.shareInfo = (res && res.data) || {}; }).catch(() => {});
|
||||
// #endif
|
||||
// 最早发出「首页地址配置」请求(与身份解析并行,通常先于它完成 → 零额外等待)。
|
||||
// loadMamaBox / retryLoad / onShow 都通过 _homeUrlReady() / _homeBase() 消费它。
|
||||
this._homeUrlReady();
|
||||
// 预热 box_app 全量应用表(url → shareImageUrl)。
|
||||
// 本页不会随 H5 应用切换重新 onLoad(应用宫格用 location.href 换页),
|
||||
// 所以分享图只能在「点转发那一刻」按 options.webViewUrl 同步匹配,
|
||||
@@ -174,7 +207,9 @@
|
||||
if (options && typeof options.url === 'string' && options.url) {
|
||||
let target = options.url;
|
||||
try { target = decodeURIComponent(target); } catch (e) {}
|
||||
this.loadMamaBox(); // 保留首页作为返回落点
|
||||
console.log('[enter-app] 显式落地(options.url,分享/朋友圈)→ 直接进容器页: ' + target +
|
||||
'(优先级高于「恢复上次应用」)');
|
||||
this.loadMamaBox(true); // 保留首页作为返回落点;带 #norestore,避免 H5 兜底把落点换成别的应用
|
||||
this.$nextTick(() => {
|
||||
uni.navigateTo({ url: '/pages/annex/web_view/index?url=' + encodeURIComponent(target) });
|
||||
});
|
||||
@@ -189,9 +224,44 @@
|
||||
// ⚠️ 但严禁在商城页主动 showTabBar 来「配对」——上一轮翻车根因
|
||||
// (showTabBar + DIY 底栏同显 = 商品列表双 tabBar,见 onShow 旧警告)。
|
||||
uni.hideTabBar();
|
||||
this.loadMamaBox();
|
||||
/* 冷启动恢复(2026-09-22,档 3):先问 box_app「上次进入的 H5 应用」,
|
||||
命中就直接把容器页压上去 —— **不加载 mama-box,因此没有首页闪屏**。
|
||||
未命中 / 取数失败 / 无身份 → 回落到原路径(加载 mama-box)。
|
||||
⚠️ 只有 options.url(分享/朋友圈落地)算显式落地并已在上面 return;
|
||||
options.scene **每次冷启动都有值**(1001 最近使用 / 1007 分享 / 1011 扫码…),
|
||||
不能拿它当「显式落地」判据,否则永远不恢复。 */
|
||||
/* 只有「冷启动落在首页/引导页且无显式落地」才尝试恢复(restoreArmed 已在 onLoad 开头消费)。
|
||||
扫码/分享进容器页、或从应用内点左上角「小房子」回首页时 armed=false → 不恢复,并且加载
|
||||
mama-box 时带 #norestore=1(否则它的兜底恢复又会把用户送回刚才那个应用,出现
|
||||
「点小房子回不了首页、要多点一次返回」的循环;2026-09-22 用户实测)。 */
|
||||
if (!restoreArmed) {
|
||||
console.log('[enter-app] 本次不是「冷启动落在首页」(显式落地 / 从应用内回首页)→ 不恢复,' +
|
||||
'直接进首页(mama-box 带 #norestore=1)');
|
||||
this.loadMamaBox(true);
|
||||
return;
|
||||
}
|
||||
console.log('[enter-app] 非显式落地 → 尝试恢复「上次进入的 H5 应用」…');
|
||||
this.restoreOrLoadHome();
|
||||
},
|
||||
onShow() {
|
||||
/* 是否「小程序热启动恢复」(点胶囊关闭后再进 / 切后台再回),而不是从其它 tab 切回首页:
|
||||
App.onShow 刚触发过 → 页面栈与 web-view 都还在,用户仍停在离开时的那个 H5 应用里。
|
||||
⚠️ 这种情况**必须跳过下面的「重载 webview」**,否则会把用户从 H5 应用踢回兜爸心选首页
|
||||
—— 2026-09-22 线上问题根因:热启动不触发 onLoad(恢复逻辑没机会跑),
|
||||
却触发了这里的重载;而 shareHref 仍是 mama-box(H5 postMessage 被微信攒着没派发),
|
||||
于是重载到首页,mama-box 的兜底又被 sessionStorage 闸门挡住 → 停在首页。
|
||||
⚠️ 切 tab 不触发 App.onShow,所以那个场景仍按原行为重载回首页。 */
|
||||
let isAppResume = false;
|
||||
try {
|
||||
const at = (app && app.globalData && app.globalData.appShowAt) || 0;
|
||||
isAppResume = at > 0 && (Date.now() - at) < 2000;
|
||||
} catch (e) {}
|
||||
/* 诊断日志(过滤关键字 enter-app):这一行是「热启动还是切 tab」的唯一判据来源。
|
||||
isAppResume=true → 热启动恢复(点胶囊关闭后再进):保持当前 H5 不动,不重载;
|
||||
isAppResume=false → 从其它 tab 切回首页:按原行为重载 web-view 回首页。 */
|
||||
console.log('[enter-app] 首页壳 onShow: isAppResume=' + isAppResume +
|
||||
'(_shownOnce=' + this._shownOnce + ', webUrl=' + (this.webUrl ? '有' : '空') +
|
||||
', shareHref=' + (this.shareHref || '空') + ')');
|
||||
// 每次回到首页都再压一次 tabBar:hideTabBar 是全局状态,可能被别处
|
||||
// showTabBar 抬回来(如后台停用 DIY 底部导航时商城页会露出原生条兜底)。
|
||||
// (原这行的 uni.$emit('tabbar-update') 随 custom-tab-bar 死代码一并移除)
|
||||
@@ -205,29 +275,43 @@
|
||||
// 目标 H5 永远收不到 phone(2026-09-18 孕检日历授权弹层复现根因之一)。
|
||||
// shareHref 由 H5 换页/发起授权前的 location 上报实时刷新(askProfile
|
||||
// 会先 reportLocation 再 navigateTo),是「当前 H5」最可靠的来源。
|
||||
const authBase = (this.shareHref || this.webUrl || MAMA_HOME).split('#')[0];
|
||||
const authBase = (this.shareHref || this.webUrl || this._homeBase()).split('#')[0];
|
||||
const authUrl = this.consumeAuthResult(authBase);
|
||||
if (authUrl) {
|
||||
this.loadError = false;
|
||||
this._shownOnce = true;
|
||||
this.webUrl = authUrl;
|
||||
} else if (this._shownOnce && this.webUrl) {
|
||||
} else if (this._shownOnce && this.webUrl && !isAppResume) {
|
||||
// ⚠️ 从商城/其它 tab 切回首页时:webview 是同一个实例,SPA 会停留在切走前的屏。
|
||||
// 改为「重载 webview」让 H5 落回首页(H5 默认即是首页)。首次展示不重复刷。
|
||||
// 同理不能写死 MAMA_HOME —— 用户停在宫格切换的应用里时会被踢回 mama-box;
|
||||
// 以 shareHref(当前 H5)为基址重载,停留在原应用首页。
|
||||
// ⚠️ 热启动恢复(isAppResume)走不到这里:见 onShow 开头的说明。
|
||||
this.loadError = false;
|
||||
const reloadBase = (this.shareHref || MAMA_HOME).split('#')[0];
|
||||
const reloadBase = (this.shareHref || this._homeBase()).split('#')[0];
|
||||
console.log('[enter-app] onShow: 非热启动(切 tab 回首页)→ 重载 web-view,基址=' + reloadBase);
|
||||
// 宿主自己把首页重载回首页 H5 时,同步清掉 last_app(人已经回到首页了)。
|
||||
// 覆盖「容器页返回箭头回首页」这类不经过 H5 后退的路径 —— H5 侧 clearLastAppOnBackHome()
|
||||
// 只认浏览器后退(back_forward/pageshow.persisted)或 referrer,宿主 src 重载不一定带得上 referrer。
|
||||
// ⚠️ 2026-10-08 起首页地址可定制:不能再写死判断 '/mama-box',要按生效首页地址比较
|
||||
// (否则定制首页后回首页不清 last_app,下次冷启动会被送回旧应用)。
|
||||
if (this._isHomeBase(reloadBase)) this._clearLastApp();
|
||||
if (this._hostOpenid()) {
|
||||
this.webUrl = this.buildWebUrl(reloadBase + '?t=' + Date.now());
|
||||
// ⚠️ 回首页 tab 的重载一律带 #norestore=1:这是「用户要回首页」,
|
||||
// 不能让 mama-box 的兜底恢复又把他送回上次那个应用(见 onLoad 的入口判定)。
|
||||
this.webUrl = this.buildWebUrl(reloadBase + '?t=' + Date.now(), ['norestore=1']);
|
||||
} else {
|
||||
/* ⚠️ 仍无 openid:走同一条「取到才加载」的路(自动重试 3 次 → 兜底屏),
|
||||
不再匿名重载(原因见 fetchIdentityThenLoad 的注释)。 */
|
||||
console.log('[auth-flow] 🔄 onShow: 仍无 openid,走「取到才加载」');
|
||||
this._idAttempts = 0;
|
||||
this._noRestore = true; // 同上:回首页 tab 不许 mama-box 兜底恢复
|
||||
this.fetchIdentityThenLoad(reloadBase);
|
||||
}
|
||||
} else {
|
||||
if (isAppResume) {
|
||||
console.log('[enter-app] onShow: 热启动恢复 → 保持当前 web-view 不重载(用户仍停在上次的 H5 应用里)');
|
||||
}
|
||||
this._shownOnce = true;
|
||||
}
|
||||
// 历史(勿照旧回退):曾试过「home hide + 商城页 show」双向 programmatic
|
||||
@@ -265,7 +349,7 @@
|
||||
现在本页 onLoad 预热全量应用表(mixins/shareCard.js),转发时用
|
||||
options.webViewUrl 同步匹配出图;H5 postMessage 的 imageUrl 有值才覆盖。 */
|
||||
onShareAppMessage(options) {
|
||||
const target = (options && options.webViewUrl) || this.shareHref || this.webUrl || MAMA_HOME;
|
||||
const target = (options && options.webViewUrl) || this.shareHref || this.webUrl || this._homeBase();
|
||||
// 按「当前 H5 地址」解析分享图:先做应用切换检测(首页壳不随 H5 换页重新 onLoad),
|
||||
// 再每次重新反查 box_app —— 不能因为 shareImageUrl 已有值就跳过,
|
||||
// 那是上一个应用的图(A 应用分享过、切到 B 后仍带 A 的图,就是这里出的错)。
|
||||
@@ -273,6 +357,8 @@
|
||||
const info = this.shareInfo || {};
|
||||
const uid = this.uid || 0;
|
||||
return {
|
||||
// 标题来源优先级:H5 postMessage 上报 → box_app 反查(后台「分享标题」,留空 = 应用名称,
|
||||
// 由 resolveShareCard 写进 shareTitle)→ CRMEB 后台分享设置 → 内置兜底。
|
||||
title: this.shareTitle || info.title || '兜爸心选 · 孕育陪伴',
|
||||
// spid:恢复原装修首页的分享推广归因(接收者容器页 / App.onShow 读入 globalData.spid)
|
||||
path: '/pages/annex/web_view/index?url=' + encodeURIComponent(stripAuthParams(target)) + '&spid=' + uid,
|
||||
@@ -280,8 +366,10 @@
|
||||
};
|
||||
},
|
||||
onShareTimeline() {
|
||||
// onShareTimeline 无回调参数,拿不到 webViewUrl,只能用 H5 传来的 href 兜底
|
||||
const target = this.shareHref || this.webUrl || MAMA_HOME;
|
||||
// onShareTimeline 无回调参数,拿不到 webViewUrl,只能用 H5 传来的 href 兜底。
|
||||
// 同一地址也解析一次:首次分享就走朋友圈时,标题/图不能还是空的。
|
||||
const target = this.shareHref || this.webUrl || this._homeBase();
|
||||
this.resolveShareCard(target);
|
||||
const info = this.shareInfo || {};
|
||||
const uid = this.uid || 0;
|
||||
return {
|
||||
@@ -302,17 +390,22 @@
|
||||
if (options.spid) app.globalData.spid = options.spid;
|
||||
},
|
||||
/**
|
||||
* 查询 box_app 拿兜爸心选的托管地址。
|
||||
* box_app 的 App 表是「产品盒子」的应用注册中心 —— 改后台这条记录的
|
||||
* url 字段即可给 H5 换地址 / 切版本,小程序不用发版。
|
||||
* 加载首页 H5。
|
||||
* 2026-10-08 起:首页地址不再写死 —— 先等 _homeUrlReady()(box_app 后台配置,
|
||||
* 本地缓存兜底,最多 2s),再按「有 openid 直接拼 hash 加载 / 无 openid 走取到才加载」。
|
||||
*/
|
||||
loadMamaBox() {
|
||||
// 2026-09 起:mama-box 不再是 box_app 的「应用」(已从 App 表删除)。
|
||||
// 它是小程序首页 + H5 入口,URL 在此【硬编码】;
|
||||
// 更新首页 = 直接改服务端 box_app/mama-box/ 目录,无需发版即可刷新内容。
|
||||
loadMamaBox(noRestore) {
|
||||
/* @param {boolean} noRestore - 加载首页时给 URL 加 #norestore=1,禁止首页 H5 自己恢复
|
||||
(它的兜底恢复会把用户从「用户明确要去的页面」再送回上次那个应用)。两种情况要带:
|
||||
· 恢复成功后留下的「返回落点」;
|
||||
· 本次明确判定「不恢复」(显式落地 / 从应用内回首页)。
|
||||
只有「尝试恢复但取数失败」才不带 —— 那时让首页 H5 兜底重试一次。 */
|
||||
this._noRestore = !!noRestore;
|
||||
console.log('[enter-app] 加载首页(返回落点)noRestore=' + this._noRestore);
|
||||
if (this.requesting) return;
|
||||
this.requesting = true;
|
||||
this.loadError = false;
|
||||
this.restoring = false;
|
||||
/* ⚠️ 身份兜底(2026-09-20 新增):store.openid / 缓存 OPENID / JWT 三处都读不到时,
|
||||
**先主动取一次**(wx.login → silence_auth,见 mixin 的 _silenceAuthOpenid),
|
||||
拿到再拼 hash 加载 —— 别匿名加载。
|
||||
@@ -321,26 +414,198 @@
|
||||
容器页那样的 openid 兜底(两条都在 2026-09-20 修,现统一叫 _ensureIdentityThenLoad)。
|
||||
取不到 openid 仍继续加载(保持可用),H5 侧会显示「未获取到微信身份」提示条。 */
|
||||
this.identityFail = false;
|
||||
if (this._hostOpenid()) {
|
||||
this.identityPending = false;
|
||||
this._homeUrlReady().then((homeUrl) => {
|
||||
if (this._hostOpenid()) {
|
||||
this.identityPending = false;
|
||||
this._idAttempts = 0;
|
||||
this.webUrl = this.buildWebUrl(homeUrl, this._noRestore ? ['norestore=1'] : []);
|
||||
this.requesting = false;
|
||||
return;
|
||||
}
|
||||
/* ⚠️⚠️ 拿不到 openid **就不加载**(2026-09-20 用户定的行为):
|
||||
宁可让用户在这一屏多等几秒(自动重试 3 次),也不匿名加载 H5 ——
|
||||
匿名加载会让 H5 进访客态(孕周 `--`、档案查不到),
|
||||
用户看到「页面能用但全是空」比等一会儿更糟,且事后很难判断是身份问题。 */
|
||||
this._idAttempts = 0;
|
||||
this.webUrl = this.buildWebUrl(MAMA_HOME);
|
||||
this.fetchIdentityThenLoad(homeUrl);
|
||||
this.requesting = false;
|
||||
});
|
||||
},
|
||||
/* ---------- 首页地址:box_app 后台可定制(2026-10-08) ----------
|
||||
过去 MAMA_HOME 写死在本文件,换首页要发小程序版。现在冷启动拉
|
||||
GET /api/mp/public/home/config 拿生效地址(管理后台「首页配置」页可改,
|
||||
homeUrl 清空 = 回内置默认);homeUrlReady 是单飞 Promise,onLoad 最先发出,
|
||||
loadMamaBox / retryLoad 消费 —— 与身份解析并行,正常零额外等待。
|
||||
可靠性分层(每一层都不能阻塞首页加载,AGENTS.md §5.6):
|
||||
① 配置请求失败/超时(2s)→ 用「本地缓存的上次地址」(离线也能进上次的定制首页);
|
||||
② 本地也没有 → 内置默认 MAMA_HOME;
|
||||
③ 响应 code!==200(⚠️ 这个后端不存在路由时 HTTP 仍是 200,错误码在 body,见 §5.7)
|
||||
或 url 非法 → 同②,但**不覆盖**本地缓存(分不清是接口坏了还是后台清空,
|
||||
宁可沿用旧值,下次冷启动再试);
|
||||
④ 只有拿到合法地址(含后台清空时下发的默认地址)才写缓存。
|
||||
⚠️ 生效时机是「下一次冷启动」:已加载的 web-view 不因配置变化主动重载
|
||||
(热启动不打扰用户,与 onShow 的 isAppResume 原则一致)。 */
|
||||
_homeUrlReady() {
|
||||
if (this._homeUrlTask) return this._homeUrlTask;
|
||||
// 先用本地缓存占位(非响应式内部字段,只给 JS 逻辑用,与 _shownOnce 同款)
|
||||
try {
|
||||
const cached = uni.getStorageSync(HOME_URL_CACHE_KEY);
|
||||
if (cached && isValidHomeUrl(cached.url)) this._homeUrl = cached.url;
|
||||
} catch (e) {}
|
||||
this._homeUrlTask = new Promise((resolve) => {
|
||||
let done = false;
|
||||
const finish = (url) => {
|
||||
if (done) return;
|
||||
done = true;
|
||||
if (url) {
|
||||
this._homeUrl = url;
|
||||
try { uni.setStorageSync(HOME_URL_CACHE_KEY, { url: url, at: Date.now() }); } catch (e) {}
|
||||
}
|
||||
resolve(this._homeUrl || MAMA_HOME);
|
||||
};
|
||||
const timer = setTimeout(() => {
|
||||
console.log('[enter-app] ⏱ 首页地址配置超时(2s)→ 按「本地缓存/默认」处理');
|
||||
finish(null);
|
||||
}, 2000);
|
||||
uni.request({
|
||||
url: HOME_CONFIG_API,
|
||||
method: 'GET',
|
||||
timeout: 2000,
|
||||
success: (res) => {
|
||||
clearTimeout(timer);
|
||||
const body = res && res.data;
|
||||
const url = body && body.code === 200 && body.result ? body.result.url : null;
|
||||
if (isValidHomeUrl(url)) {
|
||||
console.log('[enter-app] 首页地址生效: ' + url +
|
||||
(url === MAMA_HOME ? '(内置默认)' : '(后台定制)'));
|
||||
finish(url);
|
||||
} else {
|
||||
console.log('[enter-app] 首页地址配置无合法值(body=' + JSON.stringify(body) +
|
||||
') → 沿用「本地缓存/默认」');
|
||||
finish(null);
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
clearTimeout(timer);
|
||||
console.log('[enter-app] ✗ 首页地址配置请求失败 → 按「本地缓存/默认」处理: ' + JSON.stringify(err));
|
||||
finish(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
return this._homeUrlTask;
|
||||
},
|
||||
/* 当前生效的首页基址(同步取:后台配置 → 本地缓存 → 内置默认)。
|
||||
用于分享兜底 / 授权回传落点 / 兜底屏重试这些「拿不到实时值时」的场景。 */
|
||||
_homeBase() {
|
||||
return this._homeUrl || MAMA_HOME;
|
||||
},
|
||||
/* base 是否就是首页 H5(去 hash/query、忽略末尾斜杠后比较)。
|
||||
过去写死判断 indexOf('/mama-box');首页可定制后必须按生效地址比较,
|
||||
否则定制首页时「宿主重载回首页」不会清 last_app(下次冷启动被送回旧应用)。 */
|
||||
_isHomeBase(base) {
|
||||
const norm = (u) => String(u || '').split('#')[0].split('?')[0].replace(/\/+$/, '');
|
||||
return !!base && norm(base) === norm(this._homeBase());
|
||||
},
|
||||
/* ---------- 冷启动恢复:直接把容器页指向「上次进入的 H5 应用」(2026-09-22 档 3) ----------
|
||||
需求:进入某 H5 应用后退出小程序,再进要恢复它。
|
||||
做法:本页自己问 box_app `GET /api/mp/public/last-app?openid=`(Redis,per-openid,
|
||||
7 天 TTL);命中就直接 navigateTo 容器页加载目标 —— **不加载 mama-box,无首页闪屏**。
|
||||
优先级:显式落地(options.url 分享/朋友圈)> 恢复 > 首页。
|
||||
回落:无记录 / 取数失败 / 超时 / 拿不到 openid → 照旧加载 mama-box
|
||||
(mama-box 自己的 resumeLastApp 仍是「本页取数失败」时的兜底)。
|
||||
⚠️ 身份注入交给容器页(它用 query 注入)。本页的 buildWebUrl 是 **hash** 注入,
|
||||
对自带 hash 路由的应用(如 baobao-yingji)会破坏路由,所以恢复路径不自己拼身份。 */
|
||||
restoreOrLoadHome() {
|
||||
const decide = () => {
|
||||
const openid = this._hostOpenid();
|
||||
if (!openid) {
|
||||
console.log('[enter-app] ✗ 身份仍未就绪(无 openid)→ 不查 last-app,交给原路径加载首页');
|
||||
this.loadMamaBox();
|
||||
return;
|
||||
}
|
||||
console.log('[enter-app] 查 last-app: openid=' + openid);
|
||||
this._fetchLastApp(openid).then(rec => {
|
||||
if (rec && rec.url) {
|
||||
this._openRestoredApp(rec.url);
|
||||
} else {
|
||||
console.log('[enter-app] ○ last-app 无记录/未拿到 → 进兜爸心选首页');
|
||||
this.loadMamaBox();
|
||||
}
|
||||
});
|
||||
};
|
||||
this.restoring = true;
|
||||
if (this._hostOpenid()) {
|
||||
console.log('[enter-app] 恢复判定开始:openid 命中缓存,直接查 last-app');
|
||||
decide();
|
||||
return;
|
||||
}
|
||||
/* ⚠️⚠️ 拿不到 openid **就不加载**(2026-09-20 用户定的行为):
|
||||
宁可让用户在这一屏多等几秒(自动重试 3 次),也不匿名加载 H5 ——
|
||||
匿名加载会让 H5 进访客态(孕周 `--`、档案查不到),
|
||||
用户看到「页面能用但全是空」比等一会儿更糟,且事后很难判断是身份问题。 */
|
||||
this._idAttempts = 0;
|
||||
this.fetchIdentityThenLoad(MAMA_HOME);
|
||||
this.requesting = false;
|
||||
/* 无缓存身份:先等 App.vue onLaunch 那次静默登录(与 fetchIdentityThenLoad 同款——
|
||||
同一次 code exchange,不重复换 code),最多 1.5s;仍拿不到就交回原路径。 */
|
||||
console.log('[enter-app] 恢复判定开始:无缓存 openid,先等 App.vue 静默登录(最多 1.5s)…');
|
||||
this._awaitHostLogin(1500).then(decide);
|
||||
},
|
||||
/* 读一次 last_app;任何失败/超时都 resolve(null),绝不阻塞首页 */
|
||||
_fetchLastApp(openid) {
|
||||
return new Promise(resolve => {
|
||||
let done = false;
|
||||
const finish = (v) => { if (!done) { done = true; resolve(v); } };
|
||||
const api = 'https://mp.yizhezhe.com/api/mp/public/last-app?openid=' + encodeURIComponent(openid);
|
||||
const timer = setTimeout(() => {
|
||||
console.log('[enter-app] ⏱ last-app 请求超时(1.5s)→ 按无记录处理');
|
||||
finish(null);
|
||||
}, 1500);
|
||||
uni.request({
|
||||
url: api,
|
||||
method: 'GET',
|
||||
timeout: 1500,
|
||||
success: (res) => {
|
||||
clearTimeout(timer);
|
||||
const body = res && res.data;
|
||||
const rec = body && body.result;
|
||||
console.log('[enter-app] last-app 响应: HTTP ' + ((res && res.statusCode) || '?') +
|
||||
' body=' + JSON.stringify(body));
|
||||
finish(rec && rec.url ? rec : null);
|
||||
},
|
||||
fail: (err) => {
|
||||
clearTimeout(timer);
|
||||
console.log('[enter-app] ✗ last-app 请求失败 → 按无记录处理: ' + JSON.stringify(err));
|
||||
finish(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
/* 宿主侧兜底清除:小程序自己把首页重载回 mama-box 时同步清 last_app(见 onShow 调用处)。
|
||||
与 H5 侧 clearLastAppOnBackHome() 互补:那条认浏览器后退/referrer,这条是宿主确定要回首页。 */
|
||||
_clearLastApp() {
|
||||
try {
|
||||
const openid = this._hostOpenid();
|
||||
if (!openid) return;
|
||||
console.log('[enter-app] 宿主重载回首页 → 清除 last_app(下次冷启动不再回上次那个应用)');
|
||||
uni.request({
|
||||
url: 'https://mp.yizhezhe.com/api/mp/public/last-app?openid=' + encodeURIComponent(openid),
|
||||
method: 'DELETE',
|
||||
timeout: 5000,
|
||||
fail: (err) => console.log('[enter-app] ✗ 清除 last_app 失败(忽略): ' + JSON.stringify(err))
|
||||
});
|
||||
} catch (e) {}
|
||||
},
|
||||
/* 命中恢复目标:保留首页作为返回落点 + 交容器页加载(与 options.url 分享落地同款)
|
||||
⚠️ 落点必须带 #norestore=1:否则 mama-box 会在容器页底下**自己再恢复一次**,
|
||||
把返回落点也换成目标应用,back 就回不到首页了。 */
|
||||
_openRestoredApp(url) {
|
||||
console.log('[enter-app] ✅ 命中 last-app → 直接进容器页加载: ' + url +
|
||||
'(不经过 mama-box,无首页闪屏)');
|
||||
this.restoring = false;
|
||||
this.loadMamaBox(true);
|
||||
this.$nextTick(() => {
|
||||
uni.navigateTo({ url: '/pages/annex/web_view/index?url=' + encodeURIComponent(url) });
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 取到 openid 才加载 H5;自动重试 3 次仍失败 → 停在兜底屏给「重新获取身份」入口。
|
||||
* ⚠️ 每次尝试前都再读一次 _hostOpenid():App.vue 的 onLaunch 静默授权是并行的,
|
||||
* 它先落地的话这里直接命中缓存,不必自己再请求一次。
|
||||
* @param {string} base - 要加载的 H5 基址(首页壳是 MAMA_HOME;onShow 重载时是当前 H5)
|
||||
* @param {string} base - 要加载的 H5 基址(首页壳是生效首页地址;onShow 重载时是当前 H5)
|
||||
*/
|
||||
fetchIdentityThenLoad(base) {
|
||||
/* 1) 缓存命中(含 App.vue 并行登录刚落地的)→ 0 等待加载 */
|
||||
@@ -376,7 +641,9 @@
|
||||
this.identityFail = false;
|
||||
this._idAttempts = 0;
|
||||
this._shownOnce = true;
|
||||
this.webUrl = this.buildWebUrl(base + (base.indexOf('?') >= 0 ? '&' : '?') + 't=' + Date.now());
|
||||
// 沿用本次的 _noRestore(见 loadMamaBox 注释):本轮加载是否需要禁止 mama-box 兜底恢复
|
||||
this.webUrl = this.buildWebUrl(base + (base.indexOf('?') >= 0 ? '&' : '?') + 't=' + Date.now(),
|
||||
this._noRestore ? ['norestore=1'] : []);
|
||||
console.log('[auth-flow] ✅ 首页壳拿到 openid,开始加载 H5');
|
||||
return true;
|
||||
},
|
||||
@@ -384,26 +651,29 @@
|
||||
* 给 H5 拼 hash 参数(openid 单一身份键 + unionid 可选)。
|
||||
* ⚠️ 只能拼 # 不能拼 ?:微信 web-view 首次加载丢 query(app_03 实测)。
|
||||
* 身份解析统一由 mixins/webviewHost.js 的 _hostOpenid / _hostUnionid 提供。
|
||||
* @param {string} url
|
||||
* @param {string[]} [extraHash] 额外 hash 参数(如 ['norestore=1'];仅本页自用)
|
||||
*/
|
||||
buildWebUrl(url) {
|
||||
buildWebUrl(url, extraHash) {
|
||||
const parts = [];
|
||||
const openid = this._hostOpenid();
|
||||
const unionid = this._hostUnionid();
|
||||
if (openid) parts.push('openid=' + openid);
|
||||
if (unionid) parts.push('unionid=' + unionid);
|
||||
if (!parts.length) return url;
|
||||
return url + (url.indexOf('#') >= 0 ? '&' : '#') + parts.join('&');
|
||||
const all = parts.concat(extraHash || []);
|
||||
if (!all.length) return url;
|
||||
return url + (url.indexOf('#') >= 0 ? '&' : '#') + all.join('&');
|
||||
},
|
||||
|
||||
/* webviewHost hook:本页 web-view 地址字段是 webUrl */
|
||||
_hostSetWebviewUrl(url) { this.webUrl = url; },
|
||||
/* webviewHost hook:copyLink 未带 href 时的兜底地址 */
|
||||
_hostCurrentUrl() { return this.webUrl || MAMA_HOME; },
|
||||
_hostCurrentUrl() { return this.webUrl || this._homeBase(); },
|
||||
|
||||
/* 授权面板提交(base = 当前 H5 地址,同 onShow 的回传落点逻辑 ——
|
||||
宫格换应用后 MAMA_HOME 不再是用户所在的 H5)→ mixin 的共享授权接口 + hash 回传 */
|
||||
宫格换应用后首页地址不再是用户所在的 H5)→ mixin 的共享授权接口 + hash 回传 */
|
||||
submitAuth() {
|
||||
this.submitHostAuth((this.shareHref || this.webUrl || MAMA_HOME).split('#')[0]);
|
||||
this.submitHostAuth((this.shareHref || this.webUrl || this._homeBase()).split('#')[0]);
|
||||
},
|
||||
|
||||
/* MP:订阅消息模板预取(原装修首页行为;utils/SubscribeMessage.js 请求时用缓存) */
|
||||
@@ -427,19 +697,22 @@
|
||||
this.requesting = false;
|
||||
this._shownOnce = true;
|
||||
this.identityFail = false;
|
||||
/* 有身份直接重载;没有就再走一遍「取到才加载」(重置尝试次数,自动重试 3 次) */
|
||||
/* 有身份直接重载;没有就再走一遍「取到才加载」(重置尝试次数,自动重试 3 次)
|
||||
⚠️ 沿用 this._noRestore:重试首页时同样不许首页 H5 兜底恢复(见 loadMamaBox)。 */
|
||||
const homeUrl = this._homeBase();
|
||||
if (this._hostOpenid()) {
|
||||
this.webUrl = this.buildWebUrl(MAMA_HOME + '?t=' + Date.now());
|
||||
this.webUrl = this.buildWebUrl(homeUrl + '?t=' + Date.now(),
|
||||
this._noRestore ? ['norestore=1'] : []);
|
||||
return;
|
||||
}
|
||||
this._idAttempts = 0;
|
||||
this.fetchIdentityThenLoad(MAMA_HOME);
|
||||
this.fetchIdentityThenLoad(homeUrl);
|
||||
},
|
||||
|
||||
/* 授权完善资料(postMessage → 原生面板 → 共享授权接口 → hash 回传)与
|
||||
pages/annex/web_view 共用 mixins/webviewHost.js:
|
||||
handleHostMessage / onChooseHostAvatar / onHostGetPhone /
|
||||
submitHostAuth(MAMA_HOME) / consumeAuthResult(见 onShow)
|
||||
submitHostAuth(生效首页地址) / consumeAuthResult(见 onShow)
|
||||
本页不再各写一份;分享图设置由 mixins/shareCard.js 提供。 */
|
||||
}
|
||||
}
|
||||
|
||||
875
pages/index/mall.vue
Normal file
875
pages/index/mall.vue
Normal file
@@ -0,0 +1,875 @@
|
||||
<!-- ============================================================
|
||||
商城首页(第 5 个 tabBar 页「商城」)
|
||||
------------------------------------------------------------
|
||||
本页 = 原装 CRMEB 装修首页(pages/index/index.vue.origin-bak)
|
||||
原样恢复成独立路由。起因:pages/index/index 路由已被
|
||||
「兜爸心选」H5 的 web-view 壳占用,H5 底部「兜爸心选」tab
|
||||
(goMall(),见 mama-box 仓库 js/app.js)要跳回老商城首页,
|
||||
只能把它恢复成一个新 tabBar 页(tabBar 上限 5,原 4 项)。
|
||||
|
||||
与原首页的两处差异(其余 1:1):
|
||||
1. 已注册进 pages.json 的 tabBar(第 2 位「商城」)。⚠️ 底栏的真实渲染方是
|
||||
后台「装修→底部导航」DIY 配置(/api/navigation → components/pageFooter),
|
||||
商城项要在底栏出现必须在后台配置里加(链接填 /pages/index/mall,goRouter
|
||||
走 switchTab);这里的 tabBar 注册只保证 switchTab 可达 + DIY 导航禁用时
|
||||
原生 tabBar 兜底可显示(App.vue onLaunch 会 hideTabBar,DIY 启用时
|
||||
pageFooter 也会 hideTabBar,两层兜底见 components/pageFooter/index.vue)。
|
||||
2. 依赖的 4 个组件(appCenter/images/pictureCube/promotionList)
|
||||
在壳替换时被从工作区删了,已按需从 HEAD 恢复,勿再删。
|
||||
|
||||
pages.json:pages 列表 + tabBar 第 2 项均已注册(enablePullDownRefresh
|
||||
沿用原首页 true,与 web-view 壳页的 false 不同,别混)。
|
||||
============================================================ -->
|
||||
<template>
|
||||
<!-- 首页 -->
|
||||
<view v-if="pageShow" class="page"
|
||||
:class="bgTabVal==2?'fullsize noRepeat':bgTabVal==1?'repeat ysize':'noRepeat ysize'"
|
||||
:style="[pageStyle]">
|
||||
<view v-if="!errorNetwork" :style="colorStyle">
|
||||
<!-- 轮播搜索 -->
|
||||
<homeComb v-if="showHomeComb" :dataConfig="homeCombData" @bindSortId="bindSortId":isScrolled="isScrolled"></homeComb>
|
||||
<!-- 顶部搜索框 -->
|
||||
<headerSerch v-if="isHeaderSerch" :dataConfig="headerSerchCombData"></headerSerch>
|
||||
<tabNav v-if="showCateNav" :dataConfig="cateNavData" @bindHeight="bindHeighta"
|
||||
@bindSortId="bindSortId" :isFixed="isFixed && !cateNavData.stickyConfig.tabVal"></tabNav>
|
||||
<view class="index">
|
||||
<!-- 自定义样式 -->
|
||||
<block v-for="(item, index) in styleConfig" :key="index">
|
||||
<!-- <shortVideo v-if="item.name == 'shortVideo'" :dataConfig="item">
|
||||
</shortVideo> -->
|
||||
<userInfor v-if="item.name == 'userInfor'" :dataConfig="item"
|
||||
@changeLogin="changeLogin">
|
||||
</userInfor>
|
||||
<newVip v-if="item.name == 'newVip'" :dataConfig="item"></newVip>
|
||||
<pageTopbar v-if="item.name == 'pageTopbar'" :dataConfig="item"></pageTopbar>
|
||||
<!-- 文章列表 -->
|
||||
<articleList v-if="item.name == 'articleList'" :dataConfig="item">
|
||||
</articleList>
|
||||
<bargain v-if="item.name == 'bargain'" :dataConfig="item" :pullReset="pullReset" @changeBarg="changeBarg"
|
||||
></bargain>
|
||||
<blankPage v-if="item.name == 'blankPage'" :dataConfig="item"></blankPage>
|
||||
<combination v-if="item.name == 'combination'" :dataConfig="item" :pullReset="pullReset">
|
||||
</combination>
|
||||
<!-- 优惠券 -->
|
||||
<coupon v-if="item.name == 'coupon'" :dataConfig="item"
|
||||
@changeLogin="changeLogin"></coupon>
|
||||
<!-- 客户服务 -->
|
||||
<customerService v-if="item.name == 'customerService'" :dataConfig="item">
|
||||
</customerService>
|
||||
<!-- 商品列表 -->
|
||||
<goodList v-if="item.name == 'goodList'" :dataConfig="item"
|
||||
></goodList>
|
||||
<guide v-if="item.name == 'guide'" :dataConfig="item"></guide>
|
||||
<!-- 直播模块 -->
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<liveBroadcast v-if="item.name == 'liveBroadcast'" :dataConfig="item"></liveBroadcast>
|
||||
<!-- #endif -->
|
||||
<menus v-if="item.name == 'menus'" :dataConfig="item"></menus>
|
||||
<!-- 实时消息 -->
|
||||
<news v-if="item.name == 'news'" :dataConfig="item"></news>
|
||||
<!-- 图片库 -->
|
||||
<pictureCube v-if="item.name == 'pictureCube'" :dataConfig="item"></pictureCube>
|
||||
<!-- 图片组件 -->
|
||||
<images v-if="item.name == 'images'" :dataConfig="item"></images>
|
||||
<!-- 促销列表 -->
|
||||
<promotionList v-if="item.name == 'promotionList'" :dataConfig="item"
|
||||
:productVideoStatus='product_video_status' :showHomeComb="showHomeComb" :isHeaderSerch="isHeaderSerch">
|
||||
</promotionList>
|
||||
<richText v-if="item.name == 'richText'" :dataConfig="item"></richText>
|
||||
<seckill v-if="item.name == 'seckill'" :dataConfig="item" :pullReset="pullReset"></seckill>
|
||||
<!-- 轮播图-->
|
||||
<swiperBg v-if="item.name == 'swiperBg'" :dataConfig="item"></swiperBg>
|
||||
<swipers v-if="item.name == 'swipers'" :dataConfig="item"></swipers>
|
||||
<!-- 顶部选项卡 -->
|
||||
|
||||
<!-- 标题 -->
|
||||
<titles v-if="item.name == 'titles'" :dataConfig="item"></titles>
|
||||
<ranking v-if="item.name == 'ranking'" :dataConfig="item"></ranking>
|
||||
<presale v-if="item.name == 'presale'" :dataConfig="item"></presale>
|
||||
<pointsMall v-if="item.name == 'pointsMall'" :dataConfig="item"></pointsMall>
|
||||
<videos v-if="item.name == 'videos'" :dataConfig="item"></videos>
|
||||
<signIn v-if="item.name == 'signIn'" :dataConfig="item"></signIn>
|
||||
<hotspot v-if="item.name == 'hotspot'" :dataConfig="item"></hotspot>
|
||||
<follow v-if="item.name == 'follow'" :dataConfig="item"></follow>
|
||||
<appCenter v-if="item.name == 'appCenter'" :dataConfig="item"></appCenter>
|
||||
<community v-if="item.name == 'community'" :dataConfig="item"></community>
|
||||
</block>
|
||||
<!-- 分类商品模块 -->
|
||||
<!-- #ifndef APP-PLUS -->
|
||||
<view class="sort-product px-20">
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP-PLUS -->
|
||||
<!-- 商品排序 -->
|
||||
<view class="sort-product px-20" :style="{ marginTop: sortMpTop + 'px' }">
|
||||
<!-- #endif -->
|
||||
<view class="rd-24rpx bg--w111-fff p-24 mb-24" v-if="sortList.children && sortList.children.length">
|
||||
<scroll-view scroll-x="true" class="white-nowrap vertical-middle w-full" show-scrollbar="false">
|
||||
<view class="inline-block mr-24" v-for="(item, index) in sortList.children" :key="index">
|
||||
<view class="flex-col flex-center" @tap="changeSort(item, index)">
|
||||
<view class="picture w-90 h-90 rd-50-p111-"
|
||||
:class="{select: curSort == index}">
|
||||
<image :src="item.pic" class="w-full h-full rd-50-p111-"></image>
|
||||
</view>
|
||||
<text class="fs-24 pt-14" :class="{'font-num': curSort == index}">{{item.cate_name}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<waterfallsFlow ref="waterfallsFlow" :wfList="goodList" :showCart="false" @itemTap="goDetail"></waterfallsFlow>
|
||||
<Loading :loaded="loaded" :loading="loading"></Loading>
|
||||
<view v-if="goodList.length == 0 && loaded">
|
||||
<emptyPage title="暂无商品,去看点别的吧~" ></emptyPage>
|
||||
</view>
|
||||
</view>
|
||||
<activityModal :pageIndex="1"></activityModal>
|
||||
<!-- #ifdef H5 -->
|
||||
<view v-if="configData.record_No" class="site-config" @click="goICP">{{ configData.record_No }}</view>
|
||||
<!-- #endif -->
|
||||
<view class="pb-safe h-100" v-if="isFooter"></view>
|
||||
<pageFooter @newDataStatus="newDataStatus"></pageFooter>
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<add-tip></add-tip>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
<!-- #ifdef APP -->
|
||||
<app-update ref="appUpdate" :force="true" :tabbar="false"></app-update>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
<view v-else>
|
||||
<view class="o813d0">
|
||||
<image :src="imgHost + '/statics/images/error-network.gif'"></image>
|
||||
<view class="title">网络连接断开</view>
|
||||
<view class="of0b21">
|
||||
<view class="label">请检查情况:</view>
|
||||
<view class="item">· 在设置中是否已开启网络权限</view>
|
||||
<view class="item">· 当前是否处于弱网环境</view>
|
||||
<view class="item">· 版本是否过低,升级试试吧</view>
|
||||
</view>
|
||||
<view class="btn" @click="reconnect">重新连接</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import colors from "@/mixins/color";
|
||||
import couponWindow from '@/components/couponWindow/index';
|
||||
import {
|
||||
getCouponV2,
|
||||
getCouponNewUser,
|
||||
copyRight
|
||||
} from '@/api/api.js';
|
||||
import {
|
||||
getShare
|
||||
} from '@/api/public.js';
|
||||
// #ifdef H5
|
||||
import {
|
||||
silenceAuth
|
||||
} from '@/api/public.js';
|
||||
// #endif
|
||||
import Cache from '@/utils/cache';
|
||||
import userInfor from './components/userInfor';
|
||||
import homeComb from './components/homeComb';
|
||||
import newVip from './components/newVip';
|
||||
import pageTopbar from './components/pageTopbar';
|
||||
// import shortVideo from './components/shortVideo';
|
||||
import community from './components/community'
|
||||
import headerSerch from './components/headerSerch';
|
||||
import swipers from './components/swipers';
|
||||
import coupon from './components/coupon';
|
||||
import articleList from './components/articleList';
|
||||
import bargain from './components/bargain';
|
||||
import blankPage from './components/blankPage';
|
||||
import combination from './components/combination';
|
||||
import customerService from './components/customerService';
|
||||
import goodList from './components/goodList';
|
||||
import guide from './components/guide';
|
||||
import liveBroadcast from './components/liveBroadcast';
|
||||
import menus from './components/menus';
|
||||
import news from './components/news';
|
||||
import pictureCube from './components/pictureCube';
|
||||
import images from './components/images';
|
||||
import promotionList from './components/promotionList';
|
||||
import richText from './components/richText';
|
||||
import seckill from './components/seckill';
|
||||
import swiperBg from './components/swiperBg';
|
||||
import tabNav from './components/tabNav';
|
||||
import titles from './components/titles';
|
||||
import ranking from './components/ranking';
|
||||
import presale from './components/presale'
|
||||
import pointsMall from './components/pointsMall';
|
||||
import videos from './components/videos';
|
||||
import signIn from './components/signIn';
|
||||
import hotspot from './components/hotspot';
|
||||
import follow from './components/follow';
|
||||
import appCenter from './components/appCenter';
|
||||
import waterfallsFlow from "@/components/WaterfallsFlow/WaterfallsFlow.vue";
|
||||
import emptyPage from '@/components/emptyPage.vue';
|
||||
import activityModal from "@/components/activityModal/index.vue"
|
||||
// #ifdef MP
|
||||
import addTip from '@/components/weixinTip/index.vue'
|
||||
import {getTemlIds} from '@/api/api.js';
|
||||
import {
|
||||
SUBSCRIBE_MESSAGE,
|
||||
TIPS_KEY
|
||||
} from '@/config/cache';
|
||||
// #endif
|
||||
import {mapGetters,mapMutations} from 'vuex';
|
||||
import {getDiy, getDiyVersion} from '@/api/api.js';
|
||||
import {
|
||||
getCategoryList,
|
||||
getProductslist,
|
||||
getProductHot,
|
||||
diyProductApi
|
||||
} from '@/api/store.js';
|
||||
import { goShopDetail } from '@/libs/order.js';
|
||||
import { toLogin } from '@/libs/login.js';
|
||||
import { HTTP_REQUEST_URL } from '@/config/app';
|
||||
import pageFooter from '@/components/pageFooter/index.vue';
|
||||
import Loading from '@/components/Loading/index.vue';
|
||||
import recommend from '@/components/recommend';
|
||||
import appUpdate from '@/components/update/app-update.vue';
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
pageStyle(){
|
||||
return {
|
||||
backgroundColor: this.bgColor,
|
||||
backgroundImage: this.bgPic ? `url(${this.bgPic})` : '',
|
||||
minHeight: this.windowHeight + 'px'
|
||||
}
|
||||
},
|
||||
...mapGetters(['isLogin', 'uid', 'cartNum']),
|
||||
},
|
||||
mixins: [colors],
|
||||
components: {
|
||||
recommend,
|
||||
Loading,
|
||||
pageFooter,
|
||||
couponWindow,
|
||||
homeComb,
|
||||
newVip,
|
||||
pageTopbar,
|
||||
userInfor,
|
||||
community,
|
||||
headerSerch,
|
||||
swipers,
|
||||
coupon,
|
||||
articleList,
|
||||
bargain,
|
||||
blankPage,
|
||||
combination,
|
||||
customerService,
|
||||
goodList,
|
||||
guide,
|
||||
menus,
|
||||
pictureCube,
|
||||
images,
|
||||
news,
|
||||
promotionList,
|
||||
richText,
|
||||
seckill,
|
||||
swiperBg,
|
||||
tabNav,
|
||||
titles,
|
||||
ranking,
|
||||
presale,
|
||||
pointsMall,
|
||||
videos,
|
||||
signIn,
|
||||
hotspot,
|
||||
follow,
|
||||
appCenter,
|
||||
waterfallsFlow,
|
||||
activityModal,
|
||||
emptyPage,
|
||||
// #ifdef APP-PLUS
|
||||
appUpdate,
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN
|
||||
addTip,
|
||||
liveBroadcast,
|
||||
// #endif
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
__debugDiyRender: false,
|
||||
styleConfig: [],
|
||||
loading: false,
|
||||
loadend: false,
|
||||
loadTitle: '下拉加载更多', //提示语
|
||||
page: 1,
|
||||
limit: this.$config.LIMIT,
|
||||
numConfig: 0,
|
||||
code: '',
|
||||
isCouponShow: false,
|
||||
shareInfo: {},
|
||||
sortList: '',
|
||||
sortAll: [],
|
||||
goodPage: 1,
|
||||
goodList: [],
|
||||
sid: 0,
|
||||
curSort: 0,
|
||||
sortMpTop: 0,
|
||||
loaded: false,
|
||||
loading: false,
|
||||
domOffsetTop: 50,
|
||||
// #ifdef APP-PLUS || MP
|
||||
isFixed: true,
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
isFixed: false,
|
||||
// #endif
|
||||
site_config: '',
|
||||
errorNetwork: false, // 是否断网
|
||||
isHeaderSerch: false,
|
||||
showHomeComb: false,
|
||||
showCateNav: false,
|
||||
homeCombData:{},
|
||||
headerSerchCombData:{},
|
||||
cateNavData:{},
|
||||
bgColor: '',
|
||||
bgPic: '',
|
||||
bgTabVal: '',
|
||||
pageShow: true,
|
||||
windowHeight: 0,
|
||||
imgHost: HTTP_REQUEST_URL,
|
||||
isShowAuth: false,
|
||||
isScrolled: false,
|
||||
product_video_status: false,
|
||||
confirm_video_status: false,
|
||||
isFooter: false,
|
||||
pullReset: 0,
|
||||
configData: Cache.get('BASIC_CONFIG') || {},
|
||||
};
|
||||
},
|
||||
onLoad(options) {
|
||||
let that = this;
|
||||
this.__debugDiyRender = uni.getStorageSync('DEBUG_DIY_RENDER') === true
|
||||
that.getOptions(options);
|
||||
this.$nextTick(function() {
|
||||
uni.getSystemInfo({
|
||||
success: function(res) {
|
||||
that.windowHeight = res.windowHeight;
|
||||
}
|
||||
});
|
||||
})
|
||||
const {state, scope} = options;
|
||||
let identity = this.$store.state.app.identity;
|
||||
if(identity == 1 && this.isLogin){
|
||||
uni.redirectTo({
|
||||
url: "/pages/merchant/index/goods"
|
||||
})
|
||||
}else if(identity == 2 && this.isLogin){
|
||||
uni.redirectTo({
|
||||
url:"/pages/admin/work/index"
|
||||
})
|
||||
}else{
|
||||
this.diyData();
|
||||
}
|
||||
|
||||
// #ifdef H5
|
||||
this.setOpenShare();
|
||||
// #endif
|
||||
// #ifdef MP
|
||||
this.getTemlIds();
|
||||
// #endif
|
||||
getShare().then(res => {
|
||||
this.shareInfo = res.data;
|
||||
});
|
||||
},
|
||||
onShow() {
|
||||
if (this.cartNum > 0) {
|
||||
uni.setTabBarBadge({
|
||||
index: 3,
|
||||
text: this.cartNum > 99 ? '99+' : this.cartNum + ''
|
||||
})
|
||||
} else {
|
||||
uni.hideTabBarRedDot({
|
||||
index: 3
|
||||
})
|
||||
}
|
||||
uni.removeStorageSync('form_type_cart')
|
||||
},
|
||||
methods: {
|
||||
__logDiy(step, payload) {
|
||||
if (!this.__debugDiyRender) return;
|
||||
const safe = payload === undefined ? '' : payload
|
||||
console.log('[DIY][home]', step, safe)
|
||||
},
|
||||
...mapMutations(['SET_AUTOPLAY']),
|
||||
getOptions(options) {
|
||||
let that = this;
|
||||
// #ifdef MP
|
||||
if (options.scene) {
|
||||
let value = that.$util.getUrlParams(decodeURIComponent(options.scene));
|
||||
//记录推广人uid
|
||||
if (value.spid) app.globalData.spid = value.spid;
|
||||
}
|
||||
// #endif
|
||||
if (options.spid) app.globalData.spid = options.spid;
|
||||
},
|
||||
// 重新链接
|
||||
reconnect() {
|
||||
this.diyData();
|
||||
getShare().then(res => {
|
||||
this.shareInfo = res.data;
|
||||
});
|
||||
},
|
||||
goICP() {
|
||||
// #ifdef H5
|
||||
window.open('http://beian.miit.gov.cn/');
|
||||
// #endif
|
||||
// #ifdef MP
|
||||
uni.navigateTo({
|
||||
url: `/pages/annex/web_view/index?url=https://beian.miit.gov.cn/`
|
||||
});
|
||||
// #endif
|
||||
},
|
||||
bindHeighta(data) {
|
||||
// #ifdef APP-PLUS
|
||||
this.sortMpTop = data.top + data.height;
|
||||
// #endif
|
||||
},
|
||||
bindHeight(data) {
|
||||
uni.hideLoading();
|
||||
this.domOffsetTop = data.top;
|
||||
},
|
||||
// 分类点击
|
||||
changeSort(item, index) {
|
||||
if (this.curSort == index) return;
|
||||
this.curSort = index;
|
||||
this.sid = item.id;
|
||||
this.goodList = [];
|
||||
this.goodPage = 1;
|
||||
this.loaded = false;
|
||||
this.getGoodsList();
|
||||
},
|
||||
/**
|
||||
* @param data {
|
||||
classPage: 0 分类id
|
||||
microPage: 0 微页面id
|
||||
type: 1 0 微页面 1 商品分类
|
||||
}*/
|
||||
bindSortId(data) {
|
||||
this.styleConfig = [];
|
||||
this.loaded = false;
|
||||
if (data.type == 1) {
|
||||
this.getProductList(data.classPage);
|
||||
}else{
|
||||
this.sortList = [];
|
||||
this.getMicroPage(data.microPage, true);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 获取DIY
|
||||
* @param {number} id
|
||||
* @param {boolean} type 区分是否是微页面
|
||||
*/
|
||||
getMicroPage(id, type) {
|
||||
let that = this;
|
||||
that.__logDiy('micro_fetch_start', { id })
|
||||
that.styleConfig = [];
|
||||
that.goodList = [];
|
||||
uni.showLoading({
|
||||
title: '加载中...'
|
||||
});
|
||||
getDiy(id).then(res => {
|
||||
uni.hideLoading();
|
||||
let data = res.data;
|
||||
let diyArr = that.objToArr(res.data.value);
|
||||
that.__logDiy('micro_fetch_ok', { title: data?.title, count: diyArr.length, names: diyArr.map(v => v?.name) })
|
||||
diyArr = diyArr.filter(item => item.isHide !== '1');
|
||||
diyArr.forEach((item,index) => {
|
||||
if(['headerSerch','homeComb'].includes(item.name)){
|
||||
diyArr.splice(index, 1);
|
||||
}
|
||||
});
|
||||
this.styleConfig = diyArr;
|
||||
this.$nextTick(() => {
|
||||
this.__logDiy('micro_render_nextTick', { count: this.styleConfig.length, names: this.styleConfig.map(v => v?.name) })
|
||||
})
|
||||
}).catch(err => {
|
||||
return that.$util.Tips({
|
||||
title: err
|
||||
});
|
||||
uni.hideLoading();
|
||||
});
|
||||
},
|
||||
getProductList(data) {
|
||||
let tempObj = '';
|
||||
this.curSort = 0;
|
||||
this.loaded = false;
|
||||
if (this.sortAll.length > 0) {
|
||||
this.sortAll.forEach((el, index) => {
|
||||
if (el.id == data) {
|
||||
this.$set(this, 'sortList', el);
|
||||
this.sid = el.children.length ? el.children[0].id : '';
|
||||
}
|
||||
});
|
||||
this.goodList = [];
|
||||
this.goodPage = 1;
|
||||
this.$nextTick(() => {
|
||||
if (this.sortList != '') this.getGoodsList();
|
||||
});
|
||||
} else {
|
||||
getCategoryList().then(res => {
|
||||
this.sortAll = res.data;
|
||||
res.data.forEach((el, index) => {
|
||||
if (el.id == data) {
|
||||
this.sortList = el;
|
||||
this.sid = el.children.length ? el.children[0].id : '';
|
||||
}
|
||||
});
|
||||
this.goodList = [];
|
||||
this.goodPage = 1;
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (this.sortList != '') this.getGoodsList();
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
// 商品列表
|
||||
getGoodsList() {
|
||||
if (this.loading || this.loaded) return;
|
||||
this.loading = true;
|
||||
getProductslist({
|
||||
sid: this.sid,
|
||||
keyword: '',
|
||||
priceOrder: '',
|
||||
salesOrder: '',
|
||||
news: 0,
|
||||
page: this.goodPage,
|
||||
limit: 10,
|
||||
cid: this.sortList.id
|
||||
}).then(res => {
|
||||
this.loading = false;
|
||||
this.loaded = res.data.length < 10;
|
||||
this.goodPage++;
|
||||
this.goodList = this.goodList.concat(res.data);
|
||||
});
|
||||
},
|
||||
// #ifdef MP
|
||||
getTemlIds() {
|
||||
let messageTmplIds = wx.getStorageSync(SUBSCRIBE_MESSAGE);
|
||||
if (!messageTmplIds) {
|
||||
getTemlIds().then(res => {
|
||||
if (res.data) wx.setStorageSync(SUBSCRIBE_MESSAGE, JSON.stringify(res.data));
|
||||
});
|
||||
}
|
||||
},
|
||||
// #endif
|
||||
// 对象转数组
|
||||
objToArr(data) {
|
||||
let obj = Object.keys(data).sort();
|
||||
let m = obj.map(key => data[key]);
|
||||
return m;
|
||||
},
|
||||
setDiyData(data) {
|
||||
this.__logDiy('home_setDiyData_start', { title: data?.title })
|
||||
this.errorNetwork = false
|
||||
if (data.is_bg_color) {
|
||||
this.bgColor = data.color_picker
|
||||
}
|
||||
if (data.is_bg_pic) {
|
||||
this.bgPic = data.bg_pic
|
||||
this.bgTabVal = data.bg_tab_val
|
||||
}
|
||||
this.pageShow = data.is_show
|
||||
uni.setNavigationBarTitle({
|
||||
title: data.title
|
||||
});
|
||||
let temp = [];
|
||||
let lastArr = this.objToArr(data.value);
|
||||
lastArr.forEach((item, index, arr) => {
|
||||
if (item.name === 'homeComb') {
|
||||
this.showHomeComb = true
|
||||
this.homeCombData = item;
|
||||
}
|
||||
if (item.name == 'headerSerch') {
|
||||
this.isHeaderSerch = true;
|
||||
this.headerSerchCombData = item;
|
||||
}
|
||||
if (item.name == 'tabNav') {
|
||||
this.showCateNav = true;
|
||||
this.cateNavData = item;
|
||||
}
|
||||
|
||||
if (item.isHide !== '1') {
|
||||
temp.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
function sortNumber(a, b) {
|
||||
return a.timestamp - b.timestamp;
|
||||
}
|
||||
temp.sort(sortNumber)
|
||||
this.styleConfig = temp;
|
||||
this.__logDiy('home_setDiyData_done', { count: this.styleConfig.length, names: this.styleConfig.map(v => v?.name) })
|
||||
this.$nextTick(() => {
|
||||
this.__logDiy('home_render_nextTick', { count: this.styleConfig.length, names: this.styleConfig.map(v => v?.name) })
|
||||
})
|
||||
},
|
||||
getDiyData() {
|
||||
this.__logDiy('home_fetch_start', { id: 0 })
|
||||
getDiy(0).then(res => {
|
||||
this.__logDiy('home_fetch_ok', { title: res?.data?.title, keys: Object.keys(res?.data?.value || {}).length })
|
||||
uni.setStorageSync('diyData', JSON.stringify(res.data));
|
||||
this.setDiyData(res.data);
|
||||
}).catch(error => {
|
||||
// #ifdef APP-PLUS
|
||||
if (error.status) {
|
||||
uni.hideLoading()
|
||||
if (this.errorNetwork) {
|
||||
uni.showToast({
|
||||
title: '请开启网络连接',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
this.errorNetwork = true;
|
||||
}
|
||||
// #endif
|
||||
});
|
||||
},
|
||||
diyData() {
|
||||
let diyData = uni.getStorageSync('diyData');
|
||||
if (diyData) {
|
||||
getDiyVersion(0).then(res => {
|
||||
let diyVersion = uni.getStorageSync('diyVersion');
|
||||
if ((res.data.version + '0') === diyVersion) {
|
||||
this.setDiyData(JSON.parse(diyData));
|
||||
} else {
|
||||
uni.setStorageSync('diyVersion', (res.data.version + '0'));
|
||||
this.getDiyData();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.getDiyData();
|
||||
}
|
||||
},
|
||||
changeLogin() {
|
||||
this.getIsLogin();
|
||||
},
|
||||
getIsLogin() {
|
||||
toLogin()
|
||||
},
|
||||
changeBarg(item) {
|
||||
if (!this.isLogin) {
|
||||
this.getIsLogin();
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: `/pages/activity/goods_bargain_details/index?id=${item.id}&spid=${this.$store.state.app.uid}`
|
||||
});
|
||||
}
|
||||
},
|
||||
goDetail(item) {
|
||||
goShopDetail(item, this.$store.state.app.uid).catch(res => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/goods_details/index?id=${item.id}`
|
||||
});
|
||||
});
|
||||
},
|
||||
newDataStatus(val) {
|
||||
this.isFooter = val ? true : false;
|
||||
},
|
||||
checked(){
|
||||
console.log('点击了')
|
||||
},
|
||||
// #ifdef H5
|
||||
// 微信分享;
|
||||
setOpenShare: function() {
|
||||
let that = this;
|
||||
let uid = this.uid ? this.uid : 0;
|
||||
if (that.$wechat.isWeixin()) {
|
||||
getShare().then(res => {
|
||||
let data = res.data;
|
||||
let configAppMessage = {
|
||||
desc: data.synopsis,
|
||||
title: data.title,
|
||||
link: location.href + '?spid=' + uid,
|
||||
imgUrl: data.img
|
||||
};
|
||||
that.$wechat.wechatEvevt(['updateAppMessageShareData', 'updateTimelineShareData',
|
||||
'onMenuShareAppMessage', 'onMenuShareTimeline'
|
||||
],
|
||||
configAppMessage);
|
||||
});
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
onReachBottom() {
|
||||
if(this.goodList.length){
|
||||
this.getGoodsList();
|
||||
}
|
||||
},
|
||||
onPullDownRefresh() {
|
||||
this.goodList = [];
|
||||
this.sortList = [];
|
||||
this.diyData();
|
||||
this.pullReset = 1;
|
||||
setTimeout(function () {
|
||||
uni.stopPullDownRefresh();
|
||||
}, 1000);
|
||||
},
|
||||
onPageScroll(e) {
|
||||
// #ifdef H5
|
||||
if (this.isHeaderSerch) {
|
||||
if (e.scrollTop > this.domOffsetTop) {
|
||||
this.isFixed = true;
|
||||
}
|
||||
if (e.scrollTop < this.domOffsetTop) {
|
||||
this.$nextTick(() => {
|
||||
this.isFixed = false;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.isFixed = false
|
||||
}
|
||||
// #endif
|
||||
if (e.scrollTop > 10) {
|
||||
this.isScrolled = true;
|
||||
} else {
|
||||
this.isScrolled = false;
|
||||
}
|
||||
uni.$emit('scroll');
|
||||
uni.$emit('onPageScroll', e.scrollTop);
|
||||
},
|
||||
//#ifdef MP
|
||||
onShareAppMessage() {
|
||||
let uid = this.uid ? this.uid : 0;
|
||||
if(this.shareInfo.img){
|
||||
return {
|
||||
title: this.shareInfo.title,
|
||||
path: '/pages/index/index?spid=' + uid,
|
||||
imageUrl: this.shareInfo.img,
|
||||
desc: this.shareInfo.synopsis
|
||||
};
|
||||
}else{
|
||||
return {
|
||||
title: this.shareInfo.title,
|
||||
path: '/pages/index/index?spid=' + uid
|
||||
// imageUrl: this.shareInfo.img,
|
||||
// desc: this.shareInfo.synopsis
|
||||
};
|
||||
}
|
||||
|
||||
},
|
||||
//分享到朋友圈
|
||||
onShareTimeline() {
|
||||
let uid = this.uid ? this.uid : 0;
|
||||
return {
|
||||
title: this.shareInfo.title,
|
||||
path: '/pages/index/index?spid=' + uid,
|
||||
imageUrl: this.shareInfo.img,
|
||||
desc: this.shareInfo.synopsis
|
||||
};
|
||||
}
|
||||
//#endif
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
// page {
|
||||
// padding-bottom: 50px;
|
||||
// }
|
||||
.pictrue_log_class {
|
||||
background-color: var(--view-theme);
|
||||
}
|
||||
|
||||
.ysize {
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.fullsize {
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.repeat {
|
||||
background-repeat: repeat;
|
||||
}
|
||||
|
||||
.noRepeat {
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.o813d0 {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding-top: 40rpx;
|
||||
background: #fff;
|
||||
|
||||
image {
|
||||
width: 414rpx;
|
||||
height: 336rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
position: relative;
|
||||
top: -40rpx;
|
||||
font-size: 32rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.of0b21 {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
|
||||
.label {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.item {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 508rpx;
|
||||
height: 86rpx;
|
||||
margin-top: 100rpx;
|
||||
border: 1px solid #D74432;
|
||||
color: #E93323;
|
||||
font-size: 30rpx;
|
||||
border-radius: 120rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.sort-scroll {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.sort-product {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.site-config {
|
||||
margin: 40rpx 0;
|
||||
font-size: 24rpx;
|
||||
text-align: center;
|
||||
color: #666;
|
||||
|
||||
&.fixed {
|
||||
position: fixed;
|
||||
bottom: 69px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.select{
|
||||
border: 1px solid var(--view-theme);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user