多租户商城-商户小程序端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

767 lines
21 KiB

3 years ago
  1. <!--
  2. * @FileDescription: sku选择器花呗拼团下单
  3. * @Author: kahu
  4. * @Date: 2022/11/7
  5. * @LastEditors: kahu
  6. * @LastEditTime: 2022/11/7
  7. -->
  8. <template>
  9. <div class="content">
  10. <u-popup
  11. v-model="goodsDetailShowFlag"
  12. mode="bottom"
  13. border-radius="14"
  14. >
  15. <view class="goosDetailshow-box">
  16. <view class="detailImg-box flex-row-plus">
  17. <image
  18. class="detailImg"
  19. :src="selectedSku.image"
  20. ></image>
  21. <view class="flex-column-plus mar-left-40">
  22. <view class="font-color-C5AA7B">
  23. <label class="fs24">¥</label>
  24. <label
  25. class="fs36 mar-left-10"
  26. v-text="selectedSku.activityType === 1 && btnType === 4 ? selectedSku['salePrice'] : selectedSku.price"
  27. ></label>
  28. </view>
  29. <label class="fs24 font-color-999 mar-top-20">库存 {{ selectedSku.stockNumber }} </label>
  30. <label class="fs24 mar-top-20">已选</label>
  31. </view>
  32. </view>
  33. <view class="color-box flex-column-plus">
  34. <view
  35. v-for="(skuRowItem,skuRowIndex) in productData['names']"
  36. :key="skuRowIndex"
  37. >
  38. <label
  39. class="fs26 font-color-333"
  40. v-if="skuRowItem['nameCode']"
  41. >{{ skuRowItem.skuName }}</label>
  42. <view class="colorName-box">
  43. <view
  44. class="pad-bot-30"
  45. v-for="(skuColItem, skuColIndex) in skuRowItem.values"
  46. :key="skuColIndex"
  47. >
  48. <view
  49. class="colorName"
  50. :class="{'colorName-on' : selectedAttr[skuRowItem['nameCode']] === skuColItem.valueCode}"
  51. @click="handleClickSkuItem(skuRowItem['nameCode'], skuColItem.valueCode)"
  52. >
  53. {{ skuColItem.skuValue }}
  54. </view>
  55. </view>
  56. </view>
  57. </view>
  58. </view>
  59. <view class="goodsNumCent">
  60. <view
  61. class="goodsNum-box flex-row-plus flex-sp-between"
  62. :class="{'bottom-line' :aliAgingObj.supportHanaUta}"
  63. >
  64. <label class="font-color-333 fs26">数量</label>
  65. <view class="goodsNum">
  66. <view
  67. class="item subtract"
  68. @click="handleNumSub"
  69. >-
  70. </view>
  71. <view
  72. class="item goodsNumber"
  73. v-model="buyNum"
  74. >{{ buyNum }}
  75. </view>
  76. <view
  77. class="item add"
  78. @click="handleNumAdd"
  79. >+
  80. </view>
  81. </view>
  82. </view>
  83. </view>
  84. <!-- 花呗分期 -->
  85. <view
  86. class="huabei-box flex-column-plus"
  87. v-if="aliAgingObj.supportHanaUta"
  88. >
  89. <label class="font-color-999 fs24">花呗分期</label>
  90. <scroll-view
  91. class="fenqi-box"
  92. scroll-x="true"
  93. >
  94. <view
  95. class="huabei-item"
  96. :class="[{'fenqi-on' :aliAgingObj.selectIndex === 0},{'disabled' :aliAgingObj.disableSelectList[0]}]"
  97. @click="handleSelectAliAging(0)"
  98. >
  99. <label class="huabei-period">分3期(含手续费)</label>
  100. <label class="huabei-money">{{ aliAgingObj.agingMoneyList[0] }}/</label>
  101. </view>
  102. <view
  103. class="huabei-item"
  104. :class="[{'fenqi-on' :aliAgingObj.selectIndex === 1},{'disabled' :aliAgingObj.disableSelectList[1]}]"
  105. @click="handleSelectAliAging(1)"
  106. >
  107. <label class="huabei-period">分6期(含手续费)</label>
  108. <label class="huabei-money">{{ aliAgingObj.agingMoneyList[1] }}/</label>
  109. </view>
  110. <view
  111. class="huabei-item"
  112. :class="[{'fenqi-on' :aliAgingObj.selectIndex === 2},{'disabled' :aliAgingObj.disableSelectList[2]}]"
  113. @click="handleSelectAliAging(2)"
  114. >
  115. <label class="huabei-period">分12期(含手续费)</label>
  116. <label class="huabei-money">{{ aliAgingObj.agingMoneyList[2] }}/</label>
  117. </view>
  118. </scroll-view>
  119. </view>
  120. <view
  121. v-if="btnType===6"
  122. class="skuSelectBtn"
  123. >
  124. <view
  125. class="flex-row-plus offShelf"
  126. v-if="productData.shelveState === 0"
  127. >
  128. 商品已下架
  129. </view>
  130. <view
  131. class="flex-row-plus flex-items flex-sp-around"
  132. v-else-if="selectedSku.activityType === 1"
  133. >
  134. <view
  135. class="selectJoinShop selectBtn font-color-333"
  136. @click="handleBuyNow"
  137. >单独购买
  138. </view>
  139. <view
  140. class="selectBuyNow selectBtn font-color-FFEBC4"
  141. @click="handleBuyWithGroup(1)"
  142. >我要开团
  143. </view>
  144. </view>
  145. <view
  146. class="flex-row-plus flex-items flex-sp-around"
  147. v-else
  148. >
  149. <view
  150. class="selectJoinShop selectBtn font-color-333"
  151. @click="handleAddCart"
  152. >加入购物车
  153. </view>
  154. <view
  155. class="selectBuyNow selectBtn font-color-FFEBC4"
  156. @click="handleBuyNow"
  157. >立即购买
  158. </view>
  159. </view>
  160. </view>
  161. <view v-else>
  162. <view
  163. v-if="selectedSku.activityType === 1 && collageId !== 0"
  164. class="goosDetailbut-box flex-items-plus"
  165. :style="{'padding-bottom':(isIphone === true? 60:20)+'rpx'}"
  166. >
  167. <view
  168. class="joinbuyBut"
  169. @click="handleBuyWithGroup(2)"
  170. >确定
  171. </view>
  172. </view>
  173. <view
  174. v-else-if="selectedSku.activityType === 1 && btnType === 3"
  175. class="goosDetailbut-box flex-row-plus"
  176. :style="{'padding-bottom':(isIphone === true? 60:20)+'rpx'}"
  177. >
  178. <view
  179. class="buyNowBut"
  180. @click="handleBuyWithGroup(1)"
  181. >去拼团
  182. </view>
  183. </view>
  184. <view
  185. v-else
  186. class="goosDetailbut-box flex-row-plus"
  187. :style="{'padding-bottom':(isIphone === true? 60:20)+'rpx'}"
  188. >
  189. <view
  190. v-if="btnType === 1"
  191. class="buyNowBut"
  192. @click="handleAddCart"
  193. >确认
  194. </view>
  195. <view
  196. v-else
  197. class="buyNowBut"
  198. @click="handleBuyNow(2)"
  199. >确认
  200. </view>
  201. </view>
  202. </view>
  203. </view>
  204. </u-popup>
  205. </div>
  206. </template>
  207. <script>
  208. import NET from "../../../utils/request";
  209. import API from "../../../config/api";
  210. export default {
  211. name: "GoodSkuSelect",
  212. data() {
  213. return {
  214. // 是否展示SKU弹窗
  215. goodsDetailShowFlag: false,
  216. // 已经选中的valueCode key => value names.nameCode=>values.valueCode 处理选中渲染
  217. selectedAttr: {},
  218. // 当前选中的skuMap对象(服务端数据)
  219. selectedSku: {},
  220. // 1加入购物车 2立即购买 3开团 4单独购买 6SKU选择
  221. btnType: 0,
  222. buyNum: 1,
  223. // 花呗对象
  224. aliAgingObj: {
  225. supportHanaUta: false,
  226. selectIndex: -1,
  227. disableSelectList: [true, true, true],
  228. agingMoneyList: ["0.00", "0.00", "0.00"]
  229. }
  230. }
  231. },
  232. props: {
  233. productData: {
  234. type: Object,
  235. default: () => ({})
  236. },
  237. isIphone: {
  238. type: Boolean,
  239. default: () => false
  240. },
  241. collageId: {
  242. type: Number,
  243. default: () => 0
  244. }
  245. },
  246. methods: {
  247. /**
  248. * 当前SKU数量减少
  249. */
  250. handleNumSub() {
  251. if (this.buyNum > 1) {
  252. this.buyNum = this.buyNum - 1
  253. } else {
  254. uni.showToast({
  255. title: '亲!至少一件哦!',
  256. icon: "none"
  257. })
  258. }
  259. },
  260. /**
  261. * 当前SKU数量加
  262. */
  263. handleNumAdd() {
  264. if (this.buyNum < this.selectedSku.stockNumber) {
  265. this.buyNum = this.buyNum + 1
  266. } else {
  267. uni.showToast({
  268. title: '库存不足!',
  269. icon: "none"
  270. })
  271. }
  272. },
  273. /**
  274. * 根据skuId选择SKU
  275. * @param skuId SkuId
  276. */
  277. handleSelectBySkuId(skuId) {
  278. if (!skuId) return
  279. // 当前商品后端返回的所有sku的排列组合
  280. const allSkuValueGroupMap = this.productData.map
  281. for (const allSkuValueGroupMapKey in allSkuValueGroupMap) {
  282. if (parseInt(allSkuValueGroupMap[allSkuValueGroupMapKey].skuId) !== parseInt(skuId)) continue;
  283. this.selectedSku = allSkuValueGroupMap[allSkuValueGroupMapKey]
  284. this.echoFatherRowText(this.productData, this.selectedSku, this.buyNum)
  285. // 控制组件选中渲染
  286. const selectValueCodes = this.selectedSku['valueCodes'].split(',')
  287. for (const skuRow of this.productData.names) {
  288. for (const skuCol of skuRow.values) {
  289. if (!selectValueCodes.includes(skuCol['valueCode'])) continue;
  290. this.$set(this.selectedAttr, skuRow['nameCode'], skuCol['valueCode'])
  291. break; // 一行的sku只会有一个value
  292. }
  293. }
  294. }
  295. },
  296. /**
  297. * 点击sku的一项
  298. * @param nameCode SKU行的nameCode
  299. * @param valueCode SKU列的valueCode
  300. * nameCodeValueCodeClick
  301. */
  302. handleClickSkuItem(nameCode, valueCode) {
  303. // 当前选中
  304. this.$set(this.selectedAttr, nameCode, valueCode)
  305. // 获取到所有的sku的values.valueCode
  306. let values = []
  307. for (const key in this.selectedAttr) {
  308. values.push(this.selectedAttr[key])
  309. }
  310. // 当前选中的sku的key组合
  311. // 后端返回的productData.map中,排列组合了所有values[].valueCode的情况,使用逗号分隔
  312. const nowSelectSkuValueGroupKey = values.join(',') // 相较于allSkuValueGroupMap的key
  313. // 后端返回的所有sku组合(values.valueCode)
  314. const allSkuValueGroupMap = this.productData.map
  315. // 遍历后端数据
  316. for (const allSkuValueGroupMapKey in allSkuValueGroupMap) {
  317. // 当和当前选中的sku一致
  318. if (nowSelectSkuValueGroupKey === allSkuValueGroupMapKey) {
  319. this.selectedSku = allSkuValueGroupMap[allSkuValueGroupMapKey]
  320. this.echoFatherRowText(this.productData, this.selectedSku, this.buyNum)
  321. }
  322. }
  323. },
  324. /**
  325. * 回显父组件通讯
  326. * @param productData 当前商品对象
  327. * @param skuItem 当前选中的sku的后端数据
  328. * @param buyNum 当前sku购买数量
  329. */
  330. echoFatherRowText(productData, skuItem, buyNum) {
  331. // 获取到当前选中的sku的valueCode
  332. const currentSku = []
  333. // 取出所有的valueCode
  334. const nowSelectValueCodeList = skuItem['valueCodes'].split(',')
  335. const skuRows = productData.names
  336. for (const skuRow of skuRows) {
  337. const skuValues = skuRow.values
  338. for (const skuValue of skuValues) {
  339. if (!nowSelectValueCodeList.includes(skuValue.valueCode)) continue;
  340. const currentSkuItem = {skuText: ''}
  341. if (skuValue.valueCode === '单款项') {
  342. currentSkuItem['skuText'] = skuValue['skuValue']
  343. } else {
  344. currentSkuItem['skuText'] = `${ skuValue.skuName }:${ skuValue.skuValue }`
  345. }
  346. currentSku.push(currentSkuItem)
  347. break; // 只会对应一个value数据,找到就break减少循环
  348. }
  349. }
  350. this.$emit('getCurrentSku', {
  351. skuItem,
  352. currentSku,
  353. buyNum
  354. })
  355. // 选中sku之后,做一些相应的操作
  356. // postSelectSku依赖于getCurrentSku的数据
  357. this.$emit('postSelectSku')
  358. },
  359. //加入购物车
  360. async handleAddCart() {
  361. this.handleCheckIsLogin()
  362. if (this.selectedSku.stockNumber < 1) {
  363. return uni.showToast({
  364. title: '库存不足',
  365. icon: "none"
  366. })
  367. }
  368. // uni.showLoading({
  369. // mask: true,
  370. // title: '添加中...',
  371. // })
  372. try {
  373. const postData = {
  374. skuId: this.selectedSku.skuId,
  375. number: this.buyNum,
  376. }
  377. await NET.request(API.ShoppingaddCart, postData, 'POST')
  378. // 埋点
  379. this.$store.dispatch('doPointer', {
  380. eventType: 2,
  381. productIds: this.productId
  382. })
  383. // 给购物车小图标赋值数量
  384. let newAllCartNum = uni.getStorageSync('allCartNum') + this.buyNum
  385. uni.setStorageSync('allCartNum', newAllCartNum)
  386. this.$emit('changeCartNum',newAllCartNum)
  387. uni.showToast({
  388. title: '添加成功',
  389. icon: 'none'
  390. })
  391. setTimeout(()=>{
  392. this.buyNum = 1
  393. this.goodsDetailShowFlag = false
  394. },2000)
  395. }finally {
  396. uni.hideLoading()
  397. }
  398. },
  399. /**
  400. * 立即购买下单
  401. */
  402. handleBuyNow() {
  403. this.handleCheckIsLogin()
  404. if (this.selectedSku.stockNumber < 1) {
  405. return uni.showToast({
  406. title: '库存不足',
  407. icon: "none"
  408. })
  409. }
  410. if (this.buyNum > this.selectedSku.stockNumber && this.selectedSku.stockNumber !== 0) {
  411. return uni.showToast({
  412. title: '已超出最大数量限制',
  413. icon: "none"
  414. })
  415. }
  416. //组装后端数据
  417. let list = [{
  418. ifWork: 0,
  419. shopId: this.productData.shopId,
  420. shopName: this.productData.shopName,
  421. shopDiscountId: this.shopDiscountId > 0 ? this.shopDiscountId : null,
  422. shopSeckillId: this.shopSeckillId > 0 ? this.shopSeckillId : null,
  423. skus: [{
  424. productId: this.productData.productId,
  425. skuId: this.selectedSku.skuId,
  426. productName: this.productData.productName,
  427. image: this.selectedSku.image,
  428. price: this.selectedSku.price,
  429. weight: 0,
  430. number: this.buyNum,
  431. SKU: "",
  432. total: this.selectedSku.price * this.buyNum,
  433. ifLogistics: 1
  434. }]
  435. }]
  436. uni.setStorageSync('skuItemDTOList', list)
  437. this.buyNum = 1
  438. this.goodsDetailShowFlag = false
  439. uni.navigateTo({
  440. url: '../orderModule/orderConfirm?type=1',
  441. })
  442. },
  443. /**
  444. * 拼团下单
  445. * @param type 1单独开团2拼团
  446. */
  447. handleBuyWithGroup(type) {
  448. this.handleCheckIsLogin()
  449. if (this.selectedSku.stockNumber < 1) {
  450. return uni.showToast({
  451. title: '库存不足',
  452. icon: "none"
  453. })
  454. }
  455. const data = {
  456. number: this.buyNum,
  457. productId: this.productId,
  458. shopId: this.shopId,
  459. skuId: this.selectedSku.skuId,
  460. shopGroupWorkId: this.selectedSku.shopGroupWorkId,
  461. type: type
  462. }
  463. if (type !== 1) {
  464. data.collageId = this.collageId
  465. }
  466. uni.removeStorageSync("skuItemDTOList")
  467. uni.setStorageSync('skuItemList', data)
  468. this.goodsDetailShowFlag = false
  469. this.buyNum = 1
  470. uni.navigateTo({
  471. url: '../orderModule/orderConfirm?type=1',
  472. })
  473. },
  474. /**
  475. * 是否登录
  476. * @return {boolean|void}
  477. */
  478. handleCheckIsLogin() {
  479. const userInfo = uni.getStorageSync('storage_key')
  480. if (!userInfo || (userInfo && JSON.stringify(userInfo) === '{}')) {
  481. return uni.navigateTo({
  482. url: '../../pages_category_page2/userModule/login'
  483. })
  484. }
  485. return true
  486. },
  487. /**
  488. * 选择分期
  489. * @param index 0:3 1:6 2:12
  490. */
  491. handleSelectAliAging(index) {
  492. const aliAgingObj = this.aliAgingObj
  493. if (aliAgingObj.selectIndex !== index && !aliAgingObj.disableSelectList[index]) {
  494. aliAgingObj.selectIndex = index;
  495. } else {
  496. aliAgingObj.selectIndex = -1;
  497. }
  498. },
  499. /**
  500. * 渲染是否支持花呗
  501. * @param productData 当前商品
  502. * @param skuPrice:number 选中SKU的价格
  503. */
  504. handleRenderAliAging(productData, skuPrice) {
  505. if (productData.ifHuabei !== 1) return
  506. const aliAgingObj = this.aliAgingObj
  507. if (skuPrice && skuPrice >= 0.03) {
  508. aliAgingObj.supportHanaUta = true
  509. aliAgingObj.disableSelectList[0] = false;
  510. aliAgingObj.agingMoneyList[0] = (parseInt((skuPrice / 3 * 100) / 100 + '')).toFixed(2) + ""
  511. }
  512. if (skuPrice && skuPrice >= 0.06) {
  513. aliAgingObj.supportHanaUta = false;
  514. aliAgingObj.disableSelectList[1] = false;
  515. aliAgingObj.agingMoneyList[1] = (parseInt((skuPrice / 6 * 100) / 100 + '')).toFixed(2) + ""
  516. }
  517. if (skuPrice && skuPrice >= 0.12) {
  518. aliAgingObj.supportHanaUta = true;
  519. aliAgingObj.disableSelectList[2] = false;
  520. aliAgingObj.agingMoneyList[2] = (parseInt((skuPrice / 12 * 100) / 100 + '')).toFixed(2) + ""
  521. }
  522. },
  523. }
  524. }
  525. </script>
  526. <style
  527. lang="scss"
  528. scoped
  529. >
  530. .goosDetailshow-box {
  531. margin-bottom: -5upx;
  532. .detailImg-box {
  533. margin-top: 30upx;
  534. margin-left: 30upx;
  535. border-bottom: 1upx solid #EDEDED;
  536. padding-bottom: 20upx;
  537. width: 690upx;
  538. .detailImg {
  539. width: 180upx;
  540. height: 180upx;
  541. }
  542. }
  543. .color-box {
  544. padding: 30upx 30upx;
  545. width: 690upx;
  546. .colorName-box {
  547. display: flex;
  548. flex-wrap: wrap;
  549. flex-direction: row;
  550. justify-content: flex-start;
  551. align-items: center;
  552. margin-top: 30upx;
  553. margin-left: -30upx;
  554. .colorName {
  555. background-color: #FFFFFF;
  556. margin-left: 30upx;
  557. padding: 10upx 32upx;
  558. font-size: 26upx;
  559. border: 2rpx solid #E4E5E6;
  560. z-index: 2;
  561. color: #333333;
  562. }
  563. .colorName-on {
  564. box-shadow: 0 0 20rpx rgba(0, 0, 0, 0.1);
  565. color: #C5AA7B;
  566. margin-left: 30upx;
  567. padding: 10upx 32upx;
  568. font-size: 26upx;
  569. text-align: center;
  570. z-index: 1;
  571. border: none;
  572. }
  573. }
  574. }
  575. .modelNum-box {
  576. padding: 30upx 30upx;
  577. border-bottom: 1upx solid #EDEDED;
  578. width: 690upx;
  579. .modelNumName-box {
  580. display: flex;
  581. flex-wrap: wrap;
  582. flex-direction: row;
  583. justify-content: flex-start;
  584. align-items: center;
  585. margin-top: 30upx;
  586. margin-left: -30upx;
  587. .modelNumName-on {
  588. background-color: #FFE4D0;
  589. color: #FF7800;
  590. margin-left: 30upx;
  591. padding: 10upx 32upx;
  592. border-radius: 28upx;
  593. border: 1upx solid #FF7800;
  594. font-size: 26upx;
  595. text-align: center;
  596. }
  597. .modelNumName {
  598. background-color: #F5F5F5;
  599. margin-left: 30upx;
  600. padding: 10upx 32upx;
  601. border-radius: 28upx;
  602. font-size: 26upx;
  603. }
  604. }
  605. }
  606. .goodsNumCent {
  607. padding: 0 30upx;
  608. .goodsNum-box {
  609. width: 100%;
  610. padding: 30rpx 0 180rpx 0;
  611. border-top: 2rpx solid #EDEDED;
  612. .goodsNum {
  613. height: 50upx;
  614. display: flex;
  615. align-items: center;
  616. .item {
  617. width: 50upx;
  618. height: 50upx;
  619. line-height: 48rpx;
  620. border: 1upx solid #999999;
  621. text-align: center;
  622. }
  623. .subtract {
  624. border-right: 0upx;
  625. }
  626. .goodsNumber {
  627. line-height: 50rpx;
  628. }
  629. .add {
  630. border-left: 0upx;
  631. }
  632. }
  633. }
  634. }
  635. .bottom-line {
  636. border-bottom: 1upx solid #EDEDED;
  637. }
  638. .huabei-box {
  639. padding: 30upx 30upx;
  640. width: 690upx;
  641. .fenqi-box {
  642. margin-top: 15upx;
  643. width: 120%;
  644. .huabei-item {
  645. display: inline-block;
  646. background: #f3f3f3;
  647. padding: 16upx 24upx;
  648. margin: 5upx 10upx;
  649. border-radius: 15upx;
  650. text-align: center;
  651. font-size: 7upx;
  652. .huabei-period {
  653. display: block;
  654. }
  655. }
  656. .fenqi-on {
  657. border: 1px solid #EF7F93;
  658. color: #EF7F93;
  659. }
  660. .disabled {
  661. color: #cacaca;
  662. }
  663. }
  664. }
  665. .goosDetailbut-box {
  666. justify-content: center;
  667. .joinShopCartBut {
  668. width: 343upx;
  669. height: 80upx;
  670. border-radius: 40upx 0 0 40upx;
  671. background-color: #FFC300;
  672. color: #FFFEFE;
  673. font-size: 28upx;
  674. line-height: 80upx;
  675. text-align: center;
  676. margin-left: 30upx;
  677. }
  678. .buyNowBut {
  679. width: 90%;
  680. height: 90upx;
  681. background-color: #333333;
  682. font-size: 28upx;
  683. line-height: 90upx;
  684. text-align: center;
  685. color: #FFEBC4;
  686. }
  687. }
  688. }
  689. .skuSelectBtn {
  690. padding-bottom: 30rpx;
  691. .selectBtn {
  692. width: 342rpx;
  693. height: 100rpx;
  694. line-height: 100rpx;
  695. text-align: center;
  696. border: 2rpx solid #333333;
  697. font-size: 28rpx;
  698. border-radius: 8rpx;
  699. }
  700. .selectBuyNow {
  701. background: #333333;
  702. }
  703. }
  704. .couponItemimg {
  705. width: 150upx;
  706. height: 60upx;
  707. }
  708. .joinbuyBut {
  709. width: 190upx;
  710. height: 80upx;
  711. background: #333333;
  712. color: #FFEBC4;
  713. font-size: 28upx;
  714. line-height: 80upx;
  715. text-align: center;
  716. margin-left: 30upx;
  717. }
  718. </style>