409 lines
12 KiB
TypeScript
409 lines
12 KiB
TypeScript
import { useState, useEffect, useRef } from "react";
|
|
import { View, Image, Text } from "@tarojs/components";
|
|
import { Input } from "@nutui/nutui-react-taro";
|
|
import img from "@/config/images";
|
|
import { withAuth, GeneralNavbar } from "@/components";
|
|
import "./index.scss";
|
|
import httpService from "@/services/httpService";
|
|
import Taro, { useReachBottom } from "@tarojs/taro";
|
|
interface Transaction {
|
|
id: number;
|
|
user_id: number;
|
|
transaction_type: string;
|
|
freeze_action: string | null;
|
|
amount: string;
|
|
description: string;
|
|
create_time: string;
|
|
last_modify_time: string;
|
|
related_id: number;
|
|
type_text: string;
|
|
}
|
|
|
|
interface History {
|
|
id: number;
|
|
keyword: string;
|
|
}
|
|
interface TransactionLoadParams {
|
|
page: number;
|
|
limit: number;
|
|
keyword: string;
|
|
}
|
|
|
|
const QueryTransactions = () => {
|
|
// 获取当前页面的配置
|
|
const currentPage = Taro.getCurrentInstance();
|
|
const pageConfig = currentPage.page?.config;
|
|
const pageTitle = pageConfig?.navigationBarTitleText;
|
|
const isInitialMount = useRef(true);
|
|
const [loading_transactions, set_loading_transactions] = useState(false);
|
|
const [transactions, setTransactions] = useState<Transaction[]>([]);
|
|
const [searchHistory, setSearchHistory] = useState<History[]>([]);
|
|
const ref = useRef<any>(null);
|
|
const [keyword, setKeyword] = useState("");
|
|
const [load_transactions_params, set_load_transactions_params] =
|
|
useState<TransactionLoadParams>({
|
|
page: 1,
|
|
limit: 20,
|
|
keyword: "",
|
|
});
|
|
const [totalpages, setTotalpages] = useState(1);
|
|
useEffect(() => {
|
|
getSearchHistory();
|
|
}, []);
|
|
|
|
// useEffect(() => {
|
|
// if (ref?.current) {
|
|
// ref.current.focus();
|
|
// }
|
|
// }, [ref.current]);
|
|
|
|
useReachBottom(() => {
|
|
if (load_transactions_params.page >= totalpages) return;
|
|
set_load_transactions_params((prev) => {
|
|
return {
|
|
...prev,
|
|
page: prev.page + 1,
|
|
};
|
|
});
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (isInitialMount.current) {
|
|
isInitialMount.current = false;
|
|
} else {
|
|
if (load_transactions_params.keyword === "") return;
|
|
handleSearch();
|
|
}
|
|
}, [load_transactions_params]);
|
|
|
|
// 是否显示清空图标
|
|
const isShowClearIcon =
|
|
load_transactions_params.keyword &&
|
|
load_transactions_params.keyword?.length > 0;
|
|
|
|
const getSearchHistory = async () => {
|
|
try {
|
|
const response = await httpService.post("/wallet/search_history", {
|
|
limit: 10,
|
|
});
|
|
if (response && response.data) {
|
|
setSearchHistory(response.data);
|
|
}
|
|
} catch (e) {
|
|
console.error(e);
|
|
}
|
|
};
|
|
/**
|
|
* @description 输入
|
|
* @param value
|
|
*/
|
|
const handleChange = (value: string) => {
|
|
setKeyword(value);
|
|
};
|
|
|
|
/**
|
|
* @description 点击清空输入内容
|
|
*/
|
|
const handleClear = (e) => {
|
|
e.stopPropagation();
|
|
setKeyword("");
|
|
setTransactions([]);
|
|
set_load_transactions_params((prev) => {
|
|
return { ...prev, page: 1, keyword: "" };
|
|
});
|
|
};
|
|
|
|
/**
|
|
* @description 点击历史搜索
|
|
* @param value
|
|
*/
|
|
const handleHistoryClick = (item: { id: number; keyword: string }) => {
|
|
setKeyword(item?.keyword);
|
|
set_load_transactions_params((prev) => {
|
|
return { ...prev, page: 1, keyword: item?.keyword };
|
|
});
|
|
};
|
|
|
|
/**
|
|
* @description 清空历史搜索
|
|
*/
|
|
const handleClearHistory = async () => {
|
|
await httpService.post("/wallet/clear_search_history");
|
|
setSearchHistory([]);
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (load_transactions_params.keyword === "") return;
|
|
getSearchHistory();
|
|
}, [load_transactions_params.keyword]);
|
|
|
|
/**
|
|
* @description 点击搜索
|
|
*/
|
|
const handleSearch = async () => {
|
|
// set_loading_transactions(true);
|
|
try {
|
|
const response = await httpService.post("/wallet/transactions", {
|
|
...load_transactions_params,
|
|
});
|
|
if (response && response.data && response.data.list.length) {
|
|
setTransactions([...transactions, ...response.data.list]);
|
|
setTotalpages(response.data.totalPages);
|
|
} else if (load_transactions_params.page === 1) {
|
|
setTransactions([]);
|
|
}
|
|
} catch (error) {
|
|
setTransactions([]);
|
|
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,
|
|
});
|
|
} finally {
|
|
set_loading_transactions(false);
|
|
}
|
|
};
|
|
|
|
// 格式化金额显示
|
|
const format_amount = (amount: number | string) => {
|
|
const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
|
|
return numAmount.toFixed(2);
|
|
};
|
|
|
|
// 格式化时间显示
|
|
const format_time = (time: string) => {
|
|
time = time.replace(/-/g, "/");
|
|
const date = new Date(time);
|
|
const year = String(date.getFullYear());
|
|
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: `${year}-${month}-${day}`,
|
|
time: `${hours}:${minutes}:${seconds}`,
|
|
};
|
|
};
|
|
|
|
// 获取交易类型文字
|
|
const get_transaction_type_text = (transaction: Transaction) => {
|
|
// 如果有描述信息,优先使用描述
|
|
if (transaction.description) {
|
|
return transaction.description;
|
|
}
|
|
|
|
const typeMap: { [key: string]: string } = {
|
|
income: "收入",
|
|
expense: "支出",
|
|
freeze: "冻结",
|
|
unfreeze: "解冻",
|
|
};
|
|
|
|
let typeText =
|
|
typeMap[transaction.transaction_type] || transaction.transaction_type;
|
|
|
|
// 如果有冻结操作,添加到类型文字中
|
|
if (transaction.freeze_action) {
|
|
const freezeMap: { [key: string]: string } = {
|
|
freeze: "冻结",
|
|
unfreeze: "解冻",
|
|
};
|
|
typeText += `(${freezeMap[transaction.freeze_action]})`;
|
|
}
|
|
|
|
return typeText;
|
|
};
|
|
|
|
const navigateToDetail = (id: number) => {
|
|
Taro.navigateTo({
|
|
url: `/user_pages/billDetail/index?id=${id}`,
|
|
});
|
|
};
|
|
|
|
// 获取金额显示(带符号)
|
|
const get_amount_display = (transaction: Transaction) => {
|
|
const isPositive = transaction.transaction_type === "income";
|
|
const prefix = isPositive ? "+" : "-";
|
|
return `${prefix}${format_amount(transaction.amount)}`;
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<View className="listSearchContainer">
|
|
{/* 导航栏 */}
|
|
{/* <View className="custom-navbar">
|
|
<View className="detail-navigator">
|
|
<View
|
|
className="detail-navigator-back"
|
|
onClick={() => {
|
|
Taro.navigateBack();
|
|
}}
|
|
>
|
|
<Image
|
|
className="detail-navigator-back-icon"
|
|
src={img.ICON_NAVIGATOR_BACK}
|
|
/>
|
|
<Text>{pageTitle}</Text>
|
|
</View>
|
|
</View>
|
|
</View> */}
|
|
{/* 顶部导航栏 */}
|
|
<GeneralNavbar
|
|
title={pageTitle}
|
|
showBack={true}
|
|
showAvatar={false}
|
|
onBack={() => {
|
|
Taro.navigateBack();
|
|
}}
|
|
/>
|
|
{/* 搜索 */}
|
|
<View className="topSearchWrapper">
|
|
<View className="topSearch">
|
|
<Image className="searchIcon" src={img.ICON_LIST_SEARCH_SEARCH} />
|
|
<Input
|
|
placeholder="查找"
|
|
value={keyword}
|
|
defaultValue={keyword}
|
|
onChange={handleChange}
|
|
onClear={handleClear}
|
|
onBlur={() => {
|
|
// load_transactions_params.keyword &&
|
|
// setKeyword(load_transactions_params.keyword);
|
|
}}
|
|
clearable={false}
|
|
ref={ref}
|
|
/>
|
|
<View className="searchRight">
|
|
{isShowClearIcon && (
|
|
<Image
|
|
className="clearIcon icon16"
|
|
src={img.ICON_LIST_SEARCH_CLEAR}
|
|
onClick={handleClear}
|
|
/>
|
|
)}
|
|
<View className="searchLine" />
|
|
<Text
|
|
className="searchText"
|
|
onClick={() => {
|
|
isInitialMount.current = false;
|
|
setTransactions([]);
|
|
set_load_transactions_params((prev) => {
|
|
return { ...prev, page: 1, keyword };
|
|
});
|
|
}}
|
|
>
|
|
搜索
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
{/* 查找历史 */}
|
|
{!isShowClearIcon && searchHistory.length > 0 && (
|
|
<View className="historySearch">
|
|
<View className="historySearchTitleWrapper">
|
|
<View className="historySearchTitle">查找历史</View>
|
|
<View className="historySearchClear" onClick={handleClearHistory}>
|
|
<Text>清空</Text>
|
|
<Image
|
|
className="clearIcon icon16"
|
|
src={img.ICON_LIST_SEARCH_CLEAR_HISTORY}
|
|
/>
|
|
</View>
|
|
</View>
|
|
|
|
{searchHistory.length && (
|
|
<View className="historySearchList">
|
|
{(searchHistory || [])?.map((item) => {
|
|
if (!item?.keyword) {
|
|
return null;
|
|
}
|
|
return (
|
|
<Text
|
|
className="historySearchItem"
|
|
onClick={() => handleHistoryClick(item)}
|
|
>
|
|
{item?.keyword}
|
|
</Text>
|
|
);
|
|
})}
|
|
</View>
|
|
)}
|
|
</View>
|
|
)}
|
|
|
|
{/* 交易记录列表 */}
|
|
<View className="transaction_list">
|
|
{loading_transactions ? (
|
|
<View className="loading_state">
|
|
<Text className="loading_text">加载中...</Text>
|
|
</View>
|
|
) : transactions.length > 0 &&
|
|
load_transactions_params.keyword !== "" ? (
|
|
transactions.map((transaction) => {
|
|
const timeInfo = format_time(transaction.create_time);
|
|
return (
|
|
<View
|
|
key={transaction.id}
|
|
className="transaction_item"
|
|
onClick={() => {
|
|
navigateToDetail(transaction.id);
|
|
}}
|
|
>
|
|
<View className="transaction_left">
|
|
<Text className="transaction_title">
|
|
{get_transaction_type_text(transaction)}
|
|
</Text>
|
|
<View className="transaction_time">
|
|
<Text className="transaction_date">{timeInfo.date}</Text>
|
|
<Text className="transaction_clock">{timeInfo.time}</Text>
|
|
</View>
|
|
</View>
|
|
<View className="transaction_right">
|
|
<View>
|
|
<Text
|
|
className={`type_text_tag ${
|
|
transaction.type_text === "已提现" ? "success" : ""
|
|
}`}
|
|
>
|
|
{transaction.type_text}
|
|
</Text>
|
|
<Text className="transaction_amount">
|
|
{get_amount_display(transaction)}
|
|
</Text>
|
|
</View>
|
|
<Text className="balance_info">
|
|
余额 ¥{format_amount(transaction.amount)}
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
);
|
|
})
|
|
) : (
|
|
<View className="empty_state">
|
|
<Text className="empty_text">暂无交易记录</Text>
|
|
</View>
|
|
)}
|
|
</View>
|
|
{transactions.length > 0 && (
|
|
<View className="tips_text">仅支持查找2024年9月1日以后的账单</View>
|
|
)}
|
|
</View>
|
|
</>
|
|
);
|
|
};
|
|
export default withAuth(QueryTransactions);
|