diff --git a/_templates/md-viewer.html b/_templates/md-viewer.html
new file mode 100644
index 0000000..2532ae4
--- /dev/null
+++ b/_templates/md-viewer.html
@@ -0,0 +1,185 @@
+
+
+
+
+
+
+文档预览
+
+
+
+
+
+
+ 文档预览
+
+
+
+
+
+
![放大预览]()
+
+
+
+
diff --git a/_templates/screenshot-modals.js b/_templates/screenshot-modals.js
new file mode 100644
index 0000000..d926ee4
--- /dev/null
+++ b/_templates/screenshot-modals.js
@@ -0,0 +1,105 @@
+/**
+ * 通用弹窗/状态截图脚本
+ *
+ * 使用方式:
+ * node screenshot-modals.js
+ *
+ * config.json 格式:
+ * {
+ * "baseDir": "employee-app/emergency-medical",
+ * "tasks": [
+ * { "page": "resource-map.html", "output": "resource-map-simulate.jpg",
+ * "action": "() => { document.querySelector('.simulate-panel').style.display = 'block'; }" },
+ * { "page": "detail.html", "output": "detail-full.jpg", "fullPage": true }
+ * ]
+ * }
+ *
+ * task 字段说明:
+ * page - 页面 HTML 文件路径(相对于 baseDir)
+ * output - 输出截图文件名
+ * action - 可选,截图前执行的 JS(触发弹窗/状态)
+ * fullPage - 可选,true 时去掉 phone-shell 高度限制,截取完整滚动内容(长图)
+ *
+ * 如果不传 config.json,则使用内置的应急就医模块配置作为示例。
+ */
+const puppeteer = require('puppeteer');
+const path = require('path');
+const fs = require('fs');
+
+const delay = ms => new Promise(r => setTimeout(r, ms));
+
+// 只截取 .phone-shell 元素,避免外壳背景
+// fullPage=true 时去掉高度限制和溢出裁剪,截取完整内容(长图)
+async function screenshotPhoneShell(page, filepath, fullPage) {
+ if (fullPage) {
+ await page.evaluate(() => {
+ const shell = document.querySelector('.phone-shell');
+ if (shell) { shell.style.height = 'auto'; shell.style.borderRadius = '0'; }
+ const sc = document.querySelector('.scroll-content');
+ if (sc) { sc.style.overflow = 'visible'; sc.style.flex = 'none'; }
+ });
+ await new Promise(r => setTimeout(r, 100));
+ }
+ const shell = await page.$('.phone-shell');
+ if (shell) {
+ await shell.screenshot({ path: filepath, type: 'jpeg', quality: 85 });
+ } else {
+ await page.screenshot({ path: filepath, type: 'jpeg', quality: 85 });
+ }
+}
+
+// 默认配置(应急就医模块示例)
+const DEFAULT_CONFIG = {
+ baseDir: 'employee-app/emergency-medical',
+ tasks: [
+ { page: 'resource-map.html', output: 'resource-map-simulate.jpg',
+ action: `() => { const p = document.querySelector('.simulate-panel'); if(p) p.style.display = 'block'; }` },
+ { page: 'emergency-chat.html', output: 'emergency-chat-modal.jpg',
+ action: `() => { const m = document.querySelector('.modal-overlay'); if(m){m.style.display='flex';m.classList.add('show');} }` },
+ { page: 'emergency-chat.html', output: 'emergency-chat-voice.jpg',
+ action: `() => { const btns = document.querySelectorAll('[class*="voice"]'); btns.forEach(b => b.click()); }` },
+ { page: 'emergency-chat.html', output: 'emergency-chat-plus.jpg',
+ action: `() => { const p = document.querySelector('.plus-panel'); if(p){p.style.display='grid';p.classList.add('show');} }` },
+ { page: 'appointment-detail-pending.html', output: 'appointment-detail-pending-modal.jpg',
+ action: `() => { const m = document.querySelector('.modal-mask'); if(m){m.style.display='flex';m.classList.add('modal-mask--show');} }` },
+ { page: 'appointment-detail-confirmed.html', output: 'appointment-detail-confirmed-modal.jpg',
+ action: `() => { const m = document.querySelector('.modal-mask'); if(m){m.style.display='flex';m.classList.add('modal-mask--show');} }` }
+ ]
+};
+
+(async () => {
+ // 读取配置
+ let config = DEFAULT_CONFIG;
+ const configArg = process.argv[2];
+ if (configArg && fs.existsSync(configArg)) {
+ config = JSON.parse(fs.readFileSync(configArg, 'utf-8'));
+ console.log(`Using config: ${configArg}`);
+ } else {
+ console.log('Using default config (emergency-medical)');
+ }
+
+ const baseDir = path.resolve(config.baseDir);
+ const baseUrl = 'file:///' + baseDir.replace(/\\/g, '/');
+ const outDir = path.join(baseDir, 'doc', 'screenshots');
+
+ // 确保输出目录存在
+ if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
+
+ const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox'] });
+ const page = await browser.newPage();
+ await page.setViewport({ width: 500, height: 900, deviceScaleFactor: 1 });
+
+ for (const task of config.tasks) {
+ await page.goto(`${baseUrl}/${task.page}`, { waitUntil: 'networkidle0' });
+ // 执行 action 触发弹窗/状态(action 可选)
+ if (task.action) {
+ await page.evaluate(new Function('return (' + task.action + ')()'));
+ await delay(300);
+ }
+ await screenshotPhoneShell(page, path.join(outDir, task.output), task.fullPage);
+ console.log(`Done: ${task.output}`);
+ }
+
+ await browser.close();
+ console.log(`\nAll ${config.tasks.length} screenshots saved to: ${outDir}`);
+})();
diff --git a/本地服务器独立微服务化方案.md b/本地服务器独立微服务化方案.md
new file mode 100644
index 0000000..a3aae61
--- /dev/null
+++ b/本地服务器独立微服务化方案.md
@@ -0,0 +1,392 @@
+# 本地服务器独立微服务化方案
+
+> **项目**:智能餐养系统 - 边缘服务节点重构
+> **版本**:v1.0
+> **日期**:2026-05-26
+> **作者**:技术团队
+> **范围**:面向技术团队的设计与落地方案
+> **周期**:1 个月落地,边跑边迁
+
+---
+
+## 一、定位与边界
+
+**本地服务器 ≠ 业务系统**。本次重构将其重新定位为:**部署在每个食堂边缘的独立微服务,只做"硬件 ↔ 云端"的可靠中转桥梁**,与现有"健康长庆"业务系统、小程序后端、admin 后台**完全解耦**。
+
+| 做(In Scope) | 不做(Out of Scope) | 不混用(独立部署) |
+| --- | --- | --- |
+| 任务化数据中转 | 业务规则、菜品算法 | 不依赖小程序后端 |
+| 任务链状态管理与重试 | 用户登录鉴权 | 不调用四合一业务接口 |
+| 终端设备接入与协议适配 | 报表/统计/分析 | 不耦合 admin 业务模块 |
+| 本地资源缓存(视频/人脸/升级包) | 任何 UI 业务逻辑 | 独立进程、独立升级 |
+| 设备远程升级 | | |
+
+**一句话原则**:本地服务器只回答两个问题——*云端要的数据收齐了吗?云端下发的指令落地了吗?* 其他一概不管。
+
+---
+
+## 二、总体架构
+
+
+### 2.1 系统拓扑
+
+```mermaid
+flowchart TB
+ subgraph Cloud["云端"]
+ CloudAPI[云端任务网关
Spring Boot]
+ CloudDB[(任务主库
PostgreSQL)]
+ OpsUI[运维后台
Vue3 + Ant Design Vue
复用 admin 技术栈]
+ end
+
+ subgraph Edge["食堂本地 - 每个食堂一套"]
+ LS[本地服务器微服务
Spring Boot 独立 JAR]
+ LSDB[(本地任务库
SQLite)]
+ Cache[本地资源缓存
视频/人脸库/升级包]
+ end
+
+ subgraph Devices["终端硬件"]
+ T1[点餐终端]
+ T2[入库秤/配比秤]
+ T3[智能货柜/绑盘机]
+ T4[人脸设备]
+ T5[显示大屏]
+ end
+
+ OpsUI --> CloudAPI
+ CloudAPI <-->|MQTT QoS2 持久会话| LS
+ CloudAPI --- CloudDB
+ LS --- LSDB
+ LS --- Cache
+ LS <-->|HTTP/MQTT 局域网| T1
+ LS <-->|HTTP/MQTT 局域网| T2
+ LS <-->|HTTP/MQTT 局域网| T3
+ LS <-->|HTTP/MQTT 局域网| T4
+ LS -->|本地 HTTP / RTSP| T5
+```
+
+### 2.2 通信协议选型(针对弱网)
+
+| 链路 | 协议 | 选型理由 |
+| --- | --- | --- |
+| 云端 ↔ 本地服务器 | **MQTT QoS 2 + Persistent Session**(EMQX) | 弱网友好、断线自动续传、消息至少一次且不重复 |
+| 大文件下发(视频/升级包) | HTTPS 断点续传(Range) | 弱网重连不重头,降低带宽浪费 |
+| 本地服务器 ↔ 终端 | HTTP / MQTT(局域网) | 局域网稳定,简单优先,按设备类型适配 |
+| 运维后台 ↔ 云端 | HTTPS REST | 复用 admin 现有 axios + token 鉴权 |
+
+### 2.3 技术栈
+
+| 模块 | 选型 | 备注 |
+| --- | --- | --- |
+| **云端任务网关** | Spring Boot 3 + Spring Integration MQTT | 与现有 Java 后端栈一致 |
+| **本地服务器微服务** | Spring Boot 3,打包成单 JAR | 一键部署,内存占用控制在 512MB 以内 |
+| **MQTT Broker** | EMQX 5(集群) | 支持 QoS 2、共享订阅、规则引擎 |
+| **云端数据库** | **PostgreSQL 15** ✅ 推荐 / MySQL 8 备选 | PG 的 JSONB 对 `target_scope` 等字段更友好,CTE/窗口函数利于运维查询 |
+| **本地任务库** | SQLite + WAL 模式 | 零运维,适合边缘场景,单文件备份 |
+| **运维后台** | Vue 3 + Vite + TypeScript + Ant Design Vue | **复用现有 admin 工程技术栈与登录体系** |
+| **配置中心 / 注册** | 暂不引入,本地服务器走配置文件 + 远程下发 | 边缘节点数量级小,过早引入 Nacos 增加复杂度 |
+| **部署** | Docker 镜像 + 一键安装脚本 | 边缘节点需支持离线部署 |
+
+---
+
+## 三、核心机制:全链路任务化
+
+### 3.1 设计原则
+
+每一次数据流转(无论下行还是上行)都是一个**有状态、可追溯、可重试**的任务。云端与本地各持一份任务记录,通过 `task_id` 关联,任意时刻**任意任务卡在哪一跳一查就知道**。
+
+### 3.2 任务状态机
+
+```mermaid
+stateDiagram-v2
+ [*] --> Created: 云端创建任务
+ Created --> Dispatched: 推送到本地服务器
+ Dispatched --> LocalReceived: 本地落库 ACK
+ LocalReceived --> TerminalDispatched: 分发到终端
+ TerminalDispatched --> TerminalDone: 终端确认完成
+ TerminalDone --> CloudReported: 上报云端
+ CloudReported --> [*]: 任务完成
+
+ Dispatched --> RetryPending: 网络中断
+ LocalReceived --> RetryPending: 终端离线
+ TerminalDispatched --> RetryPending: 终端执行失败
+ RetryPending --> Dispatched: 自动指数退避重试
+ RetryPending --> Failed: 达到最大重试次数
+ Failed --> Dispatched: 运维后台人工触发重试
+```
+
+**重试策略**:指数退避 `1s → 5s → 30s → 2min → 10min`,默认最多 5 次,达到上限转 `Failed` 并触发告警。
+
+### 3.3 数据库 Schema(核心三表)
+
+> 以下 DDL 以 PostgreSQL 为例,MySQL 版本仅类型微调(JSONB → JSON、ENUM → VARCHAR + CHECK)。
+
+```sql
+-- ============================================
+-- 1. 任务主表
+-- ============================================
+CREATE TABLE task (
+ task_id UUID PRIMARY KEY,
+ task_type VARCHAR(32) NOT NULL,
+ -- 'DISH_DOWN','FACE_DOWN','UPGRADE_DOWN','VIDEO_DOWN','MEAL_UP',...
+ direction VARCHAR(8) NOT NULL, -- 'DOWN' / 'UP'
+ target_scope JSONB NOT NULL,
+ -- {"org_id":1,"canteen_ids":[10,11],"device_ids":["T01","T02"]}
+ -- 支持二级单位/食堂/设备级定向下发
+ payload_ref VARCHAR(255), -- 大字段指针(对象存储 key 或外部表 ID)
+ total_count INT NOT NULL DEFAULT 0,
+ success_count INT NOT NULL DEFAULT 0,
+ failed_count INT NOT NULL DEFAULT 0,
+ state VARCHAR(24) NOT NULL,
+ -- CREATED/DISPATCHED/LOCAL_RECEIVED/TERMINAL_DISPATCHED/
+ -- TERMINAL_DONE/CLOUD_REPORTED/RETRY_PENDING/FAILED
+ retry_count INT NOT NULL DEFAULT 0,
+ max_retry INT NOT NULL DEFAULT 5,
+ next_retry_at TIMESTAMP,
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ finished_at TIMESTAMP,
+ creator VARCHAR(64)
+);
+CREATE INDEX idx_task_state_retry ON task(state, next_retry_at);
+CREATE INDEX idx_task_target ON task USING GIN (target_scope);
+
+-- ============================================
+-- 2. 任务跳转流转表(全链路审计)
+-- ============================================
+CREATE TABLE task_hop (
+ hop_id BIGSERIAL PRIMARY KEY,
+ task_id UUID NOT NULL REFERENCES task(task_id),
+ hop_name VARCHAR(24) NOT NULL,
+ -- CLOUD_OUT/LOCAL_IN/LOCAL_OUT/TERMINAL_IN/TERMINAL_DONE/
+ -- LOCAL_REPORT/CLOUD_IN
+ status VARCHAR(8) NOT NULL, -- 'OK','FAIL','TIMEOUT'
+ err_code VARCHAR(32),
+ err_msg TEXT,
+ occurred_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+CREATE INDEX idx_task_hop_task ON task_hop(task_id, occurred_at);
+
+-- ============================================
+-- 3. 任务明细表(批量任务的逐条结果)
+-- ============================================
+CREATE TABLE task_item (
+ item_id BIGSERIAL PRIMARY KEY,
+ task_id UUID NOT NULL REFERENCES task(task_id),
+ biz_key VARCHAR(128) NOT NULL, -- 业务键,例如菜品 ID、人脸 ID
+ status VARCHAR(8) NOT NULL, -- 'OK','FAIL','PENDING'
+ err_msg TEXT,
+ updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ UNIQUE (task_id, biz_key)
+);
+CREATE INDEX idx_task_item_task ON task_item(task_id, status);
+```
+
+**这套表的关键能力**:
+
+- 任意任务卡在哪一跳,一查 `task_hop` 就知道
+- 1000 条菜品下发,失败的 3 条精准告诉你是哪 3 条(`task_item.status='FAIL'`)
+- 本地服务器同样跑这套 Schema(SQLite 简化版),云端拉取本地 hop 状态做对账
+
+### 3.4 可靠性三大不变量
+
+1. **先持久化再前进**:每一跳必须本地落库成功后才回 ACK;落库失败 → 让上游重发
+2. **幂等键 = `task_id` + `biz_key`**:重发不会产生重复数据;终端拿到同一个 task_id 直接覆盖原记录
+3. **任务永不丢**:本地服务器即使断电重启,任务从最近持久化的状态继续往下走;运维后台可强制重放
+
+### 3.5 接口契约(节选)
+
+**云端 → 本地:任务下发**
+
+```
+Topic: tenant/{org_id}/canteen/{canteen_id}/task/down
+QoS: 2
+Payload:
+{
+ "task_id": "uuid",
+ "task_type": "DISH_DOWN",
+ "target_scope": { "device_ids": ["T01","T02"] },
+ "payload_ref": "https://oss.../dish-snapshot-2026052601.json",
+ "items_count": 487,
+ "issued_at": "2026-05-26T10:00:00Z"
+}
+```
+
+**本地 → 云端:跳转回执**
+
+```
+Topic: tenant/{org_id}/canteen/{canteen_id}/task/hop
+Payload:
+{
+ "task_id": "uuid",
+ "hop_name": "TERMINAL_DONE",
+ "status": "OK",
+ "success_count": 485,
+ "failed_count": 2,
+ "failed_items": [
+ {"biz_key":"DISH_1024","err_msg":"image download timeout"}
+ ]
+}
+```
+
+**本地 → 云端:就餐数据上传**
+
+```
+Topic: tenant/{org_id}/canteen/{canteen_id}/task/up
+Payload: 同 task 主表结构 + items 数组
+```
+
+---
+
+## 四、运维后台
+
+> 复用现有 admin 工程的 **Vue 3 + Vite + TypeScript + Ant Design Vue + Pinia + axios** 技术栈,**沿用 admin 登录体系与权限模型**,作为 admin 工程内的一组独立路由模块(`/edge-ops/*`),与业务模块隔离。
+
+### 4.1 功能模块
+
+```
+运维后台 (admin 工程内 /edge-ops 路由组)
+├── 任务总览
+│ ├── 实时大盘:各食堂在线状态、今日任务数、失败率、堆积量
+│ └── 异常告警:失败率突增、任务堆积超阈值、设备掉线
+├── 任务管理
+│ ├── 任务列表(按食堂/类型/状态/时间筛选)
+│ ├── 任务详情(全链路流转图 + 明细 + 错误堆栈)
+│ ├── 一键重试(单任务/批量)
+│ └── 手动创建任务(应急下发)
+├── 设备管理
+│ ├── 食堂/本地服务器健康状态
+│ ├── 终端设备清单(在线、版本、最后心跳)
+│ └── 远程软件升级触发
+├── 资源管理
+│ ├── 视频/人脸库/升级包上传与下发
+│ └── 各食堂本地缓存命中情况
+├── 日志与查询
+│ ├── 实时日志流(SSE 推送)
+│ └── 数据库可视化查询(只读 SQL + 预设查询模板)
+└── 系统配置
+ ├── 重试策略、超时阈值
+ └── 二级单位/食堂组织树
+```
+
+### 4.2 关键页面示意:任务详情
+
+```
+[任务 #abc123 · 菜品下发 · 目标:总部食堂 + 5 个分食堂]
+状态: ⚠ 部分失败 进度: 487/500 耗时: 2m13s
+
+全链路流转:
+ ✓ 云端创建 10:23:01
+ ✓ 推送本地 10:23:02 (6/6 食堂)
+ ✓ 本地落库 10:23:03 (6/6 食堂)
+ ⚠ 终端分发 10:23:05 (5 食堂成功 / 1 食堂超时,自动重试中)
+ └─ 失败明细: 分食堂C - 终端 T07 离线
+
+操作: [一键重试] [跳过失败项] [取消任务] [导出日志]
+```
+
+### 4.3 路由与权限
+
+- 在 `src/router/index.ts` 的 `modules` 数组中新增「边缘运维」分组,`meta.menuKey = 'edge-ops'`
+- 路由命名:`/edge-ops/dashboard`、`/edge-ops/tasks`、`/edge-ops/devices`、`/edge-ops/resources`、`/edge-ops/logs`、`/edge-ops/config`
+- 权限模型:复用 admin 已有 `role`,新增 `edge:read`、`edge:retry`、`edge:upgrade`、`edge:config` 四类细粒度权限
+- 仅限内部运维人员访问,不对客户开放
+
+---
+
+## 五、1 个月落地计划(边跑边迁)
+
+```mermaid
+gantt
+ title 落地排期(2026-05-26 至 2026-06-22)
+ dateFormat YYYY-MM-DD
+ section 第1周 框架
+ 项目骨架/任务模型/DB Schema :a1, 2026-05-26, 3d
+ 云端↔本地通信层(MQTT QoS2) :a2, after a1, 4d
+ section 第2周 三大功能迁移
+ 菜品/营养数据下发改造 :b1, after a2, 3d
+ 就餐数据上传改造 :b2, after a2, 3d
+ 视频资源下发改造 :b3, after b1, 4d
+ section 第3周 运维后台 + 联调
+ 运维后台前后端 :c1, after b3, 5d
+ 全链路联调 + 弱网压测 :c2, after b3, 7d
+ section 第4周 灰度 + 切换
+ 单食堂灰度试运行 :d1, after c2, 3d
+ 分批切换 + 监控 + 回滚预案 :d2, after d1, 4d
+```
+
+### 边跑边迁策略
+
+- **新老并存**:旧 MQ 链路保留,新任务系统**双写一段时间**(老链路真实下发,新链路影子运行)
+- **每日对账**:跑对账脚本比对新老链路数据一致性,差异 > 0 立即告警
+- **按食堂灰度**:第 4 周第 1-3 天选 1-2 个食堂切换,稳定后批量推
+- **回滚开关**:每个食堂有独立的 `use_new_pipeline` 开关,出问题秒级切回老链路
+- **冻结老链路功能**:迁移期间老链路只修 P0 bug,不再加新功能
+
+### 验收标准
+
+| 指标 | 目标 |
+| --- | --- |
+| 弱网模拟丢包 30% 下任务最终成功率 | ≥ 99.9% |
+| 任务平均端到端延迟(局域网正常) | ≤ 3s |
+| 任意失败任务可定位到具体跳转 + 失败明细 | 100% |
+| 运维后台一键重试可用率 | 100% |
+| 灰度食堂连续 3 天无 P0 故障 | 通过 |
+
+---
+
+## 六、风险与对策
+
+| 风险 | 影响 | 对策 |
+| --- | --- | --- |
+| 弱网导致云端推送积压 | 数据延迟 | MQTT 持久会话 + 本地服务器主动拉取兜底 + 队列水位告警 |
+| 本地服务器断电/磁盘损坏 | 任务丢失 | SQLite 启用 WAL + 每日云端快照备份 + 关键任务云端可重放 |
+| 终端固件升级失败变砖 | 设备瘫痪 | 双分区 A/B 升级 + 失败自动回滚 + 升级前强制健康检查 |
+| 1 个月排期紧张 | 延期 | **第 1 周架构定型不可压缩**;运维后台 V1 可砍范围(先保任务列表 + 重试 + 日志,大盘和告警 V1.5 补) |
+| 与四合一系统数据不一致 | 业务事故 | 双写期间每日对账脚本,差异 > 0 告警;切换前必须对账连续 3 天为 0 |
+| MQTT Broker 单点 | 整体瘫痪 | EMQX 至少双节点集群 + VIP/DNS 漂移 |
+| 边缘节点版本不一致 | 兼容问题 | 本地服务器协议层做版本协商,云端兼容旧版本 N-1 |
+
+---
+
+## 七、待办与开放问题
+
+1. **EMQX 部署形态**:云端机房自建 vs 公有云托管,需运维侧拉齐
+2. **对象存储**:大文件(视频/升级包)走哪个 OSS,断点续传 SDK 选型
+3. **告警通道**:钉钉机器人 / 企业微信 / 短信,需明确接入哪一种
+4. **灰度食堂选择**:建议选 1 个网络条件好的 + 1 个网络条件差的,覆盖两种典型场景
+5. **历史任务数据迁移**:老 MQ 在途消息如何处理,是否需要补录到新任务表
+
+---
+
+## 八、附录
+
+### 8.1 与现有 admin 工程的接入点
+
+- **新增路由模块**:`src/views/edge-ops/`(dashboard / tasks / devices / resources / logs / config)
+- **新增 API 聚合**:`src/api/edge-ops.ts`,baseURL `/api/edge`,走云端任务网关
+- **菜单配置**:`MainLayout.vue` 新增「边缘运维」一级菜单,key = `edge-ops`
+- **权限**:复用 `src/stores/user.ts` 的角色与权限校验,新增四个权限位
+- **登录态**:完全沿用 admin 现有 token + axios 拦截器机制,**不新建鉴权体系**
+
+### 8.2 文件清单(新增)
+
+```
+zhican/admin/
+├── src/views/edge-ops/
+│ ├── dashboard/index.vue
+│ ├── tasks/index.vue
+│ ├── tasks/detail.vue
+│ ├── devices/index.vue
+│ ├── resources/index.vue
+│ ├── logs/index.vue
+│ └── config/index.vue
+├── src/api/edge-ops.ts
+└── docs/本地服务器独立微服务化方案.md (本文件)
+
+服务端(独立工程):
+zhican-edge/
+├── edge-cloud-gateway/ 云端任务网关 Spring Boot
+├── edge-local-server/ 本地服务器 Spring Boot(单 JAR)
+└── edge-common/ 协议/DTO/任务模型共享包
+```
+