下载账单、优化账单查询
This commit is contained in:
@@ -178,7 +178,27 @@ const DownloadBill: React.FC = () => {
|
||||
const { transaction_sub_type } = load_transactions_params;
|
||||
const { start, end } = dateRange;
|
||||
const date_range = [start, end];
|
||||
await httpService.post("/wallet/download_bill", {transaction_sub_type, date_range});
|
||||
const res = await httpService.post("/wallet/download_bill", { transaction_sub_type, date_range });
|
||||
const { fileUrl, fileName } = res.data;
|
||||
// 调用下载文件接口
|
||||
wx.downloadFile({
|
||||
url: fileUrl, // 文件路径
|
||||
success: function (res) {
|
||||
// 只有200状态码表示下载成功
|
||||
if (res.statusCode === 200) {
|
||||
// 下载成功后可以使用res.tempFilePath访问临时文件路径
|
||||
console.log('文件下载成功,临时路径为:', res.tempFilePath);
|
||||
// 保存文件到本地
|
||||
wx.openDocument({
|
||||
filePath: res.tempFilePath,
|
||||
showMenu: true // 显示保存菜单
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: function (err) {
|
||||
console.error('文件下载失败:', err);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
@@ -187,7 +207,7 @@ const DownloadBill: React.FC = () => {
|
||||
<View className="download_bill_page">
|
||||
<View className="hint_content">
|
||||
<Text>最长可导出三个月的账单 </Text>
|
||||
<Text className="button_text">示例文件</Text>
|
||||
{/* <Text className="button_text">示例文件</Text> */}
|
||||
</View>
|
||||
<View className="form_container">
|
||||
{/* <View className="form_item">
|
||||
@@ -226,9 +246,8 @@ const DownloadBill: React.FC = () => {
|
||||
近一周
|
||||
</View>
|
||||
<View
|
||||
className={`option_button ${
|
||||
dateType === "month" ? "active" : ""
|
||||
}`}
|
||||
className={`option_button ${dateType === "month" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
selectDateRange("month");
|
||||
}}
|
||||
@@ -236,9 +255,8 @@ const DownloadBill: React.FC = () => {
|
||||
近一月
|
||||
</View>
|
||||
<View
|
||||
className={`option_button ${
|
||||
dateType === "custom" ? "active" : ""
|
||||
}`}
|
||||
className={`option_button ${dateType === "custom" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
selectDateRange("custom");
|
||||
}}
|
||||
|
||||
@@ -2,41 +2,71 @@ import React, { useState, useEffect } from "react";
|
||||
import { View, Text } from "@tarojs/components";
|
||||
|
||||
import "./index.scss";
|
||||
import httpService from "@/services/httpService";
|
||||
import Taro from "@tarojs/taro";
|
||||
|
||||
interface BillRecord {
|
||||
id: number;
|
||||
file_name: string;
|
||||
download_url: string;
|
||||
file_size: number;
|
||||
create_time: string;
|
||||
expire_time: string;
|
||||
bill_date_range_start: string;
|
||||
bill_date_range_end: string;
|
||||
bill_transaction_type: string;
|
||||
bill_transaction_sub_type: string;
|
||||
date_range_desc: string;
|
||||
transaction_type_desc: string;
|
||||
transaction_sub_type_desc: string;
|
||||
}
|
||||
|
||||
const DownloadBillRecords: React.FC = () => {
|
||||
const [records, setRecords] = useState<BillRecord[]>([]);
|
||||
const [params, setParams] = useState({
|
||||
page: 1,
|
||||
limit: 20,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
fetchRecords();
|
||||
}, []);
|
||||
|
||||
const fetchRecords = async () => {
|
||||
try {
|
||||
const response = await httpService.post<{ rows: BillRecord[] }>('/wallet/download_history', params);
|
||||
setRecords(response.data.rows);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
Taro.showToast({
|
||||
title: '获取账单记录失败',
|
||||
icon: 'none',
|
||||
duration: 2000,
|
||||
});
|
||||
}
|
||||
};
|
||||
return (
|
||||
<View className="download-bill-records-page">
|
||||
<View className="records-container">
|
||||
<View className="record-item">
|
||||
<View className="title-text">账单流水文件</View>
|
||||
<View className="info-item">
|
||||
<Text>申请时间</Text>
|
||||
<Text>2025年9月12日 19:03:06</Text>
|
||||
</View>
|
||||
<View className="info-item">
|
||||
<Text>账单范围</Text>
|
||||
<Text>2025年9月12日 19:03:06 至 2025年9月12日 19:03:06</Text>
|
||||
</View>
|
||||
<View className="info-item">
|
||||
<Text></Text>
|
||||
<Text className="btn">查看材料</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View className="record-item">
|
||||
<View className="title-text">账单流水文件</View>
|
||||
<View className="info-item">
|
||||
<Text>申请时间</Text>
|
||||
<Text>2025年9月12日 19:03:06</Text>
|
||||
</View>
|
||||
<View className="info-item">
|
||||
<Text>账单范围</Text>
|
||||
<Text>2025年9月12日 19:03:06 至 2025年9月12日 19:03:06</Text>
|
||||
</View>
|
||||
<View className="info-item">
|
||||
<Text></Text>
|
||||
<Text className="btn">查看材料</Text>
|
||||
</View>
|
||||
</View>
|
||||
{
|
||||
records.map((record) => (
|
||||
<View className="record-item" key={record.id}>
|
||||
<View className="title-text">{record.file_name}</View>
|
||||
<View className="info-item">
|
||||
<Text>申请时间</Text>
|
||||
<Text>{record.create_time}</Text>
|
||||
</View>
|
||||
<View className="info-item">
|
||||
<Text>账单范围</Text>
|
||||
<Text>{record.date_range_desc}</Text>
|
||||
</View>
|
||||
<View className="info-item">
|
||||
<Text></Text>
|
||||
<Text className="btn">查看材料</Text>
|
||||
</View>
|
||||
</View>
|
||||
))
|
||||
}
|
||||
</View>
|
||||
<View className="tips">出于信息安全考虑,仅保留并展示7天内的账单下载记录</View>
|
||||
</View>
|
||||
|
||||
@@ -23,8 +23,28 @@ const ValidPhone: React.FC = () => {
|
||||
};
|
||||
|
||||
const handleConfirm = async () => {
|
||||
// TODO: 校验验证码
|
||||
Taro.navigateTo({ url: `/user_pages/setTransactionPassword/index?type=reset&phone=${formData.phone}&sms_code=${formData.sms_code}` });
|
||||
const isValid = await validSMSCode();
|
||||
if (isValid) {
|
||||
Taro.navigateTo({ url: `/user_pages/setTransactionPassword/index?type=reset&phone=${formData.phone}&sms_code=${formData.sms_code}` });
|
||||
}
|
||||
};
|
||||
|
||||
const validSMSCode = async () => {
|
||||
const { phone, sms_code } = formData;
|
||||
try {
|
||||
const res = await httpService.post("/wallet/verify_sms_code", { phone, sms_code, type: "reset_password" });
|
||||
const { verified } = res.data;
|
||||
if (verified) {
|
||||
return true;
|
||||
} else {
|
||||
Taro.showToast({ title: "验证码校验失败", icon: "none" });
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
Taro.showToast({ title: "验证码校验失败", icon: "none" });
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const getSMSCode = async () => {
|
||||
|
||||
@@ -146,7 +146,6 @@
|
||||
border: 0.5px solid #EBEBEB;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0px 0px 36px 0px rgba(0, 0, 0, 0.1);
|
||||
overflow: hidden;
|
||||
|
||||
.history_header {
|
||||
display: flex;
|
||||
@@ -154,6 +153,9 @@
|
||||
align-items: center;
|
||||
padding: 12px 20px;
|
||||
border-bottom: 0.5px solid rgba(120, 120, 128, 0.12);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background-color: #fff;
|
||||
|
||||
.history_title {
|
||||
font-size: 16px;
|
||||
|
||||
@@ -5,6 +5,7 @@ import "./index.scss";
|
||||
import { CommonPopup } from "@/components";
|
||||
import httpService from "@/services/httpService";
|
||||
import { withAuth } from "@/components";
|
||||
import { PopupPicker } from "@/components/Picker/index";
|
||||
|
||||
// 交易记录类型
|
||||
interface Transaction {
|
||||
@@ -111,6 +112,16 @@ const WalletPage: React.FC = () => {
|
||||
|
||||
// 交易记录过滤状态
|
||||
const [showFilterPopup, setShowFilterPopup] = useState(false);
|
||||
const [showMonthPicker, setShowMonthPicker] = useState(false);
|
||||
|
||||
const [filterParams, setFilterParams] = useState({
|
||||
type: TransactionType.All,
|
||||
transaction_sub_type: TransactionSubType.All,
|
||||
});
|
||||
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = String(now.getMonth() + 1).padStart(2, "0");
|
||||
|
||||
const [load_transactions_params, set_load_transactions_params] =
|
||||
useState<TransactionLoadParams>({
|
||||
@@ -119,16 +130,31 @@ const WalletPage: React.FC = () => {
|
||||
type: TransactionType.All,
|
||||
transaction_sub_type: TransactionSubType.All,
|
||||
keyword: "",
|
||||
date: "",
|
||||
date: `${year}-${month}`
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
load_transactions();
|
||||
}, [load_transactions_params]);
|
||||
// 页面显示时加载数据
|
||||
useDidShow(() => {
|
||||
load_wallet_data();
|
||||
load_transactions();
|
||||
check_password_status();
|
||||
});
|
||||
|
||||
const modify_load_transactions_params = () => {
|
||||
const { type, transaction_sub_type } = filterParams;
|
||||
set_load_transactions_params((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
type,
|
||||
transaction_sub_type,
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
|
||||
const check_password_status = async () => {
|
||||
try {
|
||||
const res = await httpService.post("/wallet/check_password_status");
|
||||
@@ -182,11 +208,10 @@ const WalletPage: React.FC = () => {
|
||||
// 加载交易记录
|
||||
const load_transactions = async () => {
|
||||
setShowFilterPopup(false);
|
||||
set_load_transactions_params({ ...load_transactions_params, page: 1 });
|
||||
// set_load_transactions_params({ ...load_transactions_params, page: 1 });
|
||||
try {
|
||||
set_loading_transactions(true);
|
||||
console.log("开始加载交易记录...");
|
||||
|
||||
const response = await httpService.post("/wallet/transactions", {
|
||||
...load_transactions_params,
|
||||
});
|
||||
@@ -327,6 +352,7 @@ const WalletPage: React.FC = () => {
|
||||
|
||||
// 格式化时间显示
|
||||
const format_time = (time: string) => {
|
||||
time = time.replace(/-/g, "/");
|
||||
const date = new Date(time);
|
||||
const month = String(date.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(date.getDate()).padStart(2, "0");
|
||||
@@ -380,6 +406,14 @@ const WalletPage: React.FC = () => {
|
||||
setShowFilterPopup(true);
|
||||
};
|
||||
|
||||
const handleFilterCancel = () => {
|
||||
setShowFilterPopup(false);
|
||||
setFilterParams({
|
||||
type: load_transactions_params.type,
|
||||
transaction_sub_type: load_transactions_params.transaction_sub_type,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<View className="wallet_page">
|
||||
{/* 钱包主卡片 */}
|
||||
@@ -465,8 +499,8 @@ const WalletPage: React.FC = () => {
|
||||
{/* 标题栏 */}
|
||||
<View className="history_header">
|
||||
<Text className="history_title">现金明细</Text>
|
||||
<View className="month_selector">
|
||||
<Text className="current_month">2025-09</Text>
|
||||
<View className="month_selector" onClick={() => setShowMonthPicker(true)}>
|
||||
<Text className="current_month">{load_transactions_params.date}</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -557,12 +591,30 @@ const WalletPage: React.FC = () => {
|
||||
</View>
|
||||
</View>
|
||||
</CommonPopup>
|
||||
|
||||
{/* 选择月份弹窗 */}
|
||||
{showMonthPicker && (
|
||||
<PopupPicker
|
||||
visible={showMonthPicker}
|
||||
setvisible={setShowMonthPicker}
|
||||
value={[
|
||||
Number(load_transactions_params.date!.split("-")[0]),
|
||||
Number(load_transactions_params.date!.split("-")[1])
|
||||
]}
|
||||
type="month"
|
||||
onChange={(e) => {
|
||||
const [year, month] = e;
|
||||
set_load_transactions_params({
|
||||
...load_transactions_params,
|
||||
date: `${year}-${String(month).padStart(2, "0")}`,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{/* 筛选账单弹窗 */}
|
||||
<CommonPopup
|
||||
visible={showFilterPopup}
|
||||
onClose={() => setShowFilterPopup(false)}
|
||||
onConfirm={load_transactions}
|
||||
onClose={handleFilterCancel}
|
||||
onConfirm={modify_load_transactions_params}
|
||||
title="选择筛选项"
|
||||
className="filter_popup"
|
||||
>
|
||||
@@ -575,14 +627,14 @@ const WalletPage: React.FC = () => {
|
||||
(option: Option<TransactionType>) => (
|
||||
<View
|
||||
className={
|
||||
load_transactions_params.type === option.value
|
||||
filterParams.type === option.value
|
||||
? "option_item active"
|
||||
: "option_item"
|
||||
}
|
||||
key={option.value}
|
||||
onClick={() => {
|
||||
set_load_transactions_params({
|
||||
...load_transactions_params,
|
||||
setFilterParams({
|
||||
...filterParams,
|
||||
type: option.value,
|
||||
});
|
||||
}}
|
||||
@@ -600,15 +652,15 @@ const WalletPage: React.FC = () => {
|
||||
(option: Option<TransactionSubType>) => (
|
||||
<View
|
||||
className={
|
||||
load_transactions_params.transaction_sub_type ===
|
||||
filterParams.transaction_sub_type ===
|
||||
option.value
|
||||
? "option_item active"
|
||||
: "option_item"
|
||||
}
|
||||
key={option.value}
|
||||
onClick={() => {
|
||||
set_load_transactions_params({
|
||||
...load_transactions_params,
|
||||
setFilterParams({
|
||||
...filterParams,
|
||||
transaction_sub_type: option.value,
|
||||
});
|
||||
}}
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
}
|
||||
|
||||
.tips-container {
|
||||
padding: 20px 20px 0;
|
||||
padding: 20px 20px;
|
||||
|
||||
.title-text {
|
||||
font-weight: 600;
|
||||
|
||||
@@ -253,6 +253,7 @@ const Withdrawal: React.FC = () => {
|
||||
<Text>4. 用户在使用提现服务前,应充分了解并同意上述规则。</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 提现输入密码弹窗 */}
|
||||
<CommonPopup
|
||||
visible={show_withdraw_popup}
|
||||
|
||||
Reference in New Issue
Block a user