index.vue 16 KB

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