|
|
@@ -0,0 +1,484 @@
|
|
|
+<template>
|
|
|
+ <div id="app" class="product-page">
|
|
|
+ <div style="padding-bottom: 100px;">
|
|
|
+ <!-- 商品图片 -->
|
|
|
+ <el-carousel class="product-img">
|
|
|
+ <el-carousel-item v-for="item in spuInfo.imageInfo" :key="item">
|
|
|
+ <img :src="item" style="width: 100%;height: 100%;">
|
|
|
+ </el-carousel-item>
|
|
|
+ </el-carousel>
|
|
|
+ <!-- <img :src="spuInfo.goodsImageUrl" class="product-img" alt="iPhone 15 Pro Max"> -->
|
|
|
+
|
|
|
+ <!-- 标签与商品名 -->
|
|
|
+ <div class="tag-bar">
|
|
|
+ <span class="tag tag-subsidy" v-if="hasActivityTag(4)">百亿补贴</span>
|
|
|
+ <span class="tag tag-flash" v-if="hasActivityTag(7)">秒杀</span>
|
|
|
+ <span class="product-name">{{ spuInfo.skuName }}</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 价格与销量 -->
|
|
|
+ <div class="price-info">
|
|
|
+ <div class="price">¥{{ spuInfo.finalPrice }} <span style="font-size:12px;color:#999;">到手价</span></div>
|
|
|
+ <div class="sales">销量 {{ spuInfo.inOrderCount30Days }}</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 规格选择 -->
|
|
|
+ <div class="spec-section">
|
|
|
+ <div v-for="(item, index) in spuInfo.propGroups">
|
|
|
+ <div class="spec-title">{{ item.groupName }}</div>
|
|
|
+ <div class="spec-options" v-for="(res, indeix) in item.atts">
|
|
|
+ <div class="spec-title1">{{ res.attName }}</div>
|
|
|
+ <div class="spec-text">{{ res.attVals[0].attValName }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ <!-- 商品描述 -->
|
|
|
+ <!-- <div class="desc-section">
|
|
|
+ <div class="desc-title">商品描述</div>
|
|
|
+ <div class="desc-content" v-html="processedIntro">
|
|
|
+ </div>
|
|
|
+ </div> -->
|
|
|
+ </div>
|
|
|
+ <!-- 底部操作栏 -->
|
|
|
+ <div class="bottom-bar">
|
|
|
+ <!-- <div class="bar-left">
|
|
|
+ <span>推广可赚 <span style="color: red; font-size: 18px;">¥{{ spuInfo.predictPromotionRate }}</span> </span>
|
|
|
+ </div> -->
|
|
|
+ <div class="bar-btn btn-buy" @click="openAPP">APP打开</div>
|
|
|
+ <!-- <div class="bar-btn btn-promote">立即推广</div> -->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { jdDetail, getAppLatestVersion } from '@/api/index.js'
|
|
|
+export default {
|
|
|
+ name: 'jd-detail',
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ androidLinkurl: "https://oss.qianzhi-y.com/appapk/qianzhiyun_V1.0.0_release.apk",
|
|
|
+ spuInfo: {},
|
|
|
+ query: {
|
|
|
+ platform: "",
|
|
|
+ shareUserId: "",
|
|
|
+ token: "",
|
|
|
+ goodsSign: ""
|
|
|
+ },
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ // this.getAppdownloadUrl()
|
|
|
+ this.query.platform = this.GetQueryString("platform")
|
|
|
+ this.query.shareUserId = this.GetQueryString("shareUserId")
|
|
|
+ this.query.token = this.GetQueryString("token")
|
|
|
+ this.query.goodsSign = this.GetQueryString("goodsSign")
|
|
|
+ this.getgoodDetail()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ hasActivityTag(tagCode) {
|
|
|
+ // 容错:先判断 activityTags 是数组且非空,再判断是否包含目标值
|
|
|
+ return Array.isArray(this.spuInfo.activityTags) && this.spuInfo.activityTags.includes(tagCode);
|
|
|
+ },
|
|
|
+ getAppdownloadUrl() {
|
|
|
+ getAppLatestVersion().then(res => {
|
|
|
+ this.androidLinkurl = res.data.downloadUrl
|
|
|
+ })
|
|
|
+ },
|
|
|
+ getgoodDetail() {
|
|
|
+ jdDetail({
|
|
|
+ skuIds: [],
|
|
|
+ itemIds: ['m6pQblHJgMDvmGeTn2E0FwFh_3lzC2xkU1gHEUbfkrn'],
|
|
|
+ }).then(res => {
|
|
|
+ this.spuInfo = res.data[0]
|
|
|
+ this.spuInfo.propGroups = JSON.parse(this.spuInfo.propGroups)
|
|
|
+ })
|
|
|
+ },
|
|
|
+ openAPP() {
|
|
|
+ const that = this;
|
|
|
+ // 1. 解析用户代理,判断设备类型
|
|
|
+ const ua = navigator.userAgent;
|
|
|
+ const isAndroid = ua.indexOf('Android') > -1 || ua.indexOf('Adr') > -1; // 安卓终端
|
|
|
+ // 新增:标记是否已唤起APP(核心修复)
|
|
|
+ let isAppInvoked = false;
|
|
|
+
|
|
|
+ // 2. 安卓端唤醒逻辑(核心优化)
|
|
|
+ if (isAndroid) {
|
|
|
+ // 记录唤醒开始时间
|
|
|
+ const loadStartTime = new Date().getTime();
|
|
|
+ // APP Scheme 唤起链接(带参数)
|
|
|
+ const schemeUrl = "com.benefit.workbox://promotion-goods" + location.search;
|
|
|
+ // ========== 关键优化1:监听页面隐藏事件(唤起APP会触发) ==========
|
|
|
+ // 当页面被隐藏(切换到APP),标记为已唤起
|
|
|
+ const onPageHide = () => {
|
|
|
+ isAppInvoked = true;
|
|
|
+ // 移除监听,避免重复触发
|
|
|
+ document.removeEventListener('visibilitychange', onPageHide);
|
|
|
+ window.removeEventListener('pagehide', onPageHide);
|
|
|
+ };
|
|
|
+ // 监听页面隐藏(兼容不同浏览器)
|
|
|
+ document.addEventListener('visibilitychange', onPageHide);
|
|
|
+ window.addEventListener('pagehide', onPageHide);
|
|
|
+
|
|
|
+ // ========== 关键优化2:简化唤起方式(避免重复触发) ==========
|
|
|
+ // 仅用iframe唤起(去掉location.href兜底,减少误触发)
|
|
|
+ const iframe = document.createElement('iframe');
|
|
|
+ iframe.style.display = 'none';
|
|
|
+ iframe.src = schemeUrl;
|
|
|
+ document.body.appendChild(iframe);
|
|
|
+ // 用完销毁iframe
|
|
|
+ setTimeout(() => {
|
|
|
+ document.body.removeChild(iframe);
|
|
|
+ }, 2000);
|
|
|
+
|
|
|
+ // ========== 关键优化3:精准检测唤起状态 ==========
|
|
|
+ setTimeout(() => {
|
|
|
+ const currentTime = new Date().getTime();
|
|
|
+ const timeDiff = currentTime - loadStartTime;
|
|
|
+
|
|
|
+ // 只有「未标记唤起」且「时间差小于阈值」,才跳转下载
|
|
|
+ if (!isAppInvoked && timeDiff < 5000) { // 阈值从10000缩短到5000,更精准
|
|
|
+ // 校验下载链接是否有效,避免报错
|
|
|
+ if (that.androidLinkurl && that.androidLinkurl.trim()) {
|
|
|
+ const a = document.createElement('a');
|
|
|
+ a.target = '_blank';
|
|
|
+ a.href = that.androidLinkurl;
|
|
|
+ a.click();
|
|
|
+ } else {
|
|
|
+ console.error('安卓下载链接未配置');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 唤起成功,清空标记
|
|
|
+ isAppInvoked = false;
|
|
|
+ // 移除监听
|
|
|
+ document.removeEventListener('visibilitychange', onPageHide);
|
|
|
+ window.removeEventListener('pagehide', onPageHide);
|
|
|
+ }
|
|
|
+ }, 2000); // 检测延迟从1000延长到2000,给APP唤起足够时间
|
|
|
+ }
|
|
|
+ },
|
|
|
+ GetQueryString(name) {
|
|
|
+ var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
|
|
|
+ var r = window.location.search.substr(1).match(reg);
|
|
|
+ if (r != null) return unescape(r[2]);
|
|
|
+ return null;
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<!-- Add "scoped" attribute to limit CSS to this component only -->
|
|
|
+<style scoped>
|
|
|
+.product-page {
|
|
|
+ /* max-width: 375px; */
|
|
|
+ margin: 0 0px;
|
|
|
+ padding: 0px;
|
|
|
+ background: #fff;
|
|
|
+ min-height: 100vh;
|
|
|
+}
|
|
|
+
|
|
|
+/* 顶部导航栏 */
|
|
|
+.top-nav {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 12px 16px;
|
|
|
+ background: #fff;
|
|
|
+ border-bottom: 1px solid #eee;
|
|
|
+}
|
|
|
+
|
|
|
+.nav-back {
|
|
|
+ font-size: 20px;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+
|
|
|
+.nav-title {
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #ff2f2f;
|
|
|
+}
|
|
|
+
|
|
|
+.nav-actions {
|
|
|
+ display: flex;
|
|
|
+ gap: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 商品图片 */
|
|
|
+.product-img {
|
|
|
+ width: 100%;
|
|
|
+ height: 300px;
|
|
|
+ object-fit: cover;
|
|
|
+ background: #f8f8f8;
|
|
|
+}
|
|
|
+
|
|
|
+/* 标签栏 */
|
|
|
+.tag-bar {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ padding: 8px 16px;
|
|
|
+ background: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.tag {
|
|
|
+ padding: 2px 4px;
|
|
|
+ border-radius: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #fff;
|
|
|
+ min-width: 60px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.tag-subsidy {
|
|
|
+ background: #ff4444;
|
|
|
+}
|
|
|
+
|
|
|
+.tag-flash {
|
|
|
+ background: #ff6600;
|
|
|
+}
|
|
|
+
|
|
|
+.product-name {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #333;
|
|
|
+ overflow: hidden;
|
|
|
+ white-space: nowrap;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ -o-text-overflow: ellipsis;
|
|
|
+ /* padding: 0 16px; */
|
|
|
+}
|
|
|
+
|
|
|
+/* 优惠信息 */
|
|
|
+.promo-bar {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ padding: 8px 16px;
|
|
|
+ background: #fff9f9;
|
|
|
+}
|
|
|
+
|
|
|
+.coupon-tag {
|
|
|
+ background: #ff4444;
|
|
|
+ color: #fff;
|
|
|
+ padding: 2px 6px;
|
|
|
+ border-radius: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+ min-width: 60px;
|
|
|
+}
|
|
|
+
|
|
|
+.promo-text {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+/* 佣金与价格 */
|
|
|
+.price-section {
|
|
|
+ padding: 12px 16px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.commission {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+.commission-value {
|
|
|
+ color: #ff4444;
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+.upgrade-btn {
|
|
|
+ background: #ff4444;
|
|
|
+ color: #fff;
|
|
|
+ border: none;
|
|
|
+ padding: 6px 12px;
|
|
|
+ border-radius: 20px;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.price-info {
|
|
|
+ padding: 0 16px 12px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.price {
|
|
|
+ font-size: 18px;
|
|
|
+ color: #ff4444;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+.sales {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+/* 规格选择 */
|
|
|
+.spec-section {
|
|
|
+ padding: 12px 16px;
|
|
|
+ border-top: 8px solid #f5f5f5;
|
|
|
+}
|
|
|
+
|
|
|
+.spec-title1 {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #9f9c9c;
|
|
|
+}
|
|
|
+
|
|
|
+.spec-text {
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.spec-title {
|
|
|
+ font-size: 18px;
|
|
|
+ color: #333;
|
|
|
+ margin-bottom: 12px;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+
|
|
|
+.spec-options {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 12px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.spec-option {
|
|
|
+ padding: 8px 12px;
|
|
|
+ border: 1px solid #ddd;
|
|
|
+ border-radius: 4px;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+
|
|
|
+.spec-option.active {
|
|
|
+ border-color: #ff4444;
|
|
|
+ color: #ff4444;
|
|
|
+ background: #fff5f5;
|
|
|
+}
|
|
|
+
|
|
|
+/* 店铺信息 */
|
|
|
+.shop-section {
|
|
|
+ padding: 12px 16px;
|
|
|
+ border-top: 8px solid #f5f5f5;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.shop-logo {
|
|
|
+ width: 40px;
|
|
|
+ height: 40px;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: #f5f5f5;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+.shop-info {
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.shop-name {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #333;
|
|
|
+ margin-bottom: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.shop-tags {
|
|
|
+ display: flex;
|
|
|
+ gap: 16px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+/* 商品描述 */
|
|
|
+.desc-section {
|
|
|
+ padding: 12px 16px;
|
|
|
+ border-top: 8px solid #f5f5f5;
|
|
|
+}
|
|
|
+
|
|
|
+.desc-title {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #333;
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.desc-content {
|
|
|
+ font-size: 13px;
|
|
|
+ color: #666;
|
|
|
+ line-height: 1.6;
|
|
|
+}
|
|
|
+
|
|
|
+/* 底部操作栏 */
|
|
|
+.bottom-bar {
|
|
|
+ position: fixed;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ /* max-width: 375px; */
|
|
|
+ margin: 0 auto;
|
|
|
+ display: flex;
|
|
|
+ background: #fff;
|
|
|
+ border-top: 1px solid #eee;
|
|
|
+ padding: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.bar-left {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ flex-direction: column;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+.bar-btn {
|
|
|
+ flex: 2;
|
|
|
+ padding: 10px;
|
|
|
+ border-radius: 24px;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+ /* 点击效果核心属性 */
|
|
|
+ touch-action: manipulation;
|
|
|
+ /* 阻止移动端双击缩放,提升点击响应 */
|
|
|
+ user-select: none;
|
|
|
+ /* 禁止文字选中 */
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.2s ease;
|
|
|
+ /* 过渡动画,让效果更丝滑 */
|
|
|
+ transform: scale(1);
|
|
|
+ /* 初始缩放 */
|
|
|
+ box-shadow: 0 2px 8px rgba(244, 51, 60, 0.3);
|
|
|
+ /* 初始阴影 */
|
|
|
+}
|
|
|
+
|
|
|
+.btn-buy {
|
|
|
+ background: #ff9900;
|
|
|
+ color: #fff;
|
|
|
+ margin-right: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.btn-promote {
|
|
|
+ background: #ff2f2f;
|
|
|
+ color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+/deep/ .el-carousel__indicators {
|
|
|
+ display: flex;
|
|
|
+}
|
|
|
+</style>
|