cart.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  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&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. changecart
  300. //修改购物车接口
  301. var params = '?num=' + num + '&goodId=' + cart.goodsId
  302. var header = {
  303. 'Mall-Token': uni.getStorageSync('tokenId')
  304. }
  305. changecart(params, header).then((res) => {
  306. if (res.success) {
  307. _self.loadData()
  308. }
  309. _self.$api.msg(res.msg)
  310. })
  311. // this.$db[_cart].update(cart._id, {
  312. // countType: data.number
  313. // }).then(res => {
  314. // if (res.code === 200) {
  315. // cart.countType = data.number;
  316. // this.calcTotal();
  317. // return;
  318. // }
  319. // this.$api.msg(res.msg);
  320. // });
  321. },
  322. // 删除
  323. deleteCart(id) {
  324. let _self = this
  325. uni.showModal({
  326. title: '提示',
  327. content: '删除购物车',
  328. success: function (res) {
  329. if (res.confirm) {
  330. var params = id
  331. var header = {
  332. 'Mall-Token': uni.getStorageSync('tokenId')
  333. }
  334. deletecart(params, header).then((res) => {
  335. if (res.success) {
  336. _self.loadData()
  337. }
  338. _self.$api.msg(res.msg)
  339. })
  340. // _self.$db[_cart].where('create_uid == $env.uid').remove(id)
  341. // .then(res => {
  342. // if (res.code === 200) {
  343. // _self.loadData();
  344. // }
  345. // })
  346. } else if (res.cancel) {
  347. }
  348. }
  349. })
  350. },
  351. // 清空
  352. clearCart() {
  353. let _self = this
  354. uni.showModal({
  355. title: '提示',
  356. content: '清空购物车',
  357. success: function (res) {
  358. if (res.confirm) {
  359. var header = {
  360. 'Mall-Token': uni.getStorageSync('tokenId')
  361. }
  362. clearcart(header).then((res) => {
  363. if (res.success) {
  364. _self.loadData()
  365. }
  366. _self.$api.msg(res.msg)
  367. })
  368. // _self.$db[_cart].where('create_uid == $env.uid').remove()
  369. // .then(res => {
  370. // if (res.code === 200) {
  371. // _self.cartDatas = [];
  372. // return;
  373. // }
  374. // _self.$api.msg(res.msg)
  375. // })
  376. } else if (res.cancel) {
  377. }
  378. }
  379. })
  380. },
  381. // 计算总价
  382. calcTotal() {
  383. if (this.cartDatas.length === 0) {
  384. this.empty = true
  385. return
  386. }
  387. let total = 0,
  388. check = true
  389. this.cartDatas.forEach((item) => {
  390. if (item.check) {
  391. // 存在库存
  392. if (item.limitNum > 0 && item.limitNum >= item.goodsCount) {
  393. total += item.goodsActualPrice * item.goodsCount
  394. }
  395. } else if (check) {
  396. check = false
  397. }
  398. })
  399. this.allChecked = check
  400. this.total = Number(total.toFixed(2))
  401. },
  402. // 创建订单
  403. createOrder() {
  404. let cart_ids = []
  405. let skuId = []
  406. this.cartDatas.forEach((item) => {
  407. // 选中有库存购物车
  408. if (item.check && item.limitNum > 0 && item.limitNum > item.goodsCount) {
  409. cart_ids.push(item.goodsId)
  410. skuId.push(item.skuId)
  411. }
  412. })
  413. if (cart_ids.length <= 0) {
  414. this.$api.msg('请选择结算商品')
  415. return
  416. }
  417. uni.navigateTo({
  418. url: `/packageShang/pages/order/create?cart_ids=${cart_ids.join(',')}&type=2&skuId=${skuId.join(',')}`
  419. })
  420. }
  421. }
  422. }
  423. </script>
  424. <style lang="scss">
  425. @import url('/packageShang/components/iconfont/iconfont.css');
  426. @import url('/packageShang/common/common.scss');
  427. page {
  428. min-height: 100%;
  429. }
  430. /* 顶部背景 */
  431. .top-bg {
  432. width: 100%;
  433. height: 196rpx;
  434. background: rgba(255, 255, 255, 1);
  435. .top-kuang {
  436. width: 100%;
  437. height: 176rpx;
  438. background: rgba(255, 255, 255, 1);
  439. box-shadow: 0px 2rpx 0px rgba(236, 236, 236, 1);
  440. .top-title {
  441. padding: 106rpx 0 0 0rpx;
  442. text-align: center;
  443. font-size: 36rpx;
  444. font-weight: 500;
  445. line-height: 52rpx;
  446. color: rgba(0, 0, 0, 1);
  447. }
  448. }
  449. }
  450. /* 购物车列表项 */
  451. .cart-item {
  452. &:last-child {
  453. margin-bottom: 0;
  454. }
  455. .image-wrapper {
  456. width: 230rpx;
  457. height: 230rpx;
  458. flex-shrink: 0;
  459. image {
  460. opacity: 1;
  461. }
  462. }
  463. .checkbox {
  464. top: -16rpx;
  465. left: -16rpx;
  466. color: $font-color-disabled;
  467. line-height: 1;
  468. font-size: 46rpx;
  469. padding: 5rpx;
  470. z-index: 8;
  471. }
  472. .disabled {
  473. color: #fff !important;
  474. width: 70%;
  475. height: 70%;
  476. background-color: rgba(51, 51, 51, 0.5);
  477. }
  478. .item-right {
  479. width: 140px;
  480. height: 260rpx;
  481. overflow: hidden;
  482. }
  483. .del-btn {
  484. bottom: 40rpx;
  485. right: 30rpx;
  486. width: 70rpx;
  487. height: 70rpx;
  488. }
  489. }
  490. /* 底部栏 */
  491. .action-section {
  492. z-index: 999;
  493. bottom: 0px;
  494. height: 100rpx;
  495. .checkbox {
  496. .iconfont {
  497. font-size: 46rpx;
  498. color: #2c405a;
  499. }
  500. }
  501. .clear-btn {
  502. left: 100rpx;
  503. background: #2c405a;
  504. border-radius: 0 50rpx 50rpx 0;
  505. padding: 12rpx 0;
  506. transition: all 0.2s;
  507. width: 0;
  508. opacity: 0;
  509. &.show {
  510. width: 120rpx;
  511. opacity: 1;
  512. }
  513. }
  514. .payment {
  515. padding: 0 40rpx;
  516. font-size: $font-base;
  517. background: $uni-color-primary;
  518. }
  519. }
  520. /* #ifdef H5 || MP-360 */
  521. .action-section {
  522. margin-bottom: 50px;
  523. }
  524. /* #endif */
  525. </style>