上篇文章我们写完了welcome页面。现在新增两个dashboard和用户列表展示页面。
编辑
1.dashboard页面
编辑
首先作为layout子路由展示。我们切换到路径看效果图。
编辑
编辑
编辑
首先图标使用我们要先安装工具npm install echarts然后引入 import * as echarts from 'echarts'然后就可以使用了。
使用步骤首先给包裹容器设置id或者ref拿到DOM节点,然后用节点去创建instace实例对象,然后进行配置项就可以了。我们直接上代码。这里有四个图表,首先获取实例以及DOM对象都是一致的,所以我们用自定义钩子设置。
编辑
javascript
import * as echarts from 'echarts'
import { useEffect, useRef, useState } from 'react'
export const useCharts=():[
React.RefObject<HTMLDivElement|null>,
echarts.ECharts | undefined
]=>{
const chartRef = useRef<HTMLDivElement>(null)
const [chartInstance,setChartInstance] = useState<echarts.EChartsType>()
useEffect(()=>{
const chart = echarts.init(chartRef.current as HTMLElement)
setChartInstance(chart)
},[])
return [chartRef,chartInstance]
}
/*
封装useChart 解决了 需要用document.getElementById()获取dom元素
然后 const instance = new echarts.init(dom节点 as HTMLELement) 获取实例
省了这两步
*/
这里我们设置的钩子调用可以拿到DOM容器以及利用容器创建实例。
typescript
import request from '@/utils/request'
import type { DashBoard, Login ,User} from '@/types/api'
//默认导出 需要用api引入 然后 api.login使用
export default {
login(params: Login.params) {
return request.post<Login.LoginResponse>('/user/login', params, {
showLoading: false
})
},
getUserInfo(){
return request.get<User.UserItem>('/users/getUserInfo')
},
//获取工作台数据
getReportData(){
return request.get<DashBoard.ReportData>('/order/dashboard/getReportData')
},
//获取折线图数据
getLineData(){
return request.get<DashBoard.LineData>('/order/dashboard/getLineData')
},
//获取城市分布数据
getPieCityData(){
return request.get<DashBoard.PieData[]>('/order/dashboard/getPieCityData')
},
//年龄分布数据
getPieAgeData(){
return request.get<DashBoard.PieData[]>('/order/dashboard/getPieAgeData')
},
//雷达图
getRadarData(){
return request.get<DashBoard.RadarData>('/order/dashboard/getRadarData')
}
}
这是我们图表获取数据调用的接口。我们可以写代码逻辑展示了。
javascript
import React, { useEffect, useState } from 'react'
import styles from './index.module.less'
import { Button, Card, Descriptions } from 'antd'
import store, { useStore } from '@/store'
import { formatMoney, formatState } from '@/utils'
import api from '@/api/index'
import type { DashBoard } from '@/types/api'
import { useCharts } from '@/hook/useCharts'
/*
创建好图表要用的容器div 节点设置id属性
用线性图表首先安装 npm install echarts
*/
export default function DashBoard() {
const userInfo = useStore(state => state.userInfo)
const [report, setReport] = useState<DashBoard.ReportData>()
//初始化折线图
const [lineRef, lineChart] = useCharts()
//饼图
const [pieRef1, pieChart1] = useCharts()
const [pieRef2, pieChart2] = useCharts()
//雷达图
const [radarRef, radarChart] = useCharts()
useEffect(() => {
//获取线图实例
//配置线图
renderLineChart()
//获取饼图实例1
renderPieChart1()
//获取饼图实例2
renderPieChart2()
//获取雷达图
renderRadarChart()
}, [lineChart, pieChart1, pieChart2, radarChart])
//加载折线图数据
const renderLineChart = async () => {
if (!lineChart) return
const data = await api.getLineData()
lineChart?.setOption({
// title: {
// text: '订单和流水走势图'
// },
tooltip: {
trigger: 'axis'
},
legend: {
data: ['订单', '流水'],
top: 30
},
grid: {
left: 50,
right: 50,
bottom: 20
},
xAxis: {
data: data.label
},
yAxis: {
type: 'value' //数据轴
},
series: [
{
name: '订单',
type: 'line',
data: data.order
},
{
name: '流水',
type: 'line',
data: data.money
}
]
})
}
//加载饼图数据1
const renderPieChart1 = async () => {
if (!pieChart1) return
const data = await api.getPieCityData()
pieChart1?.setOption({
title: {
text: '司机城市分布',
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical', //垂直方向剧中
left: 'left' //左
},
series: [
{
name: '城市分布',
type: 'pie',
radius: '50%',
data: data
}
]
})
}
//加载饼图数据2
const renderPieChart2 = async () => {
if (!pieChart2) return
const data = await api.getPieAgeData()
pieChart2?.setOption({
title: {
text: '司机年龄分布',
left: 'center',
top: 0
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical', //垂直方向剧中
left: 'left' //左
},
series: [
{
name: '年龄分布',
type: 'pie',
radius: [50, 180],
roseType: 'radious',
data: data
}
]
})
}
//加载雷达图
const renderRadarChart = async () => {
if (!radarChart) return
const data = await api.getRadarData()
radarChart?.setOption({
// title: {
// text: '司机模型诊断',
// left: 'center'
// },
legend: {
data: ['司机模型诊断']
},
radar: {
indicator: data.indicator
},
series: [
{
name: '司机模型诊断',
type: 'radar',
data: data.data
}
]
})
}
useEffect(() => {
getReportData()
}, [])
const getReportData = async () => {
const data = await api.getReportData()
//console.log('工作台数据data ', data)
setReport(data)
}
//饼图刷新
const handleRefresh = () => {
;(renderPieChart1(), renderPieChart2())
}
return (
<div className={styles.dashboard}>
<div className={styles.userInfo}>
<img
src='https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'
alt=''
className={styles.userImg}
/>
<Descriptions title='欢迎新同学,每天都要起飞'>
<Descriptions.Item label='用户ID'>
{userInfo.userId}
</Descriptions.Item>
<Descriptions.Item label='邮箱'>
{userInfo.userEmail}
</Descriptions.Item>
<Descriptions.Item label='状态'>
{formatState(userInfo.state)}
</Descriptions.Item>
<Descriptions.Item label='手机号'>
{userInfo.mobile}
</Descriptions.Item>
<Descriptions.Item label='岗位'>
{store.userInfo.job}
</Descriptions.Item>
</Descriptions>
</div>
<div className={styles.report}>
<div className={styles.card}>
<div className={styles.title}>司机数量</div>
<div className={styles.data}>{report?.driverCount}个</div>
</div>
<div className={styles.card}>
<div className={styles.title}>总流水</div>
<div className={styles.data}>{formatMoney(report?.totalmoney)}</div>
</div>
<div className={styles.card}>
<div className={styles.tltle}>总订单</div>
<div className={styles.data}>{report?.orderCount}单</div>
</div>
<div className={styles.card}>
<div className={styles.title}>开通城市</div>
<div className={styles.data}>{report?.cityNum}</div>
</div>
</div>
<div className={styles.chart}>
<Card
title='订单流水走势图'
extra={
<Button type='primary' onClick={renderLineChart}>
刷新
</Button>
}
>
<div ref={lineRef} className={styles.itemChart}></div>
</Card>
</div>
<div className={styles.chart}>
<Card
title='司机分配'
extra={
<Button type='primary' onClick={handleRefresh}>
刷新
</Button>
}
>
<div className={styles.pieChart}>
<div ref={pieRef1} className={styles.itemChart}></div>
<div ref={pieRef2} className={styles.itemChart}></div>
</div>
</Card>
</div>
<div className={styles.chart}>
<Card
title='模型诊断'
extra={
<Button type='primary' onClick={renderRadarChart}>
刷新
</Button>
}
>
<div ref={radarRef} className={styles.itemChart}></div>
</Card>
</div>
</div>
)
}
这里配置项都是最基础的用的最多的,不同种类的图表都需要这些,只是series需要去导入不同的数据。
我们还封装了自定义方法去state转化以及金额转化。
typescript
/*
工具函数封装:格式化金额显示为人民币格式
*/
/**
* 将数字格式化为中文人民币格式(例如:123456.78 => "¥123,456.78")
* @param num - 要格式化的金额,可以是数字或字符串
* @returns 格式化后的字符串,带有人民币符号(¥)
*/
export const formatMoney = (num?: number | string) => {
if(!num) return 0
// 先将 num 转为浮点数,确保是有效的数字
const a = parseFloat(num.toString())
// 使用 toLocaleString 进行本地化格式化,指定地区为中国,货币为人民币(CNY)
return a.toLocaleString('zh-CN', {
style: "currency", // 格式化为货币类型
currency: "CNY" // 指定货币为人民币
})
}
//格式化日期
export const toLocalDate=(date?:Date,rule?:string)=>{
let curdate = new Date()
if(date){
curdate = date
}
if(rule === '1'){
return curdate.toLocaleDateString()
}
if(rule === 'HH::mm:sss') return curdate.toLocaleTimeString()
return curdate.toLocaleString()
}
//用户状态转化
export const formatState=(state:number)=>{
if(state===1)return '在职'
if(state===2)return '试用期'
if(state===3)return '离职'
}
2.userlist页面
编辑
我们是通过去设置到了子路由展示的位置,所以我们只需要添加子路由就可以了。到时候通过点击导航栏切换就行了。
直接展示组件代码。只是实现了静态布局。
typescript
import React from 'react'
import styles from './index.module.less'
import type { User } from '@/types/api'
import type { TableColumnsType, TableProps } from 'antd'
import { Button, Table, Form, Input, Select, Space } from 'antd'
export default function UserList() {
const dataSource = [
{
create: 0,
mobile: '',
job: '',
deptId: '',
deptName: '',
role: 0,
roleLise: '',
state: 0,
userEmail: '',
userId: 0,
userImg: '',
userName: '',
_id: ''
}
]
const columns: TableColumnsType<User.UserItem> = [
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId'
},
{
title: '用户名称',
dataIndex: 'userName',
key: 'userName'
},
{
title: '用户邮箱',
dataIndex: 'userEmail',
key: 'userEmail'
},
{
title: '用户角色',
dataIndex: 'role',
key: 'role'
},
{
title: '用户状态',
dataIndex: 'state',
key: 'state'
},
{
title: '注册时间',
dataIndex: 'createTime',
key: 'createTime'
},
{
title: '操作',
dataIndex: 'address',
key: 'address',
render(record, values) {
return (
<Space>
<Button type='text'>编辑</Button>
<Button type='text' danger>
删除
</Button>
</Space>
)
}
}
]
return (
<div className='user-list'>
<Form
className='search-form'
layout='inline'
initialValues={{ state: 0 }}
>
<Form.Item name='userId' label='用户ID'>
<Input placeholder='请输入用户ID' />
</Form.Item>
<Form.Item name='userName' label='用户名称'>
<Input placeholder='请输入用户名称' />
</Form.Item>
<Form.Item name='state' label='状态'>
<Select style={{ width: 120 }}>
<Select.Option value={0}>所有</Select.Option>
<Select.Option value={1}>在职</Select.Option>
<Select.Option value={2}>试用</Select.Option>
<Select.Option value={3}>离职</Select.Option>
</Select>
</Form.Item>
<Form.Item name='state' label='状态'>
<Space>
<Button type='primary' className='mr10'>
搜索
</Button>
<Button type='default'>重置</Button>
</Space>
</Form.Item>
</Form>
<div className='base-table'>
<div className='header-wrapper'>
<div className='title'>用户列表</div>
<div className='action'>
<Button type='primary'>新增</Button>
<Button type='primary' danger>
批量删除
</Button>
</div>
</div>
<Table dataSource={dataSource} columns={columns} />;
</div>
</div>
)
}