Compare commits
No commits in common. "d52509d630aec47545aa9d4f749333ac6c57ed64" and "dd0650200489dfa31ec96aef027ca5d1cf58f904" have entirely different histories.
d52509d630
...
dd06502004
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
| 文档类型 | **Technical Design (技术设计文档)** |
|
| 文档类型 | **Technical Design (技术设计文档)** |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| **项目名称** | 秒思智能审核平台 (AI 营销内容合规审核平台) |
|
| **项目名称** | SmartAudit (AI 营销内容合规审核平台) |
|
||||||
| **版本号** | V2.1 |
|
| **版本号** | V2.0 |
|
||||||
| **日期** | 2026-02-03 |
|
| **日期** | 2026-02-02 |
|
||||||
| **侧重** | AI 服务动态配置、多租户隔离、模型选择 |
|
| **侧重** | AI 服务动态配置、多租户隔离、模型选择 |
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -15,7 +15,6 @@
|
|||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| V1.0 | 2026-02-02 | Claude | 初稿:AI 厂商动态配置架构设计 |
|
| V1.0 | 2026-02-02 | Claude | 初稿:AI 厂商动态配置架构设计 |
|
||||||
| V2.0 | 2026-02-02 | Claude | 重构:简化为统一提供商+三模型配置方案 |
|
| V2.0 | 2026-02-02 | Claude | 重构:简化为统一提供商+三模型配置方案 |
|
||||||
| V2.1 | 2026-02-03 | Claude | 文档一致性修订:明确单提供商模式与可切换原则 |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -23,7 +22,7 @@
|
|||||||
|
|
||||||
### 1.1 业务需求
|
### 1.1 业务需求
|
||||||
|
|
||||||
秒思智能审核平台 系统需要调用三类 AI 服务完成视频审核:
|
SmartAudit 系统需要调用三类 AI 服务完成视频审核:
|
||||||
|
|
||||||
| 服务类型 | 用途 | 示例模型 |
|
| 服务类型 | 用途 | 示例模型 |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
@ -36,7 +35,6 @@
|
|||||||
| 目标 | 描述 |
|
| 目标 | 描述 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| **灵活配置** | 品牌方可在后台自由选择 AI 提供商和模型 |
|
| **灵活配置** | 品牌方可在后台自由选择 AI 提供商和模型 |
|
||||||
| **单一提供商** | 每租户仅保留一套提供商配置,必要时手动切换 |
|
|
||||||
| **统一接入** | 支持 OneAPI/OpenRouter 中转,一套配置调用多种模型 |
|
| **统一接入** | 支持 OneAPI/OpenRouter 中转,一套配置调用多种模型 |
|
||||||
| **直连支持** | 也支持直连 Anthropic、OpenAI、DeepSeek 等厂商 |
|
| **直连支持** | 也支持直连 Anthropic、OpenAI、DeepSeek 等厂商 |
|
||||||
| **多租户隔离** | 不同品牌方使用独立的 AI 配置和配额 |
|
| **多租户隔离** | 不同品牌方使用独立的 AI 配置和配额 |
|
||||||
@ -695,7 +693,7 @@ def mask_api_key(api_key: str) -> str:
|
|||||||
|
|
||||||
## 7. 界面设计
|
## 7. 界面设计
|
||||||
|
|
||||||
> 详见 User_Role_Interfaces.md 第 4.6 章「AI 服务配置」
|
> 详见 UIDesign.md 第 10 章「AI 服务配置界面」
|
||||||
|
|
||||||
### 7.1 界面入口
|
### 7.1 界面入口
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
这是一个基于 `RequirementsDoc.md`、`FeatureSummary.md` (V1.4) 和 `User_Role_Interfaces.md` 编写的开发计划文档。
|
这是一个基于 `RequirementsDoc.md`、`FeatureSummary.md` (V1.3) 和 `User_Role_Interfaces.md` 编写的开发计划文档。
|
||||||
|
|
||||||
这份文档旨在指导技术团队进行架构设计、选型和排期,重点在于解决**视频处理的高并发/高延迟**、**多模态 AI 的集成**以及**移动端适配**等工程难点。
|
这份文档旨在指导技术团队进行架构设计、选型和排期,重点在于解决**视频处理的高并发/高延迟**、**多模态 AI 的集成**以及**移动端适配**等工程难点。
|
||||||
|
|
||||||
@ -10,10 +10,10 @@
|
|||||||
|
|
||||||
| 文档类型 | **Development Plan (技术架构与实施计划)** |
|
| 文档类型 | **Development Plan (技术架构与实施计划)** |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| **项目名称** | 秒思智能审核平台 (AI 营销内容合规审核平台) |
|
| **项目名称** | SmartAudit (AI 营销内容合规审核平台) |
|
||||||
| **版本号** | V1.6 |
|
| **版本号** | V1.5 |
|
||||||
| **日期** | 2026-02-03 |
|
| **日期** | 2026-02-03 |
|
||||||
| **依据** | FeatureSummary V1.4, PRD V1.0, RequirementsDoc V1.0 |
|
| **依据** | FeatureSummary V1.3, PRD V1.0, RequirementsDoc V1.0 |
|
||||||
| **侧重** | 技术选型、架构设计、MVP 范围、开发排期、验收标准 |
|
| **侧重** | 技术选型、架构设计、MVP 范围、开发排期、验收标准 |
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -29,7 +29,6 @@
|
|||||||
| V1.3 | 2026-02-03 | Claude | **确立 TDD 为项目核心开发规范**,关联 tdd_plan.md |
|
| V1.3 | 2026-02-03 | Claude | **确立 TDD 为项目核心开发规范**,关联 tdd_plan.md |
|
||||||
| V1.4 | 2026-02-03 | Claude | **新增 AI 厂商动态配置架构**,支持数据库配置、运行时热更新、多租户隔离 |
|
| V1.4 | 2026-02-03 | Claude | **新增 AI 厂商动态配置架构**,支持数据库配置、运行时热更新、多租户隔离 |
|
||||||
| V1.5 | 2026-02-03 | Claude | 文档一致性修复:统一加密方案、采样精度、处理时间、选型决策、P0 范围、排期等 |
|
| V1.5 | 2026-02-03 | Claude | 文档一致性修复:统一加密方案、采样精度、处理时间、选型决策、P0 范围、排期等 |
|
||||||
| V1.6 | 2026-02-03 | Claude | 文档一致性修订:AI 配置单提供商模式、审计日志不可篡改方案、FeatureSummary 版本对齐 |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -109,7 +108,7 @@ graph TD
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| **通用语义 (NLP)** | **豆包 Pro / Qwen-Max / DeepSeek** | 处理 Brief 解析、反讽识别、情感分析 |
|
| **通用语义 (NLP)** | **豆包 Pro / Qwen-Max / DeepSeek** | 处理 Brief 解析、反讽识别、情感分析 |
|
||||||
| **视觉理解 (VLM)** | **Qwen-VL / 豆包视觉** | 处理复杂场景理解(如:环境脏乱差、具体动作判定);**Brief 图片解析** |
|
| **视觉理解 (VLM)** | **Qwen-VL / 豆包视觉** | 处理复杂场景理解(如:环境脏乱差、具体动作判定);**Brief 图片解析** |
|
||||||
| **语音识别 (ASR)** | **Whisper / Paraformer / SenseVoice** | 通过 AIProviderConfig 配置音频模型,支持时间戳对齐 |
|
| **语音识别 (ASR)** | **Paraformer (阿里) / SenseVoice** | 高精度中文语音转写,支持时间戳对齐 |
|
||||||
| **文字识别 (OCR)** | **PaddleOCR v4** | 针对中文视频字幕优化,开源免费,轻量级 |
|
| **文字识别 (OCR)** | **PaddleOCR v4** | 针对中文视频字幕优化,开源免费,轻量级 |
|
||||||
| **版面分析 (Layout)** | **PaddleOCR Layout / LayoutLMv3** | Brief PDF 版面分析,提取图文混排结构 |
|
| **版面分析 (Layout)** | **PaddleOCR Layout / LayoutLMv3** | Brief PDF 版面分析,提取图文混排结构 |
|
||||||
| **竞品 Logo 检测** | **Grounding DINO + Vector DB** | ⭐ V1.2 修正:改为向量检索方案,见下方说明 |
|
| **竞品 Logo 检测** | **Grounding DINO + Vector DB** | ⭐ V1.2 修正:改为向量检索方案,见下方说明 |
|
||||||
@ -120,11 +119,11 @@ graph TD
|
|||||||
>
|
>
|
||||||
> **核心特性:**
|
> **核心特性:**
|
||||||
> - **数据库存储配置:** AI 厂商的 API Key、Base URL 等配置存储在数据库中,而非环境变量
|
> - **数据库存储配置:** AI 厂商的 API Key、Base URL 等配置存储在数据库中,而非环境变量
|
||||||
> - **运行时动态加载:** 管理员可在后台配置**单一 AI 提供商**,系统运行时动态读取配置初始化客户端
|
> - **运行时动态加载:** 管理员可在后台配置 AI 厂商,系统运行时动态读取配置初始化客户端
|
||||||
> - **多租户隔离:** 不同品牌方可配置独立的 AI 提供商配置和配额
|
> - **多租户隔离:** 不同品牌方可配置独立的 AI 厂商和配额
|
||||||
> - **热更新:** 配置变更即时生效,无需重启服务
|
> - **热更新:** 配置变更即时生效,无需重启服务
|
||||||
|
> - **故障转移:** 主厂商不可用时自动切换到备用厂商
|
||||||
> - **API Key 加密:** 使用 AES-256-GCM 加密存储敏感信息
|
> - **API Key 加密:** 使用 AES-256-GCM 加密存储敏感信息
|
||||||
> - **可切换:** 管理员可随时更换提供商(OneAPI/OpenRouter 或直连厂商)
|
|
||||||
>
|
>
|
||||||
> **支持的厂商类型:**
|
> **支持的厂商类型:**
|
||||||
> - 国内厂商:DeepSeek、通义千问、豆包、智谱、Moonshot
|
> - 国内厂商:DeepSeek、通义千问、豆包、智谱、Moonshot
|
||||||
@ -253,11 +252,11 @@ sequenceDiagram
|
|||||||
|
|
||||||
## 3. MVP (P0) 开发范围定义
|
## 3. MVP (P0) 开发范围定义
|
||||||
|
|
||||||
基于 `FeatureSummary.md V1.4`,MVP 阶段必须包含的功能:
|
基于 `FeatureSummary.md V1.3`,MVP 阶段必须包含的功能:
|
||||||
|
|
||||||
### ✅ MVP 包含 (Must Have) - 共 21 个 P0 功能
|
### ✅ MVP 包含 (Must Have) - 共 21 个 P0 功能
|
||||||
|
|
||||||
基于 `FeatureSummary.md V1.4` 第 4.1 章定义:
|
基于 `FeatureSummary.md V1.3` 第 4.1 章定义:
|
||||||
|
|
||||||
| 模块 | 功能编号 | 功能名称 | 备注 |
|
| 模块 | 功能编号 | 功能名称 | 备注 |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
@ -407,15 +406,13 @@ sequenceDiagram
|
|||||||
| `reports` | 审核报告 | id, video_id, ai_result_json, human_decision, created_at |
|
| `reports` | 审核报告 | id, video_id, ai_result_json, human_decision, created_at |
|
||||||
| `risk_items` | 风险项 | id, report_id, type, level, timestamp_start, timestamp_end, evidence_json |
|
| `risk_items` | 风险项 | id, report_id, type, level, timestamp_start, timestamp_end, evidence_json |
|
||||||
| `rule_sets` | 规则库 | id, brand_id, platform, version, rules_json |
|
| `rule_sets` | 规则库 | id, brand_id, platform, version, rules_json |
|
||||||
| `audit_logs` | 审计日志 | id, task_id, operator_id, action, detail_json, created_at, prev_hash, hash |
|
| `audit_logs` | 审计日志 | id, task_id, operator_id, action, detail_json, created_at |
|
||||||
|
|
||||||
> **审计日志不可篡改策略:** `audit_logs` 采用 append-only 写入 + hash chain(前序哈希 + 当前内容),禁止更新/删除,支持链式校验。
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8. 验收标准 (Acceptance Criteria)
|
## 8. 验收标准 (Acceptance Criteria)
|
||||||
|
|
||||||
引用自 `FeatureSummary.md V1.4` 第 9 章,MVP 上线前必须满足:
|
引用自 `FeatureSummary.md V1.3` 第 9 章,MVP 上线前必须满足:
|
||||||
|
|
||||||
| 验收项 | 标准 | 测量方式 | 责任方 |
|
| 验收项 | 标准 | 测量方式 | 责任方 |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
@ -521,6 +518,6 @@ sequenceDiagram
|
|||||||
| User_Role_Interfaces.md | 界面规范 |
|
| User_Role_Interfaces.md | 界面规范 |
|
||||||
| tasks.md | 开发任务清单 |
|
| tasks.md | 开发任务清单 |
|
||||||
| **featuredoc/tdd_plan.md** | **TDD 实施计划(核心规范)** |
|
| **featuredoc/tdd_plan.md** | **TDD 实施计划(核心规范)** |
|
||||||
| **AIProviderConfig.md** | **AI 厂商动态配置架构设计(V2.1)** |
|
| **AIProviderConfig.md** | **AI 厂商动态配置架构设计(V2.0)** |
|
||||||
| 数据字典 | 待编写 |
|
| 数据字典 | 待编写 |
|
||||||
| API 接口规范 | 待编写 |
|
| API 接口规范 | 待编写 |
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
# 设计文档矛盾与模糊点分析 (V1.7)
|
# 设计文档矛盾与模糊点分析 (V1.2)
|
||||||
|
|
||||||
本文档用于记录并跟踪 `秒思智能审核平台` 项目各设计文档之间的矛盾点与模糊点。
|
本文档用于记录并跟踪 `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
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -14,32 +11,28 @@
|
|||||||
- **对齐文档:** `DevelopmentPlan.md`、`User_Role_Interfaces.md`
|
- **对齐文档:** `DevelopmentPlan.md`、`User_Role_Interfaces.md`
|
||||||
|
|
||||||
### 1.2 Logo 检测职责边界 (已澄清)
|
### 1.2 Logo 检测职责边界 (已澄清)
|
||||||
- **结论:** 视觉模型仅用于画面语义/场景风险分析;竞品 Logo 检测由内置 CV 模型(Grounding DINO + Vector DB)处理,不受配置影响。
|
- **结论:** 视觉模型仅用于画面语义/场景风险分析;竞品 Logo 检测由内置 CV 模型处理,不受配置影响。
|
||||||
- **对齐文档:** `AIProviderConfig.md`、`UIDesign.md`、`User_Role_Interfaces.md`、`DevelopmentPlan.md`
|
- **对齐文档:** `AIProviderConfig.md`、`UIDesign.md`、`User_Role_Interfaces.md`
|
||||||
|
|
||||||
### 1.3 文件上传方案 (已同步)
|
### 1.3 文件上传方案 (已同步)
|
||||||
- **结论:** 批量上传采用 **多文件拖拽并发上传 + Tus 断点续传**,弃用 ZIP。
|
- **结论:** 批量上传采用 **多文件拖拽并发上传 + Tus 断点续传**,弃用 ZIP。
|
||||||
- **对齐文档:** `PRD.md`、`RequirementsDoc.md`、`FeatureSummary.md`、`DevelopmentPlan.md`
|
- **对齐文档:** `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. 权限与工作流
|
||||||
|
|
||||||
### 2.1 强制通过与特例关系 (已统一)
|
### 2.1 强制通过与特例关系 (已统一)
|
||||||
- **结论:** "强制通过"弹窗内提供 **保存为特例** 勾选项(默认不勾选);勾选后生成豁免条款并等待品牌方确认生效。
|
- **结论:** “强制通过”弹窗内提供 **保存为特例** 勾选项(默认不勾选);勾选后生成豁免条款并等待品牌方确认生效。
|
||||||
- **对齐文档:** `PRD.md`、`UIDesign.md`、`User_Role_Interfaces.md`
|
- **对齐文档:** `PRD.md`、`UIDesign.md`、`User_Role_Interfaces.md`
|
||||||
|
|
||||||
### 2.2 强制通过禁用后的流程 (已统一)
|
### 2.2 强制通过禁用后的流程 (已统一)
|
||||||
- **结论:** 品牌方关闭授权后,代理商端按钮文案变为"申请强制通过",填写理由并提交品牌方审批。
|
- **结论:** 品牌方关闭授权后,代理商端按钮文案变为“申请强制通过”,填写理由并提交品牌方审批。
|
||||||
- **对齐文档:** `PRD.md`、`UIDesign.md`、`User_Role_Interfaces.md`
|
- **对齐文档:** `PRD.md`、`UIDesign.md`、`User_Role_Interfaces.md`
|
||||||
|
|
||||||
### 2.3 AI 配置可见性 (已统一)
|
### 2.3 AI 配置可见性 (已统一)
|
||||||
- **结论:** 代理商/达人 **不可见** AI 配置,仅品牌方管理员可查看与修改。
|
- **结论:** 代理商/达人 **不可见** AI 配置,仅品牌方管理员可查看与修改。
|
||||||
- **对齐文档:** `UIDesign.md`、`User_Role_Interfaces.md`、`AIProviderConfig.md`
|
- **对齐文档:** `UIDesign.md`、`User_Role_Interfaces.md`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -57,124 +50,14 @@
|
|||||||
|
|
||||||
## 4. 文档一致性
|
## 4. 文档一致性
|
||||||
|
|
||||||
### 4.1 TDD 计划文档 (已补齐)
|
### 4.1 TDD 计划文档缺失 (已补齐)
|
||||||
- **结论:** 新增 `featuredoc/tdd_plan.md`,作为 `tasks.md` 中 TDD 引用的正式文档。
|
- **结论:** 新增 `featuredoc/tdd_plan.md`,作为 `tasks.md` 中 TDD 引用的正式文档。
|
||||||
- **对齐文档:** `tasks.md`、`DevelopmentPlan.md`
|
- **对齐文档:** `tasks.md`
|
||||||
|
|
||||||
### 4.2 视频采样率假设 (已同步)
|
### 4.2 视频采样率假设 (已同步)
|
||||||
- **结论:** CV 采样率默认 **2fps**,并在该采样率下验证时长统计准确性。
|
- **结论:** CV 采样率默认 **2fps**,并在该采样率下验证时长统计准确性。
|
||||||
- **对齐文档:** `PRD.md`、`FeatureSummary.md`、`DevelopmentPlan.md`
|
- **对齐文档:** `PRD.md`、`FeatureSummary.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设计 |
|
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
| 文档类型 | **Feature Summary (产品功能文档)** |
|
| 文档类型 | **Feature Summary (产品功能文档)** |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| **项目名称** | 秒思智能审核平台 (AI 营销内容合规审核平台) |
|
| **项目名称** | SmartAudit (AI 营销内容合规审核平台) |
|
||||||
| **版本号** | V1.6 |
|
| **版本号** | V1.3 |
|
||||||
| **发布日期** | 2026-02-03 |
|
| **发布日期** | 2026-02-03 |
|
||||||
| **关联文档** | RequirementsDoc.md, PRD.md, User_Role_Interfaces.md |
|
| **关联文档** | RequirementsDoc.md, PRD.md, User_Role_Interfaces.md |
|
||||||
| **侧重** | 功能清单、优先级、验收标准、界面映射、边界说明 |
|
| **侧重** | 功能清单、优先级、验收标准、界面映射、边界说明 |
|
||||||
@ -18,9 +18,6 @@
|
|||||||
| V1.1 | 2026-02-02 | Claude | 根据 Gemini 修订意见调整:补充验收标准、Out of Scope、核心痛点细化 |
|
| V1.1 | 2026-02-02 | Claude | 根据 Gemini 修订意见调整:补充验收标准、Out of Scope、核心痛点细化 |
|
||||||
| V1.2 | 2026-02-02 | Claude | 根据 Gemini 关键改进意见:优先级调整、功能拆分、新增功能、移动端适配 |
|
| V1.2 | 2026-02-02 | Claude | 根据 Gemini 关键改进意见:优先级调整、功能拆分、新增功能、移动端适配 |
|
||||||
| V1.3 | 2026-02-02 | Claude | **新增 AI 厂商动态配置功能模块 (F-47~F-50)**,支持数据库配置、多租户隔离 |
|
| 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 修订意见采纳情况:**
|
**Gemini 修订意见采纳情况:**
|
||||||
|
|
||||||
@ -40,7 +37,7 @@
|
|||||||
|
|
||||||
### 1.1 产品定位
|
### 1.1 产品定位
|
||||||
|
|
||||||
秒思智能审核平台 是一款**基于多模态大模型的 B2B SaaS 审核工具**,定位为**"智能预审员"**,在人工介入前**自动化拦截 80% 的基础错误和合规风险**,将审核流转周期从"天"缩短到"小时"。
|
SmartAudit 是一款**基于多模态大模型的 B2B SaaS 审核工具**,定位为**"智能预审员"**,在人工介入前**自动化拦截 80% 的基础错误和合规风险**,将审核流转周期从"天"缩短到"小时"。
|
||||||
|
|
||||||
### 1.2 核心价值
|
### 1.2 核心价值
|
||||||
|
|
||||||
@ -67,7 +64,7 @@
|
|||||||
|
|
||||||
```
|
```
|
||||||
┌─────────────────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
│ 秒思智能审核平台 功能架构 │
|
│ SmartAudit 功能架构 │
|
||||||
├─────────────────────────────────────────────────────────────────┤
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
│ │
|
│ │
|
||||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||||
@ -375,7 +372,6 @@
|
|||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| F-19 | 风险列表展示 | P0 | US-08 | 代理商 |
|
| F-19 | 风险列表展示 | P0 | US-08 | 代理商 |
|
||||||
| F-20 | 确认/驳回操作 | P0 | US-08 | 代理商 |
|
| F-20 | 确认/驳回操作 | P0 | US-08 | 代理商 |
|
||||||
| F-51 | 品牌方终审开关 | **P0** | - | 品牌方 |
|
|
||||||
| F-21 | 强制通过权 | P1 | US-09 | 品牌方(默认授权代理商) |
|
| F-21 | 强制通过权 | P1 | US-09 | 品牌方(默认授权代理商) |
|
||||||
| F-22 | 特例记录与白名单 | P1 | US-09 | 品牌方 |
|
| F-22 | 特例记录与白名单 | P1 | US-09 | 品牌方 |
|
||||||
| F-23 | 规则依据与证据查看 | P1 | US-08 | 代理商/品牌方 |
|
| F-23 | 规则依据与证据查看 | P1 | US-08 | 代理商/品牌方 |
|
||||||
@ -399,95 +395,12 @@
|
|||||||
|
|
||||||
**操作说明:**
|
**操作说明:**
|
||||||
- 驳回:自动将勾选的问题打包发送给达人
|
- 驳回:自动将勾选的问题打包发送给达人
|
||||||
- 通过:
|
- 通过:流程结束
|
||||||
- 若品牌方**未开启终审**(默认)→ 流程结束,任务状态变为「已通过」
|
|
||||||
- 若品牌方**已开启终审** → 进入品牌方终审队列,任务状态变为「待终审」
|
|
||||||
|
|
||||||
**界面映射:** 代理商端 → 审核决策台 → 决策栏
|
**界面映射:** 代理商端 → 审核决策台 → 决策栏
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### F-51 品牌方终审开关 ⭐ P0 (新增)
|
|
||||||
|
|
||||||
**功能描述:** 品牌方可配置是否对代理商初审通过的内容进行终审。
|
|
||||||
|
|
||||||
**配置选项:**
|
|
||||||
- **终审开关**:开启/关闭(**默认关闭**)
|
|
||||||
- **终审范围**:全部内容 / 仅舆情风险内容 / 仅指定代理商
|
|
||||||
- **终审超时处理**:超时自动通过 / 超时提醒(默认48小时)
|
|
||||||
|
|
||||||
**流程说明:**
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────────┐
|
|
||||||
│ 终审关闭(默认) │
|
|
||||||
│ 达人提交 → AI审核 → 代理商初审通过 → ✅ 最终通过 │
|
|
||||||
├─────────────────────────────────────────────────────────────┤
|
|
||||||
│ 终审开启 │
|
|
||||||
│ 达人提交 → AI审核 → 代理商初审通过 → 品牌方终审 │
|
|
||||||
│ ├─ 通过 → ✅ 最终通过 │
|
|
||||||
│ └─ 驳回 → 返回达人修改 │
|
|
||||||
└─────────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
**为什么是 P0:** 审核流程是系统核心逻辑,需在 MVP 阶段确定流程框架,即使默认关闭也需要支持配置能力。
|
|
||||||
|
|
||||||
**界面映射:** 品牌方端 → 系统设置 → 审核流程配置
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### F-52 审核流程进度可视化 ⭐ P0 (新增)
|
|
||||||
|
|
||||||
**功能描述:** **全角色(达人、代理商、品牌方)** 均可在移动端和桌面端实时查看内容的完整审核流程状态,清晰了解当前处于哪个审核阶段。
|
|
||||||
|
|
||||||
**审核状态流转:**
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────────────┐
|
|
||||||
│ 审核流程状态(全角色可见) │
|
|
||||||
├─────────────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ ① 已提交 ② AI审核中 ③ 待代理商审核 ④ 待品牌终审 │
|
|
||||||
│ ⬇️ ⬇️ ⬇️ ⬇️ │
|
|
||||||
│ ┌──────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
|
||||||
│ │ 📤 │ ──▶ │ 🤖 AI │ ──▶│ 👥 代理商│ ──▶│ 🛡️ 品牌方│ │
|
|
||||||
│ │已上传 │ │ 审核中 │ │ 审核中 │ │ 终审中 │ │
|
|
||||||
│ └──────┘ └──────────┘ └──────────┘ └──────────┘ │
|
|
||||||
│ │ │ │ │
|
|
||||||
│ ▼ ▼ ▼ │
|
|
||||||
│ ⚠️ 需修改 ⚠️ 驳回 ⚠️ 驳回 │
|
|
||||||
│ │ │ │ │
|
|
||||||
│ └───────────────┴───────────────┘ │
|
|
||||||
│ 返回修改 │
|
|
||||||
│ │
|
|
||||||
│ 最终状态:✅ 审核通过 或 ❌ 审核驳回 │
|
|
||||||
└─────────────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
**状态定义:**
|
|
||||||
| 状态 | 图标 | 颜色 | 说明 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| 已提交 | 📤 | 灰色 | 内容已上传,等待处理 |
|
|
||||||
| AI审核中 | 🤖 | 蓝色/动画 | AI 正在分析内容 |
|
|
||||||
| AI审核通过 | ✅ | 绿色 | AI 未发现硬性问题,进入人工复核 |
|
|
||||||
| 需修改 | ⚠️ | 橙色 | AI 发现问题,需要达人修改 |
|
|
||||||
| 待代理商审核 | 👥 | 紫色 | 等待代理商人工复核 |
|
|
||||||
| 待品牌终审 | 🛡️ | 紫色 | 等待品牌方终审(仅当终审开启时) |
|
|
||||||
| 审核通过 | ✅ | 绿色 | 流程完成,可发布 |
|
|
||||||
| 审核驳回 | ❌ | 红色 | 被驳回,需修改后重新提交 |
|
|
||||||
|
|
||||||
**为什么是 P0:** 达人最关心"我的内容现在在哪个环节",清晰的流程状态能减少达人焦虑,避免频繁询问代理商,提升用户体验。代理商和品牌方也需要在审核时清楚了解内容当前所处阶段。
|
|
||||||
|
|
||||||
**界面映射:**
|
|
||||||
| 角色 | 端 | 页面 | 说明 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| 达人 | 桌面 | 任务列表、审核结果页 | 卡片状态标签 + 顶部进度条 |
|
|
||||||
| 达人 | 移动 | 任务列表、审核结果页 | 卡片状态标签 + 顶部进度条 |
|
|
||||||
| 代理商 | 桌面 | 审核决策台 | 顶部进度条,标注"当前:代理商审核" |
|
|
||||||
| 代理商 | 移动 | 快捷审核 | 导航栏下方进度条 |
|
|
||||||
| 品牌方 | 桌面 | 终审台 | 顶部进度条,标注"当前:品牌终审" |
|
|
||||||
| 品牌方 | 移动 | 审批中心 | 审批项内显示进度条 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### F-21 强制通过权
|
#### F-21 强制通过权
|
||||||
|
|
||||||
**功能描述:** 品牌方可手动放行过于保守的误报(如达人玩的新梗)。**默认授权代理商独立使用强制通过功能**;品牌方可在设置中**按代理商**关闭授权,关闭后代理商需发起审批流程。
|
**功能描述:** 品牌方可手动放行过于保守的误报(如达人玩的新梗)。**默认授权代理商独立使用强制通过功能**;品牌方可在设置中**按代理商**关闭授权,关闭后代理商需发起审批流程。
|
||||||
@ -793,7 +706,7 @@ V1 版本指出 3 个违规点:✅ 已修复 2 个 | ❌ 未修复 1 个
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 3.12 系统管理 - AI 厂商配置 (V1.4 修订)
|
### 3.12 系统管理 - AI 厂商配置 (V1.4 新增)
|
||||||
|
|
||||||
| 功能编号 | 功能名称 | 优先级 | 用户故事 | 使用角色 |
|
| 功能编号 | 功能名称 | 优先级 | 用户故事 | 使用角色 |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
@ -804,13 +717,13 @@ V1 版本指出 3 个违规点:✅ 已修复 2 个 | ❌ 未修复 1 个
|
|||||||
|
|
||||||
#### F-47 AI 厂商动态配置 ⭐ P0
|
#### F-47 AI 厂商动态配置 ⭐ P0
|
||||||
|
|
||||||
**功能描述:** 品牌方管理员可在后台配置**单一 AI 提供商**(OneAPI/OpenRouter 中转或直连厂商),配置存储在数据库中,运行时动态加载,无需修改代码或重启服务。每个租户仅保留一套配置,可随时切换提供商。
|
**功能描述:** 品牌方管理员可在后台配置多个 AI 厂商(DeepSeek、OpenAI、通义千问、OneAPI 中转等),配置存储在数据库中,运行时动态加载,无需修改代码或重启服务。
|
||||||
|
|
||||||
**核心功能:**
|
**核心功能:**
|
||||||
- 支持配置与更新 AI 提供商
|
- 支持添加、编辑、删除 AI 厂商配置
|
||||||
- 配置 Base URL、API Key(AES-256-GCM 加密存储)、默认模型
|
- 配置 Base URL、API Key(AES-256-GCM 加密存储)、默认模型
|
||||||
- 为不同使用场景(Brief 解析、脚本预审、视频审核)指定不同模型
|
- 为不同使用场景(Brief 解析、脚本预审、视频审核)指定不同厂商
|
||||||
- 可通过 OneAPI/OpenRouter 聚合多模型
|
- 配置优先级和备用厂商(故障转移)
|
||||||
- 未配置时阻断调用并提示品牌方完成配置
|
- 未配置时阻断调用并提示品牌方完成配置
|
||||||
|
|
||||||
**为什么是 P0:** 这是 AI 服务的基础设施,所有 AI 功能都依赖此配置。
|
**为什么是 P0:** 这是 AI 服务的基础设施,所有 AI 功能都依赖此配置。
|
||||||
@ -831,7 +744,7 @@ V1 版本指出 3 个违规点:✅ 已修复 2 个 | ❌ 未修复 1 个
|
|||||||
|
|
||||||
#### F-49 多租户 AI 配置隔离
|
#### F-49 多租户 AI 配置隔离
|
||||||
|
|
||||||
**功能描述:** 不同品牌方可配置独立的 AI 提供商,实现租户级别的配置隔离和配额管理。
|
**功能描述:** 不同品牌方可配置独立的 AI 厂商,实现租户级别的配置隔离和配额管理。
|
||||||
|
|
||||||
**界面映射:** 品牌方后台 → 系统设置 → AI 配置
|
**界面映射:** 品牌方后台 → 系统设置 → AI 配置
|
||||||
|
|
||||||
@ -886,8 +799,6 @@ V1 版本指出 3 个违规点:✅ 已修复 2 个 | ❌ 未修复 1 个
|
|||||||
| F-17 | 审核进度实时展示 | 视频审核 | ⭐ P1→P0,缓解等待焦虑 |
|
| F-17 | 审核进度实时展示 | 视频审核 | ⭐ P1→P0,缓解等待焦虑 |
|
||||||
| F-19 | 风险列表展示 | 审核台 | |
|
| F-19 | 风险列表展示 | 审核台 | |
|
||||||
| F-20 | 确认/驳回操作 | 审核台 | |
|
| F-20 | 确认/驳回操作 | 审核台 | |
|
||||||
| F-51 | 品牌方终审开关 | 审核台 | ⭐ 新增,审核流程可配置 |
|
|
||||||
| F-52 | 审核流程进度可视化 | 达人端 | ⭐ 新增,达人可见审核状态 |
|
|
||||||
| F-33 | 核心指标卡片 | 数据看板 | |
|
| F-33 | 核心指标卡片 | 数据看板 | |
|
||||||
| F-47 | AI 厂商动态配置 | 系统管理 | ⭐ V1.3 新增,AI 基础设施 |
|
| F-47 | AI 厂商动态配置 | 系统管理 | ⭐ V1.3 新增,AI 基础设施 |
|
||||||
| F-48 | AI 厂商连通性测试 | 系统管理 | ⭐ V1.3 新增 |
|
| F-48 | AI 厂商连通性测试 | 系统管理 | ⭐ V1.3 新增 |
|
||||||
@ -957,7 +868,7 @@ V1 版本指出 3 个违规点:✅ 已修复 2 个 | ❌ 未修复 1 个
|
|||||||
| **安全** | 传输与存储加密(AES-256-GCM);基于角色权限控制;关键操作二次确认 |
|
| **安全** | 传输与存储加密(AES-256-GCM);基于角色权限控制;关键操作二次确认 |
|
||||||
| **隐私** | 数据最小化;默认保留 30 天;符合《个保法》与 GDPR |
|
| **隐私** | 数据最小化;默认保留 30 天;符合《个保法》与 GDPR |
|
||||||
| **数据本地化** | 国内客户数据存储于中国大陆境内服务器 |
|
| **数据本地化** | 国内客户数据存储于中国大陆境内服务器 |
|
||||||
| **审计** | 操作日志可审计且不可篡改(append-only + hash chain) |
|
| **审计** | 操作日志可审计且不可篡改 |
|
||||||
| **移动端适配** | **达人端(上传/查看报告)必须适配移动端 H5 竖屏操作** |
|
| **移动端适配** | **达人端(上传/查看报告)必须适配移动端 H5 竖屏操作** |
|
||||||
|
|
||||||
> ⚠️ **移动端适配说明:** 达人的工作场景多在拍摄现场(移动端),需要在手机上完成脚本上传、查看审核结果等操作。如果只做 PC 网页版,达人无法在拍摄现场即时使用,产品价值会大打折扣。
|
> ⚠️ **移动端适配说明:** 达人的工作场景多在拍摄现场(移动端),需要在手机上完成脚本上传、查看审核结果等操作。如果只做 PC 网页版,达人无法在拍摄现场即时使用,产品价值会大打折扣。
|
||||||
@ -1014,7 +925,7 @@ V1 版本指出 3 个违规点:✅ 已修复 2 个 | ❌ 未修复 1 个
|
|||||||
| RequirementsDoc.md | 业务需求文档(用户故事、成功指标) |
|
| RequirementsDoc.md | 业务需求文档(用户故事、成功指标) |
|
||||||
| PRD.md | 产品需求文档(功能需求、技术架构) |
|
| PRD.md | 产品需求文档(功能需求、技术架构) |
|
||||||
| User_Role_Interfaces.md | 用户角色与界面规范 |
|
| User_Role_Interfaces.md | 用户角色与界面规范 |
|
||||||
| **AIProviderConfig.md** | **AI 厂商动态配置架构设计(V2.1)** |
|
| **AIProviderConfig.md** | **AI 厂商动态配置架构设计(V2.0)** |
|
||||||
| 技术设计文档 (TDD) | 待编写 |
|
| 技术设计文档 (TDD) | 待编写 |
|
||||||
| API 接口规范 | 待编写 |
|
| API 接口规范 | 待编写 |
|
||||||
| 数据字典 | 待编写 |
|
| 数据字典 | 待编写 |
|
||||||
|
|||||||
35
PRD.md
35
PRD.md
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
| 文档类型 | **PRD (Product Requirement Document)** |
|
| 文档类型 | **PRD (Product Requirement Document)** |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| **项目名称** | 秒思智能审核平台 (AI 营销内容合规审核平台) |
|
| **项目名称** | SmartAudit (AI 营销内容合规审核平台) |
|
||||||
| **版本号** | V1.0 |
|
| **版本号** | V1.0 |
|
||||||
| **发布日期** | 2026-02-03 |
|
| **发布日期** | 2026-02-03 |
|
||||||
| **状态** | 草稿 (Draft) |
|
| **状态** | 草稿 (Draft) |
|
||||||
@ -102,12 +102,11 @@
|
|||||||
- 视频自动审核(竞品、违禁词、画面风险) → [US-05]
|
- 视频自动审核(竞品、违禁词、画面风险) → [US-05]
|
||||||
- 审核台风险打点与确认/驳回 → [US-08]
|
- 审核台风险打点与确认/驳回 → [US-08]
|
||||||
- 语境理解降低误报 → [US-04]
|
- 语境理解降低误报 → [US-04]
|
||||||
- 审核进度展示(F-17) → [US-07]
|
- 审核进度展示与时间戳修改清单 → [US-07]
|
||||||
- 基础黑白名单与竞品库(F-05-A) → [US-10A]
|
- 基础黑白名单与竞品库(F-05-A) → [US-10A]
|
||||||
- 时长与频次校验(F-45) → [US-05]
|
- 时长与频次校验(F-45) → [US-05]
|
||||||
- AI 服务配置与连通性测试(F-47/F-48)
|
- AI 服务配置与连通性测试(F-47/F-48)
|
||||||
- 多租户 AI 配置隔离(F-49)
|
- 多租户 AI 配置隔离(F-49)
|
||||||
- 数据看板核心指标卡片(F-33)
|
|
||||||
|
|
||||||
**P1(首版发布后快速迭代)**
|
**P1(首版发布后快速迭代)**
|
||||||
- Brand Safety 软性风险提示 → [US-06]
|
- Brand Safety 软性风险提示 → [US-06]
|
||||||
@ -135,7 +134,6 @@
|
|||||||
- **规则库管理与版本控制:** 支持平台规则库更新、品牌私有规则与白名单配置
|
- **规则库管理与版本控制:** 支持平台规则库更新、品牌私有规则与白名单配置
|
||||||
- **权限与多租户隔离:** 支持品牌/代理/达人不同角色的权限与数据隔离
|
- **权限与多租户隔离:** 支持品牌/代理/达人不同角色的权限与数据隔离
|
||||||
- **审计日志与报告导出:** 支持导出可追溯的审核证据链
|
- **审计日志与报告导出:** 支持导出可追溯的审核证据链
|
||||||
- **数据看板与核心指标:** 提供核心指标卡片与基础数据概览
|
|
||||||
|
|
||||||
### 5.2 Out of Scope
|
### 5.2 Out of Scope
|
||||||
|
|
||||||
@ -220,21 +218,15 @@
|
|||||||
**P0**
|
**P0**
|
||||||
- 审核台展示风险列表(红/黄/绿分级)与时间戳
|
- 审核台展示风险列表(红/黄/绿分级)与时间戳
|
||||||
- 支持确认/驳回操作,无需从头看视频
|
- 支持确认/驳回操作,无需从头看视频
|
||||||
- **可配置审核流程(F-51)**:品牌方可开启/关闭终审环节
|
|
||||||
- **终审关闭(默认)**:代理商初审通过 → 最终通过
|
|
||||||
- **终审开启**:代理商初审通过 → 品牌方终审 → 最终通过/驳回
|
|
||||||
- 支持配置终审范围(全部/仅舆情风险/指定代理商)
|
|
||||||
- 支持配置终审超时处理(默认48小时)
|
|
||||||
|
|
||||||
**P1**
|
**P1**
|
||||||
- 品牌方"强制通过权":可手动放行过于保守的误报(需记录原因与审批人);**默认授权代理商独立使用,可在品牌方设置中按代理商关闭,关闭后需走审批流程**。强制通过弹窗需填写原因,并提供"保存为特例"可选项(**默认不勾选**,勾选后形成豁免条款,需品牌方确认生效)
|
- 品牌方"强制通过权":可手动放行过于保守的误报(需记录原因与审批人);**默认授权代理商独立使用,可在品牌方设置中按代理商关闭,关闭后需走审批流程**。强制通过弹窗需填写原因,并提供“保存为特例”可选项(**默认不勾选**,勾选后形成豁免条款,需品牌方确认生效)
|
||||||
- 特例可沉淀为规则白名单/豁免条款(含来源:强制通过勾选或手动记录)
|
- 特例可沉淀为规则白名单/豁免条款(含来源:强制通过勾选或手动记录)
|
||||||
- 如需用于模型优化,必须确保数据授权与合规评估
|
- 如需用于模型优化,必须确保数据授权与合规评估
|
||||||
- 可查看规则依据与证据片段
|
- 可查看规则依据与证据片段
|
||||||
|
|
||||||
**验收要点**
|
**验收要点**
|
||||||
- 每条结论包含规则版本、模型版本、证据截图/片段与时间戳
|
- 每条结论包含规则版本、模型版本、证据截图/片段与时间戳
|
||||||
- 终审开启时,代理商通过后任务状态变为「待终审」,品牌方操作后变为「已通过」或「待修改」
|
|
||||||
|
|
||||||
### 6.5 代理商管理
|
### 6.5 代理商管理
|
||||||
|
|
||||||
@ -277,22 +269,6 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 6.9 数据看板与核心指标
|
|
||||||
|
|
||||||
**P0**
|
|
||||||
- 核心指标卡片(F-33):展示审核总量、初审通过率、硬性召回率、舆情拦截数、平均审核周期
|
|
||||||
|
|
||||||
**P1**
|
|
||||||
- 趋势图表(F-34):近 30 天审核量与通过率趋势
|
|
||||||
- 风险预警(F-35):竞品露出集中爆发、达人连续未通过、舆情异常上升
|
|
||||||
- 代理商绩效对比(F-36)与达人排行榜(F-37)
|
|
||||||
|
|
||||||
**验收要点**
|
|
||||||
- 指标口径与成功指标定义一致
|
|
||||||
- 指标数据可追溯到审计记录
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. 关键流程 (Key User Flows)
|
## 7. 关键流程 (Key User Flows)
|
||||||
|
|
||||||
### 7.1 品牌方工作流
|
### 7.1 品牌方工作流
|
||||||
@ -350,7 +326,6 @@
|
|||||||
- 全流程日志可追溯、不可篡改
|
- 全流程日志可追溯、不可篡改
|
||||||
- 导出报告包含规则版本、模型版本、证据截图/片段与时间戳
|
- 导出报告包含规则版本、模型版本、证据截图/片段与时间戳
|
||||||
- 支持争议场景下完整审核证据链导出
|
- 支持争议场景下完整审核证据链导出
|
||||||
- 审计日志采用 append-only + hash chain(前序哈希 + 当前内容)确保可追溯
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -419,13 +394,13 @@
|
|||||||
- **ASR/OCR**:支持普通话及主流方言的语音识别,支持复杂背景字幕识别
|
- **ASR/OCR**:支持普通话及主流方言的语音识别,支持复杂背景字幕识别
|
||||||
- **计算机视觉**:Logo 检测、物体识别、场景分类
|
- **计算机视觉**:Logo 检测、物体识别、场景分类
|
||||||
- **消息队列**:异步处理视频审核任务,支持优先级调度
|
- **消息队列**:异步处理视频审核任务,支持优先级调度
|
||||||
- **AI 厂商动态配置**:品牌方管理员可在后台配置**单一 AI 提供商**(可为 OneAPI/OpenRouter 中转或直连厂商),运行时动态加载,支持多租户隔离;配置变更可随时切换(详见 AIProviderConfig.md)
|
- **AI 厂商动态配置**:品牌方管理员可在后台配置多个 AI 厂商(DeepSeek/OpenAI/OneAPI 等),运行时动态加载,支持多租户隔离和故障转移(详见 AIProviderConfig.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 14. 里程碑与发布计划 (Milestones)
|
## 14. 里程碑与发布计划 (Milestones)
|
||||||
|
|
||||||
- **MVP (P0)**:Brief 解析、规则加载、脚本预审、视频审核、审核台、语境理解降低误报、审核进度展示、基础黑白名单与竞品库、时长与频次校验、AI 服务商配置、核心指标卡片
|
- **MVP (P0)**:Brief 解析、规则加载、脚本预审、视频审核、审核台、语境理解降低误报、审核进度展示、基础黑白名单与竞品库、时长与频次校验、AI 服务商配置
|
||||||
- **V1.1 (P1)**:Brand Safety 提示、规则版本、证据链导出、强制通过权、高级豁免规则
|
- **V1.1 (P1)**:Brand Safety 提示、规则版本、证据链导出、强制通过权、高级豁免规则
|
||||||
- **V2 (P2)**:批量处理、版本差异报告
|
- **V2 (P2)**:批量处理、版本差异报告
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
| 文档类型 | **RD (Requirements Document)** |
|
| 文档类型 | **RD (Requirements Document)** |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| **项目名称** | 秒思智能审核平台 (AI 营销内容合规审核平台) |
|
| **项目名称** | SmartAudit (AI 营销内容合规审核平台) |
|
||||||
| **版本号** | V1.0 |
|
| **版本号** | V1.0 |
|
||||||
| **发布日期** | 2026-02-03 |
|
| **发布日期** | 2026-02-03 |
|
||||||
| **状态** | **修订 (Revised)** |
|
| **状态** | **修订 (Revised)** |
|
||||||
@ -135,7 +135,6 @@
|
|||||||
7. **规则库管理与版本控制:** 支持平台规则库更新、品牌私有规则与白名单配置。
|
7. **规则库管理与版本控制:** 支持平台规则库更新、品牌私有规则与白名单配置。
|
||||||
8. **权限与多租户隔离:** 支持品牌/代理/达人不同角色的权限与数据隔离。
|
8. **权限与多租户隔离:** 支持品牌/代理/达人不同角色的权限与数据隔离。
|
||||||
9. **审计日志与报告导出:** 支持导出可追溯的审核证据链。
|
9. **审计日志与报告导出:** 支持导出可追溯的审核证据链。
|
||||||
10. **数据看板与核心指标:** 提供核心指标卡片与基础数据概览。
|
|
||||||
|
|
||||||
### ❌ Out of Scope (本期不做)
|
### ❌ Out of Scope (本期不做)
|
||||||
|
|
||||||
@ -189,7 +188,7 @@
|
|||||||
* **ASR/OCR:** 支持普通话及主流方言的语音识别,支持复杂背景字幕识别
|
* **ASR/OCR:** 支持普通话及主流方言的语音识别,支持复杂背景字幕识别
|
||||||
* **计算机视觉:** Logo 检测、物体识别、场景分类
|
* **计算机视觉:** Logo 检测、物体识别、场景分类
|
||||||
* **消息队列:** 异步处理视频审核任务,支持优先级调度
|
* **消息队列:** 异步处理视频审核任务,支持优先级调度
|
||||||
* **AI 厂商动态配置:** 支持在数据库中配置**单一 AI 提供商**(可为 OneAPI/OpenRouter 中转或直连厂商),运行时动态加载,支持多租户隔离;配置变更可随时切换(详见 AIProviderConfig.md)
|
* **AI 厂商动态配置:** 支持在数据库中配置多个 AI 厂商(DeepSeek/OpenAI/OneAPI 等),运行时动态加载,支持多租户隔离和故障转移(详见 AIProviderConfig.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -214,7 +213,6 @@
|
|||||||
* **性能:** ≤ 100MB 视频上传后,AI 预审报告产出时间不超过 5 分钟(含排队 ≤ 2 分钟)。
|
* **性能:** ≤ 100MB 视频上传后,AI 预审报告产出时间不超过 5 分钟(含排队 ≤ 2 分钟)。
|
||||||
* **审计链路:** 每条结论包含规则版本、模型版本、证据截图/片段与时间戳。
|
* **审计链路:** 每条结论包含规则版本、模型版本、证据截图/片段与时间戳。
|
||||||
* **F-45 时长与频次统计:** 时长统计误差 ≤ 1秒;频次统计准确率 ≥ 95%。
|
* **F-45 时长与频次统计:** 时长统计误差 ≤ 1秒;频次统计准确率 ≥ 95%。
|
||||||
* **审计日志不可篡改:** 采用 append-only + hash chain(前序哈希 + 当前内容)校验可追溯。
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
38
UIDesign.md
38
UIDesign.md
@ -1,23 +1,12 @@
|
|||||||
# UIDesign.md - 智能视频审核系统 UI 设计规范
|
# UIDesign.md - 智能视频审核系统 UI 设计规范
|
||||||
|
|
||||||
> ⚠️ **重要说明 (2026-02-03)**
|
|
||||||
>
|
|
||||||
> 本文档为**早期设计参考文档**,设计风格为浅色系。
|
|
||||||
>
|
|
||||||
> **当前正式设计规范请参考:[UIDesignSpec.md](./UIDesignSpec.md)**
|
|
||||||
> - 设计稿文件:`pencil-new.pen`
|
|
||||||
> - 设计风格:Apple-style **暗色主题**
|
|
||||||
> - 包含最新的设计令牌、组件规范和页面清单
|
|
||||||
>
|
|
||||||
> 本文档仅保留用于历史参考和设计原则说明。开发时以 `UIDesignSpec.md` 为准。
|
|
||||||
|
|
||||||
| 文档类型 | **UI Design System (设计系统规范)** |
|
| 文档类型 | **UI Design System (设计系统规范)** |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| **项目名称** | 秒思智能审核平台 (AI 营销内容合规审核平台) |
|
| **项目名称** | SmartAudit (AI 营销内容合规审核平台) |
|
||||||
| **版本号** | V1.1 |
|
| **版本号** | V1.1 |
|
||||||
| **发布日期** | 2026-02-03 |
|
| **发布日期** | 2026-02-03 |
|
||||||
| **设计风格** | ~~Apple Human Interface Guidelines 浅色系~~ → 已更新为暗色主题,见 UIDesignSpec.md |
|
| **设计风格** | Apple Human Interface Guidelines 浅色系 |
|
||||||
| **关联文档** | PRD.md, FeatureSummary.md, User_Role_Interfaces.md, DevelopmentPlan.md, **UIDesignSpec.md** |
|
| **关联文档** | PRD.md, FeatureSummary.md, User_Role_Interfaces.md, DevelopmentPlan.md |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -27,23 +16,22 @@
|
|||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| V1.0 | 2026-02-02 | Claude | 初稿:设计原则、色彩系统、组件库、三端界面规范 |
|
| V1.0 | 2026-02-02 | Claude | 初稿:设计原则、色彩系统、组件库、三端界面规范 |
|
||||||
| V1.1 | 2026-02-02 | Claude | 新增第10章:AI 服务配置界面设计规范 |
|
| V1.1 | 2026-02-02 | Claude | 新增第10章:AI 服务配置界面设计规范 |
|
||||||
| V1.2 | 2026-02-03 | Claude | 添加废弃声明,指向 UIDesignSpec.md(暗色主题) |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1. 设计原则 (Design Principles)
|
## 1. 设计原则 (Design Principles)
|
||||||
|
|
||||||
借鉴 Apple Human Interface Guidelines,秒思智能审核平台 的设计遵循以下核心原则:
|
借鉴 Apple Human Interface Guidelines,SmartAudit 的设计遵循以下核心原则:
|
||||||
|
|
||||||
### 1.1 核心设计理念
|
### 1.1 核心设计理念
|
||||||
|
|
||||||
| 原则 | 描述 | 在 秒思智能审核平台 中的体现 |
|
| 原则 | 描述 | 在 SmartAudit 中的体现 |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| **Clarity (清晰)** | 文字清晰易读,图标精确传意,功能显而易见 | 审核结论用红/黄/绿 + 文字 + 图标三重表达 |
|
| **Clarity (清晰)** | 文字清晰易读,图标精确传意,功能显而易见 | 审核结论用红/黄/绿 + 文字 + 图标三重表达 |
|
||||||
| **Deference (克制)** | UI 退居幕后,内容为王 | 审核台以视频和报告为核心,界面元素轻量化 |
|
| **Deference (克制)** | UI 退居幕后,内容为王 | 审核台以视频和报告为核心,界面元素轻量化 |
|
||||||
| **Depth (层次)** | 通过视觉层次和流畅动效建立空间感 | 卡片悬浮阴影、模态弹窗、进度条层叠 |
|
| **Depth (层次)** | 通过视觉层次和流畅动效建立空间感 | 卡片悬浮阴影、模态弹窗、进度条层叠 |
|
||||||
|
|
||||||
### 1.2 秒思智能审核平台 专属原则
|
### 1.2 SmartAudit 专属原则
|
||||||
|
|
||||||
| 原则 | 说明 |
|
| 原则 | 说明 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
@ -653,7 +641,7 @@ font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
|
|||||||
│ │
|
│ │
|
||||||
│ ┌──────────┐ ┌────────────────────────────────────────────────────────┐ │
|
│ ┌──────────┐ ┌────────────────────────────────────────────────────────┐ │
|
||||||
│ │ │ │ │ │
|
│ │ │ │ │ │
|
||||||
│ │ 秒思智能审核平台│ │ 页面内容区域 │ │
|
│ │ SmartAudit│ │ 页面内容区域 │ │
|
||||||
│ │ │ │ │ │
|
│ │ │ │ │ │
|
||||||
│ ├──────────┤ │ │ │
|
│ ├──────────┤ │ │ │
|
||||||
│ │ │ │ │ │
|
│ │ │ │ │ │
|
||||||
@ -692,7 +680,7 @@ font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
|
|||||||
|
|
||||||
```
|
```
|
||||||
┌────────────────────────────────────────────────────────────────────────────┐
|
┌────────────────────────────────────────────────────────────────────────────┐
|
||||||
│ 秒思智能审核平台 🔔 (3) 👤 张三 │
|
│ SmartAudit 🔔 (3) 👤 张三 │
|
||||||
├──────────┬─────────────────────────────────────────────────────────────────┤
|
├──────────┬─────────────────────────────────────────────────────────────────┤
|
||||||
│ │ │
|
│ │ │
|
||||||
│ 📊 工作台 │ 工作台 │
|
│ 📊 工作台 │ 工作台 │
|
||||||
@ -739,7 +727,7 @@ font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
|
|||||||
|
|
||||||
```
|
```
|
||||||
┌────────────────────────────────────────────────────────────────────────────┐
|
┌────────────────────────────────────────────────────────────────────────────┐
|
||||||
│ 秒思智能审核平台 🔔 (3) 👤 张三 │
|
│ SmartAudit 🔔 (3) 👤 张三 │
|
||||||
├──────────┬─────────────────────────────────────────────────────────────────┤
|
├──────────┬─────────────────────────────────────────────────────────────────┤
|
||||||
│ │ │
|
│ │ │
|
||||||
│ 📊 工作台 │ Brief 配置中心 │
|
│ 📊 工作台 │ Brief 配置中心 │
|
||||||
@ -781,7 +769,7 @@ font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
|
|||||||
|
|
||||||
```
|
```
|
||||||
┌────────────────────────────────────────────────────────────────────────────┐
|
┌────────────────────────────────────────────────────────────────────────────┐
|
||||||
│ 秒思智能审核平台 🔔 (3) 👤 张三 │
|
│ SmartAudit 🔔 (3) 👤 张三 │
|
||||||
├──────────┬─────────────────────────────────────────────────────────────────┤
|
├──────────┬─────────────────────────────────────────────────────────────────┤
|
||||||
│ │ │
|
│ │ │
|
||||||
│ 📊 工作台 │ 审核决策台 ⬅️ ➡️ │
|
│ 📊 工作台 │ 审核决策台 ⬅️ ➡️ │
|
||||||
@ -904,7 +892,7 @@ font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
|
|||||||
|
|
||||||
```
|
```
|
||||||
┌────────────────────────────────────────────────────────────────────────────┐
|
┌────────────────────────────────────────────────────────────────────────────┐
|
||||||
│ 秒思智能审核平台 🔔 (3) 👤 王总 │
|
│ SmartAudit 🔔 (3) 👤 王总 │
|
||||||
├──────────┬─────────────────────────────────────────────────────────────────┤
|
├──────────┬─────────────────────────────────────────────────────────────────┤
|
||||||
│ │ │
|
│ │ │
|
||||||
│ 📊 数据 │ 数据看板 本月 ▼ 导出报告 ▼ │
|
│ 📊 数据 │ 数据看板 本月 ▼ 导出报告 ▼ │
|
||||||
@ -948,7 +936,7 @@ font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
|
|||||||
|
|
||||||
```
|
```
|
||||||
┌────────────────────────────────────────────────────────────────────────────┐
|
┌────────────────────────────────────────────────────────────────────────────┐
|
||||||
│ 秒思智能审核平台 🔔 (3) 👤 王总 │
|
│ SmartAudit 🔔 (3) 👤 王总 │
|
||||||
├──────────┬─────────────────────────────────────────────────────────────────┤
|
├──────────┬─────────────────────────────────────────────────────────────────┤
|
||||||
│ │ │
|
│ │ │
|
||||||
│ 📊 数据 │ 规则配置 │
|
│ 📊 数据 │ 规则配置 │
|
||||||
@ -1010,7 +998,7 @@ font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
|
|||||||
|
|
||||||
```
|
```
|
||||||
┌────────────────────────────────────────────────────────────────────────────┐
|
┌────────────────────────────────────────────────────────────────────────────┐
|
||||||
│ 秒思智能审核平台 🔔 (3) 👤 王总 │
|
│ SmartAudit 🔔 (3) 👤 王总 │
|
||||||
├──────────┬─────────────────────────────────────────────────────────────────┤
|
├──────────┬─────────────────────────────────────────────────────────────────┤
|
||||||
│ │ │
|
│ │ │
|
||||||
│ 📊 数据 │ AI 服务配置 │
|
│ 📊 数据 │ AI 服务配置 │
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
| 文档类型 | **UI Design Specification** |
|
| 文档类型 | **UI Design Specification** |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| **项目名称** | 秒思智能审核平台 (AI 营销内容合规审核平台) |
|
| **项目名称** | SmartAudit (AI 营销内容合规审核平台) |
|
||||||
| **版本号** | V1.0 |
|
| **版本号** | V1.0 |
|
||||||
| **发布日期** | 2026-02-03 |
|
| **发布日期** | 2026-02-03 |
|
||||||
| **设计稿文件** | `pencil-new.pen` |
|
| **设计稿文件** | `pencil-new.pen` |
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
| 文档类型 | **UI/UX Spec (Interface Definitions)** |
|
| 文档类型 | **UI/UX Spec (Interface Definitions)** |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| **项目名称** | 秒思智能审核平台 (AI 营销内容合规审核平台) |
|
| **项目名称** | SmartAudit (AI 营销内容合规审核平台) |
|
||||||
| **版本号** | V1.5 |
|
| **版本号** | V1.3 |
|
||||||
| **发布日期** | 2026-02-03 |
|
| **发布日期** | 2026-02-03 |
|
||||||
| **关联文档** | RequirementsDoc.md, PRD.md, FeatureSummary.md, DevelopmentPlan.md, AIProviderConfig.md, UIDesign.md, tasks.md |
|
| **关联文档** | RequirementsDoc.md, PRD.md, FeatureSummary.md, DevelopmentPlan.md, AIProviderConfig.md, UIDesign.md, tasks.md |
|
||||||
| **侧重** | 角色权限、核心页面布局、交互逻辑 |
|
| **侧重** | 角色权限、核心页面布局、交互逻辑 |
|
||||||
@ -19,8 +19,6 @@
|
|||||||
| V1.1 | 2026-02-02 | Claude | 与 RD/PRD 对齐:补充用户故事引用、区域合规、特例记录规范、证据链权限 |
|
| V1.1 | 2026-02-02 | Claude | 与 RD/PRD 对齐:补充用户故事引用、区域合规、特例记录规范、证据链权限 |
|
||||||
| V1.2 | 2026-02-02 | Claude | 新增代理商端和品牌方端移动端 UI 设计(工作台、快捷审核、预警、审批) |
|
| V1.2 | 2026-02-02 | Claude | 新增代理商端和品牌方端移动端 UI 设计(工作台、快捷审核、预警、审批) |
|
||||||
| V1.3 | 2026-02-02 | Claude | 新增 AI 服务配置章节(4.6),品牌方专属功能 |
|
| V1.3 | 2026-02-02 | Claude | 新增 AI 服务配置章节(4.6),品牌方专属功能 |
|
||||||
| V1.4 | 2026-02-03 | Claude | **新增审核流程进度可视化 UI(F-52)**:达人端任务列表状态标签、审核结果页进度条 |
|
|
||||||
| V1.5 | 2026-02-03 | Claude | **扩展审核流程进度可视化至全角色**:代理商审核决策台/快捷审核、品牌方审批中心均可查看进度条 |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -36,16 +34,14 @@
|
|||||||
| **Brief 管理** | 查看任务详情 | ✅ 上传/解析/编辑 Brief | ✅ 全局规则配置 |
|
| **Brief 管理** | 查看任务详情 | ✅ 上传/解析/编辑 Brief | ✅ 全局规则配置 |
|
||||||
| **脚本/视频提交** | ✅ 上传 & 修改 [US-03] | ❌ 不可提交 | ❌ 不可提交 |
|
| **脚本/视频提交** | ✅ 上传 & 修改 [US-03] | ❌ 不可提交 | ❌ 不可提交 |
|
||||||
| **查看 AI 报告** | ✅ 仅查看自己的 [US-07] | ✅ 查看所管辖达人的 | ✅ 查看所有 |
|
| **查看 AI 报告** | ✅ 仅查看自己的 [US-07] | ✅ 查看所管辖达人的 | ✅ 查看所有 |
|
||||||
| **审核决策** | ❌ 无权 | ✅ 初审 (驳回/通过) [US-08] | ✅ 终审(可配置)/ 强制通过 [US-09] |
|
| **审核决策** | ❌ 无权 | ✅ 初审 (驳回/通过) [US-08] | ✅ 终审 / 强制通过 [US-09] |
|
||||||
| **申诉功能** | ✅ 发起申诉 (消耗令牌) | ✅ 仲裁申诉 | ❌ 无需申诉 |
|
| **申诉功能** | ✅ 发起申诉 (消耗令牌) | ✅ 仲裁申诉 | ❌ 无需申诉 |
|
||||||
| **证据链导出** | ❌ 无权 | ✅ 导出所管辖任务 | ✅ 导出全部 [US-12] |
|
| **证据链导出** | ❌ 无权 | ✅ 导出所管辖任务 | ✅ 导出全部 [US-12] |
|
||||||
| **数据看板** | 仅看个人任务进度 | 整体进度 / 达人排名 | 全局合规率 / 舆情风控 |
|
| **数据看板** | 仅看个人任务进度 | 整体进度 / 达人排名 | 全局合规率 / 舆情风控 |
|
||||||
| **系统配置** | ❌ 无权 | ❌ 无权 | ✅ 规则库/阈值/白名单/区域合规/审核流程 [US-10A/US-10B] |
|
| **系统配置** | ❌ 无权 | ❌ 无权 | ✅ 规则库/阈值/白名单/区域合规 [US-10A/US-10B] |
|
||||||
| **AI 服务配置** | ❌ 无权 | ❌ 无权(继承品牌方配置) | ✅ 配置 AI 提供商/模型/参数 |
|
| **AI 服务配置** | ❌ 无权 | ❌ 无权(继承品牌方配置) | ✅ 配置 AI 提供商/模型/参数 |
|
||||||
| **用户管理** | ❌ 无权 | ✅ 管理所属达人 | ✅ 管理代理商与达人 |
|
| **用户管理** | ❌ 无权 | ✅ 管理所属达人 | ✅ 管理代理商与达人 |
|
||||||
|
|
||||||
> **审核流程说明:** 品牌方可在系统设置中配置是否开启终审环节。**默认关闭**,代理商初审通过即为最终通过;开启后,代理商初审通过的内容需进入品牌方终审队列。
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1.1 各端导航结构 (Navigation Structure)
|
## 1.1 各端导航结构 (Navigation Structure)
|
||||||
@ -112,52 +108,13 @@
|
|||||||
## 2. 界面详解:达人端 (The Creator Portal)
|
## 2. 界面详解:达人端 (The Creator Portal)
|
||||||
|
|
||||||
**设计目标:** 极简、透明、减少焦虑。让达人像发朋友圈一样简单地完成合规检查。
|
**设计目标:** 极简、透明、减少焦虑。让达人像发朋友圈一样简单地完成合规检查。
|
||||||
**核心设备:** 手机浏览器 (H5) / 小程序。
|
**核心设备:** 手机浏览器 (Mobile Web) / 小程序。
|
||||||
|
|
||||||
### 2.1 任务列表页 (Task List)
|
### 2.1 任务列表页 (Task List)
|
||||||
|
|
||||||
* **状态概览:** 卡片式布局,显示当前任务状态(待提交、AI审核中、需修改、已通过)。
|
* **状态概览:** 卡片式布局,显示当前任务状态(待提交、AI审核中、需修改、已通过)。
|
||||||
* **行动号召 (CTA):** 针对不同状态显示醒目按钮,如 `[上传脚本]` 或 `[查看修改意见]`。
|
* **行动号召 (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]
|
### 2.2 智能上传与扫描页 (The Magic Scanner) [US-03, US-07]
|
||||||
|
|
||||||
这是达人等待 AI 结果的页面,必须缓解等待焦虑(Wait-time Anxiety)。
|
这是达人等待 AI 结果的页面,必须缓解等待焦虑(Wait-time Anxiety)。
|
||||||
@ -179,38 +136,7 @@
|
|||||||
|
|
||||||
### 2.3 审核结果反馈页 (Audit Report)
|
### 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):** 存在硬性违规,必须修改。
|
* 🔴 **未通过 (Blocked):** 存在硬性违规,必须修改。
|
||||||
@ -305,31 +231,6 @@
|
|||||||
|
|
||||||
**布局结构:**
|
**布局结构:**
|
||||||
|
|
||||||
#### 3.3.1 审核流程进度条 ⭐ F-52
|
|
||||||
|
|
||||||
**页面顶部显示当前任务的审核流程进度:**
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────────────┐
|
|
||||||
│ 审核决策台 返回列表 ← │
|
|
||||||
├─────────────────────────────────────────────────────────────────┤
|
|
||||||
│ ┌────────────────────────────────────────────────────────────┐ │
|
|
||||||
│ │ 审核流程 当前:代理商审核 │ │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ ✅已提交 ────▶ ✅AI审核 ────▶ ●代理商审核 ────▶ ○品牌终审 │ │
|
|
||||||
│ │ ↑当前阶段 │ │
|
|
||||||
│ └────────────────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ [视频播放器区域] [AI检查单区域] │
|
|
||||||
└─────────────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
**进度条显示规则:**
|
|
||||||
- 当前阶段:紫色高亮,大圆点
|
|
||||||
- 已完成阶段:绿色 ✅,显示完成时间
|
|
||||||
- 待处理阶段:灰色空心圆
|
|
||||||
- 品牌终审步骤:仅当品牌方开启终审时显示
|
|
||||||
|
|
||||||
* **左侧:视频播放器**
|
* **左侧:视频播放器**
|
||||||
* **智能进度条:** 进度条上打满 colored dots
|
* **智能进度条:** 进度条上打满 colored dots
|
||||||
* 🔴 红点:硬伤(点击跳转)
|
* 🔴 红点:硬伤(点击跳转)
|
||||||
@ -349,13 +250,11 @@
|
|||||||
|
|
||||||
* **底部:决策栏 (Action Bar)**
|
* **底部:决策栏 (Action Bar)**
|
||||||
* `[ 驳回 ]`:点击后,自动将勾选的问题打包发送给达人
|
* `[ 驳回 ]`:点击后,自动将勾选的问题打包发送给达人
|
||||||
* `[ 强制通过 ]` [US-09]:强制通过(默认可用;品牌方关闭授权时按钮改为"申请强制通过",提交后进入审批)
|
* `[ 强制通过 ]` [US-09]:强制通过(默认可用;品牌方关闭授权时按钮改为“申请强制通过”,提交后进入审批)
|
||||||
* **必须填写放行原因**(如"达人玩的新梗,品牌方认可")
|
* **必须填写放行原因**(如"达人玩的新梗,品牌方认可")
|
||||||
* 弹窗提供"**保存为特例**"可选项(**默认不勾选**,勾选后形成豁免条款,需品牌方确认后生效)
|
* 弹窗提供“**保存为特例**”可选项(**默认不勾选**,勾选后形成豁免条款,需品牌方确认后生效)
|
||||||
* **记录审批人**与操作时间,纳入审计日志
|
* **记录审批人**与操作时间,纳入审计日志
|
||||||
* `[ 通过 ]`:
|
* `[ 通过 ]`:流程结束
|
||||||
* 若品牌方**未开启终审**(默认)→ 流程结束,任务状态「已通过」
|
|
||||||
* 若品牌方**已开启终审** → 进入品牌方终审队列,任务状态「待终审」
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -461,10 +360,6 @@
|
|||||||
│ ← 返回 快捷审核 ⋮ 更多 │
|
│ ← 返回 快捷审核 ⋮ 更多 │
|
||||||
├─────────────────────────────────────────────┤
|
├─────────────────────────────────────────────┤
|
||||||
│ ┌─────────────────────────────────────┐ │
|
│ ┌─────────────────────────────────────┐ │
|
||||||
│ │ 审核流程 代理商审核中 │ │
|
|
||||||
│ │ ✅提交 ─▶ ✅AI ─▶ ●代理商 ─▶ ○终审 │ │
|
|
||||||
│ └─────────────────────────────────────┘ │
|
|
||||||
│ ┌─────────────────────────────────────┐ │
|
|
||||||
│ │ │ │
|
│ │ │ │
|
||||||
│ │ 📹 视频播放器 │ │
|
│ │ 📹 视频播放器 │ │
|
||||||
│ │ (支持横屏全屏) │ │
|
│ │ (支持横屏全屏) │ │
|
||||||
@ -629,101 +524,7 @@
|
|||||||
* **模型版本号:** AI 检测时使用的模型版本
|
* **模型版本号:** AI 检测时使用的模型版本
|
||||||
* 完整操作日志(不可篡改)
|
* 完整操作日志(不可篡改)
|
||||||
|
|
||||||
### 4.5 终审台 (Final Review) ⭐ 新增
|
### 4.5 舆情预警中心 (Brand Safety Center)
|
||||||
|
|
||||||
**入口位置:** 品牌方端侧边栏 → 终审台(仅当终审开启时显示)
|
|
||||||
**触发条件:** 品牌方在系统设置中开启「终审开关」后,代理商初审通过的内容进入此队列
|
|
||||||
|
|
||||||
#### 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 标记为"舆情风险"的视频列表
|
* 近期被 AI 标记为"舆情风险"的视频列表
|
||||||
@ -736,7 +537,7 @@
|
|||||||
* **预警规则:**
|
* **预警规则:**
|
||||||
* 配置自动通知规则(如:高风险视频自动 @品牌方)
|
* 配置自动通知规则(如:高风险视频自动 @品牌方)
|
||||||
|
|
||||||
### 4.7 AI 服务配置 (AI Configuration) 🤖
|
### 4.6 AI 服务配置 (AI Configuration) 🤖
|
||||||
|
|
||||||
**入口位置:** 系统设置 → AI 服务配置
|
**入口位置:** 系统设置 → AI 服务配置
|
||||||
**权限控制:** 仅品牌方管理员可配置,代理商和达人自动继承品牌方配置
|
**权限控制:** 仅品牌方管理员可配置,代理商和达人自动继承品牌方配置
|
||||||
@ -920,26 +721,15 @@
|
|||||||
|
|
||||||
#### 4.7.3 移动端审批中心 (Approval Center)
|
#### 4.7.3 移动端审批中心 (Approval Center)
|
||||||
|
|
||||||
**场景:**
|
**场景:** 当品牌方关闭授权时,代理商申请"强制通过",品牌方需审批。
|
||||||
1. 当品牌方关闭授权时,代理商申请"强制通过",品牌方需审批
|
|
||||||
2. **当开启品牌终审时,代理商初审通过的视频进入品牌方终审队列** ⭐ F-52
|
|
||||||
|
|
||||||
```
|
```
|
||||||
┌─────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────┐
|
||||||
│ 审批中心 待审批 │ 已处理 │
|
│ ✅ 待审批 筛选 ▼ │
|
||||||
├─────────────────────────────────────────────┤
|
├─────────────────────────────────────────────┤
|
||||||
|
│ 待处理 (3) │
|
||||||
│ ┌─────────────────────────────────────┐ │
|
│ ┌─────────────────────────────────────┐ │
|
||||||
│ │ 🟣 视频终审申请 30分钟前│ │
|
│ │ 🟡 强制通过申请 │ │
|
||||||
│ │ 达人「小美」的视频「春季护肤新品 │ │
|
|
||||||
│ │ 体验」已通过代理商审核,等待终审 │ │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ 审核流程进度: │ │
|
|
||||||
│ │ ✅提交 ─▶ ✅AI ─▶ ✅代理商 ─▶ ●终审│ │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ [ 拒绝 ] [ 通过 ] │ │
|
|
||||||
│ └─────────────────────────────────────┘ │
|
|
||||||
│ ┌─────────────────────────────────────┐ │
|
|
||||||
│ │ 🟡 强制通过申请 10分钟前│ │
|
|
||||||
│ │ 达人:@小美美 │ │
|
│ │ 达人:@小美美 │ │
|
||||||
│ │ 申请人:代理商A - 张三 │ │
|
│ │ 申请人:代理商A - 张三 │ │
|
||||||
│ │ 原因:达人玩的新梗,品牌方认可 │ │
|
│ │ 原因:达人玩的新梗,品牌方认可 │ │
|
||||||
@ -950,30 +740,18 @@
|
|||||||
│ │ │ │
|
│ │ │ │
|
||||||
│ │ [ 拒绝 ] [ 批准 ] │ │
|
│ │ [ 拒绝 ] [ 批准 ] │ │
|
||||||
│ └─────────────────────────────────────┘ │
|
│ └─────────────────────────────────────┘ │
|
||||||
│ ┌─────────────────────────────────────┐ │
|
├─────────────────────────────────────────────┤
|
||||||
│ │ 🟡 规则配置变更 2小时前 │ │
|
│ 已处理 (12) [查看 >] │
|
||||||
│ │ 代理商「星耀传媒」申请修改审核规则│ │
|
|
||||||
│ │ 竞品露出阈值调整为70% │ │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ [ 拒绝 ] [ 通过 ] │ │
|
|
||||||
│ └─────────────────────────────────────┘ │
|
|
||||||
├─────────────────────────────────────────────┤
|
├─────────────────────────────────────────────┤
|
||||||
│ 📊 🔔 ✅ 📋 👤 │
|
│ 📊 🔔 ✅ 📋 👤 │
|
||||||
└─────────────────────────────────────────────┘
|
└─────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
**视频终审审批项说明:** ⭐ F-52
|
|
||||||
* 仅当品牌方开启"终审开关"时显示此类审批项
|
|
||||||
* 显示完整审核流程进度条,品牌终审阶段高亮
|
|
||||||
* 点击可查看视频详情和代理商初审意见
|
|
||||||
* 通过/拒绝后自动通知代理商和达人
|
|
||||||
|
|
||||||
**交互说明:**
|
**交互说明:**
|
||||||
* 点击视频片段可预览关键时间点
|
* 点击视频片段可预览关键时间点
|
||||||
* 批准/拒绝需二次确认
|
* 批准/拒绝需二次确认
|
||||||
* 批准后自动通知代理商和达人
|
* 批准后自动通知代理商和达人
|
||||||
* 审批记录同步至审计日志
|
* 审批记录同步至审计日志
|
||||||
* **进度条交互:** 点击已完成节点可查看该阶段详情(处理人、时间、结果)
|
|
||||||
|
|
||||||
#### 4.7.4 移动端审计日志 (Audit Quick View)
|
#### 4.7.4 移动端审计日志 (Audit Quick View)
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
<title>秒思智能审核平台 · AI 服务配置(说明版)</title>
|
<title>SmartAudit · AI 服务配置(说明版)</title>
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--bg: #0b0c0f;
|
--bg: #0b0c0f;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,22 +0,0 @@
|
|||||||
/**
|
|
||||||
* 秒思智能审核平台组件库统一导出
|
|
||||||
* 基于 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';
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
/**
|
|
||||||
* DesktopLayout 桌面端布局组件
|
|
||||||
* 设计稿参考: UIDesignSpec.md 3.2
|
|
||||||
* 尺寸: 1440x900,侧边栏260px
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
@ -1,136 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
@ -1,104 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
@ -1,112 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
@ -1,166 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
@ -1,129 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
@ -1,90 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
@ -1,98 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
/**
|
|
||||||
* 颜色常量
|
|
||||||
* 设计稿参考: 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;
|
|
||||||
@ -1,92 +0,0 @@
|
|||||||
/**
|
|
||||||
* 图标映射常量
|
|
||||||
* 设计稿参考: 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;
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
/**
|
|
||||||
* 常量统一导出
|
|
||||||
*/
|
|
||||||
|
|
||||||
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;
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
{
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
plugins: {
|
|
||||||
tailwindcss: {},
|
|
||||||
autoprefixer: {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@ -1,434 +0,0 @@
|
|||||||
/* 秒思智能审核平台 - 全局样式文件 */
|
|
||||||
/* 基于 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);
|
|
||||||
}
|
|
||||||
@ -1,163 +0,0 @@
|
|||||||
/** @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: [],
|
|
||||||
};
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
"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"]
|
|
||||||
}
|
|
||||||
3401
pencil-new.pen
3401
pencil-new.pen
File diff suppressed because it is too large
Load Diff
@ -1,199 +0,0 @@
|
|||||||
#!/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
688
tasks.md
@ -1,9 +1,9 @@
|
|||||||
# tasks.md - 秒思智能审核平台 开发任务清单
|
# tasks.md - SmartAudit 开发任务清单
|
||||||
|
|
||||||
| 文档类型 | **Development Tasks (开发任务清单)** |
|
| 文档类型 | **Development Tasks (开发任务清单)** |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| **项目名称** | 秒思智能审核平台 (AI 营销内容合规审核平台) |
|
| **项目名称** | SmartAudit (AI 营销内容合规审核平台) |
|
||||||
| **版本号** | V1.7 |
|
| **版本号** | V1.4 |
|
||||||
| **发布日期** | 2026-02-03 |
|
| **发布日期** | 2026-02-03 |
|
||||||
| **依据文档** | PRD.md, FeatureSummary.md, DevelopmentPlan.md, UIDesign.md, User_Role_Interfaces.md, AIProviderConfig.md |
|
| **依据文档** | PRD.md, FeatureSummary.md, DevelopmentPlan.md, UIDesign.md, User_Role_Interfaces.md, AIProviderConfig.md |
|
||||||
| **总周期** | 11 周 (2.75 个月) |
|
| **总周期** | 11 周 (2.75 个月) |
|
||||||
@ -19,9 +19,6 @@
|
|||||||
| V1.2 | 2026-02-02 | Claude | Gemini 审阅优化:新增 API Mock、CI/CD、消息中心后端接口任务 |
|
| V1.2 | 2026-02-02 | Claude | Gemini 审阅优化:新增 API Mock、CI/CD、消息中心后端接口任务 |
|
||||||
| V1.3 | 2026-02-02 | Claude | 确立 TDD 为核心开发规范 |
|
| V1.3 | 2026-02-02 | Claude | 确立 TDD 为核心开发规范 |
|
||||||
| V1.4 | 2026-02-02 | Claude | 新增 AI 服务配置任务(TASK-005-D/E/F) |
|
| 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` |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -90,7 +87,7 @@
|
|||||||
|
|
||||||
| 优先级 | 功能数量 | 说明 |
|
| 优先级 | 功能数量 | 说明 |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| **P0 (MVP)** | 23 | 必须实现(含 F-51 品牌方终审开关、F-52 审核流程进度可视化) |
|
| **P0 (MVP)** | 21 | 必须实现 |
|
||||||
| **P1** | 22 | 首版后快速迭代(以 FeatureSummary 的 P1 清单为准) |
|
| **P1** | 22 | 首版后快速迭代(以 FeatureSummary 的 P1 清单为准) |
|
||||||
| **P2** | 8 | 中长期规划 |
|
| **P2** | 8 | 中长期规划 |
|
||||||
|
|
||||||
@ -152,8 +149,6 @@
|
|||||||
| F-48 | TASK-005-E |
|
| F-48 | TASK-005-E |
|
||||||
| F-49 | TASK-066 |
|
| F-49 | TASK-066 |
|
||||||
| F-50 | TASK-067 |
|
| 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 标记。
|
> 注:F-05 已拆分为 F-05-A/B,历史任务中仍可能出现 F-05 标记。
|
||||||
|
|
||||||
@ -197,7 +192,6 @@
|
|||||||
**任务描述:**
|
**任务描述:**
|
||||||
- PostgreSQL 数据库设计
|
- PostgreSQL 数据库设计
|
||||||
- 核心表创建:brands, agencies, creators, tasks, briefs, videos, reports, risk_items, rule_sets, audit_logs
|
- 核心表创建:brands, agencies, creators, tasks, briefs, videos, reports, risk_items, rule_sets, audit_logs
|
||||||
- audit_logs 增加 prev_hash/hash 字段,支持 append-only + hash chain
|
|
||||||
- 配置 pgvector 扩展(向量检索)
|
- 配置 pgvector 扩展(向量检索)
|
||||||
- 配置 Alembic 数据库迁移
|
- 配置 Alembic 数据库迁移
|
||||||
- 创建种子数据
|
- 创建种子数据
|
||||||
@ -208,7 +202,6 @@
|
|||||||
- [ ] 所有核心表创建成功
|
- [ ] 所有核心表创建成功
|
||||||
- [ ] pgvector 扩展可用
|
- [ ] pgvector 扩展可用
|
||||||
- [ ] 迁移脚本可正常执行
|
- [ ] 迁移脚本可正常执行
|
||||||
- [ ] audit_logs hash chain 字段可用
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -303,43 +296,24 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### TASK-005-C: CI/CD 流水线与 GitHub 配置
|
#### TASK-005-C: CI/CD 流水线配置
|
||||||
| 属性 | 内容 |
|
| 属性 | 内容 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| **负责人** | Backend |
|
| **负责人** | Backend |
|
||||||
| **优先级** | P0 |
|
| **优先级** | P0 |
|
||||||
| **预估工时** | 1.5d |
|
| **预估工时** | 1d |
|
||||||
| **依赖** | TASK-001, TASK-006 |
|
| **依赖** | TASK-001, TASK-006 |
|
||||||
| **功能编号** | 基础设施 |
|
| **功能编号** | 基础设施 |
|
||||||
|
|
||||||
**任务描述:**
|
**任务描述:**
|
||||||
- 配置 GitHub Actions 工作流
|
- 配置 GitLab CI / GitHub Actions
|
||||||
- `.github/workflows/frontend-test.yml` (Vitest + Playwright)
|
- 实现代码提交后自动 Lint 检查
|
||||||
- `.github/workflows/backend-test.yml` (pytest)
|
|
||||||
- 实现代码提交后自动 Lint + 测试
|
|
||||||
- **配置 Codecov 覆盖率报告**(见下方步骤)
|
|
||||||
- 实现 Docker 镜像自动构建
|
- 实现 Docker 镜像自动构建
|
||||||
- 配置 Dev 环境自动部署
|
- 配置 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/测试错误阻断 PR 合并
|
- [ ] Lint 错误阻断合并
|
||||||
- [ ] **Codecov 覆盖率报告正常上传**(验证:https://codecov.io/gh/{owner}/{repo})
|
|
||||||
- [ ] **分支保护规则已生效**(验证:`gh api repos/{owner}/{repo}/branches/main/protection`)
|
|
||||||
- [ ] 直接 push 到 main 被拒绝
|
|
||||||
- [ ] Dev 环境自动更新
|
- [ ] Dev 环境自动更新
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -1435,203 +1409,6 @@ gh secret set CODECOV_TOKEN --body "<your-codecov-token>"
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 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 响应式设计与无障碍
|
### 4.7 响应式设计与无障碍
|
||||||
|
|
||||||
> 规范参考:User_Role_Interfaces.md 第 7-8 章
|
> 规范参考:User_Role_Interfaces.md 第 7-8 章
|
||||||
@ -1959,11 +1736,6 @@ CREATE TABLE review_stage_logs (
|
|||||||
**任务描述:**
|
**任务描述:**
|
||||||
- 实现审核记录查询
|
- 实现审核记录查询
|
||||||
- 实现完整审核链路查看
|
- 实现完整审核链路查看
|
||||||
- 审计日志采用 append-only + hash chain(前序哈希 + 当前内容),禁止更新/删除
|
|
||||||
|
|
||||||
**验收标准:**
|
|
||||||
- [ ] 审计日志链式校验通过
|
|
||||||
- [ ] 不支持对历史审计日志的更新/删除
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -2258,443 +2030,7 @@ graph TD
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 10. UI 开发任务 (关联设计稿)
|
## 10. 相关文档
|
||||||
|
|
||||||
> **重要说明:本章节的 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. 相关文档
|
|
||||||
|
|
||||||
| 文档 | 说明 |
|
| 文档 | 说明 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
@ -2702,7 +2038,5 @@ graph TD
|
|||||||
| FeatureSummary.md | 功能清单与优先级 |
|
| FeatureSummary.md | 功能清单与优先级 |
|
||||||
| DevelopmentPlan.md | 开发计划与技术架构 |
|
| DevelopmentPlan.md | 开发计划与技术架构 |
|
||||||
| UIDesign.md | UI 设计规范 |
|
| UIDesign.md | UI 设计规范 |
|
||||||
| UIDesignSpec.md | UI 设计规范(详细版) |
|
|
||||||
| User_Role_Interfaces.md | 用户角色与界面规范 |
|
| User_Role_Interfaces.md | 用户角色与界面规范 |
|
||||||
| AIProviderConfig.md | AI 服务配置架构设计 |
|
| AIProviderConfig.md | AI 服务配置架构设计 |
|
||||||
| pencil-new.pen | 设计稿文件(Pencil 格式) |
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user