|
|
|
|
@ -2,7 +2,10 @@
@@ -2,7 +2,10 @@
|
|
|
|
|
* 充值记录列表组件 |
|
|
|
|
*/ |
|
|
|
|
import { View, Text, Image } from '@tarojs/components' |
|
|
|
|
import { FC } from 'react' |
|
|
|
|
import { FC, useState } from 'react' |
|
|
|
|
import { ArrowDown } from '@taroify/icons' |
|
|
|
|
import { Popup, DatetimePicker } from '@taroify/core' |
|
|
|
|
import Taro from '@tarojs/taro' |
|
|
|
|
import './RechargeRecordList.scss' |
|
|
|
|
|
|
|
|
|
const noDataImg = require('../../../assets/big/noData.png') |
|
|
|
|
@ -21,27 +24,158 @@ interface RechargeRecordListProps {
@@ -21,27 +24,158 @@ interface RechargeRecordListProps {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const RechargeRecordList: FC<RechargeRecordListProps> = ({ recordList }) => { |
|
|
|
|
const [selectedMonth, setSelectedMonth] = useState('2025-03') |
|
|
|
|
const [datePickerOpen, setDatePickerOpen] = useState(false) |
|
|
|
|
const [pickerValue, setPickerValue] = useState(new Date()) |
|
|
|
|
const [dataList, setDataList] = useState<RechargeRecordItem[]>(recordList) |
|
|
|
|
|
|
|
|
|
// 模拟接口请求充值记录数据
|
|
|
|
|
const fetchRechargeRecords = async (yearMonth: string) => { |
|
|
|
|
Taro.showLoading({ |
|
|
|
|
title: '加载中...', |
|
|
|
|
mask: true |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
// 模拟接口请求
|
|
|
|
|
return new Promise<RechargeRecordItem[]>((resolve) => { |
|
|
|
|
setTimeout(() => { |
|
|
|
|
// 模拟返回数据
|
|
|
|
|
const mockData: RechargeRecordItem[] = [ |
|
|
|
|
{ |
|
|
|
|
id: `${yearMonth}-1`, |
|
|
|
|
storeName: '来力.山岩', |
|
|
|
|
rechargeTime: `${yearMonth}-15 14:30:00`, |
|
|
|
|
rechargeType: '账户充值', |
|
|
|
|
amount: 100, |
|
|
|
|
status: '充值完成' |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
id: `${yearMonth}-2`, |
|
|
|
|
storeName: '来力.山岩', |
|
|
|
|
rechargeTime: `${yearMonth}-10 10:20:00`, |
|
|
|
|
rechargeType: '账户充值', |
|
|
|
|
amount: 200, |
|
|
|
|
status: '充值完成' |
|
|
|
|
} |
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
setDataList(mockData) |
|
|
|
|
Taro.hideLoading() |
|
|
|
|
resolve(mockData) |
|
|
|
|
}, 1000) // 模拟 1 秒的网络延迟
|
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 按月份分组记录
|
|
|
|
|
const groupByMonth = (records: RechargeRecordItem[]) => { |
|
|
|
|
const groups: Record<string, RechargeRecordItem[]> = {} |
|
|
|
|
records.forEach(record => { |
|
|
|
|
const month = record.rechargeTime.substring(0, 7) // 提取 YYYY-MM
|
|
|
|
|
if (!groups[month]) { |
|
|
|
|
groups[month] = [] |
|
|
|
|
} |
|
|
|
|
groups[month].push(record) |
|
|
|
|
}) |
|
|
|
|
return groups |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const groupedRecords = groupByMonth(dataList) |
|
|
|
|
|
|
|
|
|
// 计算当月总充值金额
|
|
|
|
|
const calculateMonthTotal = (records: RechargeRecordItem[]) => { |
|
|
|
|
return records.reduce((sum, record) => sum + record.amount, 0) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 打开月份选择器
|
|
|
|
|
const handleSelectMonth = () => { |
|
|
|
|
setDatePickerOpen(true) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 确认选择月份
|
|
|
|
|
const handleDateConfirm = async (value: Date) => { |
|
|
|
|
const year = value.getFullYear() |
|
|
|
|
const month = String(value.getMonth() + 1).padStart(2, '0') |
|
|
|
|
const formattedMonth = `${year}-${month}` |
|
|
|
|
|
|
|
|
|
setSelectedMonth(formattedMonth) |
|
|
|
|
setPickerValue(value) |
|
|
|
|
setDatePickerOpen(false) |
|
|
|
|
|
|
|
|
|
// 调用接口请求该月份的数据
|
|
|
|
|
await fetchRechargeRecords(formattedMonth) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 取消选择
|
|
|
|
|
const handleDateCancel = () => { |
|
|
|
|
setDatePickerOpen(false) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<View className="recharge-record-list"> |
|
|
|
|
{recordList.length === 0 ? ( |
|
|
|
|
{dataList.length === 0 ? ( |
|
|
|
|
<View className="empty-data"> |
|
|
|
|
<Image className="empty-image" src={noDataImg} mode="aspectFit" /> |
|
|
|
|
</View> |
|
|
|
|
) : ( |
|
|
|
|
<> |
|
|
|
|
{recordList.map(item => ( |
|
|
|
|
<View key={item.id} className="record-card"> |
|
|
|
|
<View className="record-header"> |
|
|
|
|
<Text className="store-name">{item.storeName}</Text> |
|
|
|
|
<Text className="amount">+¥{item.amount.toFixed(2)}</Text> |
|
|
|
|
</View> |
|
|
|
|
<View className="record-info"> |
|
|
|
|
<Text className="info-text">充值方式:{item.rechargeType}</Text> |
|
|
|
|
<Text className="info-text">充值时间:{item.rechargeTime}</Text> |
|
|
|
|
<Text className="info-text">状态:{item.status}</Text> |
|
|
|
|
{Object.keys(groupedRecords).map(month => { |
|
|
|
|
const monthRecords = groupedRecords[month] |
|
|
|
|
const monthTotal = calculateMonthTotal(monthRecords) |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<View key={month} className="month-card"> |
|
|
|
|
{/* 月份标题和充值统计 */} |
|
|
|
|
<View className="month-header"> |
|
|
|
|
<View className="month-left" onClick={handleSelectMonth}> |
|
|
|
|
<Text className="month-text">{month}</Text> |
|
|
|
|
<ArrowDown className="month-arrow" size="20px" color="#FFFEFE" /> |
|
|
|
|
</View> |
|
|
|
|
<View className="month-right"> |
|
|
|
|
<Text className="amount-label">充值</Text> |
|
|
|
|
<Text className="amount-symbol">¥</Text> |
|
|
|
|
<Text className="amount-value">{monthTotal.toFixed(2)}</Text> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
|
|
|
|
|
{/* 分割线 */} |
|
|
|
|
<View className="divider" /> |
|
|
|
|
|
|
|
|
|
{/* 记录列表 */} |
|
|
|
|
<View className="record-list"> |
|
|
|
|
{monthRecords.map((item, index) => ( |
|
|
|
|
<View key={item.id}> |
|
|
|
|
<View className="record-item"> |
|
|
|
|
{/* 第一行:店铺名称 + 状态 */} |
|
|
|
|
<View className="item-row"> |
|
|
|
|
<Text className="store-name">{item.storeName}</Text> |
|
|
|
|
<Text className="status">{item.status}</Text> |
|
|
|
|
</View> |
|
|
|
|
|
|
|
|
|
{/* 第二行:充值类型 */} |
|
|
|
|
<View className="item-row"> |
|
|
|
|
<Text className="recharge-type">{item.rechargeType}</Text> |
|
|
|
|
</View> |
|
|
|
|
|
|
|
|
|
{/* 第三行:充值时间 + 实付金额 */} |
|
|
|
|
<View className="item-row"> |
|
|
|
|
<Text className="recharge-time">充值时间:{item.rechargeTime}</Text> |
|
|
|
|
<View className="actual-pay"> |
|
|
|
|
<Text className="pay-label">实付 ¥</Text> |
|
|
|
|
<Text className="pay-amount">{item.amount.toFixed(2)}</Text> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
|
|
|
|
|
{/* item 之间的分割线 */} |
|
|
|
|
{index < monthRecords.length - 1 && ( |
|
|
|
|
<View className="item-divider" /> |
|
|
|
|
)} |
|
|
|
|
</View> |
|
|
|
|
))} |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
))} |
|
|
|
|
) |
|
|
|
|
})} |
|
|
|
|
|
|
|
|
|
{/* 到底了提示 */} |
|
|
|
|
<View className="list-end"> |
|
|
|
|
@ -49,6 +183,21 @@ const RechargeRecordList: FC<RechargeRecordListProps> = ({ recordList }) => {
@@ -49,6 +183,21 @@ const RechargeRecordList: FC<RechargeRecordListProps> = ({ recordList }) => {
|
|
|
|
|
</View> |
|
|
|
|
</> |
|
|
|
|
)} |
|
|
|
|
|
|
|
|
|
{/* 年月选择器 */} |
|
|
|
|
<Popup |
|
|
|
|
open={datePickerOpen} |
|
|
|
|
placement="bottom" |
|
|
|
|
onClose={() => setDatePickerOpen(false)} |
|
|
|
|
> |
|
|
|
|
<DatetimePicker |
|
|
|
|
type="year-month" |
|
|
|
|
value={pickerValue} |
|
|
|
|
onChange={setPickerValue} |
|
|
|
|
onCancel={handleDateCancel} |
|
|
|
|
onConfirm={handleDateConfirm} |
|
|
|
|
/> |
|
|
|
|
</Popup> |
|
|
|
|
</View> |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
|