react + zarm + antV F2 实现账单数据统计饼图效果

网友投稿 1086 2022-11-28

react + zarm + antV F2 实现账单数据统计饼图效果

react + zarm + antV F2 实现账单数据统计饼图效果

需要实现的效果

为了方便展示,饼图放到右边标明:

实现过程

这里我们尝试用一下 antV F2 移动端可视化引擎来实现饼图效果

1.F2 移动端可视化引擎

​​文档:React 中使用:

​​install @antv/f2 --savenpm install

我们可以参考这里的例子:

​​饼图:components 里添加 PieChart 文件夹,里面新增 ​​index.jsx​​​ 跟 ​​style.module.less​​ 文件,添加代码如下:

import Canvas from "@antv/f2-react";import { Chart, Interval, Legend, PieLabel } from "@antv/f2";import PropTypes from 'prop-types';import s from './style.module.less';const PieChart = ({ chartData = [] }) => { console.log('进入 PieChart', chartData) return (

{ chartData.length > 0 ? { const { yMax, yMin } = record; return { // 半径放大 1.1 倍 r: (yMax - yMin) * 1.1, }; }, }} /> { return { text: `${data.type_name}:${data.percent}%`, fill: "#0d1a26", fontSize: 12, }; }} /> : null }
);};PieChart.propTypes = { chartData: PropTypes.array,}export default PieChart;

.pie-chart { min-height: 200px;}

3.编写数据分析页面的逻辑

我们在 container 里添加 Data 文件夹,里面新增 ​​index.jsx​​​ 跟 ​​style.module.less​​ 文件,以及 api 相关配置文件,添加代码如下:

import React, { useEffect, useRef, useState } from 'react';import { Icon, Progress, Toast } from 'zarm';import cx from 'classnames';import dayjs from 'dayjs';import CustomIcon from '@/components/CustomIcon';import PopupDate from '@/components/PopupDate';import PieChart from '@/components/PieChart';import { analysisMonthBill } from "./api/index.js";import { typeMap } from '@/utils';import s from './style.module.less';const Data = () => { const monthRef = useRef(); const [currentMonth, setCurrentMonth] = useState(dayjs().format('YYYY-MM')); // 当前月份 const [totalType, setTotalType] = useState('expense'); // 收入或支出类型 const [totalExpense, setTotalExpense] = useState(0); // 总支出 const [totalIncome, setTotalIncome] = useState(0); // 总收入 const [expenseData, setExpenseData] = useState([]); // 支出数据 const [incomeData, setIncomeData] = useState([]); // 收入数据 const [pieType, setPieType] = useState('expense'); // 饼图的「收入」和「支出」控制 const [chartData, setChartData] = useState([]); // 饼图需要渲染的数据 useEffect(() => { getData(); }, [currentMonth]); // 获取数据详情 const getData = async () => { const { status, desc, data } = await analysisMonthBill({ billDate: currentMonth // 示例值:2022-02 }); console.log('获取数据详情', status, desc, data) if(status === 200) { // 总收支 setTotalExpense(data.totalExpense); setTotalIncome(data.totalIncome); // 过滤支出和收入 let expense_data = data.dataList.filter(item => item.pay_type == 1).sort((a,) => b.number - a.number); // 过滤出账单类型为支出的项 let income_data = data.dataList.filter(item => item.pay_type == 2).sort((a,) => b.number - a.number); // 过滤出账单类型为收入的项 expense_data = expense_data.map(item => { return { ...item, payType: item.pay_type.toString(), percent: Number(Number((item.number / Number(data.totalExpense)) * 100).toFixed(2)) } }) income_data = income_data.map(item => { return { ...item, payType: item.pay_type.toString(), percent: Number(Number((item.number / Number(data.totalIncome)) * 100).toFixed(2)) } }) setExpenseData(expense_data); setIncomeData(income_data); // 设置饼图数据 setChartData(pieType == 'expense' ? expense_data : income_data); }else{ Toast.show(desc); } }; // 月份弹窗开关 const monthShow = () => { monthRef.current && monthRef.current.show(); }; // 选择月份 const selectMonth = (item) => { setCurrentMonth(item); }; // 切换收支构成类型 const changeTotalType = (type) => { setTotalType(type); }; // 切换饼图收支类型 const changePieType = (type) => { setPieType(type); setChartData(type == 'expense' ? expenseData : incomeData); } return

{currentMonth}
共支出
¥{ totalExpense }
共收入¥{ totalIncome }
收支构成
changeTotalType('expense')} className={cx({ [s.expense]: true, [s.active]: totalType == 'expense' })}>支出 changeTotalType('income')} className={cx({ [s.income]: true, [s.active]: totalType == 'income' })}>收入
{ (totalType == 'expense' ? expenseData : incomeData).map(item =>
{ item.type_name }
¥{ Number(item.number).toFixed(2) || 0 }
) }
收支构成
changePieType('expense')} className={cx({ [s.expense]: true, [s.active]: pieType == 'expense' })}>支出 changePieType('income')} className={cx({ [s.income]: true, [s.active]: pieType == 'income' })}>收入
{/* 饼图 */}
}export default

.data { min-height: 100%; background-color: #f5f5f5; .total { background-color: #fff; display: flex; flex-direction: column; align-items: center; padding: 24px 0; margin-bottom: 10px; .time { position: relative; width: 96px; padding: 6px; background-color: #f5f5f5; color: rgba(0, 0, 0, .9); border-radius: 4px; font-size: 14px; display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; span:nth-of-type(1)::after { content: ''; position: absolute; top: 9px; bottom: 8px; right: 28px; width: 1px; background-color: rgba(0, 0, 0, .5); } .date { font-size: 16px; color: rgba(0, 0, 0, .5); } } .title { color: #007fff; margin-bottom: 8px; font-size: 12px; font-weight: 500; } .expense { font-size: 24px; color: #007fff; font-weight: 600; margin-bottom: 16px; } .income { color: rgba(0, 0, 0, .5); font-weight: 500; } } .structure { padding: 0 16px 54px; background-color: #fff; margin-bottom: 10px; .head { display: flex; justify-content: space-between; align-items: center; padding: 12px 0; .title { font-size: 18px; color: rgba(0, 0, 0, .9); } .tab { span { display: inline-block; width: 40px; height: 24px; background-color: #f5f5f5; text-align: center; line-height: 24px; margin-left: 10px; border-radius: 4px; } .expense { &.active { background-color: rgba(0, 127, 255, 0.2); color: #007fff; } } .income { &.active { background-color: rgba(236, 190, 37, 0.2); color: rgb(236, 190, 37); } } } } .content { .item { display: flex; height: 50px; align-items: center; .left { flex: 4; display: flex; align-items: center; justify-content: space-between; margin-right: 10px; .type { display: flex; align-items: center; span:nth-of-type(1) { display: flex; justify-content: center; align-items: center; border-radius: 50%; width: 30px; height: 30px; margin-right: 10px; color: #fff; flex-shrink: 0; } .name { width: 30px; } .expense { background-color: #007fff; } .income { background-color: rgb(236, 190, 37); } } } .right { flex: 8; display: flex; align-items: center; .percent { flex: 1; :global { .za-progress__track { background: transparent; } } } .momey { width: 100px; } } } } .proportion { background-color: #fff; padding: 12px 0; .head { display: flex; justify-content: space-between; align-items: center; padding: 12px 0; .title { font-size: 18px; color: rgba(0, 0, 0, .9); } .tab { span { display: inline-block; width: 40px; height: 24px; background-color: #f5f5f5; text-align: center; line-height: 24px; margin-left: 10px; border-radius: 4px; } .expense { &.active { background-color: rgba(0, 127, 255, 0.2); color: #007fff; } } .income { &.active { background-color: rgba(236, 190, 37, 0.2); color: rgb(236, 190, 37); } } } } } }}

import { fetchData } from "@/utils/axios.js";// 获取月度统计账单export function analysisMonthBill(data) { return fetchData('/api/analysis/monthBill', 'get', data);}

4.测试一下效果

我们可以通过切换月份得到该月份的统计数据

收支构成可以通过切换支出跟收入查看:

饼图构成也是一下的交互

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:浏览器原理 35 # HTTPS
下一篇:Mybatis动态SQL的示例代码
相关文章

 发表评论

暂时没有评论,来抢沙发吧~