cart.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. <template>
  2. <view class="container bg-drak" :class="{ 'margin-bottom-big': !empty }">
  3. <!-- <view class="top-bg">
  4. <view class="top-kuang">
  5. <view class="top-title">购物车</view>
  6. </view>
  7. </view> -->
  8. <!-- 00. 未授权登录 -->
  9. <!-- <use-empty v-if="!islogin" e-style="round" e-type="unauthorized" tip="当前未授权" btn-tip="去登录" height="70vh"
  10. :auto="false" @goto="tologin">11</use-empty> -->
  11. <!-- 00. 空白页 -->
  12. <use-empty v-if="empty" :auto="true" e-style="round" e-type="cart" tip="购物车数据为空" height="70vh"></use-empty>
  13. <!-- 00. 列表 -->
  14. <view v-else>
  15. <!-- 01. 购物车列表1 -->
  16. <view class="cart-list padding-sm">
  17. <block v-for="(item, index) in cartDatas" :key="index">
  18. <view class="cart-item bg-main margin-bottom-sm padding-lg pos-r dflex-s border-radius">
  19. <view class="image-wrapper pos-r" @click="togoods(item)">
  20. <!-- 商品图片 -->
  21. <image class="border-radius-xs wh-full" mode="aspectFill" :lazy-load="true" :src="item.goodsMasterImg"></image>
  22. <!-- 选中|未选中按钮 -->
  23. <view
  24. v-if="item.limitNum > 0 && item.limitNum >= item.goodsCount"
  25. class="iconfont checkbox pos-a bg-main border-radius-big"
  26. :class="{ active: item.check, iconxuanzhongzhuangtai: item.check, iconweixuanzhongzhuangtai: !item.check }"
  27. @tap.stop="check('item', index)"
  28. ></view>
  29. <view v-if="item.limitNum < item.goodsCount" class="disabled dflex-c dflex-flow-c pos-a pos-tl-c border-radius-c">
  30. <text>库存不足</text>
  31. <!-- <text class="margin-left-xs fs-xs" v-if="item.limitNum > 0">剩余 {{ item.limitNum }}</text> -->
  32. </view>
  33. </view>
  34. <view class="item-right padding-left pos-r">
  35. <!-- 商品名称 -->
  36. <view class="clamp-2 title" @click="togoods(item)">{{ item.goodsName }}</view>
  37. <view class="ft-dark fs-xs padding-top-xs">{{ item.goodAttr || '&nbsp;&nbsp;' }}</view>
  38. <view class="padding-tb-sm">
  39. <text class="price">{{ item.goodsActualPrice }}</text>
  40. <text class="m-price" v-if="item.marketPrice > 0">{{ item.marketPrice }}</text>
  41. </view>
  42. <!-- + - 购物车数量 -->
  43. <use-number-box
  44. :min="1"
  45. :max="item.limitNum || 1"
  46. :value="item.goodsCount"
  47. :is-max="item.goodsCount >= item.limitNum"
  48. :is-min="item.goodsCount === 1"
  49. :index="index"
  50. :disabled="item.goodsCount >= item.limitNum"
  51. @eventChange="numberChange"
  52. ></use-number-box>
  53. </view>
  54. <!-- 删除 -->
  55. <view class="del-btn iconfont iconlajitong-01 pos-a border-radius-c dflex-c ft-dark fs-xl" @tap.stop="deleteCart(item.key)"></view>
  56. </view>
  57. </block>
  58. </view>
  59. <!-- 02. 底部操作栏 -->
  60. <view class="action-section dflex w-full bg-main pos-f padding-right">
  61. <view class="checkbox pos-r h-full dflex-c">
  62. <view
  63. class="padding-lr iconfont"
  64. :class="{ active: allChecked, iconxuanzhongzhuangtai: allChecked, iconweixuanzhongzhuangtai: !allChecked }"
  65. @click="check('all')"
  66. ></view>
  67. <view class="clear-btn pos-a tac ft-white" :class="{ show: allChecked }" @click="clearCart">清空</view>
  68. </view>
  69. <view class="total-box flex1 tar padding-right-lg">
  70. <text class="price">{{ total || 0 }}</text>
  71. </view>
  72. <button type="primary" class="payment no-border border-radius-lg fs" @click="createOrder()">去结算</button>
  73. </view>
  74. </view>
  75. <!-- 03. 猜你喜欢 -->
  76. <use-hot-goods :datas="goodsHotDatas" title-type="round" title="热门推荐"></use-hot-goods>
  77. <view style="width: 100%; height: 100px"></view>
  78. <!-- <tabbar :current-page="2"></tabbar> -->
  79. </view>
  80. </template>
  81. <script>
  82. import { goodscart, cartcheck, cartcheckpiliang, changecart, deletecart, clearcart } from '../../utils/api_cart.js'
  83. import { goodslistlimit } from '../../utils/api_home.js'
  84. // import tabbar from '../tabbar.vue'
  85. import useHotGoods from '../../components/use-hot-goods/use-hot-goods.vue'
  86. import useNumberBox from '../../components/use-number-box/use-number-box.vue'
  87. import useEmpty from '../../components/use-empty/use-empty.vue'
  88. export default {
  89. components: {
  90. useNumberBox,
  91. useHotGoods,
  92. useEmpty
  93. // tabbar
  94. },
  95. data() {
  96. return {
  97. // 空白页
  98. empty: false, //false
  99. // 购物车数据
  100. cartDatas: [
  101. // {goods:{name:'111'}}
  102. ],
  103. // countType:'',//商品类型数量
  104. // 全选状态
  105. allChecked: false,
  106. // 总价格
  107. total: 0,
  108. // 热门推荐
  109. goodsHotDatas: []
  110. }
  111. },
  112. watch: {
  113. //显示空白页
  114. cartDatas(e) {
  115. console.log(e, 'e')
  116. let empty = e.length === 0
  117. if (this.empty !== empty) {
  118. this.empty = empty
  119. }
  120. }
  121. },
  122. // 监听页面显示。页面每次出现在屏幕上都触发,包括从下级页面点返回露出当前页面
  123. onShow() {
  124. this.loadData()
  125. this.get_good_hot()
  126. var j = 0
  127. for (var i = 0; i < this.cartDatas.length; i++) {
  128. if (this.cartDatas[index].check) {
  129. j++
  130. }
  131. }
  132. if (j == this.cartDatas.length) {
  133. this.allChecked = true
  134. } else {
  135. this.allChecked = false
  136. }
  137. },
  138. // 下拉刷新
  139. onPullDownRefresh() {
  140. this.loadData(() => {
  141. uni.stopPullDownRefresh()
  142. })
  143. },
  144. methods: {
  145. //请求数据
  146. loadData(callback) {
  147. var _self = this
  148. _self.cartDatas = []
  149. var header = {
  150. 'Mall-Token': uni.getStorageSync('tokenId')
  151. }
  152. goodscart(header).then((res) => {
  153. if (res.success) {
  154. if (res.data.items == null) {
  155. } else {
  156. let _cartDatas = []
  157. res.data.items.forEach((data) => {
  158. _self.cartDatas.push(data)
  159. })
  160. //计算总价
  161. _self.calcTotal()
  162. if (typeof callback === 'function') {
  163. // 数据加载完成回调函数
  164. callback()
  165. }
  166. }
  167. }
  168. })
  169. // // 更改为临时表方式查询
  170. // const goodsTemp = db.collection('usemall-goods').getTemp();
  171. // const goodsSkuTemp = db.collection('usemall-goods-sku').getTemp();
  172. // db.collection(_cart, goodsTemp, goodsSkuTemp)
  173. // .where('create_uid == $env.uid')
  174. // .field(
  175. // '_id, goodsCount, goods_sku.spec, goods.price, goods.market_price, limitNum, goods.name,goods.name_pw ,last_modify_time, goods._id as goods_id, goods.img, goods.state'
  176. // )
  177. // .orderBy('last_modify_time desc')
  178. // .get()
  179. // .then(res => {
  180. // if (res && res.result && res.result.errCode === 0) {
  181. // let _cartDatas = [];
  182. // res.result.data.forEach(x => {
  183. // x.goods = x.goods[0];
  184. // x.goods_id = x.goods_id[0];
  185. // x.goods_sku = x.goods_sku[0] || {};
  186. // if (x.goods && x.goods_id) _cartDatas.push(x);
  187. // });
  188. // // 购物车数据
  189. // this.cartDatas = _cartDatas;
  190. // console.log('购',this.cartDatas)
  191. // // 计算总价
  192. // this.calcTotal();
  193. // if (typeof callback === 'function') {
  194. // // 数据加载完成回调函数
  195. // callback();
  196. // }
  197. // }
  198. // })
  199. // return;
  200. },
  201. // 热门推荐
  202. get_good_hot() {
  203. let _self = this
  204. _self.goodsHotDatas = []
  205. var data = '?hot=1&state=1'
  206. goodslistlimit(data).then((res) => {
  207. if (res.success) {
  208. var total = res.data.totalCount
  209. data = '?hot=1&state=1&pageSize=' + total
  210. goodslistlimit(data).then((res) => {
  211. if (res.success) {
  212. res.data.list.forEach((data) => {
  213. _self.goodsHotDatas.push(data)
  214. })
  215. } else {
  216. _self.$message.warning('没有符合条件的数据!')
  217. }
  218. })
  219. }
  220. })
  221. },
  222. // 跳转登录页
  223. tologin() {
  224. this.$api.tologin()
  225. },
  226. // 跳转商品页
  227. togoods(item) {
  228. this.$api.togoods({
  229. id: item.goodsId
  230. })
  231. },
  232. // 选中状态处理
  233. check(type, index) {
  234. var _self = this
  235. if (type === 'item') {
  236. _self.cartDatas[index].check = !_self.cartDatas[index].check
  237. if (_self.cartDatas[index].check) {
  238. var check = 1
  239. } else {
  240. var check = 0
  241. }
  242. var j = 0
  243. for (var i = 0; i < _self.cartDatas.length; i++) {
  244. if (_self.cartDatas[index].check) {
  245. j++
  246. }
  247. }
  248. if (j == _self.cartDatas.length) {
  249. _self.allChecked = true
  250. } else {
  251. _self.allChecked = false
  252. }
  253. //购物车选中或取消
  254. var header = {
  255. 'Mall-Token': uni.getStorageSync('tokenId')
  256. }
  257. console.log(_self.cartDatas[index].key, 'check')
  258. var params = _self.cartDatas[index].key
  259. var data = check
  260. cartcheck(params, data, header).then((res) => {
  261. if (res.success) {
  262. _self.calcTotal()
  263. }
  264. })
  265. } else {
  266. const check = !_self.allChecked
  267. var keys = []
  268. var k2 = ''
  269. _self.cartDatas.forEach((item) => {
  270. item.check = check
  271. _self.allChecked = check
  272. keys.push(item.key)
  273. })
  274. _self.allChecked = check
  275. if (_self.allChecked) {
  276. var check2 = 1
  277. } else {
  278. var check2 = 0
  279. }
  280. k2 = keys.toString()
  281. //购物车批量选中或取消
  282. var params = '?check=' + check2 + '&keys=' + k2
  283. var header = {
  284. 'Mall-Token': uni.getStorageSync('tokenId')
  285. }
  286. cartcheckpiliang(params, header).then((res) => {
  287. if (res.success) {
  288. _self.calcTotal()
  289. }
  290. })
  291. }
  292. _self.calcTotal()
  293. },
  294. // +- 数量
  295. numberChange(data) {
  296. var _self = this
  297. let cart = _self.cartDatas[data.index]
  298. var num = data.number - _self.cartDatas[data.index].goodsCount
  299. //修改购物车接口
  300. var params = '?num=' + num + '&goodId=' + cart.goodsId+'&skuId='+cart.skuId
  301. var header = {
  302. 'Mall-Token': uni.getStorageSync('tokenId')
  303. }
  304. changecart(params, header).then((res) => {
  305. if (res.success) {
  306. _self.loadData()
  307. }
  308. _self.$api.msg(res.msg)
  309. })
  310. // this.$db[_cart].update(cart._id, {
  311. // countType: data.number
  312. // }).then(res => {
  313. // if (res.code === 200) {
  314. // cart.countType = data.number;
  315. // this.calcTotal();
  316. // return;
  317. // }
  318. // this.$api.msg(res.msg);
  319. // });
  320. },
  321. // 删除
  322. deleteCart(id) {
  323. let _self = this
  324. uni.showModal({
  325. title: '提示',
  326. content: '删除购物车',
  327. success: function (res) {
  328. if (res.confirm) {
  329. var params = id
  330. var header = {
  331. 'Mall-Token': uni.getStorageSync('tokenId')
  332. }
  333. deletecart(params, header).then((res) => {
  334. if (res.success) {
  335. _self.loadData()
  336. }
  337. _self.$api.msg(res.msg)
  338. })
  339. // _self.$db[_cart].where('create_uid == $env.uid').remove(id)
  340. // .then(res => {
  341. // if (res.code === 200) {
  342. // _self.loadData();
  343. // }
  344. // })
  345. } else if (res.cancel) {
  346. }
  347. }
  348. })
  349. },
  350. // 清空
  351. clearCart() {
  352. let _self = this
  353. uni.showModal({
  354. title: '提示',
  355. content: '清空购物车',
  356. success: function (res) {
  357. if (res.confirm) {
  358. var header = {
  359. 'Mall-Token': uni.getStorageSync('tokenId')
  360. }
  361. clearcart(header).then((res) => {
  362. if (res.success) {
  363. _self.loadData()
  364. }
  365. _self.$api.msg(res.msg)
  366. })
  367. // _self.$db[_cart].where('create_uid == $env.uid').remove()
  368. // .then(res => {
  369. // if (res.code === 200) {
  370. // _self.cartDatas = [];
  371. // return;
  372. // }
  373. // _self.$api.msg(res.msg)
  374. // })
  375. } else if (res.cancel) {
  376. }
  377. }
  378. })
  379. },
  380. // 计算总价
  381. calcTotal() {
  382. if (this.cartDatas.length === 0) {
  383. this.empty = true
  384. return
  385. }
  386. let total = 0,
  387. check = true
  388. this.cartDatas.forEach((item) => {
  389. if (item.check) {
  390. // 存在库存
  391. if (item.limitNum > 0 && item.limitNum >= item.goodsCount) {
  392. total += item.goodsActualPrice * item.goodsCount
  393. }
  394. } else if (check) {
  395. check = false
  396. }
  397. })
  398. this.allChecked = check
  399. this.total = Number(total.toFixed(2))
  400. },
  401. // 创建订单
  402. createOrder() {
  403. let cart_ids = []
  404. let skuId = []
  405. this.cartDatas.forEach((item) => {
  406. // 选中有库存购物车
  407. if (item.check && item.limitNum > 0 && item.limitNum > item.goodsCount) {
  408. cart_ids.push(item.goodsId)
  409. skuId.push(item.skuId)
  410. }
  411. })
  412. if (cart_ids.length <= 0) {
  413. this.$api.msg('请选择结算商品')
  414. return
  415. }
  416. uni.navigateTo({
  417. url: `/packageShang/pages/order/create?cart_ids=${cart_ids.join(',')}&type=2&skuId=${skuId.join(',')}`
  418. })
  419. }
  420. }
  421. }
  422. </script>
  423. <style lang="scss">
  424. @import url('/packageShang/components/iconfont/iconfont.css');
  425. @import url('/packageShang/common/common.scss');
  426. page {
  427. min-height: 100%;
  428. }
  429. /* 顶部背景 */
  430. .top-bg {
  431. width: 100%;
  432. height: 196rpx;
  433. background: rgba(255, 255, 255, 1);
  434. .top-kuang {
  435. width: 100%;
  436. height: 176rpx;
  437. background: rgba(255, 255, 255, 1);
  438. box-shadow: 0px 2rpx 0px rgba(236, 236, 236, 1);
  439. .top-title {
  440. padding: 106rpx 0 0 0rpx;
  441. text-align: center;
  442. font-size: 36rpx;
  443. font-weight: 500;
  444. line-height: 52rpx;
  445. color: rgba(0, 0, 0, 1);
  446. }
  447. }
  448. }
  449. /* 购物车列表项 */
  450. .cart-item {
  451. &:last-child {
  452. margin-bottom: 0;
  453. }
  454. .image-wrapper {
  455. width: 230rpx;
  456. height: 230rpx;
  457. flex-shrink: 0;
  458. image {
  459. opacity: 1;
  460. }
  461. }
  462. .checkbox {
  463. top: -16rpx;
  464. left: -16rpx;
  465. color: $font-color-disabled;
  466. line-height: 1;
  467. font-size: 46rpx;
  468. padding: 5rpx;
  469. z-index: 8;
  470. }
  471. .disabled {
  472. color: #fff !important;
  473. width: 70%;
  474. height: 70%;
  475. background-color: rgba(51, 51, 51, 0.5);
  476. }
  477. .item-right {
  478. width: 140px;
  479. height: 260rpx;
  480. overflow: hidden;
  481. }
  482. .del-btn {
  483. bottom: 30rpx;
  484. right: 30rpx;
  485. width: 70rpx;
  486. height: 70rpx;
  487. }
  488. }
  489. /* 底部栏 */
  490. .action-section {
  491. z-index: 999;
  492. bottom: 0px;
  493. height: 100rpx;
  494. .checkbox {
  495. .iconfont {
  496. font-size: 46rpx;
  497. color: #2c405a;
  498. }
  499. }
  500. .clear-btn {
  501. left: 100rpx;
  502. background: #2c405a;
  503. border-radius: 0 50rpx 50rpx 0;
  504. padding: 12rpx 0;
  505. transition: all 0.2s;
  506. width: 0;
  507. opacity: 0;
  508. &.show {
  509. width: 120rpx;
  510. opacity: 1;
  511. }
  512. }
  513. .payment {
  514. padding: 0 40rpx;
  515. font-size: $font-base;
  516. background: $uni-color-primary;
  517. }
  518. }
  519. /* #ifdef H5 || MP-360 */
  520. .action-section {
  521. margin-bottom: 50px;
  522. }
  523. /* #endif */
  524. </style>