withdraw.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. <!-- 提现 -->
  2. <template>
  3. <s-layout :title="t('wallet.withdraw')">
  4. <view class="bg-white ss-modal-box ss-flex-col">
  5. <!-- 提现方式 -->
  6. <view class="modal-content">
  7. <view class="out-title ss-p-l-30 ss-m-y-30">{{ t('wallet.select_withdrawal_method') }}</view>
  8. <radio-group @change="onTapOut">
  9. <label class="out-type-item" v-for="item in state.outMethods" :key="item.title">
  10. <view class="out-item ss-flex ss-col-center ss-row-between ss-p-x-30 border-bottom"
  11. :class="{ 'disabled-out-item': item.disabled }">
  12. <view class="ss-flex ss-col-center">
  13. <view class="check-box ss-flex ss-col-center ss-p-l-10">
  14. <radio
  15. :value="item.value"
  16. color="var(--ui-BG-Main)"
  17. style="transform: scale(0.8)"
  18. :disabled="item.disabled"
  19. :checked="state.payment === item.value"
  20. />
  21. </view>
  22. <text class="out-title">{{ item.title }}</text>
  23. </view>
  24. <text style="float: right;" v-if="item.account">{{item.account}}</text>
  25. <text style="float: right;" v-else @click="handleBind(item.value)">{{ t('wallet.not_bound_click_to_bind') }}&nbsp;></text>
  26. </view>
  27. </label>
  28. </radio-group>
  29. </view>
  30. <!-- 提现金额 -->
  31. <view class="modal-content ss-m-t-30">
  32. <uni-forms :model="state.model" :rules="state.rules" validateTrigger="bind" labelPosition="left" border
  33. class="form-box" labelWidth='200' ref="FormRef">
  34. <view class="bg-white ss-p-x-30">
  35. <uni-forms-item name="quota" :label="t('wallet.withdrawal_amount')" :required="true">
  36. <uni-easyinput v-model="state.outMoney" type="number"
  37. :placeholder="t('wallet.enter_withdrawal_amount')" :inputBorder="false" :clearable="false" />
  38. </uni-forms-item>
  39. <uni-forms-item name="quota" :label="t('wallet.actual_amount_received')">
  40. <view class="ss-flex ss-h-100">
  41. {{commission}}
  42. </view>
  43. </uni-forms-item>
  44. <uni-forms-item name="quota" :label="t('wallet.consumption_points')">
  45. <view class="ss-flex ss-h-100">
  46. {{consumption}}
  47. </view>
  48. </uni-forms-item>
  49. </view>
  50. </uni-forms>
  51. <!-- <view class="out-title ss-p-l-30 ss-m-y-30">提现金额</view>
  52. <view class="ss-flex ss-row-left ss-col-center input-money ss-m-y-30" >
  53. <input v-model.number="state.outMoney" class="uni-input " type="number"
  54. placeholder="请输入金额" />
  55. </view> -->
  56. <view class="ss-flex ss-row-center ss-col-center ss-m-t-30">
  57. {{ t('wallet.current_exchangeable_amount') }}<text class="text-red">{{canUseMoney}}</text>
  58. <button class="ss-m-l-10 all-btn " @click="useAllPonints">{{ t('common.all') }}</button>
  59. </view>
  60. <view class="ss-flex ss-row-center ss-col-center ss-m-t-30 text-red text-center">{{ t('wallet.note',{commission:withdrawCommission,consumption:withdrawConsumption}) }}</view>
  61. </view>
  62. <!-- 工具 -->
  63. <view class="modal-footer ss-flex ss-row-center ss-col-center ss-m-t-80 ss-m-b-40 ss-flex-5">
  64. <button class="ss-reset-button save-btn" @tap="submit" :disabled="state.disabled" :class="{ 'disabled-btn': state.disabled }"
  65. >
  66. {{ t('common.confirm') }}
  67. </button>
  68. </view>
  69. </view>
  70. </s-layout>
  71. </template>
  72. <script setup>
  73. import {
  74. computed,
  75. reactive,
  76. watchEffect,
  77. nextTick,
  78. onUnmounted
  79. } from 'vue';
  80. import {
  81. onLoad
  82. } from '@dcloudio/uni-app';
  83. import sheep from '@/sheep';
  84. import { clone } from 'lodash';
  85. import {
  86. fen2yuan,
  87. points2point
  88. } from '@/sheep/hooks/useGoods';
  89. import md5 from 'blueimp-md5';
  90. import PayWalletApi from '@/sheep/api/pay/wallet';
  91. import WithdrawalApi from '@/sheep/api/distri/withdrawal';
  92. import { showAuthModal, showShareModal } from '@/sheep/hooks/useModal';
  93. import { t } from '@/locale'
  94. const userWallet = computed(() => sheep.$store('user').userWallet);
  95. const userInfo = computed(() => sheep.$store('user').userInfo);
  96. const canUseMoney = computed(() => points2point(userWallet.value.integralDO.currentQuota));
  97. const alipayAccount = (account) => {
  98. // let account = state.model.alipayAccount;
  99. if (!account) {
  100. return false
  101. }
  102. // 手机号脱敏
  103. if (/^\d{11}$/.test(account)) { // 检查是否是11位数字的手机号
  104. return `${account.substring(0, 3)}****${account.substring(7)}`;
  105. } else if (/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/.test(account)) {
  106. const atIndex = account.indexOf('@');
  107. // 邮箱用户名长度小于等于3位时,不脱敏
  108. if (atIndex <= 3) {
  109. return account;
  110. }
  111. const username = account.substring(0, Math.ceil(atIndex / 2)); // 取邮箱用户名的一半
  112. const domain = account.substring(atIndex); // 邮箱域名部分
  113. return `${username}***${domain}`;
  114. }
  115. }
  116. const bankAccount = (account) => {
  117. if (!account) {
  118. return false
  119. }
  120. if (account.length === 8) {
  121. return account.substring(0, 2) + '********' + account.substr(-2);
  122. } else {
  123. return account.substring(0, 4) + '******' + account.substr(-4);
  124. }
  125. }
  126. const state = reactive({
  127. model: {},
  128. orderType: 'goods', // 订单类型; goods - 商品订单, recharge - 充值订单
  129. outMent: '',
  130. outMoney:undefined,
  131. disabled:true,
  132. withdrawalPercentage:{
  133. withdrawCommission:0,
  134. withdrawConsumption:0
  135. },
  136. outMethods: [
  137. // {
  138. // title: t('wallet.withdraw_to_wechat'),
  139. // value: '1'
  140. // },
  141. {
  142. title: t('wallet.withdraw_to_alipay'),
  143. value: '2',
  144. account:''
  145. },
  146. {
  147. title: t('wallet.withdraw_to_bank_card'),
  148. value: '3',
  149. account:''
  150. }
  151. ]
  152. });
  153. const withdrawCommission = computed(() => {
  154. return state.withdrawalPercentage.withdrawCommission * 100 + '%';
  155. });
  156. const withdrawConsumption = computed(() => {
  157. return state.withdrawalPercentage.withdrawConsumption * 100 + '%';
  158. });
  159. const commission = computed(() => {
  160. if(!state.outMoney){
  161. return 0;
  162. }
  163. let result = parseFloat(state.withdrawalPercentage.withdrawCommission) * state.outMoney;
  164. // 地板除到小数点后两位
  165. result = Math.floor(result * 100) / 100;
  166. return result;
  167. });
  168. const consumption = computed(() => {
  169. if(!state.outMoney){
  170. return 0;
  171. }
  172. let result = parseFloat(state.withdrawalPercentage.withdrawConsumption) * state.outMoney;
  173. // 地板除到小数点后两位
  174. result = Math.floor(result * 100) / 100;
  175. return result;
  176. });
  177. const handleBind = async (type) => {
  178. // console.log(type)
  179. if(type === '2'){
  180. showAuthModal('alipayAccount');
  181. }else if(type === '3'){
  182. showAuthModal('bankAccount');
  183. }
  184. }
  185. const submit = async () => {
  186. if (state.outMent === '') {
  187. sheep.$helper.toast(t('wallet.please_select_withdrawal_method'));
  188. return;
  189. }
  190. if (!state.outMoney) {
  191. sheep.$helper.toast(t('wallet.enter_withdrawal_amount'));
  192. return;
  193. }
  194. if (state.outMent === '2' && !userInfo.value.alipayAccount){
  195. // 没绑定支付宝
  196. uni.showModal({
  197. title: t('setting.prompt'),
  198. content: t('wallet.alipay_not_bound'),
  199. confirmText:t('wallet.go_bind'),
  200. success: async function(res) {
  201. if (!res.confirm) {
  202. return;
  203. }
  204. showAuthModal('alipayAccount');
  205. },
  206. });
  207. return;
  208. }
  209. if (state.outMent === '3' && !userInfo.value.bankAccount){
  210. // 没绑定银行卡
  211. uni.showModal({
  212. title: t('setting.prompt'),
  213. content: t('wallet.bank_card_not_bound'),
  214. confirmText:t('wallet.go_bind'),
  215. success: async function(res) {
  216. if (!res.confirm) {
  217. return;
  218. }
  219. showAuthModal('bankAccount');
  220. },
  221. });
  222. return;
  223. }
  224. let {
  225. code,
  226. data
  227. } = await PayWalletApi.createWithdrawal({
  228. amountTotal:state.outMoney,
  229. withdrawalType:state.outMent
  230. });
  231. if(code === 0){
  232. uni.showToast({
  233. icon: 'success',
  234. title: t('wallet.application_successful'),
  235. });
  236. sheep.$router.redirect('/pages/user/wallet/withdrawalLog')
  237. uni.$emit('createWithDrawComplete');
  238. }
  239. };
  240. // 切换提现方式
  241. function onTapOut(e) {
  242. state.outMent = e.detail.value;
  243. }
  244. // 提现全部佣金
  245. async function useAllPonints(){
  246. const {code,data} = await PayWalletApi.getDuserInfo();
  247. const userCanUsePoints = parseFloat(points2point(data.integralDO.currentQuota));
  248. state.outMoney = parseInt(userCanUsePoints);
  249. state.disable = false;
  250. }
  251. watchEffect(() => {
  252. // 提现金额不能大于可用佣金
  253. if (parseFloat(state.outMoney) > parseFloat(canUseMoney.value)) {
  254. // 使用 nextTick 确保 DOM 更新
  255. nextTick(() => {
  256. state.outMoney = parseInt(canUseMoney.value);
  257. });
  258. }
  259. // 如果计算出来的当前可以使用的最大佣金等于小于0 则不给输入
  260. if(canUseMoney.value == 0 || canUseMoney.value < 0){
  261. state.disabled = true
  262. }
  263. if(canUseMoney.value > 0){
  264. state.disabled = false
  265. }
  266. })
  267. // 获得用户信息
  268. const getUserInfo = async () => {
  269. // 个人信息
  270. const userInfo = await sheep.$store('user').getInfo();
  271. state.model = clone(userInfo);
  272. state.outMethods.forEach(item=>{
  273. if(item.value === '2'){
  274. item.account = alipayAccount(state.model.alipayAccount);
  275. }else if(item.value === '3'){
  276. item.account = bankAccount(state.model.bankAccount);
  277. }
  278. })
  279. };
  280. const getWithdrawalPercentage = async () => {
  281. const {code,data} = await WithdrawalApi.getWithdrawalPercentage();
  282. if(code === 0){
  283. state.withdrawalPercentage = data;
  284. }
  285. }
  286. onLoad(async(options) => {
  287. await getUserInfo();
  288. await getWithdrawalPercentage();
  289. // refresh()
  290. uni.$on('alipayAccountChangeComplete', getUserInfo);
  291. uni.$on('bankAccountChangeComplete', getUserInfo);
  292. });
  293. </script>
  294. <style lang="scss" scoped>
  295. .all-btn{
  296. height: 60rpx;
  297. line-height: 60rpx;
  298. min-width: 80rpx;
  299. padding: 0 30rpx;
  300. border-radius: 30rpx;
  301. font-size: 26rpx;
  302. margin-right: 10rpx;
  303. border: 2rpx solid var(--ui-BG-Main);
  304. color: var(--ui-BG-Main);
  305. }
  306. .out-icon {
  307. width: 36rpx;
  308. height: 36rpx;
  309. margin-right: 26rpx;
  310. }
  311. .ss-modal-box {
  312. height: calc(100vh - 88rpx);
  313. // max-height: 1000rpx;
  314. .input-money {
  315. width:90% ;
  316. padding:0 10rpx;
  317. // text-indent: 20rpx;
  318. height: 80rpx;
  319. border: 1px solid #bbbbbb;
  320. border-radius: 10rpx;
  321. margin: 15rpx auto;
  322. font-size: 28rpx;
  323. input{
  324. width: 100%;
  325. height: 100%;
  326. font-size: 28rpx;
  327. }
  328. }
  329. .modal-header {
  330. position: relative;
  331. padding: 60rpx 20rpx 40rpx;
  332. .money-text {
  333. color: $red;
  334. font-size: 46rpx;
  335. font-weight: bold;
  336. font-family: OPPOSANS;
  337. &::before {
  338. content: '¥';
  339. font-size: 30rpx;
  340. }
  341. }
  342. .time-text {
  343. font-size: 26rpx;
  344. color: $gray-b;
  345. }
  346. .close-icon {
  347. position: absolute;
  348. top: 10rpx;
  349. right: 20rpx;
  350. font-size: 46rpx;
  351. opacity: 0.2;
  352. }
  353. }
  354. .modal-content {
  355. overflow-y: auto;
  356. .out-title {
  357. font-size: 26rpx;
  358. font-weight: 500;
  359. color: #333333;
  360. }
  361. .out-tip {
  362. font-size: 26rpx;
  363. color: #bbbbbb;
  364. }
  365. .out-item {
  366. height: 86rpx;
  367. }
  368. .disabled-out-item {
  369. .out-title {
  370. color: #999999;
  371. }
  372. }
  373. .userInfo-money {
  374. font-size: 26rpx;
  375. color: #bbbbbb;
  376. line-height: normal;
  377. }
  378. }
  379. .save-btn {
  380. width: 710rpx;
  381. height: 80rpx;
  382. border-radius: 40rpx;
  383. background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
  384. color: $white;
  385. }
  386. .disabled-btn {
  387. background: #e5e5e5;
  388. color: #999999;
  389. }
  390. .past-due-btn {
  391. width: 710rpx;
  392. height: 80rpx;
  393. border-radius: 40rpx;
  394. background-color: #999;
  395. color: #fff;
  396. }
  397. }
  398. </style>