expressSet.vue 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172
  1. <template>
  2. <view class="app-content">
  3. <!-- 门店地址管理 -->
  4. <view class="shop-address-section">
  5. <view class="section-header">
  6. <text class="section-title">门店地址</text>
  7. </view>
  8. <view class="shop-info-card" v-if="shopAddress">
  9. <view class="shop-status success">
  10. <text class="status-icon">✓</text>
  11. <text class="status-text">已创建门店地址</text>
  12. </view>
  13. <!-- <view class="shop-details">
  14. <view class="detail-item">
  15. <text class="detail-label">门店名称:</text>
  16. <text class="detail-value">{{ shopAddress.shopName || '未设置' }}</text>
  17. </view>
  18. <view class="detail-item">
  19. <text class="detail-label">门店地址:</text>
  20. <text class="detail-value">{{ shopAddress.fullAddress || '未设置' }}</text>
  21. </view>
  22. </view> -->
  23. <button class="update-btn" @click="updateShopAddressFn">
  24. <text class="btn-text">更新门店地址</text>
  25. </button>
  26. </view>
  27. <view class="shop-info-card empty" v-else>
  28. <view class="shop-status warning">
  29. <text class="status-icon">!</text>
  30. <text class="status-text">暂未创建门店地址</text>
  31. </view>
  32. <view class="shop-desc">
  33. <text class="desc-text">请先创建门店地址,以便正常使用跑腿服务</text>
  34. </view>
  35. <button class="create-btn" @click="createShopAddress">
  36. <text class="btn-text">创建门店</text>
  37. </button>
  38. </view>
  39. </view>
  40. <!-- 余额卡片 -->
  41. <view class="balance-card">
  42. <view class="balance-left">
  43. <view class="balance-header">
  44. <text class="balance-title">账户余额</text>
  45. </view>
  46. <view class="balance-amount">
  47. <text class="amount-text">{{ balance.toFixed(2) }}</text>
  48. <text class="balance-unit">元</text>
  49. </view>
  50. <view class="balance-desc">
  51. <text class="desc-text">用于支付跑腿费用</text>
  52. </view>
  53. </view>
  54. <view class="balance-right">
  55. <view class="sub-balance sf">
  56. <text class="sub-balance-label">达达</text>
  57. <text class="sub-balance-amount">{{ dadaBalance.toFixed(2) }}元</text>
  58. </view>
  59. <view class="sub-balance dada">
  60. <text class="sub-balance-label">顺丰同城</text>
  61. <text class="sub-balance-amount">{{ sfBalance.toFixed(2) }}元</text>
  62. </view>
  63. </view>
  64. </view>
  65. <!-- 充值按钮 -->
  66. <view class="recharge-section">
  67. <button class="recharge-btn" @click="showRechargeModal">
  68. <text class="btn-text">立即充值</text>
  69. </button>
  70. </view>
  71. <!-- 充值记录 -->
  72. <!-- <view class="record-section">
  73. <view class="section-header">
  74. <text class="section-title">充值记录</text>
  75. </view>
  76. <view class="record-list" v-if="rechargeRecords.length > 0">
  77. <view class="record-item" v-for="(record, index) in rechargeRecords" :key="index">
  78. <view class="record-info">
  79. <text class="record-amount">+{{ record.amount }}元</text>
  80. <text class="record-time">{{ record.time }}</text>
  81. </view>
  82. <text class="record-status" :class="record.status">{{ record.statusText }}</text>
  83. </view>
  84. </view>
  85. <view class="empty-record" v-else>
  86. <text class="empty-text">暂无充值记录</text>
  87. </view>
  88. </view> -->
  89. <!-- 充值弹窗 -->
  90. <view class="modal-overlay" v-if="showModal" @click="hideRechargeModal">
  91. <view class="modal-content" @click.stop>
  92. <view class="modal-header">
  93. <text class="modal-title">账户充值</text>
  94. <text class="modal-close" @click="hideRechargeModal">×</text>
  95. </view>
  96. <view class="modal-body">
  97. <view v-if="!showPayUrl">
  98. <!-- 配送公司选择 -->
  99. <view class="form-item">
  100. <text class="form-label">选择跑腿</text>
  101. <view class="express-company-options">
  102. <view
  103. class="express-option"
  104. :class="{ active: expressCompany === 'DADA' }"
  105. @click="selectExpressCompany('DADA')"
  106. >
  107. <text class="express-option-text">达达</text>
  108. </view>
  109. <view
  110. class="express-option"
  111. :class="{ active: expressCompany === 'SFTC' }"
  112. @click="selectExpressCompany('SFTC')"
  113. >
  114. <text class="express-option-text">顺丰同城</text>
  115. </view>
  116. </view>
  117. </view>
  118. <view class="form-item">
  119. <text class="form-label">充值金额</text>
  120. <view class="amount-input-wrapper">
  121. <text class="currency-symbol">¥</text>
  122. <input
  123. class="amount-input"
  124. type="digit"
  125. v-model="rechargeAmount"
  126. placeholder="充值金额"
  127. @input="onAmountInput"
  128. />
  129. </view>
  130. <view style="color:red;margin:10upx 0 10upx 0;font-size:24upx;font-weight:bold;">充值金额不能少于50元,用不完可以退</view>
  131. </view>
  132. <!-- 快捷金额选择 -->
  133. <view class="quick-amounts">
  134. <text class="quick-title">快捷选择</text>
  135. <view class="amount-options">
  136. <view
  137. class="amount-option"
  138. v-for="amount in quickAmounts"
  139. :key="amount"
  140. :class="{ active: rechargeAmount == amount }"
  141. @click="selectAmount(amount)"
  142. >
  143. <text class="option-text">{{ amount }}元</text>
  144. </view>
  145. </view>
  146. </view>
  147. </view>
  148. <!-- 支付链接展示区域 -->
  149. <view v-if="showPayUrl" class="pay-url-section">
  150. <view class="pay-url-title">
  151. <text>请复制以下链接在浏览器中打开完成支付</text>
  152. </view>
  153. <view class="pay-url-box">
  154. <text class="pay-url-text" user-select>{{ payUrl }}</text>
  155. </view>
  156. <view class="copy-btn-wrapper">
  157. <button class="copy-btn" @click="copyPayUrl">
  158. <text class="copy-btn-text">复制链接</text>
  159. </button>
  160. </view>
  161. </view>
  162. </view>
  163. <view class="modal-footer">
  164. <button class="cancel-btn" @click="hideRechargeModal">
  165. <text class="cancel-text">{{ showPayUrl ? '关闭' : '取消' }}</text>
  166. </button>
  167. <button v-if="!showPayUrl" class="confirm-btn" @click="confirmRecharge" :disabled="!canRecharge">
  168. <text class="confirm-text">获取充值链接</text>
  169. </button>
  170. </view>
  171. </view>
  172. </view>
  173. </view>
  174. </template>
  175. <script>
  176. import TuiListCell from "@/components/plugin/list-cell";
  177. import { createStore, updateStore, getStore, getStoreBalance, rechargeStore } from "@/api/shop-express";
  178. import { getWxStoreId } from "@/api/main/index";
  179. export default {
  180. name: "expressSet",
  181. components: {
  182. TuiListCell,
  183. },
  184. data() {
  185. return {
  186. balance: 0.00, // 总账户余额
  187. sfBalance: 0.00, // 顺丰余额
  188. dadaBalance: 0.00, // 达达余额
  189. showModal: false, // 是否显示充值弹窗
  190. rechargeAmount: '', // 充值金额
  191. expressCompany: 'DADA', // 跑腿公司,默认达达
  192. quickAmounts: [50, 100, 200, 500], // 快捷金额选项
  193. rechargeRecords: [], // 充值记录
  194. shopAddress: null, // 门店地址信息
  195. loading: false,
  196. payUrl: '', // 支付链接
  197. showPayUrl: false, // 是否显示支付链接
  198. wxStoreId:''
  199. };
  200. },
  201. computed: {
  202. canRecharge() {
  203. const amount = parseFloat(this.rechargeAmount);
  204. return amount > 0 && amount <= 1000000; // 限制最大充值金额
  205. }
  206. },
  207. onLoad() {
  208. },
  209. onShow() {
  210. uni.setNavigationBarTitle({
  211. title: `跑腿设置`,
  212. });
  213. },
  214. methods: {
  215. // 复制支付链接
  216. copyPayUrl() {
  217. uni.setClipboardData({
  218. data: this.payUrl,
  219. success: () => {
  220. uni.showToast({
  221. title: '链接已复制',
  222. icon: 'success'
  223. });
  224. }
  225. });
  226. },
  227. init() {
  228. getWxStoreId().then(res=>{
  229. if(res.code == 1){
  230. if(res.data.wx){
  231. this.wxStoreId = res.data.wx.wxStoreId
  232. if(this.wxStoreId!=''){
  233. this.initExpress()
  234. }
  235. }
  236. }
  237. })
  238. },
  239. async initExpress(){
  240. try {
  241. this.loading = true;
  242. // 获取门店地址信息
  243. this.getShopAddressInfo();
  244. // 获取账户余额和充值记录
  245. this.getBalance();
  246. this.getRechargeRecords();
  247. } catch (error) {
  248. console.error('初始化失败:', error);
  249. uni.showToast({
  250. title: '加载失败',
  251. icon: 'none'
  252. });
  253. } finally {
  254. this.loading = false;
  255. }
  256. },
  257. // 获取门店地址信息
  258. async getShopAddressInfo() {
  259. try {
  260. const result = await getStore();
  261. console.log(result.data);
  262. if (result.data.id) {
  263. this.shopAddress = result.data ? {
  264. province: result.data.province,
  265. city: result.data.city,
  266. area: result.data.dist,
  267. floor: result.data.floor,
  268. address: result.data.address,
  269. lat: result.data.lat,
  270. lng: result.data.long,
  271. wxStoreId: result.data.wx_store_id
  272. } : null;
  273. } else {
  274. this.shopAddress = result.data ? {
  275. province: result.data.address_info.province,
  276. city: result.data.address_info.city,
  277. area: result.data.address_info.area,
  278. street: result.data.address_info.street,
  279. house: result.data.address_info.house,
  280. lat: result.data.address_info.lat,
  281. lng: result.data.address_info.lng,
  282. cityId: result.data.city_id,
  283. orderPattern: result.data.order_pattern,
  284. outStoreId: result.data.out_store_id,
  285. serviceTransPrefer: result.data.service_trans_prefer,
  286. wxStoreId: result.data.wx_store_id
  287. } : null;
  288. console.log(this.shopAddress);
  289. }
  290. } catch (error) {
  291. // console.error('获取门店地址失败:', error);
  292. // 如果接口不存在或失败,设置为null
  293. this.shopAddress = null;
  294. }
  295. },
  296. // 创建门店地址
  297. async createShopAddress() {
  298. try {
  299. uni.showLoading({
  300. title: '创建中...'
  301. });
  302. // 调用创建门店地址API
  303. const result = await createStore({
  304. // 这里可以传入默认的门店信息
  305. shopName: '默认门店',
  306. province: '',
  307. city: '',
  308. address: '',
  309. lat: 0,
  310. lng: 0
  311. });
  312. uni.hideLoading();
  313. if (result.code === 1) {
  314. uni.showToast({
  315. title: '创建成功',
  316. icon: 'success'
  317. });
  318. // 刷新门店信息
  319. await this.getShopAddressInfo();
  320. } else {
  321. if(result.msg && result.msg.includes('address_info.house is empty')){
  322. this.$msg('门店的门牌号未填写')
  323. } else {
  324. console.log(result.message);
  325. uni.showToast({
  326. title: '创建失败',
  327. icon: 'none'
  328. });
  329. }
  330. }
  331. } catch (error) {
  332. uni.hideLoading();
  333. console.error('创建门店地址失败:', error);
  334. uni.showToast({
  335. title: '创建失败,请重试',
  336. icon: 'none'
  337. });
  338. }
  339. },
  340. // 更新门店地址
  341. async updateShopAddressFn() {
  342. try {
  343. uni.showLoading({
  344. title: '更新中...'
  345. });
  346. // 调用更新门店地址API
  347. const result = await updateStore({
  348. id: this.shopAddress.id,
  349. province: this.shopAddress.province,
  350. city: this.shopAddress.city,
  351. address: this.shopAddress.address,
  352. lat: this.shopAddress.lat,
  353. lng: this.shopAddress.lng
  354. });
  355. uni.hideLoading();
  356. if (result.code === 1) {
  357. uni.showToast({
  358. title: '更新成功',
  359. icon: 'success'
  360. });
  361. // 刷新门店信息
  362. await this.getShopAddressInfo();
  363. } else {
  364. console.log(result);
  365. if(result.msg && result.msg.includes('content.address_info.house is empty')){
  366. this.$msg('门店的门牌号未填写')
  367. } else {
  368. console.log(result.msg);
  369. uni.showToast({
  370. title: '更新失败',
  371. icon: 'none'
  372. });
  373. }
  374. }
  375. } catch (error) {
  376. uni.hideLoading();
  377. console.error('更新门店地址失败:', error);
  378. if(error.msg && error.msg.includes('content.address_info.house is empty')){
  379. this.$msg('门店的门牌号未填写')
  380. } else {
  381. console.log(error.msg);
  382. this.$msg('更新失败')
  383. }
  384. }
  385. },
  386. // 获取账户余额
  387. async getBalance() {
  388. try {
  389. const result = await getStoreBalance();
  390. this.balance = result.data.all_balance || 0;
  391. // 获取顺丰和达达的余额
  392. this.sfBalance = result.data.sf_balance || 0;
  393. this.dadaBalance = result.data.dada_balance || 0;
  394. } catch (error) {
  395. console.log(error);
  396. // console.error('获取余额失败:', error);
  397. }
  398. },
  399. // 获取充值记录
  400. async getRechargeRecords() {
  401. try {
  402. // 这里调用实际的API获取充值记录
  403. // const result = await getRechargeRecords();
  404. // this.rechargeRecords = result.data || [];
  405. // 模拟数据
  406. this.rechargeRecords = [
  407. {
  408. amount: 100,
  409. time: '2024-01-15 14:30:25',
  410. status: 'success',
  411. statusText: '充值成功'
  412. },
  413. {
  414. amount: 200,
  415. time: '2024-01-10 09:15:30',
  416. status: 'success',
  417. statusText: '充值成功'
  418. }
  419. ];
  420. } catch (error) {
  421. console.error('获取充值记录失败:', error);
  422. }
  423. },
  424. // 显示充值弹窗
  425. showRechargeModal() {
  426. this.showModal = true;
  427. this.rechargeAmount = '';
  428. this.expressCompany = 'DADA'; // 默认选择顺丰
  429. },
  430. // 隐藏充值弹窗
  431. hideRechargeModal() {
  432. this.showModal = false;
  433. this.rechargeAmount = '';
  434. this.payUrl = '';
  435. this.showPayUrl = false;
  436. },
  437. // 选择跑腿公司
  438. selectExpressCompany(company) {
  439. this.expressCompany = company;
  440. },
  441. // 金额输入处理
  442. onAmountInput(e) {
  443. let value = e.detail.value;
  444. // 限制只能输入数字和小数点
  445. value = value.replace(/[^\d.]/g, '');
  446. // 限制小数点后两位
  447. if (value.includes('.')) {
  448. const parts = value.split('.');
  449. if (parts[1].length > 2) {
  450. value = parts[0] + '.' + parts[1].substring(0, 2);
  451. }
  452. }
  453. this.rechargeAmount = value;
  454. },
  455. // 选择快捷金额
  456. selectAmount(amount) {
  457. this.rechargeAmount = amount.toString();
  458. },
  459. // 确认充值
  460. async confirmRecharge() {
  461. if (!this.canRecharge) {
  462. uni.showToast({
  463. title: '请输入有效金额',
  464. icon: 'none'
  465. });
  466. return;
  467. }
  468. const amount = parseFloat(this.rechargeAmount);
  469. try {
  470. uni.showLoading({
  471. title: '获取中...'
  472. });
  473. // 调用实际的充值API,传入金额和跑腿公司
  474. const result = await rechargeStore({
  475. amount: amount,
  476. expressId: this.expressCompany // 添加跑腿公司参数
  477. });
  478. uni.hideLoading();
  479. if (result.code === 1 && result.data && result.data.payurl) {
  480. // 保存支付链接并显示
  481. this.payUrl = result.data.payurl;
  482. this.showPayUrl = true;
  483. // 不关闭弹窗,而是显示支付链接
  484. } else {
  485. // 充值单生成成功但没有支付链接
  486. uni.showToast({
  487. title: '充值单已生成',
  488. icon: 'success'
  489. });
  490. this.hideRechargeModal();
  491. // 刷新余额和记录
  492. await this.initExpress()
  493. }
  494. } catch (error) {
  495. uni.hideLoading();
  496. console.error('充值失败:', error);
  497. uni.showToast({
  498. title: '充值失败,请重试',
  499. icon: 'none'
  500. });
  501. }
  502. }
  503. },
  504. };
  505. </script>
  506. <style lang="scss" scoped>
  507. .app-content {
  508. min-height: 100vh;
  509. background-color: #f5f5f5;
  510. padding: 20rpx;
  511. }
  512. // 门店地址管理样式
  513. .shop-address-section {
  514. background-color: #ffffff;
  515. border-radius: 20rpx;
  516. padding: 30rpx;
  517. margin-bottom: 30rpx;
  518. box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
  519. }
  520. .section-header {
  521. margin-bottom: 30rpx;
  522. }
  523. .section-title {
  524. color: #333333;
  525. font-size: 32rpx;
  526. font-weight: 600;
  527. }
  528. .shop-info-card {
  529. &.empty {
  530. text-align: center;
  531. padding: 40rpx 0;
  532. }
  533. }
  534. .shop-status {
  535. display: flex;
  536. align-items: center;
  537. justify-content: center;
  538. margin-bottom: 25rpx;
  539. &.success {
  540. .status-icon {
  541. color: #52c41a;
  542. background-color: #f6ffed;
  543. border: 2rpx solid #b7eb8f;
  544. }
  545. }
  546. &.warning {
  547. .status-icon {
  548. color: #faad14;
  549. background-color: #fffbe6;
  550. border: 2rpx solid #ffe58f;
  551. }
  552. }
  553. }
  554. .status-icon {
  555. width: 40rpx;
  556. height: 40rpx;
  557. border-radius: 50%;
  558. display: flex;
  559. align-items: center;
  560. justify-content: center;
  561. font-size: 24rpx;
  562. font-weight: bold;
  563. margin-right: 15rpx;
  564. }
  565. .status-text {
  566. color: #333333;
  567. font-size: 30rpx;
  568. font-weight: 500;
  569. }
  570. .shop-desc {
  571. margin-bottom: 30rpx;
  572. .desc-text {
  573. color: #666666;
  574. font-size: 26rpx;
  575. line-height: 1.5;
  576. }
  577. }
  578. .shop-details {
  579. margin-bottom: 30rpx;
  580. }
  581. .detail-item {
  582. display: flex;
  583. margin-bottom: 15rpx;
  584. &:last-child {
  585. margin-bottom: 0;
  586. }
  587. }
  588. .detail-label {
  589. color: #666666;
  590. font-size: 26rpx;
  591. min-width: 140rpx;
  592. }
  593. .detail-value {
  594. color: #333333;
  595. font-size: 26rpx;
  596. flex: 1;
  597. }
  598. .create-btn, .update-btn {
  599. width: 60%;
  600. height: 80rpx;
  601. border-radius: 40rpx;
  602. border: none;
  603. display: flex;
  604. align-items: center;
  605. justify-content: center;
  606. font-size: 28rpx;
  607. font-weight: 500;
  608. transition: all 0.3s ease;
  609. }
  610. .create-btn {
  611. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  612. box-shadow: 0 8rpx 24rpx rgba(102, 126, 234, 0.3);
  613. .btn-text {
  614. color: #ffffff;
  615. }
  616. &:active {
  617. transform: translateY(2rpx);
  618. box-shadow: 0 4rpx 12rpx rgba(102, 126, 234, 0.3);
  619. }
  620. }
  621. .update-btn {
  622. background: linear-gradient(135deg, #52c41a 0%, #389e0d 100%);
  623. box-shadow: 0 8rpx 24rpx rgba(82, 196, 26, 0.3);
  624. .btn-text {
  625. color: #ffffff;
  626. }
  627. &:active {
  628. transform: translateY(2rpx);
  629. box-shadow: 0 4rpx 12rpx rgba(82, 196, 26, 0.3);
  630. }
  631. }
  632. // 余额卡片样式
  633. .balance-card {
  634. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  635. border-radius: 20rpx;
  636. padding: 40rpx 30rpx;
  637. margin-bottom: 30rpx;
  638. box-shadow: 0 8rpx 32rpx rgba(102, 126, 234, 0.3);
  639. display: flex;
  640. justify-content: space-between;
  641. }
  642. .balance-left {
  643. flex: 1;
  644. }
  645. .balance-right {
  646. width: 200rpx;
  647. display: flex;
  648. flex-direction: column;
  649. justify-content: center;
  650. border-left: 2rpx solid rgba(255, 255, 255, 0.2);
  651. padding-left: 30rpx;
  652. margin-left: 20rpx;
  653. }
  654. .balance-header {
  655. display: flex;
  656. align-items: center;
  657. margin-bottom: 20rpx;
  658. }
  659. .balance-title {
  660. color: rgba(255, 255, 255, 0.9);
  661. font-size: 28rpx;
  662. font-weight: 400;
  663. }
  664. .balance-amount {
  665. margin-bottom: 15rpx;
  666. display: flex;
  667. align-items: baseline;
  668. }
  669. .amount-text {
  670. color: #ffffff;
  671. font-size: 60rpx;
  672. font-weight: 600;
  673. font-family: 'DIN Alternate', sans-serif;
  674. }
  675. .balance-unit {
  676. color: rgba(255, 255, 255, 0.7);
  677. font-size: 24rpx;
  678. margin-left: 10rpx;
  679. }
  680. .balance-desc {
  681. .desc-text {
  682. color: rgba(255, 255, 255, 0.8);
  683. font-size: 21rpx;
  684. }
  685. }
  686. .sub-balance {
  687. display: flex;
  688. flex-direction: column;
  689. padding: 10rpx 0;
  690. &.sf {
  691. margin-bottom: 20rpx;
  692. padding-bottom: 20rpx;
  693. border-bottom: 2rpx solid rgba(255, 255, 255, 0.2);
  694. }
  695. }
  696. .sub-balance-label {
  697. color: rgba(255, 255, 255, 0.8);
  698. font-size: 24rpx;
  699. margin-bottom: 8rpx;
  700. }
  701. .sub-balance-amount {
  702. color: #ffffff;
  703. font-size: 32rpx;
  704. font-weight: 600;
  705. font-family: 'DIN Alternate', sans-serif;
  706. }
  707. // 充值按钮样式
  708. .recharge-section {
  709. margin-bottom: 30rpx;
  710. }
  711. .recharge-btn {
  712. width: 60%;
  713. height: 88rpx;
  714. background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%);
  715. border-radius: 44rpx;
  716. border: none;
  717. display: flex;
  718. align-items: center;
  719. justify-content: center;
  720. box-shadow: 0 8rpx 24rpx rgba(255, 107, 107, 0.3);
  721. transition: all 0.3s ease;
  722. }
  723. .recharge-btn:active {
  724. transform: translateY(2rpx);
  725. box-shadow: 0 4rpx 12rpx rgba(255, 107, 107, 0.3);
  726. }
  727. .btn-text {
  728. color: #ffffff;
  729. font-size: 32rpx;
  730. font-weight: 600;
  731. }
  732. // 记录区域样式
  733. .record-section {
  734. background-color: #ffffff;
  735. border-radius: 20rpx;
  736. padding: 30rpx;
  737. box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
  738. }
  739. .record-list {
  740. .record-item {
  741. display: flex;
  742. justify-content: space-between;
  743. align-items: center;
  744. padding: 25rpx 0;
  745. border-bottom: 1rpx solid #f0f0f0;
  746. &:last-child {
  747. border-bottom: none;
  748. }
  749. }
  750. .record-info {
  751. display: flex;
  752. flex-direction: column;
  753. }
  754. .record-amount {
  755. color: #333333;
  756. font-size: 30rpx;
  757. font-weight: 600;
  758. margin-bottom: 8rpx;
  759. }
  760. .record-time {
  761. color: #999999;
  762. font-size: 24rpx;
  763. }
  764. .record-status {
  765. font-size: 26rpx;
  766. padding: 8rpx 16rpx;
  767. border-radius: 20rpx;
  768. &.success {
  769. color: #52c41a;
  770. background-color: #f6ffed;
  771. }
  772. &.pending {
  773. color: #faad14;
  774. background-color: #fffbe6;
  775. }
  776. &.failed {
  777. color: #ff4d4f;
  778. background-color: #fff2f0;
  779. }
  780. }
  781. }
  782. .empty-record {
  783. text-align: center;
  784. padding: 60rpx 0;
  785. .empty-text {
  786. color: #999999;
  787. font-size: 28rpx;
  788. }
  789. }
  790. // 支付链接样式
  791. .pay-url-section {
  792. padding: 20rpx 0;
  793. }
  794. .pay-url-title {
  795. margin-bottom: 20rpx;
  796. text-align: center;
  797. text {
  798. color: #333333;
  799. font-size: 28rpx;
  800. }
  801. }
  802. .pay-url-box {
  803. background-color: #f5f5f5;
  804. border-radius: 12rpx;
  805. padding: 20rpx;
  806. margin-bottom: 30rpx;
  807. word-break: break-all;
  808. border: 2rpx dashed #ddd;
  809. }
  810. .pay-url-text {
  811. color: #0066cc;
  812. font-size: 26rpx;
  813. line-height: 1.5;
  814. }
  815. .copy-btn-wrapper {
  816. display: flex;
  817. justify-content: center;
  818. }
  819. .copy-btn {
  820. width: 60%;
  821. height: 80rpx;
  822. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  823. border-radius: 40rpx;
  824. display: flex;
  825. align-items: center;
  826. justify-content: center;
  827. box-shadow: 0 8rpx 16rpx rgba(102, 126, 234, 0.3);
  828. transition: all 0.3s ease;
  829. &:active {
  830. transform: translateY(2rpx);
  831. box-shadow: 0 4rpx 8rpx rgba(102, 126, 234, 0.3);
  832. }
  833. }
  834. .copy-btn-text {
  835. color: #ffffff;
  836. font-size: 28rpx;
  837. font-weight: 500;
  838. }
  839. // 弹窗样式
  840. .modal-overlay {
  841. position: fixed;
  842. top: 0;
  843. left: 0;
  844. right: 0;
  845. bottom: 0;
  846. background-color: rgba(0, 0, 0, 0.5);
  847. display: flex;
  848. align-items: center;
  849. justify-content: center;
  850. z-index: 9999;
  851. }
  852. .modal-content {
  853. width: 600rpx;
  854. background-color: #ffffff;
  855. border-radius: 20rpx;
  856. overflow: hidden;
  857. animation: modalSlideIn 0.3s ease;
  858. }
  859. @keyframes modalSlideIn {
  860. from {
  861. opacity: 0;
  862. transform: scale(0.8) translateY(50rpx);
  863. }
  864. to {
  865. opacity: 1;
  866. transform: scale(1) translateY(0);
  867. }
  868. }
  869. .modal-header {
  870. display: flex;
  871. justify-content: space-between;
  872. align-items: center;
  873. padding: 30rpx;
  874. border-bottom: 1rpx solid #f0f0f0;
  875. }
  876. .modal-title {
  877. color: #333333;
  878. font-size: 32rpx;
  879. font-weight: 600;
  880. }
  881. .modal-close {
  882. color: #999999;
  883. font-size: 40rpx;
  884. line-height: 1;
  885. padding: 10rpx;
  886. }
  887. .modal-body {
  888. padding: 30rpx;
  889. }
  890. .form-item {
  891. margin-bottom: 30rpx;
  892. }
  893. .form-label {
  894. display: block;
  895. color: #333333;
  896. font-size: 28rpx;
  897. font-weight: 500;
  898. margin-bottom: 20rpx;
  899. }
  900. .amount-input-wrapper {
  901. display: flex;
  902. align-items: center;
  903. border: 2rpx solid #e8e8e8;
  904. border-radius: 12rpx;
  905. padding: 0 20rpx;
  906. background-color: #fafafa;
  907. transition: all 0.3s ease;
  908. &:focus-within {
  909. border-color: #667eea;
  910. background-color: #ffffff;
  911. }
  912. }
  913. .currency-symbol {
  914. color: #333333;
  915. font-size: 32rpx;
  916. font-weight: 600;
  917. margin-right: 15rpx;
  918. }
  919. .amount-input {
  920. flex: 1;
  921. height: 80rpx;
  922. font-size: 32rpx;
  923. color: #333333;
  924. background: transparent;
  925. border: none;
  926. }
  927. .quick-amounts {
  928. margin-top: 30rpx;
  929. }
  930. .quick-title {
  931. display: block;
  932. color: #666666;
  933. font-size: 26rpx;
  934. margin-bottom: 20rpx;
  935. }
  936. .amount-options {
  937. display: flex;
  938. flex-wrap: wrap;
  939. gap: 20rpx;
  940. }
  941. .amount-option {
  942. flex: 1;
  943. min-width: 120rpx;
  944. height: 70rpx;
  945. border: 2rpx solid #e8e8e8;
  946. border-radius: 12rpx;
  947. display: flex;
  948. align-items: center;
  949. justify-content: center;
  950. background-color: #ffffff;
  951. transition: all 0.3s ease;
  952. &.active {
  953. border-color: #667eea;
  954. background-color: #667eea;
  955. .option-text {
  956. color: #ffffff;
  957. }
  958. }
  959. &:active {
  960. transform: scale(0.95);
  961. }
  962. }
  963. .option-text {
  964. color: #333333;
  965. font-size: 26rpx;
  966. font-weight: 500;
  967. }
  968. // 跑腿公司选择样式
  969. .express-company-options {
  970. display: flex;
  971. flex-direction: row;
  972. gap: 30rpx;
  973. margin-bottom: 20rpx;
  974. }
  975. .express-option {
  976. height: 80rpx;
  977. border: 2rpx solid #e8e8e8;
  978. border-radius: 12rpx;
  979. display: flex;
  980. align-items: center;
  981. padding: 0 20rpx;
  982. background-color: #ffffff;
  983. transition: all 0.3s ease;
  984. &.active {
  985. border-color: #667eea;
  986. background-color: #f0f4ff;
  987. .express-option-text {
  988. color: #667eea;
  989. }
  990. }
  991. &:active {
  992. transform: scale(0.98);
  993. }
  994. }
  995. .express-option-text {
  996. color: #333333;
  997. font-size: 28rpx;
  998. font-weight: 500;
  999. }
  1000. .modal-footer {
  1001. display: flex;
  1002. border-top: 1rpx solid #f0f0f0;
  1003. }
  1004. .cancel-btn, .confirm-btn {
  1005. flex: 1;
  1006. height: 88rpx;
  1007. border: 1rpx solid #e8e8e8;
  1008. border-radius: 8rpx;
  1009. font-size: 30rpx;
  1010. font-weight: 500;
  1011. display: flex;
  1012. align-items: center;
  1013. justify-content: center;
  1014. }
  1015. .cancel-btn {
  1016. background-color: #f5f5f5;
  1017. .cancel-text {
  1018. color: #666666;
  1019. }
  1020. }
  1021. .confirm-btn {
  1022. background-color: #52c41a;
  1023. .confirm-text {
  1024. color: #666666;
  1025. }
  1026. &:disabled {
  1027. background-color: #f5f5f5 !important;
  1028. .confirm-text {
  1029. color: #666666 !important;
  1030. }
  1031. }
  1032. }
  1033. </style>