这个项目是用于展示一些产品以及运营的数据,也便于记录运营数据
总的来说分为可视化图表页以及后台数据页
1├─dtable
2│ ├─operations
3│ └─product
4│ ├─tracking
5│ └─untracking
6├─dvisualization
7└─login
8
我负责的就是 dvisualization 部分
后台总体框架的搭建和交通局的类似,但是我这次采用了重邮帮后台的路由以及侧边栏渲染,这里就不多谈了,有兴趣可以看交通局
数据可视化界面中的图表,我采用的是Rechart,易上手,类型丰富,最重要的是有中文翻译
因为涉及到数据的展示,所以我采用数据与组件分离的设计模式,将组件和数据抽离开
先说 service,我们技术选型的时候选择了 SWR 作为网络请求库,原因有以下几点:
但是 SWR 同样也具有一些缺点
1export function useGetPv() {
2 const { data, error, isLoading } = useSWR(
3 `/data-middle-office/pvuv?type=pv&periods=${xAxis["days"]}`,
4 fetcher,
5 );
6 if (!isLoading && !error) {
7 const cqappPv = data.products.cqapp;
8 const cqhelperPv = data.products.cqhelper;
9 return [cqappPv, cqhelperPv];
10 }
11 // return [null, null];
12}
13
像这样一个 swr 获取 PV 数据,在 isLoading 阶段是不会有返回值的,这样就会导致const [cqappPv, cqhelperPv] = useGetPv()
报错 undefined 所以我采用return [null,null]
来处理,像这样的空值处理在数据组件分离中很常见,感觉我这样的写法也不算是最优的。
另外一点关于 service 数据处理的是关于类型的处理 早在暑假的场地申请中遇到两个模块类似的数据的处理,当时我的做法是直接拆开为两个部分,但是这样会有一些问题:
1//,其余场地
2export interface DataType {
3 application_id: number;
4 location_id: number;
5 place?: string;
6 apply_date: number;
7 periods?: boolean[];
8 use_date?: string;
9 application: string;
10 applicant_id: string;
11 organization?: string;
12 is_org: boolean;
13 state: number;
14 reason: string;
15 phone: string;
16}
17//科技会堂
18export interface techologyHallDataType {
19 application_id: number;
20 location_id: number;
21 place?: string;
22 apply_date: number;
23 payloads: payload[];
24 periods?: boolean[];
25 use_date?: string;
26
27 application: string;
28 applicant_id: string;
29 organization_name?: string;
30 is_org: boolean;
31 state: number;
32 reason: string;
33 phone: string;
34}
35
而这次的运营数据也遇到了对应的问题,但这次我选择不分开而是联合起来 数据类型部分:
1export type OperationData = {
2 id: string;
3 name: string;
4 periods: string;
5 purpose: string;
6 users: string;
7 price: string;
8};
9
10export type helperOperationData = OperationData & {
11 reading: number;
12 transmit: number;
13};
14
15export type qqOperationData = OperationData & {
16 reading: number;
17 comment: number;
18};
19
20export type otherData = OperationData & {
21 way: string;
22 result: string;
23};
24
获取数据部分:
1export type Operations<T extends "qq" | "helper" | "other"> = T extends "qq"
2 ? qqOperationData[]
3 : T extends "helper"
4 ? helperOperationData[]
5 : T extends "other"
6 ? otherData[]
7 : never;
8export function getOperationData<T extends "qq" | "helper" | "other">(
9 project: T,
10 periods?: string,
11): Operations<T> | undefined {
12 const url = periods
13 ? `/data-middle-office/runtimes/${project}?periods=${periods}`
14 : `/data-middle-office/runtimes/${project}`;
15 // eslint-disable-next-line react-hooks/rules-of-hooks
16 const { data, error, isLoading } = useSWR(url, fetcher);
17 if (isLoading) {
18 console.log("Loading...");
19 return undefined;
20 } else if (error) {
21 console.log("Error:", error);
22 return undefined;
23 } else {
24 console.log("Data:", data);
25 return data as Operations<T>;
26 }
27}
28
采取对应参数返回对应数据模式,一开始采用的是函数重载方式,但是过于臃肿,于是换成这种泛型模式
图表部分我采用的是二层封装的思路
为了文章的大小就不在这展示了。
这算是第 4 次做项目,可能也是因为项目本身也不大,做起来还是很快的,只是在后端接口上耽误了时间
debug 能力也有所提高,对于一些小 bug 比如跨域以及图片路径丢失等等,解决起来比暑假快上不少
重点收获是图表的封装以及对网络请求的一些理解,还有 React Design 的一些想法
记得关注 RRFE-CLI