列表加载更多

This commit is contained in:
2025-09-30 17:18:44 +08:00
parent 9c9be49f0e
commit 5f13effcd4
6 changed files with 419 additions and 339 deletions

View File

@@ -1,206 +1,226 @@
.listSearchContainer {
padding: 0 15px;
padding-top: 16px;
padding: 0 15px;
padding-top: 16px;
.icon16 {
width: 16px;
height: 16px;
.icon16 {
width: 16px;
height: 16px;
}
.topSearchWrapper {
position: fixed;
top: 0;
left: 0;
background-color: #fff;
width: 100vw;
padding: 5px 15px;
box-sizing: border-box;
}
.topSearch {
display: flex;
align-items: center;
height: 44px;
box-sizing: border-box;
gap: 10px;
border-radius: 44px;
border: 0.5px solid rgba(0, 0, 0, 0.06);
background: #fff;
box-shadow: 0 4px 48px 0 rgba(0, 0, 0, 0.08);
padding: 0 16px 0 12px;
.nut-input {
padding: 0;
height: 100%;
}
}
.historySearch {
padding-top: 50px;
}
.searchRight {
display: flex;
align-items: center;
gap: 12px;
.searchLine {
width: 1px;
height: 20px;
border-radius: 20px;
background: rgba(0, 0, 0, 0.06);
}
.topSearch {
padding: 5px 16px 5px 12px;
display: flex;
align-items: center;
height: 44px;
box-sizing: border-box;
gap: 10px;
border-radius: 44px;
border: 0.5px solid rgba(0, 0, 0, 0.06);
background: #fff;
box-shadow: 0 4px 48px 0 rgba(0, 0, 0, 0.08);
.searchText {
color: #000000;
font-size: 16px;
font-weight: 600;
line-height: 20px;
}
}
.nut-input {
padding: 0;
height: 100%;
}
.searchIcon {
width: 20px;
height: 20px;
}
.historySearchTitleWrapper {
display: flex;
padding: 12px 0;
justify-content: space-between;
align-items: flex-end;
align-self: stretch;
.historySearchTitle,
.historySearchClear {
color: #000;
font-size: 14px;
font-weight: 600;
line-height: 20px;
}
.searchRight {
.historySearchClear {
color: #9a9a9a;
display: flex;
align-items: center;
gap: 4px;
}
}
.historySearchList {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
.historySearchItem {
color: #3c3c4399;
font-size: 12px;
flex-shrink: 0;
flex-grow: 0;
display: flex;
padding: 4px 12px;
justify-content: center;
align-items: center;
gap: 2px;
border-radius: 999px;
border: 0.5px solid rgba(0, 0, 0, 0.06);
background: rgba(0, 0, 0, 0.03);
}
}
.searchSuggestion {
padding: 6px 0;
.searchSuggestionItem {
padding: 10px 20px;
display: flex;
align-items: center;
justify-content: space-between;
.searchSuggestionItemLeft {
display: flex;
align-items: center;
gap: 12px;
color: rgba(60, 60, 67, 0.6);
font-size: 14px;
font-weight: 400;
line-height: 20px;
}
.searchLine {
width: 1px;
height: 20px;
border-radius: 20px;
background: rgba(0, 0, 0, 0.06);
}
.highlight {
color: #000000;
}
}
}
.searchText {
color: #000000;
font-size: 16px;
font-weight: 600;
line-height: 20px;
}
.transaction_list {
padding: 40px 0 70px;
.loading_state,
.empty_state {
padding: 40px 20px;
text-align: center;
.loading_text,
.empty_text {
font-size: 14px;
color: #999;
}
}
.searchIcon {
width: 20px;
height: 20px;
}
.transaction_item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 0;
.historySearchTitleWrapper {
.transaction_left {
display: flex;
padding: 12px 0;
justify-content: space-between;
flex-direction: column;
gap: 4px;
flex: 1;
.transaction_title {
font-size: 12px;
font-weight: 600;
color: #000;
line-height: 1.5;
text-align: left;
}
.transaction_time {
display: flex;
align-items: center;
align-self: stretch;
gap: 4px;
.transaction_date,
.transaction_clock {
font-size: 10px;
font-weight: 400;
color: rgba(60, 60, 67, 0.6);
line-height: 1.2;
text-align: left;
}
}
}
.transaction_right {
display: flex;
flex-direction: column;
align-items: flex-end;
align-self: stretch;
gap: 4px;
width: 68px;
.historySearchTitle,
.historySearchClear {
color: #000;
font-size: 14px;
font-weight: 600;
line-height: 20px;
.transaction_amount {
font-size: 12px;
font-weight: 600;
color: #000;
line-height: 1.5;
text-align: right;
}
.historySearchClear {
color: #9a9a9a;
display: flex;
align-items: center;
gap: 4px;
.balance_info {
font-size: 10px;
font-weight: 400;
color: rgba(60, 60, 67, 0.6);
line-height: 1.2;
text-align: right;
}
}
}
}
.historySearchList {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
.historySearchItem {
color: #3C3C4399;
font-size: 12px;
flex-shrink: 0;
flex-grow: 0;
display: flex;
padding: 4px 12px;
justify-content: center;
align-items: center;
gap: 2px;
border-radius: 999px;
border: 0.5px solid rgba(0, 0, 0, 0.06);
background: rgba(0, 0, 0, 0.03);
}
}
.searchSuggestion {
padding: 6px 0;
.searchSuggestionItem {
padding: 10px 20px;
display: flex;
align-items: center;
justify-content: space-between;
.searchSuggestionItemLeft {
display: flex;
align-items: center;
gap: 12px;
color: rgba(60, 60, 67, 0.6);
font-size: 14px;
font-weight: 400;
line-height: 20px;
}
.highlight {
color: #000000;
}
}
}
.transaction_list {
.loading_state,
.empty_state {
padding: 40px 20px;
text-align: center;
.loading_text,
.empty_text {
font-size: 14px;
color: #999;
}
}
.transaction_item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 0;
.transaction_left {
display: flex;
flex-direction: column;
gap: 4px;
flex: 1;
.transaction_title {
font-size: 12px;
font-weight: 600;
color: #000;
line-height: 1.5;
text-align: left;
}
.transaction_time {
display: flex;
align-items: center;
align-self: stretch;
gap: 4px;
.transaction_date,
.transaction_clock {
font-size: 10px;
font-weight: 400;
color: rgba(60, 60, 67, 0.6);
line-height: 1.2;
text-align: left;
}
}
}
.transaction_right {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 4px;
width: 68px;
.transaction_amount {
font-size: 12px;
font-weight: 600;
color: #000;
line-height: 1.5;
text-align: right;
}
.balance_info {
font-size: 10px;
font-weight: 400;
color: rgba(60, 60, 67, 0.6);
line-height: 1.2;
text-align: right;
}
}
}
}
.tips_text {
font-size: 12px;
text-align: center;
color: #3C3C4399;
margin-top: 20px;
}
}
.tips_text {
font-size: 12px;
text-align: center;
color: rgba(60, 60, 67, 0.6);
position: fixed;
bottom: 0;
left: 0;
width: 100%;
padding: 20px 0 40px;
background: #fff;
}
}

View File

@@ -1,12 +1,11 @@
import { useState } from "react";
import { useState, useEffect, useRef } from "react";
import { View, Image, Text } from "@tarojs/components";
import { Input } from "@nutui/nutui-react-taro";
import { useEffect, useRef } from "react";
import img from "@/config/images";
import { withAuth } from "@/components";
import "./index.scss";
import httpService from "@/services/httpService";
import Taro from "@tarojs/taro";
import Taro, { useReachBottom } from "@tarojs/taro";
interface Transaction {
id: number;
user_id: number;
@@ -19,15 +18,6 @@ interface Transaction {
related_id: number;
}
// 钱包信息类型
interface WalletInfo {
balance: number;
frozen_balance?: number;
total_balance?: number;
total_income?: number;
total_withdraw?: number;
}
interface History {
id: number;
keyword: string;
@@ -39,6 +29,7 @@ interface TransactionLoadParams {
}
const QueryTransactions = () => {
const isInitialMount = useRef(true);
const [loading_transactions, set_loading_transactions] = useState(false);
const [transactions, setTransactions] = useState<Transaction[]>([]);
const [searchHistory, setSearchHistory] = useState<History[]>([]);
@@ -63,6 +54,23 @@ const QueryTransactions = () => {
}
}, [ref.current]);
useReachBottom(() => {
set_load_transactions_params((prev) => {
return {
...prev,
page: prev.page + 1,
}
})
});
useEffect(() => {
if (isInitialMount.current) {
isInitialMount.current = false;
} else {
handleSearch();
}
}, [load_transactions_params]);
// 是否显示清空图标
const isShowClearIcon =
load_transactions_params.keyword &&
@@ -106,7 +114,6 @@ const QueryTransactions = () => {
*/
const handleHistoryClick = (item: { id: number; keyword: string }) => {
set_load_transactions_params((prev) => {
handleSearch(item?.keyword);
return { ...prev, keyword: item?.keyword };
});
};
@@ -123,21 +130,15 @@ const QueryTransactions = () => {
* @description 点击搜索
*/
const handleSearch = async (val?: string) => {
if (!val) {
return;
}
set_loading_transactions(true);
// set_loading_transactions(true);
try {
const response = await httpService.post("/wallet/transactions", {
...load_transactions_params,
keyword: val,
});
console.log("交易记录响应:", response);
if (response && response.data && response.data.list) {
setTransactions(response.data.list);
} else {
setTransactions([]);
setTransactions([...transactions, ...response.data.list]);
}
} catch (error) {
setTransactions([]);
@@ -169,13 +170,9 @@ const QueryTransactions = () => {
return numAmount.toFixed(2);
};
// 钱包信息状态
const [wallet_info, set_wallet_info] = useState<WalletInfo>({
balance: 0,
});
// 格式化时间显示
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");
@@ -235,33 +232,35 @@ const QueryTransactions = () => {
<>
<View className="listSearchContainer">
{/* 搜索 */}
<View className="topSearch">
<Image className="searchIcon" src={img.ICON_LIST_SEARCH_SEARCH} />
<Input
placeholder="查找"
value={load_transactions_params.keyword}
defaultValue={load_transactions_params.keyword}
onChange={handleChange}
onClear={handleClear}
autoFocus
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={() => handleSearch(load_transactions_params.keyword)}
>
</Text>
<View className="topSearchWrapper">
<View className="topSearch">
<Image className="searchIcon" src={img.ICON_LIST_SEARCH_SEARCH} />
<Input
placeholder="查找"
value={load_transactions_params.keyword}
defaultValue={load_transactions_params.keyword}
onChange={handleChange}
onClear={handleClear}
autoFocus
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={() => handleSearch(load_transactions_params.keyword)}
>
</Text>
</View>
</View>
</View>
{/* 查找历史 */}
@@ -329,7 +328,7 @@ const QueryTransactions = () => {
{get_amount_display(transaction)}
</Text>
<Text className="balance_info">
¥{format_amount(wallet_info.balance)}
¥{format_amount(transaction.amount)}
</Text>
</View>
</View>
@@ -341,11 +340,9 @@ const QueryTransactions = () => {
</View>
)}
</View>
{
transactions.length > 0 && (
<View className="tips_text">202491</View>
)
}
{transactions.length > 0 && (
<View className="tips_text">202491</View>
)}
</View>
</>
);