charging-cabinet/docs/tech/小程序用户端.md

199 lines
12 KiB
Markdown
Raw Normal View History

docs: 文档分类整理 —— AGENTS.md 只留判据与链接,详细篇按用途归入 docs/ 子目录 ## 为什么要做 `AGENTS.md` 曾达 **90,370 B**,而工作区指令预算是 **65,536 B** —— 系统按**保留头部**截断, 于是**尾部约 25 KB 永远不会被加载**:组织架构、数据模型、TCP 协议、数据单位规范、 微信小程序用户端**全部处于"写了但读不到"的状态**。手册实际上部分失效。 ## 一、AGENTS.md 瘦身:90,370 → 60,227 B(余量 5,309 B,尾部不再被截断) 三个**纯参考型大段**整段搬迁到 `docs/tech/`(**内容逐字保留,未删改**), 原位置换成「判据 + 链接」: | 原 AGENTS.md 章节 | 大小 | 现位置 | |---|---|---| | `## 部署与维护` | 17,611 B | `docs/tech/部署手册.md` | | `## 数据模型` | 12,100 B | `docs/tech/数据模型.md` | | `## 微信小程序用户端` | 10,262 B | `docs/tech/小程序用户端.md` | 替换后的章节**只留改动前必须先知道的硬约束**(例如:产物名与测试环境落地名不一致、 ETXTBSY 的 `.new`→`stop`→`mv`→`start` 流程、`stream{}` 不可重加、发布顺序 device 先 api 后、 建表顺序即依赖顺序且写错报 MySQL 1824、时间列必须 DATETIME、`cabinets.status` 是配置态不表示在线……), 其余指向详细篇。**判据留在常驻加载的 AGENTS.md,逐项参考移出**。 ## 二、docs/ 分类(原 21 个文件平铺 → 五个用途目录) ``` docs/ ├── README.md 新增:文档地图(分类/权威性/旧名→现名映射/维护约定) ├── protocol/ 设备协议(冻结,对硬件交付)★唯一权威 │ ├── 柜控板固件对接文档.md │ └── 1TN协议标准_*.md / *.pdf ├── tech/ 平台技术文档(开发/运维必读) │ ├── API.md · 数据模型.md · 部署手册.md · 小程序用户端.md ├── contract/ 合同·规格·验收标准(商务依据,不描述实现) ├── compound-notes/ 单点经验笔记(原有) └── archive/ ⛔ 历史留痕(只读,不代表现状,不可作依据) ├── 开发文档.md(早于现行实现) └── 审查报告/深度分析报告-2026-07-06 ``` - 19 个文件用 `git mv` 迁移(保留历史),3 个未跟踪文件用普通移动; - **内容零改动**(唯一例外是引用替换),已核验 `docs/tech/API.md` 的 `git diff` 为空。 ## 三、全仓引用同步:40 处 / 10 个文件 路径不只出现在文档里,还散落在**源码注释**(`db/migrate.rs`、`routes/cabinets.rs`、 `workers/report_worker.rs`、`tcp/connection.rs`、`h5-uniapp/utils/format.ts`)、 `test/tcp_e2e_smoke.py`、`tasks/001-*.md`、`README.md`、`AGENTS.md` 中,全部同步。 **并已实测校验命令能失败**:往 `docs/tech/API.md` 植入 `<!-- probe: docs/API.md -->` → 命中;删除 → 无输出。 > ⚠️ 过程中踩了一个坑并已修:这些 `.md` 多为 **CRLF**,我第一次用 `\n` 正则删除时 > **没匹配上 `\r\n`**,以为删干净了其实残留了一行 —— 靠 `git diff` 非空才发现。 > 已把「CRLF 必须按 `\r?\n` 处理」写进 `docs/README.md` 的维护约定。 ## 四、顺带查实的失效引用(归档保留原文,不改写历史) - `docs/tcp-protocol.md`:仅出现在 2026-07-06 的两份历史报告里(当时的事实); - `docs/柜控板-平台TCP接口文档.md`:仅出现在协议文档 **v1.1 变更记录**里 (记录"已删除该内部重复文档"这件事),**不是活链接**,无需修复。 两者已在 `docs/README.md` 的「旧名 → 现名映射」表中给出对应关系。
2026-09-20 04:42:51 +08:00
# 微信小程序用户端(AGENTS.md 的详细参考篇)
> 本文件由 `AGENTS.md` 的「微信小程序用户端」整段搬迁而来(**内容逐字保留,未删改**)。
> 页面清单、构建/上传流程、状态位与 RSSI 的分层展示口径都在这里。
> 门禁命令(`vue-tsc` 类型检查 + `build:mp-weixin`)与「产物不上传服务器」已留在 `AGENTS.md`。
---
## 微信小程序用户端
### 小程序配置
| 参数 | 值 |
|------|-----|
| AppID | `wx226061c550c52e85` |
| AppSecret | `f11dfee9dc73265b75bf54277ebb1047` |
| 账号 | `13951516272@163.com` |
| 消息加解密方式 | 明文模式 |
| 数据格式 | XML |
| 服务器地址(URL) | `https://app.anzhizhichong.com/api/wechat/callback` |
| Token(令牌) | `7GW16XdnFyak0mE32rc8ZPij` |
| EncodingAESKey | `kRijggSqeCFWi3JhfGyK0nzc6VmdygWWkoqyKPl0bYu` |
chore: 清理过时与误提交产物;取消 archive/(过时就删,历史交给 git) ## 起因 用户问"历史留痕?看看有没有过时的和无用的东西可以删除" —— **不该把"归档"当免检区**。逐项查证后:确认了 3 类该删的、1 类归错类的、1 个不能删的。 ## 一、删除:被"顺手 git add"误带进无关提交的产物 用 `git log --diff-filter=A` 追来历,发现它们**根本不是有意提交的**: | 文件 | 来历 | 判据 | |---|---|---| | `换电柜用锂电池充电器1TN标准通信协议 - RS485 V1.0(1).pdf` | `652bde4`(nginx 路由修复) | 与 `docs/hardware/1TN协议标准_苏州翌工电源_V1.0.pdf` **MD5 完全相同**(`B723A1FC…`)—— 纯重复 | | `package.json` + `package-lock.json` | `652bde4`(同上) | 唯一依赖 `html-docx-js`,**全仓无任何脚本引用**(当次把合同 md 转 docx 的一次性工具残留) | | `9b0d3b8a…jpg` / `d6e6add1…png` / `ea4410ba…jpg` | `8bc7812`("23 个函数拆分")/ `999885c`(协议对齐) | **零引用**,且混在与图片毫无关系的重构提交里 —— 误提交的截图 | ## 二、归错类(**不是过时,所以不删**):`开发文档.md` → `hardware/硬件与系统设计文档.md` 原本被塞进 `archive/`,但通读目录后确认它含**硬件设计内容**,这些在 `AGENTS.md`/`docs/tech/` 里**没有**: 硬件架构、仓控/柜控主板设计、指示灯状态机、充电控制逻辑(握手/双模式/动态调整/无协议模式)、 BMS 协议适配、安全防护联动、性能指标、第三方服务配置。 ⇒ 它是**归错类而非过时**:**硬件部分仍是权威参考**,只有第 7 章(软件平台)被现行文档取代。 已在 `docs/README.md` 写明"两者冲突时软件口径以 `AGENTS.md` 为准"。 ## 三、删除:两份 2026-07-06 报告(**问题已全部解决**) 逐条核对了它们"发现的问题",**无一条仍然成立**: | 报告 | 当时的问题 | 现状 | |---|---|---| | 深度分析报告 | 敏感信息泄露(AGENTS.md 明文密码) | 已成 `AGENTS.md` 的**明示豁免**条目 | | | 目录名不一致(可能用 taro,需确认) | 已确认 `h5-uniapp`,无 taro | | | `test/` 目录缺失 | `test/` 已存在且有 7 项验收脚本 | | | 温度单位不一致(K×100 vs 0.1°C) | 已统一为 K×100 | | 数据单位审查报告 | SOC/SOH 单位标注错误 | `API.md` 早已重写;该报告基准 `tcp-protocol.md` 已不存在 | ## 四、**不删**:`生产环境.txt`(并修掉自相矛盾的表述) 它是**唯一凭据清单**(阿里云账号/小程序 AppSecret/腾讯地图 key/SSL AccessKey 都在其中), 且被 `docs/tech/小程序用户端.md` 明确引用为"密钥记录处"。 但原文写着"仅记录在内网 Git 仓库 `生产环境.txt`,**不入代码仓库**"—— **与事实矛盾** (`git ls-files` 实测它**已入库**)。已改为准确表述:只记录在该文件、**绝不写进任何源码/.env**、 **不要删除**(新凭据追加到那里,不要散落别处)。 > 🔐 **留给你的决定**:该文件含大量明文凭据。现策略与 `AGENTS.md`「明文密码」豁免一致(内网仓库), > 若要收紧,建议把它加入 `.gitignore` 并另存到密码管理器 —— 但这会改变 agent 的直连方式,故未擅自改。 ## 五、取消 `archive/` 目录本身 **不再设归档**。理由:被删内容在 **git 历史里完整可查**(`git log -- <原路径>`), 归档的"留痕"价值因此为零,却持续制造"这文件还算不算依据"的歧义。 已把该结论写进 `docs/README.md` 的维护约定:**过时就删;仍有价值的归到正确的类。** ## 六、其他归位 - `营业执照.jpg`(主体资质,小程序/备案用)→ `docs/contract/` - 根目录现在只剩 5 个必要文件:`.gitignore` / `AGENTS.md` / `README.md` / `opencode.json` / `生产环境.txt` ## 校验 - docs 相对链接 **0 断链**(搬迁引入的 2 处已在上一提交修好,本次复检通过); - 已删除文件的残留引用:**仅剩 `docs/README.md` 的处置记录/映射表**(旧名必须出现,属预期); - `cargo check --all-targets` 两服务零 error/warning(本次只动文档与仓库清理,未碰源码逻辑)。
2026-09-20 05:00:29 +08:00
> ⚠️ 以上密钥只记录在**仓库根目录的 `生产环境.txt`**(内网 Gitea,明文密码见
> `AGENTS.md`「代码审查豁免」)—— **绝不写进任何源码、`.env` 或配置文件**。
> 该文件是**唯一凭据清单**(阿里云/小程序 AppSecret/腾讯地图/SSL AccessKey 都在其中),
> **不要删除**;需要新凭据时追加到那里,不要散落在别处。
docs: 文档分类整理 —— AGENTS.md 只留判据与链接,详细篇按用途归入 docs/ 子目录 ## 为什么要做 `AGENTS.md` 曾达 **90,370 B**,而工作区指令预算是 **65,536 B** —— 系统按**保留头部**截断, 于是**尾部约 25 KB 永远不会被加载**:组织架构、数据模型、TCP 协议、数据单位规范、 微信小程序用户端**全部处于"写了但读不到"的状态**。手册实际上部分失效。 ## 一、AGENTS.md 瘦身:90,370 → 60,227 B(余量 5,309 B,尾部不再被截断) 三个**纯参考型大段**整段搬迁到 `docs/tech/`(**内容逐字保留,未删改**), 原位置换成「判据 + 链接」: | 原 AGENTS.md 章节 | 大小 | 现位置 | |---|---|---| | `## 部署与维护` | 17,611 B | `docs/tech/部署手册.md` | | `## 数据模型` | 12,100 B | `docs/tech/数据模型.md` | | `## 微信小程序用户端` | 10,262 B | `docs/tech/小程序用户端.md` | 替换后的章节**只留改动前必须先知道的硬约束**(例如:产物名与测试环境落地名不一致、 ETXTBSY 的 `.new`→`stop`→`mv`→`start` 流程、`stream{}` 不可重加、发布顺序 device 先 api 后、 建表顺序即依赖顺序且写错报 MySQL 1824、时间列必须 DATETIME、`cabinets.status` 是配置态不表示在线……), 其余指向详细篇。**判据留在常驻加载的 AGENTS.md,逐项参考移出**。 ## 二、docs/ 分类(原 21 个文件平铺 → 五个用途目录) ``` docs/ ├── README.md 新增:文档地图(分类/权威性/旧名→现名映射/维护约定) ├── protocol/ 设备协议(冻结,对硬件交付)★唯一权威 │ ├── 柜控板固件对接文档.md │ └── 1TN协议标准_*.md / *.pdf ├── tech/ 平台技术文档(开发/运维必读) │ ├── API.md · 数据模型.md · 部署手册.md · 小程序用户端.md ├── contract/ 合同·规格·验收标准(商务依据,不描述实现) ├── compound-notes/ 单点经验笔记(原有) └── archive/ ⛔ 历史留痕(只读,不代表现状,不可作依据) ├── 开发文档.md(早于现行实现) └── 审查报告/深度分析报告-2026-07-06 ``` - 19 个文件用 `git mv` 迁移(保留历史),3 个未跟踪文件用普通移动; - **内容零改动**(唯一例外是引用替换),已核验 `docs/tech/API.md` 的 `git diff` 为空。 ## 三、全仓引用同步:40 处 / 10 个文件 路径不只出现在文档里,还散落在**源码注释**(`db/migrate.rs`、`routes/cabinets.rs`、 `workers/report_worker.rs`、`tcp/connection.rs`、`h5-uniapp/utils/format.ts`)、 `test/tcp_e2e_smoke.py`、`tasks/001-*.md`、`README.md`、`AGENTS.md` 中,全部同步。 **并已实测校验命令能失败**:往 `docs/tech/API.md` 植入 `<!-- probe: docs/API.md -->` → 命中;删除 → 无输出。 > ⚠️ 过程中踩了一个坑并已修:这些 `.md` 多为 **CRLF**,我第一次用 `\n` 正则删除时 > **没匹配上 `\r\n`**,以为删干净了其实残留了一行 —— 靠 `git diff` 非空才发现。 > 已把「CRLF 必须按 `\r?\n` 处理」写进 `docs/README.md` 的维护约定。 ## 四、顺带查实的失效引用(归档保留原文,不改写历史) - `docs/tcp-protocol.md`:仅出现在 2026-07-06 的两份历史报告里(当时的事实); - `docs/柜控板-平台TCP接口文档.md`:仅出现在协议文档 **v1.1 变更记录**里 (记录"已删除该内部重复文档"这件事),**不是活链接**,无需修复。 两者已在 `docs/README.md` 的「旧名 → 现名映射」表中给出对应关系。
2026-09-20 04:42:51 +08:00
### 构建命令
```bash
cd software/h5-uniapp
npm run build:mp-weixin
# 产物在 dist/build/mp-weixin/,用微信开发者工具导入上传
```
### API 域名配置
小程序请求后端 API 必须配置合法域名(HTTPS):
- 后台「开发管理 → 开发设置 → 服务器域名」
- request 合法域名:`https://app.anzhizhichong.com`
- 开发阶段可在 `manifest.json` 设 `urlCheck: false` 跳过校验
### API base URL
小程序用全 URL(`api/index.ts` 条件编译):
```typescript
// #ifdef MP-WEIXIN
const BASE_URL = 'https://app.anzhizhichong.com/api/pms'
// #endif
// #ifndef MP-WEIXIN
const BASE_URL = '/api/pms'
// #endif
```
### 信号强度显示(RSSI)
设备卡片右上角显示 RSSI 信号强度。
> ✅ **2026-09 已收敛为「两端同源同名、统一 5 档」**(此前两端不一致,见下方"行为变化")。
> **唯一权威实现**:`web/src/utils/deviceStatus.ts` 与 `h5-uniapp/src/utils/deviceStatus.ts`
> 的 `rssiSignal()` / `rssiBarColors()` / `RSSI_TIERS`(**两端逐字一致,改一边必须同步另一边**)。
> 一致性用例:`node test/rssi_signal.test.mjs`(遍历 0–99 逐值断言两端 `level`/`bars`/`color` 相同)。
> ⛔ **页面里不得再自己写一套阈值**(历史上两端各写一套,就是不一致的根因)。
**统一分档表(协议口径:`rssi` 是 0–99 的信号等级,不是 dBm)**
| 阈值 | `level` | 颜色 | 5 格制格数 | PC 图标亮的 `<path>` |
|------|---------|------|-----------|---------------------|
| ≥ 70 | 4 `strong` | `#16a34a` 绿 | 5 | 4 条全亮 |
| ≥ 55 | 3 `good` | `#2563eb` 蓝 | 4 | 3 条 |
| ≥ 40 | 2 `fair` | `#f59e0b` 黄 | 3 | 2 条 |
| ≥ 30 | 1 `weak` | `#f97316` 橙 | 2 | 1 条 |
| < 30 或 null | 0 `none` | `#9ca3af` 灰 | 1(底格) | 0 条(只剩底部圆点 `M2 20h.01`) |
**两端如何消费同一份纯函数:**
- **PC**(`web/src/pages/devices/CabinetGrid.tsx::SignalIconComponent`):`rssiSignal(rssi)` 取 `color` 与 `level`,
4 条 `<path>` 按 `level > i` 决定亮几条;卡片头部数值颜色用同一个 `color`。
- **小程序**(`home/index.vue`、`device-detail/index.vue`):
`v-for="(color, i) in rssiBarColors(cab.rssi)"` 渲染 `bars` 根 `<view class="signal-bar">`,
颜色**内联** `:style="{ background: color }"`;**格数真的随档位变化**。
- 颜色只在 TS 里定义一次(不再有 `.signal.good/.mid/.low/.off` 这类 CSS 颜色规则;
页面 CSS 只负责尺寸/间距)。
**后端(两端共用):** 设备列表接口用 pipeline 批量 `HGET device:{imei} rssi`
(`routes/cabinet_tree.rs::attach_realtime_status`,字段下标见 `DEVICE_LIST_FIELDS`);
小程序侧 `routes/h5.rs::get_cabinets` 同样带 Redis。
**相关文件:**
- 纯函数(权威): `software/web/src/utils/deviceStatus.ts`、`software/h5-uniapp/src/utils/deviceStatus.ts`
- PC 消费点: `software/web/src/pages/devices/CabinetGrid.tsx`(`SignalIconComponent` + 卡片头部)
- 小程序消费点: `software/h5-uniapp/src/pages/home/index.vue`、`pages/device-detail/index.vue`
- 类型: `software/h5-uniapp/src/api/index.ts` — `CabinetItem.rssi`
- 一致性用例: `test/rssi_signal.test.mjs`
> ⚠️ **行为变化(2026-09,小程序端显示会变 —— 这是有意为之)**
> 收敛前:PC 5 档(≥70 绿/≥55 蓝/≥40 黄/≥30 橙/<30 灰,格数随档位增删);
> 小程序只有 **4 档(无 ≥70)**、**30–39 用红色**、且**恒渲染 5 格只改颜色**。
> 收敛后小程序:**新增 ≥70 档(绿/满格)**、**30–39 由红改橙**、**≥55 由绿改蓝**、
> **离线灰由 `#94a3b8` 改为 `#9ca3af`**,且**格数随档位变化**(不再恒 5 格)。
> 影响页面:小程序首页设备卡片、小程序设备详情页头部。
### 近期 UI 改动
1. **设备卡片头部**:**PC 管理端**(`web/src/pages/devices/CabinetGrid.tsx`)去掉"在线/离线"文字 badge,
改为信号图标 + RSSI 数值。
✅ **小程序保留"在线/离线"文字 badge —— 这是有意差异,不是缺陷,不要当 bug 改掉**:
`h5-uniapp/src/pages/home/index.vue:43`(设备卡片,`cab.status===1 ? '在线' : '离线'`)与
`pages/device-detail/index.vue:18`(设备详情;同文件 `:74` 还有**板级**的在线/离线 badge)。
理由(产品决定):PC 用"信号图标 + RSSI 数值"表达;小程序屏幕小、文字 badge 更直观。
> PC 卡片:**图标 + 数值**;小程序:**文字 badge**(有意保留)。
另外 **PC 设备详情页**(`web/src/pages/devices/cabinet.tsx:503`)也仍用 `Tag` 渲染
`CABINET_STATUS_MAP`(`0 离线 / 1 在线 / 2 禁用`)—— 只是**卡片**去掉了,别理解成"全平台都去掉了"。
2. **通道统计**:图标+数字一行排列,图标用 `<svg>` 内联 Lucide(不加容器,flex 居中)
3. **右上角扫码**:scan-line 图标(Lucide),灰色 #6b7280,居中垂直对齐
### 状态位展示约定(**状态位按归属层级展示**)
> 以下三条是**协议 §3.8 / §4.2 / §5.7 的既定结论**(产品已确认),后续不要再反复确认。
1. **柜级状态位 → 显示在"柜子"层面**
- 数据:**⚠️ 这两个名字不是 DB 列**(实测 `cabinets` 表**没有** `status1`/`status2` 列,
它的列是 `id/project_id/abstract_id/imei/iccid/auth_str/name/address/status/created_at/updated_at/
latitude/longitude/work_mode/auth_str_issued/cell`)。它们是:
**Redis 字段** `device:{imei}` 的 `cabinet_status1` / `cabinet_status2`(设备上报原样落,2 位 hex)
→ 接口**原样透出**为响应字段 `status1` / `status2`。
写:`report_worker.rs::write_device_state`;读:`cabinet_tree.rs::attach_realtime_status`(列表)、
`cabinets.rs::fetch_cabinet_realtime`(详情)。
- 位定义(§3.8):`status1` bit0 断电|bit1 烟雾|bit2 水位|bit3 倾倒|**bit4 柜门打开**|
bit5 加热风扇|bit6 接触器断开|bit7 喷淋;`status2` bit0 声光报警|**bit1 柜门打开超时**
(阈值硬件定义,**平台只呈现、不自行判定**);`status2` bit2–7 为保留位,**不展示**。
- 页面:PC `web/src/pages/devices/cabinet.tsx`、小程序 `h5-uniapp/src/pages/device-detail/index.vue`。
- **取不到返回 `null`(未知),绝不落 `"00"`** —— `"00"` 是"全部正常"的有效值。
2. **仓体级状态位 → 显示在"仓体"层面**
- 数据:通道 18 字符 hex 的 `batt_status`(byte0) / `pow_status`(byte1);保留位
(`batt_status` bit2–3、`pow_status` bit3–6)**不展示**。
- 页面:PC 柜子详情里的通道卡片、小程序 `pages/compartment-detail/index.vue`。
- **仓体层面不显示任何"门"状态**:协议**没有**"按仓体(舱门)开门"的指令(§4.2 L403)。
3. **柜门是柜级独立动作,不与业务联动,全平台只有一个开门按钮**
- `open` 是**柜级**指令(**不带 `id`**),语义是**「柜门解锁,下发后由人拉开,门不会自动开」**;
没有"关门"指令(关门也是人为动作)。**全平台只有一扇柜门**,不按仓体区分。
- **柜门状态永远来自 `status_post`(约 60 秒一次),不是实时量** —— 界面上必须标注
"来自最近一次上报(约 60 秒一次),非实时"(§4.2 L428)。
- 开门是**独立流程**,与电池插入、充电开始/结束**没有因果关系也没有先后要求**(§5.7、§7.2):
不得出现在"开始充电"流程里、不得改任何订单状态、不得要求存在订单。
- 入口只有一个:PC 详情页按钮(`<Permission code="charge:open_door">` 包裹)+
小程序设备详情页按钮;**仓体(通道)详情页不放开门按钮**。
- 权限码 `charge:open_door`(后端 `check_permission` 硬校验;`device:door:unlock` 是历史误用的
不存在权限码,**禁止再用**)。
4. **解析函数两端必须同源同名**:`web/src/utils/deviceStatus.ts` 与
`h5-uniapp/src/utils/deviceStatus.ts` 各有一组 `parseCabinetStatus1` / `parseCabinetStatus2` /
`cabinetDoorState` / `cabinetStatusTags`(注释互相指认对方文件,改一边务必同步另一边)。
端到端一致性用例见 `test/device_status_parse.test.mjs`(`node test/device_status_parse.test.mjs`,
逐位遍历 0x00–0xFF 断言两端一致)。
5. **`cabinets.status` 是「启用/禁用」配置态,不表示在线** —— `1` 启用 / `2` 禁用(`0` 是建表默认值
产生的取值,代码不显式写它,语义等同启用);实时在线一律以 Redis `device:{imei}.online` 为准
(唯一权威判据 `routes/cabinet_tree.rs::device_online_flag`,接口字段 `is_online`),
`energy_stats` 的 `online_count`、H5 首页 `online_cabinets`、PC/小程序的「在线/离线」全部消费它
(`CABINET_STATUS_MAP` 只保留启用/禁用两档,**不要再出现"离线"档**)。
### 开发约束(uni-app 特定)
1. **`<text>` 不支持 `display: flex`** — uni-app 的 `<text>` 组件是纯文本组件,不接受 flex 布局。需要 flex 的地方用 `<view>`
2. **SVG 图标居中**:`.stat-chip svg { display: block; flex-shrink: 0 }` 用 CSS 统一控制尺寸,比内联属性更可靠
3. **内联 SVG + v-if**:Vue 3 支持在 `<path>` 上用 `v-if` 条件渲染,适用于动态图标
4. **CSS 覆盖 SVG 尺寸**:用 `.xxx svg { width: Xpx; height: Xpx }` 统一控制图标大小,不在每个 `<svg>` 上写死
chore: 清掉误入库的 agent 工具记忆目录与 Vite 模板 README(内容先按主题归位) ## 起因 用户问"现在确定所有文档都是按分类存放没重复和过期内容了吧" —— **不能凭感觉答"是"**,于是做了一次针对**已跟踪文件**的体检(重复/断链/过期陈述三维度)。 第一轮体检结果:重复 0 组、断链 0 处,但**又扫出 3 处该处理的东西**。 ## 一、`.workbuddy/memory/` —— 另一个 agent 工具的记忆目录被误入库 3 个文件(`MEMORY.md` / `2026-07-02.md` / `2026-07-07.md`),**全仓零引用**, 最后一次"提交"是搭车进 `feat(protocol): TCP v1.1 协议对齐` 这类无关提交 —— 与之前那几张误提交的图片同一模式。 - ⚠️ `2026-07-02.md` 里含一处**生图 API Key 片段**(`sk-ib7i...M2z`); - `.gitignore` 里 `.codebuddy/` 早有,但 `.workbuddy/` **漏了** ⇒ 才被顺手提交进来。 ### 处理:内容先归位,再删目录(不是一删了之) 按 `docs/README.md` 已确立的原则"**过时就删;仍有价值的归到正确的类**", 把 `MEMORY.md` 里仍有价值的三类内容分别落位: | 内容 | 归到哪 | 为什么 | |---|---|---| | UI 颜色系统 / 背景容器 / 36 仓通道卡布局 | **`docs/tech/小程序用户端.md`** 新增「附:UI 设计规范(视觉口径,改动界面前必读)」 | 这是页面视觉口径,属小程序文档 | | Ardot `batch_edit` 的 `fills`/`strokes`/`cornerRadius` 写法坑 + 设计稿 7 屏 ID | **`docs/compound-notes/2026-07-ardot-batch-edit-属性写法.md`** | 工具特有的单点教训,正是 compound-notes 的定义 | | "开发前必须确认需求"、"生产环境须授权"、落地页明亮风格偏好 | **`AGENTS.md` 新增「操作规则」小节** | 项目级规则,须常驻加载 | 然后把 `.workbuddy/` 从版本控制移除并**加入 `.gitignore`**(连同 `.opencode/`、`.codegraph/`), 堵住同一个坑再犯。 ## 二、`software/web/README.md` —— 建站模板残留 23 行里 9 行是 Vite/plugin-react/Oxlint 的模板话术(英文、与项目无关)。 `api-server` / `device-server` / `h5-uniapp` 三个工程**都没有** README —— 构建方式统一在 `AGENTS.md` 与 `docs/tech/部署手册.md` 里。⇒ **删除**。 ## 三、一个我自己的误判(已纠正,记录以免后人重复) 我一度怀疑 `docs/tech/API.md` 接口表"少 12 行"(我数出 68 行,而 `mod.rs` 有 80 个 `.route(`)。 复核发现 **`API.md` 自己写明了计数约定**:"一行 = 一次 `.route(...)` 注册,共 80 行; 展开后 93 对" —— 而我的正则 `^\|\s*(GET|POST)\s*\|` **漏掉了 `| GET / POST |` 这种链式写法**。 用能匹配链式的正则重数 = **正好 80** ⇒ **`API.md` 是准确的,我的怀疑是错的**。 ## 校验(只扫 git 已跟踪文件) - 已跟踪文件 **217**(原 221 → 删 3 个工具记忆 + 1 个模板 README); - 文档内容重复:**0 组**; - 已跟踪 md 的本地链接:**0 断链**; - `.workbuddy` 已跟踪文件数 = 0、工作区已不存在。 ## 仍**刻意保留**的(不是遗漏) - `生产环境.txt`:**唯一凭据清单**且被 `docs/tech/小程序用户端.md` 引用为密钥记录处 —— 上一提交已把"不入代码仓库"这句与事实矛盾的表述改准;是否改走 `.gitignore`+密码管理器由你定。 - `docs/README.md` 的「旧名→现名映射」表 / 处置记录 / 自证方法:**必须**出现旧名,属预期。 - `docs/compound-notes/TEMPLATE.md`(94 B):新建笔记的模板,给该目录提供格式约束。 - `tasks/002-未结待办-*.md`:两项未结(`energy` 等硬件答复、长函数重构), `tasks/` 本身已 gitignore、不入库。
2026-09-20 05:04:53 +08:00
---
## 附:UI 设计规范(视觉口径,改动界面前必读)
> 来源:H5 设计稿(Ardot 文件 ID `701384244279693`「安知充H5应用设计稿」,7 屏:
> 登录 / 首页 / 设备详情 / 设备列表 / 仓体详情 / 订单 / 我的)落地时沉淀的口径。
> **改动任何页面配色或布局前先对照本节**,避免同一系统内出现两套视觉。
### 颜色系统(状态色 + 背景色成对使用)
| 语义 | 主色 | 浅底 |
|------|------|------|
| 主色(品牌蓝) | `#2563eb` | `#eff6ff` |
| 在线 | `#16a34a` | `#f0fdf4` |
| 离线 | `#9ca3af` | `#f9fafb` |
| 故障 | `#dc2626` | `#fef2f2` |
| 停止 | `#f59e0b` | `#fffbeb` |
| 充电中 | `#2563eb` | `#eff6ff` |
| 满电 | `#7c3aed` | — |
### 背景与容器
- 页面底色统一 `#f5f5f5`(**含 tab 页与子页面**:设备详情 / 设备列表 / 仓体详情);
- 登录页用渐变 `linear-gradient(135deg, #f0f4ff, #e0e7ff, #f0f9ff)`;
- **所有卡片/容器为白底 `#FFFFFF` + 圆角**。
### 设备详情(36 仓)
- 布局为 **6 板 × 6 通道 = 36**;通道卡片白底 + **顶部 3px 彩色状态条**(色条取上表状态色)。