多租户商城-商户小程序端
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.

633 lines
18 KiB

2 years ago
  1. <template>
  2. <view class="group-list" v-if="selectComposeData && selectComposeData.length > 0">
  3. <view class="group-warp">
  4. <view class="title">
  5. <label>
  6. <image class="title-img" src="https://ceres.zkthink.com/static/images/combinationIcon.png" alt="组合销售" mode="widthFix"></image>
  7. </label>
  8. <view class="price-text">
  9. 组合价¥{{composePrice}}
  10. </view>
  11. </view>
  12. <view>
  13. <scroll-view class="tabs-nav" scroll-x="true">
  14. <view class="ul">
  15. <view v-for="(item,index) in selectComposeData" :key="index" class="li" :class="tabIndex===index && 'on'" @click="tabChange(index)">
  16. {{ item.composeName }}</view>
  17. </view>
  18. </scroll-view>
  19. <view class="tabs-item" v-for="(item,index) in selectComposeData" :key="index" :class="tabIndex===index && 'on'">
  20. <swiper class="swiper pro-box" :indicator-dots="false" :autoplay="true" :display-multiple-items="item.composeProductInfoList.length < 3?item.composeProductInfoList.length:3" @change="swiperChange" :disable-touch="item.composeProductInfoList.length <= 3">
  21. <swiper-item class="pro-item-warp" v-for="(itemJ,indexJ) in item.composeProductInfoList" :key="indexJ" >
  22. <view class="pro-item-inner">
  23. <view class="pro-item">
  24. <view class="pro-item-img">
  25. <image class="img" :src="itemJ.productImage"></image>
  26. </view>
  27. <view class="pro-item-info">
  28. <h3 class="name">
  29. {{itemJ.productName}}
  30. </h3>
  31. <view class="sku" @click.stop="changeSkuItemValue(itemJ, indexJ)">
  32. <view class="text">{{itemJ.skuItem.skuName}}</view>
  33. </view>
  34. </view>
  35. </view>
  36. </view>
  37. </swiper-item>
  38. </swiper>
  39. <view class="swiper-dots" v-if='item.composeProductInfoList.length > 3'>
  40. <text :class="{'dot-active':swiperCurrent === index,'dot': true}"
  41. v-for="(dot, index) in item.composeProductInfoList.length - 2"
  42. :key="index"
  43. ></text>
  44. </view>
  45. </view>
  46. <view class="btn-buy" @click="doBuy">立即购买</view>
  47. </view>
  48. </view>
  49. <!-- 商品详情 -->
  50. <u-popup v-model="goodsDetailShowFlag" mode="bottom" border-radius="14">
  51. <view class="goosDetailshow-box">
  52. <view class="detailImg-box flex-row-plus">
  53. <image class="detailImg" :src="selectedSku.image"></image>
  54. <view class="flex-column-plus mar-left-40">
  55. <view class="font-color-C5AA7B">
  56. <label class="fs24">¥</label>
  57. <label class="fs36 mar-left-10"
  58. v-text="getPrice(selectedSku)"></label>
  59. </view>
  60. <label class="fs24 font-color-999 mar-top-20">库存 {{selectedSku.stockNumber}} </label>
  61. <label class="fs24 mar-top-20">已选</label>
  62. </view>
  63. </view>
  64. <view class="color-box flex-column-plus">
  65. <view v-for="(attritem,index) in skuProData.names" :key="index" class="skuStyle">
  66. <label class="fs24 font-color-999">{{attritem.skuName}}</label>
  67. <view class="colorName-box">
  68. <view class="pad-bot-30" v-for="(attrRes, resIndex) in attritem.values" :key="resIndex">
  69. <view class="colorName"
  70. :class="{'colorName-on' : getselectedAttrVal(attritem.nameCode) == attrRes.valueCode}"
  71. @click="nameCodeValueCodeClick(attritem.nameCode, attrRes.valueCode, true)">
  72. {{attrRes.skuValue}}
  73. </view>
  74. </view>
  75. </view>
  76. </view>
  77. </view>
  78. <!-- <view class="goodsNum-box flex-row-plus flex-sp-between" :class="{'bottom-line' :supportHuabei}">-->
  79. <!-- <label class="font-color-999 fs24">数量</label>-->
  80. <!-- <view class="goodsNum">-->
  81. <!-- <text class="subtract" @click="updateNumSub()">-</text>-->
  82. <!-- <text class="goodsNumber" v-model="buyNum">{{buyNum}}</text>-->
  83. <!-- <text class="add" @click.stop="-->
  84. <!-- ()">+</text>-->
  85. <!-- </view>-->
  86. <!-- </view>-->
  87. <view class="goosDetailbut-box flex-items-plus">
  88. <!-- <button type="default" @click="goodsDateils(shopId,productId,skuId)" >查看详情</button>-->
  89. <button type="default" class="submitBtn" @click="submitBtn()">确认</button>
  90. </view>
  91. </view>
  92. </u-popup>
  93. </view>
  94. </template>
  95. <script>
  96. import NET from "../../utils/request";
  97. import API from "../../config/api";
  98. export default {
  99. name: "combinedSales",
  100. props: {
  101. pid: {
  102. type: String,
  103. default: ''
  104. },
  105. productData: {
  106. type: Object,
  107. default: ()=>{}
  108. }
  109. },
  110. data () {
  111. return {
  112. skuShowFalg: false,
  113. tabIndex: 0,
  114. swiperCurrent: 0,
  115. selectComposeData: [],
  116. curProIndex: 0,
  117. selectedSku: [],
  118. selectedAttr: [],
  119. skuProData: {},
  120. goodsDetailShowFlag: false,
  121. composePrice: 0
  122. }
  123. },
  124. mounted() {
  125. this.getSelectCompose()
  126. },
  127. methods:{
  128. // 切换套餐
  129. tabChange(index){
  130. this.tabIndex = index
  131. this.calculatePrice()
  132. },
  133. // 滑动回调方法
  134. swiperChange(e) {
  135. this.swiperCurrent = e.detail.current;
  136. },
  137. // 获取组合销售数据
  138. getSelectCompose() {
  139. NET.request(API.selectCompose, {
  140. productId: this.pid
  141. },
  142. "GET").then(res => {
  143. this.selectComposeData = res.data
  144. for(let i=0;i< this.selectComposeData.length;i++) {
  145. let proList = this.selectComposeData[i].composeProductInfoList
  146. for (let j = 0; j < proList.length; j++) {
  147. proList[j].skuItem = proList[j].composeSkuInfoList[0]
  148. }
  149. }
  150. this.calculatePrice()
  151. }).catch(res => {
  152. })
  153. },
  154. // 更换商品样式
  155. changeSkuItemValue(item,index) {
  156. this.curProIndex = index
  157. uni.showLoading({
  158. mask: true,
  159. title: '加载中...'
  160. })
  161. NET.request(API.QueryProductDetail, {
  162. shopId: this.productData.shopId,
  163. productId: item.productId,
  164. skuId: item.skuItem.skuId,
  165. terminal: 1
  166. },
  167. "GET").then(res => {
  168. uni.hideLoading()
  169. this.skuProData = res.data
  170. // console.log(this.skuProData,'this.skuProData', res.data)
  171. //如果是单款式商品,需要特殊处理productData.names
  172. const mapKeys = Object.keys(this.skuProData.map)
  173. if (mapKeys.length === 1 && mapKeys[0] === '单款项') {
  174. this.skuProData.names[0].values.push({
  175. skuValue: '单款项',
  176. valueCode: '单款项'
  177. })
  178. }
  179. //如果sku的图像为空,设置为商品的图像
  180. for (var key in this.skuProData.map) {
  181. let skuImage = this.skuProData.map[key].image
  182. if (!skuImage) {
  183. this.skuProData.map[key].image = this.skuProData.images[0]
  184. }
  185. }
  186. this.goodsDetailShowFlag = true
  187. this.selectBySkuId(item.skuItem.skuId)
  188. }).catch(res => {
  189. uni.hideLoading()
  190. })
  191. },
  192. selectBySkuId(skuId) {
  193. if (skuId) {
  194. let mapinfo = this.skuProData.map
  195. let flag = true
  196. for (var key in mapinfo) {
  197. if (parseInt(mapinfo[key].skuId) === parseInt(skuId)) {
  198. flag = false
  199. this.selectedSku = mapinfo[key]
  200. // 选中sku对应的规格
  201. const valueCodeList = key.split(',')
  202. this.selectedAttr = []
  203. this.skuProData.names.forEach(attr => {
  204. for (var index in attr.values) {
  205. let valueCode = attr.values[index].valueCode
  206. if (valueCodeList.includes(valueCode)) {
  207. this.nameCodeValueCodeClick(attr.nameCode, valueCode, false)
  208. break
  209. }
  210. }
  211. })
  212. break
  213. }
  214. }
  215. // 匹配不上就赋值第一个
  216. if(flag){
  217. for (var key in mapinfo) {
  218. console.log(key,'key')
  219. this.selectedSku = mapinfo[key]
  220. break
  221. }
  222. }
  223. }
  224. },
  225. nameCodeValueCodeClick(nameCode, valueCode, reSelectSku) {
  226. this.selectedAttr[nameCode] = valueCode
  227. console.log(this.selectedAttr, 'this.selectedAttr')
  228. if (reSelectSku) {
  229. let attrList = []
  230. for (var key in this.selectedAttr) {
  231. attrList.push(this.selectedAttr[key])
  232. }
  233. const attrkey = attrList.join(',')
  234. let mapinfo = this.skuProData.map
  235. for (var key in mapinfo) {
  236. if (attrkey === key) {
  237. this.selectedSku = mapinfo[key]
  238. }
  239. }
  240. }
  241. this.$forceUpdate(); // 重绘
  242. },
  243. // 提交更换商品规格
  244. submitBtn() {
  245. console.log(this.selectedSku,'this.selectedSku')
  246. const curPro = this.selectComposeData[this.tabIndex].composeProductInfoList[this.curProIndex]
  247. for(let i=0;i<curPro.composeSkuInfoList.length;i++){
  248. if(curPro.composeSkuInfoList[i].skuId === this.selectedSku.skuId){
  249. this.selectedSku.skuName = curPro.composeSkuInfoList[i].skuName
  250. }
  251. }
  252. curPro.skuItem = this.selectedSku
  253. this.calculatePrice()
  254. this.goodsDetailShowFlag = false
  255. },
  256. // 计算组合价
  257. calculatePrice(){
  258. const proList = this.selectComposeData[this.tabIndex].composeProductInfoList,composeType= this.selectComposeData[this.tabIndex].composeType,promote= this.selectComposeData[this.tabIndex].promote
  259. let total = 0
  260. for(let i=0;i<proList.length;i++){
  261. total += this.getPrice(proList[i].skuItem)
  262. }
  263. switch (composeType){
  264. case 1:
  265. this.composePrice = promote.toFixed(2)
  266. break
  267. case 2:
  268. this.composePrice = (total - promote).toFixed(2)
  269. break
  270. case 3:
  271. this.composePrice = parseFloat(total * promote / 10).toFixed(2)
  272. break
  273. }
  274. console.log(total, this.composePrice, 'total')
  275. },
  276. // 根据活动显示不同价格
  277. getPrice(item){
  278. // 所属活动 0-常规商品 1-拼团活动 2-秒杀活动 3-限时折扣活动 4-平台秒杀 5-平台折扣 6-定价捆绑 7-组合捆绑 8-场景营销 9-会员价
  279. if(item.activityType){
  280. if(item.activityType === 0 || item.activityType === 6 || item.activityType === 7){
  281. return item.price
  282. } else {
  283. return item.originalPrice
  284. }
  285. } else {
  286. return item.price
  287. }
  288. },
  289. // 立即购买
  290. doBuy(){
  291. let addCart = []
  292. let shopObj = {}
  293. shopObj["shopId"] = this.productData.shopId
  294. shopObj["composeId"] = this.selectComposeData[this.tabIndex].composeId
  295. shopObj["skus"] = []
  296. let proList = this.selectComposeData[this.tabIndex].composeProductInfoList
  297. let len2 = proList.length
  298. for (let j = 0; j < len2; j++) {
  299. let skusObj = {}
  300. skusObj["number"] = 1
  301. skusObj["skuId"] = proList[j].skuItem.skuId
  302. shopObj.skus.push(skusObj)
  303. }
  304. addCart.push(shopObj)
  305. uni.setStorageSync('skuItemDTOList', addCart)
  306. uni.navigateTo({
  307. url: '../../pages_category_page1/orderModule/orderConfirm?type=1'
  308. })
  309. },
  310. getselectedAttrVal(item){
  311. return this.selectedAttr[item]
  312. }
  313. }
  314. }
  315. </script>
  316. <style lang="scss" scoped>
  317. .group-list{
  318. padding: 10upx 20upx 60upx;
  319. border-top: 12upx solid #F8F8F8;
  320. .group-warp{
  321. height: 680upx;
  322. background: #333333;
  323. box-shadow: 0 20upx 30upx rgba(0, 0, 0, 0.3);
  324. opacity: 1;
  325. border-radius: 20upx;
  326. }
  327. .title{
  328. display: flex;
  329. align-items:center;
  330. position: relative;
  331. justify-content: space-between;
  332. padding: 32upx 0 20upx 30upx;
  333. .title-img{
  334. width: 203upx;
  335. }
  336. .price-text{
  337. padding: 0 34upx;
  338. margin-right: 10upx;
  339. height: 50upx;
  340. background: linear-gradient(90deg, #C83732 0%, #E25C44 100%);
  341. box-shadow: 0 6upx 12upx rgba(233, 0, 0, 0.3);
  342. border-radius: 26upx;
  343. font-size: 24upx;
  344. color: #fff;
  345. text-align: center;
  346. line-height: 50upx;
  347. margin-left: 20upx;
  348. .swiper{
  349. height: 50upx;
  350. }
  351. }
  352. }
  353. .tabs-nav{
  354. padding: 0 10upx;
  355. margin-bottom: 20upx;
  356. .ul{
  357. display: flex;
  358. .li{
  359. //flex: 1 0 auto;
  360. text-align: center;
  361. font-size: 26rpx;
  362. color: #999;
  363. position: relative;
  364. padding: 12px 40px;
  365. word-break: keep-all;
  366. &:first-child{
  367. margin-left: 0;
  368. }
  369. &.on{
  370. color: #FFEBC4;
  371. &:after{
  372. content: '';
  373. width: 100%;
  374. height: 2rpx;
  375. background: #FFEBC4;
  376. position: absolute;
  377. left: 0;
  378. bottom: 0;
  379. }
  380. }
  381. }
  382. }
  383. }
  384. .tabs-item{
  385. display: none;
  386. &.on{
  387. display: block;
  388. }
  389. }
  390. .pro-box{
  391. height: 318upx;
  392. padding: 0 2upx 20upx;
  393. .pro-item-inner{
  394. padding: 0 8upx;
  395. display: flex;
  396. justify-content: center;
  397. }
  398. .pro-item{
  399. width: 219upx;
  400. background: #FFFFFF;
  401. padding: 10upx;
  402. height: 318upx;
  403. .pro-item-img{
  404. width: 100%;
  405. height: 160upx;
  406. .img{
  407. width: 100%;
  408. height: 100%;
  409. object-fit: contain;
  410. }
  411. }
  412. .pro-item-info{
  413. .name{
  414. font-size: 24upx;
  415. line-height: 34upx;
  416. color: #333333;
  417. overflow: hidden;
  418. text-overflow:ellipsis;
  419. white-space: nowrap;
  420. text-align: center;
  421. font-weight: normal;
  422. margin: 8upx 0 26upx;
  423. }
  424. .sku{
  425. width: 180upx;
  426. height: 50upx;
  427. margin: 0 auto;
  428. line-height: 50upx;
  429. border: 2upx solid #E4E5E6;
  430. background: url("https://ceres.zkthink.com/static/images/arrow-suk-select.png") no-repeat right center / 60upx 60upx;
  431. .text{
  432. font-size: 24upx;
  433. color: #999;
  434. padding-left: 20upx;
  435. width: 126px;
  436. text-overflow:ellipsis;
  437. white-space: nowrap;
  438. }
  439. }
  440. }
  441. }
  442. }
  443. .swiper-dots{
  444. display: flex;
  445. justify-content: center;
  446. .dot{
  447. display: block;
  448. width: 24upx;
  449. height: 4upx;
  450. background: #FFFFFF;
  451. opacity: 0.5;
  452. border-radius: 2upx;
  453. margin: 0 20upx;
  454. &.dot-active{
  455. opacity: 1;
  456. }
  457. }
  458. }
  459. }
  460. .btn-buy{
  461. width: 688upx;
  462. height: 84upx;
  463. //border: 2upx solid rgba(0, 0, 0, 0);
  464. background: linear-gradient(88deg, #C5AA7B 0%, #FFEBC4 100%);
  465. font-size: 28upx;
  466. color: #333;
  467. line-height: 84upx;
  468. margin: 30upx auto 0;
  469. text-align: center;
  470. }
  471. .goosDetailshow-box {
  472. .detailImg-box {
  473. margin-top: 30rpx;
  474. margin-left: 30rpx;
  475. border-radius: 10rpx;
  476. border-bottom: 1rpx solid #EDEDED;
  477. padding-bottom: 20rpx;
  478. width: 690rpx;
  479. .detailImg {
  480. width: 180rpx;
  481. height: 180rpx;
  482. }
  483. }
  484. .color-box {
  485. padding: 30rpx 30rpx;
  486. border-bottom: 1rpx solid #EDEDED;
  487. width: 690rpx;
  488. .skuStyle{
  489. padding: 20rpx 0;
  490. }
  491. .skuStyle:nth-child(2) {
  492. border-top: 1px solid #F3F4F5;
  493. }
  494. .colorName-box {
  495. display: flex;
  496. flex-wrap: wrap;
  497. flex-direction: row;
  498. justify-content: flex-start;
  499. align-items: center;
  500. margin-top: 30rpx;
  501. margin-left: -30rpx;
  502. .colorName-on {
  503. background-color: #FFE5D0;
  504. color: #C5AA7B;
  505. margin-left: 30rpx;
  506. padding: 10rpx 32rpx;
  507. border-radius: 28rpx;
  508. border: 1rpx solid #C5AA7B;
  509. font-size: 26rpx;
  510. text-align: center;
  511. z-index: 1;
  512. }
  513. .colorName {
  514. background-color: #F5F5F5;
  515. margin-left: 30rpx;
  516. padding: 10rpx 32rpx;
  517. border-radius: 28rpx;
  518. font-size: 26rpx;
  519. z-index: 2;
  520. }
  521. }
  522. }
  523. .modelNum-box {
  524. padding: 30rpx 30rpx;
  525. border-bottom: 1rpx solid #EDEDED;
  526. width: 690rpx;
  527. .modelNumName-box {
  528. display: flex;
  529. flex-wrap: wrap;
  530. flex-direction: row;
  531. justify-content: flex-start;
  532. align-items: center;
  533. margin-top: 30rpx;
  534. margin-left: -30rpx;
  535. .modelNumName-on {
  536. background-color: #FFE4D0;
  537. color: #C5AA7B;
  538. margin-left: 30rpx;
  539. padding: 10rpx 32rpx;
  540. border-radius: 28rpx;
  541. border: 1rpx solid #C5AA7B;
  542. font-size: 26rpx;
  543. text-align: center;
  544. }
  545. .modelNumName {
  546. background-color: #F5F5F5;
  547. margin-left: 30rpx;
  548. padding: 10rpx 32rpx;
  549. border-radius: 28rpx;
  550. font-size: 26rpx;
  551. }
  552. }
  553. }
  554. .goodsNum-box {
  555. padding: 30rpx 30rpx;
  556. width: 690rpx;
  557. padding-bottom: 140rpx;
  558. .goodsNumber {
  559. text-align: center;
  560. border: 1rpx solid #999999;
  561. padding: 3rpx 20rpx;
  562. }
  563. .subtract {
  564. border: 1rpx solid #999999;
  565. padding: 3rpx 20rpx;
  566. margin-right: -1rpx;
  567. }
  568. .add {
  569. border: 1rpx solid #999999;
  570. padding: 3rpx 20rpx;
  571. margin-left: -1rpx;
  572. }
  573. }
  574. .goosDetailbut-box {
  575. .joinShopCartBut {
  576. width: 343rpx;
  577. height: 80rpx;
  578. background-color: #FFC300;
  579. color: #FFFEFE;
  580. font-size: 28rpx;
  581. line-height: 80rpx;
  582. text-align: center;
  583. margin-left: 30rpx;
  584. }
  585. .buyNowBut {
  586. width: 343rpx;
  587. height: 80rpx;
  588. border-radius: 0 40rpx 40rpx 0;
  589. background-color: #FF6F00;
  590. color: #FFFEFE;
  591. font-size: 28rpx;
  592. line-height: 80rpx;
  593. text-align: center;
  594. }
  595. }
  596. .submitBtn {
  597. width: 342rpx;
  598. height: 100rpx;
  599. line-height: 100rpx;
  600. font-size: 28rpx;
  601. border: 1px solid;
  602. border-radius: 0;
  603. color: #FFEBC4;
  604. background: #333333;
  605. margin: 20rpx 0;
  606. }
  607. }
  608. </style>