Compare commits

...

3 Commits

Author SHA1 Message Date
Your Name
d52509d630 docs: 完善 TDD 计划与项目名称统一
主要变更:
- 项目名称统一为"秒思智能审核平台"(替换 SmartAudit)
- 完善 TDD 实施评估与计划 (featuredoc/tdd_plan.md V2.0)
  - 新增项目现状诊断与可行性分析
  - 新增前后端测试策略与工具链配置模板
  - 新增 CI/CD 集成方案与 Codecov 配置说明
  - 标注所有待创建模板文件
- 新增 GitHub 配置脚本 (scripts/setup-github.sh)
  - 自动配置分支保护规则
  - 验证 GitHub CLI 登录状态
- 更新 TASK-005-C 包含分支保护与 Codecov 配置
- 同步更新 F-51/F-52 功能至所有相关文档
- UI 设计 Logo 统一为"秒思"

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 11:08:59 +08:00
Your Name
6ca52c87d1 Fix tasks.md: correct UI task counts and add missing references
- Fix P0/P1/P2 task counts (17/10/8, not 14/9/8)
- Add total count row showing 35 UI tasks
- Add relationship explanation between function tasks and UI tasks
- Add missing "关联任务" fields for all UI tasks
- Clarify that desktop UI tasks reuse mobile logic with layout adaptation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 17:48:55 +08:00
Your Name
f166c04422 Add frontend component library and UI development tasks
- Create Tailwind CSS configuration with design tokens from UIDesignSpec
- Create globals.css with CSS variables and component styles
- Add React component library:
  - UI components: Button, Card, Tag, Input, Select, ProgressBar, Modal
  - Navigation: BottomNav, Sidebar, StatusBar
  - Layout: MobileLayout, DesktopLayout
- Add constants for colors, icons, and layout
- Update tasks.md with 31 UI development tasks linked to design node IDs
- Configure package.json, tsconfig.json, and postcss.config.js

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 17:44:22 +08:00
35 changed files with 8640 additions and 285 deletions

View File

@ -2,9 +2,9 @@
| 文档类型 | **Technical Design (技术设计文档)** |
| --- | --- |
| **项目名称** | SmartAudit (AI 营销内容合规审核平台) |
| **版本号** | V2.0 |
| **日期** | 2026-02-02 |
| **项目名称** | 秒思智能审核平台 (AI 营销内容合规审核平台) |
| **版本号** | V2.1 |
| **日期** | 2026-02-03 |
| **侧重** | AI 服务动态配置、多租户隔离、模型选择 |
---
@ -15,6 +15,7 @@
| --- | --- | --- | --- |
| V1.0 | 2026-02-02 | Claude | 初稿AI 厂商动态配置架构设计 |
| V2.0 | 2026-02-02 | Claude | 重构:简化为统一提供商+三模型配置方案 |
| V2.1 | 2026-02-03 | Claude | 文档一致性修订:明确单提供商模式与可切换原则 |
---
@ -22,7 +23,7 @@
### 1.1 业务需求
SmartAudit 系统需要调用三类 AI 服务完成视频审核:
秒思智能审核平台 系统需要调用三类 AI 服务完成视频审核:
| 服务类型 | 用途 | 示例模型 |
| --- | --- | --- |
@ -35,6 +36,7 @@ SmartAudit 系统需要调用三类 AI 服务完成视频审核:
| 目标 | 描述 |
| --- | --- |
| **灵活配置** | 品牌方可在后台自由选择 AI 提供商和模型 |
| **单一提供商** | 每租户仅保留一套提供商配置,必要时手动切换 |
| **统一接入** | 支持 OneAPI/OpenRouter 中转,一套配置调用多种模型 |
| **直连支持** | 也支持直连 Anthropic、OpenAI、DeepSeek 等厂商 |
| **多租户隔离** | 不同品牌方使用独立的 AI 配置和配额 |
@ -693,7 +695,7 @@ def mask_api_key(api_key: str) -> str:
## 7. 界面设计
> 详见 UIDesign.md 第 10 章「AI 服务配置界面
> 详见 User_Role_Interfaces.md 第 4.6 章「AI 服务配置
### 7.1 界面入口

View File

@ -1,4 +1,4 @@
这是一个基于 `RequirementsDoc.md``FeatureSummary.md` (V1.3) 和 `User_Role_Interfaces.md` 编写的开发计划文档。
这是一个基于 `RequirementsDoc.md``FeatureSummary.md` (V1.4) 和 `User_Role_Interfaces.md` 编写的开发计划文档。
这份文档旨在指导技术团队进行架构设计、选型和排期,重点在于解决**视频处理的高并发/高延迟**、**多模态 AI 的集成**以及**移动端适配**等工程难点。
@ -10,10 +10,10 @@
| 文档类型 | **Development Plan (技术架构与实施计划)** |
| --- | --- |
| **项目名称** | SmartAudit (AI 营销内容合规审核平台) |
| **版本号** | V1.5 |
| **项目名称** | 秒思智能审核平台 (AI 营销内容合规审核平台) |
| **版本号** | V1.6 |
| **日期** | 2026-02-03 |
| **依据** | FeatureSummary V1.3, PRD V1.0, RequirementsDoc V1.0 |
| **依据** | FeatureSummary V1.4, PRD V1.0, RequirementsDoc V1.0 |
| **侧重** | 技术选型、架构设计、MVP 范围、开发排期、验收标准 |
---
@ -29,6 +29,7 @@
| V1.3 | 2026-02-03 | Claude | **确立 TDD 为项目核心开发规范**,关联 tdd_plan.md |
| V1.4 | 2026-02-03 | Claude | **新增 AI 厂商动态配置架构**,支持数据库配置、运行时热更新、多租户隔离 |
| V1.5 | 2026-02-03 | Claude | 文档一致性修复统一加密方案、采样精度、处理时间、选型决策、P0 范围、排期等 |
| V1.6 | 2026-02-03 | Claude | 文档一致性修订AI 配置单提供商模式、审计日志不可篡改方案、FeatureSummary 版本对齐 |
---
@ -108,7 +109,7 @@ graph TD
| --- | --- | --- |
| **通用语义 (NLP)** | **豆包 Pro / Qwen-Max / DeepSeek** | 处理 Brief 解析、反讽识别、情感分析 |
| **视觉理解 (VLM)** | **Qwen-VL / 豆包视觉** | 处理复杂场景理解(如:环境脏乱差、具体动作判定);**Brief 图片解析** |
| **语音识别 (ASR)** | **Paraformer (阿里) / SenseVoice** | 高精度中文语音转写,支持时间戳对齐 |
| **语音识别 (ASR)** | **Whisper / Paraformer / SenseVoice** | 通过 AIProviderConfig 配置音频模型,支持时间戳对齐 |
| **文字识别 (OCR)** | **PaddleOCR v4** | 针对中文视频字幕优化,开源免费,轻量级 |
| **版面分析 (Layout)** | **PaddleOCR Layout / LayoutLMv3** | Brief PDF 版面分析,提取图文混排结构 |
| **竞品 Logo 检测** | **Grounding DINO + Vector DB** | ⭐ V1.2 修正:改为向量检索方案,见下方说明 |
@ -119,11 +120,11 @@ graph TD
>
> **核心特性:**
> - **数据库存储配置:** AI 厂商的 API Key、Base URL 等配置存储在数据库中,而非环境变量
> - **运行时动态加载:** 管理员可在后台配置 AI 厂商,系统运行时动态读取配置初始化客户端
> - **多租户隔离:** 不同品牌方可配置独立的 AI 厂商和配额
> - **运行时动态加载:** 管理员可在后台配置**单一 AI 提供商**,系统运行时动态读取配置初始化客户端
> - **多租户隔离:** 不同品牌方可配置独立的 AI 提供商配置和配额
> - **热更新:** 配置变更即时生效,无需重启服务
> - **故障转移:** 主厂商不可用时自动切换到备用厂商
> - **API Key 加密:** 使用 AES-256-GCM 加密存储敏感信息
> - **可切换:** 管理员可随时更换提供商OneAPI/OpenRouter 或直连厂商)
>
> **支持的厂商类型:**
> - 国内厂商DeepSeek、通义千问、豆包、智谱、Moonshot
@ -252,11 +253,11 @@ sequenceDiagram
## 3. MVP (P0) 开发范围定义
基于 `FeatureSummary.md V1.3`MVP 阶段必须包含的功能:
基于 `FeatureSummary.md V1.4`MVP 阶段必须包含的功能:
### ✅ MVP 包含 (Must Have) - 共 21 个 P0 功能
基于 `FeatureSummary.md V1.3` 第 4.1 章定义:
基于 `FeatureSummary.md V1.4` 第 4.1 章定义:
| 模块 | 功能编号 | 功能名称 | 备注 |
| --- | --- | --- | --- |
@ -406,13 +407,15 @@ sequenceDiagram
| `reports` | 审核报告 | id, video_id, ai_result_json, human_decision, created_at |
| `risk_items` | 风险项 | id, report_id, type, level, timestamp_start, timestamp_end, evidence_json |
| `rule_sets` | 规则库 | id, brand_id, platform, version, rules_json |
| `audit_logs` | 审计日志 | id, task_id, operator_id, action, detail_json, created_at |
| `audit_logs` | 审计日志 | id, task_id, operator_id, action, detail_json, created_at, prev_hash, hash |
> **审计日志不可篡改策略:** `audit_logs` 采用 append-only 写入 + hash chain前序哈希 + 当前内容),禁止更新/删除,支持链式校验。
---
## 8. 验收标准 (Acceptance Criteria)
引用自 `FeatureSummary.md V1.3` 第 9 章MVP 上线前必须满足:
引用自 `FeatureSummary.md V1.4` 第 9 章MVP 上线前必须满足:
| 验收项 | 标准 | 测量方式 | 责任方 |
| --- | --- | --- | --- |
@ -518,6 +521,6 @@ sequenceDiagram
| User_Role_Interfaces.md | 界面规范 |
| tasks.md | 开发任务清单 |
| **featuredoc/tdd_plan.md** | **TDD 实施计划(核心规范)** |
| **AIProviderConfig.md** | **AI 厂商动态配置架构设计V2.0** |
| **AIProviderConfig.md** | **AI 厂商动态配置架构设计V2.1** |
| 数据字典 | 待编写 |
| API 接口规范 | 待编写 |

View File

@ -1,6 +1,9 @@
# 设计文档矛盾与模糊点分析 (V1.2)
# 设计文档矛盾与模糊点分析 (V1.7)
本文档用于记录并跟踪 `SmartAudit` 项目各设计文档之间的矛盾点与模糊点。以下条目均已对齐并给出统一结论。
本文档用于记录并跟踪 `秒思智能审核平台` 项目各设计文档之间的矛盾点与模糊点。
**最后检查时间:** 2026-02-03
**检查版本:** PRD V1.0, RequirementsDoc V1.0, FeatureSummary V1.6, DevelopmentPlan V1.6, tasks.md V1.6, UIDesignSpec V1.0, UIDesign V1.1, User_Role_Interfaces V1.5, AIProviderConfig V2.1, tdd_plan V1.0
---
@ -11,28 +14,32 @@
- **对齐文档:** `DevelopmentPlan.md``User_Role_Interfaces.md`
### 1.2 Logo 检测职责边界 (已澄清)
- **结论:** 视觉模型仅用于画面语义/场景风险分析;竞品 Logo 检测由内置 CV 模型处理,不受配置影响。
- **对齐文档:** `AIProviderConfig.md``UIDesign.md``User_Role_Interfaces.md`
- **结论:** 视觉模型仅用于画面语义/场景风险分析;竞品 Logo 检测由内置 CV 模型Grounding DINO + Vector DB处理,不受配置影响。
- **对齐文档:** `AIProviderConfig.md``UIDesign.md``User_Role_Interfaces.md``DevelopmentPlan.md`
### 1.3 文件上传方案 (已同步)
- **结论:** 批量上传采用 **多文件拖拽并发上传 + Tus 断点续传**,弃用 ZIP。
- **对齐文档:** `PRD.md``RequirementsDoc.md``FeatureSummary.md``DevelopmentPlan.md`
### 1.4 AI 厂商配置范围 (已统一)
- **结论:** 每租户仅配置**单一 AI 提供商**OneAPI/OpenRouter 中转或直连厂商),不做自动故障转移;需要切换由管理员手动更新配置。
- **对齐文档:** `AIProviderConfig.md``PRD.md``RequirementsDoc.md``FeatureSummary.md``DevelopmentPlan.md`
---
## 2. 权限与工作流
### 2.1 强制通过与特例关系 (已统一)
- **结论:** “强制通过”弹窗内提供 **保存为特例** 勾选项(默认不勾选);勾选后生成豁免条款并等待品牌方确认生效。
- **结论:** "强制通过"弹窗内提供 **保存为特例** 勾选项(默认不勾选);勾选后生成豁免条款并等待品牌方确认生效。
- **对齐文档:** `PRD.md``UIDesign.md``User_Role_Interfaces.md`
### 2.2 强制通过禁用后的流程 (已统一)
- **结论:** 品牌方关闭授权后,代理商端按钮文案变为“申请强制通过”,填写理由并提交品牌方审批。
- **结论:** 品牌方关闭授权后,代理商端按钮文案变为"申请强制通过",填写理由并提交品牌方审批。
- **对齐文档:** `PRD.md``UIDesign.md``User_Role_Interfaces.md`
### 2.3 AI 配置可见性 (已统一)
- **结论:** 代理商/达人 **不可见** AI 配置,仅品牌方管理员可查看与修改。
- **对齐文档:** `UIDesign.md``User_Role_Interfaces.md`
- **对齐文档:** `UIDesign.md``User_Role_Interfaces.md``AIProviderConfig.md`
---
@ -50,14 +57,124 @@
## 4. 文档一致性
### 4.1 TDD 计划文档缺失 (已补齐)
### 4.1 TDD 计划文档 (已补齐)
- **结论:** 新增 `featuredoc/tdd_plan.md`,作为 `tasks.md` 中 TDD 引用的正式文档。
- **对齐文档:** `tasks.md`
- **对齐文档:** `tasks.md``DevelopmentPlan.md`
### 4.2 视频采样率假设 (已同步)
- **结论:** CV 采样率默认 **2fps**,并在该采样率下验证时长统计准确性。
- **对齐文档:** `PRD.md``FeatureSummary.md`
- **对齐文档:** `PRD.md``FeatureSummary.md``DevelopmentPlan.md`
### 4.3 UI 设计风格 (已统一)
- **问题:** 存在两份 UI 设计文档,风格不一致:
- `UIDesign.md`: Apple Human Interface Guidelines **浅色系** (#FFFFFF 为主背景)
- `UIDesignSpec.md`: Apple-style **暗色主题** (#0B0B0E 为页面背景)
- **结论:**`UIDesignSpec.md` 和设计稿 `pencil-new.pen` 为准,采用 **暗色主题**
- **已处理:**`UIDesign.md` 头部添加废弃声明,指向 `UIDesignSpec.md` 为正式规范。
- **对齐文档:** `UIDesign.md``UIDesignSpec.md`
- **备注:** `tasks.md` 中的 UIDesign.md 引用保持不变,因 UIDesign.md 中的设计原则和交互说明仍有参考价值;具体颜色/组件规范以 UIDesignSpec.md 为准。
### 4.4 审计日志不可篡改实现 (已明确)
- **结论:** 采用 append-only + hash chain前序哈希 + 当前内容)保证审计日志可追溯与不可篡改。
- **对齐文档:** `PRD.md``RequirementsDoc.md``FeatureSummary.md``DevelopmentPlan.md``tasks.md`
---
**当前状态:** 无待决策项。
## 5. 数值与指标一致性 (已验证)
### 5.1 功能优先级数量
| 优先级 | PRD | FeatureSummary | DevelopmentPlan | tasks.md | 状态 |
| --- | --- | --- | --- | --- | --- |
| P0 (MVP) | 12项 (场景级) | 23 | 21 | 23 | ✅ 一致(新增 F-51, F-52 |
| P1 | 4项 (场景级) | 22 | - | 22 | ✅ 一致 |
| P2 | 2项 (场景级) | 8 | - | 8 | ✅ 一致 |
### 5.2 技术指标
| 指标 | PRD | FeatureSummary | DevelopmentPlan | 状态 |
| --- | --- | --- | --- | --- |
| 审核报告产出时间 | ≤ 5 分钟(含排队 ≤ 2 分钟) | ≤ 5 分钟(含排队 ≤ 2 分钟) | ≤ 5 分钟(含排队 ≤ 2 分钟) | ✅ 一致 |
| 竞品 Logo F1 | ≥ 0.85 | ≥ 0.85 | ≥ 0.85 | ✅ 一致 |
| ASR 字错率 | ≤ 10% | ≤ 10% | ≤ 10% | ✅ 一致 |
| OCR 准确率 | ≥ 95% | ≥ 95% | ≥ 95% | ✅ 一致 |
| 语境理解误报率 | ≤ 5% | ≤ 5% | ≤ 5% | ✅ 一致 |
| 时长统计误差 | ≤ 1秒 | ≤ 1秒 | ≤ 1秒 | ✅ 一致 |
| 频次统计准确率 | ≥ 95% | ≥ 95% | ≥ 95% | ✅ 一致 |
| 加密方案 | AES-256-GCM | AES-256-GCM | AES-256-GCM | ✅ 一致 |
| CV 采样率 | 2fps | 2fps | 2fps | ✅ 一致 |
### 5.3 开发周期
| 项目 | DevelopmentPlan | tasks.md | 状态 |
| --- | --- | --- | --- |
| 总周期 | 11 周 | 11 周 | ✅ 一致 |
| Phase 1 | Week 1-2 | Week 1-2 | ✅ 一致 |
| Phase 2 | Week 3-6 (4周) | Week 3-6 (4周) | ✅ 一致 |
| Phase 3 | Week 7-9 | Week 7-9 | ✅ 一致 |
| Phase 4 | Week 10-11 | Week 10-11 | ✅ 一致 |
### 5.4 测试覆盖率要求
| 类型 | DevelopmentPlan | tdd_plan.md | tasks.md | 状态 |
| --- | --- | --- | --- | --- |
| 后端覆盖率 | ≥ 80% | ≥ 80% | ≥ 80% | ✅ 一致 |
| 前端覆盖率 | ≥ 70% | ≥ 70% | ≥ 70% | ✅ 一致 |
---
## 6. 合理性评估 (已验证)
### 6.1 技术方案合理性
- ✅ **前后端分离 + AI 微服务化**:适合视频处理的高算力需求
- ✅ **FastAPI + Celery + Redis**Python 生态成熟,适合 AI 集成
- ✅ **PostgreSQL + pgvector**:减少架构复杂度,统一向量检索
- ✅ **Tus 协议**:解决大文件上传不稳定问题
- ✅ **弹性 GPU 集群**:支持自动扩缩容,控制成本
### 6.2 时间估算合理性
- ✅ **Phase 2 延长至 4 周**:预留多模态时间戳对齐的工程时间
- ✅ **Phase 3 移动端 + 审核台**3 周合理
- ✅ **Phase 4 联调验收**2 周合理
### 6.3 功能优先级合理性
- ✅ **F-09 语境理解提升至 P0**:避免"人工智障"体验
- ✅ **F-17 进度展示提升至 P0**:缓解等待焦虑
- ✅ **F-05 拆分为 A/B**MVP 聚焦核心防竞品能力
- ✅ **F-45 时长频次校验 P0**:满足 Brief 硬性指标
- ✅ **F-47/48/49 AI 配置 P0**AI 服务基础设施
---
## 7. 已完成处理项
### 7.1 UI 设计文档统一 ✅
**状态:** 已完成 (2026-02-03)
**描述:** `UIDesign.md`(浅色系)与 `UIDesignSpec.md`(暗色主题)风格冲突
**决策:** 以 `UIDesignSpec.md``pencil-new.pen` 为准(暗色主题)
**已完成行动:**
1. ✅ 在 `UIDesign.md` 头部添加废弃声明,指向 `UIDesignSpec.md` 为正式规范
2. ✅ `tasks.md` 中的引用保持不变(设计原则部分仍有参考价值)
### 7.2 AIProviderConfig 文档引用更新 ✅
**状态:** 已完成 (2026-02-03)
**描述:** `AIProviderConfig.md` 第7章引用了已废弃的 `UIDesign.md`
**已完成行动:**
- ✅ 更新引用为 `User_Role_Interfaces.md` 第 4.6 章
### 7.3 tdd_plan.md 版本号补充 ✅
**状态:** 已完成 (2026-02-03)
**描述:** `tdd_plan.md` 缺少版本号和文档头部元信息
**已完成行动:**
- ✅ 添加文档头部元信息,版本号 V1.0
---
**当前状态:** ✅ 无待决策项。所有文档一致性问题已解决,可开始开发。
---
## 8. 检查历史
| 检查时间 | 版本 | 检查人 | 发现问题 | 处理结果 |
| --- | --- | --- | --- | --- |
| 2026-02-03 | V1.4 | Claude | UI设计风格不一致、版本号引用 | 已统一 |
| 2026-02-03 | V1.5 | Claude | AIProviderConfig引用过时、tdd_plan缺版本号 | 已修复 |
| 2026-02-03 | V1.6 | Claude | 新增 F-51 品牌方终审开关、F-52 审核流程进度可视化 | 已同步至全部文档 |
| 2026-02-03 | V1.7 | Claude | F-52 扩展为全角色(达人/代理商/品牌方)可见 | 已同步FeatureSummary、tasks.md、User_Role_Interfaces、UI设计 |

View File

@ -2,8 +2,8 @@
| 文档类型 | **Feature Summary (产品功能文档)** |
| --- | --- |
| **项目名称** | SmartAudit (AI 营销内容合规审核平台) |
| **版本号** | V1.3 |
| **项目名称** | 秒思智能审核平台 (AI 营销内容合规审核平台) |
| **版本号** | V1.6 |
| **发布日期** | 2026-02-03 |
| **关联文档** | RequirementsDoc.md, PRD.md, User_Role_Interfaces.md |
| **侧重** | 功能清单、优先级、验收标准、界面映射、边界说明 |
@ -18,6 +18,9 @@
| V1.1 | 2026-02-02 | Claude | 根据 Gemini 修订意见调整补充验收标准、Out of Scope、核心痛点细化 |
| V1.2 | 2026-02-02 | Claude | 根据 Gemini 关键改进意见:优先级调整、功能拆分、新增功能、移动端适配 |
| V1.3 | 2026-02-02 | Claude | **新增 AI 厂商动态配置功能模块 (F-47~F-50)**,支持数据库配置、多租户隔离 |
| V1.4 | 2026-02-03 | Claude | 文档一致性修订AI 配置单提供商模式、审计日志不可篡改方案、版本号更新 |
| V1.5 | 2026-02-03 | Claude | **新增 F-51 品牌方终审开关、F-52 审核流程进度可视化** |
| V1.6 | 2026-02-03 | Claude | **F-52 扩展为全角色可见**:代理商端(桌面+移动)、品牌方端(桌面+移动)均可查看进度 |
**Gemini 修订意见采纳情况:**
@ -37,7 +40,7 @@
### 1.1 产品定位
SmartAudit 是一款**基于多模态大模型的 B2B SaaS 审核工具**,定位为**"智能预审员"**,在人工介入前**自动化拦截 80% 的基础错误和合规风险**,将审核流转周期从"天"缩短到"小时"。
秒思智能审核平台 是一款**基于多模态大模型的 B2B SaaS 审核工具**,定位为**"智能预审员"**,在人工介入前**自动化拦截 80% 的基础错误和合规风险**,将审核流转周期从"天"缩短到"小时"。
### 1.2 核心价值
@ -64,7 +67,7 @@ SmartAudit 是一款**基于多模态大模型的 B2B SaaS 审核工具**,定
```
┌─────────────────────────────────────────────────────────────────┐
SmartAudit 功能架构 │
秒思智能审核平台 功能架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
@ -372,6 +375,7 @@ SmartAudit 是一款**基于多模态大模型的 B2B SaaS 审核工具**,定
| --- | --- | --- | --- | --- |
| F-19 | 风险列表展示 | P0 | US-08 | 代理商 |
| F-20 | 确认/驳回操作 | P0 | US-08 | 代理商 |
| F-51 | 品牌方终审开关 | **P0** | - | 品牌方 |
| F-21 | 强制通过权 | P1 | US-09 | 品牌方(默认授权代理商) |
| F-22 | 特例记录与白名单 | P1 | US-09 | 品牌方 |
| F-23 | 规则依据与证据查看 | P1 | US-08 | 代理商/品牌方 |
@ -395,12 +399,95 @@ SmartAudit 是一款**基于多模态大模型的 B2B SaaS 审核工具**,定
**操作说明:**
- 驳回:自动将勾选的问题打包发送给达人
- 通过:流程结束
- 通过:
- 若品牌方**未开启终审**(默认)→ 流程结束,任务状态变为「已通过」
- 若品牌方**已开启终审** → 进入品牌方终审队列,任务状态变为「待终审」
**界面映射:** 代理商端 → 审核决策台 → 决策栏
---
#### F-51 品牌方终审开关 ⭐ P0 (新增)
**功能描述:** 品牌方可配置是否对代理商初审通过的内容进行终审。
**配置选项:**
- **终审开关**:开启/关闭(**默认关闭**
- **终审范围**:全部内容 / 仅舆情风险内容 / 仅指定代理商
- **终审超时处理**:超时自动通过 / 超时提醒默认48小时
**流程说明:**
```
┌─────────────────────────────────────────────────────────────┐
│ 终审关闭(默认) │
│ 达人提交 → AI审核 → 代理商初审通过 → ✅ 最终通过 │
├─────────────────────────────────────────────────────────────┤
│ 终审开启 │
│ 达人提交 → AI审核 → 代理商初审通过 → 品牌方终审 │
│ ├─ 通过 → ✅ 最终通过 │
│ └─ 驳回 → 返回达人修改 │
└─────────────────────────────────────────────────────────────┘
```
**为什么是 P0** 审核流程是系统核心逻辑,需在 MVP 阶段确定流程框架,即使默认关闭也需要支持配置能力。
**界面映射:** 品牌方端 → 系统设置 → 审核流程配置
---
#### F-52 审核流程进度可视化 ⭐ P0 (新增)
**功能描述:** **全角色(达人、代理商、品牌方)** 均可在移动端和桌面端实时查看内容的完整审核流程状态,清晰了解当前处于哪个审核阶段。
**审核状态流转:**
```
┌─────────────────────────────────────────────────────────────────┐
│ 审核流程状态(全角色可见) │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ① 已提交 ② AI审核中 ③ 待代理商审核 ④ 待品牌终审 │
│ ⬇️ ⬇️ ⬇️ ⬇️ │
│ ┌──────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 📤 │ ──▶ │ 🤖 AI │ ──▶│ 👥 代理商│ ──▶│ 🛡️ 品牌方│ │
│ │已上传 │ │ 审核中 │ │ 审核中 │ │ 终审中 │ │
│ └──────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ⚠️ 需修改 ⚠️ 驳回 ⚠️ 驳回 │
│ │ │ │ │
│ └───────────────┴───────────────┘ │
│ 返回修改 │
│ │
│ 最终状态:✅ 审核通过 或 ❌ 审核驳回 │
└─────────────────────────────────────────────────────────────────┘
```
**状态定义:**
| 状态 | 图标 | 颜色 | 说明 |
| --- | --- | --- | --- |
| 已提交 | 📤 | 灰色 | 内容已上传,等待处理 |
| AI审核中 | 🤖 | 蓝色/动画 | AI 正在分析内容 |
| AI审核通过 | ✅ | 绿色 | AI 未发现硬性问题,进入人工复核 |
| 需修改 | ⚠️ | 橙色 | AI 发现问题,需要达人修改 |
| 待代理商审核 | 👥 | 紫色 | 等待代理商人工复核 |
| 待品牌终审 | 🛡️ | 紫色 | 等待品牌方终审(仅当终审开启时) |
| 审核通过 | ✅ | 绿色 | 流程完成,可发布 |
| 审核驳回 | ❌ | 红色 | 被驳回,需修改后重新提交 |
**为什么是 P0** 达人最关心"我的内容现在在哪个环节",清晰的流程状态能减少达人焦虑,避免频繁询问代理商,提升用户体验。代理商和品牌方也需要在审核时清楚了解内容当前所处阶段。
**界面映射:**
| 角色 | 端 | 页面 | 说明 |
| --- | --- | --- | --- |
| 达人 | 桌面 | 任务列表、审核结果页 | 卡片状态标签 + 顶部进度条 |
| 达人 | 移动 | 任务列表、审核结果页 | 卡片状态标签 + 顶部进度条 |
| 代理商 | 桌面 | 审核决策台 | 顶部进度条,标注"当前:代理商审核" |
| 代理商 | 移动 | 快捷审核 | 导航栏下方进度条 |
| 品牌方 | 桌面 | 终审台 | 顶部进度条,标注"当前:品牌终审" |
| 品牌方 | 移动 | 审批中心 | 审批项内显示进度条 |
---
#### F-21 强制通过权
**功能描述:** 品牌方可手动放行过于保守的误报(如达人玩的新梗)。**默认授权代理商独立使用强制通过功能**;品牌方可在设置中**按代理商**关闭授权,关闭后代理商需发起审批流程。
@ -706,7 +793,7 @@ V1 版本指出 3 个违规点:✅ 已修复 2 个 | ❌ 未修复 1 个
---
### 3.12 系统管理 - AI 厂商配置 (V1.4 新增)
### 3.12 系统管理 - AI 厂商配置 (V1.4 修订)
| 功能编号 | 功能名称 | 优先级 | 用户故事 | 使用角色 |
| --- | --- | --- | --- | --- |
@ -717,13 +804,13 @@ V1 版本指出 3 个违规点:✅ 已修复 2 个 | ❌ 未修复 1 个
#### F-47 AI 厂商动态配置 ⭐ P0
**功能描述:** 品牌方管理员可在后台配置多个 AI 厂商DeepSeek、OpenAI、通义千问、OneAPI 中转等),配置存储在数据库中,运行时动态加载,无需修改代码或重启服务。
**功能描述:** 品牌方管理员可在后台配置**单一 AI 提供商**OneAPI/OpenRouter 中转或直连厂商),配置存储在数据库中,运行时动态加载,无需修改代码或重启服务。每个租户仅保留一套配置,可随时切换提供商。
**核心功能:**
- 支持添加、编辑、删除 AI 厂商配置
- 支持配置与更新 AI 提供商
- 配置 Base URL、API KeyAES-256-GCM 加密存储)、默认模型
- 为不同使用场景Brief 解析、脚本预审、视频审核)指定不同厂商
- 配置优先级和备用厂商(故障转移)
- 为不同使用场景Brief 解析、脚本预审、视频审核)指定不同模型
- 可通过 OneAPI/OpenRouter 聚合多模型
- 未配置时阻断调用并提示品牌方完成配置
**为什么是 P0** 这是 AI 服务的基础设施,所有 AI 功能都依赖此配置。
@ -744,7 +831,7 @@ V1 版本指出 3 个违规点:✅ 已修复 2 个 | ❌ 未修复 1 个
#### F-49 多租户 AI 配置隔离
**功能描述:** 不同品牌方可配置独立的 AI 商,实现租户级别的配置隔离和配额管理。
**功能描述:** 不同品牌方可配置独立的 AI 提供商,实现租户级别的配置隔离和配额管理。
**界面映射:** 品牌方后台 → 系统设置 → AI 配置
@ -799,6 +886,8 @@ V1 版本指出 3 个违规点:✅ 已修复 2 个 | ❌ 未修复 1 个
| F-17 | 审核进度实时展示 | 视频审核 | ⭐ P1→P0缓解等待焦虑 |
| F-19 | 风险列表展示 | 审核台 | |
| F-20 | 确认/驳回操作 | 审核台 | |
| F-51 | 品牌方终审开关 | 审核台 | ⭐ 新增,审核流程可配置 |
| F-52 | 审核流程进度可视化 | 达人端 | ⭐ 新增,达人可见审核状态 |
| F-33 | 核心指标卡片 | 数据看板 | |
| F-47 | AI 厂商动态配置 | 系统管理 | ⭐ V1.3 新增AI 基础设施 |
| F-48 | AI 厂商连通性测试 | 系统管理 | ⭐ V1.3 新增 |
@ -868,7 +957,7 @@ V1 版本指出 3 个违规点:✅ 已修复 2 个 | ❌ 未修复 1 个
| **安全** | 传输与存储加密AES-256-GCM基于角色权限控制关键操作二次确认 |
| **隐私** | 数据最小化;默认保留 30 天;符合《个保法》与 GDPR |
| **数据本地化** | 国内客户数据存储于中国大陆境内服务器 |
| **审计** | 操作日志可审计且不可篡改 |
| **审计** | 操作日志可审计且不可篡改append-only + hash chain |
| **移动端适配** | **达人端(上传/查看报告)必须适配移动端 H5 竖屏操作** |
> ⚠️ **移动端适配说明:** 达人的工作场景多在拍摄现场(移动端),需要在手机上完成脚本上传、查看审核结果等操作。如果只做 PC 网页版,达人无法在拍摄现场即时使用,产品价值会大打折扣。
@ -925,7 +1014,7 @@ V1 版本指出 3 个违规点:✅ 已修复 2 个 | ❌ 未修复 1 个
| RequirementsDoc.md | 业务需求文档(用户故事、成功指标) |
| PRD.md | 产品需求文档(功能需求、技术架构) |
| User_Role_Interfaces.md | 用户角色与界面规范 |
| **AIProviderConfig.md** | **AI 厂商动态配置架构设计V2.0** |
| **AIProviderConfig.md** | **AI 厂商动态配置架构设计V2.1** |
| 技术设计文档 (TDD) | 待编写 |
| API 接口规范 | 待编写 |
| 数据字典 | 待编写 |

35
PRD.md
View File

@ -2,7 +2,7 @@
| 文档类型 | **PRD (Product Requirement Document)** |
| --- | --- |
| **项目名称** | SmartAudit (AI 营销内容合规审核平台) |
| **项目名称** | 秒思智能审核平台 (AI 营销内容合规审核平台) |
| **版本号** | V1.0 |
| **发布日期** | 2026-02-03 |
| **状态** | 草稿 (Draft) |
@ -102,11 +102,12 @@
- 视频自动审核(竞品、违禁词、画面风险) → [US-05]
- 审核台风险打点与确认/驳回 → [US-08]
- 语境理解降低误报 → [US-04]
- 审核进度展示与时间戳修改清单 → [US-07]
- 审核进度展示F-17 → [US-07]
- 基础黑白名单与竞品库F-05-A → [US-10A]
- 时长与频次校验F-45 → [US-05]
- AI 服务配置与连通性测试F-47/F-48
- 多租户 AI 配置隔离F-49
- 数据看板核心指标卡片F-33
**P1首版发布后快速迭代**
- Brand Safety 软性风险提示 → [US-06]
@ -134,6 +135,7 @@
- **规则库管理与版本控制:** 支持平台规则库更新、品牌私有规则与白名单配置
- **权限与多租户隔离:** 支持品牌/代理/达人不同角色的权限与数据隔离
- **审计日志与报告导出:** 支持导出可追溯的审核证据链
- **数据看板与核心指标:** 提供核心指标卡片与基础数据概览
### 5.2 Out of Scope
@ -218,15 +220,21 @@
**P0**
- 审核台展示风险列表(红/黄/绿分级)与时间戳
- 支持确认/驳回操作,无需从头看视频
- **可配置审核流程F-51**:品牌方可开启/关闭终审环节
- **终审关闭(默认)**:代理商初审通过 → 最终通过
- **终审开启**:代理商初审通过 → 品牌方终审 → 最终通过/驳回
- 支持配置终审范围(全部/仅舆情风险/指定代理商)
- 支持配置终审超时处理默认48小时
**P1**
- 品牌方"强制通过权":可手动放行过于保守的误报(需记录原因与审批人);**默认授权代理商独立使用,可在品牌方设置中按代理商关闭,关闭后需走审批流程**。强制通过弹窗需填写原因,并提供“保存为特例”可选项(**默认不勾选**,勾选后形成豁免条款,需品牌方确认生效)
- 品牌方"强制通过权":可手动放行过于保守的误报(需记录原因与审批人);**默认授权代理商独立使用,可在品牌方设置中按代理商关闭,关闭后需走审批流程**。强制通过弹窗需填写原因,并提供"保存为特例"可选项(**默认不勾选**,勾选后形成豁免条款,需品牌方确认生效)
- 特例可沉淀为规则白名单/豁免条款(含来源:强制通过勾选或手动记录)
- 如需用于模型优化,必须确保数据授权与合规评估
- 可查看规则依据与证据片段
**验收要点**
- 每条结论包含规则版本、模型版本、证据截图/片段与时间戳
- 终审开启时,代理商通过后任务状态变为「待终审」,品牌方操作后变为「已通过」或「待修改」
### 6.5 代理商管理
@ -269,6 +277,22 @@
---
### 6.9 数据看板与核心指标
**P0**
- 核心指标卡片F-33展示审核总量、初审通过率、硬性召回率、舆情拦截数、平均审核周期
**P1**
- 趋势图表F-34近 30 天审核量与通过率趋势
- 风险预警F-35竞品露出集中爆发、达人连续未通过、舆情异常上升
- 代理商绩效对比F-36与达人排行榜F-37
**验收要点**
- 指标口径与成功指标定义一致
- 指标数据可追溯到审计记录
---
## 7. 关键流程 (Key User Flows)
### 7.1 品牌方工作流
@ -326,6 +350,7 @@
- 全流程日志可追溯、不可篡改
- 导出报告包含规则版本、模型版本、证据截图/片段与时间戳
- 支持争议场景下完整审核证据链导出
- 审计日志采用 append-only + hash chain前序哈希 + 当前内容)确保可追溯
---
@ -394,13 +419,13 @@
- **ASR/OCR**:支持普通话及主流方言的语音识别,支持复杂背景字幕识别
- **计算机视觉**Logo 检测、物体识别、场景分类
- **消息队列**:异步处理视频审核任务,支持优先级调度
- **AI 厂商动态配置**:品牌方管理员可在后台配置多个 AI 厂商DeepSeek/OpenAI/OneAPI 等),运行时动态加载,支持多租户隔离和故障转移(详见 AIProviderConfig.md
- **AI 厂商动态配置**:品牌方管理员可在后台配置**单一 AI 提供商**(可为 OneAPI/OpenRouter 中转或直连厂商),运行时动态加载,支持多租户隔离;配置变更可随时切换(详见 AIProviderConfig.md
---
## 14. 里程碑与发布计划 (Milestones)
- **MVP (P0)**Brief 解析、规则加载、脚本预审、视频审核、审核台、语境理解降低误报、审核进度展示、基础黑白名单与竞品库、时长与频次校验、AI 服务商配置
- **MVP (P0)**Brief 解析、规则加载、脚本预审、视频审核、审核台、语境理解降低误报、审核进度展示、基础黑白名单与竞品库、时长与频次校验、AI 服务商配置、核心指标卡片
- **V1.1 (P1)**Brand Safety 提示、规则版本、证据链导出、强制通过权、高级豁免规则
- **V2 (P2)**:批量处理、版本差异报告

View File

@ -2,7 +2,7 @@
| 文档类型 | **RD (Requirements Document)** |
| --- | --- |
| **项目名称** | SmartAudit (AI 营销内容合规审核平台) |
| **项目名称** | 秒思智能审核平台 (AI 营销内容合规审核平台) |
| **版本号** | V1.0 |
| **发布日期** | 2026-02-03 |
| **状态** | **修订 (Revised)** |
@ -135,6 +135,7 @@
7. **规则库管理与版本控制:** 支持平台规则库更新、品牌私有规则与白名单配置。
8. **权限与多租户隔离:** 支持品牌/代理/达人不同角色的权限与数据隔离。
9. **审计日志与报告导出:** 支持导出可追溯的审核证据链。
10. **数据看板与核心指标:** 提供核心指标卡片与基础数据概览。
### ❌ Out of Scope (本期不做)
@ -188,7 +189,7 @@
* **ASR/OCR** 支持普通话及主流方言的语音识别,支持复杂背景字幕识别
* **计算机视觉:** Logo 检测、物体识别、场景分类
* **消息队列:** 异步处理视频审核任务,支持优先级调度
* **AI 厂商动态配置:** 支持在数据库中配置多个 AI 厂商DeepSeek/OpenAI/OneAPI 等),运行时动态加载,支持多租户隔离和故障转移(详见 AIProviderConfig.md
* **AI 厂商动态配置:** 支持在数据库中配置**单一 AI 提供商**(可为 OneAPI/OpenRouter 中转或直连厂商),运行时动态加载,支持多租户隔离;配置变更可随时切换(详见 AIProviderConfig.md
---
@ -213,6 +214,7 @@
* **性能:** ≤ 100MB 视频上传后AI 预审报告产出时间不超过 5 分钟(含排队 ≤ 2 分钟)。
* **审计链路:** 每条结论包含规则版本、模型版本、证据截图/片段与时间戳。
* **F-45 时长与频次统计:** 时长统计误差 ≤ 1秒频次统计准确率 ≥ 95%。
* **审计日志不可篡改:** 采用 append-only + hash chain前序哈希 + 当前内容)校验可追溯。
---

View File

@ -1,12 +1,23 @@
# UIDesign.md - 智能视频审核系统 UI 设计规范
> ⚠️ **重要说明 (2026-02-03)**
>
> 本文档为**早期设计参考文档**,设计风格为浅色系。
>
> **当前正式设计规范请参考:[UIDesignSpec.md](./UIDesignSpec.md)**
> - 设计稿文件:`pencil-new.pen`
> - 设计风格Apple-style **暗色主题**
> - 包含最新的设计令牌、组件规范和页面清单
>
> 本文档仅保留用于历史参考和设计原则说明。开发时以 `UIDesignSpec.md` 为准。
| 文档类型 | **UI Design System (设计系统规范)** |
| --- | --- |
| **项目名称** | SmartAudit (AI 营销内容合规审核平台) |
| **项目名称** | 秒思智能审核平台 (AI 营销内容合规审核平台) |
| **版本号** | V1.1 |
| **发布日期** | 2026-02-03 |
| **设计风格** | Apple Human Interface Guidelines 浅色系 |
| **关联文档** | PRD.md, FeatureSummary.md, User_Role_Interfaces.md, DevelopmentPlan.md |
| **设计风格** | ~~Apple Human Interface Guidelines 浅色系~~ → 已更新为暗色主题,见 UIDesignSpec.md |
| **关联文档** | PRD.md, FeatureSummary.md, User_Role_Interfaces.md, DevelopmentPlan.md, **UIDesignSpec.md** |
---
@ -16,22 +27,23 @@
| --- | --- | --- | --- |
| V1.0 | 2026-02-02 | Claude | 初稿:设计原则、色彩系统、组件库、三端界面规范 |
| V1.1 | 2026-02-02 | Claude | 新增第10章AI 服务配置界面设计规范 |
| V1.2 | 2026-02-03 | Claude | 添加废弃声明,指向 UIDesignSpec.md暗色主题 |
---
## 1. 设计原则 (Design Principles)
借鉴 Apple Human Interface GuidelinesSmartAudit 的设计遵循以下核心原则:
借鉴 Apple Human Interface Guidelines秒思智能审核平台 的设计遵循以下核心原则:
### 1.1 核心设计理念
| 原则 | 描述 | 在 SmartAudit 中的体现 |
| 原则 | 描述 | 在 秒思智能审核平台 中的体现 |
| --- | --- | --- |
| **Clarity (清晰)** | 文字清晰易读,图标精确传意,功能显而易见 | 审核结论用红/黄/绿 + 文字 + 图标三重表达 |
| **Deference (克制)** | UI 退居幕后,内容为王 | 审核台以视频和报告为核心,界面元素轻量化 |
| **Depth (层次)** | 通过视觉层次和流畅动效建立空间感 | 卡片悬浮阴影、模态弹窗、进度条层叠 |
### 1.2 SmartAudit 专属原则
### 1.2 秒思智能审核平台 专属原则
| 原则 | 说明 |
| --- | --- |
@ -641,7 +653,7 @@ font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
│ │
│ ┌──────────┐ ┌────────────────────────────────────────────────────────┐ │
│ │ │ │ │ │
│ │ SmartAudit│ │ 页面内容区域 │ │
│ │ 秒思智能审核平台│ │ 页面内容区域 │ │
│ │ │ │ │ │
│ ├──────────┤ │ │ │
│ │ │ │ │ │
@ -680,7 +692,7 @@ font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
```
┌────────────────────────────────────────────────────────────────────────────┐
SmartAudit 🔔 (3) 👤 张三 │
秒思智能审核平台 🔔 (3) 👤 张三 │
├──────────┬─────────────────────────────────────────────────────────────────┤
│ │ │
│ 📊 工作台 │ 工作台 │
@ -727,7 +739,7 @@ font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
```
┌────────────────────────────────────────────────────────────────────────────┐
SmartAudit 🔔 (3) 👤 张三 │
秒思智能审核平台 🔔 (3) 👤 张三 │
├──────────┬─────────────────────────────────────────────────────────────────┤
│ │ │
│ 📊 工作台 │ Brief 配置中心 │
@ -769,7 +781,7 @@ font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
```
┌────────────────────────────────────────────────────────────────────────────┐
SmartAudit 🔔 (3) 👤 张三 │
秒思智能审核平台 🔔 (3) 👤 张三 │
├──────────┬─────────────────────────────────────────────────────────────────┤
│ │ │
│ 📊 工作台 │ 审核决策台 ⬅️ ➡️ │
@ -892,7 +904,7 @@ font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
```
┌────────────────────────────────────────────────────────────────────────────┐
SmartAudit 🔔 (3) 👤 王总 │
秒思智能审核平台 🔔 (3) 👤 王总 │
├──────────┬─────────────────────────────────────────────────────────────────┤
│ │ │
│ 📊 数据 │ 数据看板 本月 ▼ 导出报告 ▼ │
@ -936,7 +948,7 @@ font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
```
┌────────────────────────────────────────────────────────────────────────────┐
SmartAudit 🔔 (3) 👤 王总 │
秒思智能审核平台 🔔 (3) 👤 王总 │
├──────────┬─────────────────────────────────────────────────────────────────┤
│ │ │
│ 📊 数据 │ 规则配置 │
@ -998,7 +1010,7 @@ font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
```
┌────────────────────────────────────────────────────────────────────────────┐
SmartAudit 🔔 (3) 👤 王总 │
秒思智能审核平台 🔔 (3) 👤 王总 │
├──────────┬─────────────────────────────────────────────────────────────────┤
│ │ │
│ 📊 数据 │ AI 服务配置 │

View File

@ -2,7 +2,7 @@
| 文档类型 | **UI Design Specification** |
| --- | --- |
| **项目名称** | SmartAudit (AI 营销内容合规审核平台) |
| **项目名称** | 秒思智能审核平台 (AI 营销内容合规审核平台) |
| **版本号** | V1.0 |
| **发布日期** | 2026-02-03 |
| **设计稿文件** | `pencil-new.pen` |

View File

@ -2,8 +2,8 @@
| 文档类型 | **UI/UX Spec (Interface Definitions)** |
| --- | --- |
| **项目名称** | SmartAudit (AI 营销内容合规审核平台) |
| **版本号** | V1.3 |
| **项目名称** | 秒思智能审核平台 (AI 营销内容合规审核平台) |
| **版本号** | V1.5 |
| **发布日期** | 2026-02-03 |
| **关联文档** | RequirementsDoc.md, PRD.md, FeatureSummary.md, DevelopmentPlan.md, AIProviderConfig.md, UIDesign.md, tasks.md |
| **侧重** | 角色权限、核心页面布局、交互逻辑 |
@ -19,6 +19,8 @@
| V1.1 | 2026-02-02 | Claude | 与 RD/PRD 对齐:补充用户故事引用、区域合规、特例记录规范、证据链权限 |
| V1.2 | 2026-02-02 | Claude | 新增代理商端和品牌方端移动端 UI 设计(工作台、快捷审核、预警、审批) |
| V1.3 | 2026-02-02 | Claude | 新增 AI 服务配置章节4.6),品牌方专属功能 |
| V1.4 | 2026-02-03 | Claude | **新增审核流程进度可视化 UIF-52**:达人端任务列表状态标签、审核结果页进度条 |
| V1.5 | 2026-02-03 | Claude | **扩展审核流程进度可视化至全角色**:代理商审核决策台/快捷审核、品牌方审批中心均可查看进度条 |
---
@ -34,14 +36,16 @@
| **Brief 管理** | 查看任务详情 | ✅ 上传/解析/编辑 Brief | ✅ 全局规则配置 |
| **脚本/视频提交** | ✅ 上传 & 修改 [US-03] | ❌ 不可提交 | ❌ 不可提交 |
| **查看 AI 报告** | ✅ 仅查看自己的 [US-07] | ✅ 查看所管辖达人的 | ✅ 查看所有 |
| **审核决策** | ❌ 无权 | ✅ 初审 (驳回/通过) [US-08] | ✅ 终审 / 强制通过 [US-09] |
| **审核决策** | ❌ 无权 | ✅ 初审 (驳回/通过) [US-08] | ✅ 终审(可配置)/ 强制通过 [US-09] |
| **申诉功能** | ✅ 发起申诉 (消耗令牌) | ✅ 仲裁申诉 | ❌ 无需申诉 |
| **证据链导出** | ❌ 无权 | ✅ 导出所管辖任务 | ✅ 导出全部 [US-12] |
| **数据看板** | 仅看个人任务进度 | 整体进度 / 达人排名 | 全局合规率 / 舆情风控 |
| **系统配置** | ❌ 无权 | ❌ 无权 | ✅ 规则库/阈值/白名单/区域合规 [US-10A/US-10B] |
| **系统配置** | ❌ 无权 | ❌ 无权 | ✅ 规则库/阈值/白名单/区域合规/审核流程 [US-10A/US-10B] |
| **AI 服务配置** | ❌ 无权 | ❌ 无权(继承品牌方配置) | ✅ 配置 AI 提供商/模型/参数 |
| **用户管理** | ❌ 无权 | ✅ 管理所属达人 | ✅ 管理代理商与达人 |
> **审核流程说明:** 品牌方可在系统设置中配置是否开启终审环节。**默认关闭**,代理商初审通过即为最终通过;开启后,代理商初审通过的内容需进入品牌方终审队列。
---
## 1.1 各端导航结构 (Navigation Structure)
@ -108,13 +112,52 @@
## 2. 界面详解:达人端 (The Creator Portal)
**设计目标:** 极简、透明、减少焦虑。让达人像发朋友圈一样简单地完成合规检查。
**核心设备:** 手机浏览器 (Mobile Web) / 小程序。
**核心设备:** 手机浏览器 (H5) / 小程序。
### 2.1 任务列表页 (Task List)
* **状态概览:** 卡片式布局显示当前任务状态待提交、AI审核中、需修改、已通过
* **行动号召 (CTA):** 针对不同状态显示醒目按钮,如 `[上传脚本]``[查看修改意见]`
#### 2.1.1 审核流程进度可视化 ⭐ F-52
**功能说明:** 达人可在任务列表和详情页清晰看到内容当前处于哪个审核阶段。
**任务卡片状态标签:**
```
┌─────────────────────────────────────────────────────────────────┐
│ 📹 XX品牌618推广 │
│ │
│ 审核进度: │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ ✅已提交 → 🤖AI审核中 → ○待代理商审核 → ○待品牌终审 → ○通过 │ │
│ │ ↑当前阶段 │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ 状态: 🤖 AI审核中 更新于: 2分钟前 │
│ [查看详情] │
└─────────────────────────────────────────────────────────────────┘
```
**状态定义与样式:**
| 状态 | 图标 | 颜色 | 标签文案 |
| --- | --- | --- | --- |
| 待提交 | 📤 | 灰色 | 待提交 |
| 已提交 | ✅ | 灰色 | 已提交 |
| AI审核中 | 🤖 | 蓝色(动画) | AI审核中 |
| AI审核通过 | ✅ | 绿色 | AI通过待人工复核 |
| 需修改 | ⚠️ | 橙色 | 需修改 |
| 待代理商审核 | 👥 | 紫色 | 等待代理商审核 |
| 代理商驳回 | ❌ | 红色 | 代理商驳回 |
| 待品牌终审 | 🛡️ | 紫色 | 等待品牌方终审 |
| 品牌方驳回 | ❌ | 红色 | 品牌方驳回 |
| 审核通过 | ✅ | 绿色 | 审核通过,可发布 |
**进度条规则:**
- 终审关闭时:显示 4 步(已提交 → AI审核 → 代理商审核 → 通过)
- 终审开启时:显示 5 步(已提交 → AI审核 → 代理商审核 → 品牌终审 → 通过)
- 当前阶段高亮显示,已完成阶段打勾,未到达阶段灰色
### 2.2 智能上传与扫描页 (The Magic Scanner) [US-03, US-07]
这是达人等待 AI 结果的页面必须缓解等待焦虑Wait-time Anxiety
@ -136,7 +179,38 @@
### 2.3 审核结果反馈页 (Audit Report)
当 AI 发现问题时,不能直接把 JSON 扔给达人,要翻译成“人话”。
当 AI 发现问题时,不能直接把 JSON 扔给达人,要翻译成"人话"。
#### 2.3.1 审核流程进度条 ⭐ F-52
**页面顶部显示完整审核流程进度:**
```
┌─────────────────────────────────────────────────────────────────┐
│ 📹 XX品牌618推广 - 审核详情 返回 ← │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ 已提交 AI审核 代理商审核 最终结果 │ │
│ │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │ │
│ │ │ ✅ │ ───▶ │ ✅ │ ───▶ │ 👥 │ ───▶ │ ○ │ │ │
│ │ │ 完成 │ │ 通过 │ │审核中│ │ 待定 │ │ │
│ │ └──────┘ └──────┘ └──────┘ └──────┘ │ │
│ │ 2/3 10:30 2/3 10:35 当前 │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ 当前状态:👥 等待代理商审核 │
│ 预计处理时间:通常 2-4 小时内 │
│ │
├─────────────────────────────────────────────────────────────────┤
│ 以下为审核详情内容... │
└─────────────────────────────────────────────────────────────────┘
```
**进度条交互:**
- 点击已完成的节点可查看该阶段详情(时间、处理人、结果)
- 当前阶段显示预估等待时间
- 驳回状态时显示驳回原因摘要
* **结果横幅:**
* 🔴 **未通过 (Blocked):** 存在硬性违规,必须修改。
@ -231,6 +305,31 @@
**布局结构:**
#### 3.3.1 审核流程进度条 ⭐ F-52
**页面顶部显示当前任务的审核流程进度:**
```
┌─────────────────────────────────────────────────────────────────┐
│ 审核决策台 返回列表 ← │
├─────────────────────────────────────────────────────────────────┤
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ 审核流程 当前:代理商审核 │ │
│ │ │ │
│ │ ✅已提交 ────▶ ✅AI审核 ────▶ ●代理商审核 ────▶ ○品牌终审 │ │
│ │ ↑当前阶段 │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ [视频播放器区域] [AI检查单区域] │
└─────────────────────────────────────────────────────────────────┘
```
**进度条显示规则:**
- 当前阶段:紫色高亮,大圆点
- 已完成阶段:绿色 ✅,显示完成时间
- 待处理阶段:灰色空心圆
- 品牌终审步骤:仅当品牌方开启终审时显示
* **左侧:视频播放器**
* **智能进度条:** 进度条上打满 colored dots
* 🔴 红点:硬伤(点击跳转)
@ -250,11 +349,13 @@
* **底部:决策栏 (Action Bar)**
* `[ 驳回 ]`:点击后,自动将勾选的问题打包发送给达人
* `[ 强制通过 ]` [US-09]:强制通过(默认可用;品牌方关闭授权时按钮改为“申请强制通过”,提交后进入审批)
* `[ 强制通过 ]` [US-09]:强制通过(默认可用;品牌方关闭授权时按钮改为"申请强制通过",提交后进入审批)
* **必须填写放行原因**(如"达人玩的新梗,品牌方认可"
* 弹窗提供“**保存为特例**”可选项(**默认不勾选**,勾选后形成豁免条款,需品牌方确认后生效)
* 弹窗提供"**保存为特例**"可选项(**默认不勾选**,勾选后形成豁免条款,需品牌方确认后生效)
* **记录审批人**与操作时间,纳入审计日志
* `[ 通过 ]`:流程结束
* `[ 通过 ]`
* 若品牌方**未开启终审**(默认)→ 流程结束,任务状态「已通过」
* 若品牌方**已开启终审** → 进入品牌方终审队列,任务状态「待终审」
@ -360,6 +461,10 @@
│ ← 返回 快捷审核 ⋮ 更多 │
├─────────────────────────────────────────────┤
│ ┌─────────────────────────────────────┐ │
│ │ 审核流程 代理商审核中 │ │
│ │ ✅提交 ─▶ ✅AI ─▶ ●代理商 ─▶ ○终审 │ │
│ └─────────────────────────────────────┘ │
│ ┌─────────────────────────────────────┐ │
│ │ │ │
│ │ 📹 视频播放器 │ │
│ │ (支持横屏全屏) │ │
@ -524,7 +629,101 @@
* **模型版本号:** AI 检测时使用的模型版本
* 完整操作日志(不可篡改)
### 4.5 舆情预警中心 (Brand Safety Center)
### 4.5 终审台 (Final Review) ⭐ 新增
**入口位置:** 品牌方端侧边栏 → 终审台(仅当终审开启时显示)
**触发条件:** 品牌方在系统设置中开启「终审开关」后,代理商初审通过的内容进入此队列
#### 4.5.1 终审列表
```
┌─────────────────────────────────────────────────────────────────┐
│ ✅ 待终审 (8) 筛选 ▼ 搜索 🔍 │
├─────────────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 📹 XX品牌618推广 - 达人A │ │
│ │ 代理商代理商A · 初审人:张三 · 3小时前 │ │
│ │ 🟡 舆情风险 1 项 [查看详情] │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 📹 XX品牌新品测评 - 达人B │ │
│ │ 代理商代理商B · 初审人:李四 · 5小时前 │ │
│ │ ✅ 无风险项 [查看详情] │ │
│ └─────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ ⏱️ 超时提醒2 条内容将在 24 小时内超时 │
└─────────────────────────────────────────────────────────────────┘
```
#### 4.5.2 终审详情页 ⭐ F-52
**UI 设计:** `pencil-new.pen` → "品牌方端 - 终审台" (aePi5)
**审核流程进度条(页面顶部):**
```
┌─────────────────────────────────────────────────────────────────┐
│ 终审台 返回列表 ← │
│ 春季护肤新品体验分享 · 达人: 小美 │
├─────────────────────────────────────────────────────────────────┤
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ 审核流程 当前:品牌终审 │ │
│ │ │ │
│ │ ✅已提交 ────▶ ✅AI审核 ────▶ ✅代理商审核 ────▶ ●品牌终审 │ │
│ │ ↑当前阶段 │ │
│ └────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
```
* **布局:** 复用代理商审核决策台布局(视频播放器 + AI 检查单)
* **额外信息:** 显示代理商初审意见和通过理由
* **决策按钮:**
* `[ 驳回 ]`:填写驳回理由,任务状态变为「终审驳回」,返回达人修改
* `[ 通过 ]`:任务状态变为「已通过」,流程结束
#### 4.5.3 审核流程配置
**入口位置:** 系统设置 → 审核流程配置
```
┌─────────────────────────────────────────────────────────────────┐
│ ⚙️ 审核流程配置 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 品牌方终审 │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ ○ 关闭(默认)- 代理商初审通过即为最终通过 │ │
│ │ ● 开启 - 代理商初审通过后需品牌方终审 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 终审范围(仅当开启终审时可配置) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ ● 全部内容 │ │
│ │ ○ 仅舆情风险内容AI 标记为黄色/红色舆情风险) │ │
│ │ ○ 仅指定代理商 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 终审超时处理 │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 超时时间:[ 48 ] 小时 │ │
│ │ ● 超时后自动通过 │ │
│ │ ○ 超时后仅提醒(不自动通过) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ [ 取消 ] [ 保存 ] │
└─────────────────────────────────────────────────────────────────┘
```
**配置说明:**
| 配置项 | 默认值 | 说明 |
| --- | --- | --- |
| 终审开关 | **关闭** | 关闭时代理商通过即为最终通过 |
| 终审范围 | 全部内容 | 可按内容类型或代理商筛选 |
| 超时时间 | 48小时 | 待终审内容的最长等待时间 |
| 超时处理 | 自动通过 | 超时后自动通过或仅提醒 |
---
### 4.6 舆情预警中心 (Brand Safety Center)
* **实时监控:**
* 近期被 AI 标记为"舆情风险"的视频列表
@ -537,7 +736,7 @@
* **预警规则:**
* 配置自动通知规则(如:高风险视频自动 @品牌方
### 4.6 AI 服务配置 (AI Configuration) 🤖
### 4.7 AI 服务配置 (AI Configuration) 🤖
**入口位置:** 系统设置 → AI 服务配置
**权限控制:** 仅品牌方管理员可配置,代理商和达人自动继承品牌方配置
@ -721,15 +920,26 @@
#### 4.7.3 移动端审批中心 (Approval Center)
**场景:** 当品牌方关闭授权时,代理商申请"强制通过",品牌方需审批。
**场景:**
1. 当品牌方关闭授权时,代理商申请"强制通过",品牌方需审批
2. **当开启品牌终审时,代理商初审通过的视频进入品牌方终审队列** ⭐ F-52
```
┌─────────────────────────────────────────────┐
✅ 待审批 筛选 ▼
审批中心 待审批 │ 已处理
├─────────────────────────────────────────────┤
│ 待处理 (3) │
│ ┌─────────────────────────────────────┐ │
│ │ 🟡 强制通过申请 │ │
│ │ 🟣 视频终审申请 30分钟前│ │
│ │ 达人「小美」的视频「春季护肤新品 │ │
│ │ 体验」已通过代理商审核,等待终审 │ │
│ │ │ │
│ │ 审核流程进度: │ │
│ │ ✅提交 ─▶ ✅AI ─▶ ✅代理商 ─▶ ●终审│ │
│ │ │ │
│ │ [ 拒绝 ] [ 通过 ] │ │
│ └─────────────────────────────────────┘ │
│ ┌─────────────────────────────────────┐ │
│ │ 🟡 强制通过申请 10分钟前│ │
│ │ 达人:@小美美 │ │
│ │ 申请人代理商A - 张三 │ │
│ │ 原因:达人玩的新梗,品牌方认可 │ │
@ -740,18 +950,30 @@
│ │ │ │
│ │ [ 拒绝 ] [ 批准 ] │ │
│ └─────────────────────────────────────┘ │
├─────────────────────────────────────────────┤
│ 已处理 (12) [查看 >] │
│ ┌─────────────────────────────────────┐ │
│ │ 🟡 规则配置变更 2小时前 │ │
│ │ 代理商「星耀传媒」申请修改审核规则│ │
│ │ 竞品露出阈值调整为70% │ │
│ │ │ │
│ │ [ 拒绝 ] [ 通过 ] │ │
│ └─────────────────────────────────────┘ │
├─────────────────────────────────────────────┤
│ 📊 🔔 ✅ 📋 👤 │
└─────────────────────────────────────────────┘
```
**视频终审审批项说明:** ⭐ F-52
* 仅当品牌方开启"终审开关"时显示此类审批项
* 显示完整审核流程进度条,品牌终审阶段高亮
* 点击可查看视频详情和代理商初审意见
* 通过/拒绝后自动通知代理商和达人
**交互说明:**
* 点击视频片段可预览关键时间点
* 批准/拒绝需二次确认
* 批准后自动通知代理商和达人
* 审批记录同步至审计日志
* **进度条交互:** 点击已完成节点可查看该阶段详情(处理人、时间、结果)
#### 4.7.4 移动端审计日志 (Audit Quick View)

View File

@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>SmartAudit · AI 服务配置(说明版)</title>
<title>秒思智能审核平台 · AI 服务配置(说明版)</title>
<style>
:root {
--bg: #0b0c0f;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
/**
*
* UIDesignSpec.md
*/
// UI 基础组件
export { Button, type ButtonProps, type ButtonVariant, type ButtonSize } from './ui/Button';
export { Card, CardHeader, CardTitle, CardContent, CardFooter, type CardProps } from './ui/Card';
export { Tag, SuccessTag, PendingTag, WarningTag, ErrorTag, type TagProps, type TagStatus } from './ui/Tag';
export { Input, SearchInput, PasswordInput, type InputProps } from './ui/Input';
export { Select, type SelectProps, type SelectOption } from './ui/Select';
export { ProgressBar, CircularProgress, type ProgressBarProps, type CircularProgressProps } from './ui/ProgressBar';
export { Modal, ConfirmModal, type ModalProps, type ConfirmModalProps } from './ui/Modal';
// 导航组件
export { BottomNav, type BottomNavProps, type NavItem } from './navigation/BottomNav';
export { Sidebar, type SidebarProps, type SidebarItem, type SidebarSection } from './navigation/Sidebar';
export { StatusBar, type StatusBarProps } from './navigation/StatusBar';
// 布局组件
export { MobileLayout, type MobileLayoutProps } from './layout/MobileLayout';
export { DesktopLayout, type DesktopLayoutProps } from './layout/DesktopLayout';

View File

@ -0,0 +1,61 @@
/**
* DesktopLayout
* 设计稿参考: UIDesignSpec.md 3.2
* 尺寸: 1440x900260px
*/
import React from 'react';
import { Sidebar, SidebarSection } from '../navigation/Sidebar';
export interface DesktopLayoutProps {
children: React.ReactNode;
logo?: React.ReactNode;
sidebarSections: SidebarSection[];
activeNavId: string;
onNavItemClick?: (id: string) => void;
sidebarFooter?: React.ReactNode;
headerContent?: React.ReactNode;
className?: string;
contentClassName?: string;
}
export const DesktopLayout: React.FC<DesktopLayoutProps> = ({
children,
logo,
sidebarSections,
activeNavId,
onNavItemClick,
sidebarFooter,
headerContent,
className = '',
contentClassName = '',
}) => {
return (
<div className={`min-h-screen bg-bg-page ${className}`}>
{/* Sidebar */}
<Sidebar
logo={logo}
sections={sidebarSections}
activeId={activeNavId}
onItemClick={onNavItemClick}
footer={sidebarFooter}
/>
{/* Main Content */}
<div className="ml-sidebar">
{/* Header (optional) */}
{headerContent && (
<header className="px-8 py-4 border-b border-border-subtle bg-bg-page sticky top-0 z-10">
{headerContent}
</header>
)}
{/* Content Area */}
<main className={`p-8 ${contentClassName}`}>
{children}
</main>
</div>
</div>
);
};
export default DesktopLayout;

View File

@ -0,0 +1,66 @@
/**
* MobileLayout
* 设计稿参考: UIDesignSpec.md 3.1
* 尺寸: 402x874
*/
import React from 'react';
import { StatusBar } from '../navigation/StatusBar';
import { BottomNav, NavItem } from '../navigation/BottomNav';
export interface MobileLayoutProps {
children: React.ReactNode;
navItems?: NavItem[];
activeNavId?: string;
onNavItemClick?: (id: string) => void;
showStatusBar?: boolean;
showBottomNav?: boolean;
className?: string;
contentClassName?: string;
}
export const MobileLayout: React.FC<MobileLayoutProps> = ({
children,
navItems = [],
activeNavId = '',
onNavItemClick,
showStatusBar = true,
showBottomNav = true,
className = '',
contentClassName = '',
}) => {
return (
<div
className={`
min-h-screen bg-bg-page
flex flex-col
${className}
`}
>
{/* Status Bar */}
{showStatusBar && <StatusBar />}
{/* Content Area */}
<main
className={`
flex-1 overflow-y-auto
px-6 py-4
${showBottomNav ? 'pb-[99px]' : ''}
${contentClassName}
`}
>
{children}
</main>
{/* Bottom Navigation */}
{showBottomNav && navItems.length > 0 && (
<BottomNav
items={navItems}
activeId={activeNavId}
onItemClick={onNavItemClick}
/>
)}
</div>
);
};
export default MobileLayout;

View File

@ -0,0 +1,81 @@
/**
* BottomNav ()
* 设计稿参考: UIDesignSpec.md 3.6
*/
import React from 'react';
import { LucideIcon } from 'lucide-react';
export interface NavItem {
id: string;
label: string;
icon: LucideIcon;
href?: string;
badge?: number;
}
export interface BottomNavProps {
items: NavItem[];
activeId: string;
onItemClick?: (id: string) => void;
className?: string;
}
export const BottomNav: React.FC<BottomNavProps> = ({
items,
activeId,
onItemClick,
className = '',
}) => {
return (
<nav
className={`
fixed bottom-0 left-0 right-0 z-bottom-nav
flex justify-around items-center
h-bottom-nav px-[21px] py-3
safe-area-bottom
${className}
`}
style={{
background: 'linear-gradient(180deg, transparent 0%, #0B0B0E 50%)',
}}
>
{items.map((item) => {
const isActive = item.id === activeId;
const Icon = item.icon;
return (
<button
key={item.id}
onClick={() => onItemClick?.(item.id)}
className={`
flex flex-col items-center gap-1
transition-colors duration-200
${isActive ? 'text-accent-indigo' : 'text-text-secondary'}
`}
>
<div className="relative">
<Icon size={24} />
{item.badge !== undefined && item.badge > 0 && (
<span
className="
absolute -top-1 -right-1
min-w-[16px] h-4 px-1
flex items-center justify-center
bg-accent-coral text-white
text-[10px] font-semibold
rounded-full
"
>
{item.badge > 99 ? '99+' : item.badge}
</span>
)}
</div>
<span className="text-nav">{item.label}</span>
</button>
);
})}
</nav>
);
};
export default BottomNav;

View File

@ -0,0 +1,136 @@
/**
* Sidebar ()
* 设计稿参考: UIDesignSpec.md 3.7
*/
import React from 'react';
import { LucideIcon } from 'lucide-react';
export interface SidebarItem {
id: string;
label: string;
icon: LucideIcon;
href?: string;
badge?: number;
children?: SidebarItem[];
}
export interface SidebarSection {
title?: string;
items: SidebarItem[];
}
export interface SidebarProps {
logo?: React.ReactNode;
sections: SidebarSection[];
activeId: string;
onItemClick?: (id: string) => void;
footer?: React.ReactNode;
className?: string;
}
export const Sidebar: React.FC<SidebarProps> = ({
logo,
sections,
activeId,
onItemClick,
footer,
className = '',
}) => {
return (
<aside
className={`
fixed left-0 top-0 bottom-0 z-sidebar
w-sidebar bg-bg-card
flex flex-col
border-r border-border-subtle
${className}
`}
>
{/* Logo */}
{logo && (
<div className="px-4 py-5 border-b border-border-subtle">
{logo}
</div>
)}
{/* Navigation */}
<nav className="flex-1 overflow-y-auto py-4 px-3">
{sections.map((section, sectionIndex) => (
<div key={sectionIndex} className="mb-6">
{section.title && (
<h4 className="px-3 mb-2 text-small text-text-tertiary uppercase tracking-wider">
{section.title}
</h4>
)}
<ul className="space-y-1">
{section.items.map((item) => (
<SidebarNavItem
key={item.id}
item={item}
isActive={item.id === activeId}
onClick={() => onItemClick?.(item.id)}
/>
))}
</ul>
</div>
))}
</nav>
{/* Footer */}
{footer && (
<div className="px-4 py-4 border-t border-border-subtle">
{footer}
</div>
)}
</aside>
);
};
interface SidebarNavItemProps {
item: SidebarItem;
isActive: boolean;
onClick: () => void;
}
const SidebarNavItem: React.FC<SidebarNavItemProps> = ({
item,
isActive,
onClick,
}) => {
const Icon = item.icon;
return (
<li>
<button
onClick={onClick}
className={`
w-full flex items-center gap-2.5
px-3 py-2.5 rounded-btn
transition-colors duration-200
${isActive
? 'bg-bg-elevated text-accent-indigo font-semibold'
: 'text-text-secondary hover:bg-bg-elevated'
}
`}
>
<Icon size={20} className="flex-shrink-0" />
<span className="flex-1 text-left text-body">{item.label}</span>
{item.badge !== undefined && item.badge > 0 && (
<span
className="
min-w-[20px] h-5 px-1.5
flex items-center justify-center
bg-accent-coral text-white
text-[11px] font-semibold
rounded-full
"
>
{item.badge > 99 ? '99+' : item.badge}
</span>
)}
</button>
</li>
);
};
export default Sidebar;

View File

@ -0,0 +1,41 @@
/**
* StatusBar ()
* 设计稿参考: UIDesignSpec.md 3.1
*/
import React from 'react';
import { Signal, Wifi, BatteryFull } from 'lucide-react';
export interface StatusBarProps {
time?: string;
className?: string;
}
export const StatusBar: React.FC<StatusBarProps> = ({
time = '9:41',
className = '',
}) => {
return (
<div
className={`
flex items-center justify-between
h-status-bar px-6
bg-bg-page safe-area-top
${className}
`}
>
{/* Time */}
<span className="text-body font-semibold text-text-primary">
{time}
</span>
{/* Status Icons */}
<div className="flex items-center gap-1">
<Signal size={16} className="text-text-primary" />
<Wifi size={16} className="text-text-primary" />
<BatteryFull size={16} className="text-text-primary" />
</div>
</div>
);
};
export default StatusBar;

View File

@ -0,0 +1,104 @@
/**
* Button
* 设计稿参考: UIDesignSpec.md 3.4
*/
import React from 'react';
import { LucideIcon } from 'lucide-react';
export type ButtonVariant = 'primary' | 'secondary' | 'danger' | 'success' | 'ghost';
export type ButtonSize = 'sm' | 'md' | 'lg';
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: ButtonVariant;
size?: ButtonSize;
icon?: LucideIcon;
iconPosition?: 'left' | 'right';
loading?: boolean;
fullWidth?: boolean;
children?: React.ReactNode;
}
const variantStyles: Record<ButtonVariant, string> = {
primary: 'bg-accent-indigo text-white hover:opacity-90 active:opacity-80',
secondary: 'bg-bg-elevated text-text-secondary hover:bg-opacity-80',
danger: 'bg-accent-coral text-white hover:opacity-90 active:opacity-80',
success: 'bg-accent-green text-white hover:opacity-90 active:opacity-80',
ghost: 'bg-transparent text-text-secondary hover:bg-bg-elevated',
};
const sizeStyles: Record<ButtonSize, string> = {
sm: 'px-3 py-1.5 text-small',
md: 'px-4 py-2.5 text-body',
lg: 'px-6 py-3 text-section-title',
};
const iconSizes: Record<ButtonSize, number> = {
sm: 14,
md: 16,
lg: 20,
};
export const Button: React.FC<ButtonProps> = ({
variant = 'primary',
size = 'md',
icon: Icon,
iconPosition = 'left',
loading = false,
fullWidth = false,
children,
className = '',
disabled,
...props
}) => {
const isDisabled = disabled || loading;
const iconSize = iconSizes[size];
return (
<button
className={`
inline-flex items-center justify-center gap-2 font-semibold
rounded-btn transition-all duration-200
${variantStyles[variant]}
${sizeStyles[size]}
${fullWidth ? 'w-full' : ''}
${isDisabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
${className}
`}
disabled={isDisabled}
{...props}
>
{loading && (
<svg
className="animate-spin"
width={iconSize}
height={iconSize}
viewBox="0 0 24 24"
fill="none"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
/>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
/>
</svg>
)}
{!loading && Icon && iconPosition === 'left' && (
<Icon size={iconSize} />
)}
{children}
{!loading && Icon && iconPosition === 'right' && (
<Icon size={iconSize} />
)}
</button>
);
};
export default Button;

View File

@ -0,0 +1,81 @@
/**
* Card
* 设计稿参考: UIDesignSpec.md 3.3
*/
import React from 'react';
export interface CardProps {
children: React.ReactNode;
className?: string;
variant?: 'default' | 'elevated';
padding?: 'mobile' | 'desktop' | 'none';
onClick?: () => void;
hoverable?: boolean;
}
const paddingStyles = {
mobile: 'p-[14px_16px]',
desktop: 'p-[16px_20px]',
none: 'p-0',
};
export const Card: React.FC<CardProps> = ({
children,
className = '',
variant = 'default',
padding = 'mobile',
onClick,
hoverable = false,
}) => {
return (
<div
className={`
bg-bg-card rounded-card
${paddingStyles[padding]}
${variant === 'elevated' ? 'bg-bg-elevated shadow-elevated' : ''}
${hoverable ? 'cursor-pointer transition-all duration-200 hover:bg-bg-elevated hover:shadow-card' : ''}
${onClick ? 'cursor-pointer' : ''}
${className}
`}
onClick={onClick}
>
{children}
</div>
);
};
export const CardHeader: React.FC<{
children: React.ReactNode;
className?: string;
}> = ({ children, className = '' }) => (
<div className={`flex items-center justify-between mb-3 ${className}`}>
{children}
</div>
);
export const CardTitle: React.FC<{
children: React.ReactNode;
className?: string;
}> = ({ children, className = '' }) => (
<h3 className={`text-section-title text-text-primary font-semibold ${className}`}>
{children}
</h3>
);
export const CardContent: React.FC<{
children: React.ReactNode;
className?: string;
}> = ({ children, className = '' }) => (
<div className={className}>{children}</div>
);
export const CardFooter: React.FC<{
children: React.ReactNode;
className?: string;
}> = ({ children, className = '' }) => (
<div className={`mt-4 pt-4 border-t border-border-subtle ${className}`}>
{children}
</div>
);
export default Card;

View File

@ -0,0 +1,112 @@
/**
* Input
* 设计稿参考: UIDesignSpec.md
*/
import React, { forwardRef } from 'react';
import { LucideIcon, Search, Eye, EyeOff } from 'lucide-react';
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
label?: string;
error?: string;
hint?: string;
leftIcon?: LucideIcon;
rightIcon?: LucideIcon;
onRightIconClick?: () => void;
fullWidth?: boolean;
}
export const Input = forwardRef<HTMLInputElement, InputProps>(({
label,
error,
hint,
leftIcon: LeftIcon,
rightIcon: RightIcon,
onRightIconClick,
fullWidth = true,
className = '',
disabled,
...props
}, ref) => {
return (
<div className={`${fullWidth ? 'w-full' : ''}`}>
{label && (
<label className="block mb-1.5 text-caption text-text-secondary">
{label}
</label>
)}
<div className="relative">
{LeftIcon && (
<LeftIcon
size={18}
className="absolute left-3 top-1/2 -translate-y-1/2 text-text-tertiary"
/>
)}
<input
ref={ref}
className={`
w-full bg-bg-elevated text-text-primary
border border-border-subtle rounded-btn
px-4 py-2.5 text-body
transition-colors duration-200
placeholder:text-text-tertiary
focus:outline-none focus:border-accent-indigo
disabled:opacity-50 disabled:cursor-not-allowed
${LeftIcon ? 'pl-10' : ''}
${RightIcon ? 'pr-10' : ''}
${error ? 'border-accent-coral focus:border-accent-coral' : ''}
${className}
`}
disabled={disabled}
{...props}
/>
{RightIcon && (
<button
type="button"
onClick={onRightIconClick}
className="absolute right-3 top-1/2 -translate-y-1/2 text-text-tertiary hover:text-text-secondary"
>
<RightIcon size={18} />
</button>
)}
</div>
{error && (
<p className="mt-1 text-small text-accent-coral">{error}</p>
)}
{hint && !error && (
<p className="mt-1 text-small text-text-tertiary">{hint}</p>
)}
</div>
);
});
Input.displayName = 'Input';
// 搜索输入框
export const SearchInput = forwardRef<HTMLInputElement, Omit<InputProps, 'leftIcon'>>(
(props, ref) => (
<Input ref={ref} leftIcon={Search} placeholder="搜索..." {...props} />
)
);
SearchInput.displayName = 'SearchInput';
// 密码输入框
export const PasswordInput = forwardRef<HTMLInputElement, Omit<InputProps, 'type' | 'rightIcon'>>(
(props, ref) => {
const [showPassword, setShowPassword] = React.useState(false);
return (
<Input
ref={ref}
type={showPassword ? 'text' : 'password'}
rightIcon={showPassword ? EyeOff : Eye}
onRightIconClick={() => setShowPassword(!showPassword)}
{...props}
/>
);
}
);
PasswordInput.displayName = 'PasswordInput';
export default Input;

View File

@ -0,0 +1,166 @@
/**
* Modal
* 设计稿参考: UIDesignSpec.md
*/
import React, { useEffect, useCallback } from 'react';
import { X } from 'lucide-react';
import { Button } from './Button';
export interface ModalProps {
isOpen: boolean;
onClose: () => void;
title?: string;
children: React.ReactNode;
footer?: React.ReactNode;
size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';
closeOnOverlay?: boolean;
closeOnEsc?: boolean;
showCloseButton?: boolean;
className?: string;
}
const sizeStyles = {
sm: 'max-w-sm',
md: 'max-w-md',
lg: 'max-w-lg',
xl: 'max-w-xl',
full: 'max-w-[90vw] max-h-[90vh]',
};
export const Modal: React.FC<ModalProps> = ({
isOpen,
onClose,
title,
children,
footer,
size = 'md',
closeOnOverlay = true,
closeOnEsc = true,
showCloseButton = true,
className = '',
}) => {
// Handle ESC key
const handleKeyDown = useCallback((e: KeyboardEvent) => {
if (closeOnEsc && e.key === 'Escape') {
onClose();
}
}, [closeOnEsc, onClose]);
useEffect(() => {
if (isOpen) {
document.addEventListener('keydown', handleKeyDown);
document.body.style.overflow = 'hidden';
}
return () => {
document.removeEventListener('keydown', handleKeyDown);
document.body.style.overflow = '';
};
}, [isOpen, handleKeyDown]);
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-modal flex items-center justify-center">
{/* Overlay */}
<div
className="absolute inset-0 bg-black/60 backdrop-blur-xs"
onClick={closeOnOverlay ? onClose : undefined}
/>
{/* Modal Content */}
<div
className={`
relative w-full mx-4
bg-bg-card rounded-card
shadow-elevated
animate-scale-in
${sizeStyles[size]}
${className}
`}
>
{/* Header */}
{(title || showCloseButton) && (
<div className="flex items-center justify-between px-5 py-4 border-b border-border-subtle">
{title && (
<h2 className="text-section-title text-text-primary font-semibold">
{title}
</h2>
)}
{showCloseButton && (
<button
onClick={onClose}
className="p-1 text-text-tertiary hover:text-text-primary transition-colors"
>
<X size={20} />
</button>
)}
</div>
)}
{/* Body */}
<div className="px-5 py-4 max-h-[60vh] overflow-y-auto">
{children}
</div>
{/* Footer */}
{footer && (
<div className="px-5 py-4 border-t border-border-subtle flex justify-end gap-3">
{footer}
</div>
)}
</div>
</div>
);
};
// 确认弹窗
export interface ConfirmModalProps {
isOpen: boolean;
onClose: () => void;
onConfirm: () => void;
title: string;
message: string;
confirmText?: string;
cancelText?: string;
variant?: 'default' | 'danger';
loading?: boolean;
}
export const ConfirmModal: React.FC<ConfirmModalProps> = ({
isOpen,
onClose,
onConfirm,
title,
message,
confirmText = '确认',
cancelText = '取消',
variant = 'default',
loading = false,
}) => {
return (
<Modal
isOpen={isOpen}
onClose={onClose}
title={title}
size="sm"
footer={
<>
<Button variant="secondary" onClick={onClose} disabled={loading}>
{cancelText}
</Button>
<Button
variant={variant === 'danger' ? 'danger' : 'primary'}
onClick={onConfirm}
loading={loading}
>
{confirmText}
</Button>
</>
}
>
<p className="text-body text-text-secondary">{message}</p>
</Modal>
);
};
export default Modal;

View File

@ -0,0 +1,129 @@
/**
* ProgressBar
*
*/
import React from 'react';
export interface ProgressBarProps {
value: number; // 0-100
max?: number;
showLabel?: boolean;
size?: 'sm' | 'md' | 'lg';
variant?: 'default' | 'success' | 'warning' | 'error';
className?: string;
}
const sizeStyles = {
sm: 'h-1',
md: 'h-2',
lg: 'h-3',
};
const variantStyles = {
default: 'bg-accent-indigo',
success: 'bg-accent-green',
warning: 'bg-accent-amber',
error: 'bg-accent-coral',
};
export const ProgressBar: React.FC<ProgressBarProps> = ({
value,
max = 100,
showLabel = false,
size = 'md',
variant = 'default',
className = '',
}) => {
const percentage = Math.min(100, Math.max(0, (value / max) * 100));
return (
<div className={`w-full ${className}`}>
{showLabel && (
<div className="flex justify-between mb-1">
<span className="text-small text-text-secondary"></span>
<span className="text-small text-text-primary">{Math.round(percentage)}%</span>
</div>
)}
<div className={`w-full bg-bg-elevated rounded-full overflow-hidden ${sizeStyles[size]}`}>
<div
className={`h-full rounded-full transition-all duration-300 ${variantStyles[variant]}`}
style={{ width: `${percentage}%` }}
/>
</div>
</div>
);
};
// 环形进度条 (用于审核中状态)
export interface CircularProgressProps {
value: number; // 0-100
size?: number;
strokeWidth?: number;
variant?: 'default' | 'success' | 'warning' | 'error';
showLabel?: boolean;
label?: string;
className?: string;
}
const circularVariantColors = {
default: '#6366F1',
success: '#32D583',
warning: '#F59E0B',
error: '#E85A4F',
};
export const CircularProgress: React.FC<CircularProgressProps> = ({
value,
size = 120,
strokeWidth = 8,
variant = 'default',
showLabel = true,
label,
className = '',
}) => {
const percentage = Math.min(100, Math.max(0, value));
const radius = (size - strokeWidth) / 2;
const circumference = radius * 2 * Math.PI;
const offset = circumference - (percentage / 100) * circumference;
return (
<div className={`relative inline-flex items-center justify-center ${className}`}>
<svg width={size} height={size} className="-rotate-90">
{/* Background circle */}
<circle
cx={size / 2}
cy={size / 2}
r={radius}
fill="none"
stroke="#27272A"
strokeWidth={strokeWidth}
/>
{/* Progress circle */}
<circle
cx={size / 2}
cy={size / 2}
r={radius}
fill="none"
stroke={circularVariantColors[variant]}
strokeWidth={strokeWidth}
strokeLinecap="round"
strokeDasharray={circumference}
strokeDashoffset={offset}
className="transition-all duration-500"
/>
</svg>
{showLabel && (
<div className="absolute inset-0 flex flex-col items-center justify-center">
<span className="text-card-title text-text-primary">
{Math.round(percentage)}%
</span>
{label && (
<span className="text-small text-text-tertiary mt-1">{label}</span>
)}
</div>
)}
</div>
);
};
export default ProgressBar;

View File

@ -0,0 +1,90 @@
/**
* Select
* 设计稿参考: UIDesignSpec.md
*/
import React, { forwardRef } from 'react';
import { ChevronDown } from 'lucide-react';
export interface SelectOption {
value: string;
label: string;
disabled?: boolean;
}
export interface SelectProps extends Omit<React.SelectHTMLAttributes<HTMLSelectElement>, 'children'> {
label?: string;
error?: string;
hint?: string;
options: SelectOption[];
placeholder?: string;
fullWidth?: boolean;
}
export const Select = forwardRef<HTMLSelectElement, SelectProps>(({
label,
error,
hint,
options,
placeholder,
fullWidth = true,
className = '',
disabled,
...props
}, ref) => {
return (
<div className={`${fullWidth ? 'w-full' : ''}`}>
{label && (
<label className="block mb-1.5 text-caption text-text-secondary">
{label}
</label>
)}
<div className="relative">
<select
ref={ref}
className={`
w-full bg-bg-elevated text-text-primary
border border-border-subtle rounded-btn
px-4 py-2.5 text-body
appearance-none cursor-pointer
transition-colors duration-200
focus:outline-none focus:border-accent-indigo
disabled:opacity-50 disabled:cursor-not-allowed
${error ? 'border-accent-coral focus:border-accent-coral' : ''}
${className}
`}
disabled={disabled}
{...props}
>
{placeholder && (
<option value="" disabled>
{placeholder}
</option>
)}
{options.map((option) => (
<option
key={option.value}
value={option.value}
disabled={option.disabled}
>
{option.label}
</option>
))}
</select>
<ChevronDown
size={18}
className="absolute right-3 top-1/2 -translate-y-1/2 text-text-tertiary pointer-events-none"
/>
</div>
{error && (
<p className="mt-1 text-small text-accent-coral">{error}</p>
)}
{hint && !error && (
<p className="mt-1 text-small text-text-tertiary">{hint}</p>
)}
</div>
);
});
Select.displayName = 'Select';
export default Select;

View File

@ -0,0 +1,98 @@
/**
* Tag
* 设计稿参考: UIDesignSpec.md 3.5
*/
import React from 'react';
import { LucideIcon, Check, Clock, AlertTriangle, XCircle } from 'lucide-react';
export type TagStatus = 'success' | 'pending' | 'warning' | 'error';
export type TagSize = 'sm' | 'md';
export interface TagProps {
status: TagStatus;
children: React.ReactNode;
size?: TagSize;
icon?: LucideIcon | boolean;
className?: string;
}
const statusStyles: Record<TagStatus, { bg: string; text: string; defaultIcon: LucideIcon }> = {
success: {
bg: 'bg-status-success',
text: 'text-accent-green',
defaultIcon: Check,
},
pending: {
bg: 'bg-status-pending',
text: 'text-accent-indigo',
defaultIcon: Clock,
},
warning: {
bg: 'bg-status-warning',
text: 'text-accent-amber',
defaultIcon: AlertTriangle,
},
error: {
bg: 'bg-status-error',
text: 'text-accent-coral',
defaultIcon: XCircle,
},
};
const sizeStyles: Record<TagSize, { padding: string; text: string; iconSize: number }> = {
sm: { padding: 'px-1.5 py-0.5', text: 'text-[11px]', iconSize: 12 },
md: { padding: 'px-2 py-1', text: 'text-small', iconSize: 14 },
};
export const Tag: React.FC<TagProps> = ({
status,
children,
size = 'md',
icon,
className = '',
}) => {
const styles = statusStyles[status];
const sizeStyle = sizeStyles[size];
const showIcon = icon !== false;
const IconComponent = icon === true || icon === undefined ? styles.defaultIcon : icon;
return (
<span
className={`
inline-flex items-center gap-1 font-medium rounded-tag
${styles.bg} ${styles.text}
${sizeStyle.padding} ${sizeStyle.text}
${className}
`}
>
{showIcon && IconComponent && (
<IconComponent size={sizeStyle.iconSize} />
)}
{children}
</span>
);
};
// 预定义的状态标签
export const SuccessTag: React.FC<{ children: React.ReactNode; size?: TagSize }> = ({
children,
size,
}) => <Tag status="success" size={size}>{children}</Tag>;
export const PendingTag: React.FC<{ children: React.ReactNode; size?: TagSize }> = ({
children,
size,
}) => <Tag status="pending" size={size}>{children}</Tag>;
export const WarningTag: React.FC<{ children: React.ReactNode; size?: TagSize }> = ({
children,
size,
}) => <Tag status="warning" size={size}>{children}</Tag>;
export const ErrorTag: React.FC<{ children: React.ReactNode; size?: TagSize }> = ({
children,
size,
}) => <Tag status="error" size={size}>{children}</Tag>;
export default Tag;

View File

@ -0,0 +1,66 @@
/**
*
* 设计稿参考: UIDesignSpec.md 1.1
*/
// 背景色
export const BG_COLORS = {
page: '#0B0B0E',
card: '#16161A',
elevated: '#1A1A1E',
} as const;
// 文字色
export const TEXT_COLORS = {
primary: '#FAFAF9',
secondary: '#A1A1AA',
tertiary: '#71717A',
} as const;
// 强调色
export const ACCENT_COLORS = {
indigo: '#6366F1',
green: '#32D583',
coral: '#E85A4F',
amber: '#F59E0B',
} as const;
// 边框色
export const BORDER_COLORS = {
subtle: '#27272A',
} as const;
// 状态色 (带透明度用于背景)
export const STATUS_COLORS = {
success: {
bg: 'rgba(50, 213, 131, 0.125)',
text: '#32D583',
},
pending: {
bg: 'rgba(99, 102, 241, 0.125)',
text: '#6366F1',
},
warning: {
bg: 'rgba(245, 158, 11, 0.125)',
text: '#F59E0B',
},
error: {
bg: 'rgba(232, 90, 79, 0.125)',
text: '#E85A4F',
},
} as const;
// CSS 变量名映射
export const CSS_VARS = {
bgPage: '--bg-page',
bgCard: '--bg-card',
bgElevated: '--bg-elevated',
textPrimary: '--text-primary',
textSecondary: '--text-secondary',
textTertiary: '--text-tertiary',
accentIndigo: '--accent-indigo',
accentGreen: '--accent-green',
accentCoral: '--accent-coral',
accentAmber: '--accent-amber',
borderSubtle: '--border-subtle',
} as const;

View File

@ -0,0 +1,92 @@
/**
*
* 设计稿参考: UIDesignSpec.md 2.2
* 使 Lucide Icons
*/
// 导航图标映射
export const NAV_ICONS = {
// 通用导航
home: 'house', // 工作台/首页
tasks: 'clipboard-list', // 任务
review: 'circle-check', // 审核/审批
reviewDesk: 'clipboard-check', // 审核台
messages: 'bell', // 消息/通知
profile: 'user', // 个人中心
// 侧边栏导航
creators: 'users', // 达人管理
dashboard: 'chart-column', // 数据看板/报表
sentiment: 'triangle-alert', // 舆情预警
agencies: 'building-2', // 代理商管理
auditLog: 'scroll-text', // 审计日志
settings: 'settings', // 系统设置
brief: 'file-text', // Brief管理
versionCompare: 'git-compare', // 版本比对
} as const;
// 操作图标映射
export const ACTION_ICONS = {
filter: 'sliders-horizontal', // 筛选
search: 'search', // 搜索
add: 'plus', // 添加
edit: 'pencil', // 编辑
view: 'eye', // 查看
download: 'download', // 下载/导出
arrowRight: 'chevron-right', // 箭头右
arrowDown: 'chevron-down', // 箭头下
} as const;
// 状态栏图标映射
export const STATUS_BAR_ICONS = {
signal: 'signal',
wifi: 'wifi',
battery: 'battery-full',
} as const;
// 其他图标映射
export const MISC_ICONS = {
security: 'shield-check', // 隐私与安全
info: 'info', // 关于我们
help: 'message-circle', // 帮助与反馈
} as const;
// 图标尺寸常量
export const ICON_SIZES = {
bottomNav: 24,
sidebar: 20,
button: 16,
statusBar: 16,
} as const;
// Lucide React 图标导入映射 (便于动态使用)
export const LUCIDE_ICON_MAP = {
'house': 'House',
'clipboard-list': 'ClipboardList',
'circle-check': 'CircleCheck',
'clipboard-check': 'ClipboardCheck',
'bell': 'Bell',
'user': 'User',
'users': 'Users',
'chart-column': 'ChartColumn',
'triangle-alert': 'TriangleAlert',
'building-2': 'Building2',
'scroll-text': 'ScrollText',
'settings': 'Settings',
'file-text': 'FileText',
'git-compare': 'GitCompare',
'sliders-horizontal': 'SlidersHorizontal',
'search': 'Search',
'plus': 'Plus',
'pencil': 'Pencil',
'eye': 'Eye',
'download': 'Download',
'chevron-right': 'ChevronRight',
'chevron-down': 'ChevronDown',
'signal': 'Signal',
'wifi': 'Wifi',
'battery-full': 'BatteryFull',
'shield-check': 'ShieldCheck',
'info': 'Info',
'message-circle': 'MessageCircle',
} as const;

View File

@ -0,0 +1,69 @@
/**
*
*/
export * from './colors';
export * from './icons';
// 布局尺寸常量
export const LAYOUT = {
// 移动端
mobile: {
width: 402,
height: 874,
statusBarHeight: 44,
bottomNavHeight: 83,
paddingX: 24,
paddingY: 16,
},
// 桌面端
desktop: {
minWidth: 1280,
maxWidth: 1440,
height: 900,
sidebarWidth: 260,
padding: 32,
},
// 响应式断点
breakpoints: {
mobile: 768,
tablet: 1024,
desktop: 1280,
},
} as const;
// 圆角常量
export const RADIUS = {
card: 12,
btn: 8,
tag: 4,
} as const;
// 间距常量
export const SPACING = {
xs: 4,
sm: 8,
md: 12,
lg: 16,
xl: 20,
'2xl': 24,
'3xl': 32,
} as const;
// 字体大小常量
export const FONT_SIZES = {
pageTitle: 24,
cardTitle: 22,
sectionTitle: 16,
body: 15,
caption: 13,
small: 12,
nav: 11,
} as const;
// 动画时长常量
export const ANIMATION = {
fast: 150,
normal: 200,
slow: 300,
} as const;

48
frontend/package.json Normal file
View File

@ -0,0 +1,48 @@
{
"name": "smartaudit-frontend",
"version": "1.0.0",
"description": "秒思智能审核平台AI 营销内容合规审核平台)- 前端",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"test": "vitest",
"test:coverage": "vitest --coverage"
},
"dependencies": {
"next": "^14.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"lucide-react": "^0.300.0",
"zustand": "^4.4.0",
"axios": "^1.6.0",
"@uppy/core": "^3.8.0",
"@uppy/tus": "^3.4.0",
"@uppy/react": "^3.2.0",
"socket.io-client": "^4.7.0",
"clsx": "^2.1.0",
"tailwind-merge": "^2.2.0"
},
"devDependencies": {
"@types/node": "^20.10.0",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"typescript": "^5.3.0",
"tailwindcss": "^3.4.0",
"postcss": "^8.4.0",
"autoprefixer": "^10.4.0",
"eslint": "^8.55.0",
"eslint-config-next": "^14.0.0",
"vitest": "^1.0.0",
"@testing-library/react": "^14.1.0",
"@testing-library/jest-dom": "^6.1.0",
"@vitejs/plugin-react": "^4.2.0",
"jsdom": "^23.0.0",
"@vitest/coverage-v8": "^1.0.0"
},
"engines": {
"node": ">=18.0.0"
}
}

View File

@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};

434
frontend/styles/globals.css Normal file
View File

@ -0,0 +1,434 @@
/* 秒思智能审核平台 - 全局样式文件 */
/* 基于 UIDesignSpec.md 设计规范 */
@import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap');
@tailwind base;
@tailwind components;
@tailwind utilities;
/* ========================================
1. CSS Variables (设计令牌)
======================================== */
:root {
/* 背景色 */
--bg-page: #0B0B0E;
--bg-card: #16161A;
--bg-elevated: #1A1A1E;
/* 文字色 */
--text-primary: #FAFAF9;
--text-secondary: #A1A1AA;
--text-tertiary: #71717A;
/* 强调色 */
--accent-indigo: #6366F1;
--accent-green: #32D583;
--accent-coral: #E85A4F;
--accent-amber: #F59E0B;
/* 边框色 */
--border-subtle: #27272A;
/* 字体 */
--font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
/* 圆角 */
--radius-card: 12px;
--radius-btn: 8px;
--radius-tag: 4px;
/* 间距 */
--spacing-xs: 4px;
--spacing-sm: 8px;
--spacing-md: 12px;
--spacing-lg: 16px;
--spacing-xl: 20px;
--spacing-2xl: 24px;
--spacing-3xl: 32px;
}
/* ========================================
2. Base Styles (基础样式)
======================================== */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
font-size: 16px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
font-family: var(--font-family);
background-color: var(--bg-page);
color: var(--text-primary);
line-height: 1.5;
}
/* ========================================
3. Typography (字体系统)
======================================== */
.text-page-title {
font-size: 24px;
font-weight: 700;
color: var(--text-primary);
}
.text-card-title {
font-size: 22px;
font-weight: 700;
color: var(--text-primary);
}
.text-section-title {
font-size: 16px;
font-weight: 600;
color: var(--text-primary);
}
.text-body {
font-size: 15px;
font-weight: 400;
color: var(--text-primary);
}
.text-caption {
font-size: 13px;
font-weight: 400;
color: var(--text-secondary);
}
.text-small {
font-size: 12px;
font-weight: 400;
color: var(--text-tertiary);
}
.text-nav {
font-size: 11px;
font-weight: 400;
}
/* ========================================
4. Component Styles (组件样式)
======================================== */
/* Card 卡片 */
@layer components {
.card {
@apply bg-bg-card rounded-card;
padding: 14px 16px;
}
.card-desktop {
@apply bg-bg-card rounded-card;
padding: 16px 20px;
}
}
/* Button 按钮 */
@layer components {
.btn {
@apply inline-flex items-center justify-center font-semibold transition-all duration-200;
border-radius: var(--radius-btn);
}
.btn-primary {
@apply btn bg-accent-indigo text-white;
padding: 10px 16px;
}
.btn-primary:hover {
@apply opacity-90;
}
.btn-primary:active {
@apply opacity-80;
}
.btn-secondary {
@apply btn bg-bg-elevated text-text-secondary;
padding: 8px 16px;
}
.btn-secondary:hover {
@apply bg-opacity-80;
}
.btn-danger {
@apply btn bg-accent-coral text-white;
padding: 10px 16px;
}
.btn-success {
@apply btn bg-accent-green text-white;
padding: 10px 16px;
}
}
/* Status Tags 状态标签 */
@layer components {
.tag {
@apply inline-flex items-center px-2 py-1 text-xs font-medium;
border-radius: var(--radius-tag);
}
.tag-success {
background-color: rgba(50, 213, 131, 0.125);
color: var(--accent-green);
}
.tag-pending {
background-color: rgba(99, 102, 241, 0.125);
color: var(--accent-indigo);
}
.tag-error {
background-color: rgba(232, 90, 79, 0.125);
color: var(--accent-coral);
}
.tag-warning {
background-color: rgba(245, 158, 11, 0.125);
color: var(--accent-amber);
}
}
/* Bottom Navigation 底部导航 (移动端) */
@layer components {
.bottom-nav {
@apply fixed bottom-0 left-0 right-0 flex justify-around items-center;
height: 83px;
padding: 12px 21px;
background: linear-gradient(180deg, transparent 0%, var(--bg-page) 50%);
}
.nav-item {
@apply flex flex-col items-center gap-1 text-text-secondary;
}
.nav-item.active {
@apply text-accent-indigo;
}
.nav-item-icon {
@apply w-6 h-6;
}
.nav-item-label {
@apply text-nav;
}
}
/* Sidebar Navigation 侧边栏导航 (桌面端) */
@layer components {
.sidebar {
@apply fixed left-0 top-0 bottom-0 bg-bg-card flex flex-col;
width: 260px;
}
.sidebar-nav-item {
@apply flex items-center gap-2.5 px-3 py-2.5 rounded-btn text-text-secondary transition-colors;
}
.sidebar-nav-item:hover {
@apply bg-bg-elevated;
}
.sidebar-nav-item.active {
@apply bg-bg-elevated text-accent-indigo font-semibold;
}
.sidebar-nav-icon {
@apply w-5 h-5;
}
}
/* Status Bar 状态栏 (移动端) */
@layer components {
.status-bar {
@apply flex items-center justify-between px-6;
height: 44px;
background-color: var(--bg-page);
}
.status-bar-time {
@apply text-body font-semibold;
}
.status-bar-icons {
@apply flex items-center gap-1;
}
}
/* ========================================
5. Layout Utilities (布局工具类)
======================================== */
/* Mobile Layout */
.mobile-layout {
@apply min-h-screen flex flex-col;
padding: 16px 24px;
padding-bottom: 99px; /* 83px bottom nav + 16px padding */
}
/* Desktop Layout */
.desktop-layout {
@apply min-h-screen;
margin-left: 260px; /* sidebar width */
padding: 32px;
}
/* Content Area */
.content-area {
@apply flex flex-col;
gap: var(--spacing-lg);
}
.content-area-desktop {
@apply flex flex-col;
gap: var(--spacing-2xl);
}
/* ========================================
6. Form Elements (表单元素)
======================================== */
@layer components {
.input {
@apply w-full bg-bg-elevated text-text-primary border border-border-subtle rounded-btn px-4 py-2.5 text-body;
transition: border-color 0.2s;
}
.input:focus {
@apply outline-none border-accent-indigo;
}
.input::placeholder {
@apply text-text-tertiary;
}
.select {
@apply input appearance-none cursor-pointer;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23A1A1AA' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 12px center;
padding-right: 40px;
}
.textarea {
@apply input resize-none;
min-height: 100px;
}
}
/* ========================================
7. Animations (动画)
======================================== */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.animate-fade-in {
animation: fadeIn 0.2s ease-out;
}
.animate-slide-up {
animation: slideUp 0.3s ease-out;
}
.animate-pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
/* ========================================
8. Scrollbar Styles (滚动条样式)
======================================== */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: var(--bg-card);
}
::-webkit-scrollbar-thumb {
background: var(--border-subtle);
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--text-tertiary);
}
/* ========================================
9. Responsive Breakpoints (响应式断点)
======================================== */
/* Mobile: < 768px (default) */
/* Tablet: 768px - 1024px */
/* Desktop: > 1024px */
@media (min-width: 768px) {
.mobile-only {
display: none;
}
}
@media (max-width: 767px) {
.desktop-only {
display: none;
}
}
/* ========================================
10. Utility Classes (工具类)
======================================== */
.truncate-2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.truncate-3 {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
.glass-effect {
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
/* Safe area for iOS */
.safe-area-bottom {
padding-bottom: env(safe-area-inset-bottom, 0);
}
.safe-area-top {
padding-top: env(safe-area-inset-top, 0);
}

163
frontend/tailwind.config.js Normal file
View File

@ -0,0 +1,163 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
'./app/**/*.{js,ts,jsx,tsx,mdx}',
'./src/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {
// ========================================
// Colors - 颜色系统
// ========================================
colors: {
// 背景色
'bg-page': '#0B0B0E',
'bg-card': '#16161A',
'bg-elevated': '#1A1A1E',
// 文字色
'text-primary': '#FAFAF9',
'text-secondary': '#A1A1AA',
'text-tertiary': '#71717A',
// 强调色
'accent-indigo': '#6366F1',
'accent-green': '#32D583',
'accent-coral': '#E85A4F',
'accent-amber': '#F59E0B',
// 边框色
'border-subtle': '#27272A',
// 状态色 (带透明度)
'status-success': 'rgba(50, 213, 131, 0.125)',
'status-pending': 'rgba(99, 102, 241, 0.125)',
'status-error': 'rgba(232, 90, 79, 0.125)',
'status-warning': 'rgba(245, 158, 11, 0.125)',
},
// ========================================
// Typography - 字体系统
// ========================================
fontFamily: {
sans: ['DM Sans', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'sans-serif'],
},
fontSize: {
// 页面标题
'page-title': ['24px', { lineHeight: '1.3', fontWeight: '700' }],
// 卡片标题
'card-title': ['22px', { lineHeight: '1.3', fontWeight: '700' }],
// 区块标题
'section-title': ['16px', { lineHeight: '1.4', fontWeight: '600' }],
// 正文内容
'body': ['15px', { lineHeight: '1.5', fontWeight: '400' }],
// 辅助文字
'caption': ['13px', { lineHeight: '1.5', fontWeight: '400' }],
// 小标签
'small': ['12px', { lineHeight: '1.4', fontWeight: '400' }],
// 底部导航
'nav': ['11px', { lineHeight: '1.3', fontWeight: '400' }],
},
// ========================================
// Spacing - 间距系统
// ========================================
spacing: {
'4.5': '18px',
'13': '52px',
'15': '60px',
'18': '72px',
'21': '84px', // bottom nav padding
'22': '88px',
'65': '260px', // sidebar width
'83': '332px',
},
// ========================================
// Border Radius - 圆角系统
// ========================================
borderRadius: {
'card': '12px',
'btn': '8px',
'tag': '4px',
},
// ========================================
// Sizes - 尺寸
// ========================================
width: {
'sidebar': '260px',
'mobile': '402px',
},
height: {
'status-bar': '44px',
'bottom-nav': '83px',
'mobile': '874px',
},
minHeight: {
'screen-mobile': '874px',
},
maxWidth: {
'mobile': '402px',
'desktop': '1440px',
},
// ========================================
// Box Shadow - 阴影
// ========================================
boxShadow: {
'card': '0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -1px rgba(0, 0, 0, 0.2)',
'elevated': '0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.3)',
'inner-subtle': 'inset 0 2px 4px 0 rgba(0, 0, 0, 0.2)',
},
// ========================================
// Animations - 动画
// ========================================
animation: {
'fade-in': 'fadeIn 0.2s ease-out',
'slide-up': 'slideUp 0.3s ease-out',
'slide-down': 'slideDown 0.3s ease-out',
'scale-in': 'scaleIn 0.2s ease-out',
},
keyframes: {
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' },
},
slideUp: {
'0%': { opacity: '0', transform: 'translateY(10px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
},
slideDown: {
'0%': { opacity: '0', transform: 'translateY(-10px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
},
scaleIn: {
'0%': { opacity: '0', transform: 'scale(0.95)' },
'100%': { opacity: '1', transform: 'scale(1)' },
},
},
// ========================================
// Backdrop Blur - 毛玻璃效果
// ========================================
backdropBlur: {
xs: '2px',
},
// ========================================
// Z-Index - 层级
// ========================================
zIndex: {
'sidebar': '40',
'bottom-nav': '50',
'modal': '60',
'toast': '70',
},
},
},
plugins: [],
};

33
frontend/tsconfig.json Normal file
View File

@ -0,0 +1,33 @@
{
"compilerOptions": {
"target": "ES2020",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./*"],
"@/components/*": ["./components/*"],
"@/constants/*": ["./constants/*"],
"@/styles/*": ["./styles/*"],
"@/lib/*": ["./lib/*"],
"@/hooks/*": ["./hooks/*"],
"@/types/*": ["./types/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

File diff suppressed because it is too large Load Diff

199
scripts/setup-github.sh Executable file
View File

@ -0,0 +1,199 @@
#!/bin/bash
#
# GitHub 仓库配置脚本
# 用于配置分支保护规则和其他 GitHub 设置
#
# 使用方法: ./scripts/setup-github.sh
#
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
echo ""
echo "========================================"
echo " 秒思智能审核平台 - GitHub 配置脚本"
echo "========================================"
echo ""
# 1. 检查 GitHub CLI 是否安装
log_info "检查 GitHub CLI..."
if ! command -v gh &> /dev/null; then
log_error "GitHub CLI (gh) 未安装"
echo ""
echo "请先安装 GitHub CLI:"
echo " macOS: brew install gh"
echo " Ubuntu: sudo apt install gh"
echo " Windows: winget install GitHub.cli"
echo ""
echo "安装后运行: gh auth login"
exit 1
fi
log_success "GitHub CLI 已安装: $(gh --version | head -n1)"
# 2. 检查是否已登录
log_info "检查 GitHub 登录状态..."
if ! gh auth status &> /dev/null; then
log_error "未登录 GitHub"
echo ""
echo "请运行以下命令登录:"
echo " gh auth login"
echo ""
exit 1
fi
log_success "已登录 GitHub"
# 3. 检查是否在 git 仓库中
log_info "检查 Git 仓库..."
if ! git rev-parse --is-inside-work-tree &> /dev/null; then
log_error "当前目录不是 Git 仓库"
exit 1
fi
# 4. 获取远程仓库信息
log_info "获取远程仓库信息..."
REMOTE_URL=$(git remote get-url origin 2>/dev/null || echo "")
if [ -z "$REMOTE_URL" ]; then
log_error "未找到远程仓库 (origin)"
echo ""
echo "请先添加远程仓库:"
echo " git remote add origin https://github.com/YOUR_USERNAME/YOUR_REPO.git"
echo ""
exit 1
fi
# 解析 owner/repo
if [[ "$REMOTE_URL" =~ github\.com[:/]([^/]+)/([^/.]+)(\.git)?$ ]]; then
OWNER="${BASH_REMATCH[1]}"
REPO="${BASH_REMATCH[2]}"
else
log_error "无法解析 GitHub 仓库地址: $REMOTE_URL"
exit 1
fi
log_success "仓库: $OWNER/$REPO"
# 5. 检查仓库是否存在于 GitHub
log_info "验证远程仓库..."
if ! gh repo view "$OWNER/$REPO" &> /dev/null; then
log_warn "远程仓库不存在或无权限访问"
echo ""
read -p "是否创建远程仓库? (y/n): " CREATE_REPO
if [ "$CREATE_REPO" = "y" ]; then
log_info "创建远程仓库..."
gh repo create "$OWNER/$REPO" --private --source=. --push
log_success "远程仓库已创建"
else
log_error "请先在 GitHub 上创建仓库"
exit 1
fi
fi
# 6. 获取默认分支
log_info "获取默认分支..."
DEFAULT_BRANCH=$(gh repo view "$OWNER/$REPO" --json defaultBranchRef --jq '.defaultBranchRef.name' 2>/dev/null || echo "main")
log_info "默认分支: $DEFAULT_BRANCH"
# 7. 配置分支保护规则
echo ""
log_info "配置分支保护规则..."
# 构建 JSON payload
PROTECTION_PAYLOAD=$(cat <<EOF
{
"required_status_checks": {
"strict": true,
"contexts": [
"Frontend Tests / Unit & Integration Tests",
"Backend Tests / Unit & Integration Tests"
]
},
"enforce_admins": false,
"required_pull_request_reviews": {
"required_approving_review_count": 1,
"dismiss_stale_reviews": true,
"require_code_owner_reviews": false
},
"restrictions": null,
"allow_force_pushes": false,
"allow_deletions": false
}
EOF
)
# 应用分支保护规则
if gh api "repos/$OWNER/$REPO/branches/$DEFAULT_BRANCH/protection" \
--method PUT \
--input - <<< "$PROTECTION_PAYLOAD" &> /dev/null; then
log_success "分支保护规则已配置"
else
log_warn "分支保护规则配置失败(可能需要 GitHub Pro/Team 计划)"
echo ""
echo "对于免费版 GitHub请手动在 Web UI 配置:"
echo " 1. 进入 https://github.com/$OWNER/$REPO/settings/branches"
echo " 2. 点击 'Add branch protection rule'"
echo " 3. Branch name pattern: $DEFAULT_BRANCH"
echo " 4. 勾选 'Require a pull request before merging'"
echo " 5. 勾选 'Require status checks to pass before merging'"
echo ""
fi
# 8. 验证配置
echo ""
log_info "验证分支保护配置..."
PROTECTION_STATUS=$(gh api "repos/$OWNER/$REPO/branches/$DEFAULT_BRANCH/protection" 2>/dev/null || echo "none")
if [ "$PROTECTION_STATUS" != "none" ]; then
log_success "分支保护规则已生效"
echo ""
echo "当前保护规则:"
gh api "repos/$OWNER/$REPO/branches/$DEFAULT_BRANCH/protection" --jq '{
"必需状态检查": .required_status_checks.contexts,
"必需PR审批数": .required_pull_request_reviews.required_approving_review_count,
"管理员强制执行": .enforce_admins.enabled
}' 2>/dev/null || echo " (无法获取详情)"
else
log_warn "未检测到分支保护规则"
fi
# 9. 配置仓库设置
echo ""
log_info "配置仓库设置..."
# 启用自动删除合并后的分支
gh api "repos/$OWNER/$REPO" \
--method PATCH \
--field delete_branch_on_merge=true \
&> /dev/null && log_success "启用: 合并后自动删除分支" || log_warn "无法配置自动删除分支"
# 禁用 wiki如果不需要
gh api "repos/$OWNER/$REPO" \
--method PATCH \
--field has_wiki=false \
&> /dev/null && log_success "禁用: Wiki" || true
# 10. 完成
echo ""
echo "========================================"
echo " 配置完成!"
echo "========================================"
echo ""
echo "后续步骤:"
echo " 1. 确保 CI 工作流文件已提交 (.github/workflows/)"
echo " 2. 创建第一个 PR 验证 CI 是否正常运行"
echo " 3. 验证分支保护规则是否阻止直接 push 到 $DEFAULT_BRANCH"
echo ""
echo "验证命令:"
echo " gh pr status # 查看 PR 状态"
echo " gh run list # 查看 CI 运行记录"
echo " gh api repos/$OWNER/$REPO/branches/$DEFAULT_BRANCH/protection # 查看保护规则"
echo ""

688
tasks.md
View File

@ -1,9 +1,9 @@
# tasks.md - SmartAudit 开发任务清单
# tasks.md - 秒思智能审核平台 开发任务清单
| 文档类型 | **Development Tasks (开发任务清单)** |
| --- | --- |
| **项目名称** | SmartAudit (AI 营销内容合规审核平台) |
| **版本号** | V1.4 |
| **项目名称** | 秒思智能审核平台 (AI 营销内容合规审核平台) |
| **版本号** | V1.7 |
| **发布日期** | 2026-02-03 |
| **依据文档** | PRD.md, FeatureSummary.md, DevelopmentPlan.md, UIDesign.md, User_Role_Interfaces.md, AIProviderConfig.md |
| **总周期** | 11 周 (2.75 个月) |
@ -19,6 +19,9 @@
| V1.2 | 2026-02-02 | Claude | Gemini 审阅优化:新增 API Mock、CI/CD、消息中心后端接口任务 |
| V1.3 | 2026-02-02 | Claude | 确立 TDD 为核心开发规范 |
| V1.4 | 2026-02-02 | Claude | 新增 AI 服务配置任务TASK-005-D/E/F |
| V1.5 | 2026-02-03 | Claude | **新增 F-51/F-52 相关任务**TASK-069~073终审配置+审核流程进度) |
| V1.6 | 2026-02-03 | Claude | **F-52 扩展为全角色可见**TASK-073 新增代理商端/品牌方端进度条验收标准 |
| V1.7 | 2026-02-04 | Claude | **新增 GitHub 配置脚本**TASK-005-C 扩展为包含分支保护规则配置,新增 `scripts/setup-github.sh` |
---
@ -87,7 +90,7 @@
| 优先级 | 功能数量 | 说明 |
| --- | --- | --- |
| **P0 (MVP)** | 21 | 必须实现 |
| **P0 (MVP)** | 23 | 必须实现(含 F-51 品牌方终审开关、F-52 审核流程进度可视化) |
| **P1** | 22 | 首版后快速迭代(以 FeatureSummary 的 P1 清单为准) |
| **P2** | 8 | 中长期规划 |
@ -149,6 +152,8 @@
| F-48 | TASK-005-E |
| F-49 | TASK-066 |
| F-50 | TASK-067 |
| F-51 | TASK-069, TASK-070, TASK-071 |
| F-52 | TASK-072, TASK-073 |
> 注F-05 已拆分为 F-05-A/B历史任务中仍可能出现 F-05 标记。
@ -192,6 +197,7 @@
**任务描述:**
- PostgreSQL 数据库设计
- 核心表创建brands, agencies, creators, tasks, briefs, videos, reports, risk_items, rule_sets, audit_logs
- audit_logs 增加 prev_hash/hash 字段,支持 append-only + hash chain
- 配置 pgvector 扩展(向量检索)
- 配置 Alembic 数据库迁移
- 创建种子数据
@ -202,6 +208,7 @@
- [ ] 所有核心表创建成功
- [ ] pgvector 扩展可用
- [ ] 迁移脚本可正常执行
- [ ] audit_logs hash chain 字段可用
---
@ -296,24 +303,43 @@
---
#### TASK-005-C: CI/CD 流水线配置
#### TASK-005-C: CI/CD 流水线与 GitHub 配置
| 属性 | 内容 |
| --- | --- |
| **负责人** | Backend |
| **优先级** | P0 |
| **预估工时** | 1d |
| **预估工时** | 1.5d |
| **依赖** | TASK-001, TASK-006 |
| **功能编号** | 基础设施 |
**任务描述:**
- 配置 GitLab CI / GitHub Actions
- 实现代码提交后自动 Lint 检查
- 配置 GitHub Actions 工作流
- `.github/workflows/frontend-test.yml` (Vitest + Playwright)
- `.github/workflows/backend-test.yml` (pytest)
- 实现代码提交后自动 Lint + 测试
- **配置 Codecov 覆盖率报告**(见下方步骤)
- 实现 Docker 镜像自动构建
- 配置 Dev 环境自动部署
- **运行 GitHub 配置脚本配置分支保护规则**
**执行命令:**
```bash
# 1. 配置 Codecov必须先完成否则 CI 会失败)
# - 访问 https://codecov.io 用 GitHub 登录
# - 添加仓库并获取 Upload Token
# - 配置 GitHub Secret:
gh secret set CODECOV_TOKEN --body "<your-codecov-token>"
# 2. 配置 GitHub 分支保护规则
./scripts/setup-github.sh
```
**验收标准:**
- [ ] 代码提交后自动触发构建
- [ ] Lint 错误阻断合并
- [ ] 代码提交后自动触发构建和测试
- [ ] Lint/测试错误阻断 PR 合并
- [ ] **Codecov 覆盖率报告正常上传**验证https://codecov.io/gh/{owner}/{repo}
- [ ] **分支保护规则已生效**(验证:`gh api repos/{owner}/{repo}/branches/main/protection`
- [ ] 直接 push 到 main 被拒绝
- [ ] Dev 环境自动更新
---
@ -1409,6 +1435,203 @@
---
#### TASK-069: 审核流程配置后端
| 属性 | 内容 |
| --- | --- |
| **负责人** | Backend |
| **优先级** | **P0** |
| **预估工时** | 2d |
| **依赖** | TASK-002, TASK-034 |
| **功能编号** | F-51 |
**任务描述:**
- 实现审核流程配置表(终审开关、终审范围、超时时间、超时处理)
- 实现审核流程配置 CRUD API
- 修改审核通过逻辑:根据配置决定是否进入终审队列
- 实现终审超时自动处理(定时任务)
- 实现待终审列表查询 API
**数据模型:**
```sql
CREATE TABLE review_flow_configs (
id UUID PRIMARY KEY,
tenant_id UUID NOT NULL UNIQUE,
final_review_enabled BOOLEAN DEFAULT false,
final_review_scope VARCHAR(50) DEFAULT 'all', -- all/risk_only/specified_agencies
specified_agency_ids JSONB DEFAULT '[]',
timeout_hours INT DEFAULT 48,
timeout_action VARCHAR(20) DEFAULT 'auto_pass', -- auto_pass/remind_only
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
```
**验收标准:**
- [ ] 配置 CRUD API 正常
- [ ] 代理商通过后根据配置正确进入终审队列或直接通过
- [ ] 超时自动处理正常
---
#### TASK-070: 品牌方终审台 PC 端
| 属性 | 内容 |
| --- | --- |
| **负责人** | Frontend |
| **优先级** | **P0** |
| **预估工时** | 3d |
| **依赖** | TASK-032, TASK-069 |
| **功能编号** | F-51 |
**任务描述:**
- 实现终审台入口(仅当终审开启时显示)
- 实现待终审列表(筛选、搜索、超时提醒)
- 实现终审详情页(复用审核决策台布局)
- 显示代理商初审意见和通过理由
- 实现终审通过/驳回操作
- 实现审核流程配置界面
**界面参考:** User_Role_Interfaces.md 第 4.5 章
**验收标准:**
- [ ] 终审列表正常展示
- [ ] 超时提醒正常显示
- [ ] 终审操作正常
- [ ] 配置界面正常
---
#### TASK-071: 品牌方终审台移动端
| 属性 | 内容 |
| --- | --- |
| **负责人** | Frontend |
| **优先级** | P1 |
| **预估工时** | 2d |
| **依赖** | TASK-070, TASK-037F |
| **功能编号** | F-51 |
**任务描述:**
- 实现移动端待终审列表
- 实现移动端终审详情页(视频预览+问题列表)
- 实现终审通过/驳回操作
- 复杂配置引导至桌面端
**界面参考:** User_Role_Interfaces.md 第 4.5 章(移动端适配)
**验收标准:**
- [ ] 待终审列表正常展示
- [ ] 终审操作正常
- [ ] 视频预览正常
---
### 4.6.2 审核流程进度可视化 (F-52)
#### TASK-072: 审核流程进度后端 API
| 属性 | 内容 |
| --- | --- |
| **负责人** | Backend |
| **优先级** | **P0** |
| **预估工时** | 2d |
| **依赖** | TASK-002, TASK-022, TASK-069 |
| **功能编号** | F-52 |
**任务描述:**
- 扩展任务状态模型,增加审核流程阶段字段
- 实现审核流程状态查询 API`GET /api/v1/tasks/{task_id}/review-progress`
- 记录每个阶段的完成时间和处理人
- 支持 WebSocket 推送状态变更通知
**数据模型:**
```sql
-- 审核流程状态记录
ALTER TABLE tasks ADD COLUMN review_stage VARCHAR(50) DEFAULT 'submitted';
ALTER TABLE tasks ADD COLUMN review_stage_updated_at TIMESTAMP;
CREATE TABLE review_stage_logs (
id UUID PRIMARY KEY,
task_id UUID NOT NULL REFERENCES tasks(id),
stage VARCHAR(50) NOT NULL, -- submitted, ai_reviewing, ai_passed, ai_rejected, agency_reviewing, agency_passed, agency_rejected, brand_reviewing, brand_passed, brand_rejected, final_passed
operator_id UUID, -- 处理人AI阶段为空
operator_type VARCHAR(20), -- system, agency, brand
result VARCHAR(20), -- passed, rejected, pending
comment TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
```
**API 响应示例:**
```json
{
"task_id": "xxx",
"current_stage": "agency_reviewing",
"stages": [
{"stage": "submitted", "status": "completed", "completed_at": "2026-02-03T10:30:00Z"},
{"stage": "ai_review", "status": "completed", "result": "passed", "completed_at": "2026-02-03T10:35:00Z"},
{"stage": "agency_review", "status": "in_progress", "started_at": "2026-02-03T10:35:00Z"},
{"stage": "brand_review", "status": "pending", "enabled": true},
{"stage": "final", "status": "pending"}
],
"estimated_wait_time": "2-4小时"
}
```
**验收标准:**
- [ ] API 返回完整审核流程状态
- [ ] 状态变更时触发 WebSocket 推送
- [ ] 历史记录可追溯
---
#### TASK-073: 审核流程进度前端 UI
| 属性 | 内容 |
| --- | --- |
| **负责人** | Frontend |
| **优先级** | **P0** |
| **预估工时** | 2d |
| **依赖** | TASK-026, TASK-027, TASK-028, TASK-072 |
| **功能编号** | F-52 |
**任务描述:**
- 实现审核流程进度条组件 `<ReviewProgressBar />`
- **全角色适配(达人/代理商/品牌方,移动端/桌面端)**
- 达人端:任务列表卡片 + 审核结果页顶部
- 代理商端:审核决策台顶部 + 移动端快捷审核页
- 品牌方端:终审台顶部 + 移动端审批中心审批项
- 根据终审配置动态显示/隐藏品牌终审节点
- 支持 WebSocket 实时更新状态
**组件设计:**
```tsx
// 进度条组件
<ReviewProgressBar
stages={stages} // 流程阶段数组
currentStage="agency_reviewing"
showBrandReview={true} // 是否显示品牌终审节点
onStageClick={handleStageClick} // 点击节点查看详情
compact={false} // 紧凑模式(移动端)
/>
// 状态标签组件
<ReviewStageTag
stage="agency_reviewing"
icon={<Users />}
color="purple"
label="等待代理商审核"
/>
```
**界面参考:** User_Role_Interfaces.md 第 2.1.1、2.3.1、3.3.1、3.8.2、4.5.2、4.7.3 章
**验收标准:**
- [ ] 达人端任务卡片正确显示当前审核阶段
- [ ] 达人端审核结果页进度条正确显示
- [ ] 代理商端审核决策台/快捷审核页进度条正确显示
- [ ] 品牌方端终审台/审批中心进度条正确显示
- [ ] 终审开启/关闭时进度条节点正确增减
- [ ] WebSocket 状态更新实时反映
---
### 4.7 响应式设计与无障碍
> 规范参考User_Role_Interfaces.md 第 7-8 章
@ -1736,6 +1959,11 @@
**任务描述:**
- 实现审核记录查询
- 实现完整审核链路查看
- 审计日志采用 append-only + hash chain前序哈希 + 当前内容),禁止更新/删除
**验收标准:**
- [ ] 审计日志链式校验通过
- [ ] 不支持对历史审计日志的更新/删除
---
@ -2030,7 +2258,443 @@ graph TD
---
## 10. 相关文档
## 10. UI 开发任务 (关联设计稿)
> **重要说明:本章节的 UI 任务与第 4 章功能任务的关系**
>
> - **功能任务TASK-026~037等**:定义"实现什么功能"和"如何验收"
> - **UI任务TASK-UI-xxx**:提供"视觉参考"关联设计稿节点ID
> - **开发流程**功能任务和UI任务应**同时参考**先看UI任务获取视觉规范再按功能任务完成开发
> - **任务编号映射**每个UI任务的"关联任务"字段指向对应的功能任务
所有 UI 开发任务必须严格对照设计稿 `pencil-new.pen` 实现,使用 Pencil MCP 工具访问设计稿节点
### 10.1 设计稿与组件库
| 资源 | 路径 | 说明 |
| --- | --- | --- |
| 设计稿文件 | `pencil-new.pen` | Pencil 格式设计稿 |
| 设计规范文档 | `UIDesignSpec.md` | 颜色、字体、间距、组件规范 |
| Tailwind 配置 | `frontend/tailwind.config.js` | 设计令牌 Tailwind 映射 |
| 全局样式 | `frontend/styles/globals.css` | CSS Variables 与组件样式 |
| 组件库 | `frontend/components/` | React 基础组件 |
| 常量定义 | `frontend/constants/` | 颜色、图标、布局常量 |
### 10.2 UI 开发检查清单
开发每个页面时,必须对照以下检查项:
- [ ] 背景色使用 `bg-bg-page` (#0B0B0E)
- [ ] 卡片使用 `bg-bg-card` (#16161A) + `rounded-card` (12px)
- [ ] 字体统一使用 DM Sans (`font-sans`)
- [ ] 图标使用 Lucide按照 `constants/icons.ts` 映射表选择
- [ ] 移动端底部导航高度 83px渐变背景
- [ ] 桌面端侧边栏宽度 260px
- [ ] 状态标签使用 `<Tag>` 组件(通过=绿色,处理中=紫色,错误=红色)
- [ ] 按钮使用 `<Button>` 组件(主要=紫色,次要=深灰色)
- [ ] 卡片使用 `<Card>` 组件
- [ ] 布局使用 `<MobileLayout>``<DesktopLayout>` 组件
### 10.3 达人端 UI 任务
#### TASK-UI-C01: 达人端 - 任务列表 (Mobile)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `PjBJD` |
| **优先级** | P0 |
| **依赖** | TASK-007, TASK-026, TASK-073 |
| **关联任务** | TASK-026, TASK-073 |
**实现要点:**
- 使用 `MobileLayout` 组件
- 任务卡片使用 `Card` 组件
- 状态标签使用 `Tag` 组件
- 底部导航:工作台/任务/审核/消息/我的
- ⭐ **审核流程进度条**F-52
- 任务卡片内嵌审核进度条组件 `<ReviewProgressBar />`
- 进度条节点ID`V5Vrv`AI审核中状态示例`r3pZG`(需修改状态示例)
- 状态流转:已提交 → AI审核 → 代理商审核 → [品牌终审] → 通过
---
#### TASK-UI-C02: 达人端 - 智能上传 (Mobile)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `ZelCS` |
| **优先级** | P0 |
| **依赖** | TASK-015, TASK-027 |
| **关联任务** | TASK-027 |
**实现要点:**
- 脚本输入文本区域
- 视频上传区域(拖拽/点击)
- 上传进度条使用 `ProgressBar` 组件
---
#### TASK-UI-C03: 达人端 - 审核结果 (Mobile)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `Vn3VU` |
| **优先级** | P0 |
| **依赖** | TASK-028, TASK-073 |
| **关联任务** | TASK-028, TASK-073 |
**实现要点:**
- ⭐ **审核流程进度卡片**F-52
- 进度卡片节点ID`GNZKG`
- 显示完整流程:已提交 → AI审核 → 代理商审核 → 最终结果
- 每个节点显示时间戳和状态
- 结果横幅(通过/警告/驳回)
- 视频播放器带时间戳标注
- 修改清单组件
---
#### TASK-UI-C04: 达人端 - AI审核中 (Mobile)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `lzdm4` |
| **优先级** | P0 |
| **依赖** | TASK-024 |
| **关联任务** | TASK-024 |
**实现要点:**
- 使用 `CircularProgress` 环形进度组件
- 步骤列表展示当前处理阶段
- "离开并稍后查看"按钮
---
#### TASK-UI-C05: 达人端 - 消息中心 (Mobile)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `pF15t` |
| **优先级** | P1 |
| **依赖** | TASK-030 |
| **关联任务** | TASK-030 |
---
#### TASK-UI-C06: 达人端 - 历史记录 (Mobile)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `ZKEFl` |
| **优先级** | P2 |
| **关联任务** | 无独立功能任务,复用任务列表逻辑,筛选已完成任务 |
---
#### TASK-UI-C07: 达人端 - 个人中心 (Mobile)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `zCdM1` |
| **优先级** | P2 |
| **关联任务** | 无独立功能任务,展示用户信息与设置入口 |
---
#### TASK-UI-C08: 达人端 - 任务列表 (Desktop)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `HD3eK` |
| **优先级** | P0 |
| **依赖** | TASK-006 |
| **关联任务** | TASK-026复用移动端逻辑适配桌面布局 |
**实现要点:**
- 使用 `DesktopLayout` 组件
- 侧边栏导航使用 `Sidebar` 组件
---
#### TASK-UI-C09: 达人端 - 智能上传 (Desktop)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `N79bL` |
| **优先级** | P0 |
| **关联任务** | TASK-027复用移动端逻辑适配桌面布局 |
---
#### TASK-UI-C10: 达人端 - 审核结果 (Desktop)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `3niUa` |
| **优先级** | P0 |
| **关联任务** | TASK-028复用移动端逻辑适配桌面布局 |
---
#### TASK-UI-C11: 达人端 - AI审核中 (Desktop)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `bxAKT` |
| **优先级** | P0 |
| **关联任务** | TASK-024复用移动端逻辑适配桌面布局 |
---
#### TASK-UI-C12: 达人端 - 消息中心 (Desktop)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `8XKLP` |
| **优先级** | P1 |
| **关联任务** | TASK-030复用移动端逻辑适配桌面布局 |
---
### 10.4 代理商端 UI 任务
#### TASK-UI-A01: 代理商端 - 工作台 (Desktop)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `RX8V9` |
| **优先级** | P0 |
| **依赖** | TASK-031 |
| **关联任务** | TASK-031 |
**实现要点:**
- 使用 `DesktopLayout` 组件
- 待办事项卡片、项目进度条、最近活动列表
---
#### TASK-UI-A02: 代理商端 - 审核决策台 (Desktop)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `2u8Bq` |
| **优先级** | P0 |
| **依赖** | TASK-032, TASK-033, TASK-034 |
| **关联任务** | TASK-032, TASK-033, TASK-034 |
**实现要点:**
- 视频播放器带智能进度条(红/黄/绿点)
- AI 检查单区块
- 驳回/通过操作按钮
---
#### TASK-UI-A03: 代理商端 - Brief配置中心 (Desktop)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `djd2K` |
| **优先级** | P0 |
| **依赖** | TASK-012 |
| **关联任务** | TASK-012 |
---
#### TASK-UI-A04: 代理商端 - 达人管理 (Desktop)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `5cFMX` |
| **优先级** | P1 |
| **关联任务** | 无独立功能任务需新建TASK实现达人列表CRUD |
---
#### TASK-UI-A05: 代理商端 - 数据报表 (Desktop)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `An8gw` |
| **优先级** | P1 |
| **关联任务** | TASK-059 |
---
#### TASK-UI-A06: 代理商端 - 版本比对 (Desktop)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `NDmYh` |
| **优先级** | P2 |
| **关联任务** | TASK-054, TASK-055 |
---
#### TASK-UI-A07: 代理商端 - 工作台 (Mobile)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `VuH3F` |
| **优先级** | P0 |
| **依赖** | TASK-037A |
| **关联任务** | TASK-037A |
---
#### TASK-UI-A08: 代理商端 - 快捷审核 (Mobile)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `lrHaj` |
| **优先级** | P0 |
| **依赖** | TASK-037B |
| **关联任务** | TASK-037B |
---
#### TASK-UI-A09: 代理商端 - 任务列表 (Mobile)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `c6SPa` |
| **优先级** | P1 |
| **关联任务** | TASK-037C |
---
#### TASK-UI-A10: 代理商端 - 消息中心 (Mobile)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `9Us9g` |
| **优先级** | P1 |
| **关联任务** | TASK-037C |
---
#### TASK-UI-A11: 代理商端 - 个人中心 (Mobile)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `8OCZ3` |
| **优先级** | P2 |
| **关联任务** | 无独立功能任务,展示用户信息与设置入口 |
---
### 10.5 品牌方端 UI 任务
#### TASK-UI-B01: 品牌方端 - 数据看板 (Desktop)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `xUM9m` |
| **优先级** | P0 |
| **依赖** | TASK-037D |
| **关联任务** | TASK-037D |
**实现要点:**
- 趋势图与问题分布饼图
- 代理商对比柱状图
- 风险预警区
---
#### TASK-UI-B02: 品牌方端 - AI服务配置 (Desktop)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `4ppiJ` |
| **优先级** | P0 |
| **依赖** | TASK-005-F |
| **关联任务** | TASK-005-F |
**实现要点:**
- AI 提供商下拉选择
- 模型配置(文本/视觉/音频)
- API Key 输入与测试连接
---
#### TASK-UI-B03: 品牌方端 - 规则配置 (Desktop)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `nhHSF` |
| **优先级** | P0 |
| **依赖** | TASK-037E |
| **关联任务** | TASK-037E |
---
#### TASK-UI-B04: 品牌方端 - 审计日志 (Desktop)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `jELTK` |
| **优先级** | P1 |
| **关联任务** | TASK-050 |
---
#### TASK-UI-B05: 品牌方端 - 代理商管理 (Desktop)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `2jnnO` |
| **优先级** | P1 |
| **关联任务** | TASK-068 |
---
#### TASK-UI-B06: 品牌方端 - 舆情预警 (Desktop)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `NjCe7` |
| **优先级** | P2 |
| **关联任务** | TASK-060 |
---
#### TASK-UI-B07: 品牌方端 - 系统设置 (Desktop)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `4nVj4` |
| **优先级** | P2 |
| **关联任务** | 无独立功能任务,展示系统配置入口 |
---
#### TASK-UI-B08: 品牌方端 - 数据看板 (Mobile)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `lpVdV` |
| **优先级** | P0 |
| **依赖** | TASK-037F |
| **关联任务** | TASK-037F |
---
#### TASK-UI-B09: 品牌方端 - 舆情预警 (Mobile)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `wWAel` |
| **优先级** | P1 |
| **关联任务** | TASK-037G |
---
#### TASK-UI-B10: 品牌方端 - 审批中心 (Mobile)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `OueOe` |
| **优先级** | P1 |
| **关联任务** | TASK-037H |
---
#### TASK-UI-B11: 品牌方端 - 消息中心 (Mobile)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `1w9xC` |
| **优先级** | P2 |
| **关联任务** | TASK-030复用消息中心逻辑 |
---
#### TASK-UI-B12: 品牌方端 - 我的 (Mobile)
| 属性 | 内容 |
| --- | --- |
| **设计稿节点ID** | `OJBbT` |
| **优先级** | P2 |
| **关联任务** | 无独立功能任务,展示用户信息与桌面端操作提示 |
---
### 10.6 UI 任务优先级汇总
| 优先级 | 任务数量 | 任务列表 |
| --- | --- | --- |
| **P0** | 17 | TASK-UI-C01~C04 (4), C08~C11 (4), A01~A03 (3), A07~A08 (2), B01~B03 (3), B08 (1) |
| **P1** | 10 | TASK-UI-C05 (1), C12 (1), A04~A05 (2), A09~A10 (2), B04~B05 (2), B09~B10 (2) |
| **P2** | 8 | TASK-UI-C06~C07 (2), A06 (1), A11 (1), B06~B07 (2), B11~B12 (2) |
| **总计** | **35** | 达人端12个 + 代理商端11个 + 品牌方端12个 |
---
## 11. 相关文档
| 文档 | 说明 |
| --- | --- |
@ -2038,5 +2702,7 @@ graph TD
| FeatureSummary.md | 功能清单与优先级 |
| DevelopmentPlan.md | 开发计划与技术架构 |
| UIDesign.md | UI 设计规范 |
| UIDesignSpec.md | UI 设计规范(详细版) |
| User_Role_Interfaces.md | 用户角色与界面规范 |
| AIProviderConfig.md | AI 服务配置架构设计 |
| pencil-new.pen | 设计稿文件Pencil 格式) |