parkingFeeCoupon.js 19 KB

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