account.uvue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. <template>
  2. <view class="page-container">
  3. <!-- 1. 资产卡片区域 -->
  4. <view class="income-section ">
  5. <view class="asset-card">
  6. <!-- 总资产 -->
  7. <view class="total-asset-section row-between">
  8. <view>
  9. <view class="row-start">
  10. <text class="label">
  11. 我的资产(元)
  12. </text>
  13. <u-icon v-if="isShowAmount" name="view" :size="20" @click="toggleShowAmount" />
  14. <u-icon v-else name="view_off" :size="20" @click="toggleShowAmount" />
  15. </view>
  16. <text class="amount" style="margin-top: 20rpx;">
  17. {{ isShowAmount ? totalAsset : '***' }}
  18. </text>
  19. </view>
  20. <view class="refresh-btn row-center" @click="refreshData">
  21. <u-icon name="sync" :size="18" />
  22. <text>
  23. 刷新
  24. </text>
  25. </view>
  26. </view>
  27. </view>
  28. <!-- 累计收益 & 打车费 -->
  29. <image class="bg-image" src="/static/imagesInfo/zh-bg.png">
  30. </image>
  31. <view class="detail-container row-start ">
  32. <!-- 左侧:累计收益 -->
  33. <view class="income-item column ">
  34. <view class="income-header-content">
  35. <view class="row-start" style="margin-top: 30rpx;">
  36. <text class="income-label">
  37. 累计收益(元)
  38. </text>
  39. <u-icon name="hollowquery" :size="16" color="#999" @click="openIncomePopup" />
  40. </view>
  41. <view class="income-main row-between">
  42. <text class="income-value">
  43. {{ cumulativeIncome }}
  44. </text>
  45. <view class="withdraw-btn" @click="handleWithdraw('income')">
  46. 提现
  47. </view>
  48. </view>
  49. </view>
  50. <view class="income-detail row-start">
  51. <image class="jine-bg" src="/static/imagesInfo/jine-bg.png" mode="widthFix">
  52. </image>
  53. <view class="detail-item column-center">
  54. <text class="detail-label">
  55. 冻结(元)
  56. </text>
  57. <text class="detail-value">
  58. {{ frozenIncome }}
  59. </text>
  60. </view>
  61. <view class="divider">
  62. </view>
  63. <view class="detail-item column-center">
  64. <text class="detail-label">
  65. 可提现(元)
  66. </text>
  67. <text class="detail-value">
  68. {{ availableIncome }}
  69. </text>
  70. </view>
  71. </view>
  72. </view>
  73. <!-- 右侧:打车费 -->
  74. <view class="income-item column " style="padding-left: 20rpx;">
  75. <view class=" row-start" style="margin-top: 30rpx;">
  76. <text class="income-label">
  77. 打车费(元)
  78. </text>
  79. <u-icon name="hollowquery" :size="16" color="#999" @click="openTaxiPopup" />
  80. </view>
  81. <view class="income-main row-between">
  82. <text class="income-value">
  83. {{ taxiFee }}
  84. </text>
  85. <view class="transfer-btn" @click="handleTransfer('taxi')">
  86. 转出
  87. </view>
  88. </view>
  89. <view class="income-detail row-start">
  90. <image class="jine-bg" src="/static/imagesInfo/jine-bg.png" mode="widthFix">
  91. </image>
  92. <view class="detail-item column-center">
  93. <text class="detail-label">
  94. 冻结(元)
  95. </text>
  96. <text class="detail-value">
  97. {{ frozenTaxi }}
  98. </text>
  99. </view>
  100. <view class="divider">
  101. </view>
  102. <view class="detail-item column-center">
  103. <text class="detail-label">
  104. 可使用(元)
  105. </text>
  106. <text class="detail-value">
  107. {{ availableTaxi }}
  108. </text>
  109. </view>
  110. </view>
  111. </view>
  112. </view>
  113. <view class="record-entry row-between" @click="viewWithdrawRecords">
  114. <text>
  115. 提现记录
  116. </text>
  117. <text>
  118. >
  119. </text>
  120. </view>
  121. </view>
  122. <!-- 提现记录入口 -->
  123. <!-- 2. 本月账单标题 -->
  124. <view class="bill-header row-between">
  125. <text class="bill-title">
  126. 本月账单
  127. </text>
  128. <text class="view-all" @click="viewAllBills">
  129. 查看全部
  130. </text>
  131. </view>
  132. <!-- 3. 账单列表 -->
  133. <view class="bill-list column">
  134. <view v-for="(bill, idx) in bills" :key="idx" class="bill-card column">
  135. <!-- 订单号行 -->
  136. <view class="order-id-row row-between">
  137. <text class="split-type">
  138. 订单号:{{ bill.orderId }}
  139. </text>
  140. <text>
  141. >
  142. </text>
  143. </view>
  144. <!-- 项目与金额 -->
  145. <view class="project-amount-row row-between">
  146. <text class="project-name">
  147. {{ bill.projectName }}
  148. </text>
  149. <text :class="['amount', bill.amount > 0 ? 'positive' : 'negative']">
  150. {{ bill.amount > 0 ? '+' : '' }}{{ Math.abs(bill.amount).toFixed(2) }}
  151. </text>
  152. </view>
  153. <!-- 分成说明 -->
  154. <view class="split-info row-between">
  155. <text class="split-type">
  156. {{ bill.splitType }}
  157. </text>
  158. <text class="split-type">
  159. {{ bill.splitDetail }}
  160. </text>
  161. </view>
  162. <!-- 记录时间 -->
  163. <view class="time-row row-between">
  164. <text class="split-type">
  165. 记录时间
  166. </text>
  167. <text class="split-type">
  168. {{ bill.recordTime }}
  169. </text>
  170. </view>
  171. </view>
  172. </view>
  173. </view>
  174. </template>
  175. <script setup lang="uts">
  176. import { ref } from 'vue';
  177. import { getCoachWallteInfo, getCoachTransRecords } from '@/utils/api/account'
  178. // --- 数据定义 ---
  179. const totalAsset = ref('0');
  180. const cumulativeIncome = ref('0');
  181. const frozenIncome = ref('0');
  182. const availableIncome = ref('0');
  183. const taxiFee = ref('0');
  184. const frozenTaxi = ref('0');
  185. const availableTaxi = ref('0');
  186. const isShowAmount = ref(true);
  187. type BillItem = {
  188. orderId : string;
  189. projectName : string;
  190. amount : number;
  191. splitType : string;
  192. splitDetail : string;
  193. recordTime : string;
  194. };
  195. const bills = ref([
  196. {
  197. orderId: '202506091311123009874638',
  198. projectName: '中式推拿',
  199. amount: 170.00,
  200. splitType: '首单分成',
  201. splitDetail: '基本套餐车费收入 x90%=20\n项目套餐收入 x50%=150',
  202. recordTime: '2025-06-09 13:58'
  203. },
  204. {
  205. orderId: '202506091311123009874638',
  206. projectName: '中式推拿',
  207. amount: 150.00,
  208. splitType: '加钟分成',
  209. splitDetail: '项目套餐收入 x71%+(70%+等级v1)=150',
  210. recordTime: '2025-06-09 13:58'
  211. },
  212. {
  213. orderId: '202506091311123009874638',
  214. projectName: '中式推拿订单退款',
  215. amount: -150.00,
  216. splitType: '首单分成',
  217. splitDetail: '基本套餐车费收入 x90%=20\n项目套餐收入 x50%=150',
  218. recordTime: '2025-06-09 13:58'
  219. },
  220. {
  221. orderId: '',
  222. projectName: '打车费转出',
  223. amount: -50.00,
  224. splitType: '分成',
  225. splitDetail: '打车费转出刘大锤账户:45.00元\n费率:0.1 手续费:5.00元',
  226. recordTime: '2025-06-09 13:58'
  227. }
  228. ] as BillItem[]); // 如果自动推断不准,可以在末尾加 'as BillItem[]' 进行断言
  229. // --- 方法定义 ---
  230. const walletInfo = ref<UTSJSONObject | null>(null)
  231. const httpGetWalletInfo = async () => {
  232. try {
  233. const res = await getCoachWallteInfo() as UTSJSONObject;
  234. const code = res["code"] as number;
  235. const data = res["data"] as UTSJSONObject;
  236. if (code === 200) {
  237. walletInfo.value = data;
  238. // 赋值到页面变量
  239. totalAsset.value = data.total_balance as string ;
  240. cumulativeIncome.value = data.total_income as string ;
  241. frozenIncome.value = data.frozen_amount as string ;
  242. availableIncome.value = data.available_balance as string;
  243. taxiFee.value = data.travel_balance as string ;
  244. frozenTaxi.value = data.travel_frozen_balance as string ;
  245. availableTaxi.value = (parseFloat(data.travel_balance as string ) - parseFloat(data.travel_frozen_balance as string )).toFixed(2);
  246. } else {
  247. uni.showToast({
  248. title: '获取钱包信息失败',
  249. icon: 'none'
  250. });
  251. }
  252. } catch (err : any) {
  253. console.error('获取技师钱包信息异常', err);
  254. uni.showToast({
  255. title: '请求失败',
  256. icon: 'none'
  257. });
  258. }
  259. };
  260. // 获取本月账单接口
  261. const billRecords = ref<any[]>([]);
  262. const httpGetBillRecords = async (params: UTSJSONObject) => {
  263. try {
  264. const res = await getCoachTransRecords(params) as UTSJSONObject;
  265. const code = res["code"] as number;
  266. const data = res["data"] as any[];
  267. if (code == 200) {
  268. billRecords.value = data;
  269. } else {
  270. uni.showToast({
  271. title: '获取本月账单失败',
  272. icon: 'none'
  273. });
  274. }
  275. } catch (err : any) {
  276. console.error('获取本月账单异常', err);
  277. uni.showToast({
  278. title: '请求失败,请稍后重试',
  279. icon: 'none'
  280. });
  281. }
  282. };
  283. const refreshData = () => {
  284. uni.showLoading({ title: '刷新中...' });
  285. setTimeout(() => {
  286. uni.hideLoading();
  287. uni.showToast({ title: '刷新成功', icon: 'success' });
  288. httpGetWalletInfo();
  289. httpGetBillRecords({});
  290. }, 800);
  291. };
  292. const handleWithdraw = (type : string) => {
  293. const amount = type === 'income' ? availableIncome.value : '0';
  294. uni.showModal({
  295. title: '提现确认',
  296. content: `确定要提现 ${amount} 元吗?`,
  297. success: (res) => {
  298. if (res.confirm) {
  299. uni.navigateTo({
  300. url: '/pages/account/withdraw'
  301. });
  302. }
  303. }
  304. });
  305. };
  306. const handleTransfer = (type : string) => {
  307. uni.navigateTo({
  308. url: '/pages/account/transfer'
  309. });
  310. };
  311. const viewWithdrawRecords = () => {
  312. uni.showToast({ title: '查看提现记录', icon: 'none' });
  313. };
  314. const viewAllBills = () => {
  315. uni.navigateTo({
  316. url: '/pages/account/bill-list'
  317. });
  318. };
  319. const toggleShowAmount = () => {
  320. console.log('toggleShowAmount', isShowAmount.value);
  321. isShowAmount.value = !isShowAmount.value;
  322. };
  323. const openIncomePopup = () => {
  324. uni.showModal({
  325. title: '我的收益',
  326. content: '我的收益包含订单分成、加钟收益+佣金收益+红包收益+车费收益。\n\n特殊说明:\n1、红包收益是商户拉新用户时平台直接奖励的,直接进入可提现余额,无冻结情况。\n2、未到账、提现中等金额属于冻结余额。',
  327. showCancel: false,
  328. confirmText: '我知道了'
  329. });
  330. };
  331. const openTaxiPopup = () => {
  332. uni.showModal({
  333. title: '车费说明',
  334. content: '1、车费主要是用户在小叮当下支付的打车费(不包含公交车费)将会进入商户的打车收益中。\n\n2、打车费可以转到我的收益里提现,提现平台将收取10%的手续费。\n\n3、车费收入为100%商户个人收入,长期以来一直是平台代商户缴纳该部分的个人经营所得税,技师提现打车费余额,平台将会代收10%的税费扣款。\n\n4、当商户长时间不接单时,打车费余额存在负数时,将优先将技师的提现余额进行抵扣,达到冲正效果。\n\n5、单程车费不超过500元,超出部分需要技师个人承担车费。',
  335. showCancel: false,
  336. confirmText: '我知道了'
  337. });
  338. };
  339. onLoad(() => {
  340. httpGetWalletInfo();
  341. httpGetBillRecords({});
  342. });
  343. </script>
  344. <style>
  345. /*
  346. ⚠️ UniApp X 样式规范:
  347. 1. 不写 display: flex (view 默认就是)
  348. 2. 不写 display: block/inline-block
  349. 3. 布局靠 flex-direction (默认 column, 需 row 时手动改)
  350. 4. 不写 border-radius: 50% (用具体数值)
  351. 5. 只用类名选择器
  352. */
  353. /* --- 辅助布局类 (核心) --- */
  354. .row-between {
  355. flex-direction: row;
  356. justify-content: space-between;
  357. align-items: center;
  358. }
  359. .row-start {
  360. flex-direction: row;
  361. align-items: center;
  362. }
  363. .row-center {
  364. flex-direction: row;
  365. justify-content: center;
  366. align-items: center;
  367. }
  368. .column {
  369. flex-direction: column;
  370. }
  371. .column-center {
  372. flex-direction: column;
  373. justify-content: center;
  374. align-items: center;
  375. }
  376. /* --- 页面容器 --- */
  377. .page-container {
  378. background-color: rgba(246, 246, 244, 0.5);
  379. padding-bottom: 40rpx;
  380. padding: 20rpx;
  381. }
  382. /* --- 资产卡片 --- */
  383. .asset-card {
  384. /* background: linear-gradient(to right, rgba(255, 249, 225, 1), rgba(255, 241, 191, 1));
  385. margin: 20rpx;
  386. border-radius: 16rpx;
  387. padding: 30rpx;
  388. box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
  389. */
  390. padding: 0 20rpx;
  391. }
  392. .total-asset-section {
  393. background: linear-gradient(to bottom, rgba(253, 252, 246, 1) ,rgba(254, 249, 234, 1));
  394. padding: 30rpx 20rpx 20rpx;
  395. border-radius: 16rpx 16rpx 0 0;
  396. box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
  397. } rgba(254, 249, 234, 1)
  398. .label {
  399. font-size: 26rpx;
  400. color: #666;
  401. }
  402. .amount {
  403. font-size: 48rpx;
  404. font-weight: bold;
  405. color: #333;
  406. }
  407. .refresh-btn {
  408. padding: 10rpx 20rpx;
  409. border-radius: 30rpx;
  410. border: 1rpx solid #ddd;
  411. font-size: 24rpx;
  412. color: #333;
  413. }
  414. /* 收益分区 */
  415. .income-section {
  416. /* gap: 30rpx; */
  417. margin-bottom: 20rpx;
  418. position: relative;
  419. }
  420. .bg-image {
  421. width: 100%;
  422. height: 400rpx;
  423. position: absolute;
  424. top: 28%;
  425. left: 0;
  426. }
  427. .detail-container{
  428. padding:0 20rpx 20rpx;
  429. }
  430. .income-item {
  431. flex: 1;
  432. /* gap: 15rpx; */
  433. }
  434. .income-label {
  435. font-size: 26rpx;
  436. }
  437. .income-main {
  438. margin-top:20rpx;
  439. }
  440. .income-value {
  441. font-size: 40rpx;
  442. font-weight: bold;
  443. color: #333;
  444. }
  445. .withdraw-btn,
  446. .transfer-btn {
  447. font-size: 28rpx;
  448. padding: 6rpx 22rpx;
  449. border-radius: 26rpx;
  450. background: #FFFCEE;
  451. border: 1rpx solid;
  452. }
  453. .withdraw-btn {
  454. color: #111111ff;
  455. border-color: #fff;
  456. }
  457. .jine-bg {
  458. width: 320rpx;
  459. height: 100%;
  460. position: absolute;
  461. top: 0;
  462. left: 0;
  463. }
  464. .transfer-btn {
  465. color: #101010ff;
  466. border-color: #fff;
  467. }
  468. /* 明细部分 */
  469. .income-detail {
  470. padding: 20rpx;
  471. position: relative;
  472. margin-top: 10rpx;
  473. justify-content: space-between;
  474. }
  475. .income-header-content {
  476. padding: 0 20rpx 0 10rpx;
  477. border-right-width: 2rpx;
  478. border-right-color: #979797;
  479. border-right-style: solid;
  480. }
  481. .detail-label {
  482. font-size: 24rpx;
  483. color: #666;
  484. }
  485. .detail-value {
  486. /* font-size: 28rpx; */
  487. font-weight: bold;
  488. }
  489. .divider {
  490. width: 1rpx;
  491. background: #ddd;
  492. margin: 0 10rpx;
  493. }
  494. /* 提现记录入口 */
  495. .record-entry {
  496. padding: 20rpx 30rpx 30rpx ;
  497. font-size: 28rpx;
  498. color: #333;
  499. /* background: #fff; */
  500. }
  501. /* --- 账单标题 --- */
  502. .bill-header {
  503. padding: 0 30rpx;
  504. /* margin-top: 20rpx; */
  505. }
  506. .view-all {
  507. font-size: 26rpx;
  508. color: #666;
  509. }
  510. /* --- 账单列表 --- */
  511. .bill-list {
  512. padding: 0 20rpx;
  513. /* gap: 20rpx; */
  514. }
  515. .bill-card {
  516. background: #ffffff;
  517. border-radius: 20rpx;
  518. padding: 30rpx;
  519. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
  520. margin-top: 20rpx;
  521. }
  522. .order-id-row {
  523. font-size: 26rpx;
  524. padding: 10rpx 0 20rpx 0;
  525. border-bottom: 1rpx solid #eee;
  526. }
  527. .project-amount-row {
  528. margin-top: 20rpx;
  529. }
  530. .project-name {
  531. font-size: 30rpx;
  532. }
  533. .amount.positive {
  534. color: #ff4d4f;
  535. font-size: 32rpx;
  536. }
  537. .amount.negative {
  538. color: #333;
  539. font-size: 32rpx;
  540. }
  541. .split-info {
  542. font-size: 24rpx;
  543. color: #999;
  544. line-height: 1.4;
  545. }
  546. .split-type {
  547. font-size: 26rpx;
  548. color: #999;
  549. }
  550. .time-row {
  551. font-size: 26rpx;
  552. color: #999;
  553. }
  554. </style>