上节写了统计用的两个接口,这节来加一下 swagger 文档,然后写下前端部分。
这个接口有 2 个 query 参数,返回值是一个对象,所以这样写:
@ApiBearerAuth()
@ApiQuery({
name: 'startTime',
type: String,
description: '开始时间'
})
@ApiQuery({
name: 'endTime',
type: String,
description: '结束时间'
})
@ApiResponse({
status: HttpStatus.OK,
type: UserBookignCount
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
涉及到的 vo 在 src/statistic/vo/UserBookignCount.vo.ts
import { ApiProperty } from "@nestjs/swagger";
export class UserBookignCount {
@ApiProperty()
userId: string;
@ApiProperty()
username: string;
@ApiProperty()
bookingCount: string;
}
2
3
4
5
6
7
8
9
10
11
12
13
访问下 http://localhost:3005/api-doc
可以看到这个接口的文档:
没啥问题。
然后添加另一个接口的:
@ApiBearerAuth()
@ApiQuery({
name: 'startTime',
type: String,
description: '开始时间'
})
@ApiQuery({
name: 'endTime',
type: String,
description: '结束时间'
})
@ApiResponse({
status: HttpStatus.OK,
type: MeetingRoomUsedCount
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
src/statistic/MeetingRoomUsedCount.vo.ts
import { ApiProperty } from "@nestjs/swagger";
export class MeetingRoomUsedCount {
@ApiProperty()
meetingRoomId: string;
@ApiProperty()
meetingRoomName: string;
@ApiProperty()
usedCount: string;
}
2
3
4
5
6
7
8
9
10
11
12
13
然后再加个 @ApiTags 把这俩接口文档分成一组:
这样,swagger 文档就完成了。
然后来写前端代码:
统计的路由我们已经写过了,只要填内容就行。
原型图是这样的:
加个 antd 的 Form,然后再用 echarts 的图表展示下数据就好了。
先加下 form:
import { Button, DatePicker, Form, Select } from "antd";
import "./statistics.css";
export function Statistics() {
function getStatisticData(values: { startTime: string; endTime: string; }) {
console.log(values);
}
return <div id="statistics-container">
<div className="statistics-form">
<Form
onFinish={getStatisticData}
name="search"
layout='inline'
colon={false}
>
<Form.Item label="开始日期" name="startTime">
<DatePicker />
</Form.Item>
<Form.Item label="结束日期" name="endTime">
<DatePicker />
</Form.Item>
<Form.Item label="图表类型" name="chartType" initialValue={"bar"}>
<Select>
<Select.Option value="pie">饼图</Select.Option>
<Select.Option value="bar">柱形图</Select.Option>
</Select>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
查询
</Button>
</Form.Item>
</Form>
</div>
<div className="statistics-chart">
图表
</div>
</div>
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
css:
#statistics-container {
padding: 20px;
}
#statistics-container .statistics-form {
margin-bottom: 40px;
}
#statistics-container .statistics-chart {
width: 800px;
height: 600px;
}
2
3
4
5
6
7
8
9
10
点击查询,会打印 form 的值:
然后安装 echarts:
npm install echarts --save
然后通过 useRef 拿到 dom 元素,再初始化下 echarts 的柱状图:
import { Button, DatePicker, Form, Select } from "antd";
import "./statistics.css";
import * as echarts from 'echarts';
import { useEffect, useRef } from "react";
export function Statistics() {
const containerRef = useRef<HTMLDivElement>(null);
function getStatisticData(values: { startTime: string; endTime: string; }) {
console.log(values);
}
useEffect(() => {
const myChart = echarts.init(containerRef.current);
myChart.setOption({
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [
{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
});
}, []);
return <div id="statistics-container">
<div className="statistics-form">
<Form
onFinish={getStatisticData}
name="search"
layout='inline'
colon={false}
>
<Form.Item label="开始日期" name="startTime">
<DatePicker />
</Form.Item>
<Form.Item label="结束日期" name="endTime">
<DatePicker />
</Form.Item>
<Form.Item label="图表类型" name="chartType" initialValue={"bar"}>
<Select>
<Select.Option value="pie">饼图</Select.Option>
<Select.Option value="bar">柱形图</Select.Option>
</Select>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
查询
</Button>
</Form.Item>
</Form>
</div>
<div className="statistics-chart" ref={containerRef}></div>
</div>
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
这样 echarts 就成功引入了:
然后我们加一下接口:
在 src/interface/interfaces.ts 里加一下:
export async function meetingRoomUsedCount(startTime: string, endTime: string) {
return await axiosInstance.get('/statistic/meetingRoomUsedCount', {
params: {
startTime,
endTime
}
});
}
export async function userBookingCount(startTime: string, endTime: string) {
return await axiosInstance.get('/statistic/userBookingCount', {
params: {
startTime,
endTime
}
});
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
我们加一个 state 来存储返回的数据,然后点击查询的时候请求接口:
当数据变化的时候,渲染图表:
import { Button, DatePicker, Form, Select, message } from "antd";
import "./statistics.css";
import * as echarts from 'echarts';
import { useEffect, useRef, useState } from "react";
import { userBookingCount } from "../../interfaces/interfaces";
import dayjs from "dayjs";
interface UserBookingData {
userId: string;
username: string;
bookingCount: string;
}
export function Statistics() {
const [userBookingData, setUserBookingData] = useState<Array<UserBookingData>>();
const containerRef = useRef<HTMLDivElement>(null);
async function getStatisticData(values: { startTime: string; endTime: string; }) {
const startTime = dayjs(values.startTime).format('YYYY-MM-DD');
const endTime = dayjs(values.endTime).format('YYYY-MM-DD');
const res = await userBookingCount(startTime, endTime);
const { data } = res.data;
if(res.status === 201 || res.status === 200) {
setUserBookingData(data);
} else {
message.error(data || '系统繁忙,请稍后再试');
}
}
useEffect(() => {
const myChart = echarts.init(containerRef.current);
if(!userBookingData) {
return;
}
myChart.setOption({
title: {
text: '用户预定情况'
},
tooltip: {},
xAxis: {
data: userBookingData?.map(item => item.username)
},
yAxis: {},
series: [
{
name: '预定次数',
type: 'bar',
data: userBookingData?.map(item => {
return {
name: item.username,
value: item.bookingCount
}
})
}
]
});
}, [userBookingData]);
return <div id="statistics-container">
<div className="statistics-form">
<Form
onFinish={getStatisticData}
name="search"
layout='inline'
colon={false}
>
<Form.Item label="开始日期" name="startTime">
<DatePicker />
</Form.Item>
<Form.Item label="结束日期" name="endTime">
<DatePicker />
</Form.Item>
<Form.Item label="图表类型" name="chartType" initialValue={"bar"}>
<Select>
<Select.Option value="pie">饼图</Select.Option>
<Select.Option value="bar">柱形图</Select.Option>
</Select>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
查询
</Button>
</Form.Item>
</Form>
</div>
<div className="statistics-chart" ref={containerRef}></div>
</div>
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
这样,点击查询的时候就会根据返回的数据渲染柱形图:
然后我们再加上饼图的部分:
这样,统计的图表就完成了:
我们在下面再加一个会议室使用情况的图表。
过程一摸一样。
import { Button, DatePicker, Form, Select, message } from "antd";
import "./statistics.css";
import * as echarts from 'echarts';
import { useEffect, useRef, useState } from "react";
import { meetingRoomUsedCount, userBookingCount } from "../../interfaces/interfaces";
import dayjs from "dayjs";
import { useForm } from "antd/es/form/Form";
interface UserBookingData {
userId: string;
username: string;
bookingCount: string;
}
interface MeetingRoomUsedData {
meetingRoomName: string;
meetingRoomId: number;
usedCount: string;
}
export function Statistics() {
const [userBookingData, setUserBookingData] = useState<Array<UserBookingData>>();
const [meetingRoomUsedData, setMeetingRoomUsedData] = useState<Array<MeetingRoomUsedData>>();
const containerRef = useRef<HTMLDivElement>(null);
const containerRef2 = useRef<HTMLDivElement>(null);
async function getStatisticData(values: { startTime: string; endTime: string; }) {
const startTime = dayjs(values.startTime).format('YYYY-MM-DD');
const endTime = dayjs(values.endTime).format('YYYY-MM-DD');
const res = await userBookingCount(startTime, endTime);
const { data } = res.data;
if(res.status === 201 || res.status === 200) {
setUserBookingData(data);
} else {
message.error(data || '系统繁忙,请稍后再试');
}
const res2 = await meetingRoomUsedCount(startTime, endTime);
const { data: data2 } = res2.data;
if(res2.status === 201 || res2.status === 200) {
setMeetingRoomUsedData(data2);
} else {
message.error(data2 || '系统繁忙,请稍后再试');
}
}
useEffect(() => {
const myChart = echarts.init(containerRef.current);
if(!userBookingData) {
return;
}
myChart.setOption({
title: {
text: '用户预定情况'
},
tooltip: {},
xAxis: {
data: userBookingData?.map(item => item.username)
},
yAxis: {},
series: [
{
name: '预定次数',
type: form.getFieldValue('chartType'),
data: userBookingData?.map(item => {
return {
name: item.username,
value: item.bookingCount
}
})
}
]
});
}, [userBookingData]);
useEffect(() => {
const myChart = echarts.init(containerRef2.current);
if(!meetingRoomUsedData) {
return;
}
myChart.setOption({
title: {
text: '会议室使用情况'
},
tooltip: {},
xAxis: {
data: meetingRoomUsedData?.map(item => item.meetingRoomName)
},
yAxis: {},
series: [
{
name: '使用次数',
type: form.getFieldValue('chartType'),
data: meetingRoomUsedData?.map(item => {
return {
name: item.meetingRoomName,
value: item.usedCount
}
})
}
]
});
}, [meetingRoomUsedData]);
const [form] = useForm();
return <div id="statistics-container">
<div className="statistics-form">
<Form
form={form}
onFinish={getStatisticData}
name="search"
layout='inline'
colon={false}
>
<Form.Item label="开始日期" name="startTime">
<DatePicker />
</Form.Item>
<Form.Item label="结束日期" name="endTime">
<DatePicker />
</Form.Item>
<Form.Item label="图表类型" name="chartType" initialValue={"bar"}>
<Select>
<Select.Option value="pie">饼图</Select.Option>
<Select.Option value="bar">柱形图</Select.Option>
</Select>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
查询
</Button>
</Form.Item>
</Form>
</div>
<div className="statistics-chart" ref={containerRef}></div>
<div className="statistics-chart" ref={containerRef2}></div>
</div>
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# 总结
这节我们加了 swagger 文档并且写了统计管理模块的前端代码。
前端部分主要是 echarts 的图表,这个根据返回的数据调整下格式,然后设置到 echarts 的 options 就行。
至此,所有模块的钱后端代码就都完成了。