index.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. <template>
  2. <div class="charge-index">
  3. <div class="background">
  4. <div class="headline">
  5. <span class="text1">电子卡充值享优惠</span>
  6. <span class="text2">会员日充值更优惠</span>
  7. </div>
  8. </div>
  9. <div class="content">
  10. <div class="title">我的卡片 ({{ cardList.length }})</div>
  11. <div class="title"></div>
  12. <div
  13. v-for="item in cardList"
  14. :key="item.id"
  15. :class="[cardOilsTypeClass[item.cardOilsType]]"
  16. >
  17. <div class="title">
  18. {{
  19. cardOilsTypeText[item.cardOilsType]
  20. }}
  21. </div>
  22. <div class="text">
  23. 余额 <span>{{ item.amt.toFixed(2) }}</span
  24. >元
  25. </div>
  26. <button @click="goCharge(item)">充值</button>
  27. </div>
  28. </div>
  29. <van-popup v-model="mask" closeable position="bottom" class="mask" round>
  30. <div class="charge">
  31. <div class="title">充值</div>
  32. <div class="tip">会员日充值更优惠,详情请咨询站长</div>
  33. <div class="amount">
  34. <span>{{
  35. cardOilsTypeText[chargeItem.cardOilsType]
  36. }}</span>
  37. <input
  38. placeholder="输入充值金额"
  39. v-model="chargeAmount"
  40. type="number"
  41. step="0.01"
  42. min="0"
  43. onkeyup="this.value= this.value.match(/\d+(\.\d{0,2})?/) ? this.value.match(/\d+(\.\d{0,2})?/)[0] : ''"
  44. />
  45. <span>¥</span>
  46. </div>
  47. <div class="container">
  48. <div
  49. class="btn"
  50. v-for="item in discountList"
  51. :key="item.cardSettingDetailId"
  52. @click="selectDiscount(item.discountAmtStart)"
  53. >
  54. <span>¥</span>
  55. <span>{{ item.discountAmtStart }}</span>
  56. <span>满{{ item.discountAmtStart }}送{{ item.presentAmt }}{{item.settingRuleType=="1"?"元":"%"}}</span>
  57. </div>
  58. </div>
  59. </div>
  60. <van-button
  61. :class="[chargeAmount !== '' ? 'selected' : '']"
  62. :loading="payLoading"
  63. loading-text="支付中..."
  64. @click="charge"
  65. :disabled="chargeAmount === ''"
  66. >
  67. 确认充值
  68. </van-button>
  69. </van-popup>
  70. </div>
  71. </template>
  72. <script>
  73. import ProductList from "../../components/ProductList";
  74. import { mapState, mapGetters, mapActions } from "vuex";
  75. import wx from "weixin-js-sdk";
  76. import Vue from "vue";
  77. import { Toast, Button, Popup, NumberKeyboard } from "vant";
  78. Vue.use(Popup);
  79. Vue.use(Toast);
  80. Vue.use(Button);
  81. Vue.use(NumberKeyboard);
  82. export default {
  83. head() {
  84. return {
  85. title: "会员充值",
  86. };
  87. },
  88. data() {
  89. return {
  90. mask: false,
  91. cardList: [],
  92. chargeItem: {},
  93. chargeAmount: "",
  94. stationInfo: {},
  95. payLoading: false,
  96. show: false,
  97. discountList: [],
  98. cardOilsTypeClass:[,"gasoline", "diesel", 'notoil', 'lng', 'cng'],
  99. cardOilsTypeText:[,'汽油卡','柴油卡','非油品卡','LNG卡','CNG卡']
  100. };
  101. },
  102. components: {
  103. ProductList,
  104. },
  105. computed: {
  106. ...mapState({
  107. pointInfo: (state) => state.point.pointInfo,
  108. }),
  109. ...mapGetters({
  110. userInfo: "authen/userInfo",
  111. }),
  112. },
  113. created() {
  114. this.init();
  115. },
  116. methods: {
  117. // onInput(value) {
  118. // Toast(value);
  119. // },
  120. // onDelete() {
  121. // Toast("删除");
  122. // },
  123. ...mapActions({
  124. getSdkConfig: "authen/getSdkConfig",
  125. }),
  126. switchMask() {
  127. this.mask = !this.mask;
  128. },
  129. getDiscount() {
  130. this.discountList = [];
  131. // 拉取折扣
  132. this.$axios
  133. .$get("/getCardRechargeSettingList", {
  134. params: {
  135. stationId: this.stationId,
  136. cardOilsType: this.chargeItem.cardOilsType,
  137. },
  138. })
  139. .then((res) => {
  140. if (res.retCode === 0) {
  141. this.discountList = res.data[0].customerCardSettingDetailList;
  142. }
  143. });
  144. },
  145. goCharge(ele) {
  146. this.chargeItem = ele;
  147. this.getDiscount();
  148. this.switchMask();
  149. },
  150. charge() {
  151. this.chargeAmount = this.chargeAmount.toString().replace(/\.$/g, "");
  152. this.pay();
  153. },
  154. init() {
  155. // 获取卡片
  156. this.$axios
  157. .$get("/getElectronicCardList", {
  158. params: {
  159. unionId: this.unionId,
  160. stationId: this.stationId,
  161. },
  162. })
  163. .then((res) => {
  164. if (res.retCode === 0) {
  165. this.cardList = res.data;
  166. console.log(this.cardList)
  167. }
  168. });
  169. // this.cardList = [{"id":105,"unionId":"o65PX6a8gYoXrRtsay4nid7vaN-k","customerNo":"11622424586654","customerName":"Joe","amt":55455.83,"cardOilsType":"1","stationId":1,"createTime":"Jun 3, 2021 10:29:58 AM","recentlyTime":"Jun 2, 2021 5:22:26 PM"},{"id":106,"unionId":"o65PX6a8gYoXrRtsay4nid7vaN-k","customerNo":"11619582798963","customerName":"Joe","amt":10005.06,"cardOilsType":"2","stationId":1,"createTime":"Jun 3, 2021 10:29:58 AM","recentlyTime":"Jun 2, 2021 5:22:39 PM"},{"id":115,"unionId":"o65PX6a8gYoXrRtsay4nid7vaN-k","customerNo":"11622424586607","customerName":"Joe","amt":55555,"cardOilsType":"3","stationId":1,"createTime":"Jun 3, 2021 10:29:58 AM"},{"id":116,"unionId":"o65PX6a8gYoXrRtsay4nid7vaN-k","customerNo":"11622424586654","customerName":"Joe","amt":55555,"cardOilsType":"4","stationId":1,"createTime":"Jun 3, 2021 10:29:58 AM"},{"id":119,"unionId":"o65PX6a8gYoXrRtsay4nid7vaN-k","customerNo":"11622538683941","customerName":"Joe","amt":0,"cardOilsType":"5","stationId":1,"createTime":"Jun 3, 2021 10:29:58 AM"}]
  170. // 这一块纯为了后端方便而已,获取station的信息
  171. this.$axios
  172. .$get("/getStationInfo", {
  173. params: {
  174. stationId: this.stationId,
  175. },
  176. })
  177. .then((res) => {
  178. this.stationInfo = res.data;
  179. });
  180. },
  181. async pay() {
  182. try {
  183. this.payLoading = true;
  184. const orderData = await this.$axios.$post("/rechargeBalance", {
  185. amt: this.chargeAmount,
  186. stationId: this.stationId,
  187. customerName: this.userInfo.nickname,
  188. cardOilsType: this.chargeItem.cardOilsType,
  189. unionId: this.unionId,
  190. });
  191. if (orderData.retCode !== 0) {
  192. throw new Error("生成订单失败");
  193. }
  194. const orderNum = orderData.data;
  195. const payInfoData = await this.$axios.$post("/rechargeBalanceSXFPay", {
  196. amt: this.chargeAmount,
  197. openId: this.openId,
  198. stationId: this.stationId,
  199. userType: "1",
  200. orderNo: orderNum,
  201. });
  202. if (payInfoData.retCode !== 0) {
  203. throw new Error("支付参数拉取失败");
  204. }
  205. if (payInfoData.data.code !== "0000") {
  206. throw new Error(payInfoData.data.msg);
  207. }
  208. if (payInfoData.data.code !== "0000") {
  209. throw new Error(payInfoData.data.msg);
  210. }
  211. if (payInfoData.data.respData.bizCode !== "0000") {
  212. throw new Error(payInfoData.data.respData.bizMsg);
  213. }
  214. const timestamp = payInfoData.data.respData.payTimeStamp;
  215. const nonceStr = payInfoData.data.respData.paynonceStr;
  216. const packageOrg = payInfoData.data.respData.payPackage;
  217. const signType = payInfoData.data.respData.paySignType;
  218. const paySign = payInfoData.data.respData.paySign;
  219. const that = this;
  220. // 拉取微信支付
  221. this.getSdkConfig(["chooseWXPay"]).then((res) => {
  222. wx.config(res);
  223. wx.ready(function (res) {
  224. wx.chooseWXPay({
  225. timestamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
  226. nonceStr, // 支付签名随机串,不长于 32 位
  227. package: packageOrg, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
  228. signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
  229. paySign, // 支付签名
  230. success: function (res) {
  231. that.payLoading = false;
  232. alert("支付完成");
  233. },
  234. cancel: function (err) {
  235. that.payLoading = false;
  236. alert("您取消了付款");
  237. },
  238. fail: function (err) {
  239. that.payLoading = false;
  240. alert(err);
  241. },
  242. });
  243. });
  244. wx.error(function (res) {
  245. alert("拉取微信Sdk配置出错");
  246. });
  247. });
  248. } catch (err) {
  249. this.payLoading = false;
  250. alert(err);
  251. }
  252. },
  253. selectDiscount(discount) {
  254. this.chargeAmount = discount;
  255. },
  256. },
  257. };
  258. </script>
  259. <style>
  260. .charge-index {
  261. position: relative;
  262. height: 100vh;
  263. }
  264. .charge-index .background {
  265. background-color: #f3b335;
  266. width: 7.5rem;
  267. height: 7.5rem;
  268. position: relative;
  269. background: url("~static/personal/23@2x.png") no-repeat 0px 0px;
  270. background-size: 100% 100%;
  271. z-index: -1;
  272. overflow: hidden;
  273. }
  274. .charge-index .background .headline {
  275. width: 6.9rem;
  276. height: 4.33rem;
  277. background: url("~static/personal/bj2@2x.png") no-repeat 0px 0px;
  278. background-size: 100% 100%;
  279. margin: 0.3rem auto;
  280. display: relative;
  281. }
  282. .charge-index .background .headline .text1 {
  283. position: absolute;
  284. left: 0.8rem;
  285. top: 1.6rem;
  286. color: #8e9aae;
  287. font-size: 0.3rem;
  288. font-weight: 600;
  289. }
  290. .charge-index .background .headline .text2 {
  291. position: absolute;
  292. left: 0.8rem;
  293. top: 2.2rem;
  294. color: #8e9aae;
  295. font-size: 0.3rem;
  296. font-weight: 600;
  297. }
  298. .charge-index .content {
  299. position: absolute;
  300. top: 3.78rem;
  301. bottom: 0rem;
  302. left: 0rem;
  303. right: 0rem;
  304. background-color: #ffffff;
  305. border-radius: 0.3rem 0.3rem 0 0;
  306. padding: 0.3rem;
  307. overflow: scroll;
  308. }
  309. .charge-index .content > div:not(.title) {
  310. width: 6.9rem;
  311. height: 1.6rem;
  312. margin-top: 0.3rem;
  313. position: relative;
  314. }
  315. .charge-index .content .title {
  316. font-size: 0.35rem;
  317. color: #333333;
  318. font-weight: 600;
  319. }
  320. .charge-index .content .gasoline {
  321. background: url("~static/personal/bj3@2x.png") no-repeat 0px 0px;
  322. background-size: 100% 100%;
  323. }
  324. .charge-index .content .diesel {
  325. background: url("~static/personal/bj4@2x.png") no-repeat 0px 0px;
  326. background-size: 100% 100%;
  327. }
  328. .charge-index .content .notoil {
  329. background: url("~static/personal/bj5.2x.png") no-repeat 0px 0px;
  330. background-size: 100% 100%;
  331. }
  332. .charge-index .content .lng {
  333. background: url("~static/personal/bj6.2x.png") no-repeat 0px 0px;
  334. background-size: 100% 100%;
  335. }
  336. .charge-index .content .cng {
  337. background: url("~static/personal/bj7.2x.png") no-repeat 0px 0px;
  338. background-size: 100% 100%;
  339. }
  340. .charge-index .content div .title {
  341. height: 0.45rem;
  342. font-size: 0.32rem;
  343. font-family: PingFangSC-Medium, PingFang SC;
  344. font-weight: 500;
  345. color: #ffffff;
  346. line-height: 0.45rem;
  347. position: absolute;
  348. top: 0.27rem;
  349. left: 1.67rem;
  350. }
  351. .charge-index .content div .text{
  352. height: 0.45rem;
  353. font-size: 0.32rem;
  354. font-weight: 500;
  355. line-height: 0.45rem;
  356. position: absolute;
  357. top: 0.9rem;
  358. left: 1.67rem;
  359. }
  360. .charge-index .content .gasoline .text {
  361. color: #3db58f;
  362. }
  363. .charge-index .content .diesel .text {
  364. color: #ea8c7d;
  365. }
  366. .charge-index .content .notoil .text {
  367. color: #898d92;
  368. }
  369. .charge-index .content .lng .text {
  370. color: #dab899;
  371. }
  372. .charge-index .content .cng .text {
  373. color: #6977b1;
  374. }
  375. .charge-index .content div .text span {
  376. color: #fff;
  377. }
  378. .charge-index .content div button {
  379. border: none;
  380. background-color: transparent;
  381. outline: none;
  382. display: block;
  383. width: 1.4rem;
  384. height: 0.6rem;
  385. background: #ffffff;
  386. border-radius: 0.3rem;
  387. position: absolute;
  388. top: 0.5rem;
  389. right: 0.3rem;
  390. }
  391. .charge-index .content .gasoline button {
  392. color: #24ac81;
  393. }
  394. .charge-index .content .diesel button {
  395. color: #e87d6d;
  396. }
  397. .charge-index .content .notoil button {
  398. color: #6d7278;
  399. }
  400. .charge-index .content .lng button {
  401. color: #d2a781;
  402. }
  403. .charge-index .content .cng button {
  404. color: #45579e;
  405. }
  406. .charge-index .mask .charge {
  407. height: 7.5rem;
  408. background: #f2f2f2;
  409. border-radius: 0.42rem 0.42rem 0rem 0rem;
  410. box-sizing: border-box;
  411. padding: 0.3rem 0;
  412. display: flex;
  413. flex-direction: column;
  414. align-items: center;
  415. }
  416. .charge-index .mask .charge > div:not(:nth-child(1)):not(.container) {
  417. margin-top: 0.2rem;
  418. }
  419. .charge-index .mask .charge .title {
  420. width: 6.5rem;
  421. height: 0.45rem;
  422. font-size: 0.32rem;
  423. font-family: PingFangSC-Regular, PingFang SC;
  424. font-weight: 400;
  425. color: #111111;
  426. line-height: 0.45rem;
  427. text-align: center;
  428. }
  429. .charge-index .mask .charge .title .close {
  430. background: url("~static/personal/6_d05_close@2x.png") no-repeat 0px 0px;
  431. background-size: 100% 100%;
  432. width: 0.4rem;
  433. height: 0.4rem;
  434. float: right;
  435. }
  436. .charge-index .mask .charge .tip {
  437. height: 0.33rem;
  438. font-size: 0.24rem;
  439. font-family: PingFangSC-Regular, PingFang SC;
  440. font-weight: 400;
  441. color: #aaaaaa;
  442. line-height: 0.33rem;
  443. }
  444. .charge-index .mask .charge .amount {
  445. width: 6.9rem;
  446. height: 1.2rem;
  447. background: url("~static/personal/biankuang@2x.png") no-repeat 0px 0px;
  448. background-size: 100% 100%;
  449. position: relative;
  450. }
  451. .charge-index .mask .charge .amount span:nth-child(1) {
  452. height: 0.4rem;
  453. font-size: 0.28rem;
  454. font-weight: 600;
  455. color: #884e16;
  456. line-height: 0.4rem;
  457. position: absolute;
  458. top: 0.4rem;
  459. left: 0.51rem;
  460. }
  461. .charge-index .mask .charge .amount input {
  462. background: none;
  463. outline: none;
  464. border: none;
  465. height: 0.4rem;
  466. font-size: 0.28rem;
  467. font-family: PingFangSC-Regular, PingFang SC;
  468. font-weight: 400;
  469. color: #111111;
  470. line-height: 0.4rem;
  471. position: absolute;
  472. top: 0.4rem;
  473. left: 2.54rem;
  474. }
  475. .charge-index .mask .charge .amount span:nth-last-child(1) {
  476. height: 0.4rem;
  477. font-size: 0.28rem;
  478. font-family: PingFangSC-Regular, PingFang SC;
  479. font-weight: 400;
  480. color: #aaaaaa;
  481. line-height: 0.4rem;
  482. position: absolute;
  483. top: 0.4rem;
  484. right: 0.4rem;
  485. }
  486. .charge-index .mask button {
  487. border: none;
  488. outline: none;
  489. bottom: 0.7rem;
  490. position: absolute;
  491. width: 6.9rem;
  492. height: 0.8rem;
  493. left: 0.3rem;
  494. background: #cccccc;
  495. border-radius: 0.45rem;
  496. font-size: 0.32rem;
  497. font-family: PingFangSC-Regular, PingFang SC;
  498. font-weight: 400;
  499. color: #ffffff;
  500. line-height: 0.45rem;
  501. }
  502. .charge-index .mask > button.selected {
  503. background-color: #0ea374;
  504. }
  505. .charge-index .mask .container {
  506. margin-top: 0.4rem;
  507. display: flex;
  508. flex-wrap: wrap;
  509. padding: 0.3rem 0.3rem;
  510. justify-content: space-between;
  511. overflow: scroll;
  512. height: 2rem;
  513. }
  514. .charge-index .mask .container .btn {
  515. display: inline-block;
  516. width: 3.3rem;
  517. height: 0.84rem;
  518. background: #ffffff;
  519. box-shadow: 0 0.04rem 0.08rem 0 #f2f2f2;
  520. border-radius: 0.42rem;
  521. margin-bottom: 0.35rem;
  522. position: relative;
  523. box-sizing: border-box;
  524. padding: 0 0.26rem;
  525. text-align: center;
  526. }
  527. .charge-index .mask .container .btn:nth-child(odd) {
  528. margin-right: 0.3rem;
  529. }
  530. .charge-index .mask .container .btn span {
  531. font-size: 0.35rem;
  532. font-family: PingFangSC-Regular, PingFang SC;
  533. color: #895017;
  534. line-height: 0.84rem;
  535. }
  536. .charge-index .mask .container .btn span:nth-child(1) {
  537. border-radius: 0.42rem;
  538. font-size: 0.2rem;
  539. float: left;
  540. }
  541. .charge-index .mask .container .btn span:nth-child(2) {
  542. float: left;
  543. font-weight: 600;
  544. }
  545. .charge-index .mask .container .btn span:nth-child(3) {
  546. font-size: 0.2rem;
  547. font-weight: 400;
  548. color: rgba(0, 0, 0, 0.29);
  549. float: right;
  550. }
  551. </style>