index.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. <template>
  2. <block>
  3. <!-- z-paging插件:具体使用文档请看https://z-paging.zxlee.cn/ -->
  4. <z-paging
  5. :auto="false"
  6. :refresher-enabled="false"
  7. auto-show-back-to-top
  8. back-to-top-bottom="300rpx"
  9. :paging-style="{ paddingBottom: 'constant(safe-area-inset-bottom)', paddingBottom: 'env(safe-area-inset-bottom)' }"
  10. ref="paging"
  11. v-model="dataList"
  12. >
  13. <template #top>
  14. <view v-if="!showEmptyCart" class="l-boxShadow c-bg-f l-flex-between o-plr-24 o-ptb-10">
  15. <view></view>
  16. <view class="c-text-16" @click="isEdit = !isEdit">{{ isEdit ? '完成' : '编辑' }}</view>
  17. </view>
  18. </template>
  19. <view class="o-plr-24 o-pt-20 chgUNumBox">
  20. <u-checkbox-group size="30" v-model="single_checkbox" placement="column" @change="single_checkboxChg">
  21. <view @click.self="isCheckChg(item)" class="l-flex-between l-boxShadow o-mb-20 c-bg-f o-plr-10 o-ptb-10 c-radius-10" v-for="item in dataList" style="border: 1px solid #eee;">
  22. <view class="l-flex-RC">
  23. <view class="l-flex-1"><u-checkbox :checked="item.isCheck" shape="circle" :name="item.imgId"></u-checkbox></view>
  24. <view class="l-flex-3">
  25. <u--image width="250rpx" height="250rpx" mode="aspectFit" :lazy-load="true" :fade="true" duration="450" :src="item.imgUrl">
  26. <view slot="error" style="font-size: 24rpx;">加载失败</view>
  27. </u--image>
  28. </view>
  29. </view>
  30. <view class="l-flex-6">
  31. <view class="c-text-r c-color-8" @click.stop="discountClk(item)">
  32. <u--text align="right" suffixIcon="arrow-right" color="#888" iconStyle="font-size: 18px;color:#888;" text="优惠码"></u--text>
  33. </view>
  34. <view class="u-line-2 o-mtb-30 c-color-8">{{ item.imgName }}</view>
  35. <view class="l-flex-between o-mb-20">
  36. <view class="">
  37. <text class="c-text-16 c-color-MR">¥{{ item.totalPrice }}</text>
  38. </view>
  39. <!-- 如果优惠券总金额大于0,则显示预估到手价 -->
  40. <view v-if="GETT_home_totalCoupon > 0" class="estiPriceCon c-text-12 c-color-f l-flex-RC">
  41. <view class="estiPriceTxt c-text-12 o-ptb-10 o-plr-14">预估到手</view>
  42. <view class="estiPrice c-text-12 o-ptb-10 o-plr-14">¥{{ compEstiPrice(item.totalPrice) }}</view>
  43. </view>
  44. </view>
  45. <u-number-box
  46. @overlimit="
  47. e => {
  48. numsOverlimit(e, item);
  49. }
  50. "
  51. v-model="item.nums"
  52. @change="
  53. e => {
  54. numsChg(e, item);
  55. }
  56. "
  57. disabledInput
  58. @minus="
  59. e => {
  60. goodMinus(e, item);
  61. }
  62. "
  63. @plus="
  64. e => {
  65. goodPlus(e, item);
  66. }
  67. "
  68. ></u-number-box>
  69. </view>
  70. </view>
  71. </u-checkbox-group>
  72. </view>
  73. <template #bottom>
  74. <view v-show="!showEmptyCart" class="l-boxShadow c-bg-f l-flex-between o-plr-24 o-ptb-20" style="width: 100%;">
  75. <view style="flex: 0 0 70px;">
  76. <u-checkbox-group size="30" v-model="all_checkbox" placement="column" @change="all_checkboxChg">
  77. <u-checkbox shape="circle" label="全选" name="全选"></u-checkbox>
  78. </u-checkbox-group>
  79. </view>
  80. <!-- 支付 -->
  81. <view class="l-flex-between o-w" v-if="!isEdit">
  82. <view>
  83. <view class="c-color-1 c-text-14">
  84. 合计:
  85. <text class="c-text-14 c-color-MR">¥{{ priceList.totalPrice }}</text>
  86. </view>
  87. <view class="l-f">
  88. <view class="c-color-1 c-text-14 o-mr-14">
  89. 已优惠:
  90. <text class="c-text-14 c-color-MR">¥{{ priceList.discountPrices }}</text>
  91. </view>
  92. <u--text @click="amountClk" size="14" type="primary" text="查看明细"></u--text>
  93. </view>
  94. </view>
  95. <view>
  96. <u-button
  97. :disabled="totalNums === 0"
  98. v-if="GETT_loginInfos.phone"
  99. @click="toPayPop"
  100. throttleTime="2000"
  101. type="primary"
  102. shape="circle"
  103. size="normal"
  104. :text="`去支付(${totalNums})`"
  105. ></u-button>
  106. <u-button
  107. :disabled="totalNums === 0"
  108. v-else
  109. open-type="getPhoneNumber"
  110. @getphonenumber="getPhone"
  111. type="primary"
  112. shape="circle"
  113. size="normal"
  114. :text="`去支付(${totalNums})`"
  115. ></u-button>
  116. </view>
  117. </view>
  118. <!-- 清除 -->
  119. <view class="" v-else><u-button @click="deleteSelClk" :disabled="totalNums === 0" type="error" shape="circle" :text="`删除(${totalNums})`"></u-button></view>
  120. </view>
  121. <!-- 底部导航栏-占位符解决上拉刷新没显示加载更多的问题 -->
  122. <k-tabbar :fixed="false" :placeholder="false" :safeAreaInsetBottom="false" />
  123. </template>
  124. <!-- 空数据页面显示 -->
  125. <template #empty>
  126. <u-empty :show="showEmptyCart" mode="car" icon="http://cdn.uviewui.com/uview/empty/car.png">
  127. <u-button @click="toHomeIdx" throttleTime="2000" size="small" type="primary" :customStyle="{ marginTop: '10px' }" min="1" text="查看更多商品"></u-button>
  128. </u-empty>
  129. </template>
  130. </z-paging>
  131. <u-modal @confirm="uModalConfirm" @cancel="uModalShow = false" showCancelButton :show="uModalShow" title="提示">
  132. <view class="slot-content"><view class="c-text-c">确定需要删除该商品吗?</view></view>
  133. </u-modal>
  134. <!-- 金额明细弹窗 -->
  135. <k-amountPop ref="kAmountPopRef"></k-amountPop>
  136. <!-- 优惠码弹窗 -->
  137. <k-discountPop ref="kDiscountPopRef"></k-discountPop>
  138. <!-- 支付弹窗 -->
  139. <k-payPop ref="kPayPopRef"></k-payPop>
  140. <!-- 支付提示弹窗 -->
  141. <u-modal @confirm="payShow = false" :show="payShow" title="提示" :content="payContent"></u-modal>
  142. <!-- 优惠券弹窗 -->
  143. <k-coupon ref="kCouponRef"></k-coupon>
  144. </block>
  145. </template>
  146. <script>
  147. // 导入优惠券弹窗
  148. import kCoupon from '@/components/common/k-coupon/index.vue';
  149. // 导入接口
  150. import { API_getPhone,API_setDingYue } from '@/common/api.js';
  151. // 引入辅助函数
  152. import { mapGetters } from 'vuex';
  153. // 导入金额明细弹窗
  154. import kAmountPop from '@/components/common/k-amountPop/index.vue';
  155. // 导入优惠码弹窗
  156. import kDiscountPop from '@/components/common/k-discountPop/index.vue';
  157. // 导入支付弹窗
  158. import kPayPop from '@/components/common/k-payPop/index.vue';
  159. // 引入底部导航栏
  160. import kTabbar from '@/components/common/k-tabbar/k-tabbar.vue';
  161. export default {
  162. components: {
  163. kTabbar,
  164. kPayPop,
  165. kDiscountPop,
  166. kAmountPop,
  167. kCoupon
  168. },
  169. data() {
  170. return {
  171. // 是否编辑模式
  172. isEdit: false,
  173. // 支付提示弹窗
  174. payShow: false,
  175. payContent: false,
  176. // 控制模态框的显示
  177. uModalShow: false,
  178. // z-paging插件的主数据,用作列表渲染
  179. dataList: [],
  180. // 全选checkbox的值
  181. all_checkbox: [],
  182. // 单选checkbox的值
  183. single_checkbox: [],
  184. // 用来存储要删除的商品
  185. deleteShops: {}
  186. };
  187. },
  188. computed: {
  189. // 使用辅助函数
  190. ...mapGetters(['GETT_loginInfos', 'GETT_clientId', 'GETT_home_couponList', 'GETT_home_totalCoupon']),
  191. // 整合购物车数据
  192. $S_tabbar_shopCarts() {
  193. let shopCarts = this.$M_GS('common', '$S_tabbar_shopCarts');
  194. if (!this.$M_IsEmpty(shopCarts)) {
  195. let cartList = [];
  196. for (let key in shopCarts) {
  197. cartList.push(shopCarts[key]);
  198. }
  199. return cartList;
  200. } else {
  201. return [];
  202. }
  203. },
  204. // 购物车数据是否为空
  205. showEmptyCart() {
  206. if (this.$M_IsEmpty(this.$S_tabbar_shopCarts)) return true;
  207. return false;
  208. },
  209. // 单选的选中值
  210. singleCheckbox() {
  211. let single_checkbox = [];
  212. if (this.$S_tabbar_shopCarts.length > 0) {
  213. single_checkbox = this.$S_tabbar_shopCarts.map(item => {
  214. if (item.isCheck) {
  215. return item.imgId;
  216. }
  217. });
  218. }
  219. return single_checkbox;
  220. },
  221. // 全选的选中值
  222. allCheckbox() {
  223. let all_checkbox = [];
  224. if (this.$S_tabbar_shopCarts.length > 0) {
  225. all_checkbox = this.$S_tabbar_shopCarts.map(item => {
  226. if (item.isCheck) {
  227. return item.imgId;
  228. }
  229. });
  230. }
  231. all_checkbox = this.arrTrimSpace(all_checkbox);
  232. if (all_checkbox.length === this.$S_tabbar_shopCarts.length) return ['全选'];
  233. return [];
  234. },
  235. // 选中的总数量
  236. totalNums() {
  237. let totalNums = 0;
  238. if (this.$S_tabbar_shopCarts.length > 0) {
  239. this.$S_tabbar_shopCarts.forEach(item => {
  240. if (item.isCheck) {
  241. totalNums = this.$M_Big(totalNums).add(item.nums);
  242. }
  243. });
  244. }
  245. return totalNums;
  246. },
  247. // 选中的总金额
  248. priceList() {
  249. let totalPrice = 0;
  250. let discountPrices = 0;
  251. if (this.$S_tabbar_shopCarts.length > 0) {
  252. this.$S_tabbar_shopCarts.forEach(item => {
  253. if (item.isCheck) {
  254. let discountPrice = 0;
  255. // 计算出每件商品的总优惠
  256. if (item.discountList && item.discountList.length > 0) {
  257. discountPrice = item.discountList.reduce((prev, cur) => {
  258. return this.$M_Big(prev)
  259. .add(cur)
  260. .toNumber();
  261. }, 0);
  262. }
  263. // 减去总优惠
  264. totalPrice = this.$M_Big(totalPrice)
  265. .add(item.totalPrice)
  266. .sub(discountPrice)
  267. .toNumber();
  268. // 总优惠是
  269. discountPrices = this.$M_Big(discountPrices)
  270. .add(discountPrice)
  271. .toNumber();
  272. }
  273. });
  274. }
  275. return {
  276. totalPrice,
  277. discountPrices
  278. };
  279. },
  280. // 计算预估到手价
  281. compEstiPrice() {
  282. return function(totalPrice) {
  283. const estiPrice = this.$M_Big(totalPrice)
  284. .sub(this.GETT_home_totalCoupon)
  285. .toNumber();
  286. if (estiPrice <= 0) return 0.01;
  287. return estiPrice;
  288. };
  289. }
  290. },
  291. mounted() {
  292. // 首次进入需要调用方法加载
  293. this.$refs.paging.complete(this.$S_tabbar_shopCarts);
  294. },
  295. updated() {
  296. // 当vuex数据更新时重新赋值给购物车
  297. this.dataList = this.$S_tabbar_shopCarts;
  298. this.single_checkbox = this.singleCheckbox;
  299. this.all_checkbox = this.allCheckbox;
  300. },
  301. methods: {
  302. // 点击改变选中状态
  303. isCheckChg(row) {
  304. row.isCheck = !row.isCheck;
  305. },
  306. // 点击删除按钮
  307. deleteSelClk() {
  308. // 如果没有机器编码就提示联系管理员
  309. uni.showModal({
  310. title: '提示',
  311. confirmText: '确定',
  312. confirmColor: '#3c9cff',
  313. content: `确定需要删除选定的商品吗?`,
  314. success: modelRes => {
  315. if (modelRes.confirm) {
  316. let cartList = this.$S_tabbar_shopCarts;
  317. let list = [];
  318. // 筛选出选中的商品
  319. if (cartList.length > 0) {
  320. cartList.forEach((item, index) => {
  321. if (item.isCheck) {
  322. delete cartList[index];
  323. } else {
  324. list.push(item);
  325. }
  326. });
  327. }
  328. // 把数组转成对象
  329. let shopCarts = this.arrAttrToOBj(list, 'imgId');
  330. this.$M_Dp('ACTI_SHOPCARTS', shopCarts);
  331. this.isEdit = false;
  332. }
  333. }
  334. });
  335. },
  336. // 点击查看明细
  337. amountClk() {
  338. this.$refs.kAmountPopRef.popOpen(this.$S_tabbar_shopCarts, this.priceList);
  339. },
  340. // 点击优惠码
  341. discountClk(row) {
  342. this.$refs.kDiscountPopRef.popOpen(row, 1);
  343. },
  344. // 获取手机号
  345. async getPhone(e) {
  346. const { code } = e.detail;
  347. // 如果用户点击允许获取手机号
  348. if (!!code) {
  349. let param = {
  350. code,
  351. id: this.GETT_loginInfos.id
  352. };
  353. // 调用获取手机号的接口
  354. let res = await API_getPhone(param);
  355. // 把手机号信息存到vuex里面
  356. await this.$M_Cm('MUTA_GETOPENID', res);
  357. console.log('GETT_loginInfos', this.GETT_loginInfos);
  358. }
  359. this.toPayPop();
  360. },
  361. // 点击支付按钮
  362. toPayPop() {
  363. // 规定支付的商品数量不能超过5
  364. if (this.totalNums > 3) {
  365. this.payContent = '支付商品的数量不能超过3件,请到购物车页面减少数量后,重新支付!!!';
  366. this.payShow = true;
  367. return;
  368. }
  369. //询问是否订阅取餐通知
  370. this.dingyue();
  371. let list = [];
  372. // 筛选出选中的商品
  373. if (this.$S_tabbar_shopCarts.length > 0) {
  374. this.$S_tabbar_shopCarts.forEach(item => {
  375. if (item.isCheck) {
  376. list.push(item);
  377. }
  378. });
  379. }
  380. // 把数组转成对象
  381. let shopCarts = this.arrAttrToOBj(list, 'imgId');
  382. // 组合要支付的参数
  383. const payParam = {
  384. shopCarts,
  385. clientId: this.GETT_clientId,
  386. id: this.GETT_loginInfos.id
  387. };
  388. // 如果有优惠券要提醒用户去选择优惠券
  389. if (this.GETT_home_couponList.length > 0) {
  390. uni.showModal({
  391. title: '提示',
  392. confirmText: '去使用',
  393. cancelText: '不使用',
  394. confirmColor: '#3c9cff',
  395. content: `当前可使用优惠券${this.GETT_home_couponList.length}张。`,
  396. success: modelRes => {
  397. if (modelRes.confirm) {
  398. // 打开优惠券弹窗
  399. this.$refs.kCouponRef.popOpen(this.GETT_home_couponList, payParam, 2, this.priceList.totalPrice);
  400. } else {
  401. // 显示支付弹窗
  402. this.$refs.kPayPopRef.popOpen(payParam, 2);
  403. }
  404. }
  405. });
  406. } else {
  407. // 显示支付弹窗
  408. this.$refs.kPayPopRef.popOpen(payParam, 2);
  409. }
  410. },
  411. //询问是否订阅取餐通知
  412. dingyue(){
  413. var that = this;
  414. wx.requestSubscribeMessage({
  415. tmplIds: ['NVmdaK4MwygT63ME830pwM6wZt4eufxhBr6jlQ2XXJ4'],
  416. success(res) {
  417. var status = res.NVmdaK4MwygT63ME830pwM6wZt4eufxhBr6jlQ2XXJ4;
  418. if(status=='accept'){
  419. //通知后台该用户订阅了消息
  420. var id = that.GETT_loginInfos.id;
  421. API_setDingYue( {id:id} ).then(res => {
  422. console.log('res', res);
  423. });
  424. }
  425. console.log('授权成功');
  426. }
  427. })
  428. },
  429. // 当数量超出范围,比如最小范围1触发
  430. numsOverlimit(e, row) {
  431. if (e === 'minus') {
  432. this.deleteShops = row;
  433. this.uModalShow = true;
  434. }
  435. },
  436. // 点击删除弹窗的确定按钮
  437. uModalConfirm() {
  438. let shopCarts = this.$S_tabbar_shopCarts;
  439. let list = [];
  440. if (shopCarts.length > 0) {
  441. // 根据id筛选出不是删除的那个商品
  442. list = shopCarts.filter(item => {
  443. if (item.imgId !== this.deleteShops.imgId) {
  444. return item;
  445. } else {
  446. // 要把优惠码和优惠价清空
  447. item.codeList = [];
  448. item.discountList = [];
  449. }
  450. });
  451. }
  452. // 把数组转成对象储存到vuex中
  453. let cartList = this.arrAttrToOBj(list, 'imgId');
  454. this.$M_Dp('ACTI_SHOPCARTS', cartList);
  455. this.uModalShow = false;
  456. },
  457. // 点击商品+
  458. goodPlus(e, row) {
  459. this.handleCar(e, row, 1);
  460. },
  461. // 点击商品-
  462. goodMinus(e, row) {
  463. this.handleCar(e, row, 2);
  464. },
  465. // 点击数量的+-
  466. numsChg(e, row) {
  467. // 增加用户体验
  468. uni.showLoading({
  469. title: '请稍等'
  470. });
  471. setTimeout(() => {
  472. uni.hideLoading();
  473. }, 200);
  474. this.handleCar(e, row, 3);
  475. },
  476. // 处理购物车数据
  477. handleCar(e, row, idx) {
  478. let shopCarts = this.$S_tabbar_shopCarts;
  479. if (shopCarts.length > 0) {
  480. shopCarts.forEach(item => {
  481. if (item.imgId === row.imgId) {
  482. switch (idx) {
  483. // 给优惠码和优惠价的列表添加一个0值
  484. case 1:
  485. item.codeList.push(0);
  486. item.discountList.push(0);
  487. break;
  488. // 去掉优惠码和优惠价的列表的最后一个
  489. case 2:
  490. item.codeList.pop();
  491. item.discountList.pop();
  492. break;
  493. // 找到购物车数据对应商品的,重新计算总价格
  494. case 3:
  495. item.nums = e.value;
  496. item.totalPrice = this.$M_Big(item.goodsPrice)
  497. .mul(item.nums)
  498. .toNumber();
  499. break;
  500. }
  501. }
  502. });
  503. }
  504. // 把数组转成对象储存到vuex中
  505. let cartList = this.arrAttrToOBj(shopCarts, 'imgId');
  506. this.$M_Dp('ACTI_SHOPCARTS', cartList);
  507. },
  508. // 根据数组的某个属性转成对象
  509. arrAttrToOBj(arr, attr, obj = {}) {
  510. if (arr.length > 0) {
  511. arr.forEach(item => {
  512. obj[item[attr]] = item;
  513. });
  514. return obj;
  515. } else {
  516. return {};
  517. }
  518. },
  519. // 去掉数组的空格,null,undefeated类型
  520. arrTrimSpace(array) {
  521. let list = [];
  522. array.forEach(item => {
  523. if (item == '' || item == null || typeof item == 'undefined') {
  524. } else {
  525. list.push(item);
  526. }
  527. });
  528. return list;
  529. },
  530. // 点击单选按钮
  531. single_checkboxChg(e) {
  532. let shopCarts = this.$S_tabbar_shopCarts;
  533. let singleList = this.arrTrimSpace(e);
  534. // 如果存在单选
  535. if (singleList.length > 0) {
  536. if (shopCarts.length > 0) {
  537. shopCarts.forEach(item => {
  538. item.isCheck = false;
  539. singleList.forEach(item1 => {
  540. if (item.imgId === item1) {
  541. item.isCheck = true;
  542. }
  543. });
  544. });
  545. }
  546. } else {
  547. if (shopCarts.length > 0) {
  548. // 取消全选,具体是遍历数组,把全选的isCheck改为false
  549. shopCarts.forEach(item => {
  550. item.isCheck = false;
  551. });
  552. }
  553. }
  554. // 把数组转成对象储存到vuex中
  555. let cartList = this.arrAttrToOBj(shopCarts, 'imgId');
  556. this.$M_Dp('ACTI_SHOPCARTS', cartList);
  557. },
  558. // 点击全选按钮
  559. all_checkboxChg(e) {
  560. let shopCarts = this.$S_tabbar_shopCarts;
  561. let all_checkbox = [];
  562. // 全选的长度大于0
  563. if (e.length > 0) {
  564. if (shopCarts.length > 0) {
  565. // 全选,具体是遍历数组,把全选的isCheck改为true,并且把控制全选的checkbox赋值
  566. shopCarts.forEach(item => {
  567. item.isCheck = true;
  568. all_checkbox.push(item.imgId);
  569. });
  570. }
  571. } else {
  572. // 取消全选,具体是遍历数组,把全选的isCheck改为false
  573. if (shopCarts.length > 0) {
  574. shopCarts.forEach(item => {
  575. item.isCheck = false;
  576. });
  577. }
  578. }
  579. // 全选的值
  580. this.all_checkbox = all_checkbox;
  581. // 把数组转成对象储存到vuex中
  582. let cartList = this.arrAttrToOBj(shopCarts, 'imgId');
  583. this.$M_Dp('ACTI_SHOPCARTS', cartList);
  584. },
  585. // 点击去首页
  586. toHomeIdx() {
  587. // 改变vuex的数据
  588. this.$M_Dp('ACTI_TABIDX', 0);
  589. }
  590. }
  591. };
  592. </script>
  593. <style lang="scss" scoped>
  594. .estiPriceCon {
  595. .estiPriceTxt {
  596. position: relative;
  597. color: #ff9900;
  598. background-color: #fff5f4;
  599. border-right: 1px solid #fff;
  600. }
  601. .estiPrice {
  602. background-color: #f15c34;
  603. border-top-right-radius: 10rpx;
  604. border-bottom-right-radius: 10rpx;
  605. }
  606. }
  607. </style>