# GeneratePanel 布局重构实施计划

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** 重构GeneratePanel组件为顶底主从式布局，解决内容截断问题并优化用户体验

**Architecture:** 采用Flexbox垂直布局，配置面板（flex-shrink: 0）固定在顶部，结果展示区（flex: 1）自适应填充剩余空间并独立滚动。表单内部使用CSS Grid双列布局提高信息密度。

**Tech Stack:** Vue 3 (Composition API), CSS Grid, Flexbox, Scoped Styles

---

## 文件结构

### 需要修改的文件:
- **Modify:** `src/components/exam/GeneratePanel.vue` - 主要重构目标
  - Template部分：重新组织DOM结构，分离配置区和结果区
  - Script部分：无需改动（保持现有逻辑）
  - Style部分：完全重写布局样式

---

### Task 1: 重构GeneratePanel容器布局 - 实现顶底主从式结构

**Files:**
- Modify: `src/components/exam/GeneratePanel.vue` (Template + Style)

- [ ] **Step 1: 重新组织Template结构**

将现有的两个ContentCard包裹在语义化的容器中：

```vue
<template>
  <div class="generate-panel">
    <!-- 页面头部和统计（保持不变） -->
    <PageHeader
      title="AI智能出题系统"
      description="基于AI技术自动生成高质量试题"
    />
    <StatsRow :stats="examTypeStats" />

    <!-- 新增：配置面板容器 -->
    <div class="config-panel">
      <ContentCard title="智能出题配置">
        <template #header>
          <h2 class="card-title">
            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
              <rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>
              <line x1="8" y1="21" x2="16" y2="21"></line>
              <line x1="12" y1="17" x2="12" y2="21"></line>
            </svg>
            智能出题配置
          </h2>
        </template>
        
        <!-- 表单内容将在Task 2中优化 -->
        <div class="form-content">
          <!-- 现有表单代码保持不变 -->
          <div class="form-item">...</div>
          <div class="form-item">...</div>
          <div class="form-item">...</div>
          <div class="action-bar">...</div>
        </div>
      </ContentCard>
    </div>

    <!-- 新增：结果展示区容器 -->
    <div class="result-panel">
      <ContentCard title="待审核题目列表">
        <div v-if="isGenerating" class="loading-state">...</div>
        
        <div v-else-if="generatedQuestions.length === 0" class="empty-state">...</div>
        
        <div v-else class="question-list">
          <!-- 现有题目列表代码保持不变 -->
        </div>
      </ContentCard>
    </div>
  </div>
</template>
```

- [ ] **Step 2: 重写容器级CSS样式**

```css
.generate-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
  padding: 16px;
  overflow: hidden; /* 外层不滚动 */
}

/* 配置面板 - 固定高度，不压缩 */
.config-panel {
  flex-shrink: 0;
  margin-bottom: 12px;
}

/* 结果展示区 - 自适应填充剩余空间 */
.result-panel {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.result-panel :deep(.content-card) {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.result-panel :deep(.card-body) {
  flex: 1;
  overflow-y: auto; /* 内容独立滚动 */
}
```

- [ ] **Step 3: 验证基础布局结构**

刷新浏览器，确认：
- ✅ 配置面板显示在顶部且完整可见
- ✅ 结果展示区占据下方所有剩余空间
- ✅ 整体无滚动条（除了结果区的内部滚动）

---

### Task 2: 优化配置表单为双列Grid布局 - 提高信息密度

**Files:**
- Modify: `src/components/exam/GeneratePanel.vue` (Template中的.form-content部分)

- [ ] **Step 1: 将表单项重组为Grid布局**

替换`.form-content`内部的HTML结构：

```vue
<div class="form-content">
  <!-- 文件选择器 - 跨两列 -->
  <div class="form-item form-item--full">
    <label class="form-label">选择制度文件 <span class="required-mark">*</span></label>
    <FileSelector 
      v-model="selectedDoc" 
      @change="onDocSelected" 
      @collection-change="onCollectionChange"
      placeholder="先选择知识库，再选择制度文件..." 
    />
    <div v-if="selectedCollectionName" class="collection-info">
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
        <path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"></path>
        <path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"></path>
      </svg>
      <span>当前知识库: <strong>{{ selectedCollectionName }}</strong></span>
    </div>
    <div v-if="selectedDocData" class="selected-file-info">
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
        <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
        <polyline points="14 2 14 8 20 8"></polyline>
      </svg>
      <span>{{ selectedDocData.title || selectedDocData.rawFileName }}</span>
      <span>v{{ selectedDocData.version }}</span>
    </div>
  </div>

  <!-- 难度等级 + 总计题数 - 并排显示 -->
  <div class="form-item">
    <label class="form-label">难度等级</label>
    <select v-model="difficulty" class="form-select">
      <option :value="1">简单</option>
      <option :value="2">中等</option>
      <option :value="3">困难</option>
    </select>
  </div>

  <div class="form-item form-item--total">
    <label class="form-label">总计题数</label>
    <div class="total-display">
      <strong>{{ totalQuestionCount }}</strong> 题
    </div>
  </div>

  <!-- 题型与数量配置 - 跨两列 -->
  <div class="form-item form-item--full">
    <label class="form-label">题型与数量配置</label>
    <div class="type-count-grid">
      <div class="type-count-item" v-for="qt in questionTypeOptions" :key="qt.value">
        <label class="checkbox-label" :class="{ active: questionTypeCounts[qt.value] > 0 }">
          <input type="checkbox" :checked="questionTypeCounts[qt.value] > 0" @change="toggleQuestionType(qt.value)" />
          {{ qt.label }}
        </label>
        <input 
          type="number" 
          v-model.number="questionTypeCounts[qt.value]" 
          min="0" 
          max="50" 
          class="form-input-sm"
          :disabled="questionTypeCounts[qt.value] <= 0"
          placeholder="0"
        />
      </div>
    </div>
  </div>

  <!-- 操作按钮 - 跨两列，右对齐 -->
  <div class="action-bar">
    <button class="btn btn-primary" @click="handleGenerateQuestions" :disabled="isGenerating">
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
        <path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z"></path>
        <path d="m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z"></path>
      </svg>
      {{ isGenerating ? '生成中...' : '开始生成题目' }}
    </button>
    <button class="btn btn-secondary" @click="generatedQuestions = []">
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
        <polyline points="3 6 5 6 21 6"></polyline>
        <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
      </svg>
      清空结果
    </button>
  </div>
</div>
```

- [ ] **Step 2: 编写Grid布局CSS**

```css
.form-content {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px 16px;
  align-items: start;
}

/* 跨列元素 */
.form-item--full {
  grid-column: 1 / -1;
}

/* 难度等级和总计的特殊样式 */
.form-item--total .total-display {
  padding: 6px 12px;
  background: #F8F9FA;
  border: 1px solid #DEE2E6;
  border-radius: 6px;
  font-size: 14px;
  font-weight: 600;
  color: #212529;
  text-align: center;
}

/* 按钮栏右对齐 */
.action-bar {
  justify-content: flex-end;
  padding-top: 12px;
  border-top: 1px solid #E9ECEF;
  margin-top: 4px;
}

/* 题型网格优化为3列 */
.type-count-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-top: 6px;
}
```

- [ ] **Step 3: 验证双列布局效果**

确认：
- ✅ 文件选择器独占一行（跨2列）
- ✅ 难度等级和总计题数左右并排
- ✅ 题型配置以3列网格显示
- ✅ 操作按钮右对齐且跨2列

---

### Task 3: 实现结果展示区独立滚动 - 自适应高度填充

**Files:**
- Modify: `src/components/exam/GeneratePanel.vue` (Style部分)

- [ ] **Step 1: 优化空状态和加载状态样式**

```css
.loading-state,
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 32px 16px;
  color: #6C757D;
  min-height: 150px;
}

.loading-icon,
.empty-icon {
  font-size: 36px;
  margin-bottom: 10px;
}

.empty-state p {
  font-size: 14px;
  font-weight: 500;
  color: #495057;
  margin-bottom: 4px;
}

.empty-hint {
  font-size: 13px;
  color: #6C757D;
  margin-top: 6px;
  max-width: 400px;
  text-align: center;
  line-height: 1.5;
}
```

- [ ] **Step 2: 优化题目列表样式**

```css
.question-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 4px;
}

.question-item {
  padding: 14px;
  background: #FFFFFF;
  border: 1px solid #E9ECEF;
  border-radius: 8px;
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.question-item:hover {
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  transform: translateY(-1px);
}
```

- [ ] **Step 3: 测试滚动行为**

生成一些测试数据或使用loading状态验证：
- ✅ 结果区可以独立滚动
- ✅ 配置面板保持固定不动
- ✅ 无整体页面滚动条
- ✅ 滚动条样式美观（可选优化）

---

### Task 4: 响应式适配与细节优化 - 移动端降级处理

**Files:**
- Modify: `src/components/exam/GeneratePanel.vue` (Style部分添加媒体查询)

- [ ] **Step 1: 添加移动端响应式规则**

```css
/* 平板设备 (≤1024px) */
@media (max-width: 1024px) {
  .type-count-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  
  .form-content {
    gap: 10px 12px;
  }
}

/* 移动设备 (≤768px) */
@media (max-width: 768px) {
  .generate-panel {
    padding: 12px;
  }
  
  /* 降级为单列布局 */
  .form-content {
    grid-template-columns: 1fr;
    gap: 10px;
  }
  
  .form-item--full,
  .action-bar {
    grid-column: 1;
  }
  
  /* 题型降为2列 */
  .type-count-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  
  /* 按钮全宽 */
  .action-bar {
    flex-direction: column;
  }
  
  .action-bar .btn {
    width: 100%;
  }
  
  /* 减少间距 */
  .config-panel {
    margin-bottom: 8px;
  }
  
  /* 缩小字体和内边距 */
  .form-label {
    font-size: 12px;
  }
  
  .type-count-item {
    padding: 6px 8px;
  }
}

/* 小屏手机 (≤480px) */
@media (max-width: 480px) {
  .type-count-grid {
    grid-template-columns: 1fr;
  }
  
  .stats-row {
    font-size: 12px;
  }
}
```

- [ ] **Step 2: 测试不同屏幕尺寸**

使用浏览器开发者工具测试：
- ✅ 桌面端 (1920x1080): 双列布局完美呈现
- ✅ 笔记本 (1366x768): 正常显示
- ✅ 平板 (768x1024): 降级为单列，按钮堆叠
- ✅ 手机 (375x667): 单列紧凑布局

- [ ] **Step 3: 最终视觉检查**

确认所有细节：
- ✅ 无内容溢出或被截断
- ✅ 所有交互元素可点击
- ✅ 样式符合项目白色体系规范
- ✅ 过渡动画流畅自然
- ✅ 空状态、加载状态、正常状态均正确显示

---

## 验收标准

完成所有任务后，GeneratePanel应满足以下要求：

1. **布局正确性**
   - 配置面板始终可见，不被遮挡
   - 结果区自适应填充剩余空间
   - 仅结果区支持独立滚动

2. **表单可用性**
   - 双列Grid布局信息密度合理
   - 所有表单项完整显示
   - 操作按钮易于触达

3. **响应式表现**
   - 桌面端：双列布局
   - 移动端：自动降级为单列
   - 无横向滚动条

4. **视觉一致性**
   - 符合项目白色体系设计规范
   - 与其他模块风格统一
   - 间距、字号、圆角等细节一致

---

## 执行选项

**Plan complete and saved to this document. Two execution options:**

**1. Subagent-Driven (recommended)** - I dispatch a fresh subagent per task, review between tasks, fast iteration

**2. Inline Execution** - Execute tasks in this session using executing-plans, batch execution with checkpoints

**Which approach?**
