parkingFeeCoupon.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. import { mapState } from 'vuex';
  2. import uni from '@/utils/uniHooks';
  3. // import { initWxJsSdkConfig } from '@/utils/login';
  4. import { Toast } from 'vant';
  5. import { getPlatform, getAppIdByGroupIdAndMallId, isInWeixinH5 } from '@/utils';
  6. import { initWxJsSdkConfig } from '@/utils/login';
  7. import moment from 'moment'
  8. // import { compare } from '@/utils/location.js';
  9. // import { isArray } from 'lodash';
  10. // import { v4 as uuidv4 } from 'uuid';
  11. export default {
  12. data() {
  13. return {
  14. checkedCouponList: [],
  15. couponList: [],
  16. launchPath: '', // H5跳转CRM微信小程序
  17. envVersion: window.env === 'qa' ? 'trial' : 'release', // 所需跳转的小程序版本,合法值为:正式版release、开发版develop、体验版trial(支持的微信版本:iOS 8.0.18及以上、Android 8.0.19及以上)
  18. platform: getPlatform(),
  19. maxCouponFee: 0, // 计算优惠券已选的总金额
  20. remainPrice: 0, // 剩余可用优惠额度
  21. newAvailableDiscountFee: 0, // 可使用的电子券的优惠金额上限
  22. extraData: {}
  23. };
  24. },
  25. computed: {
  26. ...mapState({
  27. custTypeId: (state) => state.custTypeId,
  28. actualPayFee: (state) => state.order.actualPayFee,
  29. orderDetail: (state) => state.order.orderDetail,
  30. coupons: (state) => state.order.coupons,
  31. maxOneDayDiscountFee: (state) => state.order.maxOneDayDiscountFee, // 深圳单日单次使用上限
  32. usingTotalDiscount: (state) => state.order.usingTotalDiscount, // 当前已使用优惠
  33. availableDiscountFee: (state) => state.order.availableDiscountFee, // 当前已使用优惠
  34. paperDiscountFee: (state) => state.order.paperDiscountFee, // 当前已使用优惠
  35. unLimitWeekendPoints: (state) => state.order.unLimitWeekendPoints, // 新的积分上限, 默认为false(不开启), unLimitWeekendPoints: true # 开启无上限功能;   unLimitWeekendPoints: false # 关闭无上限功能;
  36. lbsId: (state) => state.lbsId, // 楼栋ID
  37. groupId: (state) => state.groupId, // 楼盘ID
  38. remainCoupons: ( state ) => state.order.remainCoupons, // 仅限杭州当前剩余可选电子券上限
  39. parkMallCode: ( state ) => state.order.parkMallCode, // 当前车场的数据
  40. maxOneDayCoupons: ( state ) => state.order.maxOneDayCoupons,// 仅限杭州当日电子券可选上限
  41. paperDiscountFee: ( state ) => state.order.paperDiscountFee,// 纸质券的优惠金额
  42. }),
  43. totalFeeInYuan() {
  44. return this?.orderDetail?.parkingRecord?.totalFee / 100
  45. }
  46. },
  47. mounted() {
  48. // console.log('parkingFeeCoupon.js');
  49. setTimeout(() => {
  50. uni.setNavigationBarTitle({
  51. title: '优惠券',
  52. });
  53. if (isInWeixinH5()) {
  54. initWxJsSdkConfig(['checkJsApi', 'chooseImage'], ['wx-open-launch-weapp']);
  55. this.launchPathInit();
  56. }
  57. }, 300);
  58. setTimeout(() => {
  59. window?.toWXSendMsg({
  60. type: 'uni_func',
  61. funcName: 'setNavigationBarColor',
  62. options: {
  63. frontColor: '#000000',
  64. backgroundColor: '#FBFCFF',
  65. },
  66. });
  67. }, 500)
  68. this.pageInit();
  69. },
  70. methods: {
  71. pageInit() {
  72. const {parkInfo} = this.orderDetail
  73. const { parkMallCode } = parkInfo;
  74. /*
  75. * 电子优惠券初始化逻辑(后端处理)
  76. *
  77. * 1、每次change之后,需要重新计算每个电子优惠券的逻辑
  78. * 2、superposition 叠加使用规则 (1不可叠加,2仅同类型可叠加,3可叠加);
  79. * */
  80. this.couponList = [...this.coupons];
  81. this.remainPrice = this.usingTotalDiscount - this.paperDiscountFee;
  82. if ((this.parkMallCode === 4 || this.parkMallCode === 6) && this.orderDetail?.discountInfo?.points?.[0]?.discountFee) {
  83. this.remainPrice = this.remainPrice - this.orderDetail.discountInfo.points[0].discountFee
  84. }
  85. // 如果前海开启无积分上限的话,则
  86. if ( [5, 10].indexOf(parkMallCode) > -1 && this.orderDetail.discountInfo?.points?.[0]?.discountFee) {
  87. this.remainPrice = this.remainPrice - this.orderDetail?.discountInfo?.points[0]?.discountFee
  88. }
  89. this.newAvailableDiscountFee = this.availableDiscountFee
  90. // console.log(878787, this.newAvailableDiscountFee);
  91. if (this.couponList.length) {
  92. this.couponList = this.couponList.map((elm, index) => {
  93. elm.disabled = true;
  94. const selected = elm.hasOwnProperty('selected') ? elm.selected : elm.defaultSelected;
  95. if (selected) {
  96. this.maxCouponFee = this.maxCouponFee + elm.discountFee;
  97. this.checkedCouponList.push(`coupon${index}`);
  98. elm.disabled = false;
  99. } else {
  100. // elm.disabled = !elm.defaultSelected
  101. }
  102. return elm;
  103. });
  104. if (!this.checkedCouponList.length) {
  105. this.couponList = this.couponList.map((elm) => {
  106. elm.disabled = false;
  107. return elm;
  108. });
  109. }
  110. this.$nextTick(() => {
  111. // 验证剩余优惠券是否可勾选(无需验证:后端已计算可勾选的优惠券)
  112. this.newGroupedCouponData()
  113. this.setAllDisabled()
  114. if (this.parkMallCode === 4 || this.parkMallCode === 6) {
  115. this.isDisabledByRule(this.couponList[0], 0, 'showMsg');
  116. }
  117. })
  118. }
  119. },
  120. item2Number(i) {
  121. return Number.parseInt(i.replace(/coupon/g, ''));
  122. },
  123. checkboxItemChange(name, index) {
  124. const coupon = this.couponList[index];
  125. if ( coupon.disabled ) {
  126. if (this.getAmountToBePaid() <= 0) {
  127. Toast('当前无需追加优惠')
  128. return;
  129. }
  130. setTimeout(() => {
  131. // 根据电子券规则判断是否可选
  132. this.isDisabledByRule(coupon, index);
  133. }, 100)
  134. return;
  135. }
  136. // 取消勾选时
  137. if (this.checkedCouponList.indexOf(name) > -1) {
  138. this.checkedCouponList = this.checkedCouponList.filter((i) => i !== name);
  139. setTimeout(() => {
  140. this.remainPrice = this.remainPrice - this.couponList[index].discountFee
  141. this.newAvailableDiscountFee = this.newAvailableDiscountFee + this.couponList[index].discountFee
  142. this.newGroupedCouponData()
  143. this.isDisabledByRule(coupon, index, 'showMsg');
  144. }, 100)
  145. return;
  146. }
  147. // 如果有选中项
  148. // 还需支付金额 = 总金额 - 优惠金额
  149. if (this.getAmountToBePaid() <= 0) {
  150. Toast('当前无需追加优惠')
  151. return;
  152. }
  153. const item = this.couponList[index];
  154. this.remainPrice = this.remainPrice + this.couponList[index].discountFee
  155. this.newAvailableDiscountFee = this.newAvailableDiscountFee - this.couponList[index].discountFee
  156. if (!item.disabled) {
  157. this.checkedCouponList.push(`coupon${index}`);
  158. }
  159. this.$nextTick(() => {
  160. this.newGroupedCouponData()
  161. this.setAllDisabled()
  162. this.isDisabledByRule(coupon, index, 'showMsg');
  163. })
  164. },
  165. // 针对达到优惠的上限制
  166. setAllDisabled() {
  167. const {parkInfo,parkingRule} = this.orderDetail
  168. const { parkMallCode } = parkInfo;
  169. const {maxOneTimeDiscountTime,oneTimeLimitation,oneDayLimitation,hourPrice,remainConsumeTime} = parkingRule
  170. // 设置深圳的达到优惠金额的上限,置灰剩下未选择的金额
  171. if ( [5, 10].indexOf(parkMallCode) > -1 && this.remainPrice >= this.newAvailableDiscountFee) {
  172. this.couponList = this.couponList.map((elm,iemi) => {
  173. if ( !elm.disabled && this.checkedCouponList.indexOf(`coupon${iemi}`) < 0) {
  174. elm.disabled = true
  175. }
  176. return elm
  177. })
  178. return true
  179. }
  180. // 单日上限限制
  181. if ( oneDayLimitation && [5,10].indexOf(parkMallCode) < 0) {
  182. const maxOneTimeDiscountFee = maxOneTimeDiscountTime * hourPrice
  183. const remainConsumeTimeFee = remainConsumeTime * hourPrice
  184. // 计算单日剩余 remainConsumeTime
  185. // 当前使用优惠 state.usingTotalDiscount
  186. // 判断符合上限
  187. if ( this.remainPrice >= maxOneTimeDiscountFee) {
  188. this.couponList = this.couponList.map((elm,iemi) => {
  189. if ( !elm.disabled && this.checkedCouponList.indexOf(`coupon${iemi}`) < 0) {
  190. elm.disabled = true
  191. }
  192. return elm
  193. })
  194. }
  195. }
  196. // 单次上限限制
  197. if ( oneTimeLimitation && [ 5, 10 ].indexOf(parkMallCode) < 0 ) {
  198. const maxOneTimeDiscountFee = maxOneTimeDiscountTime * hourPrice
  199. // const remainConsumeTimeFee = remainConsumeTime * hourPrice
  200. // 计算单日剩余 remainConsumeTime
  201. // 当前使用优惠 state.usingTotalDiscount
  202. // 判断符合上限
  203. if ( this.remainPrice >= maxOneTimeDiscountFee ) {
  204. this.couponList = this.couponList.map((elm,iemi) => {
  205. if ( !elm.disabled && this.checkedCouponList.indexOf(`coupon${iemi}`) < 0) {
  206. elm.disabled = true
  207. }
  208. return elm
  209. })
  210. }
  211. }
  212. // 杭州、福州电子券选择上限判断
  213. if ( (parkMallCode === 2 || parkMallCode === 8) && this.checkedCouponList.length === this.remainCoupons ) {
  214. this.couponList = this.couponList.map(( elm,iemi ) => {
  215. if ( !elm.disabled && this.checkedCouponList.indexOf(`coupon${ iemi }`) < 0 ) {
  216. elm.disabled = true
  217. }
  218. return elm
  219. })
  220. }
  221. return false
  222. },
  223. // 对不同类型的优惠券进行汇总统计
  224. newGroupedCouponData() {
  225. let couponList = [...this.couponList]; // 获取目前用户的电子券
  226. if (!this.checkedCouponList.length) {
  227. this.couponList = couponList.map(elm => {
  228. elm.disabled = elm?.status !== 'available' || !moment().isBefore(elm.expirationDate);
  229. return elm;
  230. })
  231. return
  232. }
  233. // 如果杭州、福州的使用券打到上限则不自动计算其余券是否可选
  234. if ( this.checkedCouponList.length >= this.remainCoupons && (this.parkMallCode === 2 || this.parkMallCode === 8) ) {
  235. return
  236. }
  237. // console.log(292,this.couponList);
  238. const index = this.item2Number(this.checkedCouponList[0])
  239. const item = this.couponList[index];
  240. const { superposition, limitCountPerOrder = 0, name } = item;
  241. switch (superposition) {
  242. case '1': // 不可叠加
  243. couponList = couponList.map((elm, i) => {
  244. elm.disabled = i !== index
  245. return elm;
  246. })
  247. break;
  248. case '2': // 同类型可叠加
  249. // 找到
  250. couponList = couponList.map((elm, i) => {
  251. // 只有 status === 'available' 的才会赋值为 false
  252. elm.disabled = elm?.status !== 'available' || !moment().isBefore(elm.expirationDate); // 默认可选
  253. // 找到所以 superposition === 2 的同类型的券
  254. if ( elm?.status === 'unavailable' || moment().isSameOrAfter(elm.expirationDate)) {
  255. // 这里是做一个阻断,就是避免程序往下执行,没有别的意思
  256. elm.disabled = true
  257. } else if (elm.superposition === superposition) { // 这里是找到一样类型的券
  258. const selectCouponIds = couponList.filter((iem, iemi) => iem.couponId === elm.couponId && this.checkedCouponList.indexOf(`coupon${iemi}`) > -1); // 筛选出相同批次(couponId一样)的电子券,并且是已经选中的
  259. if (elm.limitCountPerOrder > 1) { // 是否存在上限
  260. if (selectCouponIds.length >= elm.limitCountPerOrder) { // 如果这个批次的券已经选了一部分,并且超过了可选上限的话。
  261. elm.disabled = selectCouponIds.findIndex(iem => iem.code === elm.code) < 0 // 置灰剩余没有选中的电子券
  262. }
  263. } else if (elm.limitCountPerOrder === 0) { // 如果是 0 的话,则不做任何限制
  264. elm.disabled = false
  265. } else {
  266. elm.disabled = selectCouponIds.findIndex(iem => iem.code === elm.code) < 0 && selectCouponIds.length > 0 // 同类型可选的券,如果可选上限是1,就设为不可选择
  267. }
  268. } else {
  269. elm.disabled = true; // 非同批次的优惠券设置为不可选择
  270. }
  271. return elm
  272. })
  273. break;
  274. }
  275. this.couponList = [...couponList];
  276. },
  277. // 根据电子券规则判断是否可选
  278. isDisabledByRule(item, index, showMsg) {
  279. const { parkMallCode } = this.orderDetail.parkInfo;
  280. // 最高优先级,提示未生效的电子券
  281. if (item.status === 'unavailable' || moment().isSameOrAfter(item.expirationDate)) {
  282. return Toast({
  283. message: `当前电子券暂未生效,不可用`,
  284. className: "white-space",
  285. icon: 'none',
  286. });
  287. }
  288. // 电子券上限判断(杭州、福州)
  289. if ( this.checkedCouponList.length >= this.remainCoupons && (this.parkMallCode === 2 || this.parkMallCode === 8) ) {
  290. if ( showMsg ) return true
  291. return Toast({
  292. message: `电子券每天最多可使用${ this.maxOneDayCoupons }张`,
  293. className: "white-space",
  294. icon: 'none',
  295. });
  296. }
  297. // 浦东每次缴费超限控制、沈阳每日超限控制
  298. if ([1, 4, 5, 999, 6, 10].indexOf(parkMallCode) > -1 && this.crossMessage(showMsg)) {
  299. this.couponList = this.couponList.map((e, i) => {
  300. if (this.checkedCouponList.findIndex((c) => c === `coupon${i}`) === -1) {
  301. e.disabled = true;
  302. }
  303. return e
  304. });
  305. return;
  306. }
  307. // 选中状态赋值
  308. // this.groupedCouponData();
  309. this.newGroupedCouponData();
  310. },
  311. // 是否选中
  312. isCheck(val) {
  313. return this.checkedCouponList.findIndex((e) => e == val) !== -1;
  314. },
  315. // 超限提示
  316. crossMessage(showMsg = '') {
  317. const { parkMallCode } = this.orderDetail.parkInfo;
  318. const { maxOneDayCoupons, maxonedaydiscountFee, maxOneTimeDiscountTime, remainConsumeTime, hourPrice, availableDiscountFee, oneTimeLimitation,oneDayLimitation, maxOneDayDiscountFee } = this.orderDetail.parkingRule;
  319. const {
  320. usingTotalDiscount, // 使用总抵扣
  321. coupons,
  322. } = this.orderDetail.discountInfo;
  323. const {
  324. // totalFee, // 应缴
  325. actualPayFee, // 应付金额
  326. } = this.orderDetail.parkingRecord;
  327. // 剩余可使用的优惠金额,支持动态计算; 优惠时长,不可能全部使用,不能超过车费减去优惠的金额;不能超过单次的应付金额
  328. let remainPrice = remainConsumeTime * hourPrice;
  329. if (parkMallCode === 5 || parkMallCode === 10) {
  330. if (remainPrice - this.paperDiscountFee > actualPayFee) {
  331. remainPrice = actualPayFee;
  332. }
  333. }
  334. // 深圳超限处理
  335. if ([5, 10].indexOf(parkMallCode) > -1 && this.remainPrice >= this.availableDiscountFee) {
  336. if ( showMsg ) return true
  337. return Toast({
  338. message: `优惠券已达当日使用上限,不可再用`,
  339. className: "white-space",
  340. icon: 'none',
  341. });
  342. }
  343. // 单日上限
  344. if (oneDayLimitation && this.remainPrice >= this.availableDiscountFee) {
  345. if ( showMsg ) return true
  346. return Toast({
  347. message: [5, 10].indexOf(parkMallCode) > -1 ? '当日优惠已达上限,不可再用' : `每日最高可抵扣${maxOneDayDiscountFee}元`,
  348. className: "white-space",
  349. icon: 'none',
  350. });
  351. }
  352. const maxOneTimeDiscountFee = maxOneTimeDiscountTime * hourPrice
  353. // 单次上限限制
  354. if ( oneTimeLimitation && [5, 10].indexOf(parkMallCode) < 0 && this.remainPrice >= maxOneTimeDiscountFee) {
  355. if ( showMsg ) return true
  356. return Toast({
  357. message: `超出抵扣上限,每次最高可抵扣${maxOneTimeDiscountTime}小时`,
  358. className: "white-space",
  359. icon: 'none',
  360. });
  361. }
  362. return false
  363. },
  364. // 确认
  365. confirm() {
  366. // 重新计算兑换券优惠
  367. const checkedCouponList = this.checkedCouponList.map((i) => this.item2Number(i));
  368. const couponList = this.couponList.map((elm, index) => {
  369. elm.selected = false;
  370. if (this.checkedCouponList.indexOf(`coupon${index}`) > -1) {
  371. elm.selected = true;
  372. }
  373. return elm;
  374. });
  375. this.$store.dispatch('order/saveCouponMath', {
  376. couponList: couponList,
  377. callback: () => {
  378. this.$router.back();
  379. },
  380. });
  381. /*uni.setStorageSync('checkedCouponList', this.checkedCouponList);
  382. uni.setStorageSync('list', this.list);
  383. uni.setStorageSync('couponInfo', {
  384. couponfee: this.totalFee,
  385. couponcode: this.couponCode.join('#'),
  386. });
  387. this.$router.back();*/
  388. },
  389. launchPathInit() {
  390. const groupId = uni.getStorageSync('groupId');
  391. const mallId = uni.getStorageSync('mallId');
  392. const { projectId } = getAppIdByGroupIdAndMallId({
  393. groupId: groupId,
  394. mallId: mallId,
  395. type: 'all',
  396. });
  397. this.launchPath = `?trackSourceType=运营位&trackSourceName=功能球&projectId=${projectId}&groupId=${groupId}&mallId=${mallId}&source=tparkingH5`;
  398. let isLogin = false
  399. const member = uni.getStorageSync('member');
  400. if (member && JSON.stringify(this.member) !== '{}') {
  401. isLogin = true
  402. }
  403. this.extraData = {
  404. brandId: this.groupId,
  405. lbsId: this.lbsId,
  406. isLogin: isLogin,
  407. navigate_time:new Date().getTime()
  408. }
  409. },
  410. // 获取还需支付金额
  411. getAmountToBePaid() {
  412. let amountToBePaid = this.totalFeeInYuan - this.paperDiscountFee - this.remainPrice;
  413. if([ 5, 10 ].indexOf(this.parkMallCode) > -1 && this.orderDetail.discountInfo?.points?.[0]?.discountFee) {
  414. amountToBePaid = amountToBePaid - this.orderDetail.discountInfo?.points?.[0]?.discountFee
  415. }
  416. if([ 4, 6 ].indexOf(this.parkMallCode) > -1 && this.orderDetail.discountInfo?.points?.[0]?.discountFee) {
  417. amountToBePaid = amountToBePaid - this.orderDetail.discountInfo?.points?.[0]?.discountFee
  418. }
  419. return amountToBePaid
  420. },
  421. // 跳转小程序
  422. navigateToMiniProgram() {
  423. if (this.platform === 'miniprogram') {
  424. window.toWXSendMsg({
  425. type: 'navigateToMiniProgram',
  426. options: {
  427. retailLbsId: this.lbsId,
  428. },
  429. });
  430. // 订阅微信小程序端的回调
  431. window.subscribe('navigateToMiniProgramOver', (options) => {
  432. if (options.navigateToMiniProgramOver === 'ok') {
  433. this.$store.commit('cachedViews/DEL_CACHED_VIEW', {
  434. name: 'parkingFeeDetail',
  435. });
  436. this.$router.go(-2);
  437. }
  438. });
  439. }
  440. if (isInWeixinH5()) {
  441. // this.$wx.chooseWXPay({
  442. // timestamp: params?.timeStamp,
  443. // nonceStr: params?.nonceStr,
  444. // package: params?.package,
  445. // signType: params?.signType,
  446. // paySign: params?.paySign,
  447. // success: function (res) {
  448. // // alert('success: ' + JSON.stringify(res));
  449. // // res: {"errMsg":"chooseWXPay:cancel"}
  450. // if (res.errMsg === 'chooseWXPay:ok') {
  451. // resolve({ errMsg: 'requestPayment:ok' });
  452. // } else {
  453. // reject(res);
  454. // }
  455. // },
  456. // cancel: function (res) {
  457. // // alert('cancel: ' + JSON.stringify(res));
  458. // // res: {"errMsg":"chooseWXPay:cancel"}
  459. // resolve({ errMsg: 'requestPayment:cancel' });
  460. // },
  461. // fail: function (err) {
  462. // // eslint-disable-next-line no-console
  463. // console.error(err);
  464. // reject(err);
  465. // },
  466. // });
  467. }
  468. },
  469. // H5 跳转到小程序
  470. launchFn({ appId, extInfo }) {
  471. // console.log(584, JSON.stringify({ appId, extInfo }));
  472. this.$store.commit('cachedViews/DEL_CACHED_VIEW', {
  473. name: 'parkingFeeDetail',
  474. });
  475. this.$router.go(-2);
  476. // console.log('H5 跳转到 嘉里中心小程序: success');
  477. },
  478. launchErrorFn({ errMsg, appId, extInfo }) {
  479. // console.log('H5 跳转到 嘉里中心小程序: fail', JSON.stringify({ errMsg, appId, extInfo }));
  480. },
  481. onLaunchReady() {
  482. // console.log('H5 跳转到 嘉里中心小程序 的标签 渲染了');
  483. },
  484. },
  485. };