react + zarm 实现账单列表展示页
Posted 凯小默:树上的男爵
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了react + zarm 实现账单列表展示页相关的知识,希望对你有一定的参考价值。
需要实现的效果
实现过程
1.安装 dayjs
npm i dayjs -S
https://dayjs.fenxianglu.cn/category/display.html#%E6%A0%BC%E5%BC%8F%E5%8C%96
2.配置接口
找到账单列表接口
我们在 src\\container\\Home\\api\\index.js
里添加下面代码
import fetchData from "@/utils/axios.js";
// 获取账单列表
export function queryBillList(data)
return fetchData('/api/bill/list', 'get', data);
接口返回的数据结构如下:
http://localhost:3000/api/bill/list?r=663.1504597032896&curPage=3&pageSize=5&typeId=all&billDate=2022-02
3.准备账单类型图标
我们去 iconfont 里找一些对应的图标,然后添加到我们项目的字体图标,然后更新链接
4.配置下拉刷新以及类型的字典
我们在 src\\utils\\index.js
里添加下面配置代码
// 刷新状态
export const REFRESH_STATE =
normal: 0, // 普通
pull: 1, // 下拉刷新(未满足刷新条件)
drop: 2, // 释放立即刷新(满足刷新条件)
loading: 3, // 加载中
success: 4, // 加载成功
failure: 5, // 加载失败
;
// 加载状态
export const LOAD_STATE =
normal: 0, // 普通
abort: 1, // 中止
loading: 2, // 加载中
success: 3, // 加载成功
failure: 4, // 加载失败
complete: 5, // 加载完成(无新数据)
;
// 类型
export const typeMap =
1:
icon: 'canyin'
,
2:
icon: 'fushi'
,
3:
icon: 'jiaotong'
,
4:
icon: 'riyong'
,
5:
icon: 'gouwu'
,
6:
icon: 'xuexi'
,
7:
icon: 'yiliao'
,
8:
icon: 'lvxing'
,
9:
icon: 'renqing'
,
10:
icon: 'qita'
,
11:
icon: 'gongzi'
,
12:
icon: 'jiangjin'
,
13:
icon: 'zhuanzhang'
,
14:
icon: 'licai'
,
15:
icon: 'tuikuang'
,
16:
icon: 'qita'
5.编写账单页
这里我们用到了 Pull 组件,用法可以查看 https://zarm.design/#/components/pull
我们在 src\\container\\Home\\index.jsx
添加下面代码:(这里我写死了 billDate: “2022-02”,为了测试用的,这个条件有数据,后面会删掉)
import React, useState, useEffect from 'react'
import Icon, Pull from 'zarm'
import dayjs from 'dayjs'
import BillItem from '@/components/BillItem'
import queryBillList from './api/index.js'
import REFRESH_STATE, LOAD_STATE from '@/utils/index.js' // Pull 组件需要的一些常量
import s from './style.module.less'
const Home = () =>
const [currentTime, setCurrentTime] = useState(dayjs().format('YYYY-MM')); // 当前筛选时间
const [totalExpense, setTotalExpense] = useState(0); // 总支出
const [totalIncome, setTotalIncome] = useState(0); // 总收入
const [page, setPage] = useState(1); // 分页
const [dataList, setDataList] = useState([]); // 账单列表
const [totalPage, setTotalPage] = useState(0); // 分页总数
const [refreshing, setRefreshing] = useState(REFRESH_STATE.normal); // 下拉刷新状态
const [loading, setLoading] = useState(LOAD_STATE.normal); // 上拉加载状态
useEffect(() =>
getBillList() // 初始化
, [page])
// 获取账单方法
const getBillList = async () =>
const data = await queryBillList(
curPage: page,
pageSize: 5,
typeId: "all",
billDate: "2022-02" || currentTime
);
// 下拉刷新,重制数据
if (page == 1)
setDataList(data.dataList);
else
setDataList(dataList.concat(data.dataList));
setTotalExpense(data.totalExpense);
setTotalIncome(data.totalIncome);
setTotalPage(data.pageObj.totalPage);
// 上滑加载状态
setLoading(LOAD_STATE.success);
setRefreshing(REFRESH_STATE.success);
// 请求列表数据
const refreshData = () =>
setRefreshing(REFRESH_STATE.loading);
if (page != 1)
setPage(1);
else
getBillList();
;
;
const loadData = () =>
if (page < totalPage)
setLoading(LOAD_STATE.loading);
setPage(page + 1);
return <div className=s.home>
<div className=s.header>
<div className=s.dataWrap>
<span className=s.expense>总支出:<b>¥ totalExpense </b></span>
<span className=s.income>总收入:<b>¥ totalIncome </b></span>
</div>
<div className=s.typeWrap>
<div className=s.left>
<span className=s.title>类型 <Icon className=s.arrow type="arrow-bottom" /></span>
</div>
<div className=s.right>
<span className=s.time>2022-05<Icon className=s.arrow type="arrow-bottom" /></span>
</div>
</div>
</div>
<div className=s.contentWrap>
dataList.length ? <Pull
animationDuration=200
stayTime=400
refresh=
state: refreshing,
handler: refreshData
load=
state: loading,
distance: 200,
handler: loadData
>
dataList.map((item, index) => <BillItem
bill=item
key=index
/>)
</Pull> : null
</div>
</div>
export default Home
在 src\\container\\Home\\style.module.less
添加样式
.home
height: 100%;
display: flex;
flex-direction: column;
padding-top: 80px;
.header
position: fixed;
top: 0;
left: 0;
display: flex;
flex-direction: column;
justify-content: space-between;
width: 100%;
height: 80px;
background-color: #007fff;
color: #fff;
font-size: 14px;
z-index: 100;
padding: 10px;
.data-wrap
font-size: 14px;
> span
font-size: 12px;
> b
font-size: 26px;
font-family: DINCondensed-Bold, DINCondensed;
margin-left: 4px;
.income
margin-left: 10px;
.type-wrap
display: flex;
justify-content: flex-end;
align-items: flex-end;
> div
align-self: flex-start;
background: rgba(0, 0, 0, 0.1);
border-radius: 30px;
padding: 3px 8px;
font-size: 12px;
.left
margin-right: 6px;
.arrow
font-size: 12px;
margin-left: 4px;
.content-wrap
height: calc(~"(100% - 50px)");
overflow: hidden;
overflow-y: scroll;
background-color: #f5f5f5;
padding: 10px;
:global
.za-pull
overflow: unset;
6.编写账单BillItem子组件
下面需要实现
在 src\\components\\BillItem\\index.jsx
添加代码
import React, useEffect, useState from 'react';
import PropTypes from 'prop-types';
import dayjs from 'dayjs';
import Cell from 'zarm';
import useNavigate from 'react-router-dom'
import CustomIcon from '../CustomIcon';
import typeMap from '@/utils';
import s from './style.module.less';
const BillItem = ( bill ) =>
const [income, setIncome] = useState(0); // 收入
const [expense, setExpense] = useState(0); // 支出
const navigate = useNavigate(); // 路由实例
// 当添加账单是,bill.bills 长度变化,触发当日收支总和计算。
useEffect(() =>
// 初始化将传入的 bill 内的 bills 数组内数据项,过滤出支出和收入。
// pay_type:1 为支出;2 为收入
// 通过 reduce 累加
const _income = bill.bills.filter(i => i.pay_type == 2).reduce((curr, item) =>
curr += Number(item.amount);
return curr;
, 0);
setIncome(_income);
const _expense = bill.bills.filter(i => i.pay_type == 1).reduce((curr, item) =>
curr += Number(item.amount);
return curr;
, 0);
setExpense(_expense);
, [bill.bills]);
// 前往账单详情
const goToDetail = (item) =>
navigate(`/detail?id=$item.id`)
;
return <div className=s.item>
<div className=s.headerDate>
<div className=s.date>bill.day</div>
<div className=s.money>
<span>
<img src=`src/assets/images/zhi.png` alt='支' />
<span>¥ expense.toFixed(2) </span>
</span>
<span>
<img src=`src/assets/images/shou.png` alt="收" />
<span>¥ income.toFixed(2) </span>
</span>
</div>
</div>
bill && bill.bills.map(item => <Cell
className=s.bill
key=item.id
onClick=() => goToDetail(item)
title=
<>
<CustomIcon
className=s.itemIcon
type=item.type_id ? typeMap[item.type_id].icon : 1
/>
<span> item.type_name </span>
</>
description=<span style= color: item.pay_type == 2 ? 'red' : '#39be77' >`$item.pay_type == 1 ? '-' : '+'$item.amount`</span>
help=<div>dayjs(item.date).format('HH:mm') item.remark ? `| $item.remark` : ''</div>
>
</Cell>)
</div>
;
BillItem.propTypes =
bill: PropTypes.object
;
export default BillItem;
在 src\\components\\BillItem\\style.module.less
里添加子组件的样式
.item
border-radius: 10px;
react + zarm 实现账单列表类型以及时间条件弹窗封装
react + zarm + antV F2 实现账单数据统计饼图效果
eggjs 怎么实现获取账单列表接口并且实现列表数据分页查询功能?