# 智慧停车项目问题分析与修复方案 > 分析日期:2026-09-07 > 分析范围:`lc_garage` 实际源码、配置、前端构建、项目文档与 Git 历史 > 结论性质:代码与配置静态审查 + 可执行构建验证,不替代真实闸机、打印机、摄像头和支付终端的现场验收。 ## 1. 结论摘要 项目已经完成从旧的 GIN-VUE-ADMIN 服务端形态向 Wails 单进程桌面应用的主要迁移,并具备停车场配置、停车会话、数字票、支付流水、月卡、交接班、报表、打印和异常处置等基础模块。当前代码也已经出现 `internal/modules` 领域模块化结构,说明迁移正在持续进行。 距离可稳定交付仍有三类问题: 1. **生产安全边界不够明确**:上传、Swagger、监控和中央缴费机入口的公开性需要逐项确认;默认账号、敏感配置和调试能力仍应纳入发布安全策略。 2. **设备和资金业务闭环不足**:真实支付、道闸反馈、打印失败补偿、摄像头识别、LED 余位屏、备份恢复和对账仍有明显缺口。 3. **文档和工程入口存在漂移**:根目录 `AGENTS.md`、旧版 `PROJECT.md`、`lc_garage/README.md`、`doc/PROJECT.md` 和 `doc/功能缺失.md` 的架构、数据库和完成状态描述不完全一致。 ## 2. 已验证现状 ### 2.1 结构与入口 - 实际应用目录为 `lc_garage/`,根目录是项目文档工作区。 - Wails 入口为 `lc_garage/main.go`,通过 `//go:embed all:frontend/dist` 嵌入前端,并将 `/api/*` 反向代理到 Gin `:8888`。 - 后端实际代码位于 `lc_garage/internal/`,不存在文档中曾描述的 `lc_garage/server/` 主目录。 - 前端同时存在 `frontend/` 和 `web/` 两套目录;Wails 配置明确使用 `frontend`,`web` 更像历史遗留或兼容目录。 - 新模块已实际存在:`parking-session`、`digital-ticket`、`payment`、`monthly`、`shift`、`report`、`printer`、`incident`、`central-payment`、`deviceprovisioning` 等。 ### 2.2 验证结果 - `frontend`: `npm run build` 成功,Vite 生成生产包;构建有 Sass 弃用提示及两个超过 500 KB 的 chunk 警告。 - `go test ./...`: 当前环境失败在 Go 构建缓存目录 `C:\Users\longc\AppData\Local\go-build` 的访问权限,输出为 `Access is denied`,不能视为代码测试失败。 - 项目进度文档声称的模块级测试命令应使用项目可写的 `GOCACHE`,并在 CI 中固定执行,避免环境权限造成误判。 ## 3. 问题清单 ### P0:上线前必须处理 #### P0-1 公开路由和敏感数据访问边界需要收紧 证据:`internal/initialize/router.go:70-92`。 - `Router.StaticFS(global.GVA_CONFIG.Local.StorePath, ...)` 直接提供本地上传目录;车牌抓拍、头像等文件可通过可预测路径访问。 - Swagger 在 `:swagger/*any` 直接注册,未看到生产环境开关。 - `dashboardRouter.InitDashboardRouter(PublicGroup)` 将监控接口放在公开组;CPU、内存等运行信息不应默认匿名暴露。 - `PublicGroup.POST("/device-images/upload", deviceimage.Upload)` 公开注册,上传接口应明确鉴权、文件类型、大小、路径和访问权限。 - 中央缴费机公开接口是设备对接需要,但必须只允许设备令牌、来源网络或签名请求,不能按普通公开 API 处理。 修复方案: 1. 将上传改为受 JWT/Casbin 保护的下载接口,或使用短时签名 URL;禁止目录遍历和原始文件名落盘。 2. 增加 `system.expose-swagger`、`system.expose-monitor` 等显式配置,生产默认关闭。 3. 设备图片上传和中央缴费机接口分别使用设备认证中间件;记录设备 ID、请求摘要和失败原因。 4. 为公开路由增加路由安全测试:匿名访问必须只允许健康检查和明确的设备协议接口。 #### P0-2 默认凭据和密钥管理不适合生产 证据:`internal/initialize/seed.go` 包含固定 bcrypt 密码和 `README.md:32-35` 公开写出 `admin/123456`;`config.yaml` 还保留对象存储示例密钥字段。 修复方案: - 首次启动进入初始化向导,强制设置管理员密码;发布包不再预置可直接登录的通用密码。 - 将 JWT secret、设备 token、摄像头密码和第三方支付密钥移出仓库,使用系统凭据存储或受保护配置文件。 - 对历史数据库提供管理员密码轮换迁移;启动时检测默认密码并阻止生产模式继续运行。 #### P0-3 SQLite 并发写、备份和恢复策略缺失 证据:`internal/initialize/gorm_sqlite.go:47-53` 只设置连接池,没有设置 WAL、`busy_timeout` 或备份策略;`config.yaml:185-199` 允许 `max-open-conns: 100`。 风险:设备事件、支付、操作日志和定时任务并发写入时可能出现 `database is locked`;进程或磁盘损坏会导致本地运营数据丢失。 修复方案: 1. SQLite 初始化后执行 `PRAGMA journal_mode=WAL`、`PRAGMA busy_timeout=5000`、合理的 `synchronous` 设置,并将写并发控制在可验证范围。 2. 增加在线一致性备份或安全快照,备份文件校验、保留周期和恢复演练。 3. 对支付、停车会话、月卡和交接班增加恢复后校验任务,发现跨表不一致时生成异常事件。 4. 增加并发写压力测试和断电恢复测试,测试不依赖用户目录下不可写的 Go 缓存。 #### P0-4 服务启动失败处理不可靠 证据:`internal/core/server.go:34-40` 调用 `s.ListenAndServe().Error()`;`internal/initialize/gorm.go:77-84` 在迁移失败时使用 `os.Exit(0)`。 风险:监听失败可能触发 nil error 解引用;数据库迁移失败却以成功码退出,Windows 启动器和发布脚本无法正确识别失败。 修复方案: - 保存 `err := s.ListenAndServe()`,对 `http.ErrServerClosed` 单独处理,其余错误记录并以失败状态退出或通知 Wails 主进程。 - 将 `os.Exit(0)` 改为错误返回/受控退出码 `1`,并在启动错误日志中写明迁移步骤和恢复建议。 - 启动前执行端口、数据库路径和配置值校验,失败时不要启动前端窗口。 #### P0-5 真实资金交易尚未形成可审计闭环 证据:`doc/功能缺失.md` 和 `internal/modules/payment` 的现状说明;当前 `payment_record` 主要记录本地业务结果,POS、扫码和中央缴费机仍需真实设备或网关确认。 修复方案: - 建立支付订单状态机:待支付、处理中、成功、失败、不确定、已退款、已撤销。 - 为支付记录增加渠道订单号、幂等键、回调时间、原始渠道状态和退款/冲正关联。 - 外部支付只能在可信回调、主动查询或设备签名结果确认后标记成功;重复回调必须幂等。 - 交接班和收入报表按支付入口、支付方式、操作员、班次、退款和差异统一对账。 ### P1:应在近期完成 #### P1-1 道闸和读卡器状态模型仍然混杂 现状记录见 `doc/功能缺失.md:117-139`。读卡器、闸机控制器、连接管理器和运行时状态存在多套来源;串口/TCP 的 ACK、分片、超时、重连和落杆反馈还需要现场验证。 修复方案:拆分设备类型与通道拓扑,统一 `DeviceRuntime` 状态源;所有开闸/关闸命令落 `device_command_log`,校验 ACK、超时和重试,增加地感、防砸、落杆确认和人工兜底测试。 #### P1-2 模拟道闸必须具备不可误用的运行保护 `config.yaml:210` 当前为 `gate-simulator: false`,默认值正确;但仍应在启动时显示运行模式,并在生产构建或生产配置中拒绝开启模拟模式。模拟模式下的“开闸成功”不能被当作真实硬件确认。 修复方案:增加 `environment=production` 与 `gate-simulator` 互斥校验;模拟模式所有指令标记 `simulated=true`,前端和审计记录明确显示。 #### P1-3 打印失败没有持久化补偿任务 现状:票机打印仍以同步硬件调用为主,失败重试、重打、作废和异常处置尚未形成完整任务模型。 修复方案:新增打印任务表和状态机,先创建任务再执行硬件动作;记录短写、串口错误、设备离线和重试次数,允许受权限控制的重打/作废,并与数字票和停车会话建立补偿规则。 #### P1-4 月卡、交接班和收入报表的财务口径仍不完整 现状:月卡退款缺少完整退款流水和审批;自然月/季/年、并发办理、人工白名单保护需要继续完善;交接班和报表还需要覆盖所有支付方式、退款和差异。 修复方案: - 月卡办理、续费、退款、白名单变更和支付流水使用同一事务及幂等键。 - 用日历月/季度/年度计算有效期,明确过期、冻结、转车和退款规则。 - 交接班增加唯一 active 约束、收款前当班校验、管理者复核和锁定机制。 - 报表提供明细追溯、导出、打印和支付记录对账。 #### P1-5 数字票过期任务和跨表对账不足 `doc/功能缺失.md` 指出 `ExpireAt` 自动执行和状态不一致检测仍不完整。应明确待支付票、已支付未离场票的过期规则,并由定时任务执行状态迁移和异常告警。 ### P2:产品能力和工程质量提升 - 摄像头 RTSP/SDK、OCR 置信度、防重复识别和通道绑定。 - LED 余位屏协议、推送、离线重试和恢复同步。 - 远程设备诊断、设备告警中心和现场运维审计。 - 历史会话、日志和抓拍图片归档清理;上传文件容量配额。 - 短信/邮件验证从模拟实现升级为真实供应商适配,并增加频率限制。 - 通道事件从内存队列升级为持久化队列,支持重启恢复。 - 前端 bundle 拆分,处理 ECharts 约 1 MB chunk;清理 Sass `@import`/legacy API 弃用警告。 - 增加 API、JWT、Casbin、操作日志脱敏、登录登出、越权和配置校验测试。 ## 4. 文档与结构问题 ### 4.1 架构描述互相冲突 - 根目录 `PROJECT.md` 仍描述 `server/` 独立后端、MySQL 和旧 Electron 结构,与实际 Wails + SQLite 代码不符。 - `AGENTS.md`、`lc_garage/README.md` 和 `doc/PROJECT.md` 对结构的描述不一致:前者较旧,后两者基本反映当前布局。 - `doc/功能缺失.md` 中部分安全问题已在提交 `8cca42f` 修复,例如注册角色层级校验、操作日志脱敏、模拟闸机告警,但文档仍把它们写成当前漏洞。 - `doc/项目进度.md` 更新日期早于最近代码提交,完成状态与后续新增的中央缴费机、设备接入模块没有完全同步。 修复方案: 1. 以 `lc_garage/doc/PROJECT.md` 作为唯一项目说明,以 `lc_garage/README.md` 作为快速开始文档。 2. 将根目录 `PROJECT.md` 标记为历史文档或删除,避免新成员误用 MySQL/server 启动方式。 3. 给 `doc/功能缺失.md` 增加“已修复/仍存在”分栏、代码版本和验证命令;删除已完成项的当前时态描述。 4. 每次领域功能合并时同步更新 `项目进度.md`、流程文档和测试记录,并在 CI 检查文档中的路径是否存在。 ### 4.2 双前端目录需要明确归属 Wails 使用 `frontend`,但 `web` 仍保留完整 Vue 源码和 Vite 配置。双目录会导致修复只落在一处、构建结果与开发结果不一致。 修复方案:短期在 `README` 和 `wails.json` 中明确 `frontend` 为唯一构建源;中期归档或删除 `web`,若必须兼容则用脚本从唯一源生成,不允许手工双写。 ## 5. 前端已确认缺陷 ### 5.1 报表异常处理引用未定义变量 `frontend/src/view/report/enter.vue:222-224` 的异常处理调用 `t.value.getListFail`,文件中没有对应的 `t` 定义。接口失败时会再次触发 `ReferenceError`,原始错误信息被覆盖。 修复方案:改为已有的 `$t`/语言包访问方式,或定义统一的 `useI18n` 实例;补充请求失败分支测试。 ### 5.2 登出失败时本地凭据清理策略不统一 `frontend/src/pinia/modules/user.js:91-98` 只有黑名单接口返回成功才清理 token;而 `frontend/src/utils/request.js:147-162` 的 401 处理依赖用户确认。 修复方案:登出无论服务端结果如何都清理本地 token;401 统一立即清理并跳转登录,弹窗只用于提示,不应让失效凭据继续留存。 ## 6. 推荐实施顺序 | 顺序 | 优先级 | 工作包 | 完成标准 | | ---: | :---: | --- | --- | | 1 | P0 | 路由、上传、Swagger、监控和设备接口安全边界 | 匿名访问测试通过;上传不可猜测读取;生产 Swagger/监控默认关闭 | | 2 | P0 | 默认凭据、密钥和配置校验 | 首次启动强制改密;仓库不含可用生产密钥;非法端口/路径拒绝启动 | | 3 | P0 | SQLite WAL、锁等待、备份恢复 | 并发写压测通过;备份可校验;恢复演练有记录 | | 4 | P0 | 启动失败和进程退出语义 | 迁移/监听失败返回非零并写清晰诊断,不出现 nil error panic | | 5 | P0 | 支付订单、回调幂等和财务对账 | 成功/失败/不确定/退款/冲正可追溯,重复通知不重复收费 | | 6 | P1 | 道闸、读卡器、打印机现场闭环 | ACK、超时、重试、离线、落杆和打印补偿均有集成测试 | | 7 | P1 | 月卡、交接班、报表和数字票过期 | 事务、并发、退款、班次和跨表对账规则明确并覆盖测试 | | 8 | P1 | 摄像头、设备告警和 LED | 设备状态、事件、恢复和余位推送可在现场验收 | | 9 | P2 | 文档收敛、双前端归档和前端性能 | 唯一开发入口,文档路径与状态可由 CI 校验 | ## 7. 验收与持续检查 发布前至少执行: ```powershell cd D:\lq\Smart Parking\lc_garage $env:GOCACHE = "D:\lq\Smart Parking\lc_garage\build\gocache-ci" go test ./... -count=1 cd frontend npm run build ``` 另外需要单独保留以下验收记录:真实闸机开/关及断网、真实打印机短写和重打、摄像头重复识别、POS/中央缴费机回调幂等、SQLite 备份恢复、管理员和操作员越权测试。只有代码、权限、自动化测试和现场流程同时通过,相关功能才应标记为“已完成”。