爱简收旧衣按件回收前端代码仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

413 lines
9.2 KiB

1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
  1. <template>
  2. <view class="withdraw-record-container">
  3. <!-- 顶部导航栏 -->
  4. <view class="nav-bar" :style="{paddingTop: statusBarHeight + 'px'}">
  5. <view class="back" @tap="goBack">
  6. <uni-icons type="left" size="20"></uni-icons>
  7. </view>
  8. <text class="title">提现记录</text>
  9. </view>
  10. <view class="main-content">
  11. <view class="record-list-card">
  12. <!-- 记录列表 -->
  13. <view class="record-item" v-for="(item, index) in recordList" :key="index">
  14. <view class="record-info">
  15. <text class="record-title">{{ item.title || '提现记录' }}</text>
  16. <text class="record-date">{{ formatDate(item.createTime) }}</text>
  17. </view>
  18. <view class="record-right">
  19. <text class="record-amount">¥{{ item.money || '0.00' }}</text>
  20. <template v-if="item.state === 0">
  21. <button class="withdraw-btn" @tap="requestWechatTransfer(item, index)">
  22. 提现
  23. </button>
  24. </template>
  25. <template v-else-if="item.state === 1">
  26. <text class="status-text received">已到账</text>
  27. </template>
  28. <template v-else>
  29. <text class="status-text cancelled">已取消</text>
  30. </template>
  31. </view>
  32. </view>
  33. <!-- 初始加载状态 -->
  34. <view v-if="loading && !isInitialized" class="loading-state">
  35. <text>数据加载中...</text>
  36. </view>
  37. <!-- 空状态 -->
  38. <view v-if="recordList.length === 0 && !loading && isInitialized" class="empty-state">
  39. <text>暂无提现记录</text>
  40. </view>
  41. </view>
  42. <!-- 加载更多状态 -->
  43. <view v-if="loadingMore" class="loading-more">
  44. <text>加载更多中...</text>
  45. </view>
  46. <!-- 没有更多 -->
  47. <view v-if="noMore && recordList.length > 0" class="no-more">
  48. <text>没有更多了</text>
  49. </view>
  50. </view>
  51. </view>
  52. </template>
  53. <script>
  54. import pullRefreshMixin from '@/pages/mixins/pullRefreshMixin.js'
  55. import api from '@/api/api.js'
  56. import config from '@/config.js'
  57. export default {
  58. mixins: [pullRefreshMixin],
  59. data() {
  60. return {
  61. statusBarHeight: 0,
  62. recordList: [],
  63. pageNum: 1,
  64. pageSize: 20,
  65. loading: false,
  66. loadingMore: false,
  67. noMore: false,
  68. refreshing: false,
  69. isInitialized: false
  70. }
  71. },
  72. onLoad() {
  73. this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight
  74. this.initData()
  75. },
  76. onPullDownRefresh() {
  77. this.onRefresh()
  78. },
  79. onReachBottom() {
  80. this.loadMore()
  81. },
  82. methods: {
  83. async initData() {
  84. await this.loadRecords()
  85. },
  86. async loadRecords(isRefresh = false) {
  87. if (this.loading) return
  88. this.loading = true
  89. // 如果是刷新,重置分页状态
  90. if (isRefresh) {
  91. this.pageNum = 1
  92. this.noMore = false
  93. this.recordList = []
  94. }
  95. try {
  96. // 获取提现记录 (status=1 表示提现记录)
  97. const res = await api('getMyMoneyLogPage', {
  98. status: 1,
  99. pageNum: this.pageNum,
  100. pageSize: this.pageSize
  101. })
  102. if (res.code === 200 && res.result) {
  103. const records = res.result.records || []
  104. if (isRefresh) {
  105. this.recordList = records
  106. } else {
  107. this.recordList = [...this.recordList, ...records]
  108. }
  109. if (records.length < this.pageSize) {
  110. this.noMore = true
  111. }
  112. } else {
  113. this.recordList = []
  114. }
  115. } catch (error) {
  116. console.error('获取提现记录失败:', error)
  117. uni.showToast({
  118. title: '获取数据失败',
  119. icon: 'none'
  120. })
  121. } finally {
  122. this.loading = false
  123. this.isInitialized = true
  124. }
  125. },
  126. async loadMore() {
  127. if (this.noMore || this.loadingMore) return
  128. this.loadingMore = true
  129. this.pageNum++
  130. try {
  131. const res = await api('getMyMoneyLogPage', {
  132. status: 1,
  133. pageNum: this.pageNum,
  134. pageSize: this.pageSize
  135. })
  136. if (res.code === 200 && res.result) {
  137. const records = res.result.records || []
  138. this.recordList = [...this.recordList, ...records]
  139. if (records.length < this.pageSize) {
  140. this.noMore = true
  141. }
  142. }
  143. } catch (error) {
  144. console.error('加载更多记录失败:', error)
  145. this.pageNum-- // 失败时回退页码
  146. uni.showToast({
  147. title: '加载更多数据失败',
  148. icon: 'none'
  149. })
  150. } finally {
  151. this.loadingMore = false
  152. }
  153. },
  154. async onRefresh() {
  155. this.refreshing = true
  156. try {
  157. await this.loadRecords(true)
  158. } finally {
  159. this.refreshing = false
  160. uni.stopPullRefresh()
  161. }
  162. },
  163. formatDate(timestamp) {
  164. if (!timestamp) return ''
  165. const date = new Date(timestamp)
  166. const month = String(date.getMonth() + 1).padStart(2, '0')
  167. const day = String(date.getDate()).padStart(2, '0')
  168. return `${month}-${day}`
  169. },
  170. goBack() {
  171. uni.navigateBack()
  172. },
  173. // 微信商户转账
  174. async requestWechatTransfer(payData, index) {
  175. try {
  176. uni.showLoading({
  177. title: '处理中...'
  178. })
  179. // 调用微信商户转账API
  180. const transferResult = await new Promise((resolve, reject) => {
  181. // 拉起微信收款确认页面
  182. if (!wx.canIUse('requestMerchantTransfer')) {
  183. wx.showModal({
  184. content: '你的微信版本过低,请更新至最新版本。',
  185. showCancel: false,
  186. })
  187. return
  188. }
  189. // 在真机环境中,调用API
  190. wx.requestMerchantTransfer({
  191. mchId: config.mchId,
  192. appId: wx.getAccountInfoSync().miniProgram.appId,
  193. package: payData.packageInfo,
  194. success: (res) => {
  195. resolve(res)
  196. },
  197. fail: (res) => {
  198. reject(res)
  199. },
  200. complete: (res) => {
  201. }
  202. })
  203. })
  204. // 转账成功后调用成功接口
  205. await api('withdrawSUccess', { id: payData.id }, '确认提现中...')
  206. // 刷新列表
  207. this.pageNum = 1
  208. this.noMore = false
  209. this.recordList = []
  210. this.isInitialized = false
  211. await this.loadRecords()
  212. uni.showToast({
  213. title: '提现成功',
  214. icon: 'success'
  215. })
  216. } catch (error) {
  217. console.error('微信转账失败:', error)
  218. uni.showToast({
  219. title: '提现失败,请重试',
  220. icon: 'none'
  221. })
  222. } finally {
  223. uni.hideLoading()
  224. }
  225. }
  226. }
  227. }
  228. </script>
  229. <style lang="scss" scoped>
  230. .withdraw-record-container {
  231. min-height: 100vh;
  232. background: #f7f7f7;
  233. }
  234. .nav-bar {
  235. display: flex;
  236. align-items: center;
  237. height: calc(150rpx + var(--status-bar-height));
  238. padding: 0 32rpx;
  239. background: #fff;
  240. position: fixed;
  241. top: 0;
  242. left: 0;
  243. right: 0;
  244. z-index: 999;
  245. box-sizing: border-box;
  246. box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.03);
  247. .back {
  248. padding: 20rpx;
  249. margin-left: -20rpx;
  250. }
  251. .title {
  252. flex: 1;
  253. text-align: center;
  254. font-size: 34rpx;
  255. font-weight: 500;
  256. color: #222;
  257. }
  258. }
  259. .main-content {
  260. margin-top: calc(150rpx + var(--status-bar-height));
  261. margin-bottom: 40rpx;
  262. }
  263. .record-list-card {
  264. background: #fff;
  265. border-radius: 40rpx;
  266. margin: 0 32rpx 32rpx 32rpx;
  267. padding: 0;
  268. box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.03);
  269. }
  270. .record-item {
  271. display: flex;
  272. align-items: center;
  273. justify-content: space-between;
  274. padding: 38rpx 36rpx;
  275. border-bottom: 2rpx solid #f3f3f3;
  276. &:last-child {
  277. border-bottom: none;
  278. }
  279. }
  280. .record-info {
  281. display: flex;
  282. flex-direction: column;
  283. flex: 1;
  284. }
  285. .record-title {
  286. font-size: 30rpx;
  287. color: #222;
  288. font-weight: 500;
  289. margin-bottom: 8rpx;
  290. }
  291. .record-date {
  292. font-size: 26rpx;
  293. color: #b3b3b3;
  294. font-weight: 400;
  295. }
  296. .record-right {
  297. display: flex;
  298. flex-direction: column;
  299. align-items: flex-end;
  300. gap: 8rpx;
  301. }
  302. .record-amount {
  303. font-size: 32rpx;
  304. color: #222;
  305. font-weight: 500;
  306. }
  307. .withdraw-btn {
  308. width: 120rpx;
  309. height: 50rpx;
  310. background: #FFB74D;
  311. color: #fff;
  312. font-size: 24rpx;
  313. border-radius: 25rpx;
  314. display: flex;
  315. align-items: center;
  316. justify-content: center;
  317. border: none;
  318. padding: 0;
  319. line-height: 1;
  320. box-sizing: border-box;
  321. white-space: nowrap;
  322. overflow: hidden;
  323. text-overflow: ellipsis;
  324. &::after {
  325. border: none;
  326. }
  327. }
  328. .status-text {
  329. font-size: 24rpx;
  330. padding: 4rpx 8rpx;
  331. border-radius: 8rpx;
  332. &.received {
  333. color: #52C41A;
  334. background: #f6ffed;
  335. }
  336. &.cancelled {
  337. color: #ff4d4f;
  338. background: #fff2f0;
  339. }
  340. }
  341. .loading-state {
  342. text-align: center;
  343. padding: 100rpx 0;
  344. color: #999;
  345. font-size: 28rpx;
  346. }
  347. .empty-state {
  348. text-align: center;
  349. padding: 100rpx 0;
  350. color: #999;
  351. font-size: 28rpx;
  352. }
  353. .loading-more {
  354. text-align: center;
  355. padding: 20rpx 0;
  356. color: #999;
  357. font-size: 28rpx;
  358. }
  359. .no-more {
  360. text-align: center;
  361. padding: 20rpx 0;
  362. color: #999;
  363. font-size: 28rpx;
  364. }
  365. </style>