index.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. <template>
  2. <div class="shop-pages">
  3. <div class="shop-head flex-row-start">
  4. <div class="head-left">
  5. <div class="left-carousel" v-if="carousel && carousel.length > 0">
  6. <div v-for="(item, index) in carousel" :key="index" class="carousel-item" :class="carouselIndex == index ? 'hig' : ''">
  7. <img :src="item" alt="" @click="onCarousel(1, index)" />
  8. </div>
  9. </div>
  10. <div class="left-next flex-row-center" @click="onCarousel(2)">
  11. <el-icon color="#6A7282" size="15">
  12. <ArrowDown />
  13. </el-icon>
  14. </div>
  15. </div>
  16. <img v-if="carousel && carousel.length > 0" :src="carousel[carouselIndex]" alt="" class="carousel-img" />
  17. <div class="head-right flex-column-between">
  18. <div>
  19. <div class="right-title">{{ dataInfo.itemName || '' }}</div>
  20. <div class="right-num">商品库存 {{ dataInfo.stock || 0 }}套</div>
  21. <div class="right-price flex-row-between">
  22. <div class="flex-row-start">
  23. <div class="price1">
  24. <span>¥</span>
  25. <span style="font-size: 24px">{{ dataInfo.standardPrice || 0 }}</span>
  26. </div>
  27. <div class="price2">平台价</div>
  28. <div class="price3">
  29. <span>¥</span>
  30. <span style="font-size: 16px">{{ dataInfo.midRangePrice || 0 }}</span>
  31. </div>
  32. </div>
  33. <div class="right-collect flex-row-start" @click="editCollection">
  34. <el-icon v-if="collection" :size="16" color="#e7000b"><StarFilled /></el-icon>
  35. <el-icon v-else class="icon-star" :size="16"><Star /></el-icon>
  36. <!-- <img src="@/assets/images/dark.svg" alt="" /> -->
  37. <span>{{ collection ? '已收藏' : '收藏' }}</span>
  38. </div>
  39. </div>
  40. <div class="address flex-row-start">
  41. <img class="address-img" src="@/assets/images/item1.png" alt="" />
  42. <div style="margin-right: 10px">配送至</div>
  43. <el-cascader v-model="regionCodes" :options="regionData as any" :placeholder="'请选择省/市/区'" style="width: 260px" />
  44. <!-- <el-icon color="#000000" size="15">
  45. <ArrowDown />
  46. </el-icon> -->
  47. </div>
  48. <div class="specs-bos">
  49. <div class="specs-list">
  50. <div>商品编号</div>
  51. <div class="specs-item hig">
  52. {{ dataInfo.productNo }}
  53. </div>
  54. <div class="specs-box"></div>
  55. </div>
  56. <div class="specs-list">
  57. <div>单位</div>
  58. <div class="specs-item hig">
  59. {{ dataInfo.unitName }}
  60. </div>
  61. <div class="specs-box"></div>
  62. </div>
  63. <div class="specs-list">
  64. <div>规格型号</div>
  65. <div class="specs-item hig">
  66. {{ dataInfo.specification }}
  67. </div>
  68. <div class="specs-box"></div>
  69. </div>
  70. <div class="specs-list">
  71. <div>UPC(69)条码</div>
  72. <div class="specs-item hig">
  73. {{ dataInfo.upcBarcode }}
  74. </div>
  75. <div class="specs-box"></div>
  76. </div>
  77. </div>
  78. <div class="number-bos">
  79. <div>数量</div>
  80. <div class="flex-row-start number-box">
  81. <el-input-number v-model="num" :min="1" :max="10" @change="handleChange" />
  82. <div style="margin-left: 10px">本产品限购2件</div>
  83. </div>
  84. </div>
  85. </div>
  86. <div class="bnt-bos flex-row-start">
  87. <div @click="onCart">加入购物车</div>
  88. <!-- <div>立即购买</div> -->
  89. </div>
  90. </div>
  91. </div>
  92. <div class="nav-bos flex-row-start">
  93. <div @click="onNav(index)" v-for="(item, index) in navList" :key="index" :class="navIndex == index ? 'hig' : ''">{{ item.title }}</div>
  94. </div>
  95. <div class="pcDetail" v-if="navIndex == 0" v-html="dataInfo.pcDetail"></div>
  96. <div class="service" v-if="navIndex == 1">
  97. <div class="service1">原厂正品保证承诺:</div>
  98. <div>(1)所有商品均为符合国家有关商品质量的技术标准、服务标准、环保标准的原厂正品。</div>
  99. <div>(2)所有商品保证是全新的货物,且来源于中华人民共和国或与中华人民共和国有正常贸易往来的国家或地区。</div>
  100. <div>(3)所有商品均为自营,不涉及任何第三方店铺,充分保证产品来源,保证质量。</div>
  101. <div>(4)所有商品均为原厂正品,如有假货,假一罚十。</div>
  102. <div>(5)所有产品均严格按照国家三包标准执行。</div>
  103. <div>(6)保证所售商品开具机打发票或电子发票。</div>
  104. <div class="service1">厂家服务:</div>
  105. <div>
  106. 本商品质保周期均为厂商对外公布的质保期或优易365对客户承诺的质保期为准。在此时间范围内可提交维修申请,具体请以厂家服务为准。
  107. 如因质量问题或故障,凭厂商维修中心或特约维修点的质量检测证明,享受7日内退货,15日内换货,15日以上在质保期内享受免费保修等三包服务!
  108. </div>
  109. <div>全国统一售后及服务电话:400-111-0027</div>
  110. <div>(注:如优易365在商品介绍中有售后保障的说明,则此商品按照说明执行售后保障服务。)</div>
  111. <div class="service1">服务承诺:</div>
  112. <div>平台销售并发货的商品,均由平台提供发票和相应的售后服务。请您放心购买!</div>
  113. <div>优易365确保客户收到的货物与商城图片、产地、附件说明完全一致。均为原厂正货!并且保证与当时市场上同样主流新品一致。</div>
  114. <div class="service1">无忧退货:</div>
  115. <div>客户购买商品7日内(含7日,自客户收到商品之日起计算),在保证商品完好的前提下,可无理由退货。(部分商品除外,详情请见各商品细则)</div>
  116. <div>• 购买运费如何收取?</div>
  117. <div class="service2">
  118. 单笔订单金额(不含运费)满88元免邮费;不满88元,每单收取10元运费。(港澳台地区需满500元免邮费;不满500元,每单收取30元运费)
  119. </div>
  120. <div>• 使用什么快递发货?</div>
  121. <div class="service2">默认使用顺丰快递发货(个别商品使用其他快递)</div>
  122. <div class="service2">配送范围覆盖全国大部分地区(港澳台地区除外)。</div>
  123. <div>• 如何申请退货?</div>
  124. <div class="service2">1.自收到商品之日起30日内,顾客可申请无忧退货,退款将原路返还,不同的银行处理时间不同,预计1-5个工作日到账;</div>
  125. <div class="service2">2.内裤和食品等特殊商品无质量问题不支持退货;</div>
  126. <div>3.退货流程:</div>
  127. <div class="service2">确认收货-申请退货-客服审核通过-用户寄回商品-仓库签收验货-退款审核-退款完成;</div>
  128. <div>
  129. 4.因优品汇产生的退货,如质量问题,退货邮费由优品汇承担,退款完成后会以现金券的形式报销。因客户个人原因产生的退货,购买和寄回运费由客户个人承担。
  130. </div>
  131. </div>
  132. <!-- <img class="shop-img" src="@/assets/images/login-background.jpg" alt="" /> -->
  133. <div class="shop-more flex-row-between">
  134. <div class="flex-row-start">
  135. <div class="more1">更多推荐</div>
  136. <div class="more2">甄选大牌,优质好品</div>
  137. </div>
  138. <div class="flex-row-start">
  139. <div class="more3">查看更多</div>
  140. <el-icon color="#364153" size="14">
  141. <ArrowRight />
  142. </el-icon>
  143. </div>
  144. </div>
  145. <div class="data-bos">
  146. <div v-for="(item, index) in 3" :key="index" class="data-list">
  147. <img class="data-img" src="@/assets/images/login-background.jpg" alt="" />
  148. <div class="data-title">格力KFR-72LW/定频冷暖空调柜机3P</div>
  149. <div class="money">
  150. <span class="money1">¥1,299</span>
  151. <span class="money2">¥1,899</span>
  152. </div>
  153. </div>
  154. </div>
  155. <!-- 取消收藏 -->
  156. <el-dialog
  157. v-model="dialogVisible"
  158. title="选择取消的收藏夹"
  159. width="500"
  160. :before-close="
  161. () => {
  162. dialogVisible = false;
  163. }
  164. "
  165. >
  166. <div>
  167. <el-radio-group v-model="radio">
  168. <el-radio v-for="(item, index) in favorites" :key="index" :value="item.id">{{ item.title }}</el-radio>
  169. </el-radio-group>
  170. </div>
  171. <template #footer>
  172. <div class="dialog-footer">
  173. <el-button @click="dialogVisible = false">取消</el-button>
  174. <el-button type="primary" @click="onCancel"> 确认 </el-button>
  175. </div>
  176. </template>
  177. </el-dialog>
  178. </div>
  179. </template>
  180. <script setup lang="ts">
  181. import { getToken } from '@/utils/auth';
  182. import { regionData } from 'element-china-area-data';
  183. import {
  184. getProductDetail,
  185. addProductShoppingCart,
  186. isProductInDefaultCollect,
  187. addProductBrowsingHistory,
  188. addProductCollect,
  189. favoritesList,
  190. cancelProductCollect
  191. } from '@/api/goods/index';
  192. const route = useRoute();
  193. const id = ref<any>(null);
  194. const dataInfo = ref<any>({});
  195. const carousel = ref<any>([]);
  196. const regionCodes = ref<any>([]);
  197. const radio = ref<any>(null);
  198. const favorites = ref<any>([]);
  199. const collection = ref<any>(null);
  200. const dialogVisible = ref<any>(false);
  201. const navList = ref<any>([{ title: '商品详情' }, { title: '售后服务说明' }, { title: '品牌信息' }, { title: '商品评价' }]);
  202. const navIndex = ref<any>(0);
  203. onMounted(() => {
  204. id.value = route.query.id;
  205. getInfo();
  206. if (getToken()) {
  207. getCollection();
  208. // 浏览记录
  209. addProductBrowsingHistory(id.value).then((res) => {});
  210. }
  211. });
  212. // 商品详情
  213. const getInfo = () => {
  214. getProductDetail(id.value).then((res) => {
  215. if (res.code == 200) {
  216. carousel.value = [];
  217. if (res.data.imageUrl) {
  218. carousel.value = res.data.imageUrl.split(',');
  219. if (carousel.value.length > 5) {
  220. carousel.value = carousel.value.slice(0, 5);
  221. }
  222. }
  223. dataInfo.value = res.data;
  224. }
  225. });
  226. };
  227. // 收藏
  228. const getCollection = () => {
  229. isProductInDefaultCollect(id.value).then((res) => {
  230. if (res.code == 200) {
  231. collection.value = res.data;
  232. }
  233. });
  234. };
  235. //修改收藏
  236. const editCollection = () => {
  237. if (collection.value) {
  238. dialogVisible.value = true;
  239. favoritesList(id.value).then((res) => {
  240. if (res.code == 200) {
  241. if (res.rows.length > 0) {
  242. radio.value = res.rows[0].id;
  243. }
  244. favorites.value = res.rows;
  245. }
  246. });
  247. } else {
  248. // 添加
  249. addProductCollect({ productId: id.value }).then((res) => {
  250. if (res.code == 200) {
  251. getCollection();
  252. }
  253. });
  254. }
  255. };
  256. // 取消收藏
  257. const onCancel = () => {
  258. cancelProductCollect({ productId: id.value, favoritesId: radio.value }).then((res) => {
  259. if (res.code == 200) {
  260. getCollection();
  261. dialogVisible.value = false;
  262. }
  263. });
  264. };
  265. // 切换
  266. const onNav = (index: any) => {
  267. navIndex.value = index;
  268. };
  269. const num = ref<any>(1);
  270. const carouselIndex = ref<any>(0);
  271. const onCarousel = (type: number, index?: any) => {
  272. if (type == 1) {
  273. carouselIndex.value = index;
  274. } else {
  275. carouselIndex.value++;
  276. if (carouselIndex.value > carousel.value.length - 1) {
  277. carouselIndex.value = 0;
  278. }
  279. }
  280. };
  281. const handleChange = (val: any) => {
  282. // num.value = val;
  283. };
  284. import { cartStore } from '@/store/modules/cart';
  285. const cart = cartStore();
  286. const onCart = () => {
  287. addProductShoppingCart({
  288. productId: id.value,
  289. productNum: num.value
  290. }).then((res) => {
  291. if (res.code == 200) {
  292. ElMessage.success('加入购物车成功');
  293. cart.onCartCount();
  294. }
  295. });
  296. };
  297. </script>
  298. <style lang="scss" scoped>
  299. .shop-pages {
  300. width: 1200px;
  301. margin: 0 auto;
  302. .shop-head {
  303. width: 1200px;
  304. .head-left {
  305. width: 106px;
  306. .left-carousel {
  307. height: 540px;
  308. overflow-y: auto;
  309. .carousel-item {
  310. width: 100px;
  311. height: 100px;
  312. border-radius: 6px;
  313. overflow: hidden;
  314. margin-top: 10px;
  315. cursor: pointer;
  316. &:nth-of-type(1) {
  317. margin-top: 0px;
  318. }
  319. &.hig {
  320. border: 1.5px solid #e7000b;
  321. }
  322. img {
  323. width: 100px;
  324. height: 100px;
  325. }
  326. }
  327. }
  328. .left-next {
  329. width: 100px;
  330. height: 36px;
  331. background: #ffffff;
  332. border-radius: 6px 6px 6px 6px;
  333. margin-top: 10px;
  334. cursor: pointer;
  335. }
  336. }
  337. .carousel-img {
  338. width: 586px;
  339. height: 586px;
  340. border-radius: 10px;
  341. margin-left: 4px;
  342. margin-right: 10px;
  343. }
  344. .head-right {
  345. width: 494px;
  346. height: 586px;
  347. background: #ffffff;
  348. border-radius: 10px 10px 10px 10px;
  349. padding: 20px 20px 30px 20px;
  350. .right-title {
  351. height: 56px;
  352. font-weight: 600;
  353. font-size: 20px;
  354. color: #101828;
  355. }
  356. .right-num {
  357. font-size: 14px;
  358. color: #6a7282;
  359. }
  360. .right-price {
  361. margin-top: 10px;
  362. .price1 {
  363. font-size: 12px;
  364. color: #e7000b;
  365. }
  366. .price2 {
  367. width: 52px;
  368. height: 21px;
  369. background: #e7000b;
  370. border-radius: 2px;
  371. font-size: 12px;
  372. color: #ffffff;
  373. line-height: 21px;
  374. text-align: center;
  375. margin: 0 16px 0 8px;
  376. }
  377. .price3 {
  378. font-size: 12px;
  379. color: #6a7282;
  380. text-decoration: line-through;
  381. }
  382. .right-collect {
  383. font-size: 14px;
  384. color: #6a7282;
  385. cursor: pointer;
  386. .icon-star {
  387. margin-right: 4px;
  388. }
  389. img {
  390. width: 12px;
  391. height: 12px;
  392. margin-right: 6px;
  393. }
  394. }
  395. }
  396. .address {
  397. height: 44px;
  398. width: 100%;
  399. border-top: 1px solid #e5e7eb;
  400. border-bottom: 1px solid #e5e7eb;
  401. margin-top: 20px;
  402. font-size: 14px;
  403. color: #000000;
  404. .address-img {
  405. width: 16px;
  406. height: 16px;
  407. margin-right: 10px;
  408. margin-top: 2px;
  409. }
  410. .address-text {
  411. margin-left: 10px;
  412. width: 138px;
  413. }
  414. }
  415. .specs-bos {
  416. .specs-list {
  417. margin-top: 15px;
  418. font-size: 14px;
  419. color: #364153;
  420. display: flex;
  421. align-items: center;
  422. .specs-item {
  423. color: #6a7282;
  424. margin-left: 10px;
  425. }
  426. }
  427. }
  428. .number-bos {
  429. margin-top: 20px;
  430. font-size: 14px;
  431. color: #364153;
  432. .number-box {
  433. font-size: 14px;
  434. color: #6a7282;
  435. margin-top: 8px;
  436. }
  437. }
  438. .bnt-bos {
  439. width: 428px;
  440. height: 44px;
  441. border-radius: 10px;
  442. overflow: hidden;
  443. div {
  444. width: 428px;
  445. // width: 214px;
  446. height: 44px;
  447. line-height: 44px;
  448. text-align: center;
  449. cursor: pointer;
  450. &:nth-of-type(1) {
  451. background: #fcecf1;
  452. color: #e7000b;
  453. }
  454. &:nth-of-type(2) {
  455. background: #e7000b;
  456. color: #ffffff;
  457. }
  458. }
  459. }
  460. }
  461. }
  462. .nav-bos {
  463. width: 696px;
  464. height: 48px;
  465. background: #f9fafb;
  466. border: 1px solid #e5e7eb;
  467. margin-top: 20px;
  468. gap: 0 32px;
  469. padding-left: 32px;
  470. font-size: 16px;
  471. color: #364153;
  472. div {
  473. cursor: pointer;
  474. }
  475. .hig {
  476. color: #101828;
  477. font-weight: 600;
  478. }
  479. }
  480. .pcDetail {
  481. width: 696px;
  482. margin-top: 20px;
  483. }
  484. .service {
  485. width: 696px;
  486. margin-top: 20px;
  487. background: #ffffff;
  488. padding: 20px;
  489. border-radius: 10px;
  490. div {
  491. margin-bottom: 20px;
  492. font-size: 14px;
  493. }
  494. .service1 {
  495. font-weight: 600;
  496. }
  497. .service2 {
  498. color: #999999;
  499. }
  500. }
  501. .shop-img {
  502. width: 696px;
  503. height: 752px;
  504. margin-top: 20px;
  505. }
  506. .shop-more {
  507. width: 696px;
  508. margin-top: 34px;
  509. .more1 {
  510. font-weight: 600;
  511. font-size: 20px;
  512. color: #101828;
  513. }
  514. .more2 {
  515. font-size: 14px;
  516. color: #364153;
  517. margin-left: 10px;
  518. }
  519. .more3 {
  520. font-size: 14px;
  521. color: #364153;
  522. margin-right: 6px;
  523. cursor: pointer;
  524. }
  525. }
  526. //数据
  527. .data-bos {
  528. display: flex;
  529. gap: 20px;
  530. flex-wrap: wrap;
  531. margin-bottom: 40px;
  532. margin-top: 24px;
  533. .data-list {
  534. width: 224px;
  535. background: #ffffff;
  536. border-radius: 10px;
  537. padding: 20px 20px 22px 20px;
  538. cursor: pointer;
  539. .data-img {
  540. width: 184px;
  541. height: 184px;
  542. border-radius: 10px;
  543. }
  544. .data-title {
  545. margin-top: 4px;
  546. font-size: 14px;
  547. color: #101828;
  548. height: 40px;
  549. }
  550. .money {
  551. margin-top: 4px;
  552. .money1 {
  553. font-size: 16px;
  554. color: #e7000b;
  555. }
  556. .money2 {
  557. font-size: 12px;
  558. color: #99a1af;
  559. text-decoration: line-through;
  560. padding-left: 6px;
  561. }
  562. }
  563. .data-cat {
  564. width: 86px;
  565. height: 26px;
  566. background: #e7000b;
  567. border-radius: 2px;
  568. font-size: 14px;
  569. color: #ffffff;
  570. line-height: 26px;
  571. text-align: center;
  572. margin-top: 16px;
  573. }
  574. }
  575. }
  576. }
  577. </style>