Files
frontend-app/pages/home/home.vue
T
2026-09-09 11:46:36 +08:00

1981 lines
54 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="home_warp" :class="platformType ? '' : 'iosplatformType'" @scroll="onScroll">
<!-- 变色搜索栏 -->
<view class="header_title_warp" :class="{ 'is-scrolled': isScrolled }" :style="headerContainerStyle">
<view class="language_warp" style="flex: 1; justify-content: flex-start;" :style="languageBoxStyle"
@click.stop="jumpSearch">
<view class="search_icon_box">
<image src="https://static.tbmall.xin/static/home/search_b.png" class="tab-icon"></image>
</view>
<text class="search_msg_warp" :style="searchMsgStyle">搜索</text>
</view>
<view class="message-entry" @click.stop="jumpNewSearch('list')">
<image src="https://static.tbmall.xin/static/chart.png" class="chart_img" :style="chartImgStyle"></image>
<text v-if="kefuUnreadCount > 0" class="message-entry-badge">{{ formatKefuBadge(kefuUnreadCount) }}</text>
</view>
</view>
<!-- 页面内容容器 -->
<view class="home_content_z_warp">
<!-- 轮播 Banner 区域 (整个紫色区域包含文案背景均为 Banner 图,延伸至头部安全区) -->
<view class="home_header_warp">
<view class="banner_swiper_container" v-if="swiperList && swiperList.length > 0">
<up-swiper :list="swiperList" height="480rpx" radius="0" @change="e => currentNum = e.current"
bgColor="#ffffff00" @click="onSwiper">
<template #indicator>
<view class="indicator-dots" v-if="swiperList.length > 1">
<view v-for="(item, index) in swiperList.length" :key="index" class="indicator-dot"
:class="{ active: currentNum === index }"></view>
</view>
</template>
</up-swiper>
</view>
<view v-else class="banner_placeholder">
<up-swiper :list="['https://static.tbmall.xin/static/logo_banner2.png']" height="230" radius="0"
bgColor="#ffffff00"></up-swiper>
</view>
</view>
<!-- 分类(覆盖在Banner上) -->
<view class="home_sort_warp">
<view class="sort_comm_warp" v-if="sortList && sortList.length !== 0 && isBlockedDate">
<view v-for="item in sortList" :key="item.id" class="sort_item_comm" @click.stop="jumpSort(item)">
<up-image :src="item.icon" width="100rpx" height="72rpx" bgColor="#f1f6ff00"></up-image>
<view class="sort_item_title_comm">{{ item.name }}</view>
</view>
</view>
<view v-else class="not_order_warp">
<up-image src="https://static.tbmall.xin/static/not_order.png" width="80" height="80"
bgColor="#f1f6ff00"></up-image>
<view class="not_order_msg_warp">暂无分类</view>
</view>
</view>
<!-- 爆款专区-->
<view class="home_content_warp Hot_Picks_Zone" v-if="faddishProduct && faddishProduct.length !== 0"
@click="onJumpYou">
<view class="product_comm_yp">
<view class="yp_title">
<view class="yp_title_left">
<text class="yp_title_main">信任桥优品</text>
<up-image src="https://static.tbmall.xin/static/home/youxuan.png" width="14" height="14"
bgColor="#f1f6ff00"></up-image>
<text class="yp_title_sub" style="margin-left: 8rpx">品牌五折秒杀福利</text>
</view>
<view class="yp_title_right">
<text>立即抢购</text>
<view class="yp_arrow_circle">
<view class="yp_arrow_chevron"></view>
</view>
</view>
</view>
<view class="yp_content">
<view class="yp_item" v-for="item in faddishProduct" :key="item.id" @click.stop="jumpInfo(item)">
<view class="yp_item_image_wrapper">
<image :src="item.url" mode="cover" lazy-load class="yp_item_image"></image>
</view>
<view class="yp_item_info">
<view class="yp_item_name">{{ item.title }}</view>
<view class="yp_item_price_tag">优选价{{ item.price }}元</view>
</view>
</view>
</view>
</view>
</view>
<!-- 带灰色背景的内容 -->
<view class="home_content_warp Hot_Picks_content">
<!-- 积分兑换,红包抽奖 -->
<view class="min_card_warp">
<!-- 积分兑换 -->
<view class="min_card_item" @click="jumpIntegral">
<!-- <up-image src="https://static.tbmall.xin/static/home/min_card_jfdh.png" width="60" height="14" bgColor="#f1f6ff00" ></up-image> -->
<view class="min_card_item_content">
<view class="min_card_item_title">积分兑换</view>
<view class="content_msg">
<view>好物随心兑</view>
</view>
</view>
<up-image src="https://static.tbmall.xin/static/home/min_card_jfdh_2.png" width="55" height="55"
bgColor="#f1f6ff00"></up-image>
</view>
<!-- 红包抽奖 -->
<view class="min_card_item" @click="jumpTurntable">
<!-- <up-image src="https://static.tbmall.xin/static/home/min_card_hbcj.png" width="60" height="14" bgColor="#f1f6ff00" ></up-image> -->
<view class="min_card_item_content">
<view class="min_card_item_title">红包抽奖</view>
<view class="content_msg">
<view>现金红包等你拿!</view>
</view>
</view>
<up-image src="https://static.tbmall.xin/static/home/min_card_hbcj_2.png" width="55" height="55"
bgColor="#f1f6ff00"></up-image>
</view>
</view>
<view @click="aaa">亲星星</view>
<view class="home_actived_warp">
<view class="home_actived_item_warp" v-for="item in homeActivedList" :key="item.id">
<view class="home_actived_item">
<view class="product_comm_tip" @click="jumpPage(item.path)">
<view class="product_comm_tip_left">
<image class="uni-image" :src="item.title_icon"></image>
<view :class="[
activedTabId === 'actived'
? 'tip_title '
: 'tip_title_lable',
]" style="margin-right: 10rpx" v-if="item.title_text" @click.stop="jumpTab(item, 'seckill')">{{
item.title_text }}</view>
<view v-if="item.activedType === 'seckill'" :class="[
activedTabId === 'seckill'
? 'tip_title '
: 'tip_title_lable',
]" @click.stop="jumpTab(item, 'actived')">{{ item.title }}</view>
<view v-else class="tip_title_lable">{{ item.title }}</view>
</view>
<view class="product_comm_tip_right">{{ item.rightText }}
<image class="uni-image" src="/static/common/right.png"></image>
<!-- <up-image src="/static/common/right.png" width="15" height="15" bgColor="#f1f6ff00"></up-image> -->
</view>
</view>
<!-- 限时秒杀 -->
<view v-if="item.activedType === 'seckill'">
<view class="product_seckill_card" v-for="ele in seckillGoodsList" :key="ele.id">
<productSeckillCard :item="ele" :actived-type="seckillActivedType" :attributes='attributes' />
</view>
</view>
<!-- 超级补贴 -->
<view v-if="item.activedType === 'super'">
<view class="product_seckill_card" v-for="ele in superGoodsList" :key="ele.id">
<productSeckillCard :item="ele" :actived-type="item.activedType" />
</view>
</view>
</view>
</view>
<!-- 为您精选 -->
<choiceness />
</view>
</view>
</view>
<!-- 暂未开放 -->
<up-modal :show="openShow" :showConfirmButton="false">
<view class="slot-content">
<view class="close_warp" @click="openShow = false">
<up-image src="/static/common/close.png" width="20" height="20" bgColor="#f1f6ff00"></up-image>
</view>
<view class="content_">
<view class="content_1">温馨提示</view>
<view class="content_2">暂未开放</view>
</view>
<view class="but_">
<view class="but_copy" @click="openShow = false">确定</view>
</view>
</view>
</up-modal>
<!-- #ifndef H5 || MP-WEIXIN-->
<CustomTabBar :tabIndex="0" />
<!-- #endif -->
<up-overlay :show="bannerShow">
<view class="up_content" @tap.stop>
<view class="uni-banner">
<view class="close_btn" v-if="!updateApkObj.isForce" @click="onCloseBannerShow"></view>
<view class="banner_box">
<view class="conter">{{ updateApkObj.content }}</view>
<view class="banner_foot" v-if="!bannerPercentageShow">
<button @click="goUpdate(updateApkObj, platformType)" class="banner_foot_button">
立即更新
</button>
<view @click="bannerShow = false" class="banner_foot_button_no" v-if="!updateApkObj.isForce">暂不更新
</view>
</view>
<view v-else>
<up-line-progress :percentage="bannerPercentage" activeColor="#a85cfa"></up-line-progress>
<view class="banner_loading_msg">
更新中{{ bannerPercentage }}%
</view>
</view>
</view>
</view>
</view>
</up-overlay>
<!-- 公告弹窗 -->
<up-overlay :show="newsShow">
<view class="up_content" @tap.stop>
<view class="uni-banner-news">
<view class="close_btn" @click="newsShow = false"></view>
<view class="banner_box">
<view class="banner_box-title">{{ newsList[0]?.title }}</view>
<view class="banner_box-subTitle">{{ newsList[0]?.subTitle }}</view>
<view class="banner_box-btn" @click="jumpNewSearch">查看</view>
</view>
</view>
</view>
</up-overlay>
<!-- 专属优惠券弹窗 -->
<up-overlay :show="showCouponPop" @click="showCouponPop = false" zIndex="10090">
<view class="coupon_pop_wrapper">
<view class="coupon_pop_card" @tap.stop>
<!-- 头部标题与关闭按钮 -->
<view class="coupon_pop_header">
<view class="coupon_pop_title">专属优惠券已到账</view>
<view class="coupon_pop_close" @click="showCouponPop = false">
<text class="close_x">✕</text>
</view>
</view>
<!-- 优惠券列表 -->
<scroll-view class="coupon_pop_list" scroll-y>
<view class="coupon_item" v-for="(item, index) in popCouponList"
:key="item.couponUserId || item.templateId || index">
<!-- 左侧金额与门槛 -->
<view class="coupon_left">
<view class="price_wrap">
<text class="currency">¥</text>
<text class="amount">{{ item.discountAmount }}</text>
</view>
<view class="threshold_tag">{{ formatThresholdText(item) }}</view>
</view>
<!-- 垂直虚线分割线 -->
<view class="coupon_divider">
<view class="notch notch_top"></view>
<view class="dashed_line"></view>
<view class="notch notch_bottom"></view>
</view>
<!-- 右侧优惠券信息 -->
<view class="coupon_right">
<view class="coupon_name">{{ item.title || '限时秒杀优惠券' }}</view>
<view class="coupon_scope_box">
<text class="scope_badge">{{ formatScopeBadge(item) }}</text>
<text class="scope_text">{{ item.scopeText || (item.scopeType === 1 ? '所有商品可用' : '部分商品可用') }}</text>
</view>
<view class="coupon_validity">{{ formatValidityText(item) }}</view>
</view>
</view>
</scroll-view>
<!-- 立即收下按钮 -->
<view class="coupon_pop_btn" @click="showCouponPop = false">
立即收下
</view>
<!-- 底部说明文案 -->
<view class="coupon_pop_tip">
优惠券详情可在【我的-优惠券】中查看
</view>
</view>
</view>
</up-overlay>
<HomePopup :show="homeShow" :dataObj="curData" @jumpShop="onJumpShop" @close="homeShow = false"></HomePopup>
<GuidePopup />
<qiaobao-assistant page-key="pages/home/home" title="商城首页" />
</view>
</template>
<script>
import choiceness from "@/components/choiceness/choiceness.vue";
import {
getGoodsDetail,
searchList,
getSeckillCurrent,
getSeckillPreview,
getSeckillGoodsList,
getGoodsTags,
} from "@/api/product.js";
import { checkAppVersion, getCarouselImage } from "@/api/common.js";
import { SEARCH_TYPE, SORT_TYPE, APP_PAGE_TYPE } from "@/utils/enumUtils.js";
import CustomTabBar from "@/components/custom-tab-bar.vue"; // 引入自定义组件路径可能需要根据项目结构调整
import dayjs from "dayjs";
import useTabber from "tabber-component";
import { getNewsList } from "@/api/news.js";
import { comparisonVersionHandler } from "@/utils/index.js";
import HomePopup from "@/components/common/home-popup.vue";
import GuidePopup from "@/components/common/guide-popup.vue";
import productSeckillCard from "@/components/common/product-seckill-card.vue";
import { SHARE_URL } from "@/utils/config.js";
import { getUnreadCount as getKefuUnreadCount } from "@/uni_modules/hashmall-customer-service/js_sdk/api.js";
import {
KEFU_REALTIME_EVENT,
startKefuRealtime,
} from "@/uni_modules/hashmall-customer-service/js_sdk/kefu-realtime.js";
import { getStorageFun, TOKEN_NAME, USER_DATA } from "@/utils/auth.js";
import { getPopNotifyList } from "@/api/coupon.js";
export default {
components: {
choiceness,
CustomTabBar,
HomePopup,
GuidePopup,
productSeckillCard,
},
data() {
return {
swiperList: [],
currentNum: 0,
sortList: [],
faddishProduct: [], // 爆款专区
productLoading: false,
openShow: false,
platformType: null, // 当前设备信息
bannerShow: false, // 是否需要強制更新app
type: "", // 设备类型 android:2, ios:1
updateApkObj: {}, // 后台数据
bannerPercentageShow: false, // 是否显示进度条
bannerPercentage: 0, // 进度条
curId: null,
curData: null,
homeShow: false,
newsList: [], // 公告列表
newsShow: false, // 是否显示公告弹窗
seckillGoodsList: [], // 秒杀商品列表
superGoodsList: [], // 超级补贴商品列表
homeActivedList: [{
id: 1,
title: "超级补贴",
title_icon: "https://static.tbmall.xin/static/new-home/home_9.png",
path: "super-subsidy",
rightText: "官方补贴 .100%正品",
activedType: "super",
},
{
id: 2,
title: "活动预告",
title_text: "限时秒杀",
title_icon: "https://static.tbmall.xin/static/new-home/home_10.png",
path: "limited-time",
rightText: "专属补贴 . 低价秒杀",
activedType: "seckill",
}
], // 首页活动列表
activedTabId: "seckill", // 当前选中的活动类型
attributes: {},
seckillActivedType: 'seckill',
isMP: false,
mpHeaderWarpStyle: {},
mpHeaderStyle: {},
mpLanguageStyle: {},
kefuUnreadCount: 0,
kefuUnreadRefreshTimer: null,
isScrolled: false,
scrollTop: 0,
showCouponPop: false,
popCouponList: [],
};
},
onPageScroll(e) {
const top = this.getScrollTop(e);
this.scrollTop = top;
this.isScrolled = top > 10;
},
onShow() {
this.refreshKefuUnread();
startKefuRealtime();
// 获取设备是安卓还是ios
const appUpdate = uni.getStorageSync("platform");
const versionUpdateTime = uni.getStorageSync("versionUpdateTime");
// #ifdef APP-PLUS
console.log(
"上次更新时间 versionUpdateTime",
dayjs(versionUpdateTime).format("YYYY-MM-DD HH:mm:ss"),
);
console.log("当前时间戳", dayjs().format("YYYY-MM-DD HH:mm:ss"));
const time1 = dayjs(versionUpdateTime); // 上一次更新的时间
const time2 = dayjs();
const diff = time2.diff(time1);
if (!versionUpdateTime || diff > 5 * 60 * 1000) {
this.platformType = appUpdate == "android" ? "ANDROID" : "IOS";
this.checkUpdate(); // 判断是否需要更新
} else {
this.onClipboard();
}
// #endif
this.getSortList();
this.querySearchList(SEARCH_TYPE.EXPLOSIVE); // 爆单专区
this.onNews(); // 获取公告
this.getCarouselImage();
this.fetchPopNotifyList(); // 获取专属优惠券弹窗通知
// 秒杀
this.onGetSeckillCurrent();
this.onGetSuperGoodsList();
},
onLoad() {
uni.$on(KEFU_REALTIME_EVENT, this.handleKefuRealtimeEvent);
/*#ifdef APP-PLUS*/
uni.hideTabBar({
animation: false,
});
/*#endif*/
// #ifdef MP
this.isMP = true;
this.initMPHeader();
// #endif
},
// 分享给朋友
onShareAppMessage() {
return {
title: "TB聚合商城",
path: "/pages/home/home",
};
},
// 分享到朋友圈
onShareTimeline() {
return {
title: "TB聚合商城",
query: "",
};
},
onUnload() {
uni.$off(KEFU_REALTIME_EVENT, this.handleKefuRealtimeEvent);
if (this.kefuUnreadRefreshTimer) clearTimeout(this.kefuUnreadRefreshTimer);
this.kefuUnreadRefreshTimer = null;
},
mounted() {
// #ifdef H5
window.addEventListener("scroll", this.handleWindowScroll, true);
const pageBody = document.querySelector("uni-page-body");
if (pageBody) {
pageBody.addEventListener("scroll", this.handleWindowScroll, true);
}
// #endif
},
beforeUnmount() {
// #ifdef H5
window.removeEventListener("scroll", this.handleWindowScroll, true);
const pageBody = document.querySelector("uni-page-body");
if (pageBody) {
pageBody.removeEventListener("scroll", this.handleWindowScroll, true);
}
// #endif
},
methods: {
aaa() {
uni.navigateTo({
url: '/pages/other_package/douyin_pay_test/douyin_pay_test'
});
},
getScrollTop(e) {
let top = 0;
if (typeof e === "number") {
top = e;
} else if (e && typeof e.scrollTop !== "undefined") {
top = e.scrollTop;
} else if (e && e.detail && typeof e.detail.scrollTop !== "undefined") {
top = e.detail.scrollTop;
}
// #ifdef H5
if (!top) {
const pageBody = document.querySelector("uni-page-body");
const pageWrapper = document.querySelector("uni-page-wrapper");
const homeWarp = document.querySelector(".home_warp");
top = Math.max(
window.pageYOffset || 0,
window.scrollY || 0,
document.documentElement?.scrollTop || 0,
document.body?.scrollTop || 0,
pageBody?.scrollTop || 0,
pageWrapper?.scrollTop || 0,
homeWarp?.scrollTop || 0
);
}
// #endif
return top;
},
handleWindowScroll(e) {
const top = this.getScrollTop(e);
this.scrollTop = top;
this.isScrolled = top > 10;
},
onScroll(e) {
const top = this.getScrollTop(e);
this.scrollTop = top;
this.isScrolled = top > 10;
},
// 查询轮播图
async getCarouselImage() {
const params = {
pageUi: APP_PAGE_TYPE.HOME,
};
const resp = await getCarouselImage(params);
if (resp && resp.bizcode === 100) {
const data = resp.data || [];
this.swiperDataList = data;
this.swiperList =
data.length !== 0 ? data.map((obj) => obj.carouselImage) : [];
}
},
onSwiper(index) {
console.log("--1---", this.swiperDataList[index])
const id = this.swiperDataList[index]?.goodsUrl;
if (!id) return;
uni.navigateTo({
url: `/pages/other_package/productInfo/productInfo?id=${id}`,
});
},
formatKefuBadge(value) {
return Number(value) > 99 ? "99+" : String(Number(value) || 0);
},
resolveKefuUserId() {
const value = getStorageFun(USER_DATA);
if (!value) return null;
let member = value;
if (typeof value !== "object") {
try {
member = JSON.parse(value);
} catch (error) {
return null;
}
}
return member && (member.id || member.userId);
},
async refreshKefuUnread() {
if (!getStorageFun(TOKEN_NAME)) {
this.kefuUnreadCount = 0;
return;
}
const userId = this.resolveKefuUserId();
if (!userId) return;
try {
this.kefuUnreadCount = await getKefuUnreadCount(userId);
} catch (error) {
// Keep the last known number during a temporary network interruption.
}
},
handleKefuRealtimeEvent(event) {
if (!event || !String(event.type || "").startsWith("kefu_")) return;
if (this.kefuUnreadRefreshTimer) clearTimeout(this.kefuUnreadRefreshTimer);
this.kefuUnreadRefreshTimer = setTimeout(() => {
this.kefuUnreadRefreshTimer = null;
this.refreshKefuUnread();
}, 120);
},
jumpMessageCenter() {
uni.navigateTo({
url: "/packages/message/message",
});
},
initMPHeader() {
// #ifdef MP-WEIXIN || MP
try {
const menuButton = uni.getMenuButtonBoundingClientRect();
const systemInfo = uni.getSystemInfoSync();
if (menuButton && menuButton.top && menuButton.top > 0) {
const menuButtonHeight = menuButton.height || 32;
const menuButtonTop = menuButton.top;
const menuButtonLeft = menuButton.left;
const windowWidth = systemInfo.windowWidth;
const rightPadding = windowWidth - menuButtonLeft + 10;
this.mpHeaderStyle = {
paddingTop: `${menuButtonTop}px`,
paddingRight: `${rightPadding}px`,
paddingLeft: '12px',
paddingBottom: '8px',
height: `${menuButtonHeight}px`,
boxSizing: 'content-box',
display: 'flex',
alignItems: 'center'
};
this.mpLanguageStyle = {
height: `${menuButtonHeight}px`,
borderRadius: `${menuButtonHeight / 2}px`,
boxSizing: 'border-box',
display: 'flex',
alignItems: 'center'
};
}
} catch (e) {
console.error("initMPHeader error:", e);
}
// #endif
},
// 切换活动类型
jumpTab(item, type) {
if (this.activedTabId === type) return;
this.activedTabId = type;
// this.attributes = { activeSeckillType: type }
this.seckillActivedType = type;
this.onGetSeckillCurrent();
},
// 获取秒杀
onGetSeckillCurrent() {
const url =
this.activedTabId === "seckill" ? getSeckillCurrent : getSeckillPreview;
console.log('获取秒杀----', this.activedTabId)
url().then((res) => {
console.log("获取秒杀", res);
if (res.bizcode === 100) {
this.seckillGoodsList = [];
if (res.data?.activityId) {
this.onGetSeckillGoodsList(res.data.activityId, "seckillGoodsList");
}
}
});
},
// 获取秒杀商品
onGetSeckillGoodsList(activityId, key) {
getSeckillGoodsList({
activityId: activityId,
page: 1,
pageSize: 3,
}).then((res) => {
console.log("获取秒杀商品", res);
if (res.bizcode === 100) {
this[key] = res.data.entitys || [];
console.log(this[key]);
}
});
},
jumpSearch() {
uni.navigateTo({
url: "/pages/rwa_package/insights/search",
});
},
// 商品列表
onGetSuperGoodsList() {
searchList({
type: -2,
page: 1,
pageSize: 3,
}).then((res) => {
console.log("商品列表", res);
if (res.bizcode === 100) {
this.superGoodsList = res.data || [];
console.log(this.superGoodsList);
}
});
},
// 获取公告
jumpNewSearch(type) {
if (type === "list") {
uni.navigateTo({
url: "/pages/login_package/message/message",
});
return;
}
uni.setStorageSync("isReadNews", this.newsList[0].id);
uni.navigateTo({
url:
"/pages/login_package/announcement-detail/announcement-detail?id=" +
this.newsList[0].id,
});
},
onNews() {
getNewsList({
category: 2,
type: 0,
page: 1,
pageSize: 10,
}).then((res) => {
console.log("获取公告", res);
if (res.bizcode === 100) {
this.newsList = res.data.entitys || [];
console.log(this.newsList);
const id = uni.getStorageSync("isReadNews");
this.newsShow = false;
if (id != this.newsList[0].id && this.newsList[0].isPop === 1) {
this.newsShow = true;
}
}
});
},
// 查看详情
onJumpNews() {
uni.navigateTo({
url: `/pages/login_package/news/news?id=${this.newsList[0].id}`,
});
},
onJumpShop() {
uni.navigateTo({
url: `/pages/other_package/productInfo/productInfo?id=${this.curId}`,
});
this.curId = null;
this.curData = null;
this.homeShow = false;
},
onClipboard() {
let _this = this;
uni.getClipboardData({
success: function (res) {
// http://localhost:5173/#/pages/other_package/productInfo/productInfo?id=1038
console.log(res.data); // 剪贴板内容
if (
res.data.indexOf(
`${SHARE_URL}/#/pages/other_package/productInfo/productInfo?id=`,
) != -1
) {
uni.showModal({
title: "",
content: "当前APP想要粘贴商品详情,是否继续?",
success: (res1) => {
if (res1.confirm) {
let id = res.data.match(/=(.*?)\s/);
_this.curId = Number(id[1]);
_this.getShop();
uni.setClipboardData({
data: "",
});
}
},
fail: (res2) => {
uni.setClipboardData({
data: "",
});
},
});
}
},
fail: function (err) {
console.error("获取剪贴板内容失败", err);
},
});
},
getShop() {
const params = {
id: this.curId,
};
getGoodsDetail(params).then((res) => {
this.curData = res.data;
this.homeShow = true;
});
},
onJumpYou() {
uni.navigateTo({
url: "/pages/rwa_package/shop/preferred-shop",
});
},
checkUpdate() {
const self = this,
localAppVersonName = uni.getStorageSync("version"),
localAppVerson = uni.getStorageSync("versionCode");
// #ifdef APP-PLUS
plus.runtime.getProperty(plus.runtime.appid, function (widgetInfo) {
const params = {
terminal: self.platformType,
versionCode: localAppVerson,
};
console.log("wgt更新-0", params);
checkAppVersion(params).then((res) => {
console.log("wgt更新-1", res);
if (res && res.bizcode === 100) {
const data = res.data || {};
// app大版本更新,versionName:1.0.1 versionCode:102
if (
data &&
Object.keys(data).length !== 0 &&
comparisonVersionHandler(localAppVerson, data.versionCode)
) {
uni.hideTabBar(); // 隐藏首页底部tabbar 按钮
self.updateApkObj = data;
self.bannerShow = true; // 显示弹窗
return;
} else {
console.log("wgt更新-2");
self.onClipboard();
return;
}
}
});
});
// #endif
},
onCloseBannerShow() {
if (this.updateApkObj.isForce) {
// #ifdef APP-PLUS
if (uni.getSystemInfoSync().platform === 'android') {
plus.runtime.quit();
} else {
uni.showToast({
title: '请先更新到最新版本',
icon: 'none',
duration: 2000,
});
}
// #endif
} else {
this.bannerShow = false;
}
},
// 安装
goUpdate(updateApkObj, platformType) {
const self = this;
if (platformType == "ANDROID") {
// 弹出系统等待对话框
var dtask = plus.downloader.createDownload(
updateApkObj.downloadUrl,
{},
function (d, status) {
// 下载完成
if (status == 200) {
plus.runtime.install(
plus.io.convertLocalFileSystemURL(d.filename),
{
force: true,
},
function (resp) {
// 直接重启APP
uni.setStorageSync("versionUpdateTime", dayjs().valueOf()); // 记录升级的时间
plus.runtime.restart();
},
function (error) {
console.log("error", error);
uni.showToast({
title: error.message,
mask: false,
duration: 1500,
});
},
);
} else {
self.bannerPercentageShow = false;
uni.showToast({
title: "更新失败",
mask: false,
duration: 1500,
});
}
},
);
try {
dtask.start(); // 开启下载的任务
let prg = 0;
this.bannerPercentageShow = true;
dtask.addEventListener("statechanged", function (task, status) {
// 给下载任务设置一个监听 并根据状态 做操作
switch (task.state) {
case 1:
break;
case 2:
break;
case 3:
prg = parseInt(
(parseFloat(task.downloadedSize) /
parseFloat(task.totalSize)) *
100,
);
self.bannerPercentage = prg;
break;
case 4:
plus.nativeUI.closeWaiting();
self.bannerShow = false; // 显示弹窗
break;
}
});
} catch (err) {
console.log("更新失败-03err", err);
plus.nativeUI.closeWaiting();
uni.showToast({
title: "更新失败-03",
mask: false,
duration: 1500,
});
}
} else if (platformType == "IOS") {
// ios跳转到app store
plus.runtime.openURL(updateApkObj.downloadUrl);
}
},
jumpIntegral() {
uni.navigateTo({
url: "/pages/rwa_package/shop/points-shop",
});
},
jumpPage(path) {
uni.navigateTo({
url: `/pages/active/${path}/${path}`,
});
},
jumpTurntable() {
uni.navigateTo({
url: "/pages/other_package/nine-grid/nine-grid?backPath=home",
});
},
/**
* 查询商品列表
*/
async querySearchList(type) {
this.productLoading = true;
const params = {
type,
page: 1,
isRecomm: true,
pageSize: type === SEARCH_TYPE.SOMETHING ? 4 : 3,
};
const resp = await searchList(params);
if (resp && resp.bizcode === 100) {
this.faddishProduct = resp.data;
}
this.productLoading = false;
},
/**
* 查询分类列表
*/
async getSortList() {
const resp = await getGoodsTags({ type: 4 });
if (resp && resp.bizcode === 100) {
this.sortList = resp.data.sort((a, b) => a.sort - b.sort);
}
},
jumpSort({ id }) {
const item = SORT_TYPE.find((item) => item.key == id);
console.log("跳转到分类栏目", item);
if (item.path.includes("/pages/supply_chain/supply_chain")) {
uni.setStorageSync("sortParams", { key: item.key, value: item.value });
return uni.switchTab({
url: item.path,
});
}
uni.navigateTo({ url: item.path });
},
// 跳转到商品详情
jumpInfo(item) {
uni.navigateTo({
url: "/pages/other_package/productInfo/productInfo?id=" + item.id,
});
},
/**
* 查询专属优惠券弹窗通知
*/
fetchPopNotifyList() {
if (!getStorageFun(TOKEN_NAME)) {
return;
}
getPopNotifyList({ page: 1, pageSize: 100 })
.then((res) => {
if (res && res.bizcode === 100) {
const list = res.data?.entitys || res.data || [];
if (Array.isArray(list) && list.length > 0) {
this.popCouponList = list;
this.showCouponPop = true;
}
}
})
.catch((err) => {
console.error("获取首页优惠券弹窗失败", err);
});
},
formatThresholdText(item) {
if (!item || !item.thresholdAmount || Number(item.thresholdAmount) === 0) {
return "无门槛";
}
return "满减券";
},
formatScopeBadge(item) {
if (item && item.scopeType === 1) {
return "通用券";
}
return "满减券";
},
formatValidityText(item) {
if (item && item.startTime && item.endTime) {
const start = dayjs(item.startTime).format("YYYY.MM.DD");
const end = dayjs(item.endTime).format("YYYY.MM.DD");
return `${start}-${end}`;
}
return "领取之日起30天有效";
},
},
computed: {
isBlockedDate() {
return useTabber(10);
},
headerContainerStyle() {
const base = this.mpHeaderStyle || {};
if (this.isScrolled) {
return {
...base,
backgroundColor: '#ffffff',
boxShadow: '0 4rpx 16rpx rgba(0, 0, 0, 0.08)',
};
}
return {
...base,
backgroundColor: 'transparent',
boxShadow: 'none',
};
},
languageBoxStyle() {
const base = this.isMP ? {
height: this.mpLanguageStyle?.height,
borderRadius: this.mpLanguageStyle?.borderRadius,
boxSizing: 'border-box'
} : {};
if (this.isScrolled) {
return {
...base,
backgroundColor: '#f4f5f8',
borderColor: '#e8e8e8',
};
}
return {
...base,
backgroundColor: 'rgba(255, 255, 255, 0.35)',
borderColor: 'rgba(255, 255, 255, 0.4)',
};
},
searchMsgStyle() {
const base = { lineHeight: '1' };
if (this.isScrolled) {
return { ...base, color: '#888888' };
}
return { ...base, color: 'rgba(255, 255, 255, 0.95)' };
},
searchIconStyle() {
if (this.isScrolled) {
return { filter: 'brightness(0.3)' };
}
return { filter: 'none' };
},
chartImgStyle() {
if (this.isScrolled) {
return { filter: 'brightness(0.2)' };
}
return { filter: 'none' };
},
},
};
</script>
<style lang="scss" scoped>
.home_warp {
background: #fff;
min-height: 100vh;
position: relative;
box-sizing: border-box;
width: 100%;
max-width: 100%;
overflow-x: hidden;
&.iosplatformType {
min-height: 100vh;
}
}
.home_header_warp {
position: relative;
width: 100%;
padding: 0;
margin: 0;
background: transparent;
overflow: hidden;
.banner_swiper_container,
.banner_placeholder {
width: 100%;
position: relative;
}
}
/* 顶部固定/变色搜索栏 */
.header_title_warp {
display: flex;
align-items: center;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 999;
background: transparent;
padding: calc(var(--status-bar-height) + 12rpx) 24rpx 16rpx;
box-sizing: border-box;
transition: background-color 0.3s ease, box-shadow 0.3s ease;
&.is-scrolled {
background: #ffffff !important;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
.language_warp {
background: #f4f5f8;
border: 1rpx solid #e8e8e8;
.search_msg_warp {
color: #888888;
}
::v-deep .up-image,
.up-image {
filter: brightness(0.3);
}
}
.chart_img {
filter: brightness(0.2);
}
}
.header_right_warp {
display: flex;
align-items: center;
width: calc(100% - 0rpx);
}
.language_warp {
flex: 1;
display: flex;
justify-content: flex-start;
align-items: center;
height: 68rpx;
padding: 0 24rpx;
background: rgba(255, 255, 255, 0.35);
border: 1rpx solid rgba(255, 255, 255, 0.4);
border-radius: 34rpx;
box-sizing: border-box;
transition: all 0.3s ease;
.search_icon_box {
display: flex;
align-items: center;
justify-content: center;
.tab-icon {
width: 40rpx;
height: 40rpx;
}
}
}
.chart_img {
width: 50rpx;
height: 50rpx;
display: block;
transition: filter 0.3s ease;
}
.message-entry {
position: relative;
width: 65rpx;
height: 58rpx;
margin-left: 15rpx;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.message-entry-badge {
position: absolute;
top: -8rpx;
right: -8rpx;
min-width: 30rpx;
height: 30rpx;
// padding: 0 7rpx;
// border: 3rpx solid #8f3be9;
border-radius: 18rpx;
background: #f04438;
color: #fff;
font-size: 19rpx;
font-weight: 600;
line-height: 30rpx;
text-align: center;
box-sizing: border-box;
}
.search_msg_warp {
margin-left: 12rpx;
font-weight: 500;
font-size: 28rpx;
color: rgba(255, 255, 255, 0.95);
transition: color 0.3s ease;
line-height: 1;
display: flex;
align-items: center;
}
}
.home_content_z_warp {
position: relative;
left: 0;
top: 0;
width: 100%;
max-width: 100%;
box-sizing: border-box;
overflow-x: hidden;
}
.logo_banner {
display: flex;
justify-content: space-between;
align-items: center;
color: #ffffff;
margin-top: 20rpx;
padding: 0 10rpx;
.logo_banner_left {
display: flex;
flex-direction: column;
}
.logo_banner_title {
font-weight: bold;
font-size: 40rpx;
line-height: 46rpx;
margin: 16rpx 0 10rpx;
color: #ffffff;
letter-spacing: 1rpx;
}
.logo_banner_msg {
font-size: 24rpx;
color: rgba(255, 255, 255, 0.9);
letter-spacing: 0.5rpx;
}
.logo_banner_right {
flex-shrink: 0;
}
}
::v-deep .u-swiper__indicator {
position: absolute;
bottom: 105rpx !important;
left: 0 !important;
right: 0 !important;
width: 100% !important;
display: flex !important;
justify-content: center !important;
z-index: 15;
}
.indicator-dots,
.indicator-dots-static {
display: flex;
justify-content: center;
align-items: center;
gap: 10rpx;
.indicator-dot {
width: 16rpx;
height: 8rpx;
border-radius: 4rpx;
background: rgba(255, 255, 255, 0.45);
transition: all 0.3s ease;
&.active {
width: 28rpx;
height: 8rpx;
border-radius: 4rpx;
background: #ffffff;
}
}
}
.home_sort_warp {
position: relative;
z-index: 10;
margin: -60rpx 30rpx 0;
.sort_comm_warp {
background: #ffffff;
padding: 30rpx 16rpx 24rpx;
border-radius: 28rpx;
box-shadow: 0 8rpx 24rpx rgba(118, 50, 255, 0.08);
display: flex;
justify-content: space-around;
align-items: center;
.sort_item_comm {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-width: 0;
.sort_item_title_comm {
font-weight: 500;
font-size: 24rpx;
color: #333333;
margin-top: 10rpx;
white-space: nowrap;
text-align: center;
}
}
}
.not_order_warp {
background: #ffffff;
padding: 30rpx;
border-radius: 28rpx;
display: flex;
flex-direction: column;
align-items: center;
box-shadow: 0 8rpx 24rpx rgba(118, 50, 255, 0.08);
.not_order_msg_warp {
font-size: 24rpx;
color: #999999;
margin-top: 12rpx;
}
}
}
.home_content_warp {
padding-bottom: 100rpx;
&.Hot_Picks_Zone {
width: calc(100% - 60rpx);
margin: 0 30rpx 100rpx;
box-sizing: border-box;
height: auto;
background: linear-gradient(344deg, #FFFFFF 0%, #EDE3FF 100%);
border-radius: 28rpx;
border: 1rpx solid #dfdfdf;
padding: 24rpx 20rpx 20rpx;
margin: 20rpx auto 0;
}
.product_comm_yp {
width: 100%;
display: flex;
flex-direction: column;
}
.yp_title {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 0 10rpx;
}
.yp_title_left {
display: flex;
align-items: center;
}
.yp_title_main {
font-weight: 800;
font-size: 36rpx;
color: #000000;
margin-right: 10rpx;
}
.yp_title_sub {
font-size: 22rpx;
color: #000000;
font-weight: 500;
}
.yp_title_right {
display: flex;
align-items: center;
font-size: 24rpx;
color: #7632ff;
font-weight: bold;
}
.yp_arrow_circle {
width: 24rpx;
height: 24rpx;
background-color: #7632ff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-left: 8rpx;
}
.yp_arrow_chevron {
width: 8rpx;
height: 8rpx;
border-top: 3rpx solid #ffffff;
border-right: 3rpx solid #ffffff;
transform: rotate(45deg);
margin-left: -2rpx;
}
.yp_content {
display: flex;
justify-content: space-between;
align-items: stretch;
width: 100%;
gap: 16rpx;
}
.yp_item {
flex: 1;
max-width: 33.3%;
min-width: 0;
background: #F0E7FE;
border-radius: 24rpx;
padding: 0;
overflow: hidden;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.yp_item_image_wrapper {
width: 100%;
height: 174rpx;
border-radius: 24rpx 24rpx 0 0;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
.yp_item_image {
width: 100%;
height: 100%;
}
}
.yp_item_info {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
min-width: 0;
padding: 12rpx 10rpx 14rpx 10rpx;
box-sizing: border-box;
}
.yp_item_name {
font-size: 30rpx;
color: #000000;
font-weight: bold;
text-align: center;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-bottom: 10rpx;
}
.yp_item_price_tag {
width: 100%;
background: linear-gradient(90deg, #7632FF 0%, #B164FB 100%);
color: #ffffff;
font-size: 22rpx;
display: flex;
justify-content: center;
align-items: center;
height: 48rpx;
border-radius: 12rpx;
white-space: nowrap;
font-weight: bold;
}
.product_comm {
border-radius: 30rpx;
padding: 10rpx;
color: #ffffff;
margin-top: 20rpx;
}
.yx_warp {
background: linear-gradient(270deg, #fdefff 0%, #ede3ff 100%);
}
.product_title_z {
font-weight: 800;
font-size: 36rpx;
color: #333333ff;
margin-right: 10rpx;
}
.product_title_zk {
background: #b164fb45;
border-radius: 6rpx;
padding: 2rpx 20rpx;
color: $app-zt-color;
}
.product_title_left {
font-size: 20rpx;
display: flex;
align-items: center;
}
.product_title_f {
font-size: 20rpx;
color: #ffffff;
margin-left: 10rpx;
display: flex;
align-items: center;
}
.product_content_yx {
display: flex;
padding: 20rpx;
}
.product_content {
background-color: #ffffff;
padding: 20rpx;
border-radius: 24rpx;
display: flex;
align-items: center;
}
.product_content2 {
justify-content: space-between;
}
.product_item {
width: 32%;
position: relative;
margin-right: 20rpx;
}
.product_item2 {
width: 32%;
position: relative;
}
.product_item_yx {
width: 23%;
position: relative;
}
.product_item_yx2 {
margin-right: 20rpx;
}
.product_f_item {
position: absolute;
bottom: 0;
width: calc(100% - 40rpx);
height: 66rpx;
background: #f0e7fe;
border-radius: 0rpx 0rpx 12rpx 12rpx;
border: 1rpx solid #ffffff;
padding: 10rpx 20rpx;
font-size: 18rpx;
color: #000000;
}
.product_f_item_name {
width: 172rpx;
white-space: nowrap;
/* 防止文本换行 */
overflow: hidden;
/* 隐藏溢出的文本 */
text-overflow: ellipsis;
/* 使用省略号表示溢出的内容 */
font-weight: bold;
}
.product_f_item_price {
text-align: center;
border-radius: 10rpx;
color: #ffffff;
margin-top: 10rpx;
padding: 2rpx 0;
}
.product_f_item_price_yx {
background: #ffba41;
}
.product_f_item_price_hx {
background: linear-gradient(270deg, #af39c4 0%, #7732ff 100%);
}
.product_tips {
font-size: 24rpx;
line-height: 40rpx;
margin-left: 20rpx;
background: linear-gradient(180deg, #b039c2 0%, #8b34e9 23%, #7632ff 100%);
-webkit-background-clip: text;
color: transparent;
display: inline-block;
}
// 积分兑换,红包
.min_card_warp {
display: flex;
gap: 10rpx;
justify-content: space-between;
padding: 30rpx 30rpx 15rpx;
background-color: #fff;
.min_card_item {
padding: 10rpx 12rpx;
flex: 1;
// height: 108rpx;
border-radius: 30rpx;
opacity: 0.8;
border-radius: 16rpx;
display: flex;
justify-content: space-between;
background: linear-gradient(344deg, #ffffff 0%, #ede3ff 100%);
border-radius: 12rpx;
border: 1rpx solid #dfdfdf;
}
.min_card_item_content {
margin-top: 15rpx;
.min_card_item_title {
font-weight: bold;
font-size: 32rpx;
color: #000000;
}
.content_msg {
font-size: 20rpx;
color: #808080;
display: grid;
margin-top: 10rpx;
}
.content_msg_but {
display: flex;
align-items: center;
margin-top: 20rpx;
}
}
}
// 热门榜
.home_actived_warp {
.home_actived_item_warp {
padding: 0 30rpx 30rpx;
background-color: #fff;
margin-bottom: 20rpx;
&:last-child {
margin-bottom: 0;
}
}
.product_comm_tip {
display: flex;
justify-content: space-between;
padding: 20rpx 0;
.product_comm_tip_left {
display: flex;
align-items: center;
font-size: 36rpx;
.uni-image {
width: 40rpx;
height: 40rpx;
margin-right: 10rpx;
}
.tip_title {
color: #666666;
}
.tip_title_lable {
font-weight: 500;
color: #000000;
}
}
.product_comm_tip_right {
display: flex;
align-items: center;
font-size: 24rpx;
color: #666666;
.uni-image {
width: 30rpx;
height: 30rpx;
vertical-align: middle;
}
}
}
}
}
.uni-banner-news {
width: 540rpx;
margin: 0 auto;
background: url(https://hashmall-prod.oss-cn-shenzhen.aliyuncs.com/common/image/%E9%9D%9E%E5%BC%BA%E5%88%B6%E5%8D%87%E7%BA%A7.png) no-repeat;
background-size: 100% 100%;
.close_btn {
position: absolute;
top: 0;
right: 0;
width: 48rpx;
height: 48rpx;
}
.banner_box-news {
height: 700rpx;
// padding:40rpx;
width: 90%;
}
.banner_box-title {
font-weight: 500;
font-size: 16px;
color: #333333;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
/* 下面两行是为了兼容老版本 Firefox */
line-clamp: 2;
box-orient: vertical;
margin-top: 250rpx;
}
.banner_box-subTitle {
font-size: 14px;
color: #868686;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
/* 下面两行是为了兼容老版本 Firefox */
line-clamp: 3;
box-orient: vertical;
margin-top: 30rpx;
}
.banner_box-btn {
// width: 480rpx;
width: calc(100% - 80rpx);
height: 80rpx;
background: linear-gradient(270deg, #af39c4 0%, #7732ff 100%);
border-radius: 16rpx;
font-weight: 500;
font-size: 32rpx;
color: #ffffff;
display: flex;
justify-content: center;
align-items: center;
position: fixed;
bottom: 60rpx;
}
}
/* 专属优惠券弹窗 */
.coupon_pop_wrapper {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
.coupon_pop_card {
width: 620rpx;
background: #ffffff;
border-radius: 32rpx;
padding: 36rpx 32rpx 36rpx;
box-sizing: border-box;
position: relative;
.coupon_pop_header {
display: flex;
align-items: center;
justify-content: center;
position: relative;
margin-bottom: 28rpx;
.coupon_pop_title {
font-size: 34rpx;
font-weight: bold;
color: #333333;
text-align: center;
}
.coupon_pop_close {
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
width: 44rpx;
height: 44rpx;
// border: 2rpx solid #dcdcdc;
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
.close_x {
color: #999999;
font-size: 24rpx;
line-height: 1;
}
}
}
.coupon_pop_list {
max-height: 520rpx;
margin-bottom: 24rpx;
}
.coupon_item {
display: flex;
align-items: center;
background: #fff5f5;
border-radius: 20rpx;
height: 160rpx;
margin-bottom: 20rpx;
position: relative;
overflow: hidden;
&:last-child {
margin-bottom: 0;
}
}
.coupon_left {
width: 200rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.price_wrap {
display: flex;
align-items: baseline;
color: #ff1e27;
.currency {
font-size: 28rpx;
font-weight: bold;
margin-right: 2rpx;
}
.amount {
font-size: 56rpx;
font-weight: bold;
line-height: 1;
}
}
.threshold_tag {
font-size: 24rpx;
color: #ff1e27;
font-weight: bold;
margin-top: 8rpx;
}
}
.coupon_divider {
width: 1rpx;
height: 100%;
position: relative;
.dashed_line {
position: absolute;
top: 16rpx;
bottom: 16rpx;
width: 0;
border-left: 2rpx dashed #ffcdcd;
}
.notch {
width: 20rpx;
height: 20rpx;
background-color: #ffffff;
border-radius: 50%;
position: absolute;
left: 50%;
transform: translateX(-50%);
&.notch_top {
top: -10rpx;
}
&.notch_bottom {
bottom: -10rpx;
}
}
}
.coupon_right {
flex: 1;
padding-left: 24rpx;
padding-right: 16rpx;
display: flex;
flex-direction: column;
justify-content: center;
.coupon_name {
font-size: 30rpx;
font-weight: bold;
color: #222222;
margin-bottom: 8rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.coupon_scope_box {
display: flex;
align-items: center;
margin-bottom: 8rpx;
.scope_badge {
font-size: 20rpx;
color: #ff2437;
border: 1rpx solid #ff8d96;
background: #fff0f0;
border-radius: 6rpx;
padding: 2rpx 10rpx;
margin-right: 12rpx;
flex-shrink: 0;
}
.scope_text {
font-size: 22rpx;
color: #666666;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.coupon_validity {
font-size: 22rpx;
color: #999999;
}
}
.coupon_pop_btn {
width: 100%;
height: 88rpx;
line-height: 88rpx;
background: #ff1e27;
border-radius: 44rpx;
color: #ffffff;
font-size: 32rpx;
font-weight: bold;
text-align: center;
margin-top: 10rpx;
}
.coupon_pop_tip {
font-size: 24rpx;
color: #999999;
text-align: center;
margin-top: 24rpx;
}
}
</style>