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

628 lines
18 KiB

2 years ago
2 years ago
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">{{$t('common.buynow')}}</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">{{$t('common.stocknum', {number: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. //如果是单款式商品,需要特殊处理productData.names
  171. const mapKeys = Object.keys(this.skuProData.map)
  172. if (mapKeys.length === 1 && mapKeys[0] === '单款项') {
  173. this.skuProData.names[0].values.push({
  174. skuValue: '单款项',
  175. valueCode: '单款项'
  176. })
  177. }
  178. //如果sku的图像为空,设置为商品的图像
  179. for (var key in this.skuProData.map) {
  180. let skuImage = this.skuProData.map[key].image
  181. if (!skuImage) {
  182. this.skuProData.map[key].image = this.skuProData.images[0]
  183. }
  184. }
  185. this.goodsDetailShowFlag = true
  186. this.selectBySkuId(item.skuItem.skuId)
  187. }).catch(res => {
  188. uni.hideLoading()
  189. })
  190. },
  191. selectBySkuId(skuId) {
  192. if (skuId) {
  193. let mapinfo = this.skuProData.map
  194. let flag = true
  195. for (var key in mapinfo) {
  196. if (parseInt(mapinfo[key].skuId) === parseInt(skuId)) {
  197. flag = false
  198. this.selectedSku = mapinfo[key]
  199. // 选中sku对应的规格
  200. const valueCodeList = key.split(',')
  201. this.selectedAttr = []
  202. this.skuProData.names.forEach(attr => {
  203. for (var index in attr.values) {
  204. let valueCode = attr.values[index].valueCode
  205. if (valueCodeList.includes(valueCode)) {
  206. this.nameCodeValueCodeClick(attr.nameCode, valueCode, false)
  207. break
  208. }
  209. }
  210. })
  211. break
  212. }
  213. }
  214. // 匹配不上就赋值第一个
  215. if(flag){
  216. for (var key in mapinfo) {
  217. this.selectedSku = mapinfo[key]
  218. break
  219. }
  220. }
  221. }
  222. },
  223. nameCodeValueCodeClick(nameCode, valueCode, reSelectSku) {
  224. this.selectedAttr[nameCode] = valueCode
  225. if (reSelectSku) {
  226. let attrList = []
  227. for (var key in this.selectedAttr) {
  228. attrList.push(this.selectedAttr[key])
  229. }
  230. const attrkey = attrList.join(',')
  231. let mapinfo = this.skuProData.map
  232. for (var key in mapinfo) {
  233. if (attrkey === key) {
  234. this.selectedSku = mapinfo[key]
  235. }
  236. }
  237. }
  238. this.$forceUpdate(); // 重绘
  239. },
  240. // 提交更换商品规格
  241. submitBtn() {
  242. const curPro = this.selectComposeData[this.tabIndex].composeProductInfoList[this.curProIndex]
  243. for(let i=0;i<curPro.composeSkuInfoList.length;i++){
  244. if(curPro.composeSkuInfoList[i].skuId === this.selectedSku.skuId){
  245. this.selectedSku.skuName = curPro.composeSkuInfoList[i].skuName
  246. }
  247. }
  248. curPro.skuItem = this.selectedSku
  249. this.calculatePrice()
  250. this.goodsDetailShowFlag = false
  251. },
  252. // 计算组合价
  253. calculatePrice(){
  254. const proList = this.selectComposeData[this.tabIndex].composeProductInfoList,composeType= this.selectComposeData[this.tabIndex].composeType,promote= this.selectComposeData[this.tabIndex].promote
  255. let total = 0
  256. for(let i=0;i<proList.length;i++){
  257. total += this.getPrice(proList[i].skuItem)
  258. }
  259. switch (composeType){
  260. case 1:
  261. this.composePrice = promote.toFixed(2)
  262. break
  263. case 2:
  264. this.composePrice = (total - promote).toFixed(2)
  265. break
  266. case 3:
  267. this.composePrice = parseFloat(total * promote / 10).toFixed(2)
  268. break
  269. }
  270. },
  271. // 根据活动显示不同价格
  272. getPrice(item){
  273. // 所属活动 0-常规商品 1-拼团活动 2-秒杀活动 3-限时折扣活动 4-平台秒杀 5-平台折扣 6-定价捆绑 7-组合捆绑 8-场景营销 9-会员价
  274. if(item.activityType){
  275. if(item.activityType === 0 || item.activityType === 6 || item.activityType === 7){
  276. return item.price
  277. } else {
  278. return item.originalPrice
  279. }
  280. } else {
  281. return item.price
  282. }
  283. },
  284. // 立即购买
  285. doBuy(){
  286. let addCart = []
  287. let shopObj = {}
  288. shopObj["shopId"] = this.productData.shopId
  289. shopObj["composeId"] = this.selectComposeData[this.tabIndex].composeId
  290. shopObj["skus"] = []
  291. let proList = this.selectComposeData[this.tabIndex].composeProductInfoList
  292. let len2 = proList.length
  293. for (let j = 0; j < len2; j++) {
  294. let skusObj = {}
  295. skusObj["number"] = 1
  296. skusObj["skuId"] = proList[j].skuItem.skuId
  297. shopObj.skus.push(skusObj)
  298. }
  299. addCart.push(shopObj)
  300. uni.setStorageSync('skuItemDTOList', addCart)
  301. uni.navigateTo({
  302. url: '../../pages_category_page1/orderModule/orderConfirm?type=1'
  303. })
  304. },
  305. getselectedAttrVal(item){
  306. return this.selectedAttr[item]
  307. }
  308. }
  309. }
  310. </script>
  311. <style lang="scss" scoped>
  312. .group-list{
  313. padding: 10upx 20upx 60upx;
  314. border-top: 12upx solid #F8F8F8;
  315. .group-warp{
  316. height: 680upx;
  317. background: #333333;
  318. box-shadow: 0 20upx 30upx rgba(0, 0, 0, 0.3);
  319. opacity: 1;
  320. border-radius: 20upx;
  321. }
  322. .title{
  323. display: flex;
  324. align-items:center;
  325. position: relative;
  326. justify-content: space-between;
  327. padding: 32upx 0 20upx 30upx;
  328. .title-img{
  329. width: 203upx;
  330. }
  331. .price-text{
  332. padding: 0 34upx;
  333. margin-right: 10upx;
  334. height: 50upx;
  335. background: linear-gradient(90deg, #C83732 0%, #E25C44 100%);
  336. box-shadow: 0 6upx 12upx rgba(233, 0, 0, 0.3);
  337. border-radius: 26upx;
  338. font-size: 24upx;
  339. color: #fff;
  340. text-align: center;
  341. line-height: 50upx;
  342. margin-left: 20upx;
  343. .swiper{
  344. height: 50upx;
  345. }
  346. }
  347. }
  348. .tabs-nav{
  349. padding: 0 10upx;
  350. margin-bottom: 20upx;
  351. .ul{
  352. display: flex;
  353. .li{
  354. //flex: 1 0 auto;
  355. text-align: center;
  356. font-size: 26rpx;
  357. color: #999;
  358. position: relative;
  359. padding: 12px 40px;
  360. word-break: keep-all;
  361. &:first-child{
  362. margin-left: 0;
  363. }
  364. &.on{
  365. color: #FFEBC4;
  366. &:after{
  367. content: '';
  368. width: 100%;
  369. height: 2rpx;
  370. background: #FFEBC4;
  371. position: absolute;
  372. left: 0;
  373. bottom: 0;
  374. }
  375. }
  376. }
  377. }
  378. }
  379. .tabs-item{
  380. display: none;
  381. &.on{
  382. display: block;
  383. }
  384. }
  385. .pro-box{
  386. height: 318upx;
  387. padding: 0 2upx 20upx;
  388. .pro-item-inner{
  389. padding: 0 8upx;
  390. display: flex;
  391. justify-content: center;
  392. }
  393. .pro-item{
  394. width: 219upx;
  395. background: #FFFFFF;
  396. padding: 10upx;
  397. height: 318upx;
  398. .pro-item-img{
  399. width: 100%;
  400. height: 160upx;
  401. .img{
  402. width: 100%;
  403. height: 100%;
  404. object-fit: contain;
  405. }
  406. }
  407. .pro-item-info{
  408. .name{
  409. font-size: 24upx;
  410. line-height: 34upx;
  411. color: #333333;
  412. overflow: hidden;
  413. text-overflow:ellipsis;
  414. white-space: nowrap;
  415. text-align: center;
  416. font-weight: normal;
  417. margin: 8upx 0 26upx;
  418. }
  419. .sku{
  420. width: 180upx;
  421. height: 50upx;
  422. margin: 0 auto;
  423. line-height: 50upx;
  424. border: 2upx solid #E4E5E6;
  425. background: url("https://ceres.zkthink.com/static/images/arrow-suk-select.png") no-repeat right center / 60upx 60upx;
  426. .text{
  427. font-size: 24upx;
  428. color: #999;
  429. padding-left: 20upx;
  430. width: 126px;
  431. text-overflow:ellipsis;
  432. white-space: nowrap;
  433. }
  434. }
  435. }
  436. }
  437. }
  438. .swiper-dots{
  439. display: flex;
  440. justify-content: center;
  441. .dot{
  442. display: block;
  443. width: 24upx;
  444. height: 4upx;
  445. background: #FFFFFF;
  446. opacity: 0.5;
  447. border-radius: 2upx;
  448. margin: 0 20upx;
  449. &.dot-active{
  450. opacity: 1;
  451. }
  452. }
  453. }
  454. }
  455. .btn-buy{
  456. width: 688upx;
  457. height: 84upx;
  458. //border: 2upx solid rgba(0, 0, 0, 0);
  459. background: linear-gradient(88deg, #C5AA7B 0%, #FFEBC4 100%);
  460. font-size: 28upx;
  461. color: #333;
  462. line-height: 84upx;
  463. margin: 30upx auto 0;
  464. text-align: center;
  465. }
  466. .goosDetailshow-box {
  467. .detailImg-box {
  468. margin-top: 30rpx;
  469. margin-left: 30rpx;
  470. border-radius: 10rpx;
  471. border-bottom: 1rpx solid #EDEDED;
  472. padding-bottom: 20rpx;
  473. width: 690rpx;
  474. .detailImg {
  475. width: 180rpx;
  476. height: 180rpx;
  477. }
  478. }
  479. .color-box {
  480. padding: 30rpx 30rpx;
  481. border-bottom: 1rpx solid #EDEDED;
  482. width: 690rpx;
  483. .skuStyle{
  484. padding: 20rpx 0;
  485. }
  486. .skuStyle:nth-child(2) {
  487. border-top: 1px solid #F3F4F5;
  488. }
  489. .colorName-box {
  490. display: flex;
  491. flex-wrap: wrap;
  492. flex-direction: row;
  493. justify-content: flex-start;
  494. align-items: center;
  495. margin-top: 30rpx;
  496. margin-left: -30rpx;
  497. .colorName-on {
  498. background-color: #FFE5D0;
  499. color: #C5AA7B;
  500. margin-left: 30rpx;
  501. padding: 10rpx 32rpx;
  502. border-radius: 28rpx;
  503. border: 1rpx solid #C5AA7B;
  504. font-size: 26rpx;
  505. text-align: center;
  506. z-index: 1;
  507. }
  508. .colorName {
  509. background-color: #F5F5F5;
  510. margin-left: 30rpx;
  511. padding: 10rpx 32rpx;
  512. border-radius: 28rpx;
  513. font-size: 26rpx;
  514. z-index: 2;
  515. }
  516. }
  517. }
  518. .modelNum-box {
  519. padding: 30rpx 30rpx;
  520. border-bottom: 1rpx solid #EDEDED;
  521. width: 690rpx;
  522. .modelNumName-box {
  523. display: flex;
  524. flex-wrap: wrap;
  525. flex-direction: row;
  526. justify-content: flex-start;
  527. align-items: center;
  528. margin-top: 30rpx;
  529. margin-left: -30rpx;
  530. .modelNumName-on {
  531. background-color: #FFE4D0;
  532. color: #C5AA7B;
  533. margin-left: 30rpx;
  534. padding: 10rpx 32rpx;
  535. border-radius: 28rpx;
  536. border: 1rpx solid #C5AA7B;
  537. font-size: 26rpx;
  538. text-align: center;
  539. }
  540. .modelNumName {
  541. background-color: #F5F5F5;
  542. margin-left: 30rpx;
  543. padding: 10rpx 32rpx;
  544. border-radius: 28rpx;
  545. font-size: 26rpx;
  546. }
  547. }
  548. }
  549. .goodsNum-box {
  550. padding: 30rpx 30rpx;
  551. width: 690rpx;
  552. padding-bottom: 140rpx;
  553. .goodsNumber {
  554. text-align: center;
  555. border: 1rpx solid #999999;
  556. padding: 3rpx 20rpx;
  557. }
  558. .subtract {
  559. border: 1rpx solid #999999;
  560. padding: 3rpx 20rpx;
  561. margin-right: -1rpx;
  562. }
  563. .add {
  564. border: 1rpx solid #999999;
  565. padding: 3rpx 20rpx;
  566. margin-left: -1rpx;
  567. }
  568. }
  569. .goosDetailbut-box {
  570. .joinShopCartBut {
  571. width: 343rpx;
  572. height: 80rpx;
  573. background-color: #FFC300;
  574. color: #FFFEFE;
  575. font-size: 28rpx;
  576. line-height: 80rpx;
  577. text-align: center;
  578. margin-left: 30rpx;
  579. }
  580. .buyNowBut {
  581. width: 343rpx;
  582. height: 80rpx;
  583. border-radius: 0 40rpx 40rpx 0;
  584. background-color: #FF6F00;
  585. color: #FFFEFE;
  586. font-size: 28rpx;
  587. line-height: 80rpx;
  588. text-align: center;
  589. }
  590. }
  591. .submitBtn {
  592. width: 342rpx;
  593. height: 100rpx;
  594. line-height: 100rpx;
  595. font-size: 28rpx;
  596. border: 1px solid;
  597. border-radius: 0;
  598. color: #FFEBC4;
  599. background: #333333;
  600. margin: 20rpx 0;
  601. }
  602. }
  603. </style>