From 5eb38a4b05fedb18cf67311a323610f8f8e81795 Mon Sep 17 00:00:00 2001 From: kkfluous Date: Tue, 25 Aug 2026 12:37:58 +0800 Subject: [PATCH] chore: checkpoint local changes --- docs/ln-bi-项目移交交接说明.md | 671 +++++++++++++++++++++++++++++++++ 1 file changed, 671 insertions(+) create mode 100644 docs/ln-bi-项目移交交接说明.md diff --git a/docs/ln-bi-项目移交交接说明.md b/docs/ln-bi-项目移交交接说明.md new file mode 100644 index 0000000..3354636 --- /dev/null +++ b/docs/ln-bi-项目移交交接说明.md @@ -0,0 +1,671 @@ +# LN-BI 项目移交交接说明 + +> 文档版本:1.0 +> 更新日期:2026-08-21 +> 对应代码版本:`1.1.15` +> 对应分支 / 提交:`main` / `2518d9ee5440c39138427ce76d1f6e0faf8d9f29` +> 项目仓库:`https://gitea.lnh2e.com/shishengliang/ln-bi.git` + +## 1. 文档目的与交接边界 + +本文用于帮助新的研发、测试、运维和产品人员快速接管 LN-BI 项目,覆盖: + +- 系统定位、代码结构和运行拓扑; +- 登录认证、角色鉴权和数据权限; +- 本地开发与免登录调试; +- 前后端技术栈; +- 数据对接方、数据库、外部服务及对应 BI / 报表; +- 当前功能、后台任务、接口边界和部署流程; +- 已知技术债、安全风险和交接检查清单。 + +本文依据当前仓库代码和配置编写,不记录数据库密码、JWT 密钥、API Key、OSS 密钥或 CI 仓库凭据。此类信息应通过密码管理器、Portainer / Docker 环境变量或 CI Secret 单独移交。 + +## 2. 项目概览 + +### 2.1 系统定位 + +LN-BI 是羚牛业务数据的统一 BI Web 应用。目前包含两组主入口: + +| 主入口 | 主要模块 | 默认路由 | +| --- | --- | --- | +| 资产 BI | 资产管理、里程管理、车辆 / 加氢热力图、智能调度 | `/asset` | +| 能源 BI | 氢能、电能、ETC | `/energy` | + +应用还保留两个不在主导航中展示的后台入口: + +| 隐藏入口 | 用途 | 路由 | +| --- | --- | --- | +| 充电记录导入 | 上传并管理电费 XLSX 数据 | `/ele/import` | +| 用户反馈管理 | 查看、回复和推进用户反馈 | `/admin/feedback` | + +页面内部主要使用 Hash 保存模块和子页面状态,例如 `/energy#hydrogen/overview`。入口兼容逻辑位于 `src/app/routing.ts`。 + +### 2.2 总体架构 + +```mermaid +flowchart LR + A[羚牛业务系统] -->|一次性 jumpToken| B[LN-BI React 前端] + B -->|/api/auth/exchange| C[Hono API] + C -->|校验 jumpToken / 获取用户角色| A + C -->|签发 8 小时本地 JWT| B + B -->|Bearer JWT| C + + C --> D[(主业务 MySQL / 跨 Schema)] + C --> E[(氢能 MySQL 连接\n默认复用主库)] + C --> F[(车辆位置 PostgreSQL)] + C --> G[OneOS 里程 API] + C --> H[阿里云 OSS] + B --> I[高德地图 JS API] +``` + +生产环境由一个 Node.js 进程同时提供 REST API 和 Vite 构建后的静态页面。开发环境中,Vite 前端和 Hono 后端分别运行,由 Vite 将 `/api` 代理到后端。 + +### 2.3 关键目录 + +| 路径 | 说明 | +| --- | --- | +| `src/App.tsx` | 应用入口、认证门禁、主路由和隐藏页面装配 | +| `src/app/modules.ts` | 资产 / 能源导航模块注册与角色可见性 | +| `src/auth/` | 前端认证状态、JWT 注入、未授权页面 | +| `src/shared/auth/` | 前后端共用角色常量和模块访问判断 | +| `src/server/` | Hono 服务、认证中间件、数据库连接、API 路由和后台任务 | +| `src/modules/` | 各 BI 页面和交互实现 | +| `src/modules/energy/hydrogen-bi-v2/` | 当前氢能 BI 原型迁入版、真实数据适配器和下钻实现 | +| `docs/` | 接口、重构和交接文档 | +| `Dockerfile` | 前端构建 + Node 运行时镜像 | +| `docker-compose.yml` | 当前容器部署参数样例 | +| `woodpecker.yml` | Woodpecker CI 构建、测试、镜像推送流程 | + +### 2.4 当前质量基线 + +2026-08-21 在当前提交和本地依赖环境完成以下验证: + +| 检查 | 结果 | +| --- | --- | +| `npm run lint` | 通过 | +| `npm test` | 113 项通过,0 项失败 | +| `npm run build` | 通过,Vite 成功生成生产构建 | + +测试和构建会输出 Node.js `DEP0205`(`module.register()` 已弃用)警告,目前不阻断运行;后续升级 `tsx` / Node 工具链时应处理。 + +## 3. 登录认证方式 + +### 3.1 正常登录链路 + +项目自身没有用户名 / 密码登录表单,正常入口依赖羚牛业务系统单点跳转: + +1. 用户先登录羚牛业务系统。 +2. 业务系统跳转到 LN-BI,并在 URL 中携带一次性 `jumpToken`。 +3. 前端调用 `GET /api/auth/exchange?jumpToken=...`。 +4. LN-BI 后端调用业务系统的 `issueTokenByJump` 接口校验一次性令牌并取得用户、部门编码和角色。 +5. 后端根据角色计算数据权限级别,并通过主业务库 `tab_department` 补全部门名称。 +6. 后端使用 `JWT_SECRET` 签发有效期 8 小时的 LN-BI JWT。 +7. 前端将 JWT 和用户信息保存到当前标签页的 `sessionStorage`: + - `bi_jwt` + - `bi_user` +8. 前端从地址栏移除 `jumpToken`,之后所有受保护 API 均发送 `Authorization: Bearer `。 +9. API 返回 `401` 时,前端清空本地会话并显示“会话已过期”。 + +关键实现: + +- 前端:`src/auth/AuthProvider.tsx` +- Token 注入:`src/auth/api-client.ts` +- Token 换取:`src/server/auth/login.ts` +- API 认证:`src/server/auth/middleware.ts` + +### 3.2 公开接口与受保护接口 + +不要求 JWT 的接口: + +- `/api/health` +- `/api/auth/*` + +其余 `/api/*` 默认经过统一认证中间件。能源、智能调度、加氢热力图和反馈管理在统一认证之上还有模块级或接口级角色校验。 + +### 3.3 会话特征 + +| 项目 | 当前实现 | +| --- | --- | +| Token 类型 | HS256 JWT(`jsonwebtoken` 默认签名算法) | +| 有效期 | 8 小时 | +| 浏览器存储 | `sessionStorage`,关闭标签页后失效 | +| 用户来源 | 羚牛业务系统 jumpToken 换取 | +| 部门名称来源 | 主业务库 `tab_department` | +| 退出方式 | 当前无独立退出接口;清除标签页会话或收到 401 后清理 | + +## 4. 角色鉴权与数据权限 + +权限分为两层,接手时必须分别理解: + +1. **模块访问权限**:决定能否进入能源、智能调度或反馈后台。 +2. **数据范围权限**:决定用户可查看全量、部门或个人负责的数据。 + +### 4.1 数据范围角色 + +| 业务系统角色 | JWT `permissionLevel` | 数据范围 | +| --- | --- | --- | +| `所有权限`、`数智中心`、`BI-Leader` | `full` | 全量数据 | +| `BI-Leader-Dep` | `department` | `departmentName / department = user.depName` | +| 其他角色或无上述角色 | `personal` | `managerId = user.userId` | + +数据过滤和客户名称脱敏由 `src/server/auth/permissions.ts` 提供。目前明确接入该过滤的主要范围包括: + +- 资产车辆统计与列表; +- 里程实时监控; +- 里程考核车辆明细; +- 智能调度建议。 + +注意:数据权限不是数据库行级安全,而是路由读取数据后在服务端过滤。新增 API 时必须主动调用统一过滤逻辑或实现等价的 SQL 过滤,不能只依赖前端隐藏。 + +### 4.2 模块访问角色 + +| 模块 / 能力 | 允许角色 | 前端控制 | 后端控制 | +| --- | --- | --- | --- | +| 资产管理、里程管理、车辆热力图 | 已认证用户 | 导航默认展示 | 统一 JWT 中间件 | +| 能源 BI(氢能 / 电能 / ETC) | `BI-LEADER-ENERGY` 或 `所有权限` | `/energy` 门禁 | `/api/energy/*` 守卫 | +| 加氢热力图 | `BI-LEADER-ENERGY` 或 `所有权限` | 无权限时不出现在热力图子导航 | `/api/hydrogen-heatmap/*` 守卫 | +| 智能调度 | `BI-SCHEDULE-OPT` | 无角色时不显示模块 | `/api/scheduling/*` 守卫 | +| 反馈管理 | `BI-ADMIN-FEEDBACK` 或任一全量数据角色 | 隐藏页面,需直接访问 | 管理列表与更新接口校验 | +| 用户反馈提交 / 我的反馈 | 已认证用户 | 页面反馈入口 | 统一 JWT 中间件 | + +角色常量和判断位于 `src/shared/auth/roles.ts`。 + +### 4.3 容易误解的权限边界 + +- `full` 只表示数据范围,不代表自动拥有所有模块权限。 +- `数智中心`、`BI-Leader` 虽会获得全量数据,但当前不会自动进入能源模块;能源仅额外接受 `所有权限`。 +- 智能调度当前仅接受 `BI-SCHEDULE-OPT`,不会因为拥有 `full` 数据权限自动放行。 +- 前端隐藏不是安全措施;任何新增受限能力都必须增加后端守卫。 + +## 5. 本地免登录调试环境 + +### 5.1 环境要求 + +- Node.js 22(Docker 和 CI 均使用 Node 22); +- npm,依赖版本以 `package-lock.json` 为准; +- 能访问所需数据库和外部 API 的网络环境; +- 本地配置文件 `.env`。该文件已被 `.gitignore` 忽略,禁止提交。 + +### 5.2 最小启动步骤 + +```bash +npm ci +npm run dev +``` + +启动后: + +| 服务 | 地址 | 说明 | +| --- | --- | --- | +| Vite 前端 | `http://localhost:3000` | 对局域网开放,`/api` 代理到 3001 | +| Hono 后端 | `http://localhost:3001` | `SERVER_PORT` 未设置时的默认端口 | +| 健康检查 | `http://localhost:3001/api/health` | 只验证进程可访问,不验证数据库 | + +### 5.3 免登录开关 + +本地前后端需要同时开启免登录: + +```dotenv +# 仅用于本地开发,生产环境严禁设置为 1 +VITE_DEV_BYPASS_AUTH=1 +DEV_BYPASS_AUTH=1 +``` + +- `VITE_DEV_BYPASS_AUTH=1`:前端直接构造“本地开发”全权限用户,仅在 Vite dev 模式生效。 +- `DEV_BYPASS_AUTH=1`:后端认证中间件注入本地开发用户,否则前端虽然进入页面,API 仍会返回 401。 +- 本地用户包含 `所有权限`、`BI-SCHEDULE-OPT`、`BI-ADMIN-FEEDBACK`、`BI-LEADER-ENERGY`。 +- 免登录只绕过认证,不会替代数据库、OneOS API、高德地图或 OSS 配置。 + +### 5.4 `.env` 配置模板 + +以下仅列变量名和占位符,不得把真实值写入本文或提交到 Git: + +```dotenv +# 认证 +EXTERNAL_API_BASE=https://<业务系统域名> +JWT_SECRET=<高强度随机密钥> +DEV_BYPASS_AUTH=1 +VITE_DEV_BYPASS_AUTH=1 + +# 主业务 MySQL +DB_HOST= +DB_PORT=3306 +DB_USER= +DB_PASSWORD= +DB_NAME= + +# 氢能 MySQL;不填时复用 DB_* +HYDROGEN_DB_HOST= +HYDROGEN_DB_PORT=3306 +HYDROGEN_DB_USER= +HYDROGEN_DB_PASSWORD= +HYDROGEN_DB_NAME= + +# 历史里程 MySQL 连接配置 +# 当前 src/server/mileage-db.ts 未被运行时代码引用;不要误认为修改后会影响里程页面 +MILEAGE_DB_HOST= +MILEAGE_DB_PORT=3306 +MILEAGE_DB_USER= +MILEAGE_DB_PASSWORD= +MILEAGE_DB_NAME= + +# 车辆位置 PostgreSQL +HEATMAP_DB_HOST= +HEATMAP_DB_PORT=5432 +HEATMAP_DB_USER= +HEATMAP_DB_PASSWORD= +HEATMAP_DB_NAME= +HEATMAP_DB_SSL=false + +# OneOS 里程 API +ONEOS_MILEAGE_API_BASE_URL=https:// +ONEOS_MILEAGE_API_KEY= +ONEOS_MILEAGE_API_TIMEOUT_MS=20000 + +# 高德地图 +AMAP_WEB_KEY= +AMAP_SECURITY_JS_CODE= + +# 用户反馈截图 OSS +OSS_REGION= +OSS_ENDPOINT= +OSS_BUCKET= +OSS_ACCESS_KEY_ID= +OSS_ACCESS_KEY_SECRET= +OSS_BASE_DIR= + +# 运行参数 +SERVER_PORT=3001 +MILEAGE_REPORT_AUTO_ARCHIVE=0 +``` + +本地调试建议将 `MILEAGE_REPORT_AUTO_ARCHIVE=0`,避免开发进程在 06:30 自动生成正式日报快照。 + +## 6. 技术栈 + +### 6.1 前端 + +| 分类 | 技术 | +| --- | --- | +| 语言 | TypeScript、TSX、CSS | +| 框架 | React 19 | +| 构建工具 | Vite 6 | +| 样式 | Tailwind CSS 4 + 模块专用 CSS | +| 图表 | Recharts 3;氢能原型包含自定义 DOM / CSS 图表 | +| 动效 | Motion for React | +| 图标 | Lucide React | +| Excel | SheetJS `xlsx` | +| 地图 | 高德地图 JS API | +| 路由 | 浏览器 Path + Hash 自研轻量路由,无 React Router | + +### 6.2 后端 + +| 分类 | 技术 | +| --- | --- | +| 语言 / 运行时 | TypeScript、Node.js 22、ES Module | +| Web 框架 | Hono 4 + `@hono/node-server` | +| TypeScript 运行 | `tsx` | +| 认证 | `jsonwebtoken` | +| MySQL | `mysql2/promise` | +| PostgreSQL | `pg` | +| 对象存储 | `ali-oss` | +| 配置 | `dotenv` / 容器环境变量 | +| 测试 | Node.js 内置 Test Runner | + +### 6.3 构建与部署 + +- `npm run lint`:TypeScript 静态检查; +- `npm test`:运行 `src/**/*.test.ts`; +- `npm run build`:生成 Vite `dist`; +- `npm run start`:Node 直接通过 `tsx` loader 启动服务; +- Docker:Node 22 Alpine 多阶段构建; +- CI:Woodpecker 执行安装、静态检查、测试、构建、Docker 镜像构建和 Harbor 推送; +- 镜像标签:`<分支名>-`; +- 当前 Compose 使用 host 网络,容器服务端口由 `SERVER_PORT` 注入,现有部署样例为 `8111`。 + +## 7. 数据对接与数据源映射 + +### 7.1 运行时数据源总表 + +| 数据源 / 对接方 | 连接方式 | 配置入口 | 主要数据 | 消费模块 | +| --- | --- | --- | --- | --- | +| 羚牛业务系统认证服务 | HTTPS API | `EXTERNAL_API_BASE` | jumpToken、用户、部门编码、角色 | 登录认证 | +| 主业务 MySQL | MySQL | `DB_*` | 车辆、合同、客户、部门、资产流转、电费、ETC、反馈、调度记录等 | 资产、里程关联信息、调度、电能、ETC、反馈 | +| 氢能业务库 | MySQL | `HYDROGEN_DB_*`;未配置则复用 `DB_*` | 加氢流水、加氢站、付款 / 结算、站点余额等 | 氢能 BI、单站、按日、下钻 | +| 里程考核数据 | 主业务 MySQL / 跨 Schema 查询 | 当前实际使用 `DB_*` | 考核目标、考核车辆、日报快照 | 里程统计、日报、智能调度 | +| OneOS 里程服务 | HTTPS API | `ONEOS_MILEAGE_API_*` | 按日 / 区间车辆里程、来源协议 | 里程监控、日报、调度 | +| 车辆位置分析库 | PostgreSQL 只读 | `HEATMAP_DB_*` | 每车每日首个有效定位点 | 车辆热力图 | +| 高德地图 | 浏览器 JS API | `AMAP_WEB_KEY`、`AMAP_SECURITY_JS_CODE` | 地图底图、空间展示 | 车辆 / 加氢热力图 | +| 阿里云 OSS | OSS SDK | `OSS_*` | 用户反馈截图 | 反馈提交、反馈管理 | +| 本地地区映射 | JSON | `src/server/routes/mileage/region-map.json` | 城市到运营区域映射 | 里程筛选和区域聚合 | + +`src/server/mileage-db.ts` 仍定义了一组 `MILEAGE_DB_*` MySQL 连接,但当前没有任何运行时代码导入该连接池。因此它属于历史遗留配置,不计入当前有效运行时数据源;接手人不应通过修改 `MILEAGE_DB_*` 来排查现有里程页面。 + +### 7.2 主业务 MySQL 的主要表 / Schema + +当前部署样例中 `DB_NAME` 指向业务库,同时代码存在 `lingniu_prod.*` 跨 Schema 查询。数据库账号必须具备实际所需 Schema 的最小权限。 + +| 数据域 | 代表表 | 用途 | +| --- | --- | --- | +| 车辆主数据 | `vehicle_info`、`vehicle_status`、`vehicle_model` | 资产、车辆归属、车型、运营状态 | +| 租赁 / 客户 | `vehicle_lease_order_record`、`vehicle_lease_contract_info`、`customer_info` | 客户、部门、经理、项目 | +| 资产流转 | `delivery_vehicle`、`return_vehicle_task`、`vehicle_replacement` | 交车、退车、换车周统计及明细 | +| 实时车辆 | `tab_truck_remote_sync_realtime_info` | 当日里程、车辆省份 | +| 里程考核 | `lingniu_prod.tab_mileage_assessment_target`、`lingniu_prod.tab_mileage_assessment_vehicle` | 目标、车辆、完成率 | +| 里程日报 | `lingniu_prod.tab_mileage_daily_report` | 每日归档快照 | +| 电费 | `bi_ele_charge_record` | XLSX 导入后的充电记录 | +| ETC | `etc_toll_record`、`energy_etc_bill` | 通行明细、应收和已收 | +| 调度 | `tab_scheduling_notifications` | 调度干预、执行状态和历史 | +| 用户反馈 | `bi_user_feedback` | 反馈、截图地址、回复和状态 | + +### 7.3 氢能 BI 主要数据表 + +| 表 | 用途 | +| --- | --- | +| `hydrogen_fuel_ledger` | 加氢主流水,统计加氢量、成本、对客金额、车辆、客户、核对状态和数据来源 | +| `hydrogen_station` | 历史加氢站主数据 | +| `new_hydrogen_site` | 当前业务站点主数据及省市区等属性 | +| `hydrogen_station_payment` | 加氢站付款 / 结算记录 | +| `new_hydrogen_site_balance_record` | 站点预充值余额记录 | +| `tab_outside_hydrogen_site` | 外部站点与内部站点、坐标的映射,用于热力图 | +| `common_district` | 行政区划名称映射 | + +氢能 V2 API 统一提供总览、按日树、下钻等视图。旧 `/hydrogen/*` 接口仍保留用于兼容和回滚,但当前氢能页面入口只装配 `hydrogen-bi-v2/PrototypeBoard.tsx`。 + +### 7.4 数据口径注意事项 + +- 氢能“车辆归属”和“成本承担方”是两个独立维度,不得互相替代。 +- 氢能成本承担方按业务字段归纳为“我司承担、客户承担、其他”;利润口径是客户承担订单的“对客总价 - 等量订单成本总价”。 +- 电能导入按 `order_no` 去重,并根据车辆信息匹配内部 / 外部 / 未知车辆。 +- ETC 金额、应收和已收直接读取台账,不做推算;没有数据时前端展示空状态。 +- 里程按自然日和上海时区处理;OneOS API 支持单日和区间查询,并按协议优先级归一化来源。 +- 客户名称会根据数据权限在服务端进行脱敏。 + +## 8. 当前功能清单 + +### 8.1 资产管理 BI + +| 功能域 | 当前能力 | +| --- | --- | +| 资产总览 | 总资产、运营、库存、待交付、周交车 / 退车 / 换车 | +| 车型分析 | 按车辆类型、车型、批次逐级统计和展开 | +| 部门分析 | 按部门 / 经理统计、展开车辆明细 | +| 区域分析 | 按大区、省市、客户筛选与统计 | +| 客户分析 | 客户多选、品牌、部门、经理、区域筛选 | +| 库存分析 | 按区域 / 车型切换,支持多级展开和筛选 | +| 资产流转 | 自定义日期范围,交车 / 退车 / 换车趋势与明细下钻 | +| 车辆明细 | 车牌、车型、批次、客户、状态、位置等筛选和弹窗 | +| 导出 | 资产相关列表和明细 Excel 导出 | +| 自动刷新 | 主页面数据每 60 秒刷新 | + +### 8.2 里程管理 BI + +| 子页面 | 当前能力 | +| --- | --- | +| 实时监控 | 当日 / 指定日 / 区间里程,来源协议优先级、部门、客户、项目、主体、状态、区域、品牌、里程区间等筛选 | +| 实时监控 | 当日 / 累计 / 统计时间排序,异常和在线状态识别,车辆详情 | +| 统计报表 | 考核目标、目标车辆、累计完成率、当年完成率、日均要求、趋势下钻 | +| 每日汇报 | 运营 / 库存车辆、当日里程、环比、车型与地区分组、近 7 日趋势、历史快照 | +| 导出 | 监控区间和车辆汇总 Excel 导出 | +| 缓存 | 服务启动立即刷新,之后每分钟刷新实时监控缓存 | +| 自动归档 | 上海时间每天 06:30 归档上一自然日日报,可通过环境变量关闭 | + +### 8.3 智能调度 + +| 功能 | 当前能力 | +| --- | --- | +| 建议生成 | 根据考核里程、剩余天数、车辆状态和车型生成高低里程调度建议 | +| 筛选 | 按建议类型、部门、车型等条件筛选和搜索 | +| 详情 | 查看当前车辆、候选车辆及差距 | +| 操作 | 单条 / 批量登记调度干预 | +| 历史 | 通知 / 干预记录查询、状态更新、取消或完成 | +| 导出 | 建议列表 CSV 导出 | + +### 8.4 车辆热力图 + +- 按日期范围、车牌 / VIN、考核批次筛选; +- 定位活跃度 / 车辆覆盖度切换; +- 网格聚合、全国概览、区域下钻和附近车辆; +- 地图和详情面板可独立展开,支持全屏; +- PostgreSQL 连接配置为只读事务默认值。 + +### 8.5 加氢热力图 + +- 按日期、站点搜索、承担维度筛选; +- 加氢量、加氢频次、车辆覆盖三种热力指标; +- 加氢站排名、区域下钻、附近站点和 GPS 覆盖提示; +- 仅对有有效坐标的数据进行地图聚合; +- 受能源角色控制。 + +### 8.6 氢能经营 BI(当前 V2 页面) + +| 页面 / 维度 | 当前能力 | +| --- | --- | +| 全局总览 | 年份、核对状态、车辆归属筛选;累计加氢量、累计成本、利润、本月、本日 KPI | +| 趋势 | 月度加氢量、月度收支、站点 Top5、区域省 / 市占比 | +| 汇总 | 加氢站汇总、客户账单汇总、列表折叠、排序和筛选 | +| KPI 下钻 | 支持先站点后客户或先客户后站点,再到车辆 / 流水 | +| 图表下钻 | 月份、站点、区域、客户等上下文穿透 | +| 账单下钻 | 客户 → 日期 → 车辆流水;站点 → 日期 → 客户 / 流水 | +| 按日页面 | 日期范围、车辆归属、核对状态;日期 → 站点 → 客户 → 车辆 / 数据源多层展开 | +| 单站页面 | 站点日期筛选、日汇总、趋势、流水和导出 | +| 导出 | KPI 穿透、客户账单、站点账单、每日明细 Excel | +| 接口 | `/api/energy/h2/v2/meta`、`overview`、`daily`、`daily-tree`、`drill` | + +说明:原型源码中仍有演示常量和兼容组件;真实运行数据应以 `prototype-adapter.ts`、`prototype-real-daily.tsx`、`prototype-real-drills.tsx` 和 V2 API 返回为准。修改页面时必须同时检查 Web 与移动端,不能只以测试通过代替原型截图验收。 + +### 8.7 电能经营 BI + +| 页面 / 能力 | 当前实现 | +| --- | --- | +| 按日 | 日充电量、费用、订单、内部 / 外部车辆和趋势 | +| 总览 | 汇总 KPI、月份趋势、车辆归属统计 | +| 数据导入 | 隐藏入口上传 `.xlsx`,按订单号去重、批次管理、记录搜索和归属汇总 | +| 数据表 | `bi_ele_charge_record`,接口首次调用时自动确保建表 | + +### 8.8 ETC 看板 + +- 通行明细笔数; +- 涉及车辆去重数; +- 通行费金额; +- ETC 账单数、应收和已收; +- 最新通行时间; +- 无台账时展示“暂无数据”,不生成模拟数据。 + +### 8.9 用户反馈闭环 + +- 普通用户提交新维度、Bug、体验或其他反馈; +- 支持最多 6 张截图,单张最大 5 MB,上传至 OSS; +- 用户查看自己的反馈历史; +- 管理员按状态查看、回复和更新为待处理 / 处理中 / 已完成 / 已忽略; +- 反馈表由接口首次调用时自动创建并兼容补列。 + +## 9. API 路由概览 + +| 路由前缀 | 用途 | +| --- | --- | +| `/api/auth` | jumpToken 换 JWT、查看当前 JWT 用户 | +| `/api/vehicles` | 资产总览、车型 / 部门 / 区域 / 客户 / 库存、流转、车辆明细 | +| `/api/mileage` | 实时监控、目标、趋势、车辆近期里程、日报及历史 | +| `/api/scheduling` | 调度建议、通知和执行记录 | +| `/api/energy` | 氢能 V2 / 兼容接口、电能经营、ETC | +| `/api/ele` | 电费 XLSX 导入、列表、批次、聚合 | +| `/api/vehicle-heatmap` | 车辆位置热力图配置、元数据、点位和附近车辆 | +| `/api/hydrogen-heatmap` | 加氢热力图配置、元数据、点位和附近站点 | +| `/api/feedback` | 反馈提交、截图上传、我的反馈、管理列表和更新 | + +## 10. 后台任务与自动建表 + +### 10.1 服务启动动作 + +`src/server/bootstrap.ts` 在正式服务进程启动时执行: + +1. 确保 `tab_scheduling_notifications` 存在; +2. 立即刷新里程监控缓存; +3. 每 60 秒刷新里程监控缓存; +4. 启动里程日报 06:30 自动归档调度器。 + +### 10.2 按需自动建表 + +以下接口会在首次使用时执行 `CREATE TABLE IF NOT EXISTS`: + +- 电费:`bi_ele_charge_record`; +- 用户反馈:`bi_user_feedback`; +- 里程日报:`lingniu_prod.tab_mileage_daily_report`; +- 智能调度:`tab_scheduling_notifications`(服务启动时)。 + +生产数据库账号若严格只读,这些功能会启动或调用失败。交接时应明确“读数据账号”和“应用写表账号”的权限边界。 + +## 11. 开发、测试和发布流程 + +### 11.1 常用命令 + +```bash +# 安装锁定依赖 +npm ci + +# 前后端开发模式 +npm run dev + +# 仅后端 / 仅前端 +npm run dev:server +npm run dev:client + +# 质量检查 +npm run lint +npm test +npm run build + +# 生产式本地启动(需先 build) +npm run start +``` + +### 11.2 发版步骤 + +1. 确认工作区只包含本次变更,排除 `.DS_Store`、临时脚本和本地数据文件。 +2. 执行 `npm run lint && npm test && npm run build`。 +3. 按语义版本更新 `package.json` 和 `package-lock.json`。 +4. 提交并推送到目标分支。 +5. Woodpecker 根据分支和版本生成镜像标签并推送 Harbor。 +6. 在 Portainer / Compose 中更新镜像版本,保留原镜像标签用于回滚。 +7. 验证健康检查、登录跳转、关键 API、Web 页面和移动端页面。 + +版本只在 Git 中更新不代表已部署;必须分别确认: + +- 代码已推送; +- CI 已通过; +- 镜像已推送; +- 部署已更新; +- 页面和数据已验收。 + +## 12. 日志与排障入口 + +| 现象 | 优先检查 | +| --- | --- | +| 无法从业务系统登录 | 浏览器 URL 是否有 `jumpToken`;`/api/auth/exchange` 响应;`EXTERNAL_API_BASE`;后端认证日志 | +| 页面能进但 API 401 | 前后端免登录是否同时开启;`bi_jwt` 是否存在;JWT_SECRET 是否一致 | +| 页面 403 | 业务系统角色、JWT 中 `roles`、模块白名单,不要只看 `permissionLevel` | +| 健康检查正常但页面无数据 | `/api/health` 不检查数据库;继续检查具体 API、数据库连接和 SQL 权限 | +| 里程无数据 | OneOS API 地址 / Key、网络、traceId、协议兼容降级日志、主库车辆关联信息 | +| 热力图无底图 | 高德 Key 和安全码、域名白名单、浏览器控制台 | +| 车辆热力图无点位 | PostgreSQL 连接、只读权限、日期范围、`is_heatmap_eligible` | +| 氢能数据慢 | V2 API 查询耗时、筛选范围、数据库索引、是否误走兼容接口 | +| 反馈图片失败 | OSS 配置、Bucket 权限、文件类型和 5 MB 限制 | +| 日报未归档 | `MILEAGE_REPORT_AUTO_ARCHIVE`、容器时区、06:30 日志、日报表写权限 | + +## 13. 已知风险与优先整改项 + +### P0:凭据管理 + +1. 当前仓库的部署配置和部分数据库连接代码存在硬编码凭据或默认口令。交接后应立即: + - 将数据库、JWT、Harbor、OSS、API Key 全部迁移到 CI Secret / Portainer Secret / 环境变量; + - 删除代码和配置中的真实 fallback; + - 对已经进入 Git 历史的凭据执行轮换; + - 不要只删除当前文件内容而忽略历史提交。 +2. `Dockerfile` 和认证代码存在可预测的 JWT 默认密钥。生产必须显式注入随机 `JWT_SECRET`,并在缺失时让应用拒绝启动。 + +### P1:认证与权限 + +1. 前端当前用公开的 `/api/health` 判断缓存 JWT 是否有效,因此该请求并未真正校验 Token;过期 Token 会在第一次访问受保护 API 时才被清理。应改为调用 `/api/auth/me`。 +2. `jumpToken` 通过查询参数传递,可能进入代理访问日志;业务条件允许时应改为 POST body,并限制日志记录。 +3. `cors()` 当前未限制来源;生产应配置允许域名白名单。 +4. `full` 数据角色与模块角色不是同一套白名单,容易产生“能看全量数据但进不了模块”的误解。变更角色策略前应由产品 / 管理员确认。 +5. 隐藏页面不是授权控制。充电导入接口目前仅依赖“已登录”,若属于管理能力,应补独立角色和后端守卫。 + +### P1:数据与运行稳定性 + +1. 主库、跨 Schema 查询和专用数据库连接并存,部署账号权限和 Schema 默认值需形成正式清单。 +2. `src/server/mileage-db.ts` 是当前未被引用的历史连接文件,`docker-compose.yml` 仍保留相应变量,容易误导排障;确认无外部依赖后应删除或重新接入。 +3. 应用启动和部分接口会自动建表;数据库权限收紧前需先迁移为正式数据库变更脚本。 +4. 氢能兼容接口和 V2 接口同时存在,新增功能应明确修改当前 V2 路径,避免只修旧接口。 +5. 氢能原型目录仍包含演示常量;新增展示必须确认数据来自真实 API,禁止把演示数据带入经营口径。 +6. 车辆和加氢热力图的默认日期目前为代码常量,长期运行应改为根据数据水位或当前日期计算。 + +### P2:工程治理 + +1. 仓库缺少统一根 README,本交接文档可作为后续 README 的基础。 +2. 本地 `.DS_Store` 容易进入工作区,建议补充全局 / 项目忽略规则。 +3. 目前使用 Path + Hash 自研路由;新增页面时必须同时验证直达、刷新、前进后退和移动端底栏状态。 +4. 氢能页面属于严格原型复刻范围,CSS / DOM 调整必须做桌面与移动端截图对比验收。 + +## 14. 交接资料与权限清单 + +以下内容不应写入 Git,需要由原负责人通过安全渠道单独移交: + +- Gitea 项目成员权限及分支保护规则; +- Woodpecker 项目、流水线和 Secret 管理权限; +- Harbor 项目及镜像拉取 / 推送账号; +- Portainer / ECS / Docker 服务管理权限; +- 主业务、氢能、里程和位置数据库的只读 / 读写账号; +- OneOS 里程 API 地址、API Key、调用方白名单和联系人; +- 羚牛业务系统认证接口联系人和 jumpToken 协议; +- 高德地图 Key、安全码及域名白名单; +- OSS Bucket、RAM 用户和目录权限; +- 生产域名、反向代理、证书和 DNS 管理权限; +- 数据口径负责人:资产、里程、调度、氢能、电能、ETC 各一名。 + +## 15. 接手验收清单 + +### 15.1 代码与环境 + +- [ ] 能拉取 `main` 并确认目标版本; +- [ ] Node.js 22、`npm ci`、lint、test、build 均通过; +- [ ] 已获得不含明文传播的本地 / 测试环境变量; +- [ ] 本地前后端和免登录调试正常; +- [ ] `.env`、数据库导出、截图和临时文件不会进入 Git。 + +### 15.2 认证与权限 + +- [ ] 从业务系统 jumpToken 跳转登录成功; +- [ ] 普通、部门、全量三类数据权限分别验收; +- [ ] 能源、智能调度、反馈管理员角色分别验收; +- [ ] 无权限用户前端不可见且后端返回 403; +- [ ] Token 过期后能正确退出并重新登录。 + +### 15.3 数据与功能 + +- [ ] 资产、里程、调度、氢能、电能、ETC 的主要 API 都能访问真实数据; +- [ ] BI 汇总值与最小粒度明细守恒; +- [ ] 氢能成本承担方、对客金额、成本金额和利润口径已由业务负责人确认; +- [ ] 里程 OneOS API 的单日、区间和来源协议正常; +- [ ] 车辆 / 加氢热力图可加载地图、点位和详情; +- [ ] Excel / CSV 导入导出可用; +- [ ] 用户反馈和截图上传可用; +- [ ] 06:30 日报归档在测试环境完成一次验证。 + +### 15.4 发布与回滚 + +- [ ] Woodpecker 流水线通过; +- [ ] Harbor 中存在对应版本镜像; +- [ ] Portainer / Compose 使用目标镜像标签和正确 Secret; +- [ ] 部署后验证健康检查、登录、API、Web 和移动端; +- [ ] 记录上一稳定镜像标签、数据库变更和回滚步骤。 + +## 16. 维护原则 + +1. **先确认真实数据口径,再改页面**:经营指标必须能从汇总下钻到真实流水。 +2. **前端隐藏不代替后端鉴权**:任何管理或敏感能力都要有 API 守卫。 +3. **配置与凭据分离**:代码只保留变量名和安全默认行为,不保留真实密码。 +4. **原型页面以截图验收**:氢能模块必须对照原型验证布局、样式、交互、下钻层级和移动端。 +5. **变更必须可回滚**:发版保留旧镜像,数据库变更先备份、再迁移、再核对。 +6. **区分可达与可用**:健康检查正常不代表数据库、外部 API 和经营数据正常。