wallet.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. <!-- 分销 - 佣金明细 -->
  2. <template>
  3. <s-layout class="wallet-wrap" title="佣金">
  4. <!-- 钱包卡片 -->
  5. <view class="header-box ss-flex ss-row-center ss-col-center">
  6. <view class="card-box ui-BG-Main ui-Shadow-Main">
  7. <view class="card-head ss-flex ss-col-center">
  8. <view class="card-title ss-m-r-10">当前佣金(元)</view>
  9. <view
  10. @tap="state.showMoney = !state.showMoney"
  11. class="ss-eye-icon"
  12. :class="state.showMoney ? 'cicon-eye' : 'cicon-eye-off'"
  13. />
  14. </view>
  15. <view class="ss-flex ss-row-between ss-col-center ss-m-t-30">
  16. <view class="money-num">{{
  17. state.showMoney ? fen2yuan(state.summary.withdrawPrice || 0) : '*****'
  18. }}</view>
  19. <view class="ss-flex">
  20. <view class="ss-m-r-20">
  21. <button
  22. class="ss-reset-button withdraw-btn"
  23. @tap="sheep.$router.go('/pages/commission/withdraw')"
  24. >
  25. 提现
  26. </button>
  27. </view>
  28. <button class="ss-reset-button balance-btn ss-m-l-20" @tap="state.showModal = true">
  29. 转余额
  30. </button>
  31. </view>
  32. </view>
  33. <view class="ss-flex">
  34. <view class="loading-money">
  35. <view class="loading-money-title">冻结佣金</view>
  36. <view class="loading-money-num">
  37. {{ state.showMoney ? fen2yuan(state.summary.frozenPrice || 0) : '*****' }}
  38. </view>
  39. </view>
  40. <view class="loading-money ss-m-l-100">
  41. <view class="loading-money-title">可提现佣金</view>
  42. <view class="loading-money-num">
  43. {{ state.showMoney ? fen2yuan(state.summary.brokeragePrice || 0) : '*****' }}
  44. </view>
  45. </view>
  46. </view>
  47. </view>
  48. </view>
  49. <su-sticky>
  50. <!-- 统计 -->
  51. <view class="filter-box ss-p-x-30 ss-flex ss-col-center ss-row-between">
  52. <uni-datetime-picker
  53. v-model="state.date"
  54. type="daterange"
  55. @change="onChangeTime"
  56. :end="state.today"
  57. >
  58. <button class="ss-reset-button date-btn">
  59. <text>{{ dateFilterText }}</text>
  60. <text class="cicon-drop-down ss-seldate-icon" />
  61. </button>
  62. </uni-datetime-picker>
  63. <view class="total-box">
  64. <!-- TODO 芋艿:【钱包-可优化】这里暂时不考虑做 -->
  65. <!-- <view class="ss-m-b-10">总收入¥{{ state.pagination.income.toFixed(2) }}</view> -->
  66. <!-- <view>总支出¥{{ (-state.pagination.expense).toFixed(2) }}</view> -->
  67. </view>
  68. </view>
  69. <su-tabs
  70. :list="tabMaps"
  71. @change="onChangeTab"
  72. :scrollable="false"
  73. :current="state.currentTab"
  74. />
  75. </su-sticky>
  76. <s-empty
  77. v-if="state.pagination.total === 0"
  78. icon="/static/data-empty.png"
  79. text="暂无数据"
  80. ></s-empty>
  81. <!-- 转余额弹框 -->
  82. <su-popup
  83. :show="state.showModal"
  84. type="bottom"
  85. round="20"
  86. @close="state.showModal = false"
  87. showClose
  88. >
  89. <view class="ss-p-x-20 ss-p-y-30">
  90. <view class="model-title ss-m-b-30 ss-m-l-20">转余额</view>
  91. <view class="model-subtitle ss-m-b-100 ss-m-l-20">将您的佣金转到余额中继续消费</view>
  92. <view class="input-box ss-flex ss-col-center border-bottom ss-m-b-70 ss-m-x-20">
  93. <view class="unit">¥</view>
  94. <uni-easyinput
  95. :inputBorder="false"
  96. class="ss-flex-1 ss-p-l-10"
  97. v-model="state.price"
  98. type="number"
  99. placeholder="请输入金额"
  100. />
  101. </view>
  102. <button
  103. class="ss-reset-button model-btn ui-BG-Main-Gradient ui-Shadow-Main"
  104. @tap="onConfirm"
  105. >
  106. 确定
  107. </button>
  108. </view>
  109. </su-popup>
  110. <!-- 钱包记录 -->
  111. <view v-if="state.pagination.total > 0">
  112. <!-- 分佣列表 -->
  113. <view v-if="state.currentTab === 0">
  114. <view
  115. class="wallet-list ss-flex border-bottom"
  116. v-for="item in state.pagination.list"
  117. :key="item.id"
  118. >
  119. <view class="list-content">
  120. <view class="title-box ss-flex ss-row-between ss-m-b-20">
  121. <text class="title ss-line-1">{{ item.title }}</text>
  122. <view class="money">
  123. <text v-if="item.price >= 0" class="add">+{{ fen2yuan(item.price) }}</text>
  124. <text v-else class="minus">{{ fen2yuan(item.price) }}</text>
  125. </view>
  126. </view>
  127. <view class="ss-flex ss-row-between ss-col-center">
  128. <text class="time">
  129. {{ sheep.$helper.timeFormat(item.createTime, 'yyyy-mm-dd hh:MM:ss') }}
  130. </text>
  131. <view class="ss-flex ss-col-center">
  132. <text class="status" :class="'status-' + item.status">{{ item.statusName }}</text>
  133. </view>
  134. </view>
  135. </view>
  136. </view>
  137. </view>
  138. <!-- 提现列表 -->
  139. <view v-else>
  140. <view
  141. class="wallet-list ss-flex border-bottom"
  142. v-for="item in state.pagination.list"
  143. :key="item.id"
  144. >
  145. <view class="list-content">
  146. <view class="title-box ss-flex ss-row-between ss-m-b-20">
  147. <text class="title ss-line-1">{{ item.typeName }}</text>
  148. <view class="money">
  149. <text class="minus">{{ fen2yuan(item.price) }}</text>
  150. </view>
  151. </view>
  152. <view class="ss-flex ss-row-between ss-col-center">
  153. <text class="time">
  154. {{ sheep.$helper.timeFormat(item.createTime, 'yyyy-mm-dd hh:MM:ss') }}
  155. </text>
  156. <button
  157. v-if="item.status === 10 && item.type === 5 && item.payTransferId > 0"
  158. class="ss-reset-button confirm-btn ss-m-l-20"
  159. @tap="onRequestMerchantTransfer(item)"
  160. >
  161. 确认收款
  162. </button>
  163. <text v-else class="status" :class="'status-' + item.status">{{
  164. item.statusName
  165. }}</text>
  166. </view>
  167. </view>
  168. </view>
  169. </view>
  170. </view>
  171. <!-- <u-gap></u-gap> -->
  172. <uni-load-more
  173. v-if="state.pagination.total > 0"
  174. :status="state.loadStatus"
  175. :content-text="{
  176. contentdown: '上拉加载更多',
  177. }"
  178. />
  179. </s-layout>
  180. </template>
  181. <script setup>
  182. import { computed, reactive } from 'vue';
  183. import { onLoad, onReachBottom } from '@dcloudio/uni-app';
  184. import sheep from '@/sheep';
  185. import dayjs from 'dayjs';
  186. import { concat } from 'lodash-es';
  187. import BrokerageApi from '@/sheep/api/trade/brokerage';
  188. import { fen2yuan } from '@/sheep/hooks/useGoods';
  189. import { resetPagination } from '@/sheep/helper/utils';
  190. import PayTransferApi from '@/sheep/api/pay/transfer';
  191. const headerBg = sheep.$url.css('/static/img/shop/user/wallet_card_bg.png');
  192. const state = reactive({
  193. showMoney: false,
  194. summary: {}, // 分销信息
  195. today: '',
  196. date: [],
  197. currentTab: 0,
  198. pagination: {
  199. list: [],
  200. total: 0,
  201. pageNo: 1,
  202. pageSize: 8,
  203. },
  204. loadStatus: '',
  205. price: undefined,
  206. showModal: false,
  207. });
  208. const tabMaps = [
  209. {
  210. name: '分佣',
  211. value: '1',
  212. },
  213. {
  214. name: '提现',
  215. value: '2',
  216. },
  217. ];
  218. const dateFilterText = computed(() => {
  219. if (state.date[0] === state.date[1]) {
  220. return state.date[0];
  221. } else {
  222. return state.date.join('~');
  223. }
  224. });
  225. async function getLogList() {
  226. state.loadStatus = 'loading';
  227. let { code, data } = await (state.currentTab === 0
  228. ? BrokerageApi.getBrokerageRecordPage({
  229. pageSize: state.pagination.pageSize,
  230. pageNo: state.pagination.pageNo,
  231. 'createTime[0]': state.date[0] + ' 00:00:00',
  232. 'createTime[1]': state.date[1] + ' 23:59:59',
  233. })
  234. : BrokerageApi.getBrokerageWithdrawPage({
  235. pageSize: state.pagination.pageSize,
  236. pageNo: state.pagination.pageNo,
  237. 'createTime[0]': state.date[0] + ' 00:00:00',
  238. 'createTime[1]': state.date[1] + ' 23:59:59',
  239. }));
  240. if (code !== 0) {
  241. return;
  242. }
  243. state.pagination.list = concat(state.pagination.list, data.list);
  244. state.pagination.total = data.total;
  245. state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
  246. }
  247. function onChangeTab(e) {
  248. resetPagination(state.pagination);
  249. state.currentTab = e.index;
  250. getLogList();
  251. }
  252. function onChangeTime(e) {
  253. state.date[0] = e[0];
  254. state.date[1] = e[e.length - 1];
  255. resetPagination(state.pagination);
  256. getLogList();
  257. }
  258. // 确认操作(转账到余额)
  259. async function onConfirm() {
  260. if (state.price <= 0) {
  261. sheep.$helper.toast('请输入正确的金额');
  262. return;
  263. }
  264. uni.showModal({
  265. title: '提示',
  266. content: '确认把您的佣金转入到余额钱包中?',
  267. success: async function (res) {
  268. if (!res.confirm) {
  269. return;
  270. }
  271. const { code } = await BrokerageApi.createBrokerageWithdraw({
  272. type: 1, // 钱包
  273. price: state.price * 100,
  274. });
  275. if (code === 0) {
  276. state.showModal = false;
  277. await getAgentInfo();
  278. onChangeTab({
  279. index: 1,
  280. });
  281. }
  282. },
  283. });
  284. }
  285. async function getAgentInfo() {
  286. const { code, data } = await BrokerageApi.getBrokerageUserSummary();
  287. if (code !== 0) {
  288. return;
  289. }
  290. state.summary = data;
  291. }
  292. // 微信场景下:用户确认收款
  293. // 可见 https://pay.weixin.qq.com/doc/v3/merchant/4012716430 文档
  294. async function onRequestMerchantTransfer(item) {
  295. const requestMerchantTransfer = sheep.$platform.useProvider()
  296. ? sheep.$platform.useProvider().requestMerchantTransfer
  297. : undefined;
  298. if (!requestMerchantTransfer) {
  299. sheep.$helper.toast('仅微信平台支持该功能');
  300. return;
  301. }
  302. // 获取提现详情
  303. const { code, data } = await BrokerageApi.getBrokerageWithdraw(item.id);
  304. if (code !== 0) {
  305. return;
  306. }
  307. if (data.status === 11) {
  308. sheep.$helper.toast('该提现单已确认收款');
  309. item.status = 11;
  310. return;
  311. }
  312. if (!data.transferChannelMchId || !data.transferChannelPackageInfo) {
  313. sheep.$helper.toast('提现信息异常,请稍后再试');
  314. return;
  315. }
  316. // 调用微信确认收款
  317. const payTransferId = data.payTransferId;
  318. await requestMerchantTransfer(
  319. data.transferChannelMchId,
  320. data.transferChannelPackageInfo,
  321. async (res) => {
  322. if (res.result !== 'success') {
  323. sheep.$helper.toast(res.errMsg);
  324. return;
  325. }
  326. // 同步转账单状态
  327. try {
  328. const syncTransferResult = await PayTransferApi.syncTransfer(payTransferId);
  329. console.log('syncTransferResult 结果', syncTransferResult);
  330. } catch (e) {
  331. console.error('syncTransferResult 异常', e);
  332. }
  333. // 查询提现单最新状态
  334. const { data } = await BrokerageApi.getBrokerageWithdraw(item.id);
  335. if (data && data.status !== 11) {
  336. sheep.$helper.toast('确认收款成功,但数据存在延迟,请以实际【微信支付】到账为准');
  337. return;
  338. }
  339. sheep.$helper.toast('确认收款成功');
  340. // 更新到列表中
  341. item.status = 11;
  342. },
  343. );
  344. }
  345. onLoad(async (options) => {
  346. state.today = dayjs().format('YYYY-MM-DD');
  347. state.date = [state.today, state.today];
  348. if (options.type === '2') {
  349. // 切换到"提现" tab 下
  350. state.currentTab = 1;
  351. }
  352. getLogList();
  353. getAgentInfo();
  354. });
  355. onReachBottom(() => {
  356. if (state.loadStatus === 'noMore') {
  357. return;
  358. }
  359. state.pagination.pageNo++;
  360. getLogList();
  361. });
  362. </script>
  363. <style lang="scss" scoped>
  364. // 钱包
  365. .header-box {
  366. background-color: $white;
  367. padding: 30rpx;
  368. .card-box {
  369. width: 100%;
  370. min-height: 300rpx;
  371. padding: 40rpx;
  372. background-size: 100% 100%;
  373. border-radius: 30rpx;
  374. overflow: hidden;
  375. position: relative;
  376. z-index: 1;
  377. box-sizing: border-box;
  378. &::after {
  379. content: '';
  380. display: block;
  381. width: 100%;
  382. height: 100%;
  383. z-index: 2;
  384. position: absolute;
  385. top: 0;
  386. left: 0;
  387. background: v-bind(headerBg) no-repeat;
  388. pointer-events: none;
  389. }
  390. .card-head {
  391. color: $white;
  392. font-size: 24rpx;
  393. }
  394. .ss-eye-icon {
  395. font-size: 40rpx;
  396. color: $white;
  397. }
  398. .money-num {
  399. font-size: 40rpx;
  400. line-height: normal;
  401. font-weight: 500;
  402. color: $white;
  403. font-family: OPPOSANS;
  404. }
  405. .reduce-num {
  406. font-size: 26rpx;
  407. font-weight: 400;
  408. color: $white;
  409. }
  410. .withdraw-btn {
  411. width: 120rpx;
  412. height: 60rpx;
  413. line-height: 60rpx;
  414. border-radius: 30px;
  415. font-size: 24rpx;
  416. font-weight: 500;
  417. background-color: $white;
  418. color: var(--ui-BG-Main);
  419. }
  420. .balance-btn {
  421. width: 120rpx;
  422. height: 60rpx;
  423. line-height: 60rpx;
  424. border-radius: 30px;
  425. font-size: 24rpx;
  426. font-weight: 500;
  427. color: $white;
  428. border: 1px solid $white;
  429. }
  430. }
  431. }
  432. .loading-money {
  433. margin-top: 56rpx;
  434. .loading-money-title {
  435. font-size: 24rpx;
  436. font-weight: 400;
  437. color: #ffffff;
  438. line-height: normal;
  439. margin-bottom: 30rpx;
  440. }
  441. .loading-money-num {
  442. font-size: 30rpx;
  443. font-family: OPPOSANS;
  444. font-weight: 500;
  445. color: #fefefe;
  446. }
  447. }
  448. // 筛选
  449. .filter-box {
  450. height: 120rpx;
  451. padding: 0 30rpx;
  452. background-color: $bg-page;
  453. .total-box {
  454. font-size: 24rpx;
  455. font-weight: 500;
  456. color: $dark-9;
  457. }
  458. .date-btn {
  459. background-color: $white;
  460. line-height: 54rpx;
  461. border-radius: 27rpx;
  462. padding: 0 20rpx;
  463. font-size: 24rpx;
  464. font-weight: 500;
  465. color: $dark-6;
  466. .ss-seldate-icon {
  467. font-size: 50rpx;
  468. color: $dark-9;
  469. }
  470. }
  471. }
  472. // tab
  473. .wallet-tab-card {
  474. .tab-item {
  475. height: 80rpx;
  476. position: relative;
  477. .tab-title {
  478. font-size: 30rpx;
  479. }
  480. .cur-tab-title {
  481. font-weight: $font-weight-bold;
  482. }
  483. .tab-line {
  484. width: 60rpx;
  485. height: 6rpx;
  486. border-radius: 6rpx;
  487. position: absolute;
  488. left: 50%;
  489. transform: translateX(-50%);
  490. bottom: 2rpx;
  491. background-color: var(--ui-BG-Main);
  492. }
  493. }
  494. }
  495. // 钱包记录
  496. .wallet-list {
  497. padding: 30rpx;
  498. background-color: #ffff;
  499. .head-img {
  500. width: 70rpx;
  501. height: 70rpx;
  502. border-radius: 50%;
  503. background: $gray-c;
  504. }
  505. .list-content {
  506. justify-content: space-between;
  507. align-items: flex-start;
  508. flex: 1;
  509. .title {
  510. font-size: 28rpx;
  511. color: $dark-3;
  512. width: 400rpx;
  513. }
  514. .time {
  515. color: $gray-c;
  516. font-size: 22rpx;
  517. }
  518. }
  519. .money {
  520. font-size: 28rpx;
  521. font-weight: bold;
  522. font-family: OPPOSANS;
  523. .add {
  524. color: var(--ui-BG-Main);
  525. }
  526. .minus {
  527. color: $dark-3;
  528. }
  529. }
  530. .confirm-btn {
  531. font-size: 22rpx;
  532. color: var(--ui-BG-Main);
  533. background: rgba(var(--ui-BG-Main-rgb), 0.1);
  534. padding: 4rpx 16rpx;
  535. margin: 0;
  536. line-height: 1.4;
  537. border-radius: 20rpx;
  538. border: 1px solid var(--ui-BG-Main);
  539. }
  540. }
  541. .model-title {
  542. font-size: 36rpx;
  543. font-weight: bold;
  544. color: #333333;
  545. }
  546. .model-subtitle {
  547. font-size: 26rpx;
  548. color: #c2c7cf;
  549. }
  550. .model-btn {
  551. width: 100%;
  552. height: 80rpx;
  553. border-radius: 40rpx;
  554. font-size: 28rpx;
  555. font-weight: 500;
  556. color: #ffffff;
  557. line-height: normal;
  558. }
  559. .input-box {
  560. height: 100rpx;
  561. .unit {
  562. font-size: 48rpx;
  563. color: #333;
  564. font-weight: 500;
  565. line-height: normal;
  566. }
  567. .uni-easyinput__placeholder-class {
  568. font-size: 30rpx;
  569. height: 40rpx;
  570. line-height: normal;
  571. }
  572. }
  573. .status {
  574. font-size: 22rpx;
  575. &.status-0 {
  576. color: #ff9900;
  577. }
  578. &.status-1 {
  579. color: #19be6b;
  580. }
  581. &.status-2 {
  582. color: #fa3534;
  583. }
  584. }
  585. </style>