5.27
一天时间,20+ 模块,从后端到前端,从业务规则引擎到地图可视化——记录一次高强度全栈开发之旅。
背景
工厂设备管理涉及工位、网格、巡检、维护、检测、备件、故障报修、人员调度等诸多环节。传统 Excel 管理方式效率低下且容易出错,一个统一的全生命周期管理系统是刚需。
我选择 FastAPI + 原生 JavaScript SPA 的架构,不引入前端框架,用最小依赖实现一个功能完整的工业管理系统。
技术栈
| 层级 | 技术 |
|---|---|
| 后端框架 | FastAPI (Python) |
| ORM | SQLAlchemy (async) |
| 数据库 | MySQL |
| 前端 | 原生 JS SPA (零框架) |
| 地图 | Leaflet.js + 高德瓦片 |
| AI | DeepSeek Agent |
| 消息 | 飞书 Webhook |
一、后端基础设施
1.1 通用 CRUD 基类
所有实体共享同一个 CRUD 基类,自动处理分页、排序、搜索和关联查询:
class BaseCRUD:
model: type[Base]
async def list(self, page, page_size, order_by, filters) -> PaginatedResponse
async def get(self, id) -> model
async def create(self, data) -> model
async def update(self, id, data) -> model
async def delete(self, id) -> None
这样一来,新增一个模块只需要定义 Model、Schema、Router 三部分,CRUD 逻辑完全复用。
1.2 依赖解析器
实体之间存在复杂的引用关系(例如工位属于网格,网格属于位置),删除时不能简单地级联,而需要精确判断依赖。我实现了 DependencyResolver,维护一张 9 实体映射表:
- 查询某个实体被哪些其他实体引用
- 删除前自动检查是否有子依赖
- 返回清晰的依赖树供前端展示
1.3 业务规则引擎
规则引擎采用可配置架构,每条规则定义为一个独立的 BusinessRule:
class BusinessRule:
code: str # 规则编码, 如 "HAS_CHILDREN"
message: str # 用户可读的错误信息
check: Callable # 校验函数
detail: dict # 附加详情
已实现的规则包括:
- DEPENDENCY_NOT_FOUND — 引用的外键实体不存在
- HAS_CHILDREN — 实体仍有子项,拒绝删除
- CIRCULAR_REFERENCE — 工艺路线中出现循环引用
- INVALID_STATUS_TRANSITION — 工单状态变更不合法
- STOCK_RANGE_INVALID — 备件库存超出安全范围
每个模块的创建、更新、删除操作都串联了对应的业务规则检查,在数据库层面之前拦截非法操作。
二、后端模块全景
系统共实现了 28 个 API 模块,涵盖工厂管理的方方面面:
基础数据模块
- 工位管理 (Station) — 工位基本信息、经纬度坐标、状态
- 网格管理 (Grid) — 厂区网格划分
- 位置管理 (Location) — 车间/厂房层级结构
设备与备件模块
- 设备分类 / 用途 / 制造商 — 设备主数据
- 故障字典 — 标准化故障编码与描述
- 备件库位 / 分类 / 型号 — 备件库存主数据
业务路线模块
- 巡检路线 & 项目 — 巡检计划与检查项
- 维护路线 & 项目 — 维护计划与作业项
- 检测路线 & 项目 — 检测计划与测试项
工艺模块
- 工艺定义 — 标准工艺流程
- 工艺路线 — 工艺步骤与流转规则(含循环引用检测)
任务与工单模块
- 巡检 / 维护 / 检测任务 — 任务生成、分配、跟踪
- 故障报修单 — 报修、诊断、备件推荐、维修闭环
- 问题报告 & 调度 — 问题上报与派工
人员与审批
- 人员档案 & 分配 — 员工信息与任务分配
- 审批中心 — 多类型审批流
- 库存工作台 — 备件出入库、流水账
集成模块
- AI Agent — 接入 DeepSeek,提供智能问答与故障诊断
- 飞书通知 — 异步 Webhook,关键事件实时推送
- 统计面板 — 多维度数据汇总
- 导入导出 — Excel 批量导入(含模板下载与预览)
三、前端 SPA 架构
3.1 设计决策:零框架
没有使用 React/Vue。理由很简单:这是一个管理后台,交互模式高度统一(列表 → 表单 → 提交),不需要虚拟 DOM 的响应式能力。原生 JS 够用、够快、零构建步骤。
3.2 CSS 变量驱动的设计系统
采用暖色工业风主题:
:root {
--primary: #e67e22; /* 橙色主色调 */
--bg: #f5f0eb; /* 暖灰背景 */
--card-bg: #ffffff;
--text: #2c3e50;
--border: #e0d5c7;
--shadow: 0 2px 12px rgba(0,0,0,0.08);
}
3.3 SPA 路由
手写了一个轻量 Hash Router:
#/dashboard→ 仪表盘#/stations→ 工位列表#/stations/map→ 工位地图#/grids,#/locations,#/inspection-routes... → 各模块列表
路由切换时动态加载对应的页面模块,保持单页体验。
3.4 可复用组件
抽象了 6 个通用组件,覆盖管理后台 90% 的交互场景:
| 组件 | 功能 |
|---|---|
| DataTable | 分页、搜索、排序、行操作 |
| FormBuilder | JSON Schema 驱动的表单生成 |
| CascadeSelect | 级联下拉(如:位置 → 网格 → 工位) |
| DependentsPanel | 展示实体被哪些记录引用 |
| Wizard | 多步骤向导(如创建工单流程) |
| ImportComponent | 文件上传、预览、确认导入 |
四、地图可视化 — 工位地图
这是整个系统视觉上最亮眼的功能。
4.1 瓦片选择
国内访问 OpenStreetMap 速度不稳定,因此配置了三级降级策略:
高德瓦片 (GCJ02) → ESRI 卫星图 → CartoDB 备用
4.2 坐标转换
高德使用 GCJ02 坐标系,GPS 使用 WGS84。我在前端实现了双向转换:
function wgs84ToGcj02(lng, lat) { ... }
function gcj02ToWgs84(lng, lat) { ... }
编辑工位时存储 WGS84 坐标,地图展示时自动转为 GCJ02,保证国内地图精度。
4.3 交互功能
- 点击标记 → 弹出详情卡片(名称、状态、所属网格、设备数)
- 侧边栏 CRUD → 不离开地图页面完成增删改查
- 飞入动画 → 列表点击工位,地图自动 flyTo 并高亮
- 在线搜索 → 输入地址,调用地理编码 API 定位
五、AI Agent 集成
接入了 DeepSeek 大模型,提供两个核心能力:
- 故障诊断助手 — 输入故障现象,推荐可能的原因和替换备件
- 操作问答 — 回答系统使用问题,降低培训成本
Agent 服务层使用单例模式管理 HTTP 客户端,应用关闭时自动回收资源。
六、开发心得
批量 commit 的节奏感
这次开发共提交了 30+ 个 commit,每个 commit 粒度很小且语义明确:
feat:新功能(如 "add business rules service layer")fix:Bug 修复(如 "guard loadData against undefined module")debug:临时调试日志chore:工程配置
小步提交的好处是:出错时可以精确回滚到任意一个安全点,而不用面对一个巨大的 diff 无从下手。
业务规则在前
在写 CRUD 之前先写好规则引擎是正确的——这保证了所有模块的删除/更新行为一致,不会出现 A 模块做了依赖检查而 B 模块漏掉的情况。
原生 JS 并不痛苦
只要把组件抽象好,原生 JS 写管理后台的体验和框架没有本质区别。反而省去了构建配置、热更新、状态管理库的心智负担。
下一步计划
这是一次"全栈密度"极高的开发体验。从数据库设计到前端地图,从业务规则到 AI 集成,一天之内构建了一个可运行、可演示的完整系统。

浙公网安备 33010602011771号