前端项目初始化提交

This commit is contained in:
2026-06-03 13:16:30 +08:00
commit 0910ba9cbe
163 changed files with 110032 additions and 0 deletions

View File

@@ -0,0 +1,745 @@
# 题目管理系统设计方案
**日期**: 2026-05-16
**基于**: 前端优化方案与设计规范.md
**模式**: 集成式设计(生成→待审核列表→操作)
---
## 一、系统架构
### 1.1 数据流图
```
[用户操作]
[GeneratePanel.vue]
├─ 配置区域 (文件选择/题型/难度)
├─ 生成按钮 → POST /api/exam/generate
[待审核列表区域]
├─ 初始化: GET /api/question/pending (自动加载)
├─ 搜索/筛选
├─ 题目卡片展示
│ ├─ 审批: PUT /api/question/review/{id}
│ ├─ 编辑: PUT /api/question/{id}
│ └─ 发布: PUT /api/question/review/{id} (status=published)
└─ 批量操作
```
### 1.2 状态管理
```javascript
// useQuestionManagement.js (新增composable)
const state = reactive({
// 生成相关
isGenerating: false,
generatedCount: 0,
// 列表相关
pendingQuestions: [], // 待审核题目列表
loading: false,
total: 0,
currentPage: 1,
pageSize: 10,
// 筛选条件
searchKeyword: '',
statusFilter: 'all', // all/pending/approved/rejected/published
typeFilter: 'all', // all/single_choice/multiple_choice/...
// 编辑状态
editingQuestion: null, // 当前编辑的题目
showEditModal: false,
// 批量操作
selectedIds: [], // 选中的题目ID
})
```
### 1.3 接口调用规划
| 功能 | 方法 | 接口 | 触发时机 |
|------|------|------|---------|
| **生成题目** | `POST` | `/api/exam/generate` | 点击"开始生成"按钮 |
| **获取待审核列表** | `GET` | `/api/question/pending` | 页面加载/生成完成/刷新 |
| **搜索题目** | `GET` | `/api/question/pending?keyword=xxx` | 输入搜索关键词 |
| **筛选题目** | `GET` | `/api/question/pending?status=xxx&type=xxx` | 选择筛选条件 |
| **审批通过** | `PUT` | `/api/question/review/{id}?status=approved` | 点击"通过"按钮 |
| **驳回题目** | `PUT` | `/api/question/review/{id}?status=rejected&comment=xxx` | 点击"驳回"+填写原因 |
| **编辑题目** | `PUT` | `/api/question/{id}` | 点击"编辑"→修改→保存 |
| **发布题目** | `PUT` | `/api/question/review/{id}?status=published` | 点击"发布"按钮 |
| **批量审批** | `PUT` | `/api/question/batch-review` | 选择多条→批量操作 |
| **删除题目** | `DELETE` | `/api/question/{id}` | 点击"删除" |
---
## 二、UI组件设计遵循设计规范
### 2.1 组件结构树
```
GeneratePanel.vue (主容器)
├── PageHeader.vue (标题栏)
├── StatsRow.vue (统计信息)
├── ContentCard: "智能出题配置"
│ ├── FileSelector (文件选择器)
│ ├── DifficultySelect (难度选择)
│ ├── TypeConfigGrid (题型数量配置)
│ └── GenerateButton (生成按钮)
├── ContentCard: "待审核题目管理"
│ ├── Toolbar (工具栏)
│ │ ├── SearchInput (搜索框)
│ │ ├── StatusFilter (状态筛选)
│ │ ├── TypeFilter (题型筛选)
│ │ └── BatchActions (批量操作按钮组)
│ ├── QuestionList (题目列表)
│ │ └── QuestionCard (题目卡片) *N
│ │ ├── QuestionHeader (题号+类型+状态)
│ │ ├── QuestionContent (题干内容)
│ │ ├── QuestionOptions (选项展示)
│ │ └── ActionButtons (操作按钮组)
│ └── Pagination (分页器)
└── EditModal.vue (编辑弹窗) [可选]
```
### 2.2 题目卡片设计QuestionCard
#### 视觉规范
```css
/* 白色体系 + 设计规范 */
.question-card {
background: #FFFFFF;
border: 1px solid #E9ECEF; /* --border-light */
border-radius: 8px; /* --radius-lg */
box-shadow: 0 1px 2px rgba(0,0,0,0.04); /* --shadow-sm */
padding: 16px; /* --space-lg */
margin-bottom: 12px; /* --space-md */
transition: all 0.15s ease; /* --transition-fast */
}
.question-card:hover {
border-color: #DEE2E6; /* --border-default */
box-shadow: 0 2px 8px rgba(0,0,0,0.06); /* --shadow-md */
}
```
#### 卡片内容布局
```
┌─────────────────────────────────────────────────────┐
│ [☑] 第1题 [单选题] [待审核] 中等难度 │ ← Header
├─────────────────────────────────────────────────────┤
│ 在按价位段自选投放工作指引中,用于评估样本零售客户 │ ← Content
│ 库存水平与销售速度匹配程度的核心公式是? │
│ │
│ A. 客户实际订货数量/订货客户订单提报需求数量*100% │ ← Options
│ B. 样本零售客户期末库存/月销量 │
│ C. 实际零售价格/零售指导价格*100% │
│ D. 特定聚类内市场状态结果按销量加权平均 │
│ │
│ [✓ 通过] [✗ 驳回] [✎ 编辑] [📤 发布] [🗑️ 删除] │ ← Actions
└─────────────────────────────────────────────────────┘
```
#### 状态徽章设计
```css
/* 状态标识 - 仅使用功能色 */
.status-badge {
display: inline-flex;
align-items: center;
padding: 2px 8px;
border-radius: 4px; /* --radius-sm */
font-size: 12px; /* --font-sm */
font-weight: 500; /* --weight-medium */
}
.status-pending {
background: #FFF9DB; /* --bg-warning */
color: #E67700; /* --color-warning */
border: 1px solid #FFE066;
}
.status-approved {
background: #EBFBEE; /* --bg-success */
color: #2B8A3E; /* --color-success */
border: 1px solid #B2F2BB;
}
.status-rejected {
background: #FFF5F5; /* --bg-error */
color: #C92A2A; /* --color-error */
border: 1px solid #FFC9C9;
}
.status-published {
background: #E7F5FF; /* --bg-info */
color: #1C7ED6; /* --color-info */
border: 1px solid #A5D8FF;
}
```
### 2.3 操作按钮设计
```css
/* 按钮组 - 遵循设计规范 5.3 */
.action-buttons {
display: flex;
gap: 6px; /* --space-xs + 2px */
margin-top: 12px; /* --space-md */
padding-top: 12px;
border-top: 1px solid #E9ECEF; /* --border-light */
}
.btn-action {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 4px 12px; /* 紧凑尺寸 */
border-radius: 6px; /* --radius-md */
font-size: 12px; /* --font-sm */
font-weight: 500;
cursor: pointer;
transition: all 0.15s ease;
border: 1px solid transparent;
}
.btn-approve {
background: #EBFBEE; /* 浅绿底 */
color: #2B8A3E; /* 绿色文字 */
border-color: #B2F2BB;
}
.btn-approve:hover {
background: #D3F9D8;
}
.btn-reject {
background: #FFF5F5; /* 浅红底 */
color: #C92A2A; /* 红色文字 */
border-color: #FFC9C9;
}
.btn-reject:hover {
background: #FFE3E3;
}
.btn-edit {
background: #FFFFFF;
color: #495057; /* --text-secondary */
border-color: #DEE2E6; /* --border-default */
}
.btn-edit:hover {
background: #F8F9FA; /* --bg-container */
border-color: #ADB5BD;
}
.btn-publish {
background: #E7F5FF; /* 浅蓝底 */
color: #1C7ED6; /* 蓝色文字 */
border-color: #A5D8FF;
}
.btn-publish:hover {
background: #D0EBFF;
}
.btn-delete {
background: #FFFFFF;
color: #C92A2A; /* 红色文字 */
border-color: #FFC9C9;
}
.btn-delete:hover {
background: #FFF5F5;
}
```
### 2.4 工具栏设计Toolbar
```
┌─────────────────────────────────────────────────────┐
│ 🔍 搜索题目... [状态: 全部 ▼] [题型: 全部 ▼] │
│ [✓ 批量通过] [✗ 批量驳回] [刷新] │
└─────────────────────────────────────────────────────┘
```
```css
.toolbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
background: #F8F9FA; /* --bg-container */
border: 1px solid #E9ECEF;
border-radius: 8px; /* --radius-lg */
margin-bottom: 16px; /* --space-lg */
}
.search-input {
flex: 1;
max-width: 320px;
height: 36px; /* 表单规范 */
padding: 6px 12px;
border: 1px solid #DEE2E6;
border-radius: 6px;
font-size: 13px; /* --font-md */
}
.filter-select {
height: 36px;
padding: 6px 12px;
border: 1px solid #DEE2E6;
border-radius: 6px;
font-size: 13px;
margin-left: 8px;
}
```
---
## 三、交互流程设计
### 3.1 生成题目流程
```
1. 用户配置参数(文件/题型/难度)
2. 点击"开始生成"按钮
3. 显示loading状态 + 进度提示
4. 调用 POST /api/exam/generate
5. 轮询检查生成状态(已有逻辑)
6. 生成完成后:
- 显示成功提示:"成功生成 X 道题目"
- 自动调用 GET /api/question/pending 刷新列表
- 滚动到待审核列表区域
7. 展示待审核题目列表
```
### 3.2 审批流程
```
单个审批:
1. 用户点击"通过"/"驳回"按钮
2. 弹出确认对话框(驳回时需要填写原因)
3. 调用 PUT /api/question/review/{id}?status=approved/rejected
4. 更新本地状态(乐观更新)
5. 刷新列表数据
批量审批:
1. 用户勾选多个题目复选框
2. 点击"批量通过"/"批量驳回"
3. 弹出确认对话框
4. 循环调用单个接口 或 调用批量接口
5. 刷新列表
```
### 3.3 编辑流程
```
方式1内联编辑推荐简单字段
1. 点击"编辑"按钮
2. 题目卡片变为编辑模式
3. 直接修改题干/选项
4. 点击"保存"/"取消"
方式2弹窗编辑推荐复杂编辑
1. 点击"编辑"按钮
2. 打开 EditModal 弹窗
3. 完整的表单编辑界面
4. 点击"保存"/"取消"
```
---
## 四、响应式与滚动策略
### 4.1 布局原则(解决之前的滚动问题)
```css
/* 主容器 - 允许自然流动,不限制高度 */
.generate-panel {
display: flex;
flex-direction: column;
min-height: 0; /* 允许收缩 */
/* 移除 height: 100% 和 overflow: hidden */
}
/* 配置面板 - 固定不滚动 */
.config-panel {
flex-shrink: 0; /* 不压缩 */
margin-bottom: 16px;
}
/* 结果面板 - 内容可撑开 */
.result-panel {
flex: 1;
display: flex;
flex-direction: column;
/* 不设置 max-height 或 overflow */
}
/* 题目列表 - 自然流动 */
.question-list {
display: flex;
flex-direction: column;
gap: 12px;
/* 不设置 overflow-y: auto */
}
```
**效果**
- ✅ 配置区域固定在顶部
- ✅ 题目列表随内容自然增长
- ✅ 当内容超出视口时,整个页面可滚动
- ✅ 无局部滚动条
### 4.2 分页策略
当题目数量较多时(>20道使用分页
```javascript
const pagination = reactive({
current: 1,
pageSize: 10, // 每页10道
total: 0,
showSizeChanger: true,
showQuickJumper: true,
pageSizeOptions: ['10', '20', '50'],
})
// 分页变化时重新请求
const handlePageChange = async (page, size) => {
pagination.current = page
pagination.pageSize = size
await fetchPendingQuestions()
}
```
---
## 五、错误处理与边界情况
### 5.1 错误处理
| 场景 | 处理方式 |
|------|---------|
| 生成失败 | 显示错误消息,保留配置不变 |
| 网络超时 | 提供重试按钮 |
| 审批接口失败 | 回滚到之前状态,显示错误 |
| 并发冲突 | 提示"数据已被其他人修改",刷新列表 |
| 权限不足 | 显示"无权限操作",隐藏操作按钮 |
### 5.2 空状态处理
```html
<!-- 无待审核题目 -->
<div class="empty-state">
<div class="empty-icon">📋</div>
<p class="empty-title">暂无需审核的题目</p>
<p class="empty-hint">
您可以:<br/>
• 使用上方配置生成新题目<br/>
• 所有题目已审核完毕 ✨
</p>
</div>
```
### 5.3 加载状态
```html
<!-- 加载中 -->
<div class="loading-state">
<a-spin size="large" />
<p>正在加载待审核题目...</p>
</div>
<!-- 生成中 -->
<div class="generating-state">
<a-spin tip="AI正在生成题目请耐心等待..." />
<progress :percent="generateProgress" />
</div>
```
---
## 六、实施计划
### Phase 1: 核心功能优先级P0
**目标**:实现基本的生成+展示+审批流程
1. **修改 useGenerateState.js**
- ✅ 修复接口调用:生成后调用 `/question/pending`
- ✅ 添加 `question_count` 参数
- ✅ 保留现有的轮询逻辑
2. **创建 useQuestionManagement.js**
- 实现 `fetchPendingQuestions()`
- 实现 `approveQuestion(id)`
- 实现 `rejectQuestion(id, comment)`
- 实现搜索/筛选逻辑
3. **重构 GeneratePanel.vue**
- 添加工具栏(搜索/筛选)
- 重构题目列表为卡片式
- 添加操作按钮组
- 实现分页功能
### Phase 2: 编辑功能优先级P1
4. **创建 EditModal.vue**
- 题干编辑器
- 选项编辑器(动态增删)
- 答案设置
- 表单验证
5. **集成编辑功能**
- 调用 `PUT /question/{id}`
- 保存后刷新列表
### Phase 3: 批量操作优先级P2
6. **实现批量选择**
- 复选框
- 全选/反选
- 批量审批接口
### Phase 4: 体验优化优先级P3
7. **性能优化**
- 虚拟滚动(大量题目时)
- 防抖搜索
- 缓存策略
8. **视觉优化**
- 动画过渡
- 拖拽排序
- 快捷键支持
---
## 七、技术要点
### 7.1 关键代码示例
#### 获取待审核题目
```javascript
// useQuestionManagement.js
const fetchPendingQuestions = async () => {
loading.value = true
try {
const params = {
page: pagination.current,
pageSize: pagination.pageSize,
}
if (searchKeyword.value) {
params.keyword = searchKeyword.value
}
if (statusFilter.value !== 'all') {
params.status = statusFilter.value
}
if (typeFilter.value !== 'all') {
params.type = typeFilter.value
}
const res = await questionAPI.getPendingQuestions(params)
pendingQuestions.value = transformQuestionData(res.data?.records || [])
pagination.total = res.data?.total || 0
console.log(`✅ 获取待审核题目: ${pendingQuestions.value.length}`)
} catch (error) {
console.error('❌ 获取待审核题目失败:', error)
message.error('加载题目列表失败')
} finally {
loading.value = false
}
}
```
#### 审批操作
```javascript
const approveQuestion = async (questionId) => {
try {
await questionAPI.reviewQuestion(questionId, 'approved')
message.success('审批通过 ✓')
// 乐观更新立即更新UI
const index = pendingQuestions.value.findIndex(q => q.id === questionId)
if (index !== -1) {
pendingQuestions.value[index].status = 'approved'
}
// 可选:延迟刷新确保数据一致性
setTimeout(() => fetchPendingQuestions(), 500)
} catch (error) {
console.error('❌ 审批失败:', error)
message.error('审批操作失败,请重试')
// 回滚:重新获取数据
await fetchPendingQuestions()
}
}
const rejectQuestion = async (questionId, comment) => {
try {
await questionAPI.reviewQuestion(questionId, 'rejected', comment)
message.success('已驳回')
// 更新本地状态
const index = pendingQuestions.value.findIndex(q => q.id === questionId)
if (index !== -1) {
pendingQuestions.value[index].status = 'rejected'
}
setTimeout(() => fetchPendingQuestions(), 500)
} catch (error) {
message.error('驳回操作失败')
await fetchPendingQuestions()
}
}
```
### 7.2 数据转换函数(复用)
```javascript
// 与 useGenerateState.js 保持一致
const transformQuestionData = (rawQuestions) => {
return rawQuestions.map((q, qIdx) => {
let contentObj = {}
try {
if (typeof q.content === 'string' && q.content.startsWith('{')) {
contentObj = JSON.parse(q.content || '{}')
} else if (typeof q.content === 'object') {
contentObj = q.content
}
} catch (e) {
console.warn(`题目${qIdx} content解析失败:`, e.message)
}
return {
id: q.id,
questionId: q.questionId,
type: String(q.questionType || q.type || '').toLowerCase(),
typeLabel: formatQuestionType(q.questionType),
difficulty: q.difficulty || 2,
score: Number(q.score) || 5,
stem: contentObj.stem || q.stem || (typeof q.content === 'string' ? q.content : ''),
options: formatOptions(contentObj.options || q.options || []),
answer: q.answer || contentObj.answer || '',
status: q.status || 'pending',
reviewerComment: q.reviewerComment || '',
createdAt: q.createdAt,
updatedAt: q.updatedAt,
}
})
}
```
---
## 八、测试场景
### 8.1 功能测试
- [ ] 生成5道题目验证列表显示正确
- [ ] 搜索题目,验证过滤结果准确
- [ ] 按状态筛选(待审核/已通过/已驳回/已发布)
- [ ] 单个审批通过/驳回
- [ ] 批量审批多道题目
- [ ] 编辑题目并保存
- [ ] 发布已通过的题目
- [ ] 删除题目(带确认)
- [ ] 分页切换第1页/第2页/每页20条
### 8.2 边界测试
- [ ] 生成了0道题目空状态显示
- [ ] 生成了100道题目性能测试
- [ ] 同时点击多次生成(防重复提交)
- [ ] 网络断开时的错误处理
- [ ] 权限不足时的UI反馈
### 8.3 UI/UX测试
- [ ] 页面滚动流畅(无局部滚动条)
- [ ] 按钮hover效果正常
- [ ] 加载动画显示正确
- [ ] 响应式布局适配不同屏幕
- [ ] 空状态提示友好
---
## 九、成功标准
### 9.1 功能完整性
✅ 用户可以完整执行以下流程:
1. 选择文件 → 配置参数 → 生成题目
2. 查看待审核题目列表
3. 对每道题目进行审批/编辑/发布
4. 搜索、筛选、分页浏览
### 9.2 用户体验
✅ 符合设计规范:
- 白色体系配色
- 紧凑但清晰的布局
- 一致的组件样式
- 流畅的交互动画
- 友好的错误提示
### 9.3 技术质量
✅ 代码质量:
- 无语法错误
- 接口调用正确
- 状态管理清晰
- 错误处理完善
- 性能可接受
---
## 十、后续扩展方向
1. **题目版本管理**:记录每次编辑的历史版本
2. **批量导入导出**支持Excel格式导入/导出题目
3. **AI辅助审核**AI自动预审人工复核
4. **统计分析**:题目通过率、平均审核时间等
5. **权限细化**:角色权限(管理员/审核员/出题人)
6. **移动端适配**:响应式布局优化手机端体验
---
**文档版本**: v1.0
**最后更新**: 2026-05-16
**状态**: 待用户确认