开发钱包相关页面,调试提现接口

This commit is contained in:
2025-09-27 23:08:32 +08:00
parent a1be43e02b
commit d6fb08eee4
13 changed files with 972 additions and 207 deletions

View File

@@ -0,0 +1,282 @@
import React, { useState, useEffect } from "react";
import { View, Text, Input, Button } from "@tarojs/components";
import Taro, { useDidShow } from "@tarojs/taro";
import httpService from "@/services/httpService";
import "./index.scss";
import { CommonPopup } from "@/components";
interface WalletInfo {
balance: string;
frozen_balance?: string;
total_balance?: string;
total_income?: string;
total_withdraw?: string;
}
const Withdrawal: React.FC = () => {
const [showTips, setShowTips] = useState(false);
const [tipsText, setTipsText] = useState<string>("");
const [inputValue, setInputValue] = useState<string>("0.00");
const [walletInfo, setWalletInfo] = useState<WalletInfo>({
balance: "0.00",
});
const [isFocus, setIsFocus] = useState(false);
const [show_withdraw_popup, set_show_withdraw_popup] = useState(false);
const [password, setPassword] = useState<string[]>(new Array(6).fill(""));
const toastConfig = {
aa: {
title: "已超单日限额",
content: "您今日提现已超过支付通道2000元单日限额建议您明日再发起提现资金仍安全存放在钱包余额中。"
},
bb: {
title: "已超单日限额",
content: "今日提现通道额度已用完,暂时无法提现;您的余额安全存放在钱包中,我们会在 次日0点恢复 提现服务;如有紧急情况,请联系客服。"
}
}
useDidShow(() => {
load_wallet_data();
});
useEffect(() => {
if (show_withdraw_popup) {
setIsFocus(true);
} else {
setPassword(new Array(6).fill(""));
setIsFocus(false);
}
}, [show_withdraw_popup]);
const validateWithdrawAmount = (amount: string) => {
if (Number(amount) > Number(walletInfo.balance)) {
setShowTips(true);
setTipsText("输入金额超过钱包余额");
} else if (Number(amount) > 200) {
setShowTips(true);
setTipsText("单笔提现金额不能超过 200元");
}
};
const withdrawAll = () => {
setInputValue(walletInfo.balance);
validateWithdrawAmount(walletInfo.balance);
};
const handleInput = (e: any) => {
console.log(e);
const value = e.detail.value;
setInputValue(value);
validateWithdrawAmount(value);
};
// 加载钱包数据
const load_wallet_data = async () => {
try {
const response = await httpService.post("/wallet/balance");
const {
balance,
frozen_balance,
total_balance,
total_income,
total_withdraw,
} = response.data;
setWalletInfo({
balance,
frozen_balance,
total_balance,
total_income,
total_withdraw,
});
} catch (error: any) {
console.error("加载钱包数据失败:", error);
let errorMessage = "加载失败,请重试";
if (
error &&
error.response &&
error.response.data &&
error.response.data.message
) {
errorMessage = error.response.data.message;
} else if (error && error.data && error.data.message) {
errorMessage = error.data.message;
}
Taro.showToast({
title: errorMessage,
icon: "error",
duration: 2000,
});
}
};
const handleWithdraw = async () => {
// TODO 校验提现状态
// if (true) {
// Taro.showToast({
// title: "您今日已累计提现 10次达到每日次数上限",
// icon: "none",
// });
// }
// const { aa, bb } = toastConfig;
// Taro.showModal({
// title: aa.title,
// content: aa.content,
// showCancel: false,
// confirmColor: "#000",
// });
// Taro.showModal({
// title: bb.title,
// content: bb.content,
// showCancel: false,
// confirmColor: "#000",
// });
set_show_withdraw_popup(true);
};
const submit_withdraw = async () => {
// 先调用后端接口获取提现参数
const response = await httpService.post("/wallet/withdraw", {
amount: parseFloat(inputValue),
transfer_remark: "用户申请提现",
});
// 根据后端返回的数据结构解析参数
const { mch_id, app_id, package_info, open_id } = response.data;
console.log("/wallet/withdraw:", response.data);
set_show_withdraw_popup(false);
// 调用微信商户转账接口
(Taro as any).requestMerchantTransfer({
mchId: mch_id,
appId: app_id,
package: package_info,
openId: open_id,
success: (res) => {
console.log("微信转账成功:", res);
Taro.showToast({
title: "提现成功",
icon: "success",
duration: 2000,
});
// 关闭弹窗并重置状态
set_show_withdraw_popup(false);
setInputValue("0.00");
// 重新加载数据
load_wallet_data();
},
fail: (res) => {
console.log("微信转账失败:", res);
},
});
}
const handlePasswordInput = (e: any) => {
const value = e.detail.value;
const [one = "", two = "", three = "", four = "", five = "", six = ""] = value.split("");
setPassword([one, two, three, four, five, six]);
if (value.length === 6) {
const timer = setTimeout(() => {
// TODO 校验密码
if (false) {
set_show_withdraw_popup(false);
Taro.showModal({
content: "支付密码错误,请重试",
cancelText: "忘记密码",
confirmText: "重试",
cancelColor: "#000",
confirmColor: "#fff",
}).then((res) => {
if (res.confirm) {
set_show_withdraw_popup(true);
} else if (res.cancel) {
Taro.navigateTo({
url: "/user_pages/validPhone/index"
});
}
}).finally(() => {
clearTimeout(timer);
});
} else {
submit_withdraw();
}
}, 100);
}
}
return (
<View className="withdrawal-page" >
<View className="withdrawal-container">
<Text className="title-text"></Text>
<View className="input-container">
<Text className="symbol">¥</Text>
<Input type="digit" placeholder="0.00" cursorColor="#000" value={inputValue} onInput={handleInput} />
{
!showTips && (Number(inputValue) !== 0) && (
<Button className="btn" onClick={handleWithdraw}></Button>
)
}
</View>
<View className="btn-container">
<View>
<Text>{`我的余额:¥${walletInfo.balance}`}</Text>
<Text>¥5000.00</Text>
</View>
<Text className="btn" onClick={withdrawAll}></Text>
</View>
{
showTips && (
<View className="tips-text">{tipsText}</View>
)
}
</View>
<View className="tips-container">
<View className="title-text"></View>
<View className="tips-text">
<Text>1. </Text>
<Text>2. </Text>
<Text>3. </Text>
<Text>4. </Text>
<Text>5. </Text>
<Text>6. </Text>
<Text>7. </Text>
</View>
</View>
<View className="tips-container">
<View className="title-text"></View>
<View className="tips-text">
<Text>1. </Text>
<Text>2. </Text>
<Text>3. </Text>
<Text>4. 使</Text>
</View>
</View>
{/* 提现输入密码弹窗 */}
<CommonPopup
visible={show_withdraw_popup}
onClose={() => set_show_withdraw_popup(false)}
title="提现"
className="withdraw_popup"
hideFooter={true}
>
<View className="popup_content">
<View className="popup_text">{`¥${inputValue}`}</View>
<View className="password_container">
{
password.map((item, index) => (
<View key={index} className="password_item">
<Text className="password_text">{item}</Text>
</View>
))
}
</View>
<Input focus={isFocus} type="number" style={{ width: "0", height: "0", opacity: "0" }} value={password.filter(item => item !== "").join("")} maxlength={6} onInput={handlePasswordInput} />
</View>
</CommonPopup>
</View >
);
};
export default Withdrawal;