index.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. <template>
  2. <view class="main">
  3. <view class="one" v-if="list.length==0&&user._id">
  4. <view class="logo"><text class="iconfont icon-gouwuche"></text></view>
  5. <view class="one_1">购物车空空如也~</view>
  6. <view class="btn">
  7. <button type="primary" size="mini" @click="toCommon('/pages/home/index')">去逛逛</button>
  8. </view>
  9. </view>
  10. <view class="two" v-else>
  11. <view class="text_1">
  12. <checkbox class="checkbox" @click="selectAll(false)" :checked="isAll">全选</checkbox>
  13. </view>
  14. <view class="text_2" v-if="num==0" @click="edit(1)">编辑</view>
  15. <view class="text_2" v-if="num==1" @click="edit(0)">完成</view>
  16. </view>
  17. <view class="thr" v-if="list.length!=0&&user._id">
  18. <scroll-view scroll-y="true" class="scroll-view">
  19. <view class="list-scroll-view">
  20. <checkbox-group name="checkbox" @change="marketChange">
  21. <view class="list" v-for="(item, index) in list" :key="index">
  22. <view class="list_1">
  23. <view class="title">
  24. <checkbox :value="item.supplier._id" :checked="item.check">
  25. <text class="iconfont icon-shangdian"></text>
  26. {{item.supplier.name}}
  27. </checkbox>
  28. </view>
  29. <checkbox-group name="checkbox" @change="goodsChange">
  30. <view class="content" v-for="gs in item.list" :key="gs.specs._id">
  31. <view class="box">
  32. <checkbox :value="gs.specs._id" :checked="gs.check" />
  33. </view>
  34. <view class="img">
  35. <image :src="getFile(gs)"></image>
  36. </view>
  37. <view class="one_1" v-if="num==0"
  38. @click="toCommon('/pagesGoods/index/index',gs)">
  39. <view class="name textOver">{{gs.goods.name}}</view>
  40. <view class="info">
  41. <view class="title_1 textOver" v-if="gs.specs.name">
  42. <text>规格:{{gs.specs.name}}</text>
  43. </view>
  44. </view>
  45. </view>
  46. <view class="money" v-if="num==0">
  47. <view>¥{{gs.money}}</view>
  48. <view>x{{gs.num}}</view>
  49. </view>
  50. <view class="num" v-if="num==1">
  51. <uni-number-box @change="changeValue(gs)" name="num" value="gs" :min="1"
  52. :max="gs.specs.num" v-model="gs.num" />
  53. </view>
  54. <view class="del" v-if="num==1">
  55. <text class="iconfont icon-del-copy" @click="toDel(gs)"></text>
  56. </view>
  57. </view>
  58. </checkbox-group>
  59. </view>
  60. </view>
  61. </checkbox-group>
  62. </view>
  63. </scroll-view>
  64. </view>
  65. <view class="foot" v-if="list.length!=0&&user._id">
  66. <view class="total">总价:<text>¥{{totalMoney}}</text></view>
  67. <view class="btn" v-if="hasCheck()">
  68. <button type="primary" size="mini" @click="toSettle()" v-if="num==0">提交订单</button>
  69. <button type="primary" size="mini" @click="toDel()" v-if="num==1">删除</button>
  70. </view>
  71. </view>
  72. </view>
  73. </template>
  74. <script>
  75. export default {
  76. data() {
  77. return {
  78. // 用户
  79. user: {},
  80. // 购物车列表
  81. list: [],
  82. // 全选
  83. isAll: false,
  84. // 编辑/完成按钮传的数字
  85. num: 0,
  86. // 总额
  87. totalMoney: 0,
  88. }
  89. },
  90. onShow() {
  91. const that = this;
  92. that.searchToken();
  93. },
  94. methods: {
  95. searchToken() {
  96. const that = this;
  97. try {
  98. const res = uni.getStorageSync('token');
  99. if (res) {
  100. that.$set(that, `user`, res);
  101. that.searchMarket();
  102. }
  103. } catch (e) {
  104. uni.showToast({
  105. title: err.errmsg,
  106. icon: 'error',
  107. duration: 2000
  108. });
  109. }
  110. },
  111. // 查询购物车信息
  112. async searchMarket() {
  113. const that = this;
  114. const res = await that.$api(`/Cart/self`, 'GET', {
  115. user: that.user._id
  116. });
  117. if (res.errcode == '0') that.$set(that, `list`, res.data)
  118. },
  119. // 编辑
  120. edit(num) {
  121. const that = this;
  122. that.$set(that, `num`, num)
  123. },
  124. //全选
  125. selectAll(e) {
  126. const that = this;
  127. const list = that.list;
  128. const isAll = that.isAll;
  129. let data = [];
  130. for (const val of list) {
  131. let a = isAll ? false : true;
  132. val.check = a;
  133. for (let s of val.list) {
  134. s.check = a
  135. }
  136. data.push(val);
  137. }
  138. that.$set(that, `list`, data)
  139. // 计算总额
  140. that.countMoney();
  141. // 赋值是否全选
  142. that.$set(that, `isAll`, isAll ? false : true)
  143. },
  144. // 选择店铺
  145. marketChange(e) {
  146. const that = this;
  147. const list = that.list;
  148. const {
  149. value
  150. } = e.detail;
  151. for (const p1 of list) {
  152. let p2 = value.find((i) => i == p1.supplier._id);
  153. let a = p2 ? true : false;
  154. p1.check = a;
  155. for (let s of p1.list) {
  156. s.check = a
  157. }
  158. }
  159. that.$set(that, `list`, list);
  160. that.marketAllChange();
  161. // 计算总额
  162. that.countMoney();
  163. },
  164. //店铺全部选择true,全选自动选择,
  165. marketAllChange() {
  166. const that = this;
  167. let list = that.list;
  168. let check = list.find((i) => i.check == false);
  169. if (check) that.$set(that, `isAll`, false)
  170. else that.$set(that, `isAll`, true)
  171. that.$set(that, `list`, list)
  172. // 计算总额
  173. that.countMoney();
  174. },
  175. //选择商品
  176. goodsChange(e) {
  177. const that = this;
  178. let list = that.list;
  179. const {
  180. value
  181. } = e.detail;
  182. let shop = list.find(f => f.list.find(i => value.find(s => s == i.specs._id)))
  183. if (shop) {
  184. for (let val of shop.list) {
  185. let p2 = value.find((i) => i == val.specs._id);
  186. if (p2) val.check = true;
  187. else val.check = false;
  188. }
  189. } else {
  190. list = list.map(i => {
  191. if (i.check == false) {
  192. i.list = i.list.map(g => ({
  193. ...g,
  194. check: false
  195. }))
  196. } else {
  197. if (i.list.length == 1) {
  198. i.list = i.list.map(g => ({
  199. ...g,
  200. check: false
  201. }))
  202. }
  203. }
  204. return i;
  205. })
  206. }
  207. that.$set(that, `list`, list)
  208. that.goodsAllChange();
  209. // 计算总额
  210. that.countMoney();
  211. },
  212. //商品全部选择true,店铺自动选择,
  213. // 所有店铺为true,则全选为true
  214. goodsAllChange() {
  215. const that = this;
  216. let list = that.list;
  217. list = list.map(i => {
  218. const isAllSelect = i.list.every(f => f.check);
  219. if (isAllSelect) i.check = true;
  220. else i.check = false;
  221. return i;
  222. })
  223. const allSelect = list.every(e => e.check)
  224. if (allSelect) that.$set(that, `isAll`, true)
  225. else that.$set(that, `isAll`, false)
  226. // 计算总额
  227. that.countMoney();
  228. },
  229. // 加减商品数量
  230. async changeValue(value) {
  231. const that = this;
  232. that.$nextTick(async () => {
  233. let res;
  234. const {
  235. goodsSpec_id: goodsSpecId,
  236. num,
  237. cart_id: cartId
  238. } = value
  239. res = await that.$api(`/cart/checkGoodsNum`, 'GET', {
  240. cartId,
  241. goodsSpecId,
  242. num
  243. });
  244. if (res.errcode === 0) {
  245. const {
  246. enough,
  247. total
  248. } = res.data
  249. if (!enough) {
  250. uni.showToast({
  251. title: `库存最大为${total}`,
  252. icon: 'error',
  253. });
  254. // 将该商品的库存量修改为最大值
  255. value.num = total;
  256. }
  257. }
  258. // 计算总额
  259. that.countMoney();
  260. })
  261. },
  262. // 删除, 接口,购物车删除,然后将该数据移除
  263. async toDel(e) {
  264. const that = this;
  265. let list = that.list;
  266. let set_list = [];
  267. let goods_list = [];
  268. uni.showModal({
  269. title: '提示',
  270. content: '请选择要删除的商品',
  271. success: async (res) => {
  272. if (!res.confirm) return
  273. if (e?.cart_id) {
  274. const result = await that.$api(`/cart/${e.cart_id}`, 'Delete');
  275. if (result.errcode === 0) {
  276. // 判断是套装还是正常商品
  277. set_list = list.filter(i => i.is_set == '0')
  278. goods_list = list.filter(i => i.is_set !== '0')
  279. set_list = set_list.filter(i => i.cart_id !== e.cart_id)
  280. goods_list = goods_list.map(i => ({
  281. ...i,
  282. goods: i.goods.filter(f => f.cart_id !== e.cart_id)
  283. }))
  284. that.$set(that, `list`, [...set_list, ...goods_list]);
  285. // 检查店铺内是否还有商品
  286. that.checkShopGoodsExist();
  287. // 计算总额
  288. that.countMoney();
  289. }
  290. } else {
  291. let goodsList = [];
  292. let cartIds = [];
  293. for (let val of this.list) {
  294. // 判断是套装还是正常商品
  295. if (val.is_set == '0') goodsList.push(val)
  296. else goodsList.push(val.goods)
  297. }
  298. for (let val of goodsList) {
  299. // 判断是套装还是正常商品
  300. if (val.is_set == '0') {
  301. if (val.check) cartIds.push(val.cart_id)
  302. } else {
  303. for (let set of val) {
  304. if (set.check) cartIds.push(set.cart_id)
  305. }
  306. }
  307. }
  308. set_list = list.filter(i => i.is_set == '0')
  309. goods_list = list.filter(i => i.is_set !== '0')
  310. for (let val of cartIds) {
  311. const result = await this.$api(`/cart/${val}`, 'Delete');
  312. if (result.errcode === 0) {
  313. // 判断是套装还是正常商品
  314. set_list = set_list.filter(i => i.cart_id !== val)
  315. goods_list = goods_list.map(i => ({
  316. ...i,
  317. goods: i.goods.filter(f => f.cart_id !== val)
  318. }))
  319. this.$set(this, `list`, [...set_list, ...goods_list]);
  320. // 检查店铺内是否还有商品
  321. this.checkShopGoodsExist();
  322. // 计算总额
  323. this.countMoney();
  324. }
  325. }
  326. }
  327. }
  328. });
  329. },
  330. //检查店铺内是否还有商品
  331. checkShopGoodsExist() {
  332. const that = this;
  333. let list = that.list;
  334. list = list.filter(f => f.list && f.list.length > 0)
  335. that.$set(that `list`, list);
  336. },
  337. // 计算总额
  338. countMoney() {
  339. const that = this;
  340. const list = that.list;
  341. let totalMoney = 0;
  342. // 渲染结束执行下面方法
  343. that.$nextTick(() => {
  344. for (const val of list) {
  345. for (let as of val.list) {
  346. if (as.check == true) {
  347. let total = that.$multiply(as.money, as.num);
  348. totalMoney += Number(total);
  349. }
  350. }
  351. }
  352. that.$set(that, `totalMoney`, totalMoney.toFixed(2))
  353. })
  354. },
  355. // 显示图片处理
  356. getFile(data) {
  357. let file
  358. if (data.specs.file) file = data.specs.file
  359. else file = data.goods.file;
  360. if (!file) return '';
  361. if (file.length && file.length > 0) return file[0].url
  362. },
  363. // 去结算
  364. async toSettle() {
  365. // 将选中的购物车放到数组中,传回服务端进行检查.然后拿着key去订单页请求数据
  366. let goodsList = [];
  367. let cartIds = [];
  368. for (let val of this.list) {
  369. goodsList.push(val)
  370. }
  371. for (let val of goodsList) {
  372. if (val.check) cartIds.push(val.cart_id)
  373. }
  374. const res = await this.$api(`/util/checkCartBuy`, 'POST', {
  375. cartIds
  376. });
  377. if (res.errcode == '0') {
  378. const {
  379. data
  380. } = res
  381. if (data.result) {
  382. const key = data.key;
  383. uni.navigateTo({
  384. url: `/pagesHome/order/order?key=${key}`
  385. })
  386. }
  387. }
  388. },
  389. // 是否选中商品,控制提交订单按钮
  390. hasCheck() {
  391. return this.list.some(e => e.list.some(eg => eg.check))
  392. },
  393. // 公共跳转
  394. toCommon(route, e) {
  395. uni.navigateTo({
  396. url: `${route}?id=${e && e.goods._id}`
  397. })
  398. },
  399. }
  400. }
  401. </script>
  402. <style lang="scss">
  403. .main {
  404. display: flex;
  405. flex-direction: column;
  406. width: 100vw;
  407. height: 100vh;
  408. background-color: var(--footColor);
  409. .one {
  410. text-align: center;
  411. margin: 2vw 0;
  412. .logo {
  413. margin: 10vw 0 2vw 0;
  414. .iconfont {
  415. font-size: 35vw;
  416. }
  417. }
  418. .one_1 {
  419. margin: 3vw 0;
  420. }
  421. button {
  422. background-color: var(--f3CColor);
  423. }
  424. }
  425. .two {
  426. display: flex;
  427. background-color: var(--mainColor);
  428. height: 35px;
  429. margin: 0 0 4px 0;
  430. padding: 5px 4vw;
  431. .text_1 {
  432. flex-grow: 1;
  433. line-height: 30px;
  434. }
  435. .text_2 {
  436. line-height: 35px;
  437. }
  438. }
  439. .thr {
  440. position: relative;
  441. flex-grow: 1;
  442. margin: 0 2vw;
  443. .list_1 {
  444. background-color: var(--mainColor);
  445. margin: 2vw 0;
  446. padding: 2vw 2.5vw;
  447. border-radius: 4px;
  448. .title {
  449. border-bottom: 1px solid var(--fcColor);
  450. padding: 0 0 2vw 0;
  451. font-size: var(--font18Size);
  452. text {
  453. margin: 0 1vw;
  454. }
  455. }
  456. .content {
  457. display: flex;
  458. padding: 2vw 0;
  459. font-size: var(--font16Size);
  460. border-bottom: 1px dashed var(--fcColor);
  461. .box {
  462. line-height: 20vw;
  463. }
  464. .img {
  465. width: 20vw;
  466. height: 20vw;
  467. border-radius: 2vw;
  468. border: 1px solid var(--fcColor);
  469. image {
  470. width: 20vw;
  471. height: 20vw;
  472. }
  473. }
  474. .one_1 {
  475. width: 49vw;
  476. margin: 0 2vw;
  477. flex-grow: 1;
  478. .info {
  479. width: 100%;
  480. display: flex;
  481. .title_1 {
  482. font-size: var(--font12Size);
  483. color: #666;
  484. margin-top: 10px;
  485. text {
  486. background-color: #eee;
  487. padding: 5px;
  488. }
  489. }
  490. }
  491. }
  492. .money {
  493. text-align: right;
  494. flex-grow: 1;
  495. }
  496. .num {
  497. margin: 6vw 4vw;
  498. font-size: var(--font20Size);
  499. }
  500. .del {
  501. margin: 6vw 0;
  502. text-align: right;
  503. flex-grow: 1;
  504. }
  505. }
  506. }
  507. }
  508. .foot {
  509. background-color: var(--fffColor);
  510. display: flex;
  511. justify-content: space-between;
  512. height: 45px;
  513. padding: 0 0 0 6vw;
  514. border-right: 1px solid var(--f99Color);
  515. .total {
  516. flex-grow: 1;
  517. display: flex;
  518. align-content: flex-end;
  519. line-height: 40px;
  520. text {
  521. color: var(--f3CColor);
  522. }
  523. }
  524. .btn {
  525. button {
  526. width: 30vw;
  527. height: 45px;
  528. line-height: 45px;
  529. border-radius: 0px;
  530. background-color: var(--f3CColor);
  531. font-weight: normal;
  532. }
  533. }
  534. }
  535. }
  536. .scroll-view {
  537. position: absolute;
  538. top: 0;
  539. left: 0;
  540. right: 0;
  541. bottom: 0;
  542. .list-scroll-view {
  543. display: flex;
  544. flex-direction: column;
  545. }
  546. }
  547. // 复选框样式
  548. checkbox .wx-checkbox-input {
  549. width: 40rpx;
  550. height: 40rpx;
  551. border-radius: 50%;
  552. border-color: var(--f99Color);
  553. background-color: var(--mainColor);
  554. }
  555. // 复选框选中样式
  556. checkbox .wx-checkbox-input.wx-checkbox-input-checked {
  557. border-color: var(--f3CColor);
  558. background-color: var(--f3CColor);
  559. }
  560. // 复选框选中之后对号的样式
  561. checkbox .wx-checkbox-input.wx-checkbox-input-checked::before {
  562. color: var(--fffColor);
  563. }
  564. </style>