敢为人鲜小程序前端代码仓库
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.

441 lines
13 KiB

1 month ago
  1. <template>
  2. <view class="wallet-page">
  3. <!-- 导航栏 -->
  4. <navbar title="钱包" leftClick @leftClick="$utils.navigateBack" bgColor="#019245" color="#fff" />
  5. <!-- 总余额展示区 -->
  6. <view class="balance-card" :style="{ backgroundImage: `url(${configList.config_money_image})` }">
  7. <view class="balance-info">
  8. <view class="balance-title">总余额</view>
  9. <view class="balance-amount">{{ userInfo.balance ? userInfo.balance.toFixed(2) : '0.00' }}</view>
  10. <view class="balance-actions">
  11. <view class="action-btn recharge-btn" v-if="!isRecharge" @tap="navigateToRecharge">
  12. <text>去充值</text>
  13. <text class="arrow">></text>
  14. </view>
  15. <view class="action-btn recharge-btn" v-if="isRecharge" @tap="isRecharge = false">
  16. <text>提现</text>
  17. <text class="arrow">></text>
  18. </view>
  19. <view class="action-btn" v-else />
  20. <view class="action-btn detail-btn" @tap="navigateToDetail">
  21. <text>资产明细</text>
  22. <text class="arrow">></text>
  23. </view>
  24. <view class="action-btn detail-btn" @tap="toRunningWater">
  25. <text>提现记录</text>
  26. <text class="arrow">></text>
  27. </view>
  28. </view>
  29. </view>
  30. </view>
  31. <!-- 提现表单 -->
  32. <view class="withdraw-section">
  33. <view class="section-title">{{ isRecharge ? '我要充值' : '我要提现' }}</view>
  34. <!-- 提现金额输入框 -->
  35. <view class="input-item">
  36. <text class="currency-symbol">¥</text>
  37. <input v-if="!isRecharge" class="amount-input" type="digit" v-model="withdrawAmount"
  38. placeholder="请输入提现金额" @blur="validateAmount" />
  39. <input v-else class="amount-input" type="digit" v-model="rechargeAmount" placeholder="请输入充值金额"
  40. @blur="validateAmount" />
  41. </view>
  42. <!-- 真实姓名输入框 -->
  43. <view class="input-item" v-if="!isRecharge">
  44. <input class="name-input" v-model="realName" placeholder="请输入真实姓名"
  45. @blur="validateName" />
  46. </view>
  47. <!-- 提现说明 -->
  48. <view class="withdraw-notes" v-if="!isRecharge">
  49. <view class="notes-title">提现说明</view>
  50. <view class="notes-list">
  51. <view class="note-item" v-for="(rule, index) in walletData.withdrawRules" :key="index">
  52. <text>{{ index + 1 }}{{ rule }}</text>
  53. </view>
  54. </view>
  55. </view>
  56. </view>
  57. <!-- 提现按钮 -->
  58. <view class="submit-btn-wrapper">
  59. <button class="submit-btn" @tap="submitWithdraw" :disabled="!isFormValid">
  60. {{ isRecharge ? '立即充值' : '立即提现' }}
  61. </button>
  62. </view>
  63. </view>
  64. </template>
  65. <script>
  66. import navbar from '@/components/base/navbar.vue'
  67. // import { walletData } from '@/static/js/mockWallet.js'
  68. export default {
  69. components: {
  70. navbar
  71. },
  72. data() {
  73. return {
  74. walletData: null,
  75. withdrawAmount: '',
  76. rechargeAmount: '',
  77. realName: '',
  78. amountError: '',
  79. nameError: '',
  80. isFormValid: true,
  81. isRecharge: false
  82. }
  83. },
  84. onLoad() {
  85. // this.walletData = walletData
  86. },
  87. methods: {
  88. // 导航到充值页面
  89. navigateToRecharge() {
  90. this.isRecharge = true
  91. },
  92. // 导航到资产明细页面
  93. navigateToDetail() {
  94. this.$utils.navigateTo('/pages_order/mine/assets')
  95. },
  96. // 验证提现金额
  97. validateAmount() {
  98. if (!this.withdrawAmount) {
  99. this.amountError = '请输入提现金额'
  100. return false
  101. }
  102. const amount = parseFloat(this.withdrawAmount)
  103. if (isNaN(amount) || amount <= 0) {
  104. this.amountError = '请输入有效的提现金额'
  105. return false
  106. }
  107. if (amount > this.userInfo.balance) {
  108. this.amountError = '提现金额不能大于余额'
  109. return false
  110. }
  111. if (amount > 200) {
  112. this.amountError = '单笔提现不能超过200元'
  113. return false
  114. }
  115. this.amountError = ''
  116. return true
  117. },
  118. // 验证真实姓名
  119. validateName() {
  120. if (!this.realName) {
  121. this.nameError = '请输入真实姓名'
  122. return false
  123. }
  124. if (this.realName.length < 2) {
  125. this.nameError = '请输入有效的姓名'
  126. return false
  127. }
  128. this.nameError = ''
  129. return true
  130. },
  131. // 提交提现申请
  132. submitWithdraw() {
  133. if (this.isRecharge) {
  134. return this.recharge()
  135. }
  136. // 再次验证表单
  137. if (!this.validateAmount() || !this.validateName()) {
  138. // 显示具体错误
  139. if (this.amountError) {
  140. uni.showToast({
  141. title: this.amountError,
  142. icon: 'error'
  143. })
  144. return
  145. }
  146. if (this.nameError) {
  147. uni.showToast({
  148. title: this.nameError,
  149. icon: 'error'
  150. })
  151. return
  152. }
  153. return
  154. }
  155. // 如果在isFormVaild为false的情况下进入函数 则为多次点击 直接返回
  156. if (this.isFormValid) {
  157. this.isFormValid = false
  158. }else return
  159. // 显示提交中状态
  160. uni.showLoading({
  161. title: '提交中...'
  162. })
  163. // 提现
  164. this.$api('cashout', { transferAmount: this.withdrawAmount, userName: this.realName }, res => {
  165. uni.hideLoading()
  166. if (res.code === 200) {
  167. // 处理待收款用户确认的情况
  168. if (res.result && res.result.state === 'WAIT_USER_CONFIRM' && res.result.packageInfo && res.result.outBillNo) {
  169. // 拉起微信收款确认页面
  170. if (!wx.canIUse('requestMerchantTransfer')) {
  171. wx.showModal({
  172. content: '你的微信版本过低,请更新至最新版本。',
  173. showCancel: false,
  174. });
  175. return
  176. }
  177. let data = res.result
  178. this.$store.commit('getUserInfo')
  179. wx.requestMerchantTransfer({
  180. mchId: this.$config.mchId,
  181. appId: wx.getAccountInfoSync().miniProgram.appId,
  182. package: res.result.packageInfo,
  183. success: (res) => {
  184. // uni.showToast({
  185. // title: '提现申请已提交',
  186. // icon: 'success'
  187. // })
  188. this.withdrawAmount = ''
  189. this.realName = ''
  190. this.$api('getMoney', {
  191. id : data.outBillNo,
  192. })
  193. },
  194. fail: (res) => {
  195. console.log('fail:', res);
  196. uni.showToast({
  197. title: '提现失败,请稍后再试',
  198. icon: 'none'
  199. })
  200. this.isFormValid = true
  201. },
  202. complete: (res) => {
  203. console.log('requestMerchantTransfer完成:', res);
  204. }
  205. });
  206. } else {
  207. uni.showToast({
  208. title: res.message,
  209. icon: 'none'
  210. })
  211. this.withdrawAmount = ''
  212. this.realName = ''
  213. }
  214. }else {
  215. uni.showToast({
  216. title: res.message,
  217. icon: 'none'
  218. })
  219. }
  220. this.isFormValid = true
  221. })
  222. },
  223. recharge() {
  224. uni.showModal({
  225. title: '确认充值',
  226. content: '充值金额为' + this.rechargeAmount + '元',
  227. confirmColor: '#019245',
  228. success: (res) => {
  229. // 这里编写函数逻辑
  230. if (res.confirm) {
  231. uni.showLoading({
  232. title: '充值中...'
  233. })
  234. this.$api('cashIn', { amount: this.rechargeAmount } , res => {
  235. uni.hideLoading()
  236. if (res.code === 200) {
  237. uni.requestPaymentWxPay(res)
  238. .then(() => {
  239. this.$store.commit('getUserInfo')
  240. this.rechargeAmount = ''
  241. this.isRecharge = false
  242. })
  243. .catch(() => {
  244. uni.showToast({
  245. title: '充值失败',
  246. icon: 'error'
  247. })
  248. })
  249. }
  250. })
  251. }
  252. },
  253. fail: (err) => {
  254. console.log(err);
  255. }
  256. })
  257. },
  258. toRunningWater() {
  259. uni.navigateTo({
  260. url: "/pages_order/mine/runningWater"
  261. })
  262. },
  263. }
  264. }
  265. </script>
  266. <style lang="scss" scoped>
  267. .wallet-page {
  268. }
  269. .balance-card {
  270. width: 96%;
  271. height: 280rpx;
  272. background-size: cover;
  273. background-position: center;
  274. padding: 30rpx;
  275. box-sizing: border-box;
  276. position: relative;
  277. margin: 20rpx auto;
  278. border-radius: 20rpx;
  279. .balance-info {
  280. position: relative;
  281. z-index: 2;
  282. color: #fff;
  283. }
  284. .balance-title {
  285. font-size: 28rpx;
  286. margin-bottom: 10rpx;
  287. }
  288. .balance-amount {
  289. font-size: 56rpx;
  290. font-weight: bold;
  291. margin-bottom: 20rpx;
  292. }
  293. .balance-actions {
  294. display: flex;
  295. justify-content: space-between;
  296. // justify-content: center;
  297. align-items: center;
  298. .action-btn {
  299. padding: 10rpx 24rpx;
  300. font-size: 24rpx;
  301. border-radius: 30rpx;
  302. display: flex;
  303. align-items: center;
  304. }
  305. .recharge-btn {
  306. background-color: #fff;
  307. color: $uni-color;
  308. border: none;
  309. min-width: 120rpx;
  310. height: 60rpx;
  311. justify-content: center;
  312. font-size: 24rpx;
  313. font-weight: normal;
  314. gap: 4rpx;
  315. // line-height: 1;
  316. padding: 0 20rpx;
  317. }
  318. .detail-btn {
  319. .arrow {
  320. margin-left: 10rpx;
  321. }
  322. }
  323. }
  324. }
  325. .withdraw-section {
  326. padding: 30rpx;
  327. // background-color: #fff;
  328. .section-title {
  329. font-size: 32rpx;
  330. color: #333;
  331. margin-bottom: 30rpx;
  332. font-weight: bold;
  333. }
  334. .input-item {
  335. display: flex;
  336. align-items: center;
  337. padding: 24rpx 20rpx;
  338. margin-bottom: 20rpx;
  339. background-color: #e7e7e7;
  340. border-radius: 20rpx;
  341. .currency-symbol {
  342. color: #FF0000;
  343. margin-right: 20rpx;
  344. }
  345. .amount-input,
  346. .name-input {
  347. flex: 1;
  348. font-size: 28rpx;
  349. height: 60rpx;
  350. }
  351. .name-input {
  352. padding-left: 40rpx;
  353. }
  354. }
  355. .withdraw-notes {
  356. margin-top: 40rpx;
  357. .notes-title {
  358. font-size: 28rpx;
  359. color: #333;
  360. margin-bottom: 20rpx;
  361. }
  362. .notes-list {
  363. .note-item {
  364. font-size: 26rpx;
  365. color: #666;
  366. line-height: 1.6;
  367. margin-bottom: 10rpx;
  368. }
  369. }
  370. }
  371. }
  372. .submit-btn-wrapper {
  373. padding: 40rpx 30rpx;
  374. .submit-btn {
  375. width: 100%;
  376. height: 88rpx;
  377. background-color: $uni-color;
  378. color: #fff;
  379. font-size: 32rpx;
  380. border-radius: 44rpx;
  381. display: flex;
  382. align-items: center;
  383. justify-content: center;
  384. border: none;
  385. &:disabled {
  386. background-color: #ccc;
  387. color: rgba(255, 255, 255, 0.6);
  388. }
  389. }
  390. }
  391. </style>