index.vue 21 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004
  1. <template>
  2. <view class="pay-container">
  3. <!-- 商家信息区域 -->
  4. <view class="merchant-section">
  5. <view class="merchant-card">
  6. <view class="merchant-logo">
  7. <image
  8. :src="shopInfo.smallAvatar"
  9. class="logo-image"
  10. mode="aspectFill"
  11. />
  12. </view>
  13. <view class="merchant-details">
  14. <text class="merchant-name">{{ shopInfo.showName || '未命名' }}</text>
  15. </view>
  16. </view>
  17. </view>
  18. <!-- 支付金额区域 -->
  19. <view class="amount-section">
  20. <view class="amount-label">支付金额</view>
  21. <view class="amount-display">
  22. <text class="currency">¥</text>
  23. <text class="amount">{{ displayAmount }}</text>
  24. </view>
  25. <view class="amount-tip">请输入金额</view>
  26. </view>
  27. <!-- 数字键盘 - 使用直接事件绑定,确保兼容性 -->
  28. <view class="keyboard-section">
  29. <view class="keyboard">
  30. <view class="keyboard-row" v-for="(row, rowIndex) in keyboardKeys" :key="rowIndex">
  31. <view
  32. class="key-item"
  33. v-for="(key, keyIndex) in row"
  34. :key="`${rowIndex}-${keyIndex}`"
  35. :class="{
  36. 'key-number': key.type === 'number',
  37. 'key-delete': key.type === 'delete',
  38. 'key-dot': key.type === 'dot',
  39. 'key-confirm': key.type === 'confirm'
  40. }"
  41. @click="handleKeyPress(key)"
  42. @touchstart="handleTouchStart"
  43. @touchend="handleTouchEnd"
  44. >
  45. <text v-if="key.type === 'delete'" class="iconfont icon-delete"></text>
  46. <text v-else-if="key.type === 'confirm'">确认</text>
  47. <text v-else>{{ key.value }}</text>
  48. </view>
  49. </view>
  50. </view>
  51. </view>
  52. <!-- 支付按钮 -->
  53. <view class="pay-button-section">
  54. <button
  55. class="pay-button"
  56. :class="{ disabled: !canPay }"
  57. :disabled="!canPay"
  58. @click="handlePay"
  59. >
  60. <text class="button-text">支付宝支付</text>
  61. </button>
  62. </view>
  63. <!-- 确认支付弹框 -->
  64. <view class="confirm-dialog" v-if="showConfirm" @click="hideConfirmDialog">
  65. <view class="dialog-content" @click.stop>
  66. <view class="dialog-header">
  67. <text class="dialog-title">提示</text>
  68. <view class="close-btn" @click="hideConfirmDialog">
  69. <text class="iconfont icon-close">×</text>
  70. </view>
  71. </view>
  72. <view class="dialog-body">
  73. <view class="confirm-amount-section">
  74. <text class="confirm-label">支付金额</text>
  75. <view class="confirm-amount-display">
  76. <text class="confirm-currency">¥</text>
  77. <text class="confirm-amount">{{ displayAmount }}</text>
  78. </view>
  79. </view>
  80. <view class="confirm-tips">
  81. <text class="tip-text">确认金额无误</text>
  82. </view>
  83. </view>
  84. <view class="dialog-footer">
  85. <button class="cancel-btn" @click="hideConfirmDialog">取消</button>
  86. <button class="confirm-btn" @click="handlePay">确认</button>
  87. </view>
  88. </view>
  89. </view>
  90. </view>
  91. </template>
  92. <script>
  93. import { fastPay } from '@/api/pay'
  94. import { orderRelate } from '@/api/order'
  95. // 优化:使用常量避免重复创建
  96. const KEY_TYPES = {
  97. NUMBER: 'number',
  98. DELETE: 'delete',
  99. DOT: 'dot',
  100. CONFIRM: 'confirm'
  101. };
  102. const MAX_INTEGER_LENGTH = 8;
  103. const MAX_DECIMAL_LENGTH = 2;
  104. export default {
  105. name: 'pay',
  106. data() {
  107. return {
  108. currentAmount: '0',
  109. displayAmount: '0',
  110. // 商家信息
  111. merchantInfo: {
  112. logo: '',
  113. name: '',
  114. description: ''
  115. },
  116. // 优化:使用静态数据,避免重复创建
  117. keyboardKeys: [
  118. [
  119. { type: KEY_TYPES.NUMBER, value: '1' },
  120. { type: KEY_TYPES.NUMBER, value: '2' },
  121. { type: KEY_TYPES.NUMBER, value: '3' }
  122. ],
  123. [
  124. { type: KEY_TYPES.NUMBER, value: '4' },
  125. { type: KEY_TYPES.NUMBER, value: '5' },
  126. { type: KEY_TYPES.NUMBER, value: '6' }
  127. ],
  128. [
  129. { type: KEY_TYPES.NUMBER, value: '7' },
  130. { type: KEY_TYPES.NUMBER, value: '8' },
  131. { type: KEY_TYPES.NUMBER, value: '9' }
  132. ],
  133. [
  134. { type: KEY_TYPES.DOT, value: '.' },
  135. { type: KEY_TYPES.NUMBER, value: '0' },
  136. { type: KEY_TYPES.DELETE, value: '' }
  137. ]
  138. ],
  139. // 优化:使用更高效的状态管理
  140. amountBuffer: '0',
  141. updateScheduled: false,
  142. updateTimer: null,
  143. // 弹框状态
  144. showConfirm: false,
  145. account:0,
  146. payWay:1,
  147. shopInfo:[]
  148. }
  149. },
  150. computed: {
  151. // 简化支付按钮判断逻辑:只要大于0就能支付
  152. canPay() {
  153. const amount = parseFloat(this.currentAmount);
  154. return amount > 0;
  155. }
  156. },
  157. onLoad(options) {
  158. if (options.account) {
  159. this.account = options.account;
  160. uni.setStorageSync('account',this.account)
  161. }
  162. if (this.account) {
  163. orderRelate({account:this.account}).then(res => {
  164. if (res.data && res.data.shop){
  165. this.shopInfo = res.data.shop?res.data.shop:[]
  166. }
  167. })
  168. }
  169. },
  170. methods: {
  171. // 优化:添加触摸反馈
  172. handleTouchStart(e) {
  173. const target = e.currentTarget;
  174. if (target && target.style) {
  175. target.style.transform = 'scale(0.95)';
  176. }
  177. },
  178. handleTouchEnd(e) {
  179. const target = e.currentTarget;
  180. if (target && target.style) {
  181. setTimeout(() => {
  182. target.style.transform = 'scale(1)';
  183. }, 100);
  184. }
  185. },
  186. // 优化:简化的键盘处理逻辑
  187. handleKeyPress(key) {
  188. // 防抖处理
  189. if (this.updateTimer) {
  190. clearTimeout(this.updateTimer);
  191. }
  192. if (key.type === KEY_TYPES.NUMBER) {
  193. this.addNumber(key.value);
  194. } else if (key.type === KEY_TYPES.DELETE) {
  195. this.deleteNumber();
  196. } else if (key.type === KEY_TYPES.DOT) {
  197. this.addDecimal();
  198. }
  199. // 使用 requestAnimationFrame 优化更新
  200. this.scheduleUpdate();
  201. },
  202. // 优化:使用 requestAnimationFrame 调度更新
  203. scheduleUpdate() {
  204. if (!this.updateScheduled) {
  205. this.updateScheduled = true;
  206. requestAnimationFrame(() => {
  207. this.updateDisplay();
  208. this.updateScheduled = false;
  209. });
  210. }
  211. },
  212. // 优化:更高效的数字添加逻辑
  213. addNumber(num) {
  214. const buffer = this.amountBuffer;
  215. // 快速路径:如果当前是0且输入的不是小数点,直接替换
  216. if (buffer === '0' && num !== '.') {
  217. this.amountBuffer = num;
  218. this.currentAmount = num;
  219. return;
  220. }
  221. // 检查长度限制
  222. const parts = buffer.split('.');
  223. const integerPart = parts[0];
  224. const decimalPart = parts[1];
  225. // 整数部分限制
  226. if (!decimalPart && integerPart.length >= MAX_INTEGER_LENGTH) {
  227. uni.showToast({
  228. title: '金额不能超过8位数',
  229. icon: 'none',
  230. duration: 1500
  231. })
  232. return;
  233. }
  234. // 小数部分限制
  235. if (decimalPart && decimalPart.length >= MAX_DECIMAL_LENGTH) {
  236. uni.showToast({
  237. title: '最多支持2位小数',
  238. icon: 'none',
  239. duration: 1500
  240. })
  241. return;
  242. }
  243. // 添加数字
  244. this.amountBuffer = buffer + num;
  245. this.currentAmount = this.amountBuffer;
  246. },
  247. // 优化:更高效的小数点添加逻辑
  248. addDecimal() {
  249. if (!this.amountBuffer.includes('.')) {
  250. this.amountBuffer += '.';
  251. this.currentAmount = this.amountBuffer;
  252. }
  253. },
  254. // 优化:更高效的删除逻辑
  255. deleteNumber() {
  256. const buffer = this.amountBuffer;
  257. if (buffer.length > 1) {
  258. this.amountBuffer = buffer.slice(0, -1);
  259. } else {
  260. this.amountBuffer = '0';
  261. }
  262. this.currentAmount = this.amountBuffer;
  263. },
  264. // 优化:更高效的显示更新逻辑
  265. updateDisplay() {
  266. let amount = this.currentAmount;
  267. // 确保 amount 是字符串类型
  268. if (typeof amount !== 'string') {
  269. amount = amount.toString();
  270. }
  271. // 快速路径:如果是0,直接显示
  272. if (amount === '0') {
  273. this.displayAmount = '0';
  274. return;
  275. }
  276. // 检查是否包含小数点
  277. if (amount.includes('.')) {
  278. const numAmount = parseFloat(amount) || 0;
  279. this.displayAmount = numAmount.toFixed(2);
  280. } else {
  281. // 整数显示
  282. this.displayAmount = amount;
  283. }
  284. },
  285. // 优化:更高效的金额设置
  286. setAmount(amount) {
  287. const numAmount = parseFloat(amount);
  288. if (!isNaN(numAmount) && numAmount > 0) {
  289. const amountStr = numAmount.toString();
  290. this.amountBuffer = amountStr;
  291. this.currentAmount = amountStr;
  292. this.updateDisplay();
  293. }
  294. },
  295. // 显示确认弹框
  296. showConfirmDialog() {
  297. if (!this.canPay) return;
  298. this.showConfirm = true;
  299. },
  300. // 隐藏确认弹框
  301. hideConfirmDialog() {
  302. this.showConfirm = false;
  303. },
  304. // 处理支付
  305. handlePay() {
  306. if (!this.canPay) return;
  307. const amount = parseFloat(this.currentAmount);
  308. // 隐藏弹框
  309. //this.hideConfirmDialog();
  310. // 简化验证:只要大于0就能支付
  311. if (amount <= 0) {
  312. uni.showToast({
  313. title: '请输入金额',
  314. icon: 'none',
  315. duration: 1000
  316. })
  317. return false
  318. }
  319. let params = {needSend:1,prePrice:amount,payWay:1,repeat:1,fromType:1,account:this.account}
  320. fastPay(params).then(res => {
  321. //错误返回判断
  322. if(res.code == 0){
  323. uni.showToast({
  324. title: res.msg,
  325. icon: 'none',
  326. duration: 1000
  327. })
  328. return false
  329. }
  330. window.location.href = res.data.url;
  331. })
  332. },
  333. goBack() {
  334. uni.navigateBack({
  335. delta: 1
  336. });
  337. }
  338. }
  339. }
  340. </script>
  341. <style lang="scss" scoped>
  342. .pay-container {
  343. min-height: 100vh;
  344. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  345. position: relative;
  346. }
  347. .merchant-section {
  348. padding: 40upx 30upx 20upx;
  349. .merchant-card {
  350. background: rgba(255, 255, 255, 0.95);
  351. backdrop-filter: blur(20px);
  352. border-radius: 20upx;
  353. padding: 30upx;
  354. display: flex;
  355. align-items: center;
  356. box-shadow: 0 8upx 30upx rgba(0, 0, 0, 0.1);
  357. border: 1upx solid rgba(255, 255, 255, 0.2);
  358. .merchant-logo {
  359. width: 100upx;
  360. height: 100upx;
  361. border-radius: 20upx;
  362. overflow: hidden;
  363. margin-right: 25upx;
  364. background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
  365. display: flex;
  366. align-items: center;
  367. justify-content: center;
  368. box-shadow: 0 4upx 15upx rgba(0, 0, 0, 0.1);
  369. .logo-image {
  370. width: 100%;
  371. height: 100%;
  372. border-radius: 20upx;
  373. }
  374. }
  375. .merchant-details {
  376. flex: 1;
  377. display: flex;
  378. align-items: center;
  379. .merchant-name {
  380. font-size: 36upx;
  381. font-weight: 600;
  382. color: #333;
  383. line-height: 1.2;
  384. }
  385. }
  386. }
  387. }
  388. .nav-bar {
  389. display: flex;
  390. align-items: center;
  391. justify-content: center; /* Changed to center the title */
  392. padding: 20upx 30upx;
  393. background: rgba(255, 255, 255, 0.1);
  394. backdrop-filter: blur(10px);
  395. .nav-back {
  396. width: 80upx;
  397. height: 80upx;
  398. display: flex;
  399. align-items: center;
  400. justify-content: center;
  401. border-radius: 50%;
  402. background: rgba(255, 255, 255, 0.2);
  403. cursor: pointer;
  404. transition: all 0.2s ease;
  405. &:active {
  406. background: rgba(255, 255, 255, 0.3);
  407. transform: scale(0.9);
  408. }
  409. .iconfont {
  410. font-size: 40upx;
  411. color: #fff;
  412. font-weight: bold;
  413. }
  414. }
  415. .nav-title {
  416. color: #fff;
  417. font-size: 36upx;
  418. font-weight: 600;
  419. }
  420. .nav-placeholder {
  421. width: 80upx; /* Placeholder for back button */
  422. }
  423. }
  424. .amount-section {
  425. padding: 60upx 40upx;
  426. text-align: center;
  427. .amount-label {
  428. color: rgba(255, 255, 255, 0.8);
  429. font-size: 28upx;
  430. margin-bottom: 20upx;
  431. }
  432. .amount-display {
  433. display: flex;
  434. align-items: baseline;
  435. justify-content: center;
  436. margin-bottom: 20upx;
  437. .currency {
  438. color: #fff;
  439. font-size: 48upx;
  440. font-weight: 600;
  441. margin-right: 10upx;
  442. }
  443. .amount {
  444. color: #fff;
  445. font-size: 80upx;
  446. font-weight: 700;
  447. font-family: 'Arial', sans-serif;
  448. }
  449. }
  450. .amount-tip {
  451. color: rgba(255, 255, 255, 0.6);
  452. font-size: 24upx;
  453. }
  454. }
  455. .customer-info-card {
  456. background: #fff; /* Changed to white */
  457. margin: 0 30upx 20upx;
  458. border-radius: 20upx;
  459. padding: 30upx;
  460. box-shadow: 0 8upx 30upx rgba(0, 0, 0, 0.08);
  461. position: relative;
  462. overflow: hidden;
  463. &::before {
  464. content: '';
  465. position: absolute;
  466. top: 0;
  467. left: 0;
  468. right: 0;
  469. height: 8upx;
  470. background: #fff; /* Changed to white */
  471. box-shadow: 0 2upx 8upx rgba(0, 0, 0, 0.1);
  472. }
  473. .card-header {
  474. display: flex;
  475. align-items: center;
  476. margin-bottom: 20upx;
  477. margin-top: 8upx;
  478. .customer-avatar {
  479. width: 90upx;
  480. height: 90upx;
  481. border-radius: 50%;
  482. background: linear-gradient(135deg, #1677ff 0%, #4096ff 100%);
  483. display: flex;
  484. align-items: center;
  485. justify-content: center;
  486. margin-right: 25upx;
  487. box-shadow: 0 6upx 20upx rgba(22, 119, 255, 0.3);
  488. position: relative;
  489. &::after {
  490. content: '';
  491. position: absolute;
  492. top: -2upx;
  493. left: -2upx;
  494. right: -2upx;
  495. bottom: -2upx;
  496. border-radius: 50%;
  497. background: linear-gradient(135deg, #1677ff 0%, #4096ff 100%);
  498. z-index: -1;
  499. opacity: 0.3;
  500. }
  501. .avatar-text {
  502. color: #fff;
  503. font-size: 44upx;
  504. font-weight: 600;
  505. }
  506. }
  507. .customer-details {
  508. flex: 1;
  509. display: flex;
  510. align-items: center;
  511. justify-content: space-between;
  512. .customer-name {
  513. display: block;
  514. font-size: 34upx;
  515. font-weight: 600;
  516. color: #333;
  517. }
  518. .customer-status {
  519. display: inline-block;
  520. font-size: 24upx;
  521. color: #999;
  522. padding: 4upx 12upx;
  523. border-radius: 20upx;
  524. background: #f8f9fa;
  525. border: 1upx solid #e9ecef;
  526. &.has-debt {
  527. color: #fff;
  528. background: linear-gradient(135deg, #ff6b6b 0%, #ff5252 100%);
  529. border-color: #ff6b6b;
  530. box-shadow: 0 2upx 10upx rgba(255, 107, 107, 0.3);
  531. }
  532. }
  533. }
  534. }
  535. .debt-info {
  536. background: linear-gradient(135deg, #fff5f5 0%, #fef2f2 100%);
  537. border-radius: 15upx;
  538. padding: 20upx 25upx;
  539. margin-top: 20upx;
  540. border: 1upx solid rgba(255, 107, 107, 0.2);
  541. position: relative;
  542. &::before {
  543. content: '';
  544. position: absolute;
  545. top: 0;
  546. left: 0;
  547. right: 0;
  548. bottom: 0;
  549. background: linear-gradient(135deg, rgba(255, 107, 107, 0.05) 0%, rgba(255, 107, 107, 0.02) 100%);
  550. border-radius: 15upx;
  551. }
  552. .debt-amount {
  553. display: flex;
  554. align-items: baseline;
  555. justify-content: space-between;
  556. margin-bottom: 10upx;
  557. position: relative;
  558. z-index: 1;
  559. .debt-label {
  560. font-size: 28upx;
  561. color: #666;
  562. font-weight: 500;
  563. }
  564. .debt-value {
  565. font-size: 40upx;
  566. font-weight: 700;
  567. color: #ff6b6b;
  568. font-family: 'Arial', sans-serif;
  569. text-shadow: 0 2upx 10upx rgba(255, 107, 107, 0.2);
  570. }
  571. }
  572. .debt-tip {
  573. font-size: 22upx;
  574. color: #999;
  575. text-align: right;
  576. position: relative;
  577. z-index: 1;
  578. font-style: italic;
  579. }
  580. }
  581. }
  582. .keyboard-section {
  583. position: fixed;
  584. bottom: 160upx;
  585. left: 0;
  586. right: 0;
  587. background: rgba(255, 255, 255, 0.98);
  588. backdrop-filter: blur(20px);
  589. padding: 30upx;
  590. border-top: 1upx solid rgba(0, 0, 0, 0.05);
  591. .keyboard {
  592. .keyboard-row {
  593. display: flex;
  594. margin-bottom: 20upx;
  595. &:last-child {
  596. margin-bottom: 0;
  597. }
  598. .key-item {
  599. flex: 1;
  600. height: 120upx;
  601. margin: 0 10upx;
  602. border-radius: 20upx;
  603. display: flex;
  604. align-items: center;
  605. justify-content: center;
  606. font-size: 40upx;
  607. font-weight: 600;
  608. transition: all 0.15s ease;
  609. user-select: none;
  610. -webkit-user-select: none;
  611. cursor: pointer;
  612. will-change: transform;
  613. position: relative;
  614. overflow: hidden;
  615. &::before {
  616. content: '';
  617. position: absolute;
  618. top: 0;
  619. left: 0;
  620. right: 0;
  621. bottom: 0;
  622. background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.05) 100%);
  623. opacity: 0;
  624. transition: opacity 0.15s ease;
  625. }
  626. &:active::before {
  627. opacity: 1;
  628. }
  629. &.key-number {
  630. background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
  631. color: #333;
  632. box-shadow: 0 4upx 20upx rgba(0, 0, 0, 0.08);
  633. border: 1upx solid rgba(0, 0, 0, 0.05);
  634. }
  635. &.key-delete {
  636. background: linear-gradient(135deg, #ff6b6b 0%, #ff5252 100%);
  637. color: #fff;
  638. box-shadow: 0 4upx 20upx rgba(255, 107, 107, 0.3);
  639. }
  640. &.key-dot {
  641. background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
  642. color: #333;
  643. box-shadow: 0 4upx 20upx rgba(0, 0, 0, 0.08);
  644. border: 1upx solid rgba(0, 0, 0, 0.05);
  645. }
  646. &.key-confirm {
  647. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  648. color: #fff;
  649. box-shadow: 0 4upx 20upx rgba(102, 126, 234, 0.3);
  650. }
  651. }
  652. }
  653. }
  654. }
  655. .pay-button-section {
  656. position: fixed;
  657. bottom: 0;
  658. left: 0;
  659. right: 0;
  660. padding: 30upx;
  661. background: rgba(255, 255, 255, 0.98);
  662. backdrop-filter: blur(20px);
  663. border-top: 1upx solid rgba(0, 0, 0, 0.05);
  664. .pay-button {
  665. width: 100%;
  666. height: 100upx;
  667. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  668. color: #fff;
  669. font-size: 36upx;
  670. font-weight: 600;
  671. border-radius: 50upx;
  672. border: none;
  673. transition: all 0.3s ease;
  674. position: relative;
  675. overflow: hidden;
  676. &::before {
  677. content: '';
  678. position: absolute;
  679. top: 0;
  680. left: 0;
  681. right: 0;
  682. bottom: 0;
  683. background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.05) 100%);
  684. opacity: 0;
  685. transition: opacity 0.3s ease;
  686. }
  687. &:active::before {
  688. opacity: 1;
  689. }
  690. &.disabled {
  691. background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%);
  692. color: #adb5bd;
  693. box-shadow: none;
  694. }
  695. &:not(.disabled):active {
  696. transform: scale(0.98);
  697. }
  698. .button-text {
  699. position: absolute;
  700. left: 50%;
  701. transform: translateX(-50%);
  702. font-size: 36upx;
  703. font-weight: 600;
  704. color: #fff;
  705. }
  706. .button-amount {
  707. position: absolute;
  708. right: 30upx;
  709. font-size: 36upx;
  710. font-weight: 700;
  711. color: #fff;
  712. font-family: 'Arial', sans-serif;
  713. }
  714. }
  715. }
  716. // 确认支付弹框样式
  717. .confirm-dialog {
  718. position: fixed;
  719. top: 0;
  720. left: 0;
  721. right: 0;
  722. bottom: 0;
  723. background: rgba(0, 0, 0, 0.6);
  724. display: flex;
  725. align-items: center;
  726. justify-content: center;
  727. z-index: 9999;
  728. animation: fadeIn 0.3s ease;
  729. .dialog-content {
  730. width: 85%;
  731. max-width: 700upx;
  732. background: #fff;
  733. border-radius: 25upx;
  734. overflow: hidden;
  735. animation: slideUp 0.3s ease;
  736. box-shadow: 0 20upx 60upx rgba(0, 0, 0, 0.2);
  737. .dialog-header {
  738. display: flex;
  739. align-items: center;
  740. justify-content: space-between;
  741. padding: 40upx 40upx 30upx;
  742. border-bottom: 1upx solid #f0f0f0;
  743. background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
  744. .dialog-title {
  745. font-size: 36upx;
  746. font-weight: 600;
  747. color: #333;
  748. }
  749. .close-btn {
  750. width: 60upx;
  751. height: 60upx;
  752. display: flex;
  753. align-items: center;
  754. justify-content: center;
  755. border-radius: 50%;
  756. background: rgba(0, 0, 0, 0.1);
  757. cursor: pointer;
  758. transition: all 0.2s ease;
  759. &:active {
  760. background: rgba(0, 0, 0, 0.2);
  761. transform: scale(0.95);
  762. }
  763. .iconfont {
  764. font-size: 32upx;
  765. color: #666;
  766. font-weight: bold;
  767. }
  768. }
  769. }
  770. .dialog-body {
  771. padding: 50upx 40upx;
  772. .confirm-amount-section {
  773. text-align: center;
  774. margin-bottom: 40upx;
  775. .confirm-label {
  776. display: block;
  777. font-size: 28upx;
  778. color: #666;
  779. margin-bottom: 25upx;
  780. font-weight: 500;
  781. }
  782. .confirm-amount-display {
  783. display: flex;
  784. align-items: baseline;
  785. justify-content: center;
  786. .confirm-currency {
  787. font-size: 60upx;
  788. font-weight: 600;
  789. color: #ff6b6b;
  790. margin-right: 10upx;
  791. }
  792. .confirm-amount {
  793. font-size: 100upx;
  794. font-weight: 700;
  795. color: #ff6b6b;
  796. font-family: 'Arial', sans-serif;
  797. text-shadow: 0 2upx 10upx rgba(255, 107, 107, 0.3);
  798. }
  799. }
  800. }
  801. .confirm-tips {
  802. text-align: center;
  803. padding: 20upx 30upx;
  804. background: rgba(255, 107, 107, 0.1);
  805. border-radius: 15upx;
  806. border-left: 4upx solid #ff6b6b;
  807. .tip-text {
  808. font-size: 26upx;
  809. color: #666;
  810. line-height: 1.5;
  811. }
  812. }
  813. }
  814. .dialog-footer {
  815. display: flex;
  816. border-top: 1upx solid #f0f0f0;
  817. padding: 30upx 40upx;
  818. gap: 20upx;
  819. .cancel-btn, .confirm-btn {
  820. flex: 1;
  821. height: 100upx;
  822. border: none;
  823. font-size: 32upx;
  824. font-weight: 600;
  825. transition: all 0.2s ease;
  826. border-radius: 50upx;
  827. display: flex;
  828. align-items: center;
  829. justify-content: center;
  830. position: relative;
  831. overflow: hidden;
  832. &::before {
  833. content: '';
  834. position: absolute;
  835. top: 0;
  836. left: 0;
  837. right: 0;
  838. bottom: 0;
  839. background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.05) 100%);
  840. opacity: 0;
  841. transition: opacity 0.2s ease;
  842. }
  843. &:active::before {
  844. opacity: 1;
  845. }
  846. &:active {
  847. transform: scale(0.98);
  848. }
  849. }
  850. .cancel-btn {
  851. background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
  852. color: #666;
  853. border: 2upx solid #dee2e6;
  854. box-shadow: 0 2upx 8upx rgba(0, 0, 0, 0.1);
  855. &:active {
  856. background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%);
  857. border-color: #ced4da;
  858. box-shadow: 0 1upx 4upx rgba(0, 0, 0, 0.15);
  859. }
  860. }
  861. .confirm-btn {
  862. background: linear-gradient(135deg, #ff6b6b 0%, #ff5252 100%);
  863. color: #fff;
  864. box-shadow: 0 4upx 20upx rgba(255, 107, 107, 0.3);
  865. &:active {
  866. background: linear-gradient(135deg, #ff5252 0%, #ff4444 100%);
  867. box-shadow: 0 2upx 10upx rgba(255, 107, 107, 0.4);
  868. }
  869. }
  870. }
  871. }
  872. }
  873. // 弹框动画
  874. @keyframes fadeIn {
  875. from {
  876. opacity: 0;
  877. }
  878. to {
  879. opacity: 1;
  880. }
  881. }
  882. @keyframes slideUp {
  883. from {
  884. opacity: 0;
  885. transform: translateY(50upx) scale(0.9);
  886. }
  887. to {
  888. opacity: 1;
  889. transform: translateY(0) scale(1);
  890. }
  891. }
  892. </style>