settlement.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. <template>
  2. <view class="page client-theme client-subpage">
  3. <view class="client-subpage-hero settlement-hero">
  4. <text class="client-subpage-hero__title">结算记录</text>
  5. <text class="client-subpage-hero__sub">累计已结算(元)</text>
  6. <text class="sum-val">¥{{ formatYuan(totalSettled) }}</text>
  7. </view>
  8. <scroll-view scroll-y class="client-subpage-scroll settlement-scroll" :show-scrollbar="true">
  9. <view class="client-subpage-body settlement-body">
  10. <view v-if="loading" class="hint">加载中...</view>
  11. <view v-else-if="list.length === 0" class="hint">暂无结算记录</view>
  12. <view v-for="row in list" :key="row.id" class="card" hover-class="card--pressed" :hover-stay-time="100">
  13. <view class="line">
  14. <view class="order-wrap">
  15. <text class="order">订单 {{ row.orderNo || row.id.slice(0, 8) }}</text>
  16. <SqCopyBtn v-if="row.orderNo" class="copy" :text="row.orderNo" label="订单号" icon-only />
  17. </view>
  18. <text class="amt">¥{{ formatYuan(row.amount) }}</text>
  19. </view>
  20. <text class="sub">{{ row.settlementMethod || '—' }} · {{ row.settlementTime || row.createAt }}</text>
  21. </view>
  22. </view>
  23. </scroll-view>
  24. </view>
  25. </template>
  26. <script setup>
  27. import { ref, onMounted } from 'vue'
  28. import { onShow } from '@dcloudio/uni-app'
  29. import { useUserStore } from '@/stores/user'
  30. import { request, parseResponseJson } from '@/utils/request'
  31. import { API_URL } from '@/config/api'
  32. import { formatYuan } from '@/utils/format'
  33. import SqCopyBtn from '@/components/sq-copy-btn.vue'
  34. const userStore = useUserStore()
  35. const list = ref([])
  36. const totalSettled = ref(0)
  37. const loading = ref(false)
  38. async function load() {
  39. loading.value = true
  40. try {
  41. const [r1, r2] = await Promise.all([
  42. request({
  43. url: API_URL.CLIENT_SETTLEMENTS,
  44. method: 'GET',
  45. data: { page: 1, pageSize: 50 }
  46. }),
  47. request({
  48. url: API_URL.CLIENT_SETTLEMENT_STATS,
  49. method: 'GET'
  50. })
  51. ])
  52. const b1 = parseResponseJson(r1)
  53. if (b1.code === 200) {
  54. list.value = (b1.data && b1.data.list) || []
  55. }
  56. const b2 = parseResponseJson(r2)
  57. if (b2.code === 200) {
  58. totalSettled.value = (b2.data && b2.data.totalSettled) ?? 0
  59. }
  60. } finally {
  61. loading.value = false
  62. }
  63. }
  64. onMounted(() => {
  65. userStore.checkLoginStatus()
  66. if (!userStore.isLoggedIn) {
  67. uni.reLaunch({ url: '/pages/login/login' })
  68. return
  69. }
  70. if (!userStore.isClient) {
  71. uni.showToast({ title: '仅客户可访问', icon: 'none' })
  72. setTimeout(() => userStore.navigateToHome(), 1200)
  73. return
  74. }
  75. load()
  76. })
  77. onShow(() => {
  78. userStore.checkLoginStatus()
  79. if (!userStore.isLoggedIn || !userStore.isClient) return
  80. void load()
  81. })
  82. </script>
  83. <style lang="scss" scoped>
  84. .page {
  85. min-height: 100vh;
  86. background: var(--c-bg);
  87. box-sizing: border-box;
  88. }
  89. .settlement-hero .sum-val {
  90. display: block;
  91. margin-top: 16rpx;
  92. font-size: 48rpx;
  93. font-weight: 700;
  94. letter-spacing: 0.5rpx;
  95. }
  96. .settlement-scroll {
  97. flex: 1;
  98. min-height: 0;
  99. height: 0;
  100. }
  101. .card--pressed {
  102. opacity: 0.94;
  103. }
  104. .hint {
  105. text-align: center;
  106. color: var(--c-muted);
  107. padding: 60rpx 0;
  108. }
  109. .card {
  110. background: var(--c-card);
  111. border: 1rpx solid var(--c-border);
  112. border-radius: var(--c-radius-card);
  113. padding: 24rpx;
  114. margin-bottom: 16rpx;
  115. }
  116. .line {
  117. display: flex;
  118. justify-content: space-between;
  119. align-items: center;
  120. }
  121. .order-wrap {
  122. flex: 1;
  123. min-width: 0;
  124. display: flex;
  125. align-items: center;
  126. gap: 10rpx;
  127. }
  128. .order {
  129. flex: 1;
  130. min-width: 0;
  131. font-size: 28rpx;
  132. color: var(--c-text);
  133. overflow: hidden;
  134. text-overflow: ellipsis;
  135. white-space: nowrap;
  136. }
  137. .copy {
  138. flex: 0 0 auto;
  139. }
  140. .amt {
  141. font-size: 30rpx;
  142. color: var(--c-danger);
  143. font-weight: 600;
  144. }
  145. .sub {
  146. font-size: 24rpx;
  147. color: var(--c-muted);
  148. margin-top: 12rpx;
  149. display: block;
  150. }
  151. </style>