Recharge.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  1. <template>
  2. <div class="recharge-page">
  3. <!-- 顶部标题 -->
  4. <div class="page-header">
  5. <div class="header-content">
  6. <div class="logo-wrapper">
  7. <div class="logo-container">
  8. <img src="@/assets/images/logo.png" alt="告白语音" class="logo-image" />
  9. </div>
  10. </div>
  11. </div>
  12. </div>
  13. <!-- 用户信息 -->
  14. <div class="user-info-section">
  15. <div class="user-info-card">
  16. <div class="user-avatar">
  17. <img v-if="userInfo.avatar" :src="userInfo.avatar" class="avatar" />
  18. <div v-else class="avatar-placeholder">
  19. <van-icon name="user-o" size="28" />
  20. </div>
  21. <!--<div class="switch-btn" @click="switchUser">
  22. </div>-->
  23. </div>
  24. <div class="user-details">
  25. <div class="user-name">{{ userInfo.nickname || '未知用户' }}</div>
  26. <div class="user-id">
  27. <img src="@/assets/images/id.png" alt="ID" class="id-icon" />
  28. <span>{{ userInfo.id || '未知ID' }}</span>
  29. </div>
  30. </div>
  31. <div class="switch-account-btn" @click="switchUser">
  32. 切换账号
  33. </div>
  34. </div>
  35. </div>
  36. <!-- 充值金额选择 -->
  37. <div class="recharge-section">
  38. <h2 class="section-title">充值金额</h2>
  39. <div class="recharge-grid">
  40. <div
  41. v-for="(item, index) in rechargeOptions"
  42. :key="index"
  43. class="recharge-item"
  44. :class="{ active: selectedRecharge === index }"
  45. @click="selectRecharge(index)"
  46. >
  47. <div class="diamond-icon">
  48. <img src="@/assets/images/recharge_zuanshi.png" alt="钻石" class="diamond-img" />
  49. </div>
  50. <div class="recharge-amount">{{ item.amount }}</div>
  51. <div class="recharge-price">¥{{ item.price }}</div>
  52. </div>
  53. </div>
  54. </div>
  55. <!-- 支付方式 -->
  56. <div class="payment-section">
  57. <div class="payment-option">
  58. <div class="payment-icon">
  59. <img src="@/assets/images/recharge_paypal.png" alt="支付宝支付" class="alipay-icon" />
  60. </div>
  61. <div class="payment-name">支付宝支付</div>
  62. <div class="payment-selected">
  63. <img src="@/assets/images/duihao.png" alt="选中" class="check-icon" />
  64. </div>
  65. </div>
  66. </div>
  67. <!-- 温馨提示 -->
  68. <div class="tips-section">
  69. <div class="tips-title">温馨提示:</div>
  70. <div class="tips-content">
  71. <div class="tip-item">1. 充值前请确定您已满18周岁并具有完全民事行为能力。</div>
  72. <div class="tip-item">2. 安全账号转账、理赔转账、刷单、代充均为骗局,请认真核实并确认</div>
  73. <div class="tip-item">3. 大额充值,支付方式可选择"零钱通"</div>
  74. <div class="tip-item">4. 如有疑问,请联系服务号客服</div>
  75. </div>
  76. <!-- 协议勾选 -->
  77. <div class="agreement-checkbox" @click="toggleAgreement">
  78. <div class="checkbox-wrapper" :class="{ checked: agreementChecked }">
  79. <van-icon v-if="agreementChecked" name="success" size="14" color="#fff" />
  80. </div>
  81. <div class="agreement-text">
  82. 我已阅读并同意 <span class="agreement-link" @click.stop="showAgreement">《用户充值协议》</span>
  83. </div>
  84. </div>
  85. </div>
  86. <!-- 支付按钮 -->
  87. <div class="pay-button">
  88. <van-button type="primary" block round @click="confirmPay">确认支付</van-button>
  89. </div>
  90. <!-- 协议弹框 -->
  91. <van-dialog
  92. v-model="agreementVisible"
  93. title="用户充值协议"
  94. confirm-button-text="我已阅读"
  95. @confirm="agreementChecked = true"
  96. :show-cancel-button="false"
  97. >
  98. <div class="agreement-content">
  99. <iframe v-if="agreementVisible" src="https://gbyy91.com/agreement/recharge.html" frameborder="0" class="agreement-iframe"></iframe>
  100. </div>
  101. </van-dialog>
  102. </div>
  103. </template>
  104. <script>
  105. // eslint-disable-next-line no-undef
  106. import { getProductList } from '@/api/product'
  107. import { getUserInfo } from '@/api/user'
  108. import { aliPayCoin, aliPayH5 } from '@/api/pay'
  109. import { getDevicePayWayId, getPlatformType } from '@/utils/config'
  110. export default {
  111. name: 'RechargePage',
  112. data() {
  113. return {
  114. resultDataMess: {},
  115. userInfo: {
  116. id: '',
  117. nickname: '',
  118. avatar: ''
  119. },
  120. rechargeOptions: [],
  121. selectedRecharge: 0,
  122. paymentMethod: 'alipay',
  123. isLoading: false,
  124. agreementChecked: false,
  125. agreementVisible: false
  126. }
  127. },
  128. computed: {
  129. selectedRechargeOption() {
  130. return this.rechargeOptions[this.selectedRecharge] || null
  131. }
  132. },
  133. created() {
  134. // 获取用户信息
  135. this.initUserInfo()
  136. // 获取产品列表
  137. this.fetchProductList()
  138. },
  139. methods: {
  140. // 初始化用户信息
  141. async initUserInfo() {
  142. // 从路由参数获取用户信息
  143. const { id, nickname, avatar } = this.$route.query
  144. if (id) {
  145. // 如果路由参数中有用户ID,直接使用
  146. this.userInfo.id = id
  147. this.userInfo.nickname = nickname || '未知用户'
  148. this.userInfo.avatar = avatar || ''
  149. } else {
  150. // 如果没有用户ID,尝试从本地存储获取
  151. const savedUserId = localStorage.getItem('lastUserId')
  152. if (savedUserId) {
  153. try {
  154. // 从API获取用户信息
  155. const res = await getUserInfo(savedUserId)
  156. if (res.data && res.data.userId) {
  157. this.userInfo.id = res.data.userId
  158. this.userInfo.nickname = res.data.userName || '未知用户'
  159. this.userInfo.avatar = res.data.avatar || ''
  160. } else {
  161. this.$toast('未找到用户信息')
  162. this.$router.replace('/')
  163. }
  164. } catch (error) {
  165. console.error('获取用户信息失败:', error)
  166. this.$toast('获取用户信息失败')
  167. this.$router.replace('/')
  168. }
  169. } else {
  170. // 没有用户ID,返回搜索页面
  171. this.$toast('请先搜索用户')
  172. this.$router.replace('/')
  173. }
  174. }
  175. // 保存最后使用的用户ID
  176. if (this.userInfo.id) {
  177. localStorage.setItem('lastUserId', this.userInfo.id)
  178. }
  179. },
  180. // 获取产品列表
  181. async fetchProductList() {
  182. try {
  183. const payWayId = getDevicePayWayId()
  184. const res = await getProductList(payWayId)
  185. this.rechargeOptions = res.data || []
  186. } catch (error) {
  187. console.error('获取产品列表失败:', error)
  188. // 设置默认数据,以防接口调用失败
  189. this.rechargeOptions = [
  190. { amount: 60, price: 6 },
  191. { amount: 120, price: 6 },
  192. { amount: 300, price: 6 },
  193. { amount: 600, price: 6 },
  194. { amount: 1000, price: 6 },
  195. { amount: 2000, price: 6 },
  196. { amount: 3800, price: 6 },
  197. { amount: 5000, price: 6 },
  198. { amount: 10000, price: 6 }
  199. ]
  200. }
  201. },
  202. selectRecharge(index) {
  203. this.selectedRecharge = index
  204. },
  205. // 切换用户
  206. switchUser() {
  207. this.$router.push('/')
  208. },
  209. // 切换协议勾选状态
  210. toggleAgreement() {
  211. this.agreementChecked = !this.agreementChecked
  212. },
  213. // 显示协议弹框
  214. showAgreement() {
  215. this.agreementVisible = true
  216. },
  217. confirmPay() {
  218. if (this.isLoading) return // 防止重复点击
  219. if (!this.userInfo.id) {
  220. this.$toast('请先选择用户')
  221. return
  222. }
  223. // 检查协议是否勾选
  224. if (!this.agreementChecked) {
  225. this.$toast('请阅读并同意充值协议')
  226. return
  227. }
  228. const selectedOption = this.rechargeOptions[this.selectedRecharge]
  229. // 使用二次确认弹窗
  230. this.$dialog.confirm({
  231. title: '支付确认',
  232. message: `
  233. <div class="confirm-dialog-content">
  234. <div class="confirm-tip">请核实并确认ID是否正确,请提防:</div>
  235. <div class="warning-list">
  236. <div class="warning-item">刷单赚取佣金</div>
  237. <div class="warning-item">公检法要求转账到安全账户</div>
  238. <div class="warning-item">购物退款、理赔需要转账</div>
  239. <div class="warning-item">代充值</div>
  240. <div class="warning-item">支付返利活动</div>
  241. </div>
  242. </div>
  243. `,
  244. confirmButtonText: '确认支付',
  245. cancelButtonText: '取消',
  246. showCancelButton: true,
  247. showConfirmButton: true,
  248. allowHtml: true
  249. }).then(() => {
  250. // 调用支付接口
  251. this.requestAliPay(selectedOption)
  252. }).catch(() => {
  253. // 取消支付
  254. })
  255. },
  256. // 请求支付宝支付
  257. async requestAliPay(product) {
  258. // 显示加载提示
  259. this.isLoading = true
  260. this.$toast.loading({
  261. message: '正在发起支付...',
  262. forbidClick: true,
  263. duration: 0
  264. })
  265. try {
  266. // 获取平台类型
  267. const platform = getPlatformType()
  268. // 构建支付参数
  269. const payData = {
  270. userId: this.userInfo.id,
  271. productId: product.id
  272. }
  273. // 调用支付宝H5支付接口
  274. const res = await aliPayH5(payData, platform)
  275. this.$toast.clear()
  276. this.isLoading = false
  277. // 处理HTML表单响应
  278. if (typeof res === 'string' && res.includes('<form')) {
  279. // 创建一个div来放置表单
  280. const div = document.createElement('div')
  281. div.innerHTML = res
  282. document.body.appendChild(div)
  283. // 自动提交表单
  284. setTimeout(() => {
  285. const form = div.querySelector('form')
  286. if (form) {
  287. form.submit()
  288. } else {
  289. this.$toast.fail('支付表单加载失败')
  290. }
  291. }, 100)
  292. } else {
  293. this.$toast.fail('获取支付表单失败')
  294. }
  295. } catch (error) {
  296. this.$toast.clear()
  297. this.isLoading = false
  298. console.error('支付请求失败:', error)
  299. this.$toast.fail('支付请求失败,请重试')
  300. }
  301. },
  302. // 处理支付成功
  303. handlePaymentSuccess() {
  304. console.log('支付成功')
  305. this.$toast.success('支付成功')
  306. window.location.href = 'https://gbyy91.com/pay'
  307. },
  308. // 处理支付失败
  309. handlePaymentFailure(message) {
  310. console.error('支付失败:', message)
  311. this.$toast.fail(message || '支付失败,请重试')
  312. },
  313. // 处理支付取消
  314. handlePaymentCancel() {
  315. console.log('用户取消支付')
  316. this.$toast('支付已取消')
  317. }
  318. }
  319. }
  320. </script>
  321. <style scoped>
  322. .recharge-page {
  323. min-height: 100vh;
  324. display: flex;
  325. flex-direction: column;
  326. background-color: #F5F7FA;
  327. padding-bottom: 10px;
  328. position: relative;
  329. overflow: hidden;
  330. }
  331. /* 顶部标题样式 */
  332. .page-header {
  333. padding: 5px 16px 0;
  334. display: flex;
  335. align-items: center;
  336. margin-bottom: 0;
  337. }
  338. .header-content {
  339. display: flex;
  340. align-items: center;
  341. width: 100%;
  342. }
  343. .logo-wrapper {
  344. display: flex;
  345. align-items: center;
  346. justify-content: flex-start;
  347. width: 100%;
  348. }
  349. .logo-container {
  350. display: flex;
  351. align-items: center;
  352. justify-content: flex-start;
  353. }
  354. .logo-image {
  355. width: 60px;
  356. height: 60px;
  357. object-fit: contain;
  358. }
  359. /* 页面标题样式 */
  360. .page-title {
  361. text-align: center;
  362. margin-bottom: 5px;
  363. }
  364. .page-title h1 {
  365. font-size: 18px;
  366. font-weight: 600;
  367. color: #333;
  368. margin: 0;
  369. }
  370. /* 用户信息样式 */
  371. .user-info-section {
  372. padding: 0 8px;
  373. margin-top: 0;
  374. margin-bottom: 5px;
  375. }
  376. .user-info-card {
  377. background-color: #fff;
  378. border-radius: 12px;
  379. padding: 8px;
  380. display: flex;
  381. align-items: center;
  382. position: relative;
  383. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
  384. }
  385. .user-avatar {
  386. margin-right: 10px;
  387. position: relative;
  388. }
  389. .avatar, .avatar-placeholder {
  390. width: 40px;
  391. height: 40px;
  392. border-radius: 50%;
  393. overflow: hidden;
  394. background-color: #f2f2f2;
  395. display: flex;
  396. align-items: center;
  397. justify-content: center;
  398. border: 2px solid #F5EEFF;
  399. }
  400. .user-details {
  401. flex: 1;
  402. }
  403. .user-name {
  404. font-size: 14px;
  405. font-weight: 600;
  406. margin-bottom: 4px;
  407. color: #333;
  408. }
  409. .user-id {
  410. font-size: 12px;
  411. color: #666;
  412. display: flex;
  413. align-items: center;
  414. background-color: #F5F5F5;
  415. padding: 2px 8px;
  416. border-radius: 12px;
  417. display: inline-flex;
  418. }
  419. .id-icon {
  420. width: 14px;
  421. height: 14px;
  422. margin-right: 4px;
  423. }
  424. .switch-account-btn {
  425. background-color: #B66FFF;
  426. color: white;
  427. padding: 6px 12px;
  428. border-radius: 16px;
  429. font-size: 12px;
  430. position: absolute;
  431. right: 12px;
  432. cursor: pointer;
  433. box-shadow: 0 2px 6px rgba(182, 111, 255, 0.3);
  434. }
  435. /* 充值金额样式 */
  436. .recharge-section {
  437. padding: 0 8px;
  438. margin-bottom: 5px;
  439. }
  440. .section-title {
  441. font-size: 14px;
  442. font-weight: bold;
  443. margin-bottom: 5px;
  444. color: #333;
  445. }
  446. .recharge-grid {
  447. display: grid;
  448. grid-template-columns: repeat(3, 1fr);
  449. gap: 10px;
  450. padding: 0 2px;
  451. }
  452. .recharge-item {
  453. background-color: #F0F0F0;
  454. border-radius: 8px;
  455. padding: 8px 8px;
  456. display: flex;
  457. flex-direction: column;
  458. align-items: center;
  459. cursor: pointer;
  460. transition: all 0.2s ease;
  461. border: 1px solid #DDDDDD;
  462. position: relative;
  463. overflow: hidden;
  464. }
  465. .recharge-item.active {
  466. background-color: #F5EEFF;
  467. border: 1px solid #B66FFF;
  468. transform: scale(1.02);
  469. box-shadow: 0 2px 8px rgba(182, 111, 255, 0.2);
  470. }
  471. .recharge-item.active:before {
  472. content: "";
  473. position: absolute;
  474. top: 0;
  475. right: 0;
  476. width: 0;
  477. height: 0;
  478. border-style: solid;
  479. border-width: 0 20px 20px 0;
  480. border-color: transparent #B66FFF transparent transparent;
  481. }
  482. .recharge-item.active:after {
  483. content: "✓";
  484. position: absolute;
  485. top: 0;
  486. right: 3px;
  487. color: white;
  488. font-size: 10px;
  489. font-weight: bold;
  490. }
  491. .diamond-icon {
  492. margin-bottom: 3px;
  493. }
  494. .diamond-img {
  495. width: 20px;
  496. height: 20px;
  497. object-fit: contain;
  498. }
  499. .recharge-amount {
  500. font-size: 14px;
  501. font-weight: bold;
  502. margin-bottom: 1px;
  503. }
  504. .recharge-price {
  505. font-size: 12px;
  506. color: #666;
  507. }
  508. /* 支付方式样式 */
  509. .payment-section {
  510. padding: 0 8px;
  511. margin-bottom: 5px;
  512. background-color: #fff;
  513. border-radius: 12px;
  514. margin-left: 8px;
  515. margin-right: 8px;
  516. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
  517. }
  518. .payment-option {
  519. display: flex;
  520. align-items: center;
  521. padding: 8px;
  522. border-bottom: 1px solid #EAEAEA;
  523. }
  524. .payment-icon {
  525. margin-right: 12px;
  526. }
  527. .alipay-icon {
  528. width: 28px;
  529. height: 28px;
  530. object-fit: contain;
  531. }
  532. .payment-name {
  533. flex: 1;
  534. font-size: 14px;
  535. font-weight: 500;
  536. color: #333;
  537. }
  538. .payment-selected {
  539. display: flex;
  540. align-items: center;
  541. justify-content: center;
  542. }
  543. .check-icon {
  544. width: 20px;
  545. height: 20px;
  546. object-fit: contain;
  547. }
  548. /* 温馨提示样式 */
  549. .tips-section {
  550. padding: 8px 12px;
  551. margin: 0 8px 5px;
  552. background-color: #f8f8f8;
  553. border-radius: 12px;
  554. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
  555. }
  556. .tips-title {
  557. font-size: 14px;
  558. font-weight: 600;
  559. color: #333;
  560. margin-bottom: 5px;
  561. }
  562. .tips-content {
  563. margin-bottom: 4px;
  564. }
  565. .tip-item {
  566. font-size: 12px;
  567. color: #666;
  568. margin-bottom: 6px;
  569. line-height: 1.5;
  570. }
  571. .tip-item:last-child {
  572. margin-bottom: 0;
  573. }
  574. .agreement-checkbox {
  575. display: flex;
  576. align-items: center;
  577. margin-top: 5px;
  578. cursor: pointer;
  579. }
  580. .checkbox-wrapper {
  581. width: 16px;
  582. height: 16px;
  583. border: 1px solid #ddd;
  584. border-radius: 3px;
  585. margin-right: 6px;
  586. display: flex;
  587. align-items: center;
  588. justify-content: center;
  589. }
  590. .checkbox-wrapper.checked {
  591. background-color: #B66FFF;
  592. border-color: #B66FFF;
  593. }
  594. .agreement-text {
  595. font-size: 12px;
  596. color: #666;
  597. }
  598. .agreement-link {
  599. color: #B66FFF;
  600. text-decoration: none;
  601. }
  602. /* 协议弹框样式 */
  603. .agreement-content {
  604. padding: 10px;
  605. height: 60vh;
  606. overflow: hidden;
  607. }
  608. .agreement-iframe {
  609. width: 100%;
  610. height: 100%;
  611. border: none;
  612. }
  613. /* 支付按钮样式 */
  614. .pay-button {
  615. padding: 0 8px;
  616. margin-top: auto;
  617. margin-bottom: 5px;
  618. }
  619. .pay-button .van-button {
  620. background-color: #B66FFF;
  621. border: none;
  622. height: 38px;
  623. font-size: 15px;
  624. font-weight: 500;
  625. box-shadow: 0 4px 12px rgba(182, 111, 255, 0.3);
  626. }
  627. /* 二次确认弹窗样式 */
  628. :deep(.custom-dialog1) {
  629. width: 90%;
  630. max-width: 300px;
  631. border-radius: 12px;
  632. overflow: hidden;
  633. }
  634. :deep(.custom-dialog .van-dialog__header) {
  635. padding: 15px 0;
  636. font-weight: 600;
  637. font-size: 16px;
  638. color: #333;
  639. }
  640. :deep(.custom-dialog .van-dialog__content) {
  641. padding: 10px 20px 15px;
  642. max-height: none;
  643. overflow: visible;
  644. }
  645. :deep(.confirm-dialog-content) {
  646. display: flex;
  647. flex-direction: column;
  648. align-items: center;
  649. text-align: center;
  650. }
  651. :deep(.confirm-price) {
  652. font-size: 24px;
  653. font-weight: bold;
  654. color: #333;
  655. margin-bottom: 10px;
  656. }
  657. :deep(.confirm-tip) {
  658. font-size: 14px;
  659. color: #333;
  660. font-weight: 500;
  661. margin-bottom: 3px;
  662. text-align: left;
  663. align-self: flex-start;
  664. }
  665. :deep(.warning-list) {
  666. width: 100%;
  667. text-align: left;
  668. margin-top: 0;
  669. }
  670. :deep(.warning-item) {
  671. font-size: 13px;
  672. color: #666;
  673. margin-bottom: 4px;
  674. position: relative;
  675. padding-left: 12px;
  676. }
  677. :deep(.warning-item:before) {
  678. content: "•";
  679. position: absolute;
  680. left: 0;
  681. color: #666;
  682. }
  683. :deep(.warning-item:last-child) {
  684. margin-bottom: 0;
  685. }
  686. :deep(.custom-dialog .van-dialog__footer) {
  687. display: flex;
  688. border-top: 1px solid #eee;
  689. }
  690. :deep(.custom-dialog .van-button) {
  691. flex: 1;
  692. height: 44px;
  693. font-size: 16px;
  694. border: none;
  695. border-radius: 0;
  696. margin: 0;
  697. }
  698. :deep(.custom-dialog .van-dialog__cancel) {
  699. color: #333;
  700. }
  701. :deep(.custom-dialog .van-dialog__confirm) {
  702. color: #f44336;
  703. font-weight: normal;
  704. }
  705. </style>