# 用户反馈系统 - UI 交互规范

> **版本**: v1.0.2  
> **最后更新**: 2026-01-06  
> **维护者**: 前端团队

> **参考标准**: [设计系统（权威）](../../../.agents/skills/frontend-main/references/design-system-standards.md)

---

## 📄 页面清单

> 说明：前端页面已实现，本规范用于对齐交互与测试。

| 页面 | 路由 | 说明 | 状态 |
|------|------|------|------|
| 反馈入口 | 全局悬浮按钮 | 反馈提交入口 | ✅ |
| 我的反馈列表 | `/feedback` | 用户反馈列表 | ✅ |
| 管理端列表 | `/settings/feedback` | 反馈管理列表 | ✅ |
| 管理端详情 | `/settings/feedback/:id` | 反馈管理详情 | ✅ |

---

## 🧭 全局组件: 反馈入口（悬浮按钮 + 弹窗）

### 基本信息

- **组件**: `FeedbackButton` + `FeedbackModal`
- **触发范围**: 全站可见
- **权限要求**: 登录用户

### 元素清单

| 元素名称 | 选择器 | 类型 | 必填 | 说明 |
|---------|--------|------|------|------|
| 悬浮按钮 | `[data-testid="feedback-fab"]` | 按钮 | - | 右下角悬浮 |
| 弹窗容器 | `[data-testid="feedback-modal"]` | 弹窗 | - | 提交反馈表单 |
| 类型选择 | `[data-field="type"]` | 单选/下拉 | ✅ | BUG/FEATURE/IMPROVEMENT/OTHER |
| 标题输入 | `input[name="title"]` | 输入框 | ✅ | 1-200 字符 |
| 内容输入 | `textarea[name="content"]` | 文本域 | ✅ | 1-5000 字符 |
| 附件 URL | `[data-field="attachments"]` | 输入组件 | ❌ | 最多 5 个 URL |
| 取消按钮 | `button[data-action="cancel"]` | 按钮 | - | 关闭弹窗 |
| 提交按钮 | `button[data-action="submit"]` | 按钮 | - | 提交反馈 |

### 交互行为

#### 1. 打开反馈弹窗

**触发**: 点击悬浮按钮

**前端行为**:
1. 打开弹窗
2. 初始化表单状态

**显示规则**:
- 未登录：隐藏入口或提示登录
- 已登录：正常展示

---

#### 2. 表单提交

**触发**: 点击提交按钮

**前端行为**:
1. 校验表单
2. 调用 API：`POST /feedbacks`
3. 成功后关闭弹窗并提示成功
4. 失败时显示错误信息，弹窗保持打开

**按钮状态**:
- 提交中：按钮禁用并显示 Loading
- 验证失败：按钮可用

**错误提示规则**:
- 字段校验错误：高亮字段并显示提示
- 业务错误：弹出错误提示

---

## 🖥️ 页面 1: 我的反馈列表

### 基本信息

- **页面标题**: 我的反馈
- **URL**: `/feedback`
- **权限要求**: 登录用户
- **布局模式**: 标准列表页

### 页面元素清单

| 元素名称 | 选择器 | 类型 | 必填 | 说明 |
|---------|--------|------|------|------|
| 页面标题 | `[data-testid="page-title"]` | 文本 | - | 显示“我的反馈” |
| 状态筛选 | `select[name="status"]` | 下拉框 | ❌ | PENDING/IN_PROGRESS/RESOLVED/CLOSED |
| 类型筛选 | `select[name="type"]` | 下拉框 | ❌ | BUG/FEATURE/IMPROVEMENT/OTHER |
| 数据表格 | `[data-testid="feedback-table"]` | 表格 | - | 显示反馈列表 |
| 分页器 | `[data-testid="pagination"]` | 分页 | - | 分页控制 |
| 加载状态 | `[data-testid="loading"]` | 容器 | - | 列表加载中 |
| 空状态 | `[data-testid="empty-state"]` | 容器 | - | 无数据提示 |

### 表格列定义

| 列名 | 字段名 | 类型 | 说明 |
|------|--------|------|------|
| 标题 | `title` | 文本 | 反馈标题 |
| 类型 | `type` | 徽章 | 反馈类型 |
| 状态 | `status` | 徽章 | 当前状态 |
| 提交时间 | `createdAt` | 文本 | 时间格式化 |
| 操作 | - | 按钮 | 查看详情 |

### 交互行为

#### 1. 页面加载

**前端行为**:
1. 调用 `GET /feedbacks/my`
2. 渲染列表

**显示规则**:
- 无数据：展示空状态
- 请求失败：展示错误提示

---

#### 2. 查看详情

**触发**: 点击“查看”

**前端行为**:
1. 调用 `GET /feedbacks/my/:id`
2. 展示详情（详情页或弹窗）

---

## 🖥️ 页面 2: 管理端列表

### 基本信息

- **页面标题**: 反馈管理
- **URL**: `/settings/feedback`
- **权限要求**: `feedback:read`
- **布局模式**: 标准列表页

### 页面元素清单

| 元素名称 | 选择器 | 类型 | 必填 | 说明 |
|---------|--------|------|------|------|
| 搜索框 | `input[name="keyword"]` | 输入框 | ❌ | 标题/内容模糊搜索 |
| 状态筛选 | `select[name="status"]` | 下拉框 | ❌ | 状态筛选 |
| 类型筛选 | `select[name="type"]` | 下拉框 | ❌ | 类型筛选 |
| 区域筛选 | `select[name="region"]` | 下拉框 | ❌ | 仅全局管理员可见 |
| 数据表格容器 | `[data-testid="admin-feedback-table"]` | 容器 | - | 反馈列表容器 |
| 数据表格 | `[data-testid="feedback-table"]` | 表格 | - | 反馈列表表格 |
| 批量操作 | `[data-testid="batch-actions"]` | 按钮组 | ❌ | 批量更新状态 |
| 加载状态 | `[data-testid="loading"]` | 容器 | - | 列表加载中 |
| 空状态 | `[data-testid="empty-state"]` | 容器 | - | 无数据提示 |
| 分页器 | `[data-testid="pagination"]` | 分页 | - | 分页控制 |

### 交互行为

#### 1. 页面加载

**前端行为**:
1. 调用 `GET /feedbacks`
2. 列表展示

**显示规则**:
- 区域管理员默认仅看到本区域数据
- 全局管理员可选择区域筛选

---

#### 2. 批量关闭

**触发**: 选择多条记录并点击批量关闭

**前端行为**:
1. 调用 `POST /feedbacks/batch-status`
2. 展示成功/失败统计

**错误规则**:
- 超过 100 条时前端提示并阻止提交

---

## 🖥️ 页面 3: 管理端详情

### 基本信息

- **页面标题**: 反馈详情
- **URL**: `/settings/feedback/:id`
- **权限要求**: `feedback:read`
- **布局模式**: 详情页

### 页面元素清单

| 元素名称 | 选择器 | 类型 | 说明 |
|---------|--------|------|------|
| 状态徽章 | `[data-field="status"]` | 徽章 | 状态显示 |
| 管理员备注 | `textarea[name="adminNote"]` | 文本域 | 内部备注 |
| 管理员回复 | `textarea[name="adminReply"]` | 文本域 | 对用户可见 |
| 优先级选择 | `select[name="priority"]` | 下拉框 | 优先级 |
| 指派处理人 | `select[name="assigneeId"]` | 下拉框 | 处理人 |
| 更新按钮 | `button[data-action="save"]` | 按钮 | 保存更新 |
| 状态变更 | `button[data-action="status"]` | 按钮 | 状态更新 |
| 详情卡片 | `[data-testid="detail-card"]` | 卡片 | 详情内容容器 |
| 加载状态 | `[data-testid="loading"]` | 容器 | 详情加载中 |
| 空状态 | `[data-testid="empty-state"]` | 容器 | 详情不存在 |

### 交互行为

#### 1. 页面加载

**前端行为**:
1. 调用 `GET /feedbacks/:id`
2. 展示完整字段（含 pageUrl、userAgent）

---

#### 2. 更新反馈信息

**触发**: 点击保存

**前端行为**:
1. 调用 `PATCH /feedbacks/:id`
2. 成功后展示提示并刷新详情

---

#### 3. 更新状态

**触发**: 点击状态按钮

**前端行为**:
1. 调用 `PATCH /feedbacks/:id/status`
2. 成功后更新状态徽章

**失败处理**:
- 无效流转：提示错误并保持弹窗/页面

---

## 🎨 通用样式规范

- 颜色与组件样式遵循设计系统规范
- 表格统一使用原生 `<table>`
- 状态徽章颜色与状态机保持一致

---

## 🔗 相关文档

- [设计系统（权威）](../../../.agents/skills/frontend-main/references/design-system-standards.md)
- [API 文档](./07-api.md)
- [状态机](./04-state-machine.md)
- [测试场景](./09-test-scenarios.md)
- [E2E 测试规范](./10-e2e-test-spec.md)

---

**最后更新**: 2026-01-06  
**版本**: v1.0.2  
**维护者**: 前端团队
