Merge branch 'master' of https://gitee.com/ballminiprogramwe/mini-programs
This commit is contained in:
@@ -29,6 +29,7 @@ export default defineAppConfig({
|
||||
"queryTransactions/index", // 查询交易
|
||||
"downloadBill/index", // 下载账单
|
||||
"downloadBillRecords/index", // 下载账单记录
|
||||
"billDetail/index", // 账单详情
|
||||
],
|
||||
},
|
||||
// {
|
||||
|
||||
@@ -28,6 +28,8 @@ const DialogCalendarCard: React.FC<DialogCalendarCardProps> = ({
|
||||
const [selectedBackup, setSelectedBackup] = useState<Date[]>(
|
||||
Array.isArray(value) ? [...(value as Date[])] : [value as Date]
|
||||
);
|
||||
const [current, setCurrent] = useState<Date>(new Date());
|
||||
const [delta, setDelta] = useState(0);
|
||||
const calendarRef = useRef<CalendarUIRef>(null);
|
||||
const [type, setType] = useState<"year" | "month" | "time">("year");
|
||||
const [selectedHour, setSelectedHour] = useState(8);
|
||||
@@ -56,11 +58,11 @@ const DialogCalendarCard: React.FC<DialogCalendarCardProps> = ({
|
||||
setPendingJump({ year, month });
|
||||
setType("year");
|
||||
if (searchType === "range") {
|
||||
const delta = calculateMonthDifference(
|
||||
selected as Date,
|
||||
calculateMonthDifference(
|
||||
current,
|
||||
new Date(year, month - 1, 1)
|
||||
);
|
||||
calendarRef.current?.gotoMonth(delta);
|
||||
|
||||
return;
|
||||
}
|
||||
setSelected(new Date(year, month - 1, 1));
|
||||
@@ -77,10 +79,10 @@ const DialogCalendarCard: React.FC<DialogCalendarCardProps> = ({
|
||||
const minutes = minute.toString().padStart(2, "0");
|
||||
const finalDate = new Date(
|
||||
dayjs(selected as Date).format("YYYY-MM-DD") +
|
||||
" " +
|
||||
hours +
|
||||
":" +
|
||||
minutes
|
||||
" " +
|
||||
hours +
|
||||
":" +
|
||||
minutes
|
||||
);
|
||||
if (onChange) onChange(finalDate);
|
||||
}
|
||||
@@ -92,12 +94,11 @@ const DialogCalendarCard: React.FC<DialogCalendarCardProps> = ({
|
||||
if (!(date1 instanceof Date) || !(date2 instanceof Date)) {
|
||||
throw new Error("Both arguments must be Date objects");
|
||||
}
|
||||
|
||||
setCurrent(date1)
|
||||
let months = (date2.getFullYear() - date1.getFullYear()) * 12;
|
||||
months -= date1.getMonth();
|
||||
months += date2.getMonth();
|
||||
|
||||
return months;
|
||||
setDelta(months);
|
||||
};
|
||||
|
||||
const handleChange = (d: Date | Date[]) => {
|
||||
@@ -106,9 +107,8 @@ const DialogCalendarCard: React.FC<DialogCalendarCardProps> = ({
|
||||
if (d.length === 2) {
|
||||
return;
|
||||
} else if (d.length === 1) {
|
||||
debugger;
|
||||
if (selectedBackup.length === 0 || selectedBackup.length === 2) {
|
||||
setSelected([]);
|
||||
setSelected([...d]);
|
||||
setSelectedBackup([...d]);
|
||||
} else {
|
||||
setSelected(
|
||||
@@ -152,6 +152,10 @@ const DialogCalendarCard: React.FC<DialogCalendarCardProps> = ({
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
calendarRef.current?.gotoMonth(delta);
|
||||
}, [delta])
|
||||
|
||||
useEffect(() => {
|
||||
if (visible && value) {
|
||||
setSelected(value || new Date());
|
||||
|
||||
@@ -83,13 +83,11 @@ const NutUICalendar = React.forwardRef<CalendarUIRef, NutUICalendarProps>(
|
||||
jumpTo: (year: number, month: number) => {
|
||||
calendarRef.current?.jumpTo(year, month);
|
||||
},
|
||||
gotoMonth: (delta: number) => {
|
||||
gotoMonth(delta);
|
||||
},
|
||||
gotoMonth,
|
||||
}));
|
||||
|
||||
const handleDateChange = (newValue: any) => {
|
||||
console.log("aaaaaaaaaaaaaaaaaaaaaa", newValue);
|
||||
if (type === "range") return;
|
||||
setSelectedValue(newValue);
|
||||
onChange?.(newValue as any);
|
||||
};
|
||||
|
||||
3
src/user_pages/billDetail/index.config.ts
Normal file
3
src/user_pages/billDetail/index.config.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: '明细详情',
|
||||
})
|
||||
56
src/user_pages/billDetail/index.scss
Normal file
56
src/user_pages/billDetail/index.scss
Normal file
@@ -0,0 +1,56 @@
|
||||
.bill-detail-page {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding: 5px;
|
||||
.title-text-box {
|
||||
height: 118px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
.title-text {
|
||||
font-family: PingFang SC;
|
||||
font-weight: 400;
|
||||
font-style: Regular;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
.amount-text {
|
||||
font-family: DingTalk JinBuTi;
|
||||
font-weight: 400;
|
||||
font-style: Regular;
|
||||
font-size: 32px;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.detail-wrapper {
|
||||
padding: 12px 20px 16px;
|
||||
border: 0.5px solid #ebebeb;
|
||||
box-shadow: 0px 4px 36px 0px #0000000d;
|
||||
.detail-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-family: PingFang SC;
|
||||
font-weight: 400;
|
||||
font-style: Regular;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
color: #000;
|
||||
margin-bottom: 8px;
|
||||
& > Text {
|
||||
&:first-child {
|
||||
color: #3c3c4399;
|
||||
}
|
||||
}
|
||||
.with-btn-box {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
.btn {
|
||||
color: #007aff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
65
src/user_pages/billDetail/index.tsx
Normal file
65
src/user_pages/billDetail/index.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { View, Text, Input, Button, Image } from "@tarojs/components";
|
||||
|
||||
import { TransactionType, TransactionSubType } from "@/user_pages/wallet/index";
|
||||
import "./index.scss";
|
||||
|
||||
enum FreezeActions {
|
||||
Unfreeze = "unfreeze",
|
||||
Freeze = "freeze",
|
||||
}
|
||||
|
||||
interface BillDetail {
|
||||
id: number;
|
||||
transaction_type: TransactionType;
|
||||
transaction_sub_type: TransactionSubType;
|
||||
freeze_action: FreezeActions;
|
||||
amount: number;
|
||||
description: string;
|
||||
related_id: number;
|
||||
create_time: string;
|
||||
order_no: string;
|
||||
game_title: string;
|
||||
order_amount: number;
|
||||
type_text: string;
|
||||
sub_type_text: string;
|
||||
amount_yuan: string;
|
||||
}
|
||||
|
||||
const BillDetail: React.FC = () => {
|
||||
const [billDetail, setBillDetail] = useState<BillDetail | null>(null);
|
||||
return (
|
||||
<View className="bill-detail-page">
|
||||
<View className="title-text-box">
|
||||
<View className="title-text">现金交易 (元)</View>
|
||||
<View className="amount-text">
|
||||
<Text>+</Text>
|
||||
<Text>65.00</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View className="detail-wrapper">
|
||||
<View className="detail-item">
|
||||
<Text>交易时间</Text>
|
||||
<Text>2025-02-16 12:21:54</Text>
|
||||
</View>
|
||||
<View className="detail-item">
|
||||
<Text>活动标题</Text>
|
||||
<Text>女生轻松双打</Text>
|
||||
</View>
|
||||
<View className="detail-item">
|
||||
<Text>现金余额</Text>
|
||||
<Text>¥3890.00</Text>
|
||||
</View>
|
||||
<View className="detail-item">
|
||||
<Text>交易单号</Text>
|
||||
<View className="with-btn-box">
|
||||
<Text>89172371293791273912</Text>
|
||||
<Text className="btn">复制</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default BillDetail;
|
||||
@@ -1,3 +1,3 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: '下载记录',
|
||||
navigationBarTitleText: '查找交易',
|
||||
})
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
.listSearchContainer {
|
||||
padding: 0 15px;
|
||||
padding-top: 16px;
|
||||
|
||||
.icon16 {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.topSearch {
|
||||
padding: 10px 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);
|
||||
|
||||
.nut-input {
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.searchRight {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
||||
.searchLine {
|
||||
width: 1px;
|
||||
height: 20px;
|
||||
border-radius: 20px;
|
||||
background: rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.searchText {
|
||||
color: #000000;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.searchIcon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.historySearchTitleWrapper {
|
||||
display: flex;
|
||||
padding: 12px 15px;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
align-self: stretch;
|
||||
|
||||
.historySearchTitle,
|
||||
.historySearchClear {
|
||||
color: #000;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.historySearchClear {
|
||||
color: #9a9a9a;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.historySearchList {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
|
||||
.historySearchItem {
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
display: flex;
|
||||
height: 28px;
|
||||
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: 8px 20px;
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,348 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { View } from "@tarojs/components";
|
||||
import { useState } 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";
|
||||
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;
|
||||
}
|
||||
|
||||
// 钱包信息类型
|
||||
interface WalletInfo {
|
||||
balance: number;
|
||||
frozen_balance?: number;
|
||||
total_balance?: number;
|
||||
total_income?: number;
|
||||
total_withdraw?: number;
|
||||
}
|
||||
|
||||
interface History {
|
||||
id: number;
|
||||
keyword: string;
|
||||
}
|
||||
interface TransactionLoadParams {
|
||||
page: number;
|
||||
limit: number;
|
||||
keyword?: string;
|
||||
}
|
||||
|
||||
const QueryTransactions = () => {
|
||||
const [loading_transactions, set_loading_transactions] = useState(false);
|
||||
const [transactions, setTransactions] = useState<Transaction[]>([]);
|
||||
const [searchHistory, setSearchHistory] = useState<History[]>([]);
|
||||
const ref = useRef<any>(null);
|
||||
const [load_transactions_params, set_load_transactions_params] =
|
||||
useState<TransactionLoadParams>({
|
||||
page: 1,
|
||||
limit: 20,
|
||||
keyword: "",
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
getSearchHistory();
|
||||
return () => {
|
||||
handleClear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (ref?.current) {
|
||||
ref.current.focus();
|
||||
}
|
||||
}, [ref.current]);
|
||||
|
||||
// 是否显示清空图标
|
||||
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) => {
|
||||
set_load_transactions_params((prev) => {
|
||||
return { ...prev, keyword: value };
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @description 点击清空输入内容
|
||||
*/
|
||||
const handleClear = () => {
|
||||
setTransactions([]);
|
||||
set_load_transactions_params((prev) => {
|
||||
return { ...prev, keyword: "" };
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @description 点击历史搜索
|
||||
* @param value
|
||||
*/
|
||||
const handleHistoryClick = (item: { id: number; keyword: string }) => {
|
||||
set_load_transactions_params((prev) => {
|
||||
handleSearch(item?.keyword);
|
||||
return { ...prev, keyword: item?.keyword };
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @description 清空历史搜索
|
||||
*/
|
||||
const handleClearHistory = async () => {
|
||||
await httpService.post("/wallet/clear_search_history");
|
||||
setSearchHistory([]);
|
||||
};
|
||||
|
||||
/**
|
||||
* @description 点击搜索
|
||||
*/
|
||||
const handleSearch = async (val?: string) => {
|
||||
if (!val) {
|
||||
return;
|
||||
}
|
||||
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([]);
|
||||
}
|
||||
} 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 [wallet_info, set_wallet_info] = useState<WalletInfo>({
|
||||
balance: 0,
|
||||
});
|
||||
|
||||
// 格式化时间显示
|
||||
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");
|
||||
|
||||
return {
|
||||
date: `2025-${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)}`;
|
||||
};
|
||||
|
||||
const QueryTransactions: React.FC = () => {
|
||||
return (
|
||||
<View>查询交易</View>
|
||||
<>
|
||||
<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>
|
||||
</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 ? (
|
||||
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">
|
||||
<Text className="transaction_amount">
|
||||
{get_amount_display(transaction)}
|
||||
</Text>
|
||||
<Text className="balance_info">
|
||||
余额 ¥{format_amount(wallet_info.balance)}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<View className="empty_state">
|
||||
<Text className="empty_text">暂无交易记录</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default QueryTransactions;
|
||||
export default withAuth(QueryTransactions);
|
||||
|
||||
@@ -4,26 +4,26 @@
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding: 5px;
|
||||
|
||||
|
||||
.wallet_main_card {
|
||||
background: #000;
|
||||
border-radius: 20px;
|
||||
padding: 12px 20px 32px;
|
||||
margin-bottom: 8px;
|
||||
color: #fff;
|
||||
|
||||
|
||||
.card_header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 32px;
|
||||
|
||||
|
||||
.header_title {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
|
||||
.modify_password {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
@@ -31,37 +31,37 @@
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.balance_display {
|
||||
.amount_section {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
|
||||
|
||||
.amount_container {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 8px;
|
||||
|
||||
|
||||
.currency_symbol {
|
||||
font-family: 'DingTalk JinBuTi', sans-serif;
|
||||
font-size: 32px;
|
||||
font-weight: 400;
|
||||
line-height: 0.8;
|
||||
}
|
||||
|
||||
|
||||
.amount_group {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
|
||||
|
||||
.main_amount {
|
||||
font-family: 'DingTalk JinBuTi', sans-serif;
|
||||
font-size: 32px;
|
||||
font-weight: 400;
|
||||
line-height: 0.75;
|
||||
}
|
||||
|
||||
|
||||
.decimal_amount {
|
||||
font-family: 'DingTalk JinBuTi', sans-serif;
|
||||
font-size: 32px;
|
||||
@@ -70,7 +70,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.withdraw_btn {
|
||||
background: #fff;
|
||||
border: none;
|
||||
@@ -86,7 +86,7 @@
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.available_amount {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
@@ -95,13 +95,13 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.function_buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
|
||||
|
||||
.function_item {
|
||||
background: white;
|
||||
border: 0.5px solid #EBEBEB;
|
||||
@@ -114,19 +114,19 @@
|
||||
box-shadow: 0px 4px 36px 0px rgba(0, 0, 0, 0.05);
|
||||
height: 24px;
|
||||
flex: 1;
|
||||
|
||||
|
||||
.function_icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
|
||||
.icon_text {
|
||||
font-size: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.function_text {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
@@ -134,7 +134,7 @@
|
||||
line-height: 1.33;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
|
||||
&:active {
|
||||
background: #f8f8f8;
|
||||
}
|
||||
@@ -169,7 +169,8 @@
|
||||
position: relative;
|
||||
padding-right: 16px;
|
||||
|
||||
&::before, &::after {
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 2px;
|
||||
@@ -195,6 +196,7 @@
|
||||
}
|
||||
|
||||
.transaction_list {
|
||||
|
||||
.loading_state,
|
||||
.empty_state {
|
||||
padding: 40px 20px;
|
||||
@@ -277,21 +279,21 @@
|
||||
.popup_content {
|
||||
padding: 12px;
|
||||
overflow: hidden;
|
||||
|
||||
|
||||
.form_section {
|
||||
.form_item {
|
||||
margin-bottom: 12px;
|
||||
|
||||
|
||||
.form_label {
|
||||
font-size: 12px;
|
||||
color: #333;
|
||||
margin-bottom: 6px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
||||
.input_wrapper {
|
||||
position: relative;
|
||||
|
||||
|
||||
.amount_input {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
@@ -301,17 +303,17 @@
|
||||
padding: 0 10px;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
|
||||
|
||||
&:focus {
|
||||
border-color: #667eea;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
|
||||
&::placeholder {
|
||||
color: #bbb;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.currency_symbol {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
@@ -321,24 +323,24 @@
|
||||
color: #999;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
|
||||
.amount_input.with_symbol {
|
||||
padding-left: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.balance_tip {
|
||||
font-size: 10px;
|
||||
color: #999;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
|
||||
.withdraw_desc {
|
||||
padding: 8px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #e9ecef;
|
||||
|
||||
|
||||
.desc_text {
|
||||
font-size: 10px;
|
||||
color: #666;
|
||||
@@ -349,3 +351,40 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 过滤弹窗
|
||||
.filter_popup {
|
||||
padding: 20px;
|
||||
|
||||
.popup_content {
|
||||
.form_section {
|
||||
.form_item {
|
||||
margin-bottom: 20px;
|
||||
.form_label {
|
||||
display: inline-block;
|
||||
font-family: PingFang SC;
|
||||
font-weight: 600;
|
||||
font-style: Semibold;
|
||||
font-size: 16px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.options_wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 8px;
|
||||
.option_item {
|
||||
background-color: #0000000D;
|
||||
text-align: center;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
&.active {
|
||||
background-color: #000000;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { View, Text, Input, Button, Image } from "@tarojs/components";
|
||||
import Taro, { useDidShow } from "@tarojs/taro";
|
||||
import "./index.scss";
|
||||
@@ -28,6 +28,70 @@ interface WalletInfo {
|
||||
total_withdraw?: number;
|
||||
}
|
||||
|
||||
export enum TransactionType {
|
||||
All = "",
|
||||
Income = "income",
|
||||
Expense = "expense",
|
||||
}
|
||||
|
||||
export enum TransactionSubType {
|
||||
All = "",
|
||||
GameActivity = "game_activity",
|
||||
Withdrawal = "withdrawal",
|
||||
Refund = "refund",
|
||||
Compensation = "compensation",
|
||||
}
|
||||
|
||||
interface TransactionLoadParams {
|
||||
page: number;
|
||||
limit: number;
|
||||
type: TransactionType;
|
||||
transaction_sub_type: TransactionSubType;
|
||||
keyword?: string;
|
||||
date?: string;
|
||||
}
|
||||
interface Option<T> {
|
||||
label: string;
|
||||
value: T;
|
||||
}
|
||||
|
||||
const income_expense_options: Option<TransactionType>[] = [
|
||||
{
|
||||
label: "全部",
|
||||
value: TransactionType.All,
|
||||
},
|
||||
{
|
||||
label: "支出",
|
||||
value: TransactionType.Expense,
|
||||
},
|
||||
{
|
||||
label: "收入",
|
||||
value: TransactionType.Income,
|
||||
},
|
||||
];
|
||||
|
||||
const transaction_type_options: Option<TransactionSubType>[] = [
|
||||
{
|
||||
label: "全部",
|
||||
value: TransactionSubType.All,
|
||||
},
|
||||
{
|
||||
label: "组织活动",
|
||||
value: TransactionSubType.GameActivity,
|
||||
},
|
||||
{
|
||||
label: "提现",
|
||||
value: TransactionSubType.Withdrawal,
|
||||
},
|
||||
{
|
||||
label: "退款",
|
||||
value: TransactionSubType.Refund,
|
||||
},
|
||||
{
|
||||
label: "企业赔付",
|
||||
value: TransactionSubType.Compensation,
|
||||
},
|
||||
];
|
||||
|
||||
const WalletPage: React.FC = () => {
|
||||
// 钱包信息状态
|
||||
@@ -44,6 +108,19 @@ const WalletPage: React.FC = () => {
|
||||
const [transactions, set_transactions] = useState<Transaction[]>([]);
|
||||
const [loading_transactions, set_loading_transactions] = useState(false);
|
||||
|
||||
// 交易记录过滤状态
|
||||
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: "",
|
||||
});
|
||||
|
||||
// 页面显示时加载数据
|
||||
useDidShow(() => {
|
||||
load_wallet_data();
|
||||
@@ -54,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;
|
||||
@@ -82,13 +170,14 @@ const WalletPage: React.FC = () => {
|
||||
|
||||
// 加载交易记录
|
||||
const load_transactions = async () => {
|
||||
setShowFilterPopup(false);
|
||||
set_load_transactions_params({ ...load_transactions_params, page: 1 });
|
||||
try {
|
||||
set_loading_transactions(true);
|
||||
console.log("开始加载交易记录...");
|
||||
|
||||
const response = await httpService.post("/wallet/transactions", {
|
||||
page: 1,
|
||||
limit: 20
|
||||
...load_transactions_params,
|
||||
});
|
||||
|
||||
console.log("交易记录响应:", response);
|
||||
@@ -105,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;
|
||||
@@ -155,17 +249,16 @@ const WalletPage: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
set_submitting(true);
|
||||
|
||||
// 先调用后端接口获取提现参数
|
||||
const response = await httpService.post("/wallet/withdraw", {
|
||||
amount: parseFloat(withdraw_amount),
|
||||
transfer_remark: "用户申请提现"
|
||||
transfer_remark: "用户申请提现",
|
||||
});
|
||||
|
||||
// 根据后端返回的数据结构解析参数
|
||||
const { mch_id, app_id, package_info, open_id } = response.data;
|
||||
const { mch_id, app_id, package_info, open_id } = response.data;
|
||||
|
||||
console.log("/wallet/withdraw:", response.data);
|
||||
|
||||
@@ -192,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}`,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -228,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]})`;
|
||||
}
|
||||
@@ -250,11 +341,15 @@ 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);
|
||||
};
|
||||
|
||||
return (
|
||||
<View className="wallet_page">
|
||||
{/* 钱包主卡片 */}
|
||||
@@ -271,34 +366,65 @@ 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>
|
||||
|
||||
{/* 功能按钮区域 */}
|
||||
<View className="function_buttons">
|
||||
<View className="function_item">
|
||||
<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>
|
||||
@@ -323,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)}
|
||||
@@ -392,6 +526,71 @@ const WalletPage: React.FC = () => {
|
||||
</View>
|
||||
</View>
|
||||
</CommonPopup>
|
||||
|
||||
{/* 筛选账单弹窗 */}
|
||||
<CommonPopup
|
||||
visible={showFilterPopup}
|
||||
onClose={() => setShowFilterPopup(false)}
|
||||
onConfirm={load_transactions}
|
||||
title="选择筛选项"
|
||||
className="filter_popup"
|
||||
>
|
||||
<View className="popup_content">
|
||||
<View className="form_section">
|
||||
<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>
|
||||
)
|
||||
)}
|
||||
</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>
|
||||
)
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</CommonPopup>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user