账单详情页面
This commit is contained in:
@@ -28,18 +28,18 @@ interface WalletInfo {
|
||||
total_withdraw?: number;
|
||||
}
|
||||
|
||||
enum TransactionType {
|
||||
All = '',
|
||||
Income = 'income',
|
||||
Expense = 'expense',
|
||||
export enum TransactionType {
|
||||
All = "",
|
||||
Income = "income",
|
||||
Expense = "expense",
|
||||
}
|
||||
|
||||
enum TransactionSubType {
|
||||
All = '',
|
||||
GameActivity = 'game_activity',
|
||||
Withdrawal = 'withdrawal',
|
||||
Refund = 'refund',
|
||||
Compensation = 'compensation',
|
||||
export enum TransactionSubType {
|
||||
All = "",
|
||||
GameActivity = "game_activity",
|
||||
Withdrawal = "withdrawal",
|
||||
Refund = "refund",
|
||||
Compensation = "compensation",
|
||||
}
|
||||
|
||||
interface TransactionLoadParams {
|
||||
@@ -57,43 +57,42 @@ interface Option<T> {
|
||||
|
||||
const income_expense_options: Option<TransactionType>[] = [
|
||||
{
|
||||
label: '全部',
|
||||
value: TransactionType.All
|
||||
label: "全部",
|
||||
value: TransactionType.All,
|
||||
},
|
||||
{
|
||||
label: '支出',
|
||||
value: TransactionType.Expense
|
||||
label: "支出",
|
||||
value: TransactionType.Expense,
|
||||
},
|
||||
{
|
||||
label: '收入',
|
||||
value: TransactionType.Income
|
||||
label: "收入",
|
||||
value: TransactionType.Income,
|
||||
},
|
||||
];
|
||||
|
||||
const transaction_type_options: Option<TransactionSubType>[] = [
|
||||
{
|
||||
label: '全部',
|
||||
value: TransactionSubType.All
|
||||
label: "全部",
|
||||
value: TransactionSubType.All,
|
||||
},
|
||||
{
|
||||
label: '组织活动',
|
||||
value: TransactionSubType.GameActivity
|
||||
label: "组织活动",
|
||||
value: TransactionSubType.GameActivity,
|
||||
},
|
||||
{
|
||||
label: '提现',
|
||||
value: TransactionSubType.Withdrawal
|
||||
label: "提现",
|
||||
value: TransactionSubType.Withdrawal,
|
||||
},
|
||||
{
|
||||
label: '退款',
|
||||
value: TransactionSubType.Refund
|
||||
label: "退款",
|
||||
value: TransactionSubType.Refund,
|
||||
},
|
||||
{
|
||||
label: '企业赔付',
|
||||
value: TransactionSubType.Compensation
|
||||
label: "企业赔付",
|
||||
value: TransactionSubType.Compensation,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
const WalletPage: React.FC = () => {
|
||||
// 钱包信息状态
|
||||
const [wallet_info, set_wallet_info] = useState<WalletInfo>({
|
||||
@@ -112,14 +111,15 @@ const WalletPage: React.FC = () => {
|
||||
// 交易记录过滤状态
|
||||
const [showFilterPopup, setShowFilterPopup] = useState(false);
|
||||
|
||||
const [load_transactions_params, set_load_transactions_params] = useState<TransactionLoadParams>({
|
||||
page: 1,
|
||||
limit: 20,
|
||||
type: TransactionType.All,
|
||||
transaction_sub_type: TransactionSubType.All,
|
||||
keyword: "",
|
||||
date: ""
|
||||
});
|
||||
const [load_transactions_params, set_load_transactions_params] =
|
||||
useState<TransactionLoadParams>({
|
||||
page: 1,
|
||||
limit: 20,
|
||||
type: TransactionType.All,
|
||||
transaction_sub_type: TransactionSubType.All,
|
||||
keyword: "",
|
||||
date: "",
|
||||
});
|
||||
|
||||
// 页面显示时加载数据
|
||||
useDidShow(() => {
|
||||
@@ -131,19 +131,30 @@ const WalletPage: React.FC = () => {
|
||||
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;
|
||||
const {
|
||||
balance,
|
||||
frozen_balance,
|
||||
total_balance,
|
||||
total_income,
|
||||
total_withdraw,
|
||||
} = response.data;
|
||||
set_wallet_info({
|
||||
balance,
|
||||
frozen_balance,
|
||||
total_balance,
|
||||
total_income,
|
||||
total_withdraw
|
||||
total_withdraw,
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error("加载钱包数据失败:", error);
|
||||
|
||||
let errorMessage = "加载失败,请重试";
|
||||
if (error && error.response && error.response.data && error.response.data.message) {
|
||||
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;
|
||||
@@ -165,7 +176,9 @@ const WalletPage: React.FC = () => {
|
||||
set_loading_transactions(true);
|
||||
console.log("开始加载交易记录...");
|
||||
|
||||
const response = await httpService.post("/wallet/transactions", { ...load_transactions_params });
|
||||
const response = await httpService.post("/wallet/transactions", {
|
||||
...load_transactions_params,
|
||||
});
|
||||
|
||||
console.log("交易记录响应:", response);
|
||||
|
||||
@@ -181,7 +194,12 @@ const WalletPage: React.FC = () => {
|
||||
set_transactions([]);
|
||||
|
||||
let errorMessage = "加载交易记录失败";
|
||||
if (error && error.response && error.response.data && error.response.data.message) {
|
||||
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;
|
||||
@@ -231,13 +249,12 @@ const WalletPage: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
set_submitting(true);
|
||||
|
||||
// 先调用后端接口获取提现参数
|
||||
const response = await httpService.post("/wallet/withdraw", {
|
||||
amount: parseFloat(withdraw_amount),
|
||||
transfer_remark: "用户申请提现"
|
||||
transfer_remark: "用户申请提现",
|
||||
});
|
||||
|
||||
// 根据后端返回的数据结构解析参数
|
||||
@@ -268,31 +285,28 @@ const WalletPage: React.FC = () => {
|
||||
},
|
||||
fail: (res) => {
|
||||
console.log("微信转账失败:", res);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
// 格式化金额显示
|
||||
const format_amount = (amount: number | string) => {
|
||||
const numAmount = typeof amount === 'string' ? parseFloat(amount) : amount;
|
||||
const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
|
||||
return numAmount.toFixed(2);
|
||||
};
|
||||
|
||||
// 格式化时间显示
|
||||
const format_time = (time: string) => {
|
||||
const date = new Date(time);
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(date.getSeconds()).padStart(2, '0');
|
||||
const month = String(date.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(date.getDate()).padStart(2, "0");
|
||||
const hours = String(date.getHours()).padStart(2, "0");
|
||||
const minutes = String(date.getMinutes()).padStart(2, "0");
|
||||
const seconds = String(date.getSeconds()).padStart(2, "0");
|
||||
|
||||
return {
|
||||
date: `2025-${month}-${day}`,
|
||||
time: `${hours}:${minutes}:${seconds}`
|
||||
time: `${hours}:${minutes}:${seconds}`,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -304,19 +318,20 @@ const WalletPage: React.FC = () => {
|
||||
}
|
||||
|
||||
const typeMap: { [key: string]: string } = {
|
||||
'income': '收入',
|
||||
'expense': '支出',
|
||||
'freeze': '冻结',
|
||||
'unfreeze': '解冻'
|
||||
income: "收入",
|
||||
expense: "支出",
|
||||
freeze: "冻结",
|
||||
unfreeze: "解冻",
|
||||
};
|
||||
|
||||
let typeText = typeMap[transaction.transaction_type] || transaction.transaction_type;
|
||||
let typeText =
|
||||
typeMap[transaction.transaction_type] || transaction.transaction_type;
|
||||
|
||||
// 如果有冻结操作,添加到类型文字中
|
||||
if (transaction.freeze_action) {
|
||||
const freezeMap: { [key: string]: string } = {
|
||||
'freeze': '冻结',
|
||||
'unfreeze': '解冻'
|
||||
freeze: "冻结",
|
||||
unfreeze: "解冻",
|
||||
};
|
||||
typeText += `(${freezeMap[transaction.freeze_action]})`;
|
||||
}
|
||||
@@ -326,14 +341,14 @@ const WalletPage: React.FC = () => {
|
||||
|
||||
// 获取金额显示(带符号)
|
||||
const get_amount_display = (transaction: Transaction) => {
|
||||
const isPositive = transaction.transaction_type === 'income';
|
||||
const prefix = isPositive ? '+' : '-';
|
||||
const isPositive = transaction.transaction_type === "income";
|
||||
const prefix = isPositive ? "+" : "-";
|
||||
return `${prefix}${format_amount(transaction.amount)}`;
|
||||
};
|
||||
|
||||
const show_filter_popup = () => {
|
||||
setShowFilterPopup(true)
|
||||
}
|
||||
setShowFilterPopup(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<View className="wallet_page">
|
||||
@@ -351,15 +366,24 @@ const WalletPage: React.FC = () => {
|
||||
<View className="amount_container">
|
||||
<Text className="currency_symbol">¥</Text>
|
||||
<View className="amount_group">
|
||||
<Text className="main_amount">{Math.floor(wallet_info.balance)}</Text>
|
||||
<Text className="decimal_amount">.{((wallet_info.balance % 1) * 100).toFixed(0).padStart(2, '0')}</Text>
|
||||
<Text className="main_amount">
|
||||
{Math.floor(wallet_info.balance)}
|
||||
</Text>
|
||||
<Text className="decimal_amount">
|
||||
.
|
||||
{((wallet_info.balance % 1) * 100)
|
||||
.toFixed(0)
|
||||
.padStart(2, "0")}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<Button className="withdraw_btn" onClick={handle_withdraw}>
|
||||
提现
|
||||
</Button>
|
||||
</View>
|
||||
<Text className="available_amount">可提现金额:¥{format_amount(wallet_info.balance)}</Text>
|
||||
<Text className="available_amount">
|
||||
可提现金额:¥{format_amount(wallet_info.balance)}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -367,18 +391,40 @@ const WalletPage: React.FC = () => {
|
||||
<View className="function_buttons">
|
||||
<View className="function_item" onClick={show_filter_popup}>
|
||||
<Text className="function_text">全部账单</Text>
|
||||
<Image className="function_icon" src={require("@/static/wallet/arrow-down.svg")} />
|
||||
<Image
|
||||
className="function_icon"
|
||||
src={require("@/static/wallet/arrow-down.svg")}
|
||||
/>
|
||||
</View>
|
||||
<View className="function_item" onClick={() => Taro.navigateTo({ url: "/user_pages/queryTransactions/index" })}>
|
||||
<Image className="function_icon" src={require("@/static/wallet/search.svg")} />
|
||||
<View
|
||||
className="function_item"
|
||||
onClick={() =>
|
||||
Taro.navigateTo({ url: "/user_pages/queryTransactions/index" })
|
||||
}
|
||||
>
|
||||
<Image
|
||||
className="function_icon"
|
||||
src={require("@/static/wallet/search.svg")}
|
||||
/>
|
||||
<Text className="function_text">查询交易</Text>
|
||||
</View>
|
||||
<View className="function_item" onClick={() => Taro.navigateTo({ url: "/user_pages/downloadBill/index" })}>
|
||||
<Image className="function_icon" src={require("@/static/wallet/download.svg")} />
|
||||
<View
|
||||
className="function_item"
|
||||
onClick={() =>
|
||||
Taro.navigateTo({ url: "/user_pages/downloadBill/index" })
|
||||
}
|
||||
>
|
||||
<Image
|
||||
className="function_icon"
|
||||
src={require("@/static/wallet/download.svg")}
|
||||
/>
|
||||
<Text className="function_text">下载账单</Text>
|
||||
</View>
|
||||
<View className="function_item">
|
||||
<Image className="function_icon" src={require("@/static/wallet/custom-service.svg")} />
|
||||
<Image
|
||||
className="function_icon"
|
||||
src={require("@/static/wallet/custom-service.svg")}
|
||||
/>
|
||||
<Text className="function_text">客服中心</Text>
|
||||
</View>
|
||||
</View>
|
||||
@@ -403,7 +449,15 @@ const WalletPage: React.FC = () => {
|
||||
transactions.map((transaction) => {
|
||||
const timeInfo = format_time(transaction.create_time);
|
||||
return (
|
||||
<View key={transaction.id} className="transaction_item">
|
||||
<View
|
||||
key={transaction.id}
|
||||
className="transaction_item"
|
||||
onClick={() => {
|
||||
Taro.navigateTo({
|
||||
url: `/user_pages/billDetail/index?id=${transaction.id}`,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<View className="transaction_left">
|
||||
<Text className="transaction_title">
|
||||
{get_transaction_type_text(transaction)}
|
||||
@@ -486,20 +540,54 @@ const WalletPage: React.FC = () => {
|
||||
<View className="form_item">
|
||||
<Text className="form_label">收支类型</Text>
|
||||
<View className="options_wrapper">
|
||||
{income_expense_options.map((option: Option<TransactionType>) => (
|
||||
<View className={load_transactions_params.type === option.value ? "option_item active" : "option_item"} key={option.value} onClick={() => { set_load_transactions_params({ ...load_transactions_params, type: option.value }) }}>{option.label}</View>
|
||||
))}
|
||||
{income_expense_options.map(
|
||||
(option: Option<TransactionType>) => (
|
||||
<View
|
||||
className={
|
||||
load_transactions_params.type === option.value
|
||||
? "option_item active"
|
||||
: "option_item"
|
||||
}
|
||||
key={option.value}
|
||||
onClick={() => {
|
||||
set_load_transactions_params({
|
||||
...load_transactions_params,
|
||||
type: option.value,
|
||||
});
|
||||
}}
|
||||
>
|
||||
{option.label}
|
||||
</View>
|
||||
)
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
<View className="form_item">
|
||||
<Text className="form_label">交易类型</Text>
|
||||
<View className="options_wrapper">
|
||||
{transaction_type_options.map((option: Option<TransactionSubType>) => (
|
||||
<View className={load_transactions_params.transaction_sub_type === option.value ? "option_item active" : "option_item"} key={option.value} onClick={() => { set_load_transactions_params({ ...load_transactions_params, transaction_sub_type: option.value }) }}>{option.label}</View>
|
||||
))}
|
||||
{transaction_type_options.map(
|
||||
(option: Option<TransactionSubType>) => (
|
||||
<View
|
||||
className={
|
||||
load_transactions_params.transaction_sub_type ===
|
||||
option.value
|
||||
? "option_item active"
|
||||
: "option_item"
|
||||
}
|
||||
key={option.value}
|
||||
onClick={() => {
|
||||
set_load_transactions_params({
|
||||
...load_transactions_params,
|
||||
transaction_sub_type: option.value,
|
||||
});
|
||||
}}
|
||||
>
|
||||
{option.label}
|
||||
</View>
|
||||
)
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
</View>
|
||||
</CommonPopup>
|
||||
|
||||
Reference in New Issue
Block a user