1339 lines
34 KiB
Markdown
1339 lines
34 KiB
Markdown
# AI 文档模板系统 — 像素级任务清单
|
||
|
||
> 每个任务 ~0.25–0.5 天,可独立分配,验收精确到文件/函数/交互效果。
|
||
> 聚焦:模板标注配置页(第一阶段 MVP)。
|
||
> UI 库:Ant Design Vue
|
||
|
||
---
|
||
|
||
## 第一阶段:MVP 任务总表(73 个)
|
||
|
||
| # | 任务名 | 端 | 预估 | 状态 |
|
||
|---|--------|:--:|:----:|:--:|
|
||
| | **环境搭建** | | | |
|
||
| 001 | 初始化 FastAPI 项目 + main.py + health 接口 | 后端 | 0.25d | ✅ 已完成 |
|
||
| 002 | 配置 MySQL 连接 + SQLAlchemy session | 后端 | 0.25d | ✅ 已完成 |
|
||
| 003 | 配置 MinIO 客户端 | 后端 | 0.25d | ✅ 已完成 |
|
||
| 004 | Alembic 初始化 + 第一个迁移脚本 | 后端 | 0.25d | ✅ 已完成 |
|
||
| 005 | Docker Compose 编排(MySQL + MinIO) | 后端 | 0.25d | ✅ 已完成 |
|
||
| 006 | 初始化 Vue3 + Vite 项目 | 前端 | 0.25d | ✅ 已完成 |
|
||
| 007 | 安装 Ant Design Vue + 全局注册 | 前端 | 0.25d | ✅ 已完成 |
|
||
| 008 | 安装 Vue Router + 配置路由结构 | 前端 | 0.25d | ✅ 已完成 |
|
||
| 009 | 安装 Pinia + 创建根 store | 前端 | 0.25d | ✅ 已完成 |
|
||
| 010 | 安装 Axios + 创建 API 客户端 base.ts | 前端 | 0.25d | ✅ 已完成 |
|
||
| 011 | 定义全局 CSS 变量 | 前端 | 0.25d | ✅ 已完成 |
|
||
| | **数据库建表(3 个)** | | | |
|
||
| 012 | 创建 template 表 + SQLAlchemy Model | 后端 | 0.25d | ✅ 已完成 |
|
||
| 013 | 创建 template_block 表 + SQLAlchemy Model | 后端 | 0.25d | ✅ 已完成 |
|
||
| 014 | 创建 block_config 表 + SQLAlchemy Model(含 unique 约束) | 后端 | 0.25d | ✅ 已完成 |
|
||
| | **模板上传** | | | |
|
||
| 015 | 实现文件接收 + .docx 格式校验 + 大小校验 | 后端 | 0.25d | ✅ 已完成 |
|
||
| 016 | 实现文件存储到 MinIO | 后端 | 0.25d | ✅ 已完成 |
|
||
| 017 | 实现 template 表 insert | 后端 | 0.25d | ✅ 已完成 |
|
||
| 018 | 组装上传接口 `POST /api/templates/upload` | 后端 | 0.25d | ✅ 已完成 |
|
||
| | **Word 解析** | | | |
|
||
| 019 | 实现 docx 文件打开 + 逐段落遍历 | 后端 | 0.25d | ⏳ 未完成 |
|
||
| 020 | 实现标题识别(Heading 1-6)→ type=heading | 后端 | 0.25d | ⏳ 未完成 |
|
||
| 021 | 实现段落识别 → type=paragraph | 后端 | 0.25d | ⏳ 未完成 |
|
||
| 022 | 实现表格识别 + 行数列数提取 → type=table | 后端 | 0.25d | ⏳ 未完成 |
|
||
| 023 | 实现 block_id 生成器(顺序编号) | 后端 | 0.25d | ⏳ 未完成 |
|
||
| 024 | 实现层级构建(parent_block_id)+ 结构树 tree 输出 | 后端 | 0.25d | ⏳ 未完成 |
|
||
| 025 | 将解析结果批量写入 template_block 表 | 后端 | 0.25d | ⏳ 未完成 |
|
||
| | **HTML 预览生成** | | | |
|
||
| 026 | 标题 → `<h2 data-block-id>` 转换 + 居中加粗样式 | 后端 | 0.25d | ⏳ 未完成 |
|
||
| 027 | 段落 → `<p data-block-id>` 转换 + 首行缩进样式 | 后端 | 0.25d | ⏳ 未完成 |
|
||
| 028 | 表格 → `<table data-block-id>` 转换 + 边框样式 | 后端 | 0.25d | ⏳ 未完成 |
|
||
| 029 | 拼接完整 HTML 字符串(带内联 CSS) | 后端 | 0.25d | ⏳ 未完成 |
|
||
| | **查询 + 配置接口** | | | |
|
||
| 030 | 实现 `GET /api/templates/{id}` 组装全部数据 | 后端 | 0.5d | ⏳ 未完成 |
|
||
| 031 | 实现 `POST /api/templates/{id}/blocks/{blockId}/config` upsert | 后端 | 0.25d | ⏳ 未完成 |
|
||
| 032 | 实现 `GET /api/data-sources` 返回预设列表 | 后端 | 0.25d | ⏳ 未完成 |
|
||
| 033 | 实现 `POST /api/data-sources` 新增数据源 | 后端 | 0.25d | ⏳ 未完成 |
|
||
| | **四栏布局** | | | |
|
||
| 034 | 实现四栏 CSS Grid 布局 | 前端 | 0.5d | ⏳ 未完成 |
|
||
| 035 | 实现左侧菜单 shell 组件 | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 036 | 实现顶部工具栏 shell 组件 | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 037 | 实现配置面板 shell 组件 | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 038 | 实现预览区 shell 组件(A4 纸效果) | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 039 | 实现结构树 shell 组件 | 前端 | 0.25d | ⏳ 未完成 |
|
||
| | **左侧菜单** | | | |
|
||
| 040 | 菜单数据模型(JSON)+ 子菜单配置 | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 041 | 菜单展开/收起交互 + 箭头旋转动画 | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 042 | 菜单选中高亮(蓝色左侧竖条) | 前端 | 0.25d | ⏳ 未完成 |
|
||
| | **顶部工具栏** | | | |
|
||
| 043 | 面包屑导航渲染 | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 044 | 模板名称 + 版本号标签展示 | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 045 | 保存状态指示器(已保存/未保存 圆点切换) | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 046 | 操作按钮区(预览/保存/生成测试/导出模板/全屏) | 前端 | 0.25d | ⏳ 未完成 |
|
||
| | **Word 预览区** | | | |
|
||
| 047 | v-html 渲染后端 HTML + 为 [data-block-id] 添加 doc-block class | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 048 | 点击事件委托 + block_id 提取 | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 049 | 选中高亮(蓝色虚线 outline + 浅蓝背景) | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 050 | 区域类型颜色映射(蓝/黄/绿/紫/灰)+ 保存后更新 | 前端 | 0.5d | ⏳ 未完成 |
|
||
| 051 | block_id 标签 absolute 定位 + hover 显示 | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 052 | 显示/隐藏标签 toggle 开关 | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 053 | 缩放控制(70%/100%/150% scale 切换) | 前端 | 0.25d | ⏳ 未完成 |
|
||
| | **结构树** | | | |
|
||
| 054 | 递归树组件 + 数据绑定 | 前端 | 0.5d | ⏳ 未完成 |
|
||
| 055 | 展开/折叠交互 + 图标 | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 056 | 状态圆点(已配置绿/待审核黄/已禁用红/未配置灰) | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 057 | 点击树节点 → 预览区 scrollIntoView + 闪烁高亮 | 前端 | 0.5d | ⏳ 未完成 |
|
||
| | **配置面板** | | | |
|
||
| 058 | 区域名称 input(默认取 text_preview) | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 059 | 区域类型 select | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 060 | 数据来源 tag chips 多选组件 | 前端 | 0.5d | ⏳ 未完成 |
|
||
| 061 | 提示词 textarea + 字数统计 | 前端 | 0.5d | ⏳ 未完成 |
|
||
| 062 | 输出格式 select | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 063 | 是否需要审核 radio | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 064 | 备注 textarea + 字数统计 | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 065 | 保存按钮 + loading 状态 + 成功/失败提示 | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 066 | 未选中区域时的空状态占位提示 | 前端 | 0.25d | ⏳ 未完成 |
|
||
| | **Pinia Store** | | | |
|
||
| 067 | templateStore | 前端 | 0.5d | ⏳ 未完成 |
|
||
| 068 | selectionStore | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 069 | uiStore | 前端 | 0.25d | ⏳ 未完成 |
|
||
| | **三区联动** | | | |
|
||
| 070 | watch selectedBlockId → 配置面板加载 | 前端 | 0.5d | ⏳ 未完成 |
|
||
| 071 | watch selectedBlockId → 结构树节点高亮 | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 072 | 页面初始化 loading(全页遮罩 + a-spin) | 前端 | 0.25d | ⏳ 未完成 |
|
||
| 073 | 加载失败错误页 + 重新加载按钮 | 前端 | 0.25d | ⏳ 未完成 |
|
||
| | **总计** | | **~18.25d** | |
|
||
|
||
---
|
||
|
||
## 第一阶段 MVP 任务卡(逐个)
|
||
|
||
---
|
||
|
||
### 环境搭建(001–011)
|
||
|
||
---
|
||
|
||
#### 001 · 初始化 FastAPI 项目 + main.py + health 接口
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/main.py`
|
||
|
||
**做什么**
|
||
- 创建 `app/` 目录,创建 `app/main.py`
|
||
- 创建 FastAPI 实例,添加 `GET /health` 返回 `{"status": "ok"}`
|
||
- 添加 CORS 中间件(允许前端 localhost 访问)
|
||
- 创建目录结构:`api/`, `models/`, `services/`, `schemas/`
|
||
|
||
**验收**
|
||
- `uvicorn app.main:app --reload` 启动成功
|
||
- 访问 `/docs` 显示 Swagger 页面
|
||
- 访问 `/health` 返回 200
|
||
|
||
---
|
||
|
||
#### 002 · 配置 MySQL 连接 + SQLAlchemy session
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/database.py`
|
||
|
||
**做什么**
|
||
- 创建 `app/database.py`
|
||
- 配置 SQLAlchemy engine(读取环境变量 `DB_HOST/DB_PORT/DB_USER/DB_PASS/DB_NAME`)
|
||
- 创建 `SessionLocal` 工厂
|
||
- 创建 `Base` 基类
|
||
- 创建 `get_db` 依赖注入函数
|
||
|
||
**验收**
|
||
- 应用启动时不会报数据库连接错误
|
||
|
||
---
|
||
|
||
#### 003 · 配置 MinIO 客户端
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/services/storage.py`
|
||
|
||
**做什么**
|
||
- 创建 `app/services/storage.py`
|
||
- 初始化 `minio.Minio` 客户端
|
||
- 实现 `upload_file(bucket, file_path, content)` 函数
|
||
- 实现 `download_file(bucket, file_path)` 函数
|
||
- 实现 `ensure_bucket(bucket_name)` 自动创建 bucket
|
||
|
||
**验收**
|
||
- MinIO 未启动时降级为本地文件存储
|
||
|
||
---
|
||
|
||
#### 004 · Alembic 初始化 + 第一个迁移脚本
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`alembic.ini`, `migrations/`
|
||
|
||
**做什么**
|
||
- 运行 `alembic init alembic`
|
||
- 配置 `alembic.ini` 中的数据库连接
|
||
- 配置 `env.py` 导入 `Base`
|
||
- 生成第一个空迁移
|
||
|
||
**验收**
|
||
- `alembic upgrade head` 成功执行
|
||
- `alembic history` 显示初始迁移
|
||
|
||
---
|
||
|
||
#### 005 · Docker Compose 编排
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`docker-compose.yml`
|
||
|
||
**做什么**
|
||
- 创建 `docker-compose.yml`
|
||
- MySQL 8.0 服务(端口 3306,初始化数据库 `ai_doc_template`)
|
||
- MinIO 服务(端口 9000 + 9001 console)
|
||
- 网络配置,服务间可通信
|
||
|
||
**验收**
|
||
- `docker-compose up -d` 启动成功
|
||
|
||
---
|
||
|
||
#### 006 · 初始化 Vue3 + Vite 项目
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:前端项目根目录
|
||
|
||
**做什么**
|
||
- 运行 `npm create vite@latest`(Vue3 + TypeScript)
|
||
- 安装依赖 `npm install`
|
||
- 确认 `npm run dev` 可启动
|
||
- 清理默认 App.vue 内容,保留 Hello World
|
||
|
||
**验收**
|
||
- `npm run dev` 启动成功
|
||
|
||
---
|
||
|
||
#### 007 · 安装 Ant Design Vue + 全局注册
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`src/main.ts`
|
||
|
||
**做什么**
|
||
- 运行 `npm install ant-design-vue`
|
||
- 在 `main.ts` 中 `import Antd from 'ant-design-vue'` + `app.use(Antd)`
|
||
- 全局导入样式:`import 'ant-design-vue/dist/reset.css'`
|
||
- 验证:在 App.vue 中使用一个 `<a-button>` 看能否渲染
|
||
|
||
**验收**
|
||
- Ant Design Vue 按钮可正常显示
|
||
- 无控制台报错
|
||
|
||
---
|
||
|
||
#### 008 · 安装 Vue Router + 配置路由结构
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`src/router/index.ts`
|
||
|
||
**做什么**
|
||
- 运行 `npm install vue-router@4`
|
||
- 创建 `src/router/index.ts`
|
||
- 配置路由:`/` → TemplateCenter, `/template/:id` → TemplateEdit
|
||
- 在 `main.ts` 中 `app.use(router)`
|
||
- 添加 `router-view` 到 App.vue
|
||
|
||
**验收**
|
||
- 访问 `/` 显示模板中心页
|
||
- 访问 `/template/1` 显示模板编辑页
|
||
|
||
---
|
||
|
||
#### 009 · 安装 Pinia + 创建根 store
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`src/stores/index.ts`
|
||
|
||
**做什么**
|
||
- 运行 `npm install pinia`
|
||
- 在 `main.ts` 中 `app.use(createPinia())`
|
||
- 创建一个简单的 counter store 验证可用
|
||
|
||
**验收**
|
||
- Pinia 正常注册,无控制台报错
|
||
|
||
---
|
||
|
||
#### 010 · 安装 Axios + 创建 API 客户端
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`src/api/base.ts`
|
||
|
||
**做什么**
|
||
- 运行 `npm install axios`
|
||
- 创建 `src/api/base.ts`
|
||
- 创建 axios 实例,baseURL 设为 `/api`
|
||
- 添加请求/响应拦截器
|
||
|
||
**验收**
|
||
- 调用 `api.get('/health')` 能收到后端响应
|
||
|
||
---
|
||
|
||
#### 011 · 定义全局 CSS 变量
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`src/styles/variables.css`
|
||
|
||
**做什么**
|
||
- 创建 `src/styles/variables.css`
|
||
- 定义 `:root` 变量:
|
||
|
||
```css
|
||
:root {
|
||
--primary: #5b5bd6;
|
||
--primary-hover: #4a4ac0;
|
||
--primary-soft: #eeeefb;
|
||
--text: #1a1d24;
|
||
--text-2: #5b626e;
|
||
--text-3: #9aa1ad;
|
||
--border: #e0e2e6;
|
||
--border-light: #eaecef;
|
||
--bg: #f5f6f8;
|
||
--bg-card: #fff;
|
||
--bg-soft: #f0f1f3;
|
||
--success: #1a8c4a;
|
||
--warn: #d48a00;
|
||
--danger: #d33;
|
||
--font: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
|
||
--fs-body: 13px;
|
||
--fs-sm: 12px;
|
||
--radius: 6px;
|
||
--sidebar-w: 220px;
|
||
--config-panel-w: 380px;
|
||
--tree-panel-w: 240px;
|
||
--toolbar-h: 48px;
|
||
}
|
||
```
|
||
|
||
- 在 `main.ts` 中 import
|
||
|
||
**验收**
|
||
- 全局样式变量可在任意组件中使用 `var(--primary)`
|
||
|
||
---
|
||
|
||
### 数据库建表(012–014)
|
||
|
||
---
|
||
|
||
#### 012 · 创建 template 表 + Model
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/models/template.py`
|
||
|
||
**做什么**
|
||
- 定义 `Template` Model(字段见附录)
|
||
- 生成 Alembic 迁移并执行
|
||
|
||
**验收**
|
||
- 表创建成功,可通过 Model 插入一条记录
|
||
|
||
---
|
||
|
||
#### 013 · 创建 template_block 表 + Model
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/models/template_block.py`
|
||
|
||
**做什么**
|
||
- 定义 `TemplateBlock` Model
|
||
- 外键关联到 `template.id`
|
||
- 生成迁移并执行
|
||
|
||
**验收**
|
||
- 插入数据时外键约束生效
|
||
|
||
---
|
||
|
||
#### 014 · 创建 block_config 表 + Model
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/models/block_config.py`
|
||
|
||
**做什么**
|
||
- 定义 `BlockConfig` Model
|
||
- 添加唯一约束 `(template_id, block_id)`
|
||
- 生成迁移并执行
|
||
|
||
**验收**
|
||
- 重复 `(template_id, block_id)` 插入时更新而非报错
|
||
|
||
---
|
||
|
||
### 模板上传(015–018)
|
||
|
||
---
|
||
|
||
#### 015 · 文件接收 + 格式校验 + 大小校验
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/services/template_service.py` 中的 `validate_file()`
|
||
|
||
**做什么**
|
||
- 校验扩展名为 `.docx`
|
||
- 校验 Content-Type
|
||
- 校验文件大小 ≤ 50MB
|
||
|
||
**验收**
|
||
- 上传 `.txt` 返回 400
|
||
- 上传 >50MB 返回 413
|
||
|
||
---
|
||
|
||
#### 016 · 文件存储到 MinIO
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/services/template_service.py` 中的 `save_file()`
|
||
|
||
**做什么**
|
||
- 调用 storage 服务的 upload_file
|
||
- 路径格式:`/templates/{template_id}/{filename}`
|
||
- MinIO 不可用时降级本地存储
|
||
|
||
**验收**
|
||
- 文件保存到指定路径
|
||
|
||
---
|
||
|
||
#### 017 · template 表 insert
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/services/template_service.py` 中的 `create_template_record()`
|
||
|
||
**做什么**
|
||
- 写入 template 表
|
||
- 返回创建的 template 对象
|
||
|
||
**验收**
|
||
- 数据库有正确记录
|
||
|
||
---
|
||
|
||
#### 018 · 组装上传接口
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/api/templates.py` 中的 upload 路由
|
||
|
||
**做什么**
|
||
- 创建 `app/api/templates.py`
|
||
- 实现 `POST /api/templates/upload` 路由
|
||
- 调用 015→016→017 三个步骤
|
||
|
||
**验收**
|
||
- Postman 上传成功,返回 `{"template_id": 1, "name": "...", "status": "uploaded"}`
|
||
|
||
---
|
||
|
||
### Word 解析(019–025)
|
||
|
||
---
|
||
|
||
#### 019 · docx 文件打开 + 逐段落遍历
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/services/doc_parser.py` 中的 `parse_document()`
|
||
|
||
**做什么**
|
||
- 使用 python-docx 打开文件
|
||
- 遍历 `document.paragraphs`
|
||
|
||
**验收**
|
||
- 返回段落列表
|
||
|
||
---
|
||
|
||
#### 020 · 标题识别(Heading 1-6)
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/services/doc_parser.py` 中的 `classify_paragraph()`
|
||
|
||
**做什么**
|
||
- 判断 `paragraph.style.name` 是否以 "Heading" 开头
|
||
- 提取标题级别和文本
|
||
|
||
**验收**
|
||
- Heading 1 → level 1
|
||
- Heading 2 → level 2
|
||
|
||
---
|
||
|
||
#### 021 · 段落识别
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/services/doc_parser.py`
|
||
|
||
**做什么**
|
||
- 非标题段落 → type="paragraph"
|
||
- 提取文本和样式名称
|
||
|
||
**验收**
|
||
- 正文段落 type=paragraph
|
||
|
||
---
|
||
|
||
#### 022 · 表格识别 + 行数列数提取
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/services/doc_parser.py` 中的 `parse_tables()`
|
||
|
||
**做什么**
|
||
- 遍历 `document.tables`
|
||
- 提取行数、列数、表头
|
||
|
||
**验收**
|
||
- 表格行数列数正确
|
||
|
||
---
|
||
|
||
#### 023 · block_id 生成器
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/services/doc_parser.py` 中的 `generate_block_id()`
|
||
|
||
**做什么**
|
||
- 格式:`block_001`, `block_002`, ... 递增
|
||
|
||
**验收**
|
||
- 输入 1 → `block_001`
|
||
- 输入 12 → `block_012`
|
||
|
||
---
|
||
|
||
#### 024 · 层级构建 + 结构树输出
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/services/doc_parser.py` 中的 `build_tree()`
|
||
|
||
**做什么**
|
||
- 根据 heading level 确定父子关系
|
||
- 填充 `parent_block_id`
|
||
- 输出嵌套 tree 结构
|
||
|
||
**验收**
|
||
- 三级标题层级正确
|
||
- 表格归属于正确的父章节
|
||
|
||
---
|
||
|
||
#### 025 · 解析结果批量写入 template_block 表
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/services/doc_parser.py` 中的 `save_blocks()`
|
||
|
||
**做什么**
|
||
- 批量 insert 到 template_block 表
|
||
- 先删除旧记录(重解析场景)
|
||
|
||
**验收**
|
||
- 数据库有对应的 block 记录
|
||
|
||
---
|
||
|
||
### HTML 预览生成(026–029)
|
||
|
||
---
|
||
|
||
#### 026 · 标题 → `<h2 data-block-id>` 转换
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/services/html_generator.py` 中的 `render_heading()`
|
||
|
||
**做什么**
|
||
- 输出 `<h2 data-block-id="block_002" style="...">标题内容</h2>`
|
||
|
||
**验收**
|
||
- 标签带 data-block-id,样式居中加粗
|
||
|
||
---
|
||
|
||
#### 027 · 段落 → `<p data-block-id>` 转换
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/services/html_generator.py` 中的 `render_paragraph()`
|
||
|
||
**做什么**
|
||
- 输出 `<p data-block-id="block_003" style="text-indent:2em;...">段落内容</p>`
|
||
|
||
**验收**
|
||
- 首行缩进,行高 1.8
|
||
|
||
---
|
||
|
||
#### 028 · 表格 → `<table data-block-id>` 转换
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/services/html_generator.py` 中的 `render_table()`
|
||
|
||
**做什么**
|
||
- 输出完整 HTML `<table>` 带 data-block-id
|
||
|
||
**验收**
|
||
- 表格正确渲染,边框可见
|
||
|
||
---
|
||
|
||
#### 029 · 拼接完整 HTML 字符串
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/services/html_generator.py` 中的 `generate_preview_html()`
|
||
|
||
**做什么**
|
||
- 按 sort_order 排序
|
||
- 遍历 blocks 调用对应的 render 函数
|
||
- 拼接为完整 HTML
|
||
|
||
**验收**
|
||
- 返回字符串可被前端 v-html 渲染
|
||
|
||
---
|
||
|
||
### 查询 + 配置接口(030–033)
|
||
|
||
---
|
||
|
||
#### 030 · 模板详情查询接口
|
||
|
||
**端**:后端 **预估**:0.5d **产出**:`app/api/templates.py` 中的 GET 路由
|
||
|
||
**做什么**
|
||
- 实现 `GET /api/templates/{template_id}`
|
||
- 查询 template 表 + template_block 表 + block_config 表
|
||
- 调用 html_generator 生成 preview_html
|
||
- 返回完整 JSON
|
||
|
||
**验收**
|
||
- 返回数据包含 template, preview_html, blocks, tree, configs
|
||
|
||
---
|
||
|
||
#### 031 · 保存区域配置接口
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/api/blocks.py` 中的 POST 路由
|
||
|
||
**做什么**
|
||
- 实现 `POST /api/templates/{template_id}/blocks/{block_id}/config`
|
||
- upsert 语义
|
||
|
||
**验收**
|
||
- 保存后数据库记录正确
|
||
- 重复调用更新记录
|
||
|
||
---
|
||
|
||
#### 032 · 获取数据源列表
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/api/data_sources.py` 中的 GET 路由
|
||
|
||
**做什么**
|
||
- 返回预设列表:财务部、运行部、生技部、安全监察部等
|
||
|
||
**验收**
|
||
- 返回 JSON 数组
|
||
|
||
---
|
||
|
||
#### 033 · 新增数据源
|
||
|
||
**端**:后端 **预估**:0.25d **产出**:`app/api/data_sources.py` 中的 POST 路由
|
||
|
||
**做什么**
|
||
- 接收 `{name, category}` 并存储
|
||
|
||
**验收**
|
||
- 新增后 GET 列表包含新数据源
|
||
|
||
---
|
||
|
||
### 四栏布局(034–039)
|
||
|
||
---
|
||
|
||
#### 034 · 四栏 CSS Grid 布局
|
||
|
||
**端**:前端 **预估**:0.5d **产出**:`src/views/TemplateEdit.vue`
|
||
|
||
**做什么**
|
||
```css
|
||
.layout {
|
||
display: grid;
|
||
grid-template-columns: var(--sidebar-w) var(--config-panel-w) 1fr var(--tree-panel-w);
|
||
grid-template-rows: var(--toolbar-h) 1fr;
|
||
height: 100vh;
|
||
}
|
||
```
|
||
|
||
- 工具栏 grid-column: 1 / -1
|
||
- 左侧菜单 grid-column: 1
|
||
- 配置面板 grid-column: 2
|
||
- 预览区 grid-column: 3
|
||
- 结构树 grid-column: 4
|
||
|
||
**验收**
|
||
- 页面渲染为四栏布局
|
||
- 各区域宽度正确
|
||
|
||
---
|
||
|
||
#### 035 · 左侧菜单 shell
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`src/components/TemplateEdit/LeftMenu.vue`
|
||
|
||
**做什么**
|
||
- 固定宽度 220px
|
||
- overflow-y: auto, border-right, 白色背景
|
||
|
||
**验收**
|
||
- 渲染在正确位置
|
||
|
||
---
|
||
|
||
#### 036 · 顶部工具栏 shell
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`src/components/TemplateEdit/TopToolbar.vue`
|
||
|
||
**做什么**
|
||
- 固定高度 48px, flex 布局, border-bottom
|
||
|
||
**验收**
|
||
- 渲染在顶部
|
||
|
||
---
|
||
|
||
#### 037 · 配置面板 shell
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`src/components/TemplateEdit/ConfigPanel.vue`
|
||
|
||
**做什么**
|
||
- 固定宽度 380px, overflow-y: auto
|
||
- border-right: 1px solid
|
||
|
||
**验收**
|
||
- 渲染在正确位置
|
||
|
||
---
|
||
|
||
#### 038 · 预览区 shell
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`src/components/TemplateEdit/WordPreview.vue`
|
||
|
||
**做什么**
|
||
- flex: 1, overflow-y: auto, 背景色 `#f0f1f3`
|
||
- 内部 A4 纸容器:794px 宽, 白色背景, box-shadow
|
||
|
||
**验收**
|
||
- A4 纸效果可见
|
||
|
||
---
|
||
|
||
#### 039 · 结构树 shell
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`src/components/TemplateEdit/StructureTree.vue`
|
||
|
||
**做什么**
|
||
- 固定宽度 240px, overflow-y: auto
|
||
- border-left: 1px solid
|
||
|
||
**验收**
|
||
- 渲染在右侧
|
||
|
||
---
|
||
|
||
### 左侧菜单(040–042)
|
||
|
||
---
|
||
|
||
#### 040 · 菜单数据模型
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`src/components/TemplateEdit/menu-data.ts`
|
||
|
||
**做什么**
|
||
```ts
|
||
interface MenuItem {
|
||
label: string
|
||
icon: string
|
||
children?: MenuItem[]
|
||
route?: string
|
||
}
|
||
```
|
||
- 完整菜单数据(模板中心/生成文档/历史记录/系统配置 及子菜单)
|
||
|
||
**验收**
|
||
- 数据结构可被菜单组件消费
|
||
|
||
---
|
||
|
||
#### 041 · 菜单展开/收起 + 箭头动画
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`LeftMenu.vue`
|
||
|
||
**做什么**
|
||
- 渲染菜单树
|
||
- 有子菜单的项显示箭头图标
|
||
- 点击切换展开/收起,箭头旋转动画
|
||
|
||
**验收**
|
||
- 点击展开子菜单,箭头旋转 90°,动画流畅
|
||
|
||
---
|
||
|
||
#### 042 · 菜单选中高亮
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`LeftMenu.vue`
|
||
|
||
**做什么**
|
||
- 当前选中菜单添加 `active` class
|
||
- 高亮样式:`background: #eeeefb; color: #5b5bd6;`
|
||
- 左侧竖条 3px:`border-left: 3px solid #5b5bd6;`
|
||
|
||
**验收**
|
||
- 点击菜单项高亮,切换时旧高亮移除
|
||
|
||
---
|
||
|
||
### 顶部工具栏(043–046)
|
||
|
||
---
|
||
|
||
#### 043 · 面包屑导航
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`TopToolbar.vue`
|
||
|
||
**做什么**
|
||
- 显示面包屑:`模板中心 / 模板名称 / 区域配置`
|
||
- 每段用 `/` 分隔,最后一段加粗
|
||
|
||
**验收**
|
||
- 面包屑渲染正确
|
||
|
||
---
|
||
|
||
#### 044 · 模板名称 + 版本号
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`TopToolbar.vue`
|
||
|
||
**做什么**
|
||
- 从 Pinia store 读取模板名称显示
|
||
- 版本号显示为灰色小标签
|
||
|
||
**验收**
|
||
- 模板名称正确读取
|
||
|
||
---
|
||
|
||
#### 045 · 保存状态指示器
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`TopToolbar.vue`
|
||
|
||
**做什么**
|
||
- 小圆点 + 文字:绿色"已保存" / 黄色"未保存"
|
||
- 从 uiStore 读取 saveStatus
|
||
|
||
**验收**
|
||
- 初始"未保存",保存成功后变"已保存"
|
||
|
||
---
|
||
|
||
#### 046 · 操作按钮区
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`TopToolbar.vue`
|
||
|
||
**做什么**
|
||
- 使用 Ant Design Vue `<a-button size="small">`
|
||
- 按钮:预览、保存(primary)、生成测试、导出模板、全屏
|
||
- 按钮间距 8px
|
||
|
||
**验收**
|
||
- 5 个按钮分布整齐,保存按钮高亮
|
||
|
||
---
|
||
|
||
### Word 预览区(047–053)
|
||
|
||
---
|
||
|
||
#### 047 · v-html 渲染后端 HTML
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`WordPreview.vue`
|
||
|
||
**做什么**
|
||
- `<div v-html="previewHtml" class="doc-content" @click="handleClick"></div>`
|
||
- 在 mounted 中为所有 `[data-block-id]` 元素添加 class `doc-block`
|
||
|
||
**验收**
|
||
- HTML 内容渲染正确
|
||
|
||
---
|
||
|
||
#### 048 · 点击事件委托 + block_id 提取
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`WordPreview.vue` handleClick
|
||
|
||
**做什么**
|
||
```ts
|
||
function handleClick(event: MouseEvent) {
|
||
const target = (event.target as HTMLElement).closest('[data-block-id]')
|
||
if (!target) { selectionStore.cancelSelection(); return }
|
||
const blockId = target.getAttribute('data-block-id')
|
||
selectionStore.selectBlock(blockId)
|
||
}
|
||
```
|
||
|
||
**验收**
|
||
- 点击段落提取到正确的 block_id
|
||
- 点击空白区域取消选中
|
||
|
||
---
|
||
|
||
#### 049 · 选中高亮
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`WordPreview.vue`
|
||
|
||
**做什么**
|
||
- 选中 block 添加 class `active-region`
|
||
- CSS:`outline: 2px solid #5b5bd6; outline-offset: -2px; background: #f0f0ff;`
|
||
|
||
**验收**
|
||
- 选中后蓝色虚线边框可见
|
||
|
||
---
|
||
|
||
#### 050 · 区域类型颜色映射
|
||
|
||
**端**:前端 **预估**:0.5d **产出**:`WordPreview.vue`
|
||
|
||
**做什么**
|
||
- 根据 region_type 添加颜色 class:
|
||
- `ai_generate` → 浅蓝 `#e8f0fe` + 蓝色左边框
|
||
- `manual` → 浅黄 `#fef7e0` + 黄色左边框
|
||
- `fixed` → 浅绿 `#e6f4ea` + 绿色左边框
|
||
- `table` → 浅紫 `#f3e8ff` + 紫色左边框
|
||
- 保存配置后立即更新
|
||
|
||
**验收**
|
||
- 保存后预览区颜色变化正确
|
||
|
||
---
|
||
|
||
#### 051 · block_id 标签
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`WordPreview.vue`
|
||
|
||
**做什么**
|
||
- 每个 block 左下角显示标签 `block_003`
|
||
- 标签样式:`position: absolute; left: -80px; font-size: 11px;`
|
||
- hover 时透明度 0→1(CSS transition)
|
||
|
||
**验收**
|
||
- 鼠标移入时标签可见
|
||
|
||
---
|
||
|
||
#### 052 · 显示/隐藏标签 toggle
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`TopToolbar.vue` + `WordPreview.vue`
|
||
|
||
**做什么**
|
||
- 工具栏添加 Ant Design Vue `<a-switch>`
|
||
- 标签:`显示区域标识`
|
||
- 切换时更新 uiStore.showLabels
|
||
|
||
**验收**
|
||
- 关闭后所有标签隐藏
|
||
|
||
---
|
||
|
||
#### 053 · 缩放控制
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`WordPreview.vue`
|
||
|
||
**做什么**
|
||
- 工具栏缩放控制:`<a-button>-</a-button> 100% <a-button>+</a-button>`
|
||
- 级别:70% / 100% / 150%
|
||
- 对 `.doc-content` 应用 `transform: scale(N)`
|
||
|
||
**验收**
|
||
- 缩放后内容清晰,交互正常
|
||
|
||
---
|
||
|
||
### 结构树(054–057)
|
||
|
||
---
|
||
|
||
#### 054 · 递归树组件 + 数据绑定
|
||
|
||
**端**:前端 **预估**:0.5d **产出**:`StructureTree.vue`
|
||
|
||
**做什么**
|
||
- 递归组件,接收 tree 数据
|
||
- 渲染文档章节层级
|
||
|
||
**验收**
|
||
- 树结构与解析结果一致,递归渲染无报错
|
||
|
||
---
|
||
|
||
#### 055 · 展开/折叠 + 图标
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`StructureTree.vue`
|
||
|
||
**做什么**
|
||
- 箭头旋转 90° 表示展开
|
||
- 图标:heading→📄, paragraph→📝, table→📊
|
||
|
||
**验收**
|
||
- 点击箭头展开/折叠,图标正确
|
||
|
||
---
|
||
|
||
#### 056 · 状态圆点
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`StructureTree.vue`
|
||
|
||
**做什么**
|
||
- 从 Pinia store 的 configs 读取配置
|
||
- 圆点:已配置=绿色 / 待审核=黄色 / 已禁用=红色 / 未配置=灰色
|
||
- 圆点样式:`width: 8px; height: 8px; border-radius: 50%;`
|
||
|
||
**验收**
|
||
- 保存后圆点变为绿色
|
||
|
||
---
|
||
|
||
#### 057 · 树节点 → 预览区滚动定位
|
||
|
||
**端**:前端 **预估**:0.5d **产出**:`StructureTree.vue` + `WordPreview.vue`
|
||
|
||
**做什么**
|
||
- 点击树节点:
|
||
1. `selectionStore.selectBlock(blockId)`
|
||
2. `document.querySelector([data-block-id="${blockId}"])?.scrollIntoView({ behavior: 'smooth', block: 'center' })`
|
||
- 闪烁效果:添加 class `flash`,0.3s 后移除
|
||
|
||
**验收**
|
||
- 点击树节点后预览区滚动到正确位置
|
||
|
||
---
|
||
|
||
### 配置面板(058–066)
|
||
|
||
---
|
||
|
||
#### 058 · 区域名称 input
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`ConfigPanel.vue`
|
||
|
||
**做什么**
|
||
- `<a-input v-model:value="form.regionName" placeholder="区域名称" :disabled="!selectedBlockId" />`
|
||
- 选中 block 时默认填充 text_preview
|
||
|
||
**验收**
|
||
- 选中后显示 block 名称,可编辑
|
||
|
||
---
|
||
|
||
#### 059 · 区域类型 select
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`ConfigPanel.vue`
|
||
|
||
**做什么**
|
||
- `<a-select v-model:value="form.regionType">`
|
||
- 选项:AI 生成区域 / 人工填写区域 / 固定区域 / 表格生成区域
|
||
|
||
**验收**
|
||
- 切换选项值变化
|
||
|
||
---
|
||
|
||
#### 060 · 数据来源 tag chips
|
||
|
||
**端**:前端 **预估**:0.5d **产出**:`ConfigPanel.vue`
|
||
|
||
**做什么**
|
||
- 已选项显示为 `<a-tag closable @close="removeSource(item)">财务部</a-tag>`
|
||
- 末尾" + 添加"按钮,点击弹出 `<a-select>` 下拉
|
||
- 已选的不可重复添加
|
||
|
||
**验收**
|
||
- 标签显示正确,可删除可添加
|
||
|
||
---
|
||
|
||
#### 061 · 提示词 textarea + 字数统计
|
||
|
||
**端**:前端 **预估**:0.5d **产出**:`ConfigPanel.vue`
|
||
|
||
**做什么**
|
||
- `<a-textarea v-model:value="form.prompt" :rows="4" :maxlength="1000" show-count />`
|
||
- 超过 850 字时数字变橙色,超过 1000 变红
|
||
|
||
**验收**
|
||
- 输入字数实时统计
|
||
|
||
---
|
||
|
||
#### 062 · 输出格式 select
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`ConfigPanel.vue`
|
||
|
||
**做什么**
|
||
- `<a-select v-model:value="form.outputFormat">`
|
||
- 选项:正式报告段落 / 分条说明 / 表格数据 / JSON 数据 / 标题文本
|
||
|
||
**验收**
|
||
- 选项切换正常
|
||
|
||
---
|
||
|
||
#### 063 · 是否需要审核 radio
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`ConfigPanel.vue`
|
||
|
||
**做什么**
|
||
- `<a-radio-group v-model:value="form.needReview">`
|
||
- `<a-radio :value="true">是</a-radio>`
|
||
- `<a-radio :value="false">否</a-radio>`
|
||
|
||
**验收**
|
||
- 切换值变化
|
||
|
||
---
|
||
|
||
#### 064 · 备注 textarea
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`ConfigPanel.vue`
|
||
|
||
**做什么**
|
||
- `<a-textarea v-model:value="form.remark" :rows="2" :maxlength="200" show-count />`
|
||
|
||
**验收**
|
||
- 输入正常,字数统计正确
|
||
|
||
---
|
||
|
||
#### 065 · 保存按钮 + 流程
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`ConfigPanel.vue`
|
||
|
||
**做什么**
|
||
- `<a-button type="primary" @click="saveConfig" :loading="saving" style="width:100%">保存该区域配置</a-button>`
|
||
- 点击后:
|
||
1. `saving = true`
|
||
2. 调用 POST 接口
|
||
3. 成功 → `saving = false` + `message.success('保存成功')`
|
||
4. 失败 → `saving = false` + `message.error('保存失败')`
|
||
|
||
**验收**
|
||
- 保存成功/失败有对应提示
|
||
|
||
---
|
||
|
||
#### 066 · 未选中空状态
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`ConfigPanel.vue`
|
||
|
||
**做什么**
|
||
- `selectedBlockId === null` 时显示:
|
||
- 居中图标 + "点击文档中的区域开始配置"
|
||
- 隐藏所有表单字段
|
||
|
||
**验收**
|
||
- 初始显示空状态,选中后显示表单
|
||
|
||
---
|
||
|
||
### Pinia Store(067–069)
|
||
|
||
---
|
||
|
||
#### 067 · templateStore
|
||
|
||
**端**:前端 **预估**:0.5d **产出**:`src/stores/templateStore.ts`
|
||
|
||
**做什么**
|
||
- state: `template`, `previewHtml`, `blocks`, `tree`, `configs`, `dataSources`
|
||
- actions: `fetchTemplate(id)`, `updateConfig(blockId, config)`
|
||
- getters: `getBlockById(blockId)`, `getConfigByBlockId(blockId)`
|
||
|
||
**验收**
|
||
- 调用 fetchTemplate 后所有数据填充
|
||
|
||
---
|
||
|
||
#### 068 · selectionStore
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`src/stores/selectionStore.ts`
|
||
|
||
**做什么**
|
||
- state: `selectedBlockId: string | null`
|
||
- actions: `selectBlock(id)`, `cancelSelection()`
|
||
|
||
**验收**
|
||
- selectBlock 后 selectedBlockId 更新
|
||
|
||
---
|
||
|
||
#### 069 · uiStore
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`src/stores/uiStore.ts`
|
||
|
||
**做什么**
|
||
- state: `zoomLevel: 100`, `showLabels: true`, `saveStatus: 'saved' | 'unsaved' | 'saving'`
|
||
- actions: `setZoom(level)`, `toggleLabels()`, `setSaveStatus(status)`
|
||
|
||
**验收**
|
||
- 状态可读可写,所有组件响应变化
|
||
|
||
---
|
||
|
||
### 三区联动(070–073)
|
||
|
||
---
|
||
|
||
#### 070 · watch selectedBlockId → 配置加载
|
||
|
||
**端**:前端 **预估**:0.5d **产出**:`ConfigPanel.vue`
|
||
|
||
**做什么**
|
||
```ts
|
||
watch(() => selectionStore.selectedBlockId, (blockId) => {
|
||
if (!blockId) { form.value = {}; return }
|
||
const config = templateStore.configs[blockId]
|
||
if (config) {
|
||
form.value = { ...config }
|
||
} else {
|
||
const block = templateStore.getBlockById(blockId)
|
||
form.value = {
|
||
regionName: block?.text_preview || '',
|
||
regionType: 'ai_generate',
|
||
dataSources: [],
|
||
prompt: '',
|
||
outputFormat: 'formal_paragraph',
|
||
needReview: true,
|
||
remark: '',
|
||
enabled: true
|
||
}
|
||
}
|
||
})
|
||
```
|
||
|
||
**验收**
|
||
- 已配置的 block 加载已有配置
|
||
- 未配置的 block 显示默认值
|
||
|
||
---
|
||
|
||
#### 071 · watch selectedBlockId → 树节点高亮
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`StructureTree.vue`
|
||
|
||
**做什么**
|
||
```ts
|
||
watch(() => selectionStore.selectedBlockId, (blockId) => {
|
||
highlightNode(blockId)
|
||
if (blockId) expandParents(blockId)
|
||
})
|
||
```
|
||
|
||
**验收**
|
||
- 选中后树节点高亮,父级自动展开
|
||
|
||
---
|
||
|
||
#### 072 · 页面初始化 loading
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`TemplateEdit.vue`
|
||
|
||
**做什么**
|
||
- 页面 mounted 时:
|
||
1. `loading = true`
|
||
2. 调用 `templateStore.fetchTemplate(id)`
|
||
3. 成功 → `loading = false`
|
||
- loading 状态:全屏半透明遮罩 + `<a-spin>` 加载动画
|
||
|
||
**验收**
|
||
- 加载时显示 loading,完成后内容出现
|
||
|
||
---
|
||
|
||
#### 073 · 加载失败错误页
|
||
|
||
**端**:前端 **预估**:0.25d **产出**:`TemplateEdit.vue`
|
||
|
||
**做什么**
|
||
- 加载失败时显示:错误图标 + "加载失败" + 错误信息 + 重新加载按钮
|
||
- 点击重新加载重试 fetchTemplate
|
||
|
||
**验收**
|
||
- 模拟网络断开时显示错误页
|
||
|
||
---
|
||
|
||
## 附录:数据库表结构
|
||
|
||
### template 表
|
||
|
||
```sql
|
||
CREATE TABLE template (
|
||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||
name VARCHAR(200) NOT NULL,
|
||
type VARCHAR(50) DEFAULT 'report',
|
||
version VARCHAR(20) DEFAULT 'v1.0.0',
|
||
original_file_path VARCHAR(500) NOT NULL,
|
||
status TINYINT DEFAULT 1,
|
||
created_by VARCHAR(50),
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||
);
|
||
```
|
||
|
||
### template_block 表
|
||
|
||
```sql
|
||
CREATE TABLE template_block (
|
||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||
template_id INT NOT NULL,
|
||
block_id VARCHAR(50) NOT NULL,
|
||
parent_block_id VARCHAR(50),
|
||
block_type VARCHAR(20) NOT NULL,
|
||
block_name VARCHAR(200),
|
||
text_preview VARCHAR(500),
|
||
level INT DEFAULT 0,
|
||
sort_order INT DEFAULT 0,
|
||
table_rows INT,
|
||
table_cols INT,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (template_id) REFERENCES template(id) ON DELETE CASCADE,
|
||
INDEX idx_template_id (template_id)
|
||
);
|
||
```
|
||
|
||
### block_config 表
|
||
|
||
```sql
|
||
CREATE TABLE block_config (
|
||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||
template_id INT NOT NULL,
|
||
block_id VARCHAR(50) NOT NULL,
|
||
region_name VARCHAR(200),
|
||
region_type VARCHAR(30) DEFAULT 'ai_generate',
|
||
data_sources TEXT,
|
||
prompt TEXT,
|
||
output_format VARCHAR(30) DEFAULT 'formal_paragraph',
|
||
need_review TINYINT DEFAULT 1,
|
||
remark TEXT,
|
||
enabled TINYINT DEFAULT 1,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (template_id) REFERENCES template(id) ON DELETE CASCADE,
|
||
UNIQUE KEY uk_template_block (template_id, block_id)
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 附录:第一阶段接口清单
|
||
|
||
| 方法 | 路径 | 任务 |
|
||
|------|------|:----:|
|
||
| GET | `/health` | 001 |
|
||
| POST | `/api/templates/upload` | 018 |
|
||
| GET | `/api/templates/{template_id}` | 030 |
|
||
| POST | `/api/templates/{template_id}/blocks/{block_id}/config` | 031 |
|
||
| GET | `/api/data-sources` | 032 |
|
||
| POST | `/api/data-sources` | 033 |
|
||
|
||
---
|
||
|
||
## 附录:Ant Design Vue 组件对照
|
||
|
||
| 用途 | Ant Design Vue 组件 |
|
||
|------|-------------------|
|
||
| 按钮 | `<a-button>` |
|
||
| 文本输入 | `<a-input v-model:value>` |
|
||
| 下拉选择 | `<a-select v-model:value>` |
|
||
| 多行文本 | `<a-textarea v-model:value>`(自带 `show-count` 字数统计) |
|
||
| 标签 | `<a-tag closable>` |
|
||
| 单选框 | `<a-radio-group> <a-radio>` |
|
||
| 开关 | `<a-switch>` |
|
||
| 加载动画 | `<a-spin>` |
|
||
| 消息提示 | `message.success()` / `message.error()`(从 `ant-design-vue` import) |
|