从 0 到 1 构建 React + TypeScript 车辆租赁后台管理系统
在企业级后台管理系统开发中,React 结合 TypeScript 已是主流技术栈 ------TypeScript 的类型校验能大幅降低大型项目的维护成本,React 的组件化特性则适配后台系统复杂的 UI 与交互场景。本文以车辆租赁后台管理系统为例,拆解从技术选型、架构设计到核心功能实现的全流程,为前端开发者提供可落地的实战思路。
一、项目背景与技术栈选型
1. 业务场景特点
车辆租赁后台需覆盖「车辆管理、订单调配、客户管理、财务结算、操作日志」等核心模块,具有以下特点:
- 数据交互频繁(如实时查询车辆状态、订单流转);
- 表单 / 表格操作密集(如批量派发任务、筛选车辆信息);
- 权限分级严格(不同角色可见 / 可操作的模块不同);
- 需兼容多端(PC 端为主,部分功能适配平板)。
2. 核心技术栈
| 技术 / 框架 | 选型理由 |
|---|---|
| React 18 | 组件化开发、Hooks 简化状态管理、Concurrent Mode 提升交互流畅度 |
| TypeScript 5.x | 强类型约束避免类型错误、提升代码可读性、便于团队协作 |
| Umi 4 | 开箱即用的路由 / 构建 / 权限方案,适配中后台开发的工程化需求 |
| Ant Design Pro | 提供 ProTable/ProForm/Descriptions 等中后台高频组件,减少重复造轮子 |
| ahooks | 封装常用 Hooks(如 useRequest、useSelections),简化异步请求 / 状态管理 |
| axios | 统一封装请求拦截、响应处理,适配后端接口规范 |
二、项目架构设计
遵循「高内聚、低耦合」原则,采用分层式架构,目录结构如下:
plaintext
scss
src/
├── api/ // 接口请求封装(按模块拆分)
│ ├── car.ts // 车辆管理接口
│ ├── order.ts // 订单调配接口
│ └── user.ts // 用户/权限接口
├── components/ // 通用业务组件(如OperationRecord、PreviewFiles)
├── pages/ // 页面级组件(按业务模块拆分)
│ ├── CarManage/ // 车辆管理
│ ├── OrderAlloc/ // 订单调配(核心模块)
│ └── System/ // 系统设置
├── utils/ // 工具函数(如字典映射、时间格式化)
├── typings/ // TS类型声明(接口返回值、组件Props)
└── access.ts // 权限控制配置
关键设计原则
- 类型先行:所有接口返回值、组件 Props、全局状态均定义 TS 类型,例如订单调配模块的核心类型:
typescript
运行
typescript
// typings/order.d.ts
/** 订单基础信息 */
export interface AllocOrder {
orderNo: string; // 工单编号
orderStatus: 'toFormulate' | 'toDistribute' | 'completed'; // 订单状态
carNo: string; // 车牌
vin: string; // 车架号
allocateInfo: {
batchNo: string;
deliveryType: string; // 交付类型
outContactsName: string; // 调出联系人
};
}
/** 订单列表请求参数 */
export interface AllocOrderParams {
orderSource: string;
batchNo?: string;
pageSize: number;
current: number;
}
- 复用性优先:抽离通用业务组件(如操作记录组件 OperationRecord),避免重复代码:
tsx
typescript
// components/OperationRecordSection/index.tsx
import React, { useEffect, useRef } from 'react';
import type { ActionType, ProColumns } from '@ant-design/pro-table';
import ProTable from '@ant-design/pro-table';
import { operationListPage } from '@/api/order';
interface OperationRecordSectionProps {
formValues: {
orderNo?: string;
[key: string]: any;
};
}
const OperationRecordSection: React.FC<OperationRecordSectionProps> = ({ formValues }) => {
const actionRef = useRef<ActionType>();
// 监听工单编号变化,自动刷新操作记录
useEffect(() => {
if (formValues?.orderNo) {
actionRef.current?.reload();
}
}, [formValues?.orderNo]);
const columns: ProColumns[] = [
{ title: '操作节点', dataIndex: 'orderNode' },
{ title: '操作人', dataIndex: 'operationName' },
{ title: '操作时间', dataIndex: 'createdDate' },
{ title: '操作详情', dataIndex: 'operatorDetail' },
];
return (
<ProTable
search={false}
actionRef={actionRef}
request={async (params) => {
if (!formValues?.orderNo) return { data: [], total: 0 };
return operationListPage({ ...params, orderNo: formValues.orderNo });
}}
columns={columns}
pagination={{ defaultPageSize: 5 }}
/>
);
};
export default OperationRecordSection;
三、核心功能实现
1. 订单调配模块(核心场景)
订单调配是车辆租赁后台的核心,需实现「方案制定、任务派发、详情查看」等功能,且需结合状态控制权限与交互。
(1)带状态控制的表格渲染
使用 ProTable 实现订单列表,根据订单状态(toFormulate/toDistribute)动态展示操作按钮,且仅允许勾选「方案制定」状态的行:
tsx
typescript
// pages/OrderAlloc/index.tsx
import React, { useState } from 'react';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import ProTable from '@ant-design/pro-table';
import { Button, message } from 'antd';
import { getAllocationList } from '@/api/order';
import Func from '@/utils/Func';
const OrderAlloc = () => {
const [selectedRowKeys, setSelectedRowKeys] = useState<string[]>([]);
const [selectedRows, setSelectedRows] = useState<AllocOrder[]>([]);
// 表格列配置
const columns = [
{
title: '工单编号',
dataIndex: 'orderNo',
key: 'orderNo',
},
{
title: '订单状态',
dataIndex: 'orderStatus',
valueEnum: Func.dictEnum(dictMap, 'AllocOrderStatus'), // 字典映射
},
{
title: '车牌',
dataIndex: 'carNo',
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record) => (
<>
{/* 仅「方案制定」状态显示「方案制定」按钮 */}
{record.orderStatus === 'toFormulate' && (
<a onClick={() => handleOpenFormulateModal(record)}>方案制定</a>
)}
{/* 仅「待派发」状态显示「派发任务」按钮 */}
{record.orderStatus === 'toDistribute' && (
<a onClick={() => handleOpenDispatchModal(record)}>派发任务</a>
)}
<a onClick={() => handleOpenDetail(record)}>详情</a>
</>
),
},
];
return (
<PageHeaderWrapper>
<ProTable
rowKey="orderNo"
rowSelection={{
selectedRowKeys,
onChange: (keys, rows) => {
// 仅保留「方案制定」状态的选中行
const validRows = rows.filter(row => row.orderStatus === 'toFormulate');
setSelectedRowKeys(validRows.map(row => row.orderNo));
setSelectedRows(validRows);
if (rows.length > validRows.length) {
message.warning('仅"方案制定"状态的订单可勾选');
}
},
// 禁用非「方案制定」状态的行勾选
getCheckboxProps: (record) => ({
disabled: record.orderStatus !== 'toFormulate',
}),
}}
request={(params) => getAllocationList({ ...params, orderSource: 'ALLOCATE' })}
columns={columns}
toolBarRender={() => [
<Button
type="primary"
disabled={selectedRows.length === 0}
onClick={() => handleBatchFormulate()}
>
批量方案制定
</Button>,
]}
/>
</PageHeaderWrapper>
);
};
export default OrderAlloc;
(2)详情弹窗实现
通过 Modal 封装详情弹窗,整合 ProTable、Descriptions 组件展示订单多维度信息,并复用操作记录组件:
tsx
javascript
// pages/OrderAlloc/components/DeploymentDetail.tsx
import React, { useEffect, useState } from 'react';
import { Modal, Descriptions, Collapse } from 'antd';
import ProTable from '@ant-design/pro-table';
import OperationRecordSection from '@/components/OperationRecordSection';
import { allocatePlanDetail } from '@/api/order';
import Func from '@/utils/Func';
const DeploymentDetail = ({ visible, onCancel, formValues }) => {
const [orderDetail, setOrderDetail] = useState<AllocOrder | null>(null);
const [taskList, setTaskList] = useState<AllocOrder[]>([]);
// 获取订单详情
useEffect(() => {
if (visible && formValues?.batchNo) {
allocatePlanDetail({ batchNo: formValues.batchNo }).then(res => {
setOrderDetail(res.data);
setTaskList(res.data.taskList || []);
});
}
}, [visible, formValues]);
// 工单信息表格列
const workColumns = [
{ title: '工单编号', dataIndex: 'orderNo' },
{ title: '车型', dataIndex: 'modelName', render: (_, r) => r.carInfo?.modelName || '-' },
{ title: '交付类型', dataIndex: 'deliveryType', render: (_, r) => Func.dictLabel(dictMap, 'DeliveryType', r.allocateInfo?.deliveryType) || '-' },
];
return (
<Modal
open={visible}
onCancel={onCancel}
width="80%"
footer={null}
destroyOnClose
>
<Collapse defaultActiveKey={['1', '2', '3']}>
<Collapse.Panel header="工单信息" key="1">
<ProTable dataSource={taskList} columns={workColumns} pagination={false} />
</Collapse.Panel>
<Collapse.Panel header="调配信息" key="2">
<Descriptions column={3}>
<Descriptions.Item label="交付类型">
{Func.dictLabel(dictMap, 'DeliveryType', orderDetail?.allocateInfo?.deliveryType) || '-'}
</Descriptions.Item>
<Descriptions.Item label="备注">{orderDetail?.remark || '-'}</Descriptions.Item>
</Descriptions>
</Collapse.Panel>
<Collapse.Panel header="操作记录" key="3">
<OperationRecordSection formValues={{ ...formValues, orderNo: orderDetail?.orderNo }} />
</Collapse.Panel>
</Collapse>
</Modal>
);
};
export default DeploymentDetail;
2. 字典映射封装
车辆租赁系统包含大量枚举值(如交付类型、订单状态),封装通用字典工具函数,统一处理类型映射:
typescript
运行
typescript
// utils/Func.ts
/**
* 字典转下拉/表格枚举格式
* @param dictMap 全局字典对象
* @param dictKey 字典key
* @returns 枚举对象
*/
export const dictEnum = (dictMap: any, dictKey: string) => {
if (!dictMap?.[dictKey]) return {};
return dictMap[dictKey].reduce((acc: any, item: any) => {
acc[item.value] = item.label;
return acc;
}, {});
};
/**
* 根据值获取字典标签
* @param dictMap 全局字典对象
* @param dictKey 字典key
* @param value 字典值
* @returns 字典标签
*/
export const dictLabel = (dictMap: any, dictKey: string, value: any) => {
if (!dictMap?.[dictKey] || !value) return '-';
const item = dictMap[dictKey].find((item: any) => item.value === value);
return item?.label || '-';
};
四、项目优化要点
1. 性能优化
- 数据缓存:使用 ahooks 的 useRequest 配置 cacheKey,缓存高频查询的订单列表,避免重复请求;
- 组件懒加载:通过 Umi 的 dynamicImport 实现页面级懒加载,减少首屏加载体积;
- 表格虚拟滚动:ProTable 开启 scroll={{y: 600}} + virtual={true},优化大数据量表格渲染。
2. 体验优化
- 状态联动:勾选行时实时过滤无效行并给出提示,避免用户误操作;
- 兜底显示:所有字典映射、嵌套数据访问均添加兜底(|| '-'),避免页面空白;
- 加载状态:异步请求时添加骨架屏 / 加载动画,提升交互体验。
3. 可维护性优化
- 统一请求封装:拦截请求 / 响应,统一处理 token、错误提示;
- 注释规范:关键业务逻辑、工具函数添加 TSDoc 注释;
- 分支管理:按「功能分支 - 测试分支 - 主分支」流程开发,避免代码冲突。
五、总结
React + TypeScript 构建车辆租赁后台管理系统,核心在于「类型约束降低风险、组件复用提升效率、业务逻辑分层解耦」。本文从架构设计到核心功能实现,覆盖了中后台开发的高频场景:表格状态控制、字典映射、通用组件封装、权限控制等。
实际开发中,需结合业务场景灵活调整 ------ 例如车辆租赁的「车辆定位、合同管理」等扩展模块,可复用本文的架构思路,通过 TypeScript 定义类型、Pro 组件快速实现 UI,最终打造高性能、易维护的企业级后台系统。