recharge.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. <!-- 账号充值 -->
  2. <template>
  3. <view class="container">
  4. <view v-if="!rechargeSn" class="amount_part flex_column_start_start">
  5. <text class="title">{{$L('充值金额')}}</text>
  6. <view class="amount_view flex_row_start_start">
  7. <text :class="{num:true, flex_row_center_center:true,hasSelAmout:amount == item}" v-for="(item,index) in amountList"
  8. :key='index' @click="selAmount(item)">{{item}}{{$L('元')}}</text>
  9. <input :class="{num:true, flex_row_center_center:true, input_amount:true,hasSelAmout:!amount||input_amount}"
  10. :placeholder="$L('请输入金额')" v-model="input_amount" placeholder-class='input_placeholder' maxlength="5"
  11. @focus='selSetAmount' @blur='handleBlur' type="text"/>
  12. </view>
  13. </view>
  14. <view class="pay_part flex_column_start_start">
  15. <text class="title">{{$L('选择充值方式')}}</text>
  16. <view v-for="(item,index) in payMethod" :key='index' @click="selectPayMethod(item)" :class="{item:true, b_b:index<payMethod.length-1, flex_row_between_center:true}">
  17. <view class="left flex_row_start_center">
  18. <image class="pay_icon" :src="item.payIcon" />
  19. <text class="tit">{{item.payMethodName}}</text>
  20. </view>
  21. <text :class="{iconfont:true, iconziyuan33:selData.payMethod == item.payMethod,iconziyuan43:selData.payMethod != item.payMethod,has_sel:selData.payMethod == item.payMethod}"></text>
  22. </view>
  23. </view>
  24. <view v-show="showBtn" class="btn_recharge flex_row_center_center" @click="reCharge">{{$L('确认充值')}}</view>
  25. </view>
  26. </template>
  27. <script>
  28. import {
  29. mapState
  30. } from 'vuex';
  31. export default {
  32. data() {
  33. return {
  34. rechargeSn: '',
  35. selData: {},
  36. payMethod: [], //支付方式
  37. amount: 50,
  38. amountList: [50, 100, 200, 500, 1000],
  39. input_amount: '',
  40. balance: 0, //账户总金额
  41. client: 'wxbrowser', //支付发起来源 pc==pc,mbrowser==移动设备浏览器,app==app,wxxcx==微信小程序,wxbrowser==微信内部浏览器
  42. isAllowAutoPay: true, //当浏览器地址有code时,是否允许自动支付,如果支付失败的话置为false
  43. wxBrowerCode: '', //微信浏览器支付的code
  44. payMethodType: '', //支付发起来源,上个页面 rechargeBalance:用户充值 rechargeDetail:充值详情
  45. rechargeId: '', //从充值详情过来的,充值id
  46. showBtn: true, // 输入金额键盘弹出时隐藏确认按钮
  47. windowHeight: '', // 屏幕高度判断键盘弹出收起,
  48. isClick:true,
  49. }
  50. },
  51. computed: {
  52. ...mapState(['hasLogin', 'userInfo'])
  53. },
  54. onLoad(options) {
  55. if (options.rechargeSn) {
  56. this.rechargeSn = options.rechargeSn;
  57. }
  58. if (options.payMethodType) {
  59. this.payMethodType = options.payMethodType;
  60. }
  61. if (options.rechargeId) {
  62. this.rechargeId = options.rechargeId;
  63. }
  64. //#ifdef H5
  65. //判断code地址的参数 start
  66. let code = this.$getQueryVariable('code');
  67. if (code) {
  68. this.wxBrowerCode = code;
  69. if (options.type == 'sel') {
  70. this.amount = options.amount;
  71. } else if (options.type == 'input') {
  72. this.input_amount = options.amount;
  73. }
  74. }
  75. //判断code地址的参数 end
  76. //#endif
  77. this.initClient();
  78. this.balance = parseFloat(options.balance) || 0;
  79. this.getPayMethod();
  80. // 手机软键盘收起时显示确认按钮
  81. uni.getSystemInfo({
  82. success: (res) => {
  83. this.windowHeight = res.windowHeight;
  84. }
  85. });
  86. uni.onWindowResize((res) => {
  87. if (res.size.windowHeight < this.windowHeight) {
  88. this.showBtn = false;
  89. } else {
  90. this.showBtn = true
  91. }
  92. })
  93. },
  94. methods: {
  95. //初始化终端类型
  96. initClient() {
  97. //#ifdef APP-PLUS
  98. this.client = 'app';
  99. //#endif
  100. //#ifdef H5
  101. this.client = this.$isWeiXinBrower() ? 'wxbrowser' : 'mbrowser';
  102. //#endif
  103. //#ifdef MP-WEIXIN
  104. this.client = 'wxxcx';
  105. //#endif
  106. },
  107. //获取支付方式
  108. getPayMethod() {
  109. let {
  110. client,
  111. wxBrowerCode,
  112. isAllowAutoPay
  113. } = this;
  114. this.$request({
  115. url: 'v3/business/front/orderPay/payMethod',
  116. data: {
  117. source: client,
  118. type: 2, //支付发起类型 1==下单支付,2==余额充值/订单列表
  119. },
  120. }).then(res => {
  121. if (res.state == 200) {
  122. res.data.map(item => {
  123. item.payIcon = getApp().globalData.imgUrl + `pay/${item.payMethod}_pay_icon.png`;
  124. });
  125. this.payMethod = res.data;
  126. if (!wxBrowerCode) {
  127. this.selData = this.payMethod[0];
  128. } else {
  129. //有code的话要默认选中微信支付,并直接提交订单
  130. this.selData = this.payMethod.filter(item => item.payMethod == 'wx')[0];
  131. if (isAllowAutoPay) {
  132. this.reCharge();
  133. }
  134. }
  135. }
  136. }).catch((e) => {})
  137. },
  138. //选择支付方式事件
  139. selectPayMethod(val) {
  140. let that = this;
  141. that.selData = val;
  142. },
  143. //确认充值事件
  144. reCharge() {
  145. const {
  146. selData,
  147. rechargeSn,
  148. amount,
  149. input_amount,
  150. wxBrowerCode,
  151. client
  152. } = this;
  153. uni.showLoading()
  154. if(!this.isClick){
  155. return false
  156. }
  157. this.isClick = false
  158. let param = {};
  159. param.method = 'POST';
  160. param.data = {};
  161. param.data.key = this.userInfo.access_token;
  162. if (rechargeSn) {
  163. param.url = 'v3/member/front/balanceRecharge/rechargeContinue';
  164. param.data.rechargeSn = rechargeSn;
  165. } else {
  166. param.url = 'v3/member/front/balanceRecharge/recharge';
  167. param.data.amount = amount || input_amount;
  168. if (!param.data.amount) {
  169. this.$api.msg('请设置充值金额');
  170. return false
  171. }
  172. }
  173. param.data.payType = selData.payType;
  174. param.data.payMethod = selData.payMethod;
  175. if (client == 'wxxcx') {
  176. //微信小程序支付
  177. uni.login({
  178. success: code => {
  179. param.data.code = code.code;
  180. param.data.codeSource = 1; //用户code来源(JSAPI支付时必填):1==小程序,2==微信内部浏览器
  181. this.$request(param).then(res => {
  182. if (res.state == 200) {
  183. uni.hideLoading()
  184. let tmp_data = res.data.payData;
  185. if (res.data.actionType == null) {
  186. //微信小程序支付
  187. uni.requestPayment({
  188. 'timeStamp': tmp_data.timeStamp,
  189. 'nonceStr': tmp_data.nonceStr,
  190. 'package': tmp_data.packageValue,
  191. 'signType': 'MD5',
  192. 'paySign': tmp_data.paySign,
  193. success: function(res) {
  194. _this.payTip('success');
  195. },
  196. fail: function(res) {
  197. _this.payTip('fail');
  198. }
  199. });
  200. }
  201. } else {
  202. this.isClick = true
  203. _this.$api.msg(res.msg);
  204. }
  205. }).catch((e) => {})
  206. }
  207. });
  208. return false;
  209. } else if (client == 'wxbrowser') {
  210. //微信h5支付
  211. if (!wxBrowerCode) {
  212. let param = '';
  213. if (rechargeSn) {
  214. param = 'type=continue';
  215. } else {
  216. if (amount) {
  217. param = 'type=sel';
  218. }
  219. if (input_amount) {
  220. param = 'type=input';
  221. }
  222. param += '&amount=' + (amount || input_amount);
  223. }
  224. if (location.href.indexOf('?') > -1) {
  225. location.href += '&' + param;
  226. } else {
  227. location.href += '?' + param;
  228. }
  229. uni.hideLoading()
  230. let uricode = encodeURIComponent(location.href)
  231. window.location.href = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' + getApp().globalData.h5AppId +
  232. '&redirect_uri=' + uricode + '&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect';
  233. return false;
  234. } else {
  235. param.data.code = wxBrowerCode;
  236. param.data.codeSource = 2; //用户code来源(JSAPI支付时必填):1==小程序,2==微信内部浏览器
  237. }
  238. }
  239. this.$request(param).then(res => {
  240. if (res.state == 200) {
  241. uni.hideLoading()
  242. let tmp_data = res.data.payData;
  243. if (res.data.actionType == 'redirect') {
  244. window.location.href = tmp_data;
  245. } else if (res.data.actionType == null) {
  246. if (client == 'wxbrowser') {
  247. //微信h5支付
  248. this.$weiXinBrowerPay({
  249. timestamp: tmp_data.timeStamp,
  250. nonceStr: tmp_data.nonceStr,
  251. package: tmp_data.packageValue,
  252. signType: 'MD5',
  253. paySign: tmp_data.paySign,
  254. appId: tmp_data.appId, //此参数可不用
  255. success: function(r) {
  256. if (r.errMsg == "chooseWXPay:ok") {
  257. _this.payTip('success');
  258. } else {
  259. _this.payTip('fail');
  260. _this.isAllowAutoPay = false; //支付失败后禁止自动支付
  261. }
  262. },
  263. cancel: function(r) {
  264. _this.payTip('fail');
  265. _this.isAllowAutoPay = false; //支付失败后禁止自动支付
  266. _this.isClick = true
  267. }
  268. });
  269. } else if (client == 'wxxcx') {
  270. //微信小程序支付
  271. uni.requestPayment({
  272. 'timeStamp': tmp_data.timeStamp,
  273. 'nonceStr': tmp_data.nonceStr,
  274. 'package': tmp_data.packageValue,
  275. 'signType': 'MD5',
  276. 'paySign': tmp_data.paySign,
  277. 'success': function(res) {
  278. _this.payTip('success');
  279. },
  280. 'fail': function(res) {
  281. _this.payTip('fail');
  282. _this.isClick = true
  283. }
  284. });
  285. } else if (client == 'app') {
  286. //APP支付
  287. let provider = '';
  288. let orderInfo = {};
  289. if (selData.payMethod == 'wx') {
  290. provider = 'wxpay';
  291. orderInfo.appid = tmp_data.appId;
  292. orderInfo.noncestr = tmp_data.nonceStr;
  293. orderInfo.package = tmp_data.packageValue;
  294. orderInfo.partnerid = tmp_data.partnerId;
  295. orderInfo.prepayid = tmp_data.prepayId;
  296. orderInfo.timestamp = tmp_data.timeStamp;
  297. orderInfo.sign = tmp_data.sign;
  298. } else if (selData.payMethod == 'alipay') {
  299. provider = 'alipay';
  300. }
  301. uni.requestPayment({
  302. provider: provider,
  303. orderInfo: provider == 'alipay' ? res.data.payData : orderInfo, //订单数据
  304. success: function(res) {
  305. _this.payTip('success');
  306. },
  307. fail: function(err) {
  308. _this.payTip('fail');
  309. _this.isClick = true
  310. }
  311. });
  312. }
  313. } else if (res.data.actionType == 'autopost') {
  314. document.write(res.data.payData);
  315. }
  316. } else {
  317. _this.isClick = true
  318. this.$api.msg(res.msg);
  319. }
  320. }).catch((e) => {})
  321. },
  322. //支付操作完成提示
  323. payTip(type) {
  324. if (type == 'success') {
  325. //提示充值成功,如果来自账户充值页面,直接跳转充值明细列表页面,否则返回上一级页面(充值详情页面),并更新数据 rechargeBalance:用户充值 rechargeDetail:充值详情
  326. this.$api.msg('充值成功');
  327. if (this.payMethodType == 'rechargeBalance') {
  328. uni.navigateTo({
  329. url: '/pages/recharge/list'
  330. })
  331. } else if (this.payMethodType == 'rechargeDetail') {
  332. const pages = getCurrentPages(); //当前页面栈
  333. if (pages.length > 1) {
  334. const beforePage = pages[pages.length - 2]; //获取上一个页面实例对象
  335. beforePage.$vm.getDetail(); //触发上个面中的方法获取订单列表 *getDetail为上个页面的方法*
  336. beforePage.$vm.rechargeId = this.rechargeId; //更新上一页的充值id
  337. }
  338. setTimeout(() => {
  339. uni.navigateBack()
  340. }, 1000)
  341. }
  342. } else if (type == 'fail') {
  343. //提示充值失败 刷新界面
  344. this.$api.msg('充值失败,请重试~');
  345. this.getPayMethod();
  346. }
  347. },
  348. //选择充值金额
  349. selAmount(amount) {
  350. this.input_amount = '';
  351. this.amount = amount;
  352. },
  353. //设置金额聚焦事件
  354. selSetAmount() {
  355. this.amount = '';
  356. this.showBtn = false
  357. },
  358. //输入金额
  359. handleBlur(e) {
  360. this.showBtn = true
  361. let val = parseFloat(e.detail.value.toString());
  362. if (val > 5000) {
  363. this.$api.msg('一次最多充值5000元');
  364. this.input_amount = 5000;
  365. } else {
  366. if (this.balance + val > 999999.00) {
  367. this.$api.msg('当前账号余额已达最大值');
  368. }else if(val<=0){
  369. this.$api.msg('充值金额不能为负数或者为零');
  370. this.input_amount=''
  371. }else if(Number.isNaN(val)){
  372. this.input_amount=''
  373. } else {
  374. //小数点后最多后两位
  375. this.input_amount = val.toString().indexOf('.')==-1? val:val.toString().substring(0,val.toString().indexOf('.')+3);
  376. }
  377. }
  378. },
  379. }
  380. }
  381. </script>
  382. <style lang="scss">
  383. page {
  384. background: $bg-color-split;
  385. width: 750rpx;
  386. margin: 0 auto;
  387. }
  388. uni-page-body {
  389. display: flex;
  390. height: 100%;
  391. }
  392. .container {
  393. display: flex;
  394. flex-direction: column;
  395. flex: 1;
  396. .amount_part {
  397. margin-top: 20rpx;
  398. width: 750rpx;
  399. height: 400rpx;
  400. background: #fff;
  401. .title {
  402. color: $main-font-color;
  403. font-size: 32rpx;
  404. line-height: 36rpx;
  405. margin: 30rpx 0 10rpx 20rpx;
  406. }
  407. .amount_view {
  408. flex-wrap: wrap;
  409. .num {
  410. width: 223rpx;
  411. height: 129rpx;
  412. background: rgba(255, 255, 255, 1);
  413. box-shadow: 0px 0px 20rpx 0px rgba(153, 153, 153, 0.2);
  414. border-radius: 15rpx;
  415. color: $main-font-color;
  416. font-size: 36rpx;
  417. margin: 20rpx 0 0 20rpx;
  418. line-height: 129rpx;
  419. &.hasSelAmout {
  420. border: 1rpx solid $main-color;
  421. }
  422. }
  423. .input_placeholder {
  424. color: $main-third-color;
  425. font-size: 24rpx;
  426. text-align: center;
  427. }
  428. .input_amount {
  429. text-align: center;
  430. }
  431. }
  432. }
  433. .pay_part {
  434. margin-top: 20rpx;
  435. background: #fff;
  436. flex: 1;
  437. .title {
  438. color: $main-font-color;
  439. font-size: 32rpx;
  440. margin-top: 30rpx;
  441. margin-left: 20rpx;
  442. }
  443. .item {
  444. width: 100%;
  445. padding: 20rpx;
  446. position: relative;
  447. .left {
  448. .pay_icon {
  449. width: 80rpx;
  450. height: 80rpx;
  451. }
  452. .tit {
  453. color: $main-font-color;
  454. font-size: 28rpx;
  455. margin-left: 20rpx;
  456. }
  457. }
  458. .iconfont {
  459. color: $main-third-color;
  460. font-size: 32rpx;
  461. }
  462. .has_sel {
  463. color: $main-color;
  464. }
  465. &.b_b:after {
  466. left: 20rpx;
  467. }
  468. }
  469. }
  470. .btn_recharge {
  471. width: 670rpx;
  472. margin: 0 40rpx;
  473. height: 88rpx;
  474. background: linear-gradient(-90deg, rgba(252, 29, 28, 1) 0%, rgba(255, 122, 24, 1) 100%);
  475. box-shadow: 0px 3rpx 20rpx 0rpx rgba(252, 30, 28, 0.26);
  476. border-radius: 44rpx;
  477. color: #fff;
  478. font-size: 36rpx;
  479. position: fixed;
  480. left: 50%;
  481. transform: translateX(-375rpx);
  482. bottom: 40rpx;
  483. // top: calc(100vh - 88rpx);
  484. // top: 1200rpx;
  485. }
  486. }
  487. </style>