Browse Source

对接部分页面功能接口好字段

v2.0
DU 3 months ago
parent
commit
e05547602e
  1. 2
      src/api/recharge.ts
  2. 6
      src/pagesOrder/accountBalance/components/RechargeRecordList.scss
  3. 135
      src/pagesOrder/accountBalance/components/RechargeRecordList.tsx
  4. 22
      src/pagesOrder/accountBalance/index.tsx
  5. 6
      src/pagesOrder/rechargeDetail/index.scss
  6. 143
      src/pagesOrder/rechargeDetail/index.tsx
  7. 3
      src/types/recharge.ts
  8. 111
      src/utils/rechargeRecords.ts

2
src/api/recharge.ts

@ -127,6 +127,8 @@ export const getRechargeRecords = async (params: RechargeRecordQueryParams) => { @@ -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<string, unknown>, 'totalCount', 'totalcount')),
pageIndex: toNumber(pickField(src as Record<string, unknown>, 'pageIndex', 'pageindex'), 1),

6
src/pagesOrder/accountBalance/components/RechargeRecordList.scss

@ -2,6 +2,12 @@ @@ -2,6 +2,12 @@
padding: 30px;
// 空数据展示
.empty-wrap {
.empty-month-card {
margin-bottom: 0;
}
}
.empty-data {
display: flex;
justify-content: center;

135
src/pagesOrder/accountBalance/components/RechargeRecordList.tsx

@ -1,76 +1,57 @@ @@ -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<RechargeRecordListProps> = ({ recordList }) => {
const [selectedMonth, setSelectedMonth] = useState('2025-03')
const RechargeRecordList: FC<RechargeRecordListProps> = () => {
const [selectedMonth, setSelectedMonth] = useState(getCurrentYearMonth())
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 [dataList, setDataList] = useState<RechargeRecordViewItem[]>([])
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<string, RechargeRecordItem[]> = {}
useEffect(() => {
loadRecords(selectedMonth)
// 仅挂载时拉当前月
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
const groupByMonth = (records: RechargeRecordViewItem[]) => {
const groups: Record<string, RechargeRecordViewItem[]> = {}
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<RechargeRecordListProps> = ({ recordList }) => { @@ -80,32 +61,27 @@ const RechargeRecordList: FC<RechargeRecordListProps> = ({ 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<RechargeRecordListProps> = ({ recordList }) => { @@ -113,18 +89,27 @@ const RechargeRecordList: FC<RechargeRecordListProps> = ({ recordList }) => {
return (
<View className="recharge-record-list">
{dataList.length === 0 ? (
<View className="empty-data">
<Image className="empty-image" src={getBigImage('NO_DATA')} mode="aspectFit" />
<View className="empty-wrap">
<View className="month-card empty-month-card">
<View className="month-header">
<View className="month-left" onClick={handleSelectMonth}>
<Text className="month-text">{selectedMonth}</Text>
<ArrowDown className="month-arrow" size="20px" color="#FFFEFE" />
</View>
</View>
</View>
<View className="empty-data">
<Image className="empty-image" src={getBigImage('NO_DATA')} mode="aspectFit" />
</View>
</View>
) : (
<>
{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>
@ -137,26 +122,21 @@ const RechargeRecordList: FC<RechargeRecordListProps> = ({ recordList }) => { @@ -137,26 +122,21 @@ const RechargeRecordList: FC<RechargeRecordListProps> = ({ recordList }) => {
</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">
@ -166,7 +146,6 @@ const RechargeRecordList: FC<RechargeRecordListProps> = ({ recordList }) => { @@ -166,7 +146,6 @@ const RechargeRecordList: FC<RechargeRecordListProps> = ({ recordList }) => {
</View>
</View>
{/* item 之间的分割线 */}
{index < monthRecords.length - 1 && (
<View className="item-divider" />
)}
@ -176,15 +155,13 @@ const RechargeRecordList: FC<RechargeRecordListProps> = ({ recordList }) => { @@ -176,15 +155,13 @@ const RechargeRecordList: FC<RechargeRecordListProps> = ({ recordList }) => {
</View>
)
})}
{/* 到底了提示 */}
<View className="list-end">
<Text className="end-text">到底了~</Text>
</View>
</>
)}
{/* 年月选择器 */}
<Popup
open={datePickerOpen}
placement="bottom"

22
src/pagesOrder/accountBalance/index.tsx

@ -73,26 +73,6 @@ const AccountBalance = () => { @@ -73,26 +73,6 @@ const AccountBalance = () => {
}
])
// 充值记录模拟数据
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 = () => { @@ -139,7 +119,7 @@ const AccountBalance = () => {
)}
{activeTab === 2 && (
<RechargeRecordList recordList={rechargeRecordList} />
<RechargeRecordList />
)}
</ScrollView>
</View>

6
src/pagesOrder/rechargeDetail/index.scss

@ -4,6 +4,12 @@ @@ -4,6 +4,12 @@
min-height: 100vh;
// 空数据展示
.empty-wrap {
.empty-month-card {
margin-bottom: 0;
}
}
.empty-data {
display: flex;
justify-content: center;

143
src/pagesOrder/rechargeDetail/index.tsx

@ -6,90 +6,46 @@ import { useState } from 'react' @@ -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<RechargeRecordItem[]>([
{
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<RechargeRecordViewItem[]>([])
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<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[]> = {}
const groupByMonth = (records: RechargeRecordViewItem[]) => {
const groups: Record<string, RechargeRecordViewItem[]> = {}
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 = () => { @@ -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 (
<View className="recharge-detail-page">
{/* 无数据时仍可切换月份 */}
{dataList.length === 0 ? (
<View className="empty-data">
<Image className="empty-image" src={getBigImage('NO_DATA')} mode="aspectFit" />
<View className="empty-wrap">
<View className="month-card empty-month-card">
<View className="month-header">
<View className="month-left" onClick={handleSelectMonth}>
<Text className="month-text">{selectedMonth}</Text>
<ArrowDown className="month-arrow" size="20px" color="#000000" />
</View>
</View>
</View>
<View className="empty-data">
<Image className="empty-image" src={getBigImage('NO_DATA')} mode="aspectFit" />
</View>
</View>
) : (
<>
{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>
@ -156,26 +117,21 @@ const RechargeDetail = () => { @@ -156,26 +117,21 @@ const RechargeDetail = () => {
</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">
@ -185,7 +141,6 @@ const RechargeDetail = () => { @@ -185,7 +141,6 @@ const RechargeDetail = () => {
</View>
</View>
{/* item 之间的分割线 */}
{index < monthRecords.length - 1 && (
<View className="item-divider" />
)}
@ -195,15 +150,13 @@ const RechargeDetail = () => { @@ -195,15 +150,13 @@ const RechargeDetail = () => {
</View>
)
})}
{/* 到底了提示 */}
<View className="list-end">
<Text className="end-text">到底了~</Text>
</View>
</>
)}
{/* 年月选择器 */}
<Popup
open={datePickerOpen}
placement="bottom"

3
src/types/recharge.ts

@ -73,6 +73,9 @@ export interface RechargeRecordItem { @@ -73,6 +73,9 @@ export interface RechargeRecordItem {
instName: string
logTime: string
updateTime: string
/** 状态(文档未给枚举,前端做兜底文案) */
status: number
outTradeNo: string
}
export interface RechargeRecordPagedResult {

111
src/utils/rechargeRecords.ts

@ -0,0 +1,111 @@ @@ -0,0 +1,111 @@
/**
* 充值记录:月份区间、状态文案、列表展示映射
*/
import { getRechargeRecords } from '../api/recharge'
import { RechargeRecordItem } from '../types/recharge'
import { userStore } from '../store'
/** 列表项(页面展示结构) */
export interface RechargeRecordViewItem {
id: string
storeName: string
rechargeTime: string
rechargeType: string
amount: number
status: string
}
/** 当前年月 YYYY-MM */
export const getCurrentYearMonth = (): string => {
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<number, string> = {
[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<RechargeRecordViewItem[]> => {
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)
}
Loading…
Cancel
Save