jd-detail.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. <template>
  2. <div id="app" class="product-page">
  3. <div style="padding-bottom: 100px;">
  4. <!-- 商品图片 -->
  5. <el-carousel class="product-img">
  6. <el-carousel-item v-for="item in spuInfo.imageInfo" :key="item">
  7. <img :src="item" style="width: 100%;height: 100%;">
  8. </el-carousel-item>
  9. </el-carousel>
  10. <!-- <img :src="spuInfo.goodsImageUrl" class="product-img" alt="iPhone 15 Pro Max"> -->
  11. <!-- 标签与商品名 -->
  12. <div class="tag-bar">
  13. <span class="tag tag-subsidy" v-if="hasActivityTag(4)">百亿补贴</span>
  14. <span class="tag tag-flash" v-if="hasActivityTag(7)">秒杀</span>
  15. <span class="product-name">{{ spuInfo.skuName }}</span>
  16. </div>
  17. <!-- 价格与销量 -->
  18. <div class="price-info">
  19. <div class="price">¥{{ spuInfo.finalPrice }} <span style="font-size:12px;color:#999;">到手价</span></div>
  20. <div class="sales">销量 {{ spuInfo.inOrderCount30Days }}</div>
  21. </div>
  22. <!-- 规格选择 -->
  23. <div class="spec-section">
  24. <div v-for="(item, index) in spuInfo.propGroups">
  25. <div class="spec-title">{{ item.groupName }}</div>
  26. <div class="spec-options" v-for="(res, indeix) in item.atts">
  27. <div class="spec-title1">{{ res.attName }}</div>
  28. <div class="spec-text">{{ res.attVals[0].attValName }}</div>
  29. </div>
  30. </div>
  31. </div>
  32. <!-- 商品描述 -->
  33. <!-- <div class="desc-section">
  34. <div class="desc-title">商品描述</div>
  35. <div class="desc-content" v-html="processedIntro">
  36. </div>
  37. </div> -->
  38. </div>
  39. <!-- 底部操作栏 -->
  40. <div class="bottom-bar">
  41. <!-- <div class="bar-left">
  42. <span>推广可赚 <span style="color: red; font-size: 18px;">¥{{ spuInfo.predictPromotionRate }}</span> </span>
  43. </div> -->
  44. <div class="bar-btn btn-buy" @click="openAPP">APP打开</div>
  45. <!-- <div class="bar-btn btn-promote">立即推广</div> -->
  46. </div>
  47. </div>
  48. </template>
  49. <script>
  50. import { jdDetail, getAppLatestVersion } from '@/api/index.js'
  51. export default {
  52. name: 'jd-detail',
  53. data() {
  54. return {
  55. androidLinkurl: "https://oss.qianzhi-y.com/appapk/qianzhiyun_V1.0.0_release.apk",
  56. spuInfo: {},
  57. query: {
  58. platform: "",
  59. shareUserId: "",
  60. token: "",
  61. goodsSign: ""
  62. },
  63. }
  64. },
  65. mounted() {
  66. // this.getAppdownloadUrl()
  67. this.query.platform = this.GetQueryString("platform")
  68. this.query.shareUserId = this.GetQueryString("shareUserId")
  69. this.query.token = this.GetQueryString("token")
  70. this.query.goodsSign = this.GetQueryString("goodsSign")
  71. this.getgoodDetail()
  72. },
  73. methods: {
  74. hasActivityTag(tagCode) {
  75. // 容错:先判断 activityTags 是数组且非空,再判断是否包含目标值
  76. return Array.isArray(this.spuInfo.activityTags) && this.spuInfo.activityTags.includes(tagCode);
  77. },
  78. getAppdownloadUrl() {
  79. getAppLatestVersion().then(res => {
  80. this.androidLinkurl = res.data.downloadUrl
  81. })
  82. },
  83. getgoodDetail() {
  84. jdDetail({
  85. skuIds: [],
  86. itemIds: ['m6pQblHJgMDvmGeTn2E0FwFh_3lzC2xkU1gHEUbfkrn'],
  87. }).then(res => {
  88. this.spuInfo = res.data[0]
  89. this.spuInfo.propGroups = JSON.parse(this.spuInfo.propGroups)
  90. })
  91. },
  92. openAPP() {
  93. const that = this;
  94. // 1. 解析用户代理,判断设备类型
  95. const ua = navigator.userAgent;
  96. const isAndroid = ua.indexOf('Android') > -1 || ua.indexOf('Adr') > -1; // 安卓终端
  97. // 新增:标记是否已唤起APP(核心修复)
  98. let isAppInvoked = false;
  99. // 2. 安卓端唤醒逻辑(核心优化)
  100. if (isAndroid) {
  101. // 记录唤醒开始时间
  102. const loadStartTime = new Date().getTime();
  103. // APP Scheme 唤起链接(带参数)
  104. const schemeUrl = "com.benefit.workbox://promotion-goods" + location.search;
  105. // ========== 关键优化1:监听页面隐藏事件(唤起APP会触发) ==========
  106. // 当页面被隐藏(切换到APP),标记为已唤起
  107. const onPageHide = () => {
  108. isAppInvoked = true;
  109. // 移除监听,避免重复触发
  110. document.removeEventListener('visibilitychange', onPageHide);
  111. window.removeEventListener('pagehide', onPageHide);
  112. };
  113. // 监听页面隐藏(兼容不同浏览器)
  114. document.addEventListener('visibilitychange', onPageHide);
  115. window.addEventListener('pagehide', onPageHide);
  116. // ========== 关键优化2:简化唤起方式(避免重复触发) ==========
  117. // 仅用iframe唤起(去掉location.href兜底,减少误触发)
  118. const iframe = document.createElement('iframe');
  119. iframe.style.display = 'none';
  120. iframe.src = schemeUrl;
  121. document.body.appendChild(iframe);
  122. // 用完销毁iframe
  123. setTimeout(() => {
  124. document.body.removeChild(iframe);
  125. }, 2000);
  126. // ========== 关键优化3:精准检测唤起状态 ==========
  127. setTimeout(() => {
  128. const currentTime = new Date().getTime();
  129. const timeDiff = currentTime - loadStartTime;
  130. // 只有「未标记唤起」且「时间差小于阈值」,才跳转下载
  131. if (!isAppInvoked && timeDiff < 5000) { // 阈值从10000缩短到5000,更精准
  132. // 校验下载链接是否有效,避免报错
  133. if (that.androidLinkurl && that.androidLinkurl.trim()) {
  134. const a = document.createElement('a');
  135. a.target = '_blank';
  136. a.href = that.androidLinkurl;
  137. a.click();
  138. } else {
  139. console.error('安卓下载链接未配置');
  140. }
  141. } else {
  142. // 唤起成功,清空标记
  143. isAppInvoked = false;
  144. // 移除监听
  145. document.removeEventListener('visibilitychange', onPageHide);
  146. window.removeEventListener('pagehide', onPageHide);
  147. }
  148. }, 2000); // 检测延迟从1000延长到2000,给APP唤起足够时间
  149. }
  150. },
  151. GetQueryString(name) {
  152. var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
  153. var r = window.location.search.substr(1).match(reg);
  154. if (r != null) return unescape(r[2]);
  155. return null;
  156. },
  157. }
  158. }
  159. </script>
  160. <!-- Add "scoped" attribute to limit CSS to this component only -->
  161. <style scoped>
  162. .product-page {
  163. /* max-width: 375px; */
  164. margin: 0 0px;
  165. padding: 0px;
  166. background: #fff;
  167. min-height: 100vh;
  168. }
  169. /* 顶部导航栏 */
  170. .top-nav {
  171. display: flex;
  172. align-items: center;
  173. justify-content: space-between;
  174. padding: 12px 16px;
  175. background: #fff;
  176. border-bottom: 1px solid #eee;
  177. }
  178. .nav-back {
  179. font-size: 20px;
  180. color: #333;
  181. }
  182. .nav-title {
  183. font-size: 18px;
  184. font-weight: 600;
  185. color: #ff2f2f;
  186. }
  187. .nav-actions {
  188. display: flex;
  189. gap: 12px;
  190. }
  191. /* 商品图片 */
  192. .product-img {
  193. width: 100%;
  194. height: 300px;
  195. object-fit: cover;
  196. background: #f8f8f8;
  197. }
  198. /* 标签栏 */
  199. .tag-bar {
  200. display: flex;
  201. align-items: center;
  202. gap: 8px;
  203. padding: 8px 16px;
  204. background: #fff;
  205. }
  206. .tag {
  207. padding: 2px 4px;
  208. border-radius: 4px;
  209. font-size: 12px;
  210. color: #fff;
  211. min-width: 60px;
  212. text-align: center;
  213. }
  214. .tag-subsidy {
  215. background: #ff4444;
  216. }
  217. .tag-flash {
  218. background: #ff6600;
  219. }
  220. .product-name {
  221. font-size: 16px;
  222. font-weight: 500;
  223. color: #333;
  224. overflow: hidden;
  225. white-space: nowrap;
  226. text-overflow: ellipsis;
  227. -o-text-overflow: ellipsis;
  228. /* padding: 0 16px; */
  229. }
  230. /* 优惠信息 */
  231. .promo-bar {
  232. display: flex;
  233. align-items: center;
  234. gap: 8px;
  235. padding: 8px 16px;
  236. background: #fff9f9;
  237. }
  238. .coupon-tag {
  239. background: #ff4444;
  240. color: #fff;
  241. padding: 2px 6px;
  242. border-radius: 4px;
  243. font-size: 12px;
  244. min-width: 60px;
  245. }
  246. .promo-text {
  247. font-size: 12px;
  248. color: #666;
  249. }
  250. /* 佣金与价格 */
  251. .price-section {
  252. padding: 12px 16px;
  253. display: flex;
  254. justify-content: space-between;
  255. align-items: center;
  256. }
  257. .commission {
  258. font-size: 14px;
  259. color: #666;
  260. }
  261. .commission-value {
  262. color: #ff4444;
  263. font-size: 18px;
  264. font-weight: 600;
  265. }
  266. .upgrade-btn {
  267. background: #ff4444;
  268. color: #fff;
  269. border: none;
  270. padding: 6px 12px;
  271. border-radius: 20px;
  272. font-size: 12px;
  273. }
  274. .price-info {
  275. padding: 0 16px 12px;
  276. display: flex;
  277. justify-content: space-between;
  278. align-items: center;
  279. }
  280. .price {
  281. font-size: 18px;
  282. color: #ff4444;
  283. font-weight: 600;
  284. }
  285. .sales {
  286. font-size: 14px;
  287. color: #666;
  288. }
  289. /* 规格选择 */
  290. .spec-section {
  291. padding: 12px 16px;
  292. border-top: 8px solid #f5f5f5;
  293. }
  294. .spec-title1 {
  295. font-size: 14px;
  296. color: #9f9c9c;
  297. }
  298. .spec-text {
  299. font-size: 14px;
  300. }
  301. .spec-title {
  302. font-size: 18px;
  303. color: #333;
  304. margin-bottom: 12px;
  305. font-weight: bold;
  306. }
  307. .spec-options {
  308. display: flex;
  309. flex-wrap: wrap;
  310. gap: 12px;
  311. margin-bottom: 16px;
  312. }
  313. .spec-option {
  314. padding: 8px 12px;
  315. border: 1px solid #ddd;
  316. border-radius: 4px;
  317. font-size: 14px;
  318. color: #333;
  319. }
  320. .spec-option.active {
  321. border-color: #ff4444;
  322. color: #ff4444;
  323. background: #fff5f5;
  324. }
  325. /* 店铺信息 */
  326. .shop-section {
  327. padding: 12px 16px;
  328. border-top: 8px solid #f5f5f5;
  329. display: flex;
  330. align-items: center;
  331. gap: 12px;
  332. }
  333. .shop-logo {
  334. width: 40px;
  335. height: 40px;
  336. border-radius: 50%;
  337. background: #f5f5f5;
  338. display: flex;
  339. align-items: center;
  340. justify-content: center;
  341. }
  342. .shop-info {
  343. flex: 1;
  344. }
  345. .shop-name {
  346. font-size: 14px;
  347. font-weight: 500;
  348. color: #333;
  349. margin-bottom: 4px;
  350. }
  351. .shop-tags {
  352. display: flex;
  353. gap: 16px;
  354. font-size: 12px;
  355. color: #666;
  356. }
  357. /* 商品描述 */
  358. .desc-section {
  359. padding: 12px 16px;
  360. border-top: 8px solid #f5f5f5;
  361. }
  362. .desc-title {
  363. font-size: 14px;
  364. font-weight: 500;
  365. color: #333;
  366. margin-bottom: 8px;
  367. }
  368. .desc-content {
  369. font-size: 13px;
  370. color: #666;
  371. line-height: 1.6;
  372. }
  373. /* 底部操作栏 */
  374. .bottom-bar {
  375. position: fixed;
  376. bottom: 0;
  377. left: 0;
  378. right: 0;
  379. /* max-width: 375px; */
  380. margin: 0 auto;
  381. display: flex;
  382. background: #fff;
  383. border-top: 1px solid #eee;
  384. padding: 8px;
  385. }
  386. .bar-left {
  387. flex: 1;
  388. display: flex;
  389. align-items: center;
  390. justify-content: center;
  391. flex-direction: column;
  392. font-size: 12px;
  393. color: #666;
  394. }
  395. .bar-btn {
  396. flex: 2;
  397. padding: 10px;
  398. border-radius: 24px;
  399. text-align: center;
  400. font-size: 16px;
  401. font-weight: 500;
  402. /* 点击效果核心属性 */
  403. touch-action: manipulation;
  404. /* 阻止移动端双击缩放,提升点击响应 */
  405. user-select: none;
  406. /* 禁止文字选中 */
  407. cursor: pointer;
  408. transition: all 0.2s ease;
  409. /* 过渡动画,让效果更丝滑 */
  410. transform: scale(1);
  411. /* 初始缩放 */
  412. box-shadow: 0 2px 8px rgba(244, 51, 60, 0.3);
  413. /* 初始阴影 */
  414. }
  415. .btn-buy {
  416. background: #ff9900;
  417. color: #fff;
  418. margin-right: 8px;
  419. }
  420. .btn-promote {
  421. background: #ff2f2f;
  422. color: #fff;
  423. }
  424. /deep/ .el-carousel__indicators {
  425. display: flex;
  426. }
  427. </style>