index.vue 12 KB

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