secondShareGoods.html 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
  6. <meta name="format-detection" content="telephone=no">
  7. <title>商品分享</title>
  8. <style>
  9. :root {
  10. --orange: #F58220;
  11. --price-red: #E62E2E;
  12. --tag-bg: #fff5e9;
  13. --tag-text: #b05b28;
  14. --text: #1a1a1a;
  15. --text-secondary: #999999;
  16. --safe-bottom: env(safe-area-inset-bottom, 0px);
  17. }
  18. * {
  19. margin: 0;
  20. padding: 0;
  21. box-sizing: border-box;
  22. }
  23. html {
  24. font-size: 16px;
  25. -webkit-tap-highlight-color: transparent;
  26. overflow-x: hidden;
  27. }
  28. body {
  29. font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Helvetica Neue", sans-serif;
  30. background: #fff;
  31. color: var(--text);
  32. min-height: 100vh;
  33. padding-bottom: calc(100px + var(--safe-bottom));
  34. }
  35. .fab-wrap {
  36. position: fixed;
  37. left: 0;
  38. right: 0;
  39. bottom: 0;
  40. z-index: 200;
  41. padding: 12px 24px calc(12px + var(--safe-bottom));
  42. background: linear-gradient(to top, rgba(255, 255, 255, 0.98) 70%, transparent);
  43. pointer-events: none;
  44. }
  45. .fab-wrap .fab {
  46. pointer-events: auto;
  47. }
  48. .fab {
  49. display: flex;
  50. align-items: center;
  51. justify-content: center;
  52. gap: 10px;
  53. width: 100%;
  54. max-width: 320px;
  55. margin: 0 auto;
  56. height: 48px;
  57. border: none;
  58. border-radius: 24px;
  59. background: #F47D1F;
  60. color: #fff;
  61. font-size: 16px;
  62. font-weight: 600;
  63. box-shadow: 0 4px 16px rgba(245, 130, 32, 0.45);
  64. cursor: pointer;
  65. }
  66. .fab__logo {
  67. width: 28px;
  68. height: 28px;
  69. flex-shrink: 0;
  70. }
  71. .home-indicator {
  72. height: 5px;
  73. background: #000;
  74. border-radius: 3px;
  75. width: 134px;
  76. margin: 8px auto 4px;
  77. opacity: 0.2;
  78. }
  79. /* 顶部大图 + 叠字 */
  80. .goods-hero {
  81. position: relative;
  82. width: 100%;
  83. min-height: 58vh;
  84. max-height: 520px;
  85. background: #e8e8e8 center / cover no-repeat;
  86. overflow: hidden;
  87. }
  88. .goods-hero__img {
  89. position: absolute;
  90. inset: 0;
  91. width: 100%;
  92. height: 100%;
  93. object-fit: cover;
  94. display: block;
  95. }
  96. .goods-hero__shade {
  97. position: absolute;
  98. inset: 0;
  99. background: linear-gradient(
  100. 180deg,
  101. rgba(0, 0, 0, 0.35) 0%,
  102. rgba(0, 0, 0, 0.1) 38%,
  103. rgba(0, 0, 0, 0.45) 100%
  104. );
  105. pointer-events: none;
  106. }
  107. .goods-hero__inner {
  108. position: relative;
  109. z-index: 1;
  110. min-height: 58vh;
  111. max-height: 520px;
  112. padding: calc(12px + env(safe-area-inset-top, 0px)) 16px 28px;
  113. display: flex;
  114. flex-direction: column;
  115. justify-content: space-between;
  116. align-items: flex-start;
  117. }
  118. .goods-hero__user {
  119. display: flex;
  120. align-items: center;
  121. gap: 10px;
  122. }
  123. .goods-hero__avatar {
  124. width: 40px;
  125. height: 40px;
  126. border-radius: 50%;
  127. object-fit: cover;
  128. flex-shrink: 0;
  129. background: rgba(255, 255, 255, 0.3);
  130. }
  131. .goods-hero__user-meta {
  132. display: flex;
  133. flex-direction: column;
  134. gap: 2px;
  135. }
  136. .goods-hero__name {
  137. font-size: 15px;
  138. font-weight: 600;
  139. color: #fff;
  140. text-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
  141. }
  142. .goods-hero__time {
  143. font-size: 12px;
  144. color: rgba(255, 255, 255, 0.82);
  145. text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  146. }
  147. .goods-hero__slogan {
  148. margin-top: auto;
  149. padding-bottom: 4px;
  150. }
  151. .goods-hero__slogan-line {
  152. font-size: 26px;
  153. font-weight: 800;
  154. line-height: 1.25;
  155. color: #fff;
  156. letter-spacing: 0.02em;
  157. text-shadow: 0 2px 12px rgba(0, 0, 0, 0.45);
  158. }
  159. /* 白色内容区 */
  160. .goods-panel {
  161. background: #fff;
  162. border-radius: 16px 16px 0 0;
  163. margin-top: -16px;
  164. position: relative;
  165. z-index: 2;
  166. padding: 20px 16px 24px;
  167. box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.06);
  168. }
  169. .goods-panel__row-price {
  170. display: flex;
  171. align-items: flex-end;
  172. justify-content: space-between;
  173. gap: 12px;
  174. margin-bottom: 14px;
  175. }
  176. .goods-panel__price {
  177. display: flex;
  178. align-items: baseline;
  179. gap: 2px;
  180. color: var(--price-red);
  181. font-weight: 800;
  182. line-height: 1;
  183. }
  184. .goods-panel__price-yen {
  185. font-size: 18px;
  186. }
  187. .goods-panel__price-num {
  188. font-size: 28px;
  189. letter-spacing: -0.02em;
  190. }
  191. .goods-panel__dist {
  192. display: inline-flex;
  193. align-items: center;
  194. gap: 4px;
  195. font-size: 12px;
  196. color: var(--text-secondary);
  197. flex-shrink: 0;
  198. padding-bottom: 2px;
  199. }
  200. .goods-panel__dist svg,
  201. .goods-panel__dist img {
  202. width: 14px;
  203. height: 14px;
  204. opacity: 0.85;
  205. display: block;
  206. flex-shrink: 0;
  207. object-fit: contain;
  208. }
  209. .goods-panel__title {
  210. font-size: 17px;
  211. font-weight: 700;
  212. line-height: 1.45;
  213. color: var(--text);
  214. margin-bottom: 16px;
  215. }
  216. .goods-panel__row-stats {
  217. display: flex;
  218. align-items: center;
  219. justify-content: space-between;
  220. gap: 12px;
  221. margin-bottom: 16px;
  222. }
  223. .goods-panel__stats {
  224. display: flex;
  225. align-items: center;
  226. gap: 18px;
  227. }
  228. .goods-panel__stat {
  229. display: inline-flex;
  230. align-items: center;
  231. gap: 5px;
  232. font-size: 14px;
  233. color: var(--text-secondary);
  234. }
  235. .goods-panel__stat svg {
  236. width: 16px;
  237. height: 16px;
  238. flex-shrink: 0;
  239. }
  240. .goods-panel__stat img {
  241. width: 16px;
  242. height: 16px;
  243. flex-shrink: 0;
  244. display: block;
  245. object-fit: contain;
  246. }
  247. .goods-panel__share {
  248. display: inline-flex;
  249. align-items: center;
  250. gap: 4px;
  251. padding: 0;
  252. border: none;
  253. background: none;
  254. font-size: 14px;
  255. color: var(--text-secondary);
  256. cursor: pointer;
  257. -webkit-tap-highlight-color: transparent;
  258. }
  259. .goods-panel__share svg {
  260. width: 18px;
  261. height: 18px;
  262. }
  263. .goods-panel__tags {
  264. display: flex;
  265. flex-wrap: wrap;
  266. align-items: center;
  267. gap: 8px;
  268. }
  269. .goods-tag {
  270. display: inline-block;
  271. padding: 2px 8px;
  272. border-radius: 4px;
  273. font-size: 12px;
  274. font-weight: 400;
  275. line-height: 1.35;
  276. background: #fff5e9;
  277. }
  278. .goods-tag--topic {
  279. color: #b05b28;
  280. }
  281. .goods-tag--label {
  282. color: #333333;
  283. }
  284. /* 留言 */
  285. .goods-comments {
  286. margin-top: 20px;
  287. padding-top: 20px;
  288. border-top: 1px solid #eee;
  289. }
  290. .goods-comments__head {
  291. display: flex;
  292. align-items: center;
  293. justify-content: space-between;
  294. margin-bottom: 18px;
  295. }
  296. .goods-comments__title {
  297. font-size: 17px;
  298. font-weight: 700;
  299. color: var(--text);
  300. }
  301. .goods-comments__total {
  302. display: inline-flex;
  303. align-items: center;
  304. gap: 4px;
  305. font-size: 14px;
  306. color: #151515;
  307. }
  308. .goods-comments__total svg {
  309. width: 18px;
  310. height: 18px;
  311. opacity: 0.85;
  312. }
  313. .goods-comments__list {
  314. list-style: none;
  315. }
  316. .goods-comments__empty {
  317. list-style: none;
  318. padding: 24px 12px;
  319. text-align: center;
  320. font-size: 14px;
  321. color: var(--text-secondary);
  322. }
  323. .goods-cmt {
  324. padding-bottom: 18px;
  325. margin-bottom: 18px;
  326. border-bottom: 1px solid #eee;
  327. }
  328. .goods-cmt:last-child {
  329. margin-bottom: 0;
  330. padding-bottom: 0;
  331. border-bottom: none;
  332. }
  333. .goods-cmt__row {
  334. display: flex;
  335. align-items: flex-start;
  336. gap: 12px;
  337. }
  338. .goods-cmt__avatar {
  339. width: 40px;
  340. height: 40px;
  341. border-radius: 50%;
  342. object-fit: cover;
  343. background: #e8e8e8;
  344. flex-shrink: 0;
  345. }
  346. .goods-cmt--nested .goods-cmt__avatar {
  347. width: 32px;
  348. height: 32px;
  349. }
  350. .goods-cmt__body {
  351. flex: 1;
  352. min-width: 0;
  353. }
  354. .goods-cmt__name {
  355. font-size: 15px;
  356. font-weight: 700;
  357. color: var(--text);
  358. line-height: 1.3;
  359. }
  360. .goods-cmt__time {
  361. display: block;
  362. margin-top: 2px;
  363. font-size: 12px;
  364. color: var(--text-secondary);
  365. line-height: 1.35;
  366. }
  367. .goods-cmt__text {
  368. margin-top: 10px;
  369. font-size: 15px;
  370. line-height: 1.5;
  371. color: var(--text);
  372. word-break: break-word;
  373. }
  374. .goods-cmt__actions {
  375. display: flex;
  376. align-items: center;
  377. gap: 20px;
  378. margin-top: 12px;
  379. }
  380. .goods-cmt__action {
  381. display: inline-flex;
  382. align-items: center;
  383. gap: 4px;
  384. padding: 0;
  385. border: none;
  386. background: none;
  387. font-size: 13px;
  388. color: var(--text-secondary);
  389. cursor: pointer;
  390. -webkit-tap-highlight-color: transparent;
  391. }
  392. .goods-cmt__action svg {
  393. width: 16px;
  394. height: 16px;
  395. flex-shrink: 0;
  396. opacity: 0.88;
  397. }
  398. .goods-cmt__thread {
  399. margin-top: 14px;
  400. padding-left: 52px;
  401. }
  402. .goods-cmt__replies-inner.is-collapsed {
  403. display: none;
  404. }
  405. .goods-cmt__thread-bar {
  406. display: flex;
  407. align-items: center;
  408. justify-content: space-between;
  409. width: 100%;
  410. margin-top: 10px;
  411. padding: 10px 12px;
  412. border: none;
  413. border-radius: 8px;
  414. background: #f5f5f5;
  415. font-size: 13px;
  416. color: #888;
  417. cursor: pointer;
  418. -webkit-tap-highlight-color: transparent;
  419. }
  420. .goods-cmt__thread-bar-right {
  421. display: inline-flex;
  422. align-items: center;
  423. gap: 4px;
  424. color: var(--text-secondary);
  425. }
  426. .goods-cmt__thread-chevron {
  427. width: 14px;
  428. height: 14px;
  429. transition: transform 0.2s ease;
  430. flex-shrink: 0;
  431. }
  432. .goods-cmt__thread-bar.is-collapsed .goods-cmt__thread-chevron {
  433. transform: rotate(180deg);
  434. }
  435. .goods-cmt--nested {
  436. padding-bottom: 0;
  437. margin-bottom: 0;
  438. border-bottom: none;
  439. }
  440. .goods-cmt--nested .goods-cmt__text {
  441. margin-top: 8px;
  442. }
  443. </style>
  444. </head>
  445. <body>
  446. <section class="goods-hero" id="goodsHero" aria-label="商品配图">
  447. <img class="goods-hero__img" id="goodsHeroImg" src="" alt="">
  448. <div class="goods-hero__shade" aria-hidden="true"></div>
  449. <div class="goods-hero__inner">
  450. <div class="goods-hero__user">
  451. <img class="goods-hero__avatar" id="goodsUserAvatar" src="images/demouser.png" alt="">
  452. <div class="goods-hero__user-meta">
  453. <span class="goods-hero__name" id="goodsUserName">维尼</span>
  454. <span class="goods-hero__time" id="goodsTimeAgo">11小时前</span>
  455. </div>
  456. </div>
  457. <div class="goods-hero__slogan" id="goodsHeroSloganWrap" style="display:none;">
  458. <div class="goods-hero__slogan-line" id="goodsSlogan1"></div>
  459. <div class="goods-hero__slogan-line" id="goodsSlogan2"></div>
  460. </div>
  461. </div>
  462. </section>
  463. <div class="goods-panel">
  464. <div class="goods-panel__row-price">
  465. <div class="goods-panel__price">
  466. <span class="goods-panel__price-yen">¥</span>
  467. <span class="goods-panel__price-num" id="goodsPrice">690.00</span>
  468. </div>
  469. <div class="goods-panel__dist">
  470. <img src="images/juli.svg" alt="" width="14" height="14" decoding="async" aria-hidden="true">
  471. <span id="goodsDistance">距离 2.5km</span>
  472. </div>
  473. </div>
  474. <h1 class="goods-panel__title" id="goodsTitle">HCK哈士奇BC-330RDE烤漆复古冰箱家用大容量单门冰柜高颜值网红</h1>
  475. <div class="goods-panel__row-stats">
  476. <div class="goods-panel__stats">
  477. <span class="goods-panel__stat goods-panel__stat--hot" id="goodsHotStat">
  478. <img src="images/huo.svg" alt="" width="16" height="16" decoding="async" aria-hidden="true">
  479. <span id="goodsHotCount" style="color:#151515;">510</span>
  480. </span>
  481. <span class="goods-panel__stat">
  482. <img src="images/xing.svg" alt="" width="16" height="16" decoding="async" aria-hidden="true">
  483. <span id="goodsFavCount" style="color:#151515;">260</span>
  484. </span>
  485. </div>
  486. </div>
  487. <div class="goods-panel__tags" id="goodsTags"></div>
  488. <section class="goods-comments" id="goodsComments" aria-label="留言">
  489. <div class="goods-comments__head">
  490. <h2 class="goods-comments__title">留言</h2>
  491. <div class="goods-comments__total">
  492. <img src="images/liuyan.svg" alt="" width="16" height="16" decoding="async" aria-hidden="true">
  493. <span id="goodsCommentTotal">24</span>
  494. </div>
  495. </div>
  496. <ul class="goods-comments__list" id="goodsCommentList"></ul>
  497. </section>
  498. </div>
  499. <div class="fab-wrap">
  500. <button type="button" class="fab" id="openApp">
  501. <img src="images/uBtn.png" alt="APP内打开" decoding="async">
  502. </button>
  503. <div class="home-indicator" aria-hidden="true"></div>
  504. </div>
  505. <script>
  506. (function () {
  507. 'use strict';
  508. /**
  509. * 商品详情:POST https://test.ailien.shop/alienSecond/recommend/querySecondGoodsDetail
  510. * body: application/x-www-form-urlencoded(「表单数据」);键 goodsId、longitude、latitude,值均为字符串;经纬度未传时用默认 121.662567 / 38.925757
  511. * 留言:GET {API_BASE}/commonComment/getListBySourceType — 成功时 data 常为数组;项含 parentId、childCommonComments、headName、headImg、createdTime、content、likeCount
  512. * URL 常用:goodsId、userId、longitude/lon/jingdu、latitude/lat/weidu、pageNum、pageSize、sourceType(含 hash 内 ? 参数)
  513. */
  514. /**
  515. * 唤起 App 落地:二手商品详情(与 pages.json 路径一致)
  516. */
  517. var APP_ANDROID_PACKAGE = 'com.alien.Udianzaizhe';
  518. var APP_IOS_URL_SCHEME = 'shopro://';
  519. var APP_UNI_STORE_PATH = 'pages/secondHandTransactions/pages/detail/index';
  520. function showDownloadTip() {
  521. var msg = '请到应用商店下载';
  522. if (typeof uni !== 'undefined' && typeof uni.showToast === 'function') {
  523. uni.showToast({ title: msg, icon: 'none', duration: 2500 });
  524. } else {
  525. window.alert(msg);
  526. }
  527. }
  528. function mergeSearchAndHashParams() {
  529. var params = new URLSearchParams();
  530. function ingest(querySlice) {
  531. if (!querySlice) return;
  532. var p = new URLSearchParams(querySlice);
  533. p.forEach(function (val, key) {
  534. params.append(key, val);
  535. });
  536. }
  537. if (location.search && location.search.length > 1) {
  538. ingest(location.search.slice(1));
  539. }
  540. var hash = location.hash || '';
  541. var qi = hash.indexOf('?');
  542. if (qi >= 0) {
  543. ingest(hash.slice(qi + 1));
  544. }
  545. return params;
  546. }
  547. function buildAppOpenQueryStringMerged() {
  548. var params = mergeSearchAndHashParams();
  549. var gid = params.get('goodsId') || params.get('id') || '';
  550. if (gid && !params.has('goodsId')) {
  551. params.set('goodsId', gid);
  552. }
  553. var sid = params.get('storeId') || params.get('id') || '';
  554. if (sid && !params.has('storeId')) {
  555. params.set('storeId', sid);
  556. }
  557. var qsOut = params.toString();
  558. return qsOut ? ('?' + qsOut) : '';
  559. }
  560. function buildAppDeepLink() {
  561. var path = String(APP_UNI_STORE_PATH || 'pages/secondHandTransactions/pages/detail/index').replace(/^\//, '');
  562. var s = buildAppOpenQueryStringMerged();
  563. var root = APP_IOS_URL_SCHEME.replace(/\/$/, '');
  564. if (!s) {
  565. return root + '/' + path;
  566. }
  567. return root + '/' + path + s;
  568. }
  569. function isWeChatInAppBrowser() {
  570. return /MicroMessenger/i.test(navigator.userAgent || '');
  571. }
  572. function launchAppDeepLink(deepLink) {
  573. try {
  574. var a = document.createElement('a');
  575. a.href = deepLink;
  576. a.setAttribute('target', '_self');
  577. document.body.appendChild(a);
  578. a.click();
  579. document.body.removeChild(a);
  580. } catch (e1) {}
  581. try {
  582. window.location.href = deepLink;
  583. } catch (e2) {}
  584. }
  585. function tryOpenHBuilderApp() {
  586. var deepLink = buildAppDeepLink();
  587. if (typeof plus !== 'undefined' && plus.runtime) {
  588. var installed = null;
  589. try {
  590. if (typeof plus.runtime.isApplicationExist === 'function') {
  591. installed = plus.runtime.isApplicationExist({
  592. pname: APP_ANDROID_PACKAGE,
  593. action: APP_IOS_URL_SCHEME
  594. });
  595. }
  596. } catch (e) {
  597. console.warn(e);
  598. }
  599. if (installed === false) {
  600. showDownloadTip();
  601. return;
  602. }
  603. try {
  604. plus.runtime.openURL(deepLink);
  605. } catch (e2) {
  606. console.warn(e2);
  607. showDownloadTip();
  608. }
  609. return;
  610. }
  611. var t0 = Date.now();
  612. var done = false;
  613. function finish() {
  614. if (done) return;
  615. done = true;
  616. document.removeEventListener('visibilitychange', onVis);
  617. window.removeEventListener('pagehide', onHide);
  618. }
  619. function onVis() {
  620. if (document.visibilityState === 'hidden') finish();
  621. }
  622. function onHide() {
  623. finish();
  624. }
  625. document.addEventListener('visibilitychange', onVis);
  626. window.addEventListener('pagehide', onHide);
  627. if (isWeChatInAppBrowser()) {
  628. window.alert('若点击后无法打开 App:请先点右上角「···」,选择「在浏览器中打开」,再点「APP内打开」。');
  629. }
  630. try {
  631. launchAppDeepLink(deepLink);
  632. } catch (e3) {
  633. finish();
  634. showDownloadTip();
  635. return;
  636. }
  637. window.setTimeout(function () {
  638. if (done) return;
  639. if (document.visibilityState === 'visible' && Date.now() - t0 < 3500) {
  640. showDownloadTip();
  641. }
  642. finish();
  643. }, 2600);
  644. }
  645. function q(name) {
  646. var v = mergeSearchAndHashParams().get(name);
  647. return v == null ? '' : String(v);
  648. }
  649. function tryDecode(s) {
  650. s = String(s || '');
  651. if (!s) return '';
  652. try {
  653. return decodeURIComponent(s.replace(/\+/g, ' '));
  654. } catch (e) {
  655. return s;
  656. }
  657. }
  658. var DEFAULT_HERO = '';
  659. var API_BASE = 'https://test.ailien.shop/alienStore';
  660. /** 二手商品等业务接口前缀(与 alienStore 分离) */
  661. var API_BASE_SECOND = 'https://test.ailien.shop/alienSecond';
  662. /** 与接口调试「表单数据」一致;地址栏未带经纬度时使用 */
  663. var DEFAULT_REQUEST_LONGITUDE = '121.662567';
  664. var DEFAULT_REQUEST_LATITUDE = '38.925757';
  665. var COMMENT_SOURCE_TYPE = 4;
  666. function apiGet(path) {
  667. return fetch(API_BASE + path, {
  668. method: 'GET',
  669. mode: 'cors',
  670. credentials: 'omit',
  671. headers: { Accept: 'application/json' }
  672. }).then(function (res) {
  673. if (!res.ok) throw new Error('HTTP ' + res.status);
  674. return res.json();
  675. });
  676. }
  677. function apiPostJson(path, body) {
  678. return fetch(API_BASE + path, {
  679. method: 'POST',
  680. mode: 'cors',
  681. credentials: 'omit',
  682. headers: {
  683. Accept: 'application/json',
  684. 'Content-Type': 'application/json'
  685. },
  686. body: JSON.stringify(body || {})
  687. }).then(function (res) {
  688. if (!res.ok) throw new Error('HTTP ' + res.status);
  689. return res.json();
  690. });
  691. }
  692. function pick(d, keys) {
  693. if (!d || typeof d !== 'object') return null;
  694. for (var i = 0; i < keys.length; i++) {
  695. var k = keys[i];
  696. if (d[k] != null && d[k] !== '') return d[k];
  697. }
  698. return null;
  699. }
  700. function isApiOk(res) {
  701. if (!res || typeof res !== 'object') return false;
  702. if (res.success === false) return false;
  703. var c = res.code;
  704. return c === 200 || c === '200' || Number(c) === 200;
  705. }
  706. function fmtPriceNum(v) {
  707. var n = v != null ? Number(v) : NaN;
  708. return !isNaN(n) ? n.toFixed(2) : String(v != null ? v : '');
  709. }
  710. /** kind: topic(#话题 棕橙)| label(分类名 深灰,不带 #) */
  711. function appendGoodsTag(mount, raw, kind) {
  712. if (!mount || raw == null) return;
  713. var s = String(raw).trim();
  714. if (!s) return;
  715. var span = document.createElement('span');
  716. span.className =
  717. 'goods-tag ' + (kind === 'label' ? 'goods-tag--label' : 'goods-tag--topic');
  718. if (kind === 'label') {
  719. span.textContent = s.replace(/^#+/, '');
  720. } else {
  721. span.textContent = s.indexOf('#') === 0 ? s : '#' + s;
  722. }
  723. mount.appendChild(span);
  724. }
  725. function renderGoodsDetail(d) {
  726. if (!d || typeof d !== 'object') return;
  727. var title = pick(d, ['goodsName', 'title', 'secondGoodsTitle', 'name']);
  728. if (title) {
  729. var el = document.getElementById('goodsTitle');
  730. if (el) el.textContent = String(title);
  731. }
  732. var price = pick(d, ['price', 'goodsPrice', 'salePrice', 'currentPrice', 'amount']);
  733. if (price != null) {
  734. var pe = document.getElementById('goodsPrice');
  735. if (pe) pe.textContent = fmtPriceNum(price);
  736. }
  737. var dist = pick(d, ['dist', 'distance', 'distanceText', 'distanceDesc', 'distanceDescription', 'distanceKm']);
  738. if (dist != null) {
  739. var dt = String(dist).trim();
  740. if (dt) {
  741. if (!/^距离/.test(dt)) dt = '距离 ' + dt;
  742. if (!/km$/i.test(dt) && !/千米/.test(dt) && !/米/.test(dt) && !/\s*m\s*$/i.test(dt)) {
  743. dt = dt.replace(/\s+$/, '') + 'km';
  744. }
  745. var de = document.getElementById('goodsDistance');
  746. if (de) de.textContent = dt;
  747. }
  748. }
  749. var img =
  750. pick(d, ['coverUrl', 'mainImage', 'goodsImage', 'firstImage', 'bannerUrl']) ||
  751. (Array.isArray(d.goodsImageList) && d.goodsImageList[0]) ||
  752. (Array.isArray(d.imageList) && d.imageList[0]);
  753. if (img) {
  754. var hi = document.getElementById('goodsHeroImg');
  755. if (hi) {
  756. hi.src = String(img);
  757. hi.alt = '商品图';
  758. }
  759. }
  760. var nick = pick(d, ['publishUserNick', 'userNickName', 'nickName', 'userName', 'publisherName']);
  761. if (nick) {
  762. var ne = document.getElementById('goodsUserName');
  763. if (ne) ne.textContent = String(nick);
  764. }
  765. var av = pick(d, ['publishUserAvatar', 'userAvatar', 'userHead', 'avatar', 'headImg']);
  766. if (av) {
  767. var ae = document.getElementById('goodsUserAvatar');
  768. if (ae) ae.src = String(av);
  769. }
  770. var tm = pick(d, ['timeAgo', 'releaseTime', 'publishTime', 'createTime', 'publishTimeStr']);
  771. if (tm) {
  772. var te = document.getElementById('goodsTimeAgo');
  773. if (te) te.textContent = String(tm);
  774. }
  775. var s1 = pick(d, ['promotionLineOne', 'promotionTitle', 'subtitle', 'slogan1', 'line1']);
  776. var s2 = pick(d, ['promotionLineTwo', 'subTitle', 'slogan2', 'line2']);
  777. var wrap = document.getElementById('goodsHeroSloganWrap');
  778. var e1 = document.getElementById('goodsSlogan1');
  779. var e2 = document.getElementById('goodsSlogan2');
  780. if (wrap && e1 && e2) {
  781. if (s1 || s2) {
  782. if (s1) e1.textContent = String(s1);
  783. if (s2) e2.textContent = String(s2);
  784. wrap.style.display = '';
  785. } else {
  786. wrap.style.display = 'none';
  787. }
  788. }
  789. var hotStat = document.getElementById('goodsHotStat');
  790. var cs = pick(d, ['collectStatus']);
  791. if (hotStat) {
  792. var hideHot =
  793. cs != null &&
  794. (Number(cs) === 0 || String(cs).trim() === '0');
  795. hotStat.style.display = hideHot ? 'none' : '';
  796. }
  797. var hot = pick(d, ['browseCount', 'viewCount', 'hotCount', 'readCount']);
  798. if (hot != null) {
  799. var he = document.getElementById('goodsHotCount');
  800. if (he) he.textContent = String(hot);
  801. }
  802. var fav = pick(d, ['collectCount', 'wantCount', 'favCount', 'favoriteCount']);
  803. if (fav != null) {
  804. var fe = document.getElementById('goodsFavCount');
  805. if (fe) fe.textContent = String(fav);
  806. }
  807. var topicStr = d.topic != null ? String(d.topic).trim() : '';
  808. var labelStr = d.label != null ? String(d.label).trim() : '';
  809. var hasApiTags = topicStr !== '' || labelStr !== '';
  810. var mount = document.getElementById('goodsTags');
  811. if (mount) {
  812. if (hasApiTags) {
  813. mount.innerHTML = '';
  814. if (topicStr) appendGoodsTag(mount, topicStr, 'topic');
  815. if (labelStr) appendGoodsTag(mount, labelStr, 'label');
  816. } else {
  817. var tags = d.tagList || d.tags || d.labelList || d.goodsTags;
  818. if (tags) {
  819. mount.innerHTML = '';
  820. var arr = Array.isArray(tags) ? tags : String(tags).split(/[,,]/);
  821. arr.forEach(function (t) {
  822. if (t == null || t === '') return;
  823. var label =
  824. typeof t === 'object'
  825. ? (t.tagName || t.name || t.label || '')
  826. : String(t);
  827. label = String(label).trim();
  828. if (!label) return;
  829. var isTopic = label.indexOf('#') === 0;
  830. appendGoodsTag(mount, label, isTopic ? 'topic' : 'label');
  831. });
  832. }
  833. }
  834. }
  835. }
  836. var SVG_LIKE = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"/></svg>';
  837. var SVG_REPLY = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>';
  838. var SVG_CHEV = '<svg class="goods-cmt__thread-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg>';
  839. function cmtAvatarUrl(c) {
  840. return String(
  841. pick(c, ['headImg', 'userAvatar', 'userHead', 'avatar', 'avatarUrl']) || ''
  842. ).trim();
  843. }
  844. function cmtUserName(c) {
  845. var s = String(pick(c, ['headName', 'userName', 'nickName', 'userNickName', 'commentUserName', 'headPhone']) || '—').trim();
  846. return s || '—';
  847. }
  848. function cmtTime(c) {
  849. return String(pick(c, ['createTime', 'createdTime', 'commentTime']) || '');
  850. }
  851. function cmtContent(c) {
  852. return String(pick(c, ['content', 'commentContent', 'text']) || '');
  853. }
  854. function cmtLikeCount(c) {
  855. var v = pick(c, ['likeCount', 'likeNum', 'praiseCount']);
  856. return v != null ? String(v) : '0';
  857. }
  858. function cmtReplies(c) {
  859. if (!c || typeof c !== 'object') return [];
  860. var sub =
  861. c.childCommonComments ||
  862. c.replyList ||
  863. c.replyVOList ||
  864. c.children ||
  865. c.subComments ||
  866. c.replies;
  867. if (sub == null) return [];
  868. return Array.isArray(sub) ? sub.filter(Boolean) : [];
  869. }
  870. function appendCmtRow(parentBody, c, showReply) {
  871. var row = document.createElement('div');
  872. row.className = 'goods-cmt__row';
  873. var img = document.createElement('img');
  874. img.className = 'goods-cmt__avatar';
  875. img.alt = '';
  876. var au = cmtAvatarUrl(c);
  877. img.src = au || 'images/demouser.png';
  878. var body = document.createElement('div');
  879. body.className = 'goods-cmt__body';
  880. var name = document.createElement('span');
  881. name.className = 'goods-cmt__name';
  882. name.textContent = cmtUserName(c);
  883. var time = document.createElement('span');
  884. time.className = 'goods-cmt__time';
  885. time.textContent = cmtTime(c);
  886. var text = document.createElement('p');
  887. text.className = 'goods-cmt__text';
  888. text.textContent = cmtContent(c);
  889. var actions = document.createElement('div');
  890. actions.className = 'goods-cmt__actions';
  891. var likeBtn = document.createElement('button');
  892. likeBtn.type = 'button';
  893. likeBtn.className = 'goods-cmt__action';
  894. likeBtn.setAttribute('aria-label', '点赞');
  895. likeBtn.innerHTML = SVG_LIKE + '<span>' + cmtLikeCount(c) + '</span>';
  896. actions.appendChild(likeBtn);
  897. if (showReply) {
  898. var repBtn = document.createElement('button');
  899. repBtn.type = 'button';
  900. repBtn.className = 'goods-cmt__action';
  901. repBtn.setAttribute('aria-label', '回复');
  902. repBtn.innerHTML = SVG_REPLY + '<span>回复</span>';
  903. actions.appendChild(repBtn);
  904. }
  905. body.appendChild(name);
  906. body.appendChild(time);
  907. body.appendChild(text);
  908. body.appendChild(actions);
  909. row.appendChild(img);
  910. row.appendChild(body);
  911. parentBody.appendChild(row);
  912. return body;
  913. }
  914. function buildNestedCmt(c) {
  915. var wrap = document.createElement('div');
  916. wrap.className = 'goods-cmt goods-cmt--nested';
  917. appendCmtRow(wrap, c, false);
  918. return wrap;
  919. }
  920. function filterTopLevelComments(list) {
  921. if (!Array.isArray(list) || !list.length) return [];
  922. var top = list.filter(function (c) {
  923. if (!c) return false;
  924. var pid = c.parentId != null ? c.parentId : c.pid;
  925. if (typeof pid === 'string') pid = pid.trim();
  926. return pid == null || pid === '' || Number(pid) === 0;
  927. });
  928. return top.length ? top : list.slice();
  929. }
  930. function countCommentsInApiList(records) {
  931. if (!Array.isArray(records)) return 0;
  932. var tops = filterTopLevelComments(records);
  933. var n = 0;
  934. for (var i = 0; i < tops.length; i++) {
  935. var c = tops[i];
  936. if (!c) continue;
  937. n += 1 + cmtReplies(c).length;
  938. }
  939. return n;
  940. }
  941. function normalizeCommentListPayload(d) {
  942. if (typeof d === 'string') {
  943. try {
  944. d = JSON.parse(d);
  945. } catch (e) {
  946. return { records: [], total: 0 };
  947. }
  948. }
  949. if (Array.isArray(d)) {
  950. return { records: d, total: countCommentsInApiList(d) };
  951. }
  952. if (d && typeof d === 'object') {
  953. var arr = d.records || d.list || d.rows;
  954. if (!Array.isArray(arr) && Array.isArray(d.data)) arr = d.data;
  955. if (!Array.isArray(arr)) arr = [];
  956. var total =
  957. d.total != null && !isNaN(Number(d.total))
  958. ? Number(d.total)
  959. : countCommentsInApiList(arr);
  960. return { records: arr, total: total };
  961. }
  962. return { records: [], total: 0 };
  963. }
  964. function renderCommentsList(rows, total) {
  965. var mount = document.getElementById('goodsCommentList');
  966. var totEl = document.getElementById('goodsCommentTotal');
  967. if (!mount) return;
  968. mount.innerHTML = '';
  969. var list = filterTopLevelComments(Array.isArray(rows) ? rows : []);
  970. var n = total != null && !isNaN(Number(total)) ? Number(total) : countCommentsInApiList(Array.isArray(rows) ? rows : []);
  971. if (totEl) totEl.textContent = String(n);
  972. if (!list.length) {
  973. var empty = document.createElement('li');
  974. empty.className = 'goods-comments__empty';
  975. empty.setAttribute('role', 'status');
  976. empty.textContent = '暂无留言';
  977. mount.appendChild(empty);
  978. return;
  979. }
  980. list.forEach(function (c) {
  981. if (!c) return;
  982. var li = document.createElement('li');
  983. li.className = 'goods-cmt';
  984. appendCmtRow(li, c, true);
  985. var replies = cmtReplies(c);
  986. if (replies.length) {
  987. var thread = document.createElement('div');
  988. thread.className = 'goods-cmt__thread';
  989. var inner = document.createElement('div');
  990. inner.className = 'goods-cmt__replies-inner';
  991. replies.forEach(function (r) {
  992. if (r) inner.appendChild(buildNestedCmt(r));
  993. });
  994. var bar = document.createElement('button');
  995. bar.type = 'button';
  996. bar.className = 'goods-cmt__thread-bar';
  997. bar.setAttribute('aria-expanded', 'true');
  998. bar.innerHTML =
  999. '<span>共<span class="js-reply-count">' + replies.length + '</span>条回复</span>' +
  1000. '<span class="goods-cmt__thread-bar-right">' +
  1001. '<span class="js-thread-label">收起</span>' + SVG_CHEV + '</span>';
  1002. thread.appendChild(inner);
  1003. thread.appendChild(bar);
  1004. li.appendChild(thread);
  1005. }
  1006. mount.appendChild(li);
  1007. });
  1008. }
  1009. function bindCommentThreadDelegation() {
  1010. var list = document.getElementById('goodsCommentList');
  1011. if (!list || list.dataset.threadDeleg) return;
  1012. list.dataset.threadDeleg = '1';
  1013. list.addEventListener('click', function (e) {
  1014. var bar = e.target.closest('.goods-cmt__thread-bar');
  1015. if (!bar) return;
  1016. var inner = bar.previousElementSibling;
  1017. if (!inner || !inner.classList.contains('goods-cmt__replies-inner')) return;
  1018. var collapsed = inner.classList.toggle('is-collapsed');
  1019. bar.classList.toggle('is-collapsed', collapsed);
  1020. bar.setAttribute('aria-expanded', collapsed ? 'false' : 'true');
  1021. var lab = bar.querySelector('.js-thread-label');
  1022. if (lab) lab.textContent = collapsed ? '展开' : '收起';
  1023. });
  1024. }
  1025. function pickGoodsStatusFromStatusApi(res) {
  1026. if (!res || typeof res !== 'object') return null;
  1027. var d = isApiOk(res) ? (res.data != null ? res.data : res.result) : null;
  1028. if (d != null && typeof d === 'object' && d.goodsStatus != null) {
  1029. return d.goodsStatus;
  1030. }
  1031. if (res.goodsStatus != null) return res.goodsStatus;
  1032. return null;
  1033. }
  1034. /** 打开页时先拉取商品状态;query 参数名为 id */
  1035. function fetchGoodsStatusById(id) {
  1036. var sid = String(id != null ? id : '').trim();
  1037. if (!sid) return Promise.resolve(null);
  1038. var path =
  1039. '/secondGoods/getGoodsStatusById?id=' + encodeURIComponent(sid);
  1040. return fetch(API_BASE_SECOND + path, {
  1041. method: 'GET',
  1042. mode: 'cors',
  1043. credentials: 'omit',
  1044. headers: { Accept: 'application/json' }
  1045. }).then(function (res) {
  1046. if (!res.ok) throw new Error('HTTP ' + res.status);
  1047. return res.json();
  1048. });
  1049. }
  1050. function fetchSecondGoodsDetail(goodsId, lon, lat, phoneId) {
  1051. var lonStr =
  1052. lon != null && String(lon).trim() !== ''
  1053. ? String(lon).trim()
  1054. : String(DEFAULT_REQUEST_LONGITUDE);
  1055. var latStr =
  1056. lat != null && String(lat).trim() !== ''
  1057. ? String(lat).trim()
  1058. : String(DEFAULT_REQUEST_LATITUDE);
  1059. var pid =
  1060. phoneId != null && String(phoneId).trim() !== ''
  1061. ? String(phoneId).trim()
  1062. : '';
  1063. /** 表单字段:键为 string,值一律 string(x-www-form-urlencoded) */
  1064. var formBody = {
  1065. goodsId: String(goodsId != null ? goodsId : '').trim(),
  1066. longitude: String(lonStr),
  1067. latitude: String(latStr),
  1068. phoneId: pid
  1069. };
  1070. var form = new URLSearchParams();
  1071. form.set('goodsId', formBody.goodsId);
  1072. form.set('longitude', formBody.longitude);
  1073. form.set('latitude', formBody.latitude);
  1074. form.set('phoneId', formBody.phoneId);
  1075. return fetch(API_BASE_SECOND + '/recommend/querySecondGoodsDetailWithOutJWT', {
  1076. method: 'POST',
  1077. mode: 'cors',
  1078. credentials: 'omit',
  1079. headers: {
  1080. Accept: 'application/json',
  1081. 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
  1082. },
  1083. body: form.toString()
  1084. }).then(function (res) {
  1085. if (!res.ok) throw new Error('HTTP ' + res.status);
  1086. return res.json();
  1087. }).then(function (res) {
  1088. var d = isApiOk(res) ? res.data || res.result : null;
  1089. if (d && typeof d === 'object') {
  1090. renderGoodsDetail(d);
  1091. } else if (res && res.msg) {
  1092. console.warn('[querySecondGoodsDetail]', res.msg);
  1093. }
  1094. });
  1095. }
  1096. function fetchCommentList(goodsId, userId, pageNum, pageSize) {
  1097. var st = (q('sourceType') || '').trim();
  1098. var sourceType = st && !isNaN(Number(st)) ? Number(st) : COMMENT_SOURCE_TYPE;
  1099. var path = '/commonComment/getListBySourceType?' +
  1100. 'sourceType=' + encodeURIComponent(String(sourceType)) +
  1101. '&sourceId=' + encodeURIComponent(String(goodsId)) +
  1102. '&pageNum=' + encodeURIComponent(String(pageNum || 1)) +
  1103. '&pageSize=' + encodeURIComponent(String(pageSize || 10)) +
  1104. '&userId=' + encodeURIComponent(userId != null ? String(userId) : '');
  1105. return apiGet(path).then(function (res) {
  1106. if (!isApiOk(res)) {
  1107. if (res && res.msg) console.warn('[getListBySourceType]', res.msg);
  1108. renderCommentsList([], 0);
  1109. return;
  1110. }
  1111. var raw = res.data != null ? res.data : res.result;
  1112. var pack = normalizeCommentListPayload(raw);
  1113. renderCommentsList(pack.records, pack.total);
  1114. });
  1115. }
  1116. function run() {
  1117. var goodsId = (q('goodsId') || q('id') || '').trim();
  1118. var userId = (q('userId') || '').trim();
  1119. var phoneId = (q('phoneId') || q('phone_id') || '').trim();
  1120. var lon = (q('longitude') || q('lon') || q('jingdu') || '').trim();
  1121. var lat = (q('latitude') || q('lat') || q('weidu') || '').trim();
  1122. var pageNum = (q('pageNum') || '1').trim();
  1123. var pageSize = (q('pageSize') || '10').trim();
  1124. bindCommentThreadDelegation();
  1125. if (!goodsId) {
  1126. applyFromUrl();
  1127. return;
  1128. }
  1129. fetchGoodsStatusById(goodsId)
  1130. .catch(function (e) {
  1131. console.warn('[getGoodsStatusById]', e);
  1132. return null;
  1133. })
  1134. .then(function (statusRes) {
  1135. var gs = pickGoodsStatusFromStatusApi(statusRes);
  1136. var gsNum = gs != null ? Number(gs) : NaN;
  1137. var gsStr = gs != null ? String(gs).trim() : '';
  1138. var gsGotoUndefined =
  1139. gs != null &&
  1140. ((!isNaN(gsNum) && (gsNum === 2 || gsNum === 4 || gsNum === 5)) ||
  1141. gsStr === '2' || gsStr === '4' || gsStr === '5');
  1142. if (gsGotoUndefined) {
  1143. var undefinedUrl = 'shareUndefined.html';
  1144. if (userId) {
  1145. undefinedUrl += '?userId=' + encodeURIComponent(userId);
  1146. }
  1147. window.location.replace(undefinedUrl);
  1148. return { skipRest: true };
  1149. }
  1150. return Promise.all([
  1151. fetchSecondGoodsDetail(goodsId, lon, lat, phoneId).catch(function (e) {
  1152. console.warn('[querySecondGoodsDetail]', e);
  1153. }),
  1154. fetchCommentList(goodsId, userId, pageNum, pageSize).catch(function (e) {
  1155. console.warn('[getListBySourceType]', e);
  1156. renderCommentsList([], 0);
  1157. })
  1158. ]).then(function () {
  1159. return { skipRest: false };
  1160. });
  1161. })
  1162. .then(function (flag) {
  1163. if (flag && flag.skipRest) return;
  1164. applyFromUrl();
  1165. });
  1166. }
  1167. function applyFromUrl() {
  1168. var heroImg = document.getElementById('goodsHeroImg');
  1169. var imgUrl = q('image') || q('goodsImage') || q('coverUrl') || q('img');
  1170. imgUrl = tryDecode(imgUrl).trim();
  1171. if (imgUrl) {
  1172. heroImg.src = imgUrl;
  1173. heroImg.alt = '商品图';
  1174. } else {
  1175. heroImg.src = DEFAULT_HERO;
  1176. heroImg.alt = '';
  1177. }
  1178. var av = tryDecode(q('userImage') || q('avatar')).trim();
  1179. document.getElementById('goodsUserAvatar').src = av || 'images/demouser.png';
  1180. var uname = tryDecode(q('userName') || q('nickname')).trim();
  1181. if (uname) document.getElementById('goodsUserName').textContent = uname;
  1182. var ago = tryDecode(q('timeAgo') || q('publishTime')).trim();
  1183. if (ago) document.getElementById('goodsTimeAgo').textContent = ago;
  1184. var s1 = tryDecode(q('slogan1') || q('line1')).trim();
  1185. var s2 = tryDecode(q('slogan2') || q('line2')).trim();
  1186. var elS1 = document.getElementById('goodsSlogan1');
  1187. var elS2 = document.getElementById('goodsSlogan2');
  1188. var elWrap = document.getElementById('goodsHeroSloganWrap');
  1189. if (s1 && elS1) elS1.textContent = s1;
  1190. if (s2 && elS2) elS2.textContent = s2;
  1191. if (elWrap && (s1 || s2)) elWrap.style.display = '';
  1192. var price = tryDecode(q('price')).trim();
  1193. if (price) {
  1194. var pn = parseFloat(price.replace(/[^\d.]/g, ''));
  1195. document.getElementById('goodsPrice').textContent =
  1196. !isNaN(pn) ? pn.toFixed(2) : price;
  1197. }
  1198. var dist = tryDecode(q('distance') || q('distanceKm') || q('dist')).trim();
  1199. if (dist) {
  1200. if (!/^距离/.test(dist)) dist = '距离 ' + dist;
  1201. if (!/km$/i.test(dist) && !/千米/.test(dist) && !/米/.test(dist) && !/\s*m\s*$/i.test(dist)) {
  1202. dist = dist.replace(/\s+$/, '') + 'km';
  1203. }
  1204. document.getElementById('goodsDistance').textContent = dist;
  1205. }
  1206. var title = tryDecode(q('title') || q('goodsTitle')).trim();
  1207. if (title) document.getElementById('goodsTitle').textContent = title;
  1208. var hot = tryDecode(q('hotCount') || q('hot')).trim();
  1209. if (hot) document.getElementById('goodsHotCount').textContent = hot;
  1210. var fav = tryDecode(q('favCount') || q('fav') || q('collectCount')).trim();
  1211. if (fav) document.getElementById('goodsFavCount').textContent = fav;
  1212. var cc = tryDecode(q('commentCount') || q('comments')).trim();
  1213. if (cc) {
  1214. var elTot = document.getElementById('goodsCommentTotal');
  1215. if (elTot) elTot.textContent = cc;
  1216. }
  1217. var tagsRaw = tryDecode(q('tags') || q('tag')).trim();
  1218. var mount = document.getElementById('goodsTags');
  1219. var hasGoodsId = (q('goodsId') || q('id') || '').trim();
  1220. if (mount) {
  1221. if (tagsRaw) {
  1222. mount.innerHTML = '';
  1223. tagsRaw.split(/[,,]/).map(function (t) { return t.trim(); }).filter(Boolean).forEach(function (t) {
  1224. appendGoodsTag(mount, t, t.indexOf('#') === 0 ? 'topic' : 'label');
  1225. });
  1226. } else if (!hasGoodsId) {
  1227. mount.innerHTML = '';
  1228. ['复古冰箱', '网红冰箱', '复古烤漆', '冰箱'].forEach(function (t) {
  1229. appendGoodsTag(mount, t, 'label');
  1230. });
  1231. }
  1232. }
  1233. }
  1234. function sharePage() {
  1235. var title = document.getElementById('goodsTitle').textContent || '商品分享';
  1236. var url = location.href;
  1237. if (navigator.share) {
  1238. navigator.share({ title: title, text: title, url: url }).catch(function () {});
  1239. return;
  1240. }
  1241. if (navigator.clipboard && navigator.clipboard.writeText) {
  1242. navigator.clipboard.writeText(url).then(function () {
  1243. window.alert('链接已复制');
  1244. }).catch(function () {
  1245. window.prompt('复制链接', url);
  1246. });
  1247. } else {
  1248. window.prompt('复制链接', url);
  1249. }
  1250. }
  1251. var shareBtn = document.getElementById('goodsShareBtn');
  1252. if (shareBtn) shareBtn.addEventListener('click', sharePage);
  1253. var openAppBtn = document.getElementById('openApp');
  1254. if (openAppBtn) {
  1255. openAppBtn.addEventListener('click', function () {
  1256. tryOpenHBuilderApp();
  1257. });
  1258. }
  1259. run();
  1260. })();
  1261. </script>
  1262. </body>
  1263. </html>