pay.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. <template>
  2. <view class="container">
  3. <image class="banner" src="@/static/images/mine/back.png" mode="aspectFill" />
  4. <view class="title" :style="{ top: `${paddingTop * 2}rpx` }">
  5. <view class="title_back" @click="handleBack">
  6. <wd-icon name="thin-arrow-left" color="#001713" size="18"></wd-icon>
  7. </view>
  8. 电子交通卡充值
  9. </view>
  10. <!-- 内容区域 -->
  11. <scroll-view class="body" scroll-y @scrolltolower="scrolltolower">
  12. <view class="body_title">选择充值面额</view>
  13. <!-- 每一个充值选项区域 -->
  14. <view class="body_item" :class="{ active: item.isChecked }" v-for="(item, index) in chongList" :key="index" @click="hadnleChange(item)">
  15. <view class="item_price">
  16. ¥
  17. <text class="text">{{item.account3}}</text>
  18. </view>
  19. <!-- <view class="item_msg">赠送{{item.account4}}元补贴包,立得{{item.account3+item.account4}}元出行金</view> -->
  20. <view class="item_check" v-if="item.isChecked" @click="item.isChecked!=item.isChecked">
  21. <wd-icon name="check-bold" color="#fff" size="20"></wd-icon>
  22. </view>
  23. </view>
  24. </scroll-view>
  25. <!-- 底部支付区域 -->
  26. <view class="foot">
  27. <view class="foot_left">
  28. <view class="left_top">
  29. 合计
  30. <text class="text">¥{{totalAmount}}</text>
  31. </view>
  32. <!-- <view class="left_bottom">
  33. 充值成功后赠送补贴金
  34. <text class="text">¥{{zengAmount}}</text>
  35. </view> -->
  36. </view>
  37. <view class="foot_right" @click="handlePay">点击支付</view>
  38. </view>
  39. </view>
  40. <!-- 选择付款方式弹窗区域 -->
  41. <wd-popup v-model="popShow_pay" position="bottom" safe-area-inset-bottom :close-on-click-modal="false">
  42. <view class="pop_pay">
  43. <view class="pay_title">选择付款方式</view>
  44. <view class="pay_close" @click="handleClose">
  45. <wd-icon name="close-bold" color="#ABA6A6" size="22"></wd-icon>
  46. </view>
  47. <!-- 支付方式列表区域 -->
  48. <view class="pay_list">
  49. <!-- 每一个支付方式区域 -->
  50. <view class="list_item" v-for="(item, index) in payList" :key="index">
  51. <view class="item_left">
  52. <image class="img" :src="item.icon" mode="aspectFill"></image>
  53. {{ item.text }}
  54. </view>
  55. <view class="item_right">
  56. <radio style="scale: 0.8" color="#FF8205" :checked="item.isCheck" @click="togglePay(item)" />
  57. </view>
  58. </view>
  59. </view>
  60. <!-- 立即付款按钮区域 -->
  61. <view class="pay_btn" @click="payTime">立即付款</view>
  62. </view>
  63. </wd-popup>
  64. </template>
  65. <script setup>
  66. import { onMounted, ref } from 'vue'
  67. import { myRequest } from '@/utils/api.ts'
  68. const userInfo = uni.getStorageSync('carUserInfo')
  69. // 胶囊按钮距离页面顶部的距离
  70. const paddingTop = ref(0)
  71. // 当前选择的索引
  72. const currentIndex = ref(0)
  73. // 付款方式弹窗显示隐藏控制
  74. const popShow_pay = ref(false)
  75. //充值套餐
  76. const chongList = ref([])
  77. // 每页多少条
  78. const pageSize = ref(10)
  79. // 当前页
  80. const currentPage = ref(1)
  81. // 总条数
  82. const total = ref(0)
  83. //合计支付金额
  84. const totalAmount = ref(0)
  85. //合计赠送金额
  86. const zengAmount = ref(0)
  87. // 支付方式列表
  88. const payList = ref([
  89. {
  90. text: '微信支付',
  91. icon: '/static/images/pay/wx.png',
  92. isCheck: true
  93. },
  94. // {
  95. // text: '电子交通卡支付',
  96. // icon: '/static/images/pay/card.png',
  97. // isCheck: false
  98. // }
  99. ])
  100. // 存储支付参数
  101. const payParams = ref({
  102. timeStamp: '',
  103. nonceStr: '',
  104. signType: '',
  105. paySign: '',
  106. appId:'',
  107. // prepay_id:'',
  108. package:'',
  109. });
  110. // 选中的支付方式
  111. const selectedPay = ref(null);
  112. onMounted(() => {
  113. paddingTop.value = uni.getMenuButtonBoundingClientRect().top
  114. getChongcommon()
  115. })
  116. // 点击切换选项的回调
  117. const hadnleChange = (item) => {
  118. chongList.value.forEach(item => {
  119. item.isChecked = false;
  120. });
  121. item.isChecked = true;
  122. totalAmount.value=item.account3
  123. zengAmount.value=item.account4
  124. }
  125. //交通卡充值
  126. const jiaotong = async () => {
  127. const res = await myRequest({
  128. url: '/cardrecharge.action',
  129. method: 'POST', // 明确指定请求方法为POST
  130. data: {
  131. mobile: userInfo.mobile,
  132. type: 1,
  133. account4: totalAmount.value,
  134. account5: zengAmount.value,
  135. }
  136. })
  137. if(res.code==200){
  138. payParams.value = {
  139. timeStamp: res.data.timeStamp,
  140. nonceStr: res.data.nonceStr,
  141. package: 'prepay_id=' + res.data.prepay_id,
  142. signType: res.data.signType,
  143. paySign: res.data.paySign,
  144. };
  145. invokeWechatPay(); // 调起支付
  146. }
  147. }
  148. // 调起微信支付
  149. const invokeWechatPay = () => {
  150. console.log(payParams.value,'支付')
  151. uni.requestPayment({
  152. ...payParams.value,
  153. success: (res) => {
  154. uni.showToast({ title: '支付成功' });
  155. popShow_pay.value = false
  156. setTimeout(function() {
  157. uni.navigateTo({
  158. url:'/pages/transportation/transportation'
  159. })
  160. }, 1000)
  161. // 支付成功后逻辑(如跳转到订单详情)
  162. },
  163. fail: (err) => {
  164. uni.showToast({ title: '支付失败', icon: 'none' });
  165. console.error('支付失败', err);
  166. }
  167. });
  168. };
  169. // 获取套餐列表数据
  170. const getChongcommon = async () => {
  171. let data = {
  172. page: currentPage.value,
  173. rows: pageSize.value,
  174. }
  175. try {
  176. const res = await myRequest({
  177. url: '/reBenefitlist.action',
  178. data
  179. });
  180. if (res.code === 200) {
  181. // 对返回的每一条数据添加 isCheck: false
  182. const formattedRows = res.rows.map(item => ({
  183. ...item, // 保留原有数据
  184. isCheck: false // 新增 isCheck 参数,默认 false
  185. }));
  186. // 🔴 同步已勾选状态:对比 selectedPassengers,标记匹配项的 isCheck 为 true
  187. // formattedRows.forEach(row => {
  188. // const isSelected = selectedPassengers.value.some(p => p.id === row.id);
  189. // if (isSelected) {
  190. // row.isCheck = true;
  191. // }
  192. // });
  193. if (currentPage.value === 1) {
  194. chongList.value = formattedRows;
  195. } else {
  196. chongList.value.push(...formattedRows);
  197. }
  198. total.value = res.total
  199. } else {
  200. // 接口返回非200状态时的提示(可选)
  201. uni.showToast({ title: '数据获取失败', icon: 'none' });
  202. }
  203. } catch (err) {
  204. console.error('请求异常', err);
  205. uni.showToast({ title: '网络异常', icon: 'none' });
  206. } finally {
  207. }
  208. }
  209. // 页面下滑到底部触发的回调
  210. const scrolltolower = () => {
  211. if (chongList.value.length < total.value) {
  212. currentPage.value++
  213. getChongcommon()
  214. } else {
  215. uni.showToast({
  216. title: '没有更多数据了',
  217. icon: 'none'
  218. })
  219. }
  220. }
  221. // 点击支付按钮回调
  222. const handlePay = () => {
  223. popShow_pay.value = true
  224. }
  225. // 点击弹窗关闭按钮回调
  226. const handleClose = () => {
  227. popShow_pay.value = false
  228. }
  229. // 顶部返回图标回调
  230. const handleBack = () => {
  231. uni.navigateBack()
  232. }
  233. // 切换支付方式(单选逻辑)
  234. const togglePay = (item) => {
  235. // console.log(1232228)
  236. // // 先重置所有支付方式为未选中
  237. // payList.value.forEach(pay => {
  238. // pay.isCheck = false;
  239. // });
  240. // // 标记当前点击的支付方式为选中
  241. // item.isCheck = true;
  242. selectedPay.value = true; // 同步选中的支付方式
  243. };
  244. //立即支付
  245. const payTime = () => {
  246. console.log(123222)
  247. // if (!selectedPay.value) {
  248. // uni.showModal({
  249. // content:'请选择支付方式'
  250. // })
  251. // return;
  252. // }
  253. jiaotong()
  254. }
  255. </script>
  256. <style lang="scss" scoped>
  257. .container {
  258. position: relative;
  259. height: 100vh;
  260. color: #001713;
  261. background-color: #fff;
  262. overflow: hidden;
  263. .banner {
  264. width: 100%;
  265. height: 482rpx;
  266. }
  267. .title {
  268. position: absolute;
  269. display: flex;
  270. align-items: center;
  271. width: 100vh;
  272. font-size: 40rpx;
  273. .title_back {
  274. margin-left: 26rpx;
  275. margin-right: 192rpx;
  276. }
  277. }
  278. .body {
  279. position: absolute;
  280. top: 160rpx;
  281. box-sizing: border-box;
  282. padding: 0 30rpx 30rpx;
  283. width: 100%;
  284. height: calc(100vh - 406rpx);
  285. font-size: 32rpx;
  286. color: #001713;
  287. .body_title {
  288. margin-bottom: 30rpx;
  289. }
  290. .body_item {
  291. position: relative;
  292. box-sizing: border-box;
  293. padding: 30rpx;
  294. margin-bottom: 40rpx;
  295. border: 2rpx solid #aba6a6;
  296. border-radius: 16rpx;
  297. background-color: #fff;
  298. .item_price {
  299. font-size: 28rpx;
  300. .text {
  301. font-size: 40rpx;
  302. }
  303. }
  304. .item_msg {
  305. margin-top: 20rpx;
  306. }
  307. .item_check {
  308. position: absolute;
  309. top: 0;
  310. right: 0;
  311. display: flex;
  312. align-items: center;
  313. justify-content: center;
  314. width: 60rpx;
  315. height: 44rpx;
  316. border-radius: 0 14rpx 0 16rpx;
  317. background-color: #ff8205;
  318. }
  319. }
  320. .active {
  321. background-color: #fff6ee;
  322. border: 2rpx solid #ff8205;
  323. }
  324. }
  325. .foot {
  326. position: absolute;
  327. left: 0;
  328. right: 0;
  329. bottom: 0;
  330. box-sizing: border-box;
  331. padding: 0 30rpx 30rpx;
  332. display: flex;
  333. align-items: center;
  334. justify-content: space-between;
  335. height: 244rpx;
  336. box-shadow: 0px 3px 6px #000000;
  337. .foot_left {
  338. .left_top {
  339. font-size: 32rpx;
  340. .text {
  341. font-size: 48rpx;
  342. color: #dc2626;
  343. }
  344. }
  345. .left_bottom {
  346. margin-top: 10rpx;
  347. font-size: 24rpx;
  348. .text {
  349. color: #dc2626;
  350. }
  351. }
  352. }
  353. .foot_right {
  354. display: flex;
  355. align-items: center;
  356. justify-content: center;
  357. width: 272rpx;
  358. height: 94rpx;
  359. color: #fff;
  360. font-size: 36rpx;
  361. border-radius: 50rpx;
  362. background-color: #ff8205;
  363. }
  364. }
  365. }
  366. .pop_pay {
  367. height: 566rpx;
  368. color: #001713;
  369. font-size: 28rpx;
  370. .pay_title {
  371. display: flex;
  372. align-items: center;
  373. justify-content: center;
  374. height: 80rpx;
  375. font-size: 32rpx;
  376. border-bottom: 18rpx solid #ff8205;
  377. }
  378. .pay_close {
  379. position: absolute;
  380. top: 24rpx;
  381. right: 42rpx;
  382. }
  383. .pay_list {
  384. box-sizing: border-box;
  385. padding: 55rpx 0;
  386. display: flex;
  387. flex-direction: column;
  388. justify-content: space-between;
  389. height: 265rpx;
  390. .list_item {
  391. display: flex;
  392. align-items: center;
  393. justify-content: space-between;
  394. box-sizing: border-box;
  395. padding: 0 32rpx 0 46rpx;
  396. .item_left {
  397. display: flex;
  398. align-items: center;
  399. .img {
  400. margin-right: 26rpx;
  401. width: 54rpx;
  402. height: 54rpx;
  403. }
  404. }
  405. .item_right {
  406. }
  407. }
  408. }
  409. .pay_btn {
  410. display: flex;
  411. align-items: center;
  412. justify-content: center;
  413. margin: auto;
  414. width: 720rpx;
  415. height: 94rpx;
  416. font-size: 36rpx;
  417. color: #fff;
  418. border-radius: 50rpx;
  419. background-color: #ff8205;
  420. }
  421. }
  422. </style>