feat(student-ui): 学生端实训页墨黑极简风格统一

- 新产品调查与分析页作为墨黑极简标准样例
- 产品开发关键因素、产品开发主要流程页重设计:
  任务头合并、杂志章节风步骤导航(大号编号+引导线)、
  纯白表格、按钮四级层级、甘特图上传区中性化
- 学生首页贴边纯白、图表灰度配色
- 移除 app-container 与第三方AIGC页蓝色重投影
- 新增项目级 skill:ink-training-theme
- 新增学生端页面 UI 清单文档
fix/exam-question-access-material-excel-delete-draft
qinzhenpen 3 weeks ago
parent 512237b721
commit 79ab9b4f73

@ -0,0 +1,244 @@
---
name: ink-training-theme
description: Apply the ink-minimal visual style to student training pages (Vue 3 + Element Plus + student-training.scss). Use when restyling or redesigning student practical-training pages, buttons, tables, or type scale in this repo. Do not use for admin/management pages or business-logic changes.
---
# 墨黑极简 · 学生实训页设计规范
本技能用于把学生端实训页(`.student-training-shell` 体系)统一为当前已在
`src/views/foundation/new-product-survey.vue` 落地的「墨黑极简」风格:纯白画布、
墨黑主操作、中性灰层次、紧凑排版。该 Vue 文件是整体标准样例;**步骤导航**
以本规范「步骤导航:杂志章节风」一节为准(已在 `product-development-factors.vue`、
`product-development-process.vue` 落地),拿不准时先读这三个文件。
## 边界
- 只动 template 结构与样式;script 业务逻辑(判题/保存/草稿/上传/接口)一律不碰。
- 仅作用于当前页根类,不得影响其他页面;不修改全局 `student-training.scss`。
- 表格类内容区不铺任何底色,对错只靠文字反馈,不靠行背景。
## 实施流程
1. 读目标页,确认根类(如 `.xxx-page.student-training-shell`)和现有 DOM。
2. 在页面 scoped 样式的根类块内定义全部令牌(见下),让所有
`var(--student-*)` 规则自动重着色,不要逐处打补丁。
3. 新增一个非 scoped `<style lang="scss">` 块,选择器全部以页面根类为锚:
- 覆盖祖先 `app-main` 画布背景(scoped 触及不到祖先);
- 重写步骤导航(全局规则带 `!important`,scoped 无法取胜,见步骤导航一节);
- 给子组件(AI 侧栏、工具栏等)换肤。
4. 按按钮四级层级、字号梯度、间距规则逐区收紧。
5. 完成后用 GetDiagnostics 校验,并全文搜索蓝色旧值确认无残留。
## 颜色令牌
在页面根类中定义:
```scss
.xxx-page {
/* 主色:墨黑 */
--student-accent: #1f2937;
--student-accent-deep: #111827;
--student-accent-light: #4b5563;
--student-accent-soft: #f3f4f6;
/* 点缀:暖橙,仅极小面积 */
--student-terracotta: #e8953c;
/* 语义色 */
--student-danger: #d9554c;
--student-success: #4a9d6e;
/* 三层次标识:石墨 / 青灰 / 灰紫(仅小色条,不做行底色) */
--student-layer-1: #374151;
--student-layer-2: #43a294;
--student-layer-3: #8b6fc0;
/* 结构色 */
--student-panel-border: #e5e7eb;
--student-card-bg: #ffffff;
--student-panel-bg: #fafbfc;
--student-text: #1f2937;
--student-text-secondary: #6b7280;
}
```
非 scoped 块中的画布与行高:
```scss
#app .studentLayout .app-main:has(.xxx-page) {
background: #ffffff !important; /* 纯白,无渐变 */
}
#app .studentLayout .app-main:has(.xxx-page) .xxx-page {
line-height: 1.55 !important; /* 全局为 1.8,本页收紧 */
}
```
## 字号层级(紧凑)
覆盖全局字号令牌,整体下调一档:
| 令牌 | 值 | 用途 |
|------|----|------|
| --student-fs-display | 17px | 页面主标题(700,行高 1.35) |
| --student-fs-h1 | 15px | 步骤大标题(700) |
| --student-fs-h2 | 14px | 面板/行标题(600) |
| --student-fs-h3 | 13px | 区块小标题 |
| --student-fs-body | 13px | 正文 |
| --student-fs-body-sm | 12px | 表格/次要文字 |
| --student-fs-caption | 11px | 标签/徽章 |
| --student-fs-button / -lg | 13px | 按钮文字 |
| --student-fs-data | 14px | 数字/成绩,配等宽字体 |
标题区三级关系:上方灰色宽字距小标签(11px,`#6b7280`,letter-spacing 0.12em,
无底色胶囊)→ 黑色步骤标题 → 灰色说明文字。禁止再用实底色 "STEP 01" 胶囊。
## 步骤导航:杂志章节风
大号编号做视觉主角,像书籍目录页。无底色、无边框、无凹槽、无连接线。
已落地样例:`product-development-factors.vue`、`product-development-process.vue`。
### 结构
```html
<nav class="step-indicator" aria-label="实训步骤">
<button
v-for="(step, index) in trainingSteps"
:key="`${step}-${index}`"
type="button"
:class="['step-tab', { active: /* 当前 */, complete: /* 已完成 */ }]"
@click="/* 切换步骤 */"
>
<span class="step-bar" aria-hidden="true"></span>
<span class="step-no">{{ String(index + 1).padStart(2, '0') }}</span>
<span class="step-name">{{ step }}</span>
</button>
</nav>
```
编号**常显**,不随完成态切 ✓。注意各页 `currentStep` 基准不同
(factors 为 0-based、process 为 1-based),只改模板/样式时不要动这个逻辑。
### 视觉规格
| 元素 | 规格 |
|------|------|
| `.step-indicator` | flex 水平居中,gap 28px;无 border/底色/阴影;margin `2px 0 20px` |
| `.step-tab` | `flex: 1 1 0`,max-width 160px;纵向排列(引导线→编号→名称),左对齐,gap 8px;无 border/底色 |
| `.step-bar` | 24×3px;默认透明,仅当前步骤 `#1f2937` |
| `.step-no` | **32px**、800 字重、等宽字体、letter-spacing -1px |
| `.step-name` | 12px,左对齐、允许换行 |
三态:
- **未到达**:编号 `#d1d5db`,名称 `#9ca3af`;hover 编号与名称转 `#6b7280`,无底色。
- **已完成**:编号与名称 `#6b7280`(名称 600);编号右上角缀 7px 绿色小圆点
(`.step-no::after`,top -3px / right -8px,`--student-success`)。
- **当前**:引导线墨黑,编号 `#1f2937`,名称 `#1f2937`、700。
### 覆盖机制(不做这步,页面仍是浅蓝大胶囊)
全局 `student-training.scss` 对 `.student-training-shell .step-indicator` 与
`.step-tab` 全部以 `!important` 锁定浅蓝底(`#f0f6fd`)、全胶囊圆角、固定高度、
`white-space: nowrap`,并在 ≤1100px 用 `!important` 强制纵向堆叠。
**scoped 样式无论怎么写特异性都打不赢**(scoped 属性选择器不增加 id 级特异性)。
正确做法——规则放进页面**非 scoped** 块,选择器带 id 锚点且每条声明 `!important`:
```scss
#app .studentLayout section.app-main:has(.xxx-page) .step-indicator { /* … */ !important; }
#app .studentLayout section.app-main:has(.xxx-page) .step-indicator .step-tab { /* … */ !important; }
```
必须显式重置的全局残留:容器的 `padding / border / border-radius / background /
box-shadow`;tab 的 `min-height / height / padding / border / border-radius /
white-space`(改回 `normal` 以允许步骤名换行)。
窄屏在非 scoped 块自行处理,**不要**接受全局 1100px 纵向规则:
```scss
@media (max-width: 900px) {
#app …:has(.xxx-page) .step-indicator {
justify-content: flex-start;
overflow-x: auto; /* 横向滑动 */
}
#app …:has(.xxx-page) .step-tab { flex: 0 0 112px; max-width: none; }
}
```
## 按钮规范
扁平无渐变,强制 `text-shadow: none`;圆角矩形而非全胶囊。标准页有两个按钮位置,
规格不同,不要混用:
### 四级层级
1. **一级主操作**:墨黑实底 `#1f2937` 白字 + 中性柔影,hover `#111827`。
用于下一步/提交任务/AI 发送/智能评分。
2. **二级描边**:白底 + 描边 + `#1f2937` 字,hover 墨黑描边 + `#f3f4f6` 底。
用于上一步/下载/重新实训/导出/清空。
3. **三级浅灰底**:`#f3f4f6` 底 + `#374151` 字,hover `#e9ecef`。用于保存草稿。
4. **危险文字**:无底色,`#d9554c` 文字链接,hover 深红加下划线。用于删除。
禁用态统一 `opacity: 0.5` + `not-allowed`,`transform: none`、去掉阴影,形状不跳变。
loading 态保持原配色。
### 位置 A:底部步骤导航(40px 标准按钮)
结构(原生 `<button>`,容器 `.step-navigation` 居中 flex,gap 14px):
```html
<div class="step-navigation">
<button class="btn-nav btn-ghost" @click="prevStep"><el-icon><ArrowLeft /></el-icon>上一步</button>
<button class="btn-nav btn-save" @click="saveCurrentProgress"><el-icon><CircleCheck /></el-icon>保存当前进度</button>
<button class="btn-nav btn-primary" @click="nextStep">下一步<el-icon><ArrowRight /></el-icon></button>
<span class="step-progress">Step 01 / 04</span>
</div>
```
- 三按钮统一 **40px 高、10px 圆角、700 字重、13px 字、gap 8px**;
ghost/primary 横向 padding 18px(primary 可 22px)。
- 次按钮基类(`.outline-action, .btn-nav` 共用):白底,描边
`1px solid rgba(31, 41, 55, 0.4)`,字色 `var(--student-accent)`。
- hover:`translateY(-1px)` + 描边变实色墨黑 + 底变 `var(--student-accent-soft)`
+ 阴影 `0 3px 10px rgba(31,41,55,.12)`;active 回落 `translateY(0)`。
- primary:墨黑实底 + 阴影 `0 3px 10px rgba(31,41,55,.28)`,hover 加深为
`#111827`、阴影 `0 5px 14px rgba(31,41,55,.32)`。
- save:`#f3f4f6` 底、`#e5e7eb` 描边、`#374151` 字,无重投影;视觉权重
低于 ghost,形成 实底黑 > 描边白 > 浅灰底 的层级。
- `.step-progress`:绝对定位右侧,12px 等宽数字、`#6b7280`、800 字重;
≤1100px 时改为静态独占一行居中。
- ≤900px:导航纵向排列,`.btn-nav` 全部 `width: 100%`。
### 位置 B:顶部任务工具栏(36px 紧凑小按钮)
工具栏是子组件(Element Plus `.el-button`),在页面非 scoped 块中以页面根类为锚
换肤(如 `.xxx-page .task-toolbar-button.el-button`),容器 gap 8px:
- 次按钮(下载案例资料/重新实训/导出实训成果):**36px 高、8px 圆角、600 字重、
13px 字**,白底 + `#d1d5db` 描边 + `#374151` 字;hover 描边和字变 `#1f2937`、
底 `#f9fafb`、阴影 `0 2px 6px rgba(17,24,39,.1)`。图标 14px 且 `color: inherit`。
- 提交按钮(`.task-toolbar-button--submit`):墨黑实底白字 +
`0 2px 8px rgba(17,24,39,.22)`,hover `#111827` + 阴影加深。
- loading 态强制保持白底灰描边,不随 Element Plus 默认变蓝。
- 无资料时的 plain 态:字色 `#9ca3af`,hover 只到 `#6b7280` + `#f9fafb`。
- 步骤标题行内的小号导出按钮可再缩到 32px 高、12px 字。
## 表格规则
- 表头、单元格、外容器一律不设 background(默认透明白),包括 hover、选中、判题后。
- 表头仅用 12–13px、800–900 字重,无渐变底。
- 只保留 `#e5e7eb` 浅灰边框与行间分隔线。
- 序号用 22px 浅灰圆角方块(`#f3f4f6`)+ 等宽数字。
- 判题结果:单元格内文字反馈(绿/红)+ 底部汇总横幅(8–10px 圆角、8% 同色底)。
- 三层次概念仅靠维度名前 3–4px 小色条标识。
## 间距(紧凑)
- 主列 gap 10px;卡片内 padding 12px;字段组 padding 12px。
- 步骤标题下 10px、说明下 14px、字段块间 12px、表格上 14px。
- 行高:页面 1.55,标题 1.35,说明 1.6,表格次要文字 1.55。
## 子组件换肤要点
- AI 侧栏面板、气泡、输入框、发送按钮全部中性灰白;其内部 Element Plus
主色按钮通过覆盖组件内 CSS 变量或 `.el-button--primary` 改墨黑。
- 工具栏 `TrainingTaskToolbar` / `TrainingMaterialButton` 按「按钮规范 · 位置 B」
换肤;提交按钮保留墨黑实底作为主操作。
- Element Plus 单选:选中圆点 `#1f2937` 填充白勾,覆盖默认蓝;带边框单选项
选中墨黑描边黑字。下拉选中值用深色 + `-webkit-text-fill-color` 防透明。

@ -0,0 +1,245 @@
# 学生端页面 UI 清单
> 用途:学生端 UI 调整前的页面盘点。信息来源:`src/router/index.js`(`roles: ["student"]` 路由组)、`src/utils/studentTrainingNavigation.js`(学生实训导航映射)及各页面源码。
> 生成日期:2026-09-20
---
## 1. 学生端页面总览
学生端路由全部位于 `src/router/index.js` 中 `roles: ["student"]` 的分组,共 **44 个路由**(对应约 42 个视图文件:`analysis.vue`/`dialogue.vue` 各被 2 条路由复用,`GenericTrainingPage.vue` 服务 2 条路由)。按性质分为三类:
| 分类 | 数量 | 说明 |
|------|------|------|
| 入口/功能页 | 13 | 首页仪表盘、AI 助手、学情分析、BI 可视化、实验报告、考试等 |
| 实训模块页 | 28 | 6 大模块下的实训任务页(本次 UI 调整重点) |
| 公共实训壳 | 3 | 综合实训、动态任务页、自定义步骤页(多任务复用) |
---
## 2. 入口/功能页
| # | 路由 | 菜单标题 | 视图文件 | 布局形态 |
|---|------|---------|---------|---------|
| 1 | `/index` | 首页(学生仪表盘) | `views/index.vue` 按角色渲染 → 学生仪表盘 `views/student/index.vue` | 卡片 + ECharts |
| 2 | `/assistant/index` | AI智能助手 | `views/AI/index.vue` | 对话式 |
| 3 | `/ai/learning-situation-analysis` | AI学情分析 | `views/analysis-of-students/analysis.vue` | 对话入口列表 |
| 4 | `/ai/learning-situation-dialogue` | AI学情对话 | `views/analysis-of-students/dialogue.vue` | 对话式 |
| 5 | `/ai/teaching-plan` | AI助手(实训教案) | `views/analysis-of-students/training-lesson-plan.vue` | 对话式 |
| 6 | `/analysis/index` | 学情分析(旧入口) | `views/analysis-of-students/analysis.vue` | 同 #3 同组件 |
| 7 | `/analysis/dialogue` | 学情对话(旧入口) | `views/analysis-of-students/dialogue.vue` | 同 #4 同组件 |
| 8 | `/bi` | BI可视化分析 | `views/visual-analysis/index.vue` | el-tabs + iframe |
| 9 | `/report/index` | 实验报告 | `views/test-report/index.vue` | 表格卡片 |
| 10 | `/examination/index` | 考试考核 | `views/exam/index.vue` | 列表页(浅色) |
| 11 | `/examination/take/:id` | 考试作答 | `views/exam/take.vue` | 表单 |
| 12 | `/examination/result/:id` | 考试成绩 | `views/exam/result.vue` | 详情 |
| 13 | `/student-demo`(hidden) | 学生演示页 | `views/studentDemo/index.vue` | 演示页 |
### 各页 UI 结构要点
**① 学生首页仪表盘**(`views/student/index.vue`,经 `views/index.vue` 按角色渲染)
- 「我的实训成绩」卡片:模块成绩分布 ECharts 饼图 + 成绩明细表格
- 「实训进度概览」卡片:学习时长条形图、任务完成进度条形图
- ECharts 需 `resize` 监听与 `dispose` 清理
**② AI智能助手**(`views/AI/index.vue`)
- 顶部 tab 导航 + 步骤/章节导航(左侧)
- 上传/导出按钮、QA 对话列表、加载态、底部输入框
**③④ 学情分析 / 对话**(`analysis-of-students/analysis.vue`、`dialogue.vue`)
- `stu-analysis-of-students` 根 class,顶部提示标题 + 分析入口按钮列表(点击触发 AI 分段输出)
- 深蓝色系提示条,无成绩数据时 `el-empty`
**⑤ BI可视化分析**(`views/visual-analysis/index.vue`)
- `el-tabs` 两个页签:「数据源管理」(`digitalMarketingAlgorithms/bigData` 组件)、「BI可视化分析」(iframe 嵌入 `VITE_APP_BI_URL`)
- 深色主题:背景 `#06121f`、tab 文字 `#a9d8ff`(硬编码,UI 调整注意)
**⑥ 实验报告**(`views/test-report/index.vue`)
- 标题(白字 + 深蓝 text-shadow)→ 学生信息行(姓名/学号/班级)→ 总成绩卡片(含班级排名 + 模块成绩表格)→ 实训任务明细卡片(任务名/模块/完成状态/AI 评分表格)
- 深色背景浅色文字,样式简单(约 5 条 scoped 规则)
**⑦ 考试考核**(`views/exam/index.vue`)
- 页头(标题+刷新按钮)→ 状态筛选按钮组(全部/未开始/进行中/已结束,带数量徽标)→ 考试列表行(日期块 | 信息区 el-tag+标题+时间 | 操作按钮)
- 浅色主题 `#20282d`,主题色 `#16839c`(青绿色,与其他模块蓝色系不一致,UI 调整注意)
- 有移动端断点 `@media(max-width:650px)`
**⑧⑨ 考试作答/成绩**(`exam/take.vue`、`exam/result.vue`)
- 本轮未深入调研,UI 调整时单独阅读
---
## 3. 实训模块页(UI 调整重点)
> 通用结构(新版实训壳,绝大多数页面遵循):
> `student-training-shell` 根容器 → `task-header` 顶部任务标题/背景(内嵌 `TrainingTaskBrief`)→ 步骤导航(`step-indicator` / `step-tabs`)→ 分步骤表单/表格/上传区 → 底部操作栏(上一步/保存/下一步/提交)→ 右侧 `TrainingAiSidebar`(AI 学习提示,可折叠)
### 3.1 互联网产品开发基础(`/foundation`,3 页)
| # | 路由 | 标题 | 文件 |
|---|------|------|------|
| 1 | `/foundation/new-product-survey` | 新产品调查与分析 | `views/foundation/new-product-survey.vue` |
| 2 | `/foundation/product-development-factors` | 产品开发关键因素 | `views/foundation/product-development-factors.vue` |
| 3 | `/foundation/product-development-process` | 产品开发主要流程 | `views/foundation/product-development-process.vue` |
- **新产品调查与分析**:4 步。Step01 产品卖点三层次分类(`TrainingStepOneChoiceQuestions` + 分类表格 + `el-select` + 判题反馈);Step02 实地调研记录(表单分组、平台/场景单选、关键词、产品名、图片上传预览列表);Step03 三层次对照分析表格 + textarea;Step04 价值判断 3 个文本域。含图片预览 Dialog。
- **产品开发关键因素**:4 步表单。Step1-3 成功/失败产品对比表格 + textarea;Step4 关键因素总结 textarea。头部含 `TrainingMaterialButton`(资料按钮)与导出按钮。
- **产品开发主要流程**:Step01 关键任务识别(任务表格 + select 分类 + 判题反馈 + 保存/清空);Step02 排期表格 + 甘特图上传预览;Step03/04 工具说明 + 并行协同复盘 textarea。
### 3.2 市场需求挖掘(`/demand`,8 路由)
| # | 路由 | 标题 | 实际视图文件 |
|---|------|------|-------------|
| 1 | `/demand/index` | 行业需求分析 | `views/demand/industry-demand-analysis.vue` |
| 2 | `/demand/environment` | 竞争环境分析 | `views/demand/competitive-environment-analysis.vue` |
| 3 | `/demand/people` | 目标用户画像 | `views/demand/people.vue` |
| 4 | `/demand/user` | 用户数据分析 | `views/demand/user.vue`(legacy) |
| 5 | `/demand/business-feasibility` | 商业可行性论证 | `views/demand/business-feasibility.vue` |
| 6 | `/demand/consumer-behavior` | 消费者需求与行为 | `views/demand/consumer-behavior.vue` |
| 7 | `/demand/consumer-scenario` | 消费场景解构 | `views/demand/consumer-scenario.vue` |
| 8 | `/demand/feature-conversion` | 需求转化为功能 | `views/demand/feature-conversion.vue` |
- **行业需求分析**(根 class `industry-pest-page`,scoped):四步实训卡片、PEST 表格、机会挑战表、结论表单;使用 `TrainingTaskToolbar`、`TrainingStepOneChoiceQuestions`。
- **竞争环境分析**(根 class `competitive-analysis-page`,scoped):SWOT 表格、策略矩阵、最终决策区。
- **目标用户画像**:文件上传面板、Excel 预览弹窗、RFM 图表上传区、洞察表格、访谈记录 tab、用户画像表单。
- **用户数据分析**(旧版 legacy 壳):`student-training-shell` + 顶部 tab 切换 + `TrainingIntro` + 动态组件渲染区 + `TrainingLegacyActions`。
- **商业可行性论证**(根 class `feasibility-core`/`workbench`):多步 form-section/table、上传面板、`el-dialog` 预览,布局与其他 demand 页不同。
- **消费者需求与行为**:分步骤表单/表格/问卷编辑器弹窗。
- **消费场景解构**:旅程排序、旅程分析表格、旅程图上传区、优化建议表格。
- **需求转化为功能**:需求转化表、RICE 优先级打分表、优先级决策表。
### 3.3 产品规划(`/product`,7 路由)
| # | 路由 | 标题 | 实际视图文件 |
|---|------|------|-------------|
| 1 | `/product/index` | 市场机会识别与选品 | `views/product/market-opportunity-selection.vue`(`hideSupplementSteps`) |
| 2 | `/product/price` | 产品定价 | `views/product/price.vue` |
| 3 | `/product/differentiation` | 产品价值主张及定位 | `views/product/differentiation.vue` |
| 4 | `/product/structure` | 产品结构规划 | `views/product/structure.vue` |
| 5 | `/product/after-sales-service` | 售后服务流程设计 | `views/product/after-sales-service.vue` |
| 6 | `/product/requirements-doc` | 产品需求说明书 | `views/product/requirements-doc.vue` |
| 7 | `/product/hardware-cost` | 智能硬件成本估算 | `views/product/hardware-cost.vue` |
- **市场机会识别与选品**(根 class `opportunity-core`):6 步——指标分类、权重设置、综合得分计算、可视化上传、用户需求洞察、选品结论。
- **产品定价**(标题区 `PRODUCT PRICING`):按 `currentStep` 动态渲染定价步骤。
- **产品价值主张及定位**:核心价值 / 用户档案 / 价值地图 / 定位陈述 / MRD 表单区块。
- **产品结构规划**:四层架构排序、操作链路排序、场景分析表格、架构图上传区(`ProductStructureImageUpload`)。
- **售后服务流程设计**:3 步——故障分类拖拽、处理流程表格、售后政策表格;通过 `getStudentTrainingPage("after-sales-service")` 接入页面体系。
- **产品需求说明书**:3 步——PRD 模块匹配拖拽、PRD 详细信息表格、文档上传/预览。
- **智能硬件成本估算**(标题区 `BOM COSTING`):4 步——BOM 选型(可编辑物料明细表格,增删行 + 合计)、批量成本核算、制造成本核算、成本优化决策(可视化上传 + 优化方案文本 + 下载模板按钮)。
### 3.4 产品投放测试(`/test`,4 路由)
| # | 路由 | 标题 | 视图文件 |
|---|------|------|---------|
| 1 | `/test/index` | 发布渠道评估 | `views/test/index.vue` |
| 2 | `/test/promotion` | 产品推广测试 | `views/test/promotion.vue` |
| 3 | `/test/channelas` | 渠道表现分析 | `views/test/channel.vue`(legacy) |
| 4 | `/test/marketing` | 产品营销定位 | `views/test/marketing.vue`(legacy) |
- **发布渠道评估**(TASK_KEY `release-channel-evaluation`):新版壳,`step-tabs` 四步表单/表格。
- **产品推广测试**(TASK_KEY `promotion-effect-optimization`):4 步——预算分配、投放策略、投放数据与 ROI、效果评估与优化。
- **渠道表现分析**(旧版):`TrainingIntro`(漏斗模型介绍)+ `funnelAnalysis` 组件 + 旧式操作栏。
- **产品营销定位**(旧版 `legacy-training-page`):`TrainingIntro` + 案例说明 + 广告数据 `el-table` + ECharts 四象限图(坐标轴可选)+ textarea 分析 + 提交/重置。
### 3.5 供应渠道管理(`/channel`,3 路由)
| # | 路由 | 标题 | 视图文件 |
|---|------|------|---------|
| 1 | `/channel/index` | 采购需求预测 | `views/channel/index.vue` |
| 2 | `/channel/purchase` | 采购产品定位 | `views/channel/purchase.vue`(legacy) |
| 3 | `/channel/supplier` | 供应商评估与选择 | `views/channel/supplier.vue` |
- **采购需求预测**:4 步——线性需求预测表格(`el-table` + `el-input-number`)、预测可视化上传/预览卡片、采购计划规则表格(安全库存/期初库存/采购量输入)、采购量预测表格 + ECharts 容器 + 代码查看弹窗。
- **采购产品定位**(旧版):`TrainingIntro`(卡拉杰克模型长文介绍)+ 四象限矩阵分析。
- **供应商评估与选择**(`workspace` header):3 步,Step1 场景 A/B 权重卡片 + 表格。
### 3.6 产品评估与考核(`/assessment`,3 路由)
| # | 路由 | 标题 | 视图文件 |
|---|------|------|---------|
| 1 | `/assessment/index` | 产品表现分析(功效系数法) | `views/assessment/index.vue` |
| 2 | `/assessment/diagnosis` | 产品问题诊断 | `views/assessment/diagnosis.vue` |
| 3 | `/assessment/optimization` | 品类结构优化 | `views/assessment/optimization.vue` |
- **产品表现分析**:`TrainingIntro` 背景与目标 + `TrainingTaskToolbar` + 多个 `el-table`(指标/绩效数据/功效值/权重)+ 底部 `taskfooter` 提交/重置。
- **产品问题诊断**(`workbench-top`):步骤 tab、漏斗计算表格、对比图上传、词云分析、情感倾向表格、根因 textarea、AB 测试方案与结论。
- **品类结构优化**(`workbench-head`):品类表格(`el-input`/`el-input-number` 增删行)、帕累托图上传区(`el-image` 预览 + 重传/移除)。
---
## 4. 公共实训壳(多任务复用,改一处影响面大)
| 路由 | 标题 | 视图文件 | 说明 |
|------|------|---------|------|
| `/comprehensive/index` | 综合实训 | `views/training/GenericTrainingPage.vue` | `pageKey: comprehensive-case-training`,`hideSupplementSteps` |
| `/training/task/:pageKey` | 实训任务(动态) | `views/training/GenericTrainingPage.vue` | 后端下发任务 → 通用渲染,`studentTrainingNavigation.js` 生成菜单 |
| `/training/:taskKey/:stepId` | 自定义实训步骤 | `views/training/CustomTrainingStepPage.vue` | 步骤 header + `TrainingTaskBrief` + textarea + 附件上传 + 上一步/保存/下一步 + empty 状态 |
- **GenericTrainingPage**:公共步骤导航(步骤 tab / marker / connector)→ 步骤标题+任务说明 → 流程表格、上传提示/按钮/文件名展示 → 综合案例 PEST/SWOT 输入区 + 结论 textarea。**未走专属 .vue 的实训任务全部由它渲染,UI 调整优先级最高。**
---
## 5. 公共组件与样式
### 5.1 实训公共组件(`src/views/components/`)
| 组件 | 作用 |
|------|------|
| `TrainingAiSidebar.vue` | 右侧 AI 学习提示侧边栏(可折叠),几乎所有实训页右栏 |
| `DynamicTrainingStepNavigator.vue` | 动态步骤导航条 |
| `TrainingTaskBrief.vue` | 任务背景/目标简介卡片(页面头部内嵌) |
| `TrainingTaskToolbar.vue` | 任务工具栏 |
| `TrainingMaterialButton.vue` | 资料查看按钮 |
| `TrainingIntro.vue` | 旧版页介绍区(background / goal 插槽) |
| `TrainingStepOneChoiceQuestions.vue` | 单选判题题组(含 `StepOneChoiceQuestionEditor.vue` 编辑器) |
| `TrainingAiEvaluation.vue` | AI 评价展示 |
| `TrainingLegacyActions.vue` | 旧版页底部操作栏 |
| `popModal.vue` / `mainContent.vue` | 弹窗 / 主内容容器 |
### 5.2 product 模块公共组件(`src/views/product/components/`)
- `ProductStandardTrainingPage.vue`:product 模块标准实训页组件(任务标题 + 简介 + 步骤导航 + 步骤内容 + 操作按钮 + AI 侧边栏),自带 scoped 样式。
- `ProductStructureImageUpload.vue`:图片上传封装(`el-upload` + 预览列表)。
### 5.3 学生端公共样式
- `src/assets/styles/student-training.scss`:学生实训页全局样式根。定义 `:root` 字号变量、`.student-training-shell` 主题色、背景渐变、网格布局、侧边 AI 栏折叠/展开宽度等。**统一 UI 风格首选改这里 + 各页 scoped 样式。**
---
## 6. 三种布局形态(UI 统一的关键)
| 形态 | 识别特征 | 使用页面 |
|------|---------|---------|
| 新版实训壳 | `student-training-shell` + `task-header` + `TrainingTaskBrief` + `step-indicator/step-tabs` + `TrainingAiSidebar` | foundation 全部、demand 大部分、product 大部分、test/index、test/promotion、channel/index、channel/supplier、assessment 全部 |
| 旧版 legacy 页 | `legacy-training-page` + `TrainingIntro` + `TrainingLegacyActions` | `demand/user`、`test/marketing`、`test/channel`、`channel/purchase` |
| 通用渲染页 | `GenericTrainingPage` / `CustomTrainingStepPage` / `ProductStandardTrainingPage` | 综合实训、动态任务、自定义步骤、product 部分页 |
**UI 调整建议**:
1. 优先统一 `student-training.scss` 与 `TrainingAiSidebar`/`TrainingTaskBrief`/步骤导航等公共件——影响面覆盖 20+ 页。
2. 旧版 legacy 4 页(demand/user、test/marketing、test/channel、channel/purchase)风格最不统一,建议重点处理。
3. 注意孤立硬编码配色:`visual-analysis`(`#06121f` 深蓝)、`exam/index`(`#16839c` 青绿)、`test-report`(text-shadow 白字)与学生实训蓝色系不一致。
4. 部分页面有独立 scoped 根 class(`industry-pest-page`、`competitive-analysis-page`、`opportunity-core`、`feasibility-core` 等),调整时需逐页确认。
---
## 7. 未注册路由的孤儿页面(UI 调整可忽略,建议后续清理)
| 文件 | 说明 |
|------|------|
| `views/demand/index.vue` | 已被 `demand/industry-demand-analysis.vue` 取代(路由 `/demand/index` 指向后者) |
| `views/demand/environment.vue` | 已被 `demand/competitive-environment-analysis.vue` 取代 |
| `views/product/index.vue` | 已被 `product/market-opportunity-selection.vue` 取代(路由 `/product/index` 指向后者) |
| `views/assessment/kano.vue` / `five.vue` / `market.vue` / `traffic.vue` | 未在路由中注册,疑似旧版遗留 |
| `views/learningCenter/*.vue`(learningResources / evaluation / Achievement) | 未在学生路由中注册 |
| `views/demand/industry-demand-analysis` 之外的重复实现 | 见上 |
> 注意:`studentDemo/index.vue` 有 hidden 路由 `/student-demo`,属演示页。
---
## 8. 学生端实训模块导航来源(菜单 ≠ 路由)
- 学生左侧/顶部实训模块页签由后端接口返回任务列表,经 `src/utils/studentTrainingNavigation.js` 的 `buildStudentTaskSections()` 按模块分组生成,任务 `taskKey` → 路由映射写在 `knownTaskPaths` 中(23 个映射)。
- **改路由前先对照 `knownTaskPaths`**,新增页面需在此登记 `taskKey → path`,否则学生菜单点不进去。
- 综合实训(`comprehensive-case-training`)单独作为顶部任务,指向 `/comprehensive/index`。

@ -533,7 +533,6 @@ aside {
.app-container {
margin: 10px;
box-shadow: 0px 0px 13px 0px #0452c6;
border-radius: 10px;
padding: 25px;
// overflow-y: auto;
@ -541,7 +540,6 @@ aside {
.app-container3 {
margin: 10px;
box-shadow: 0px 0px 13px 0px #0452c6;
border-radius: 10px;
padding: 25px 25px 3px;
}

@ -7,29 +7,29 @@
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<div class="app-containerO" v-loading="loding">
<iframe v-lazy="'https://pidoutv.com/'" src="https://pidoutv.com/" frameborder="0"></iframe>
</div>
<div class="app-containerO" v-loading="loding">
<iframe v-lazy="'https://pidoutv.com/'" src="https://pidoutv.com/" frameborder="0"></iframe>
</div>
</template>
<script setup>
const { proxy } = getCurrentInstance();
const loding = ref(true);
const { proxy } = getCurrentInstance()
const loding = ref(true)
onMounted(() => {
setTimeout(()=>{
loding.value = false;
},2000)
});
setTimeout(() => {
loding.value = false
}, 2000)
})
</script>
<style scoped lang="scss">
.app-containerO {
margin: 10px;
box-shadow: 0px 0px 13px 0px #0452c6;
border-radius: 10px;
width: 100%;
height: 740px;
margin: 10px;
border-radius: 10px;
width: 100%;
height: 740px;
}
iframe {
width: 100%;
height: 100%;
width: 100%;
height: 100%;
}
</style>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -97,7 +97,7 @@ const projectStudyTimes = ref([]);
const loading = ref(true);
const loadError = ref("");
const MODULE_COLORS = ["#6958e7", "#3698ee", "#ffb83e", "#ff6f4a", "#45b982", "#39b8ce"];
const MODULE_COLORS = ["#1f2937", "#4b5563", "#6b7280", "#9ca3af", "#c4c9d1", "#374151"];
let scoreChart;
let studyTimeChart;
@ -180,7 +180,7 @@ const renderProgressChart = () => {
type: "bar",
stack: "tasks",
barMaxWidth: 18,
itemStyle: { color: "#3e9cf4", borderRadius: [9, 0, 0, 9] },
itemStyle: { color: "#1f2937", borderRadius: [9, 0, 0, 9] },
data: modules.map((module) => Number(module.completedTaskCount) || 0)
},
{
@ -188,7 +188,7 @@ const renderProgressChart = () => {
type: "bar",
stack: "tasks",
barMaxWidth: 18,
itemStyle: { color: "#e8eef8", borderRadius: [0, 9, 9, 0] },
itemStyle: { color: "#e5e7eb", borderRadius: [0, 9, 9, 0] },
data: modules.map((module) => Math.max(0, (Number(module.totalTaskCount) || 0) - (Number(module.completedTaskCount) || 0)))
}
]
@ -217,7 +217,7 @@ const renderStudyTimeChart = () => {
name: "学习时长",
type: "bar",
barMaxWidth: 18,
itemStyle: { color: "#6958e7", borderRadius: [0, 9, 9, 0] },
itemStyle: { color: "#4b5563", borderRadius: [0, 9, 9, 0] },
data: projects.map((item) => Number((item.studySeconds / 60).toFixed(1))),
}],
}, true);
@ -274,18 +274,18 @@ onBeforeUnmount(() => {
<style lang="scss" scoped>
.student-home {
min-height: calc(100vh - 70px);
background: #f5f8fd;
padding: 20px;
background: #ffffff;
padding: 0;
}
.load-error { margin-bottom: 14px; }
.load-error { margin-bottom: 12px; }
.dashboard-card {
margin-bottom: 16px;
border: 0;
box-shadow: 0 10px 30px rgba(37, 77, 135, 0.08);
margin-bottom: 14px;
border: 1px solid #e5e7eb;
box-shadow: 0 2px 10px rgba(17, 24, 39, 0.05);
:deep(.el-card__header) { padding: 17px 20px; }
:deep(.el-card__header) { padding: 13px 16px; border-bottom: 1px solid #e5e7eb; }
}
.card-header {
@ -294,8 +294,8 @@ onBeforeUnmount(() => {
justify-content: space-between;
gap: 12px;
span { color: #1d2b4a; font-size: 18px; font-weight: 700; }
small { color: #8a98af; font-size: 13px; }
span { color: #1f2937; font-size: 15px; font-weight: 700; }
small { color: #9ca3af; font-size: 12px; }
}
.score-layout { display: grid; grid-template-columns: minmax(520px, 0.95fr) minmax(760px, 1.35fr); min-height: 330px; }
@ -304,7 +304,7 @@ onBeforeUnmount(() => {
position: relative;
display: flex;
min-width: 0;
border-right: 1px dashed #d8e2f1;
border-right: 1px dashed #e5e7eb;
}
.score-chart { width: 100%; min-height: 330px; }
@ -325,13 +325,36 @@ onBeforeUnmount(() => {
}
.score-metric { display: inline-flex; align-items: baseline; gap: 4px; }
.score-metric--ai { color: #5645d5; }
.score-metric--teacher { color: #258edc; }
.summary-label { font-size: 14px; font-weight: 600; }
.score-metric--ai { color: #1f2937; }
.score-metric--teacher { color: #6b7280; }
.summary-label { font-size: 12px; font-weight: 600; }
.score-table-wrap { display: flex; align-items: center; min-width: 0; overflow-x: auto; padding: 8px 0 8px 24px; }
.score-table { width: 100%; min-width: 760px; }
.score-table :deep(.el-table__cell) { white-space: nowrap; }
/* 成绩表:纯白底 + 中性灰边框,无蓝色/斑马重色 */
.score-table :deep(th.el-table__cell) {
color: #1f2937;
background: #ffffff;
border-color: #e5e7eb;
font-size: 12px;
font-weight: 700;
}
.score-table :deep(td.el-table__cell) {
color: #374151;
border-color: #e5e7eb;
font-size: 12px;
}
.score-table :deep(.el-table__row--striped td.el-table__cell) {
background: #fafbfc;
}
.score-table :deep(.el-table__body tr:hover > td.el-table__cell) {
background: #f3f4f6;
}
.progress-layout { display: grid; grid-template-columns: 190px minmax(370px, 1fr) minmax(370px, 1fr); gap: 24px; align-items: stretch; }
.learning-time {
@ -340,13 +363,13 @@ onBeforeUnmount(() => {
align-items: center;
justify-content: center;
min-height: 270px;
color: #ffffff;
color: #1f2937;
border: 1px solid #e5e7eb;
border-radius: 14px;
background: linear-gradient(150deg, #5fa9fa 0%, #387ee2 100%);
box-shadow: 0 14px 24px rgba(57, 126, 226, 0.24);
background: #fafbfc;
strong { margin-top: 18px; font-size: 17px; }
span { margin-top: 7px; font-size: 13px; opacity: 0.88; }
strong { margin-top: 16px; font-size: 14px; font-weight: 800; }
span { margin-top: 6px; font-size: 12px; color: #6b7280; }
}
.time-orbit {
@ -355,13 +378,13 @@ onBeforeUnmount(() => {
width: 108px;
height: 108px;
text-align: center;
border: 4px solid rgba(255, 255, 255, 0.4);
border: 3px solid #1f2937;
border-radius: 50%;
box-shadow: inset 0 0 0 8px rgba(255, 255, 255, 0.16);
box-shadow: inset 0 0 0 7px #f3f4f6;
}
.time-value { font-size: 25px; font-weight: 800; line-height: 1; }
.time-unit { margin-top: 5px; font-size: 13px; letter-spacing: 0.08em; }
.time-unit { margin-top: 5px; font-size: 12px; letter-spacing: 0.08em; color: #6b7280; }
.study-time-chart-wrap, .progress-chart-wrap { min-width: 0; }
.study-time-chart, .progress-chart { min-height: 270px; width: 100%; }
@ -381,7 +404,7 @@ onBeforeUnmount(() => {
@media (max-width: 1320px) {
.score-layout { grid-template-columns: 1fr; }
.score-visual { border-right: 0; border-bottom: 1px dashed #d8e2f1; }
.score-visual { border-bottom: 1px dashed #e5e7eb; }
.score-table-wrap { padding: 20px 0 0; }
.progress-layout { grid-template-columns: 180px 1fr; }
.progress-chart-wrap { grid-column: 1 / -1; }
@ -398,3 +421,21 @@ onBeforeUnmount(() => {
.progress-chart-wrap { grid-column: auto; }
}
</style>
<style lang="scss">
/*
* 学生首页贴边纯白(scoped 无法触及祖先,故放在非 scoped 块):
* 1) app-main 深蓝背景图/渐变 → 纯白,padding 清零;
* 2) 外层 .index 的 10px margin 清零,内容贴边。
* 选择器以 .student-home :has 为锚,不影响其他角色/页面。
*/
#app .studentLayout section.app-main:has(.student-home) {
padding: 0 !important;
background: #ffffff !important;
background-image: none !important;
}
#app .studentLayout .app-main:has(.student-home) .index {
margin: 0 !important;
}
</style>

Loading…
Cancel
Save