diff --git a/src/api/recharge.ts b/src/api/recharge.ts index 533a6db..1cd1d6d 100644 --- a/src/api/recharge.ts +++ b/src/api/recharge.ts @@ -127,6 +127,8 @@ export const getRechargeRecords = async (params: RechargeRecordQueryParams) => { instName: String(pickField(item, 'instName', 'instname') ?? ''), logTime: String(pickField(item, 'logTime', 'logtime') ?? ''), updateTime: String(pickField(item, 'updateTime', 'updatetime') ?? ''), + status: toNumber(pickField(item, 'status')), + outTradeNo: String(pickField(item, 'outTradeNo', 'outtradeno') ?? ''), })), totalCount: toNumber(pickField(src as Record, 'totalCount', 'totalcount')), pageIndex: toNumber(pickField(src as Record, 'pageIndex', 'pageindex'), 1), diff --git a/src/pagesOrder/accountBalance/components/RechargeRecordList.scss b/src/pagesOrder/accountBalance/components/RechargeRecordList.scss index ecbcb03..5290bce 100644 --- a/src/pagesOrder/accountBalance/components/RechargeRecordList.scss +++ b/src/pagesOrder/accountBalance/components/RechargeRecordList.scss @@ -2,6 +2,12 @@ padding: 30px; // 空数据展示 + .empty-wrap { + .empty-month-card { + margin-bottom: 0; + } + } + .empty-data { display: flex; justify-content: center; diff --git a/src/pagesOrder/accountBalance/components/RechargeRecordList.tsx b/src/pagesOrder/accountBalance/components/RechargeRecordList.tsx index f990629..9c2d06b 100644 --- a/src/pagesOrder/accountBalance/components/RechargeRecordList.tsx +++ b/src/pagesOrder/accountBalance/components/RechargeRecordList.tsx @@ -1,76 +1,57 @@ /** - * 充值记录列表组件 + * 充值记录列表组件(账户余额页 Tab) */ import { View, Text, Image } from '@tarojs/components' -import { FC, useState } from 'react' +import { FC, useEffect, useState } from 'react' import { ArrowDown } from '@taroify/icons' import { Popup, DatetimePicker } from '@taroify/core' import Taro from '@tarojs/taro' +import { + fetchRechargeRecordsByMonth, + getCurrentYearMonth, + RechargeRecordViewItem, +} from '../../../utils/rechargeRecords' import './RechargeRecordList.scss' import { getBigImage } from '@/utils/imageHelper' -interface RechargeRecordItem { - id: string - storeName: string - rechargeTime: string - rechargeType: string - amount: number - status: string -} - interface RechargeRecordListProps { - recordList: RechargeRecordItem[] + /** 兼容旧 props,实际数据改由接口拉取 */ + recordList?: RechargeRecordViewItem[] } -const RechargeRecordList: FC = ({ recordList }) => { - const [selectedMonth, setSelectedMonth] = useState('2025-03') +const RechargeRecordList: FC = () => { + const [selectedMonth, setSelectedMonth] = useState(getCurrentYearMonth()) const [datePickerOpen, setDatePickerOpen] = useState(false) const [pickerValue, setPickerValue] = useState(new Date()) - const [dataList, setDataList] = useState(recordList) - - // 模拟接口请求充值记录数据 - const fetchRechargeRecords = async (yearMonth: string) => { - Taro.showLoading({ - title: '加载中...', - mask: true - }) - - // 模拟接口请求 - return new Promise((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 [dataList, setDataList] = useState([]) + + const loadRecords = async (yearMonth: string) => { + Taro.showLoading({ title: '加载中...', mask: true }) + try { + const list = await fetchRechargeRecordsByMonth(yearMonth) + setDataList(list) + } catch (error: any) { + setDataList([]) + if (error?.message === 'NO_CUSTOMER_SN') { + Taro.showToast({ title: '请先登录', icon: 'none', duration: 2000 }) + } + } finally { + Taro.hideLoading() + } } - // 按月份分组记录 - const groupByMonth = (records: RechargeRecordItem[]) => { - const groups: Record = {} + useEffect(() => { + loadRecords(selectedMonth) + // 仅挂载时拉当前月 + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + const groupByMonth = (records: RechargeRecordViewItem[]) => { + const groups: Record = {} records.forEach(record => { - const month = record.rechargeTime.substring(0, 7) // 提取 YYYY-MM + const month = (record.rechargeTime || '').substring(0, 7) + if (!month || month.length < 7) return if (!groups[month]) { groups[month] = [] } @@ -80,32 +61,27 @@ const RechargeRecordList: FC = ({ recordList }) => { } const groupedRecords = groupByMonth(dataList) - - // 计算当月总充值金额 - const calculateMonthTotal = (records: RechargeRecordItem[]) => { - return records.reduce((sum, record) => sum + record.amount, 0) + + const calculateMonthTotal = (records: RechargeRecordViewItem[]) => { + return records.reduce((sum, record) => sum + (record.amount || 0), 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) + + await loadRecords(formattedMonth) } - // 取消选择 const handleDateCancel = () => { setDatePickerOpen(false) } @@ -113,18 +89,27 @@ const RechargeRecordList: FC = ({ recordList }) => { return ( {dataList.length === 0 ? ( - - + + + + + {selectedMonth} + + + + + + + ) : ( <> {Object.keys(groupedRecords).map(month => { const monthRecords = groupedRecords[month] const monthTotal = calculateMonthTotal(monthRecords) - + return ( - {/* 月份标题和充值统计 */} {month} @@ -137,26 +122,21 @@ const RechargeRecordList: FC = ({ recordList }) => { - {/* 分割线 */} - {/* 记录列表 */} {monthRecords.map((item, index) => ( - {/* 第一行:店铺名称 + 状态 */} {item.storeName} {item.status} - {/* 第二行:充值类型 */} {item.rechargeType} - {/* 第三行:充值时间 + 实付金额 */} 充值时间:{item.rechargeTime} @@ -166,7 +146,6 @@ const RechargeRecordList: FC = ({ recordList }) => { - {/* item 之间的分割线 */} {index < monthRecords.length - 1 && ( )} @@ -176,15 +155,13 @@ const RechargeRecordList: FC = ({ recordList }) => { ) })} - - {/* 到底了提示 */} + 到底了~ )} - {/* 年月选择器 */} { } ]) - // 充值记录模拟数据 - const [rechargeRecordList] = useState([ - { - id: '1', - storeName: '北京XXXXXXXXXXXXX店', - rechargeTime: '2025-03-09 00:00:00', - rechargeType: '账户充值', - amount: 100.00, - status: '充值完成' - }, - { - id: '2', - storeName: '北京XXX店', - rechargeTime: '2025-03-09 00:00:00', - rechargeType: '账户充值', - amount: 100.00, - status: '充值完成' - } - ]) - useLoad(() => { console.log('账户余额页面加载') }) @@ -139,7 +119,7 @@ const AccountBalance = () => { )} {activeTab === 2 && ( - + )} diff --git a/src/pagesOrder/rechargeDetail/index.scss b/src/pagesOrder/rechargeDetail/index.scss index 094ebb2..f8a90ca 100644 --- a/src/pagesOrder/rechargeDetail/index.scss +++ b/src/pagesOrder/rechargeDetail/index.scss @@ -4,6 +4,12 @@ min-height: 100vh; // 空数据展示 + .empty-wrap { + .empty-month-card { + margin-bottom: 0; + } + } + .empty-data { display: flex; justify-content: center; diff --git a/src/pagesOrder/rechargeDetail/index.tsx b/src/pagesOrder/rechargeDetail/index.tsx index 6b1ebd4..78ee49a 100644 --- a/src/pagesOrder/rechargeDetail/index.tsx +++ b/src/pagesOrder/rechargeDetail/index.tsx @@ -6,90 +6,46 @@ import { useState } from 'react' import { ArrowDown } from '@taroify/icons' import { Popup, DatetimePicker } from '@taroify/core' import Taro, { useLoad } from '@tarojs/taro' +import { + fetchRechargeRecordsByMonth, + getCurrentYearMonth, + RechargeRecordViewItem, +} from '../../utils/rechargeRecords' import './index.scss' import { getBigImage } from '@/utils/imageHelper' -interface RechargeRecordItem { - id: string - storeName: string - rechargeTime: string - rechargeType: string - amount: number - status: string -} - const RechargeDetail = () => { - const [selectedMonth, setSelectedMonth] = useState('2025-03') + const [selectedMonth, setSelectedMonth] = useState(getCurrentYearMonth()) const [datePickerOpen, setDatePickerOpen] = useState(false) const [pickerValue, setPickerValue] = useState(new Date()) - - // 模拟充值记录数据 - const [dataList, setDataList] = useState([ - { - id: '2025-03-1', - storeName: '北京球场风云店', - rechargeTime: '2025-03-09 00:00:00', - rechargeType: '账户充值', - amount: 100.00, - status: '充值完成' - }, - { - id: '2025-03-2', - storeName: '北京球场风云店', - rechargeTime: '2025-03-06 00:00:00', - rechargeType: '账户充值', - amount: 100.00, - status: '充值完成' + const [dataList, setDataList] = useState([]) + + const loadRecords = async (yearMonth: string) => { + Taro.showLoading({ title: '加载中...', mask: true }) + try { + const list = await fetchRechargeRecordsByMonth(yearMonth) + setDataList(list) + } catch (error: any) { + setDataList([]) + if (error?.message === 'NO_CUSTOMER_SN') { + Taro.showToast({ title: '请先登录', icon: 'none', duration: 2000 }) + } + // 其它错误由 request 拦截器提示 + } finally { + Taro.hideLoading() } - ]) + } useLoad(() => { - console.log('充值明细页面加载') + loadRecords(selectedMonth) }) - // 模拟接口请求充值记录数据 - const fetchRechargeRecords = async (yearMonth: string) => { - Taro.showLoading({ - title: '加载中...', - mask: true - }) - - // 模拟接口请求 - return new Promise((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 = {} + const groupByMonth = (records: RechargeRecordViewItem[]) => { + const groups: Record = {} records.forEach(record => { - const month = record.rechargeTime.substring(0, 7) // 提取 YYYY-MM + const month = (record.rechargeTime || '').substring(0, 7) + if (!month || month.length < 7) return if (!groups[month]) { groups[month] = [] } @@ -99,51 +55,56 @@ const RechargeDetail = () => { } const groupedRecords = groupByMonth(dataList) - - // 计算当月总充值金额 - const calculateMonthTotal = (records: RechargeRecordItem[]) => { - return records.reduce((sum, record) => sum + record.amount, 0) + + const calculateMonthTotal = (records: RechargeRecordViewItem[]) => { + return records.reduce((sum, record) => sum + (record.amount || 0), 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) + + await loadRecords(formattedMonth) } - // 取消选择 const handleDateCancel = () => { setDatePickerOpen(false) } return ( + {/* 无数据时仍可切换月份 */} {dataList.length === 0 ? ( - - + + + + + {selectedMonth} + + + + + + + ) : ( <> {Object.keys(groupedRecords).map(month => { const monthRecords = groupedRecords[month] const monthTotal = calculateMonthTotal(monthRecords) - + return ( - {/* 月份标题和充值统计 */} {month} @@ -156,26 +117,21 @@ const RechargeDetail = () => { - {/* 分割线 */} - {/* 记录列表 */} {monthRecords.map((item, index) => ( - {/* 第一行:店铺名称 + 状态 */} {item.storeName} {item.status} - {/* 第二行:充值类型 */} {item.rechargeType} - {/* 第三行:充值时间 + 实付金额 */} 充值时间:{item.rechargeTime} @@ -185,7 +141,6 @@ const RechargeDetail = () => { - {/* item 之间的分割线 */} {index < monthRecords.length - 1 && ( )} @@ -195,15 +150,13 @@ const RechargeDetail = () => { ) })} - - {/* 到底了提示 */} + 到底了~ )} - {/* 年月选择器 */} { + const now = new Date() + const year = now.getFullYear() + const month = String(now.getMonth() + 1).padStart(2, '0') + return `${year}-${month}` +} + +/** 某月起止时间(供 records 接口过滤) */ +export const getMonthDateRange = (yearMonth: string): { startDate: string; endDate: string } => { + const [yStr, mStr] = yearMonth.split('-') + const year = Number(yStr) + const month = Number(mStr) + const lastDay = new Date(year, month, 0).getDate() + const day = String(lastDay).padStart(2, '0') + return { + startDate: `${yearMonth}-01 00:00:00`, + endDate: `${yearMonth}-${day} 23:59:59`, + } +} + +/** + * 支付状态(后端枚举,适用于 recharge/records.status 等) + * 来源:后端「支付状态定义」 + */ +export enum RechargePaymentStatus { + Invalid = 0, + Pending = 1, + Initialized = 2, + Paying = 3, + Success = 4, + Failed = 5, + Cancelled = 6, + Refunding = 7, + Refunded = 8, + RefundFailed = 9, + Closed = 10, +} + +export const RECHARGE_PAYMENT_STATUS_LABEL: Record = { + [RechargePaymentStatus.Invalid]: '无效', + [RechargePaymentStatus.Pending]: '待支付', + [RechargePaymentStatus.Initialized]: '已初始化', + [RechargePaymentStatus.Paying]: '支付中', + [RechargePaymentStatus.Success]: '支付成功', + [RechargePaymentStatus.Failed]: '支付失败', + [RechargePaymentStatus.Cancelled]: '已取消', + [RechargePaymentStatus.Refunding]: '退款中', + [RechargePaymentStatus.Refunded]: '已退款', + [RechargePaymentStatus.RefundFailed]: '退款失败', + [RechargePaymentStatus.Closed]: '已关闭', +} + +/** + * 充值状态文案(后端支付状态定义) + */ +export const formatRechargeStatus = (status: number): string => { + if (RECHARGE_PAYMENT_STATUS_LABEL[status] !== undefined) { + return RECHARGE_PAYMENT_STATUS_LABEL[status] + } + return '未知状态' +} + +export const mapRechargeRecordToView = (item: RechargeRecordItem): RechargeRecordViewItem => ({ + id: String(item.id || item.outTradeNo || item.logTime), + storeName: item.bpName || '--', + rechargeTime: item.logTime || '--', + rechargeType: item.rcgTypeName || '账户充值', + amount: item.amount, + status: formatRechargeStatus(item.status), +}) + +/** + * 拉取指定月份充值记录(需已登录且有客户 sn) + */ +export const fetchRechargeRecordsByMonth = async ( + yearMonth: string +): Promise => { + const customerSn = userStore.userInfo?.sn + if (!customerSn) { + throw new Error('NO_CUSTOMER_SN') + } + + const { startDate, endDate } = getMonthDateRange(yearMonth) + const res = await getRechargeRecords({ + customerSn, + startDate, + endDate, + pageIndex: 1, + pageSize: 100, + }) + + return (res.data?.data || []).map(mapRechargeRecordToView) +}