cart.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. <template>
  2. <div class="mobile-fix-content mobile-centerfix-content mobile-cart" id="mobileFixContent">
  3. <ul class="store-list">
  4. <li class="store-item" v-for="(item, storeIndex) in cartList">
  5. <div class="store-info">
  6. <label class="mobile-cart-check" :class="{'active': item.$active}">
  7. <input type="checkbox" @change="setActive('store', storeIndex)">
  8. </label>
  9. <span class="store-tag inline-block">{{item.storeType | storeTypeFilter}}</span>
  10. <p class="store-name inline-block text-ellipse">{{item.storeName}}</p>
  11. <a class="link" @click="linkSaler(item)"><i class="iconfont icon-kefu1"></i>联系卖家</a>
  12. </div>
  13. <ul class="goods-list">
  14. <li class="goods-item" v-for="(goods, goodsIndex) in item.goods">
  15. <label class="mobile-cart-check" :class="{'active': goods.$active}">
  16. <input type="checkbox" @change="setActive('goods', storeIndex, goodsIndex)">
  17. </label>
  18. <div class="params inline-block">
  19. <p class="param text-ellipse"><span>品牌:</span>{{goods.goods.brandNameEn || '-'}}</p>
  20. <p class="param text-ellipse"><span>类目:</span>{{goods.kiName || '-'}}</p>
  21. <p class="param text-ellipse"><span>型号:</span>{{goods.code || '-'}}</p>
  22. <p class="param text-ellipse"><span>规格:</span>{{goods.spec || '-'}}</p>
  23. </div>
  24. <div class="fr">
  25. <!--<p class="goods-tag">{{goods.goods.tag || '-'}}</p>-->
  26. <div class="input-line">
  27. <span class="inline-block" @click="setGoods('sub', goods)">-</span>
  28. <input type="number" v-model="goods.goods.purchaseNumber" @input="onPurchaseNumberInput(goods)" @blur="setGoods('set', goods)">
  29. <span class="inline-block" @click="setGoods('add', goods)">+</span>
  30. </div>
  31. <div class="price-line">
  32. <span>{{goods.currencyName | currencyFilter}}</span>{{goods.goods.currentPrice}}
  33. </div>
  34. </div>
  35. </li>
  36. </ul>
  37. </li>
  38. </ul>
  39. <div class="buy-wrap">
  40. <label class="mobile-cart-check" :class="{'active': isAllChecked}">
  41. <input type="checkbox" @change="setActive('all')">
  42. <span>全选</span>
  43. </label>
  44. <div class="fr">
  45. <i class="fare">不含运费</i>
  46. <span class="title">合计:</span><span class="price"><span v-show="allCount > 0">{{allCurrency | currencyFilter}}</span>{{allPrice}}</span>
  47. <button class="buy-btn" @click="submit">结算({{allCount}})</button>
  48. </div>
  49. </div>
  50. <remind-box :title="remindText" :timeoutCount="timeoutCount"></remind-box>
  51. <pull-up :fixId="'mobileFixContent'" :searchMore="fetching" :allPage="allPage" :page="page" @pullUpAction="onPullUpAction"></pull-up>
  52. <link-user :infoObj="currentStoreInfo"
  53. :showLink="showLink"
  54. @closeAction="showLink = false"></link-user>
  55. </div>
  56. </template>
  57. <script>
  58. import {RemindBox, PullUp} from '~components/mobile/common'
  59. import {LinkUser} from '~components/mobile/base'
  60. export default {
  61. layout: 'mobile',
  62. middleware: 'authenticated',
  63. data () {
  64. return {
  65. cartList: [],
  66. remindText: '',
  67. timeoutCount: '',
  68. isAllChecked: false,
  69. page: 1,
  70. count: 10,
  71. allCurrency: 'RMB', // 选定币别
  72. currentStoreInfo: {},
  73. showLink: false
  74. }
  75. },
  76. components: {
  77. RemindBox,
  78. PullUp,
  79. LinkUser
  80. },
  81. fetch ({ store }) {
  82. return Promise.all([
  83. store.dispatch('userCenter/loadCartList', {page: 1, count: 10})
  84. ])
  85. },
  86. watch: {
  87. '$store.state.userCenter.list.cart.data': {
  88. handler: function (val) {
  89. let tmpVal = this.baseUtils.deepCopy(val)
  90. // this.cartList = []
  91. tmpVal.content.forEach(item => {
  92. let current = this.cartList.find(objItem => {
  93. return objItem.storeUuid === item.storeUuid
  94. })
  95. item.$active = false
  96. // 初始化购买数量及状态
  97. let goodsItem = item.goods
  98. let pack = goodsItem.perQty || goodsItem.minPackQty
  99. if (goodsItem.breakUp) {
  100. goodsItem.purchaseNumber = goodsItem.minBuyQty
  101. goodsItem.canSub = false
  102. goodsItem.canAdd = goodsItem.purchaseNumber < goodsItem.reserve
  103. } else {
  104. if (pack >= goodsItem.minBuyQty) {
  105. goodsItem.purchaseNumber = pack
  106. } else {
  107. let max = Math.max(pack, goodsItem.minBuyQty)
  108. goodsItem.purchaseNumber = max + max % pack
  109. }
  110. goodsItem.canSub = false
  111. goodsItem.canAdd = goodsItem.purchaseNumber + goodsItem.minPackQty <= goodsItem.reserve
  112. }
  113. goodsItem.currentPrice = Number((this.baseUtils.getPriceByLevel(goodsItem.prices, goodsItem.purchaseNumber, goodsItem.currencyName) * goodsItem.purchaseNumber).toFixed(6))
  114. if (!current) {
  115. this.cartList.push({
  116. storeName: item.storeName,
  117. storeType: item.storeType,
  118. storeUuid: item.storeUuid,
  119. enterprise: item.storeEnterprise.enterpriseInfo,
  120. goods: [item],
  121. $active: false
  122. })
  123. } else {
  124. current.goods.push(item)
  125. }
  126. })
  127. this.checkAll()
  128. },
  129. immediate: true
  130. }
  131. },
  132. computed: {
  133. cartData () {
  134. return this.$store.state.userCenter.list.cart.data
  135. },
  136. fetching () {
  137. return this.$store.state.userCenter.list.cart.fetching
  138. },
  139. allPage () {
  140. return this.cartData.totalPages
  141. },
  142. // 已选goods
  143. allActiveObj () {
  144. let arr = []
  145. this.cartList.forEach(item => {
  146. item.goods.forEach(goodsItem => {
  147. if (goodsItem.$active) {
  148. arr.push(goodsItem)
  149. }
  150. })
  151. })
  152. return arr
  153. },
  154. // 统计价格
  155. allPrice () {
  156. let price = 0
  157. this.allActiveObj.forEach(item => {
  158. price += Number(item.goods.currentPrice)
  159. })
  160. return price
  161. },
  162. // 统计数量
  163. allCount () {
  164. return this.allActiveObj.length
  165. }
  166. },
  167. methods: {
  168. setRemindText: function (str) {
  169. this.remindText = str
  170. this.timeoutCount++
  171. },
  172. checkCurrency: function (currency, callback) {
  173. if (currency === this.allCurrency) {
  174. callback.call()
  175. } else {
  176. this.setRemindText('所选产品币别与已选产品不是同一币别')
  177. }
  178. },
  179. setActive (type, storeIndex, goodsIndex, goodsCheckFlag) {
  180. if (type === 'store') {
  181. let storeActive = this.cartList[storeIndex].$active
  182. for (let i = 0; i < this.cartList[storeIndex].goods.length; i++) {
  183. this.setActive('goods', storeIndex, i, !storeActive)
  184. }
  185. // this.cartList[storeIndex].goods.forEach(item => {
  186. // this.checkCurrency(item.goods.currencyName, () => {
  187. // item.$active = !this.cartList[storeIndex].$active
  188. // })
  189. // })
  190. this.checkAll()
  191. } else if (type === 'goods') {
  192. if (!this.allActiveObj[0]) {
  193. this.allCurrency = this.cartList[storeIndex].goods[goodsIndex].currencyName
  194. }
  195. this.checkCurrency(this.cartList[storeIndex].goods[goodsIndex].currencyName, () => {
  196. this.cartList[storeIndex].goods[goodsIndex].$active = typeof goodsCheckFlag === 'undefined' ? !this.cartList[storeIndex].goods[goodsIndex].$active : goodsCheckFlag
  197. // this.cartList[storeIndex].$active = !this.cartList[storeIndex].goods.find(item => {
  198. // return !item.$active
  199. // })
  200. this.checkAll()
  201. })
  202. } else if (type === 'all') {
  203. let activeFlag = true
  204. this.cartList.forEach(item => {
  205. item.goods.forEach(goodsItem => {
  206. if (!goodsItem.$active) {
  207. activeFlag = false
  208. }
  209. })
  210. })
  211. for (let i = 0; i < this.cartList.length; i++) {
  212. this.cartList[i].$active = activeFlag
  213. this.setActive('store', i)
  214. }
  215. this.checkAll()
  216. }
  217. },
  218. // 总勾选校验
  219. checkAll: function () {
  220. let activeFlag = true
  221. this.cartList.forEach(item => {
  222. let itemActive = true
  223. item.goods.forEach(goodsItem => {
  224. if (!goodsItem.$active) {
  225. activeFlag = false
  226. itemActive = false
  227. }
  228. })
  229. item.$active = itemActive
  230. })
  231. this.isAllChecked = activeFlag
  232. },
  233. onPurchaseNumberInput: function (goods) {
  234. let showPrice = this.baseUtils.getPriceByLevel(goods.goods.prices, goods.goods.purchaseNumber, goods.goods.currencyName)
  235. goods.goods.currentPrice = Number(((showPrice || goods.goods.currentPrice) * goods.goods.purchaseNumber).toFixed(6))
  236. },
  237. checkPurchaseNumber: function (goods) {
  238. if ((/^[\d]*$/).test(goods.goods.purchaseNumber)) {
  239. this.changeNum(goods.goods.purchaseNumber, goods)
  240. } else {
  241. this.setRemindText('请输入整数')
  242. goods.goods.purchaseNumber = goods.goods.minBuyQty
  243. }
  244. },
  245. setGoods: function (type, goods) {
  246. if (type === 'set') {
  247. this.checkPurchaseNumber(goods)
  248. } else {
  249. let isAdd = type === 'add'
  250. let pack = goods.goods.perQty || goods.goods.minPackQty
  251. let newNum = 0
  252. if (goods.goods.breakUp) {
  253. newNum = isAdd ? goods.goods.purchaseNumber + 1 : goods.goods.purchaseNumber - 1
  254. } else {
  255. newNum = isAdd ? goods.goods.purchaseNumber + pack : goods.goods.purchaseNumber - pack
  256. }
  257. this.changeNum(newNum, goods)
  258. this.onPurchaseNumberInput(goods)
  259. }
  260. },
  261. changeNum: function (newNum, goods) {
  262. let pack = goods.goods.perQty || goods.goods.minPackQty
  263. let buy = goods.goods.minBuyQty
  264. let reserve = goods.goods.reserve
  265. let breakUp = goods.goods.breakUp
  266. if (!newNum && newNum !== 0) {
  267. goods.goods.purchaseNumber = buy
  268. } else {
  269. newNum = parseInt(newNum)
  270. if (breakUp) {
  271. if (newNum < buy) {
  272. this.setRemindText('最小起订量为' + buy)
  273. goods.goods.purchaseNumber = buy
  274. goods.goods.canSub = false
  275. goods.goods.canAdd = true
  276. } else if (newNum > reserve) {
  277. this.setRemindText('库存不足')
  278. goods.goods.purchaseNumber = reserve
  279. goods.goods.canAdd = false
  280. goods.goods.canSub = true
  281. } else {
  282. goods.goods.canSub = true
  283. goods.goods.canAdd = true
  284. goods.goods.purchaseNumber = newNum
  285. newNum === buy && (goods.goods.canSub = false)
  286. newNum === reserve && (goods.goods.canAdd = false)
  287. }
  288. } else {
  289. if (newNum < buy) {
  290. this.setRemindText('最小起订量为' + buy)
  291. goods.goods.purchaseNumber = buy
  292. goods.goods.canSub = false
  293. if (newNum > reserve) {
  294. this.setRemindText('库存不足')
  295. goods.goods.purchaseNumber = reserve - (reserve % pack)
  296. goods.goods.canAdd = false
  297. }
  298. } else if (newNum > reserve) {
  299. goods.goods.canSub = true
  300. goods.goods.canAdd = false
  301. this.setRemindText('库存不足')
  302. goods.goods.purchaseNumber = reserve - (reserve % pack)
  303. } else {
  304. goods.goods.canSub = true
  305. goods.goods.canAdd = true
  306. let remainder = newNum % pack
  307. if (remainder !== 0) {
  308. // console.log(this.fragment.num)
  309. this.setRemindText('不支持拆包且包装量为' + pack)
  310. // 这个直接赋值的,应该给这个值进行判断(Math.floor(newNum / pack) + 1) * pack
  311. let res = (Math.floor(newNum / pack) + 1) * pack
  312. goods.goods.purchaseNumber = res > reserve ? Math.floor(newNum / pack) * pack : res
  313. } else {
  314. goods.goods.purchaseNumber = newNum
  315. }
  316. newNum === buy && (goods.goods.canSub = false)
  317. newNum === reserve && (goods.goods.canAdd = false)
  318. }
  319. }
  320. }
  321. },
  322. onPullUpAction: function () {
  323. this.page++
  324. this.reloadList()
  325. },
  326. reloadList: function () {
  327. this.$store.dispatch('userCenter/loadCartList', {page: this.page, count: this.count})
  328. },
  329. submit: function () {
  330. if (!this.allCount) {
  331. this.setRemindText('请勾选要生成订单的批次')
  332. return
  333. }
  334. let arrOD = []
  335. this.allActiveObj.forEach(item => {
  336. arrOD.push({
  337. batchCode: item.goods.batchCode,
  338. minPackQty: item.goods.minPackQty,
  339. number: item.goods.purchaseNumber,
  340. storeid: item.storeUuid
  341. })
  342. })
  343. console.log(arrOD)
  344. this.$http.post('/trade/order/saveByGroup', {
  345. arrOD: arrOD,
  346. currency: this.allCurrency
  347. }).then(res => {
  348. console.log(res.data)
  349. if (res.data.code === 1) {
  350. if (res.data.message) {
  351. this.setRemindText(res.data.message)
  352. }
  353. this.$router.push(`/mobile/center/user/pay/${this.baseUtils.enidfilter(res.data.data.orderid)}`)
  354. } else if (res.data.code === 7) {
  355. this.setRemindText('选中的购物车信息已经失效,将为您刷新界面之后重新操作')
  356. setTimeout(() => {
  357. this.page = 1
  358. this.reloadList()
  359. }, 1500)
  360. } else {
  361. this.setRemindText(res.data.message)
  362. }
  363. }, err => {
  364. console.log(err.response.data.data || '系统错误')
  365. this.setRemindText(err.response.data.data || '系统错误')
  366. })
  367. },
  368. linkSaler (item) {
  369. this.currentStoreInfo = item.enterprise
  370. this.showLink = true
  371. }
  372. }
  373. }
  374. </script>
  375. <style lang="scss" scoped>
  376. .mobile-cart {
  377. bottom: 2rem;
  378. .store-list {
  379. .store-item {
  380. padding: 0 .25rem;
  381. background: #fff;
  382. margin: .19rem 0;
  383. .store-info {
  384. height: .9rem;
  385. line-height: .9rem;
  386. .store-tag {
  387. width: .54rem;
  388. height: .3rem;
  389. line-height: .3rem;
  390. text-align: center;
  391. font-size: .24rem;
  392. color: #fff;
  393. background: #15b262;
  394. border-radius: .04rem;
  395. margin-left: .18rem;
  396. }
  397. .store-name {
  398. font-size: .28rem;
  399. margin-left: .08rem;
  400. max-width: 5.7rem;
  401. }
  402. .link {
  403. float: right;
  404. font-size: .26rem;
  405. color: #3f84f6;
  406. margin-right: .12rem;
  407. i {
  408. margin-right: .08rem;
  409. position: relative;
  410. top: .04rem;
  411. font-size: .34rem;
  412. }
  413. }
  414. }
  415. .goods-list {
  416. .goods-item {
  417. padding: .32rem 0;
  418. border-top: 1px solid #e4e4e4;
  419. .params {
  420. margin-left: .17rem;
  421. .param {
  422. width: 3.65rem;
  423. span {
  424. color: #666;
  425. }
  426. }
  427. }
  428. .fr {
  429. width: 2.6rem;
  430. text-align: center;
  431. .input-line {
  432. $group-height: .35rem;
  433. margin-top: .52rem;
  434. input {
  435. width: 1.31rem;
  436. height: .35rem;
  437. border-top: 1px solid #ddd;
  438. border-bottom: 1px solid #ddd;
  439. vertical-align: middle;
  440. border-radius: 0;
  441. padding: 0 .05rem;
  442. text-align: center;
  443. position: relative;
  444. top: .01rem;
  445. }
  446. span {
  447. width: .5rem;
  448. height: $group-height;
  449. line-height: $group-height;
  450. text-align: center;
  451. border: 1px solid #ddd;
  452. }
  453. }
  454. .price-line {
  455. font-size: .32rem;
  456. color: #f43938;
  457. margin-top: .2rem;
  458. span {
  459. font-size: .24rem;
  460. }
  461. }
  462. }
  463. }
  464. }
  465. }
  466. }
  467. .buy-wrap {
  468. position: fixed;
  469. bottom: .98rem;
  470. height: 1.02rem;
  471. line-height: 1.02rem;
  472. padding-left: .27rem;
  473. background: #fff;
  474. width: 100%;
  475. border-top: .02rem solid #ccc;
  476. .fr {
  477. .fare {
  478. font-size: .18rem;
  479. color: #999;
  480. margin-right: .15rem;
  481. font-style: normal;
  482. }
  483. .title {
  484. font-size: .28rem;
  485. margin-right: .38rem;
  486. }
  487. .price {
  488. font-size: .28rem;
  489. color: #fc2706;
  490. display: inline-block;
  491. max-width: 1.6rem;
  492. overflow: hidden;
  493. text-overflow: ellipsis;
  494. white-space: nowrap;
  495. vertical-align: middle;
  496. span {
  497. font-size: .24rem;
  498. margin-right: .08rem;
  499. }
  500. margin-right: .25rem;
  501. }
  502. .buy-btn {
  503. width: 2.08rem;
  504. height: 1.02rem;
  505. line-height: 1.02rem;
  506. text-align: center;
  507. font-size: .28rem;
  508. color: #fff;
  509. background: #fc2706;
  510. }
  511. }
  512. }
  513. }
  514. .mobile-cart-check {
  515. min-width: .36rem;
  516. height: .36rem;
  517. background: url('/images/mobile/center/user/car-noChecked.png') no-repeat;
  518. background-size: contain;
  519. &.active {
  520. background-image: url('/images/mobile/center/user/car-checked.png');
  521. }
  522. vertical-align: middle;
  523. margin-bottom: .02rem;
  524. input {
  525. display: none;
  526. }
  527. span {
  528. font-size: .26rem;
  529. margin-left: .15rem;
  530. position: absolute;
  531. left: .6rem;
  532. top: .02rem;
  533. font-weight: normal;
  534. }
  535. }
  536. </style>