withdraw.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. <template>
  2. <view class="container">
  3. <!-- 导航栏 -->
  4. <view class="navbar">
  5. <view class="nav-left" @click="goBack">
  6. <text class="back-icon"><</text>
  7. </view>
  8. <view class="nav-title">提现</view>
  9. <view class="nav-right">
  10. <text class="more-icon">...</text>
  11. <text class="eye-icon">O</text>
  12. </view>
  13. </view>
  14. <!-- 内容区域 -->
  15. <scroll-view class="content" scroll-y>
  16. <!-- 提现至 -->
  17. <view class="withdraw-to-section">
  18. <view class="section-label">提现至</view>
  19. <view class="bank-info" @click="goSelectBank">
  20. <text>{{ bankCardInfo.bankName || '请选择银行卡' }}</text>
  21. <text class="card-tail" v-if="bankCardInfo.cardNumber">({{ getCardTail(bankCardInfo.cardNumber) }})</text>
  22. <text class="arrow-right">></text>
  23. </view>
  24. </view>
  25. <!-- 提现金额 -->
  26. <view class="amount-section">
  27. <view class="section-label">提现金额</view>
  28. <view class="amount-input-wrapper">
  29. <text class="currency">¥</text>
  30. <input
  31. class="amount-input"
  32. v-model="withdrawAmount"
  33. type="digit"
  34. placeholder="0.00"
  35. @input="onAmountInput"
  36. />
  37. </view>
  38. <view class="amount-footer">
  39. <text class="available-amount">可提现金额: ¥ {{ availableAmount || '0.00' }}</text>
  40. <text class="withdraw-all" @click="withdrawAll">全部提现</text>
  41. </view>
  42. </view>
  43. </scroll-view>
  44. <!-- 底部按钮和提示 -->
  45. <view class="bottom-bar">
  46. <view class="submit-btn" @click="handleSubmit">确认提现</view>
  47. <view class="tips">提现申请发起后,预计在3个工作日到账</view>
  48. </view>
  49. </view>
  50. </template>
  51. <script>
  52. import { submitWithdraw, getWithdrawInfo } from '@/api-js/withdraw'
  53. import { getBankCardInfo } from '@/api-js/bankCard'
  54. export default {
  55. data() {
  56. return {
  57. withdrawAmount: '320.00',
  58. availableAmount: '320.00',
  59. bankCardInfo: {}
  60. }
  61. },
  62. onLoad() {
  63. this.loadData()
  64. },
  65. methods: {
  66. async loadData() {
  67. try {
  68. uni.showLoading({ title: '加载中...' })
  69. const [bankRes, withdrawRes] = await Promise.all([
  70. getBankCardInfo(),
  71. getWithdrawInfo()
  72. ])
  73. uni.hideLoading()
  74. if (bankRes.code === 200 && bankRes.data) {
  75. this.bankCardInfo = bankRes.data
  76. }
  77. if (withdrawRes.code === 200 && withdrawRes.data) {
  78. this.availableAmount = (withdrawRes.data.availableAmount || 0).toFixed(2)
  79. this.withdrawAmount = this.availableAmount
  80. } else {
  81. // 示例数据
  82. this.availableAmount = '320.00'
  83. this.withdrawAmount = '320.00'
  84. }
  85. if (!this.bankCardInfo.id) {
  86. // 示例数据
  87. this.bankCardInfo = {
  88. bankName: '中国工商银行',
  89. cardNumber: '8869'
  90. }
  91. }
  92. } catch (e) {
  93. uni.hideLoading()
  94. console.error('加载数据失败', e)
  95. this.availableAmount = '320.00'
  96. this.withdrawAmount = '320.00'
  97. this.bankCardInfo = {
  98. bankName: '中国工商银行',
  99. cardNumber: '8869'
  100. }
  101. }
  102. },
  103. getCardTail(cardNumber) {
  104. if (!cardNumber) return ''
  105. if (cardNumber.length < 4) return cardNumber
  106. return cardNumber.substring(cardNumber.length - 4)
  107. },
  108. onAmountInput(e) {
  109. let value = e.detail.value
  110. // 限制只能输入数字和小数点
  111. value = value.replace(/[^\d.]/g, '')
  112. // 限制小数点后两位
  113. if (value.indexOf('.') > -1) {
  114. const parts = value.split('.')
  115. if (parts[1] && parts[1].length > 2) {
  116. value = parts[0] + '.' + parts[1].substring(0, 2)
  117. }
  118. }
  119. // 限制不能超过可提现金额
  120. const amount = parseFloat(value) || 0
  121. const available = parseFloat(this.availableAmount) || 0
  122. if (amount > available) {
  123. value = this.availableAmount
  124. }
  125. this.withdrawAmount = value
  126. },
  127. withdrawAll() {
  128. this.withdrawAmount = this.availableAmount
  129. },
  130. goBack() {
  131. uni.navigateBack()
  132. },
  133. goSelectBank() {
  134. uni.navigateTo({
  135. url: '/pages_user/bankCard'
  136. })
  137. },
  138. async handleSubmit() {
  139. // 验证银行卡
  140. if (!this.bankCardInfo.id) {
  141. uni.showToast({
  142. icon: 'none',
  143. title: '请先添加银行卡'
  144. })
  145. setTimeout(() => {
  146. this.goSelectBank()
  147. }, 1500)
  148. return
  149. }
  150. // 验证金额
  151. const amount = parseFloat(this.withdrawAmount) || 0
  152. if (amount <= 0) {
  153. uni.showToast({
  154. icon: 'none',
  155. title: '请输入提现金额'
  156. })
  157. return
  158. }
  159. const available = parseFloat(this.availableAmount) || 0
  160. if (amount > available) {
  161. uni.showToast({
  162. icon: 'none',
  163. title: '提现金额不能超过可提现金额'
  164. })
  165. return
  166. }
  167. try {
  168. uni.showLoading({ title: '提交中...' })
  169. const res = await submitWithdraw({
  170. amount: this.withdrawAmount,
  171. bankCardId: this.bankCardInfo.id
  172. })
  173. uni.hideLoading()
  174. if (res.code === 200) {
  175. uni.navigateTo({
  176. url: '/pages_user/withdrawSuccess'
  177. })
  178. } else {
  179. uni.showToast({
  180. icon: 'none',
  181. title: res.msg || '提现失败'
  182. })
  183. }
  184. } catch (e) {
  185. uni.hideLoading()
  186. uni.showToast({
  187. icon: 'none',
  188. title: '提现失败'
  189. })
  190. }
  191. }
  192. }
  193. }
  194. </script>
  195. <style lang="scss" scoped>
  196. .container {
  197. min-height: 100vh;
  198. background: #f5f5f5;
  199. display: flex;
  200. flex-direction: column;
  201. }
  202. .navbar {
  203. display: flex;
  204. align-items: center;
  205. justify-content: space-between;
  206. padding: 20rpx 24rpx;
  207. background: #fff;
  208. border-bottom: 1rpx solid #f0f0f0;
  209. .nav-left {
  210. width: 60rpx;
  211. .back-icon {
  212. font-size: 36rpx;
  213. color: #333;
  214. font-weight: bold;
  215. }
  216. }
  217. .nav-title {
  218. flex: 1;
  219. text-align: center;
  220. font-size: 36rpx;
  221. font-weight: bold;
  222. color: #333;
  223. }
  224. .nav-right {
  225. display: flex;
  226. align-items: center;
  227. gap: 24rpx;
  228. width: 60rpx;
  229. justify-content: flex-end;
  230. .more-icon {
  231. font-size: 32rpx;
  232. color: #333;
  233. }
  234. .eye-icon {
  235. font-size: 32rpx;
  236. color: #333;
  237. }
  238. }
  239. }
  240. .content {
  241. flex: 1;
  242. padding-bottom: 200rpx;
  243. }
  244. .withdraw-to-section {
  245. background: #fff;
  246. padding: 32rpx 24rpx;
  247. margin: 24rpx;
  248. border-radius: 16rpx;
  249. display: flex;
  250. align-items: center;
  251. justify-content: space-between;
  252. .section-label {
  253. font-size: 28rpx;
  254. color: #333;
  255. font-weight: 500;
  256. }
  257. .bank-info {
  258. flex: 1;
  259. display: flex;
  260. align-items: center;
  261. justify-content: flex-end;
  262. margin-left: 24rpx;
  263. font-size: 28rpx;
  264. color: #333;
  265. .card-tail {
  266. margin: 0 8rpx;
  267. }
  268. .arrow-right {
  269. font-size: 32rpx;
  270. color: #999;
  271. margin-left: 8rpx;
  272. }
  273. }
  274. }
  275. .amount-section {
  276. background: #fff;
  277. padding: 32rpx 24rpx;
  278. margin: 0 24rpx 24rpx;
  279. border-radius: 16rpx;
  280. .section-label {
  281. font-size: 28rpx;
  282. color: #333;
  283. font-weight: 500;
  284. margin-bottom: 24rpx;
  285. }
  286. .amount-input-wrapper {
  287. display: flex;
  288. align-items: center;
  289. margin-bottom: 24rpx;
  290. .currency {
  291. font-size: 48rpx;
  292. font-weight: bold;
  293. color: #333;
  294. margin-right: 8rpx;
  295. }
  296. .amount-input {
  297. flex: 1;
  298. font-size: 56rpx;
  299. font-weight: bold;
  300. color: #333;
  301. height: 80rpx;
  302. line-height: 80rpx;
  303. }
  304. }
  305. .amount-footer {
  306. display: flex;
  307. align-items: center;
  308. justify-content: space-between;
  309. .available-amount {
  310. font-size: 24rpx;
  311. color: #999;
  312. }
  313. .withdraw-all {
  314. font-size: 28rpx;
  315. color: #388BFF;
  316. }
  317. }
  318. }
  319. .bottom-bar {
  320. position: fixed;
  321. bottom: 0;
  322. left: 0;
  323. right: 0;
  324. background: #fff;
  325. padding: 24rpx;
  326. border-top: 1rpx solid #f0f0f0;
  327. z-index: 100;
  328. .submit-btn {
  329. width: 100%;
  330. height: 88rpx;
  331. background: #388BFF;
  332. border-radius: 44rpx;
  333. display: flex;
  334. align-items: center;
  335. justify-content: center;
  336. font-size: 32rpx;
  337. font-weight: bold;
  338. color: #fff;
  339. margin-bottom: 16rpx;
  340. }
  341. .tips {
  342. text-align: center;
  343. font-size: 24rpx;
  344. color: #999;
  345. line-height: 1.5;
  346. }
  347. }
  348. </style>