specPopup.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. <template>
  2. <u-popup ref="popup" :show="show" mode="bottom" @close="close" background-color="#fff" @change="change">
  3. <view class="specPop">
  4. <view class="s-box padding-sm" v-if="current">
  5. <view class="s-img dflex-c">
  6. <image v-if="current.img" :src="current.img.url" mode="aspectFit"></image>
  7. <u-icon v-else name="photo" size="36"></u-icon>
  8. </view>
  9. <view class="g-info">
  10. <view class="s-name">{{current.skuName}}</view>
  11. <view class="s-price">¥{{current.retailPrice}}</view>
  12. </view>
  13. </view>
  14. <view class="s-box padding-sm" v-else>
  15. <view class="s-img dflex-c">
  16. <image v-if="supValue.majorImg" :src="supValue.majorImg" mode="aspectFit"></image>
  17. <u-icon v-else name="photo" size="36"></u-icon>
  18. </view>
  19. <view class="g-info">
  20. <view class="s-name">{{supValue.spuName}}</view>
  21. <view class="s-price" v-if="supValue.minPrice == supValue.maxPrice">¥{{supValue.maxPrice}}</view>
  22. <view class="s-price" v-else>¥{{supValue.minPrice}} ~ ¥{{supValue.maxPrice}}</view>
  23. </view>
  24. </view>
  25. <uni-section :title="item.name" v-for="item in temp" :key="item.field">
  26. <view class="spec-box padding-lr-sm">
  27. <view class="spec-item padding-lr-sm" :class="{'on-spec':item.value == specItem}" @click="actSpec(item,specItem)" v-for="(specItem,index) of item.data" :key="index">{{specItem}}</view>
  28. </view>
  29. </uni-section>
  30. <uni-section title="购买数量">
  31. <view class="purchase-num padding-lr-sm">
  32. <view class="num">
  33. <!-- 剩余562件 -->
  34. </view>
  35. <uni-number-box v-model="vModelValue" :min="1" @change="changeValue" />
  36. </view>
  37. </uni-section>
  38. <view class="btn-box">
  39. <view class="btn reset" @click="close">取消</view>
  40. <view class="btn confirm" v-if="type==1" @click="payBtn">立即购买</view>
  41. <view class="btn confirm" v-else @click="clickAddcart">{{cartData.skuId ? '确定' : '加入购物车'}}</view>
  42. </view>
  43. <u-loading-page :loading="load"></u-loading-page>
  44. <u-toast ref="uToast"></u-toast>
  45. </view>
  46. </u-popup>
  47. </template>
  48. <script>
  49. export default {
  50. name:"specPopup",
  51. props:{
  52. noClear:{}
  53. },
  54. data(){
  55. return{
  56. dinCarData:{},
  57. show:false,
  58. load:false,
  59. supValue:{}, //spu数据
  60. temp:[], //规格列表
  61. checkObj:{}, //选中的规格
  62. skuData:[], //sku数据
  63. current:null, //当前sku数据
  64. vModelValue:1,
  65. cartList:[], //购物车列表
  66. cartData:null, //当前购物车数据
  67. dinCarData:{},
  68. type:0
  69. }
  70. },
  71. created() {
  72. let carData = uni.getStorageSync('dinCarData');
  73. if(carData){
  74. try{
  75. this.dinCarData = JSON.parse(carData)
  76. }catch(e){}
  77. }
  78. let cartInfo = uni.getStorageSync('cartInfo');
  79. if(cartInfo){
  80. try{
  81. this.cartList = JSON.parse(cartInfo)
  82. }catch(e){}
  83. }
  84. },
  85. methods:{
  86. payBtn(){
  87. if(!this.isCheckFind()){
  88. this.$refs.uToast.show({
  89. type:'warning',
  90. message: '请选择规格!'
  91. })
  92. return
  93. }
  94. if(!this.current){
  95. this.$refs.uToast.show({
  96. type:'warning',
  97. message: '该商品没有库存!'
  98. })
  99. return
  100. }
  101. let data = this.getSkuDataObj()
  102. uni.setStorageSync('selectPay', JSON.stringify([data]))
  103. uni.navigateTo({
  104. url: '/pages/order/submitOrder/submitOrder'
  105. });
  106. },
  107. setType(n){
  108. this.type = n
  109. },
  110. changeValue(){},
  111. change(){},
  112. getSkuDataObj() {
  113. let data = {
  114. skuId:this.current.skuId,
  115. basePrice:this.current.tagPrice,
  116. price:this.current.retailPrice,
  117. quantity:this.vModelValue,
  118. imgUrl:this.current.img?this.current.img.url:'',
  119. skuTitle:this.current.title,
  120. spuId:this.current.spuId,
  121. skuCode:this.current.skuCode,
  122. splitMergeId:this.current.splitMergeId,
  123. title:this.current.title,
  124. skuName:this.current.skuName,
  125. productWeight: this.current.grossWeight,
  126. }
  127. if(this.current.freightTemplateId){
  128. data.freightTemplateId = this.current.freightTemplateId
  129. }
  130. if(this.current.color){
  131. data.skuProperties = this.current.color
  132. }
  133. if(this.current.size){
  134. data.skuProperties = data.skuProperties ? data.skuProperties + ';' + this.current.size : this.current.size
  135. }
  136. if(this.current.extendProps){
  137. for(const key in this.current.extendProps){
  138. data.skuProperties = data.skuProperties ? data.skuProperties + ';' + this.current.extendProps[key] : this.current.extendProps[key]
  139. }
  140. }
  141. return data;
  142. },
  143. //加入购物车
  144. clickAddcart(){
  145. if(!this.isCheckFind()){
  146. this.$refs.uToast.show({
  147. type:'warning',
  148. message: '请选择规格!'
  149. })
  150. return
  151. }
  152. if(!this.current){
  153. this.$refs.uToast.show({
  154. type:'warning',
  155. message: '该商品没有库存!'
  156. })
  157. return
  158. }
  159. if(!this.vModelValue || this.vModelValue == 0){
  160. this.$refs.uToast.show({
  161. type:'warning',
  162. message: '请输入购买数量!'
  163. })
  164. return
  165. }
  166. // let that = this;
  167. //加个采购商验证功能
  168. // if(!this.dinCarData || !this.dinCarData.id){
  169. // this.$refs.uToast.show({
  170. // type:'warning',
  171. // message: '您不是采购商,请前往服务平台注册!'
  172. // })
  173. // return
  174. // }
  175. let ind = -1;
  176. let cartDataInd = -1;
  177. this.cartList.forEach((item,index) => {
  178. if(item.skuId == this.current.skuId){
  179. ind = index
  180. }
  181. if(this.cartData && item.skuId == this.cartData.skuId){
  182. cartDataInd = index
  183. }
  184. })
  185. if(ind >= 0) {
  186. if(ind == cartDataInd){
  187. this.cartList[ind].quantity = this.vModelValue
  188. }else{
  189. this.cartList[ind].quantity = this.cartList[ind].quantity + this.vModelValue
  190. if(cartDataInd >= 0 ){
  191. this.cartList.splice(cartDataInd, 1)
  192. }
  193. }
  194. }else{
  195. // let skuProperties = '';
  196. // for(const key in this.checkObj){
  197. // if(!skuProperties){
  198. // skuProperties = this.checkObj[key]
  199. // }else{
  200. // skuProperties = skuProperties + ';' + this.checkObj[key]
  201. // }
  202. // }
  203. let data = this.getSkuDataObj()
  204. if(cartDataInd >= 0 ){
  205. this.cartList.splice(cartDataInd, 1)
  206. }
  207. this.cartList.push(data)
  208. }
  209. const stringData = JSON.stringify(this.cartList)
  210. uni.setStorageSync('cartInfo',stringData);
  211. this.$refs.uToast.show({
  212. type:'success',
  213. message: '操作成功!'
  214. })
  215. this.$emit('onSuccess')
  216. setTimeout(() => {
  217. this.close()
  218. },500)
  219. },
  220. //选中规格
  221. actSpec(item,v){
  222. item.value = v;
  223. this.checkObj[item.field] = v;
  224. if(this.isCheckFind()){
  225. for(const item of this.skuData){
  226. let n = true
  227. for(const key in this.checkObj){
  228. if(key == 'color' || key == 'size'){
  229. if(this.checkObj[key] !== item[key]){
  230. n = false;
  231. break
  232. }
  233. }else{
  234. if(!item.extendProps || this.checkObj[key] !== item.extendProps[key]){
  235. n = false;
  236. break
  237. }
  238. }
  239. }
  240. if(n){
  241. this.current = item
  242. }
  243. }
  244. if(this.current){
  245. this.$emit('onCheckSpec',{
  246. spec:this.checkObj,
  247. sku:this.current
  248. })
  249. }
  250. }else{
  251. this.current = null;
  252. }
  253. },
  254. //判断规格是否已选完
  255. isCheckFind(){
  256. let n = true
  257. for(const item of this.temp){
  258. if(!this.checkObj[item.field]){
  259. n = false
  260. break
  261. }
  262. }
  263. return n;
  264. },
  265. //根据spuId获取sku列表
  266. loadSkuList(bo){
  267. this.load = true;
  268. const that = this;
  269. this.$req({
  270. url:'/item/sku/queryItem',
  271. data:{spuId:this.supValue.spuId},
  272. success: res => {
  273. that.skuData = res.rows
  274. for(const item of that.skuData){
  275. if(item.extendProps){
  276. try{
  277. item.extendProps = JSON.parse(item.extendProps)
  278. }catch(e){}
  279. }
  280. }
  281. //是否是多规格
  282. if(!bo){
  283. if(that.skuData[0].color){
  284. that.temp.push({
  285. name:'颜色',
  286. field:'color',
  287. data:[that.skuData[0].color],
  288. value:''
  289. })
  290. }
  291. if(that.skuData[0].size){
  292. that.temp.push({
  293. name:'规格',
  294. field:'size',
  295. data:[that.skuData[0].size],
  296. value:''
  297. })
  298. }
  299. }
  300. //设置默认规格
  301. if(!that.current){
  302. for(const item of that.temp){
  303. that.actSpec(item, item.data[0])
  304. }
  305. }
  306. },
  307. fail: err => {
  308. let msg = ''
  309. if(err && err.msg && err.msg.length < 15){
  310. msg = err.msg
  311. }else{
  312. msg = '系统繁忙'
  313. }
  314. that.$refs.uToast.show({
  315. message: msg
  316. })
  317. },
  318. complete: () => {
  319. that.load = false
  320. }
  321. })
  322. },
  323. //重置数据
  324. setData(v,cartData){
  325. this.cartData = cartData ? cartData : null
  326. if(!this.noClear || !this.supValue.spuId){
  327. this.checkObj = {}
  328. this.current = null
  329. this.vModelValue = cartData?cartData.quantity:1
  330. this.loadSpu(v)
  331. }
  332. },
  333. loadSku(data){
  334. let that = this;
  335. this.$req({
  336. url:'/item/sku/queryItem/' + data.skuId,
  337. success: res => {
  338. that.current = res.data
  339. let d = null
  340. if(that.current.extendProps){
  341. try{
  342. d = JSON.parse(that.current.extendProps)
  343. }catch(e){}
  344. }
  345. for(const item of that.temp){
  346. if(that.current[item.field]){
  347. item.value = that.current[item.field]
  348. that.checkObj[item.field] = that.current[item.field]
  349. }
  350. if(d && d[item.field]){
  351. item.value = d[item.field]
  352. that.checkObj[item.field] = d[item.field]
  353. }
  354. }
  355. },
  356. fail: err => {
  357. let msg = ''
  358. if(err && err.msg && err.msg.length < 15){
  359. msg = err.msg
  360. }else{
  361. msg = '系统繁忙'
  362. }
  363. that.$refs.uToast.show({
  364. message: msg
  365. })
  366. },
  367. complete: () => {
  368. // that.load = false
  369. }
  370. })
  371. },
  372. loadSpu(v){
  373. let that = this;
  374. this.load = true
  375. this.$req({
  376. url:'/item/spu/queryProduct/' + v,
  377. success: res => {
  378. let _data = res.data;
  379. that.supValue = _data;
  380. if(that.supValue.imgList){
  381. for(const imgItem of that.supValue.imgList){
  382. if(imgItem.major == '2'){
  383. this.supValue.majorImg = imgItem.url
  384. }
  385. }
  386. }
  387. let valueFun = data => {
  388. let n = ''
  389. if(cartData){
  390. let arr = cartData.skuProperties
  391. }
  392. return n;
  393. }
  394. let extendPropsData = {}
  395. if(_data.extendProps){
  396. that.temp = []
  397. try{
  398. extendPropsData = JSON.parse(_data.extendProps);
  399. for(const key in extendPropsData.template.propValues){
  400. let name = ''
  401. if(key == 'color'){
  402. name = '颜色'
  403. }else if(key == 'size'){
  404. name = '规格'
  405. }else{
  406. name = key
  407. }
  408. that.temp.push({
  409. name:name,
  410. field:key,
  411. data:extendPropsData.template.propValues[key],
  412. value:''
  413. })
  414. }
  415. }catch(e){}
  416. }
  417. that.loadSkuList(extendPropsData.multiple)
  418. if(that.cartData){
  419. that.loadSku(that.cartData)
  420. }
  421. },
  422. fail: err => {
  423. let msg = ''
  424. if(err && err.msg && err.msg.length < 15){
  425. msg = err.msg
  426. }else{
  427. msg = '系统繁忙'
  428. }
  429. that.$refs.uToast.show({
  430. message: msg
  431. })
  432. },
  433. complete: () => {
  434. that.load = false
  435. }
  436. })
  437. },
  438. close(){
  439. this.show = false;
  440. },
  441. open(){
  442. this.show = true;
  443. }
  444. }
  445. }
  446. </script>
  447. <style lang="scss" scoped>
  448. .specPop{
  449. height: 900upx;
  450. overflow-y: auto;
  451. position: relative;
  452. padding-bottom: 150upx;
  453. }
  454. .btn-box{
  455. width: 100%;
  456. display: flex;
  457. justify-content: space-around;
  458. align-items: center;
  459. padding-top: 50upx;
  460. padding-bottom: 30upx;
  461. position: fixed;
  462. left: 0;
  463. bottom: 0;
  464. background-color: #FFF;
  465. z-index: 10;
  466. .btn{
  467. width: 45%;
  468. height: 70upx;
  469. text-align: center;
  470. line-height: 70upx;
  471. border-radius: 35upx;
  472. }
  473. .reset{
  474. border:solid 1px #EEE;
  475. box-sizing: border-box;
  476. }
  477. .confirm{
  478. background-image: $base-bg-gradient-color;
  479. color: #FFF;
  480. }
  481. }
  482. .spec-box{
  483. width: 100%;
  484. display: flex;
  485. flex-wrap: wrap;
  486. .spec-item{
  487. height: 60upx;
  488. line-height: 60upx;
  489. border:solid 1px #EEE;
  490. box-sizing: border-box;
  491. text-align: center;
  492. margin-left: 20upx;
  493. border-radius: 3px;
  494. margin-bottom: 20upx;
  495. font-size: 12px;
  496. }
  497. .spec-item:first-child{
  498. margin-left: 0;
  499. }
  500. .on-spec{
  501. background-image: $base-bg-gradient-color;
  502. color: #FFF;
  503. }
  504. }
  505. .s-box{
  506. width: 100%;
  507. display: flex;
  508. border-bottom: solid 1px #EEE;
  509. .s-img{
  510. width: 140upx;
  511. height: 140upx;
  512. background-color: #EEE;
  513. border-radius: 4px;
  514. >image{
  515. width: 100%;
  516. height: 100%;
  517. }
  518. }
  519. .g-info{
  520. padding-left: 20upx;
  521. .s-name{
  522. padding-bottom: 4px;
  523. }
  524. .s-price{
  525. color: #F00;
  526. font-size: 14px;
  527. }
  528. }
  529. }
  530. .purchase-num{
  531. width: 100%;
  532. display: flex;
  533. justify-content: space-between;
  534. align-items: center;
  535. border-bottom: solid 1px #EEE;
  536. padding-bottom: 30upx;
  537. .num{
  538. font-size: 12px;
  539. }
  540. }
  541. </style>