merge: merge origin/dev-QQq into master

fix/exam-question-access-material-excel-delete-draft
chenyuan 2 weeks ago
commit 182360e458

@ -21,19 +21,23 @@
.student-training-shell {
--student-step-height: 40px;
--student-step-font: 13px;
--student-action-height: 38px;
--student-action-font: 15px;
--student-action-height: 34px;
--student-action-font: 13px;
--student-upload-height: 36px;
--student-upload-font: 13px;
--student-aux-height: 38px;
--student-aux-font: 13px;
--student-radius-sm: 6px;
--student-radius-pill: 999px;
/* 墨黑极简主题令牌 */
--student-accent: #1f2937;
--student-accent-deep: #111827;
--student-accent-light: #4b5563;
--student-accent-soft: #f3f4f6;
/* 教育蓝主题令牌(复刻 foundation/new-product-survey.vue) */
--student-accent: #2563eb;
--student-accent-deep: #1d4ed8;
--student-accent-light: #3b82f6;
--student-accent-soft: #eff6ff;
/* 语义色 */
--student-danger: #ef4444;
--student-success: #2ba471;
/* 结构色 */
--student-panel-border: #e5e7eb;
--student-card-bg: #ffffff;
--student-panel-bg: #fafbfc;
@ -55,9 +59,9 @@
--el-input-bg-color: #ffffff;
--el-input-text-color: #1f2937;
--el-input-border-color: #e5e7eb;
--el-input-hover-border-color: #1f2937;
--el-input-focus-border-color: #1f2937;
--el-input-focus-ring-color: rgba(31, 41, 55, 0.15);
--el-input-hover-border-color: #3b82f6;
--el-input-focus-border-color: #2563eb;
--el-input-focus-ring-color: rgba(59, 130, 246, 0.15);
--el-input-disabled-bg-color: #f3f4f6;
--el-input-disabled-text-color: #9ca3af;
--el-input-disabled-border-color: #e5e7eb;
@ -65,20 +69,52 @@
--el-textarea-bg-color: #ffffff;
--el-textarea-text-color: #1f2937;
--el-textarea-border-color: #e5e7eb;
--el-textarea-hover-border-color: #1f2937;
--el-textarea-focus-border-color: #1f2937;
--el-textarea-focus-ring-color: rgba(31, 41, 55, 0.15);
--el-textarea-hover-border-color: #3b82f6;
--el-textarea-focus-border-color: #2563eb;
--el-textarea-focus-ring-color: rgba(59, 130, 246, 0.15);
--el-select-bg-color: #ffffff;
--el-select-text-color: #1f2937;
--el-select-border-color-hover: #1f2937;
--el-select-border-color-hover: #3b82f6;
/* Element Plus 主色:教育蓝(复刻源页,保证 checkbox/radio/switch/分页等激活色全站一致) */
--el-color-primary: #2563eb;
--el-color-primary-light-3: #60a5fa;
--el-color-primary-light-5: #93c5fd;
--el-color-primary-light-7: #bfdbfe;
--el-color-primary-light-8: #dbeafe;
--el-color-primary-light-9: #eff6ff;
--el-color-primary-dark-2: #1d4ed8;
--el-fill-color-blank: #ffffff;
--el-border-color: #e5e7eb;
--el-border-color-hover: #1f2937;
--el-border-color-hover: #3b82f6;
--el-border-radius-base: 6px;
}
/*
* 考试考核 / 实训报告 / BI 可视化页不在 .student-training-shell 内,
* 单独接管 Element Plus 主色,保证勾选框、单选、分页等激活色同为教育蓝。
*/
.student-exams,
.take-page,
.result-page,
.test-report,
.visual-analysis {
--el-color-primary: #2563eb;
--el-color-primary-light-3: #60a5fa;
--el-color-primary-light-5: #93c5fd;
--el-color-primary-light-7: #bfdbfe;
--el-color-primary-light-8: #dbeafe;
--el-color-primary-light-9: #eff6ff;
--el-color-primary-dark-2: #1d4ed8;
--el-input-hover-border-color: #3b82f6;
--el-input-focus-border-color: #2563eb;
--el-input-focus-ring-color: rgba(59, 130, 246, 0.15);
--el-textarea-hover-border-color: #3b82f6;
--el-textarea-focus-border-color: #2563eb;
}
/*
* The app-main padding around a student training page is part of the page
* canvas. It must blend into the training canvas instead of exposing the
@ -86,13 +122,18 @@
*/
#app .studentLayout .app-main:has(.student-training-shell),
#app .teacherLayout .app-main:has(.student-training-shell),
#app .studentLayout .app-main:has(.student-home) {
background: linear-gradient(135deg, #f5f8fc 0%, #eaf2fb 52%, #f3f8ff 100%) !important;
#app .studentLayout .app-main:has(.student-home),
#app .studentLayout .app-main:has(.student-exams),
#app .studentLayout .app-main:has(.take-page),
#app .studentLayout .app-main:has(.result-page),
#app .studentLayout .app-main:has(.test-report),
#app .studentLayout .app-main:has(.visual-analysis) {
background: #ffffff !important;
}
/* 教师端亮色主题:实训页背景改为浅色,与学生端统一浅色风格 */
/* 教师端亮色主题:实训页背景改为纯白,与学生端统一 */
#app .teacherLayout .app-main:has(.student-training-shell) {
background: linear-gradient(135deg, #f5f8fc 0%, #eaf2fb 52%, #f3f8ff 100%) !important;
background: #ffffff !important;
}
#app .studentLayout .app-main:has(.student-training-shell) .student-training-shell,
@ -108,8 +149,7 @@
min-height: calc(100vh - 90px) !important;
margin: 0 !important;
/* padding 由架构标签 .app-main 提供(sidebar.scss 中 28px 32px 40px 24px),子页面根标签不再叠加 */
// padding: 10px 10px 16px !important;
// padding: 10px 10px 16px !important;
padding: 0 !important;
background: #ffffff !important;
/* 应用实训页专用字体栈 + 数字等宽对齐 */
font-family: var(--student-font-base) !important;
@ -135,26 +175,39 @@
*/
.student-training-shell > main {
min-width: 0 !important;
/* 复刻 new-product-survey:core 为透明网格层,无独立卡片盒模型 */
padding: 14px !important;
border: 0 !important;
border-radius: 20px !important;
background: transparent !important;
box-shadow: none !important;
}
.student-training-shell > main > .task-card,
.student-training-shell > main > .process-workbench,
.student-training-shell > main > .factors-workbench,
.student-training-shell > main > .workbench {
/* 复刻 new-product-survey .task-card:透明工作区,仅内容内缩,不画卡片 */
margin: 0 !important;
padding: 10px 12px !important;
border: 0 !important;
border-radius: 16px !important;
background: transparent !important;
box-shadow: none !important;
}
#app .studentLayout .app-main:has(.student-training-shell) .student-training-shell.product-process .process-workbench {
margin: 0 !important;
padding: 10px 12px !important;
border: 0 !important;
border-radius: 16px !important;
background: transparent !important;
box-shadow: none !important;
}
#app .studentLayout .app-main:has(.student-training-shell) .student-training-shell.product-process .process-step-card {
padding: 12px !important;
border-radius: 16px !important;
border-radius: 12px !important;
}
#app .studentLayout .app-main:has(.student-training-shell) .student-training-shell.product-process .task-header {
@ -178,15 +231,45 @@
.student-training-shell .step-card,
.student-training-shell .process-step-card,
.student-training-shell .factor-step-card {
/* 复刻 new-product-survey .step-card:白卡 12px 内边距、12px 圆角 */
margin: 0 !important;
padding: 12px !important;
border-radius: 16px !important;
padding: 12px !important;
border-radius: 16px !important;
border: 1px solid var(--student-panel-border) !important;
border-radius: 12px !important;
background: var(--student-card-bg) !important;
box-shadow: none !important;
}
/* ============================================================
* task-header 统一(复刻 new-product-survey:
* padding 18px 20px 18px 24px、12px 圆角、白卡、左侧 4px 教育蓝竖条)
* ============================================================ */
.student-training-shell .task-header {
margin-bottom: 12px !important;
margin-bottom: 12px !important;
position: relative !important;
margin: 0 0 12px !important;
padding: 18px 20px 18px 24px !important;
border: 1px solid var(--student-panel-border) !important;
border-radius: 12px !important;
background: var(--student-card-bg) !important;
box-shadow: none !important;
overflow: hidden !important;
&::before {
content: "" !important;
position: absolute !important;
top: 0 !important;
bottom: 0 !important;
left: 0 !important;
width: 4px !important;
background: var(--student-accent) !important;
}
}
/* 步骤眉标统一教育蓝(部分页面遗留灰色) */
.student-training-shell .section-eyebrow {
color: var(--student-accent) !important;
font-size: var(--student-fs-caption) !important;
font-weight: 700 !important;
}
.student-training-shell .task-header .task-title {
@ -242,8 +325,8 @@
display: flex !important;
flex-wrap: nowrap !important;
align-items: stretch !important;
justify-content: flex-start !important;
gap: 10px !important;
justify-content: center !important;
gap: 0 !important;
width: 100% !important;
max-width: 100% !important;
margin: 4px 0 20px !important;
@ -262,22 +345,28 @@
display: none !important;
}
/* 胶囊分段不需要连接线 */
.student-training-shell .step-indicator .step-connector,
.student-training-shell .comprehensive-step-strip .step-connector {
display: none !important;
}
.student-training-shell .flow-pill,
.student-training-shell .step-tab {
flex: 0 0 auto !important;
min-width: auto !important;
max-width: none !important;
flex: 1 1 0 !important;
max-width: 240px !important;
display: flex !important;
flex-direction: row !important;
align-items: center !important;
justify-content: center !important;
gap: 8px !important;
height: auto !important;
min-height: 42px !important;
min-height: 40px !important;
margin: 0 !important;
padding: 8px 14px !important;
border: 1px solid #e5e7eb !important;
border-radius: 8px !important;
border-right: none !important;
border-radius: 0 !important;
background: #ffffff !important;
box-shadow: none !important;
color: #6b7280 !important;
@ -285,11 +374,19 @@
font-weight: 600 !important;
line-height: 1.3 !important;
letter-spacing: 0 !important;
white-space: nowrap !important;
white-space: normal !important;
text-align: center !important;
cursor: pointer;
transition: background-color .16s ease, color .16s ease, border-color .16s ease !important;
&:first-child {
border-radius: 8px 0 0 8px !important;
}
&:last-child {
border-radius: 0 8px 8px 0 !important;
border-right: 1px solid #e5e7eb !important;
}
.step-bar { display: none !important; }
.step-no,
@ -318,32 +415,33 @@
.student-training-shell .flow-pill:hover:not(.active):not(.complete),
.student-training-shell .step-tab:hover:not(.active):not(.complete) {
border-color: #1f2937 !important;
background: #f9fafb !important;
color: #1f2937 !important;
border-color: #2563eb !important;
background: #eff6ff !important;
color: #2563eb !important;
z-index: 1 !important;
.step-no,
&:has(.step-no) .step-no {
background: #1f2937 !important;
background: #2563eb !important;
color: #ffffff !important;
}
}
.student-training-shell .flow-pill.complete:not(.active),
.student-training-shell .step-tab.complete:not(.active) {
border-color: #dce9e2 !important;
border-color: #e5e7eb !important;
color: #374151 !important;
.step-no,
&:has(.step-no) .step-no {
background: rgba(74,157,110,.12) !important;
color: #3f8a5f !important;
background: rgba(43, 164, 113, 0.12) !important;
color: #16915f !important;
}
&:hover {
border-color: #4a9d6e !important;
background: #f9fafb !important;
color: #374151 !important;
border-color: #2ba471 !important;
background: #f0fdf6 !important;
z-index: 1 !important;
.step-no,
&:has(.step-no) .step-no {
background: #4a9d6e !important;
background: #2ba471 !important;
color: #ffffff !important;
}
}
@ -351,22 +449,29 @@
.student-training-shell .flow-pill.active,
.student-training-shell .step-tab.active {
border-color: #1f2937 !important;
background: #1f2937 !important;
border-color: #2563eb !important;
background: #2563eb !important;
color: #ffffff !important;
font-weight: 700 !important;
box-shadow: 0 2px 6px rgba(31,41,55,.16) !important;
box-shadow: none !important;
z-index: 2 !important;
.step-no,
&:has(.step-no) .step-no {
background: #ffffff !important;
color: #1f2937 !important;
color: #2563eb !important;
}
&:hover {
background: #111827 !important;
border-color: #111827 !important;
background: #1d4ed8 !important;
border-color: #1d4ed8 !important;
}
}
/* 综合实训导航(GenericTrainingPage):步骤多、可拖动,tab 固定宽,视觉沿用胶囊 */
.student-training-shell .comprehensive-step-strip .step-tab {
flex: 0 0 190px !important;
max-width: 190px !important;
}
/* 窄屏步骤导航横向滑动 */
@media (max-width: 900px) {
.student-training-shell .step-indicator {
@ -376,8 +481,9 @@
}
.student-training-shell .step-tab,
.student-training-shell .flow-pill {
flex: 0 0 auto !important;
min-width: 140px !important;
flex: 0 0 140px !important;
min-width: 0 !important;
max-width: none !important;
}
}
@ -526,10 +632,10 @@
height: 40px !important;
min-height: 40px !important;
padding: 0 18px !important;
border: 1px solid #1f2937 !important;
border: 1px solid var(--student-accent, #1f2937) !important;
border-radius: 10px !important;
color: #ffffff !important;
background: #1f2937 !important;
background: var(--student-accent, #1f2937) !important;
box-shadow: 0 2px 6px rgba(31,41,55,.16) !important;
font-size: var(--student-fs-body) !important;
font-weight: 700 !important;
@ -538,8 +644,8 @@
}
.training-step-area .el-button:hover {
background: #111827 !important;
border-color: #111827 !important;
background: var(--student-accent-deep, #111827) !important;
border-color: var(--student-accent-deep, #111827) !important;
}
.training-step-area .el-button span {
@ -565,16 +671,16 @@
justify-content: center !important;
min-width: 112px !important;
width: auto !important;
height: 40px !important;
min-height: 40px !important;
padding: 0 18px !important;
border: 1px solid #e5e7eb !important;
border-radius: 10px !important;
color: #1f2937 !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
box-shadow: none !important;
font-size: var(--student-fs-body) !important;
font-weight: 700 !important;
font-weight: 600 !important;
line-height: 1 !important;
letter-spacing: 0 !important;
cursor: pointer;
@ -589,26 +695,26 @@
.student-training-shell .training-actions .el-button.training-action:hover:not(.is-disabled),
.student-training-shell .training-actions button.training-action:hover:not(:disabled) {
border-color: #1f2937 !important;
color: #1f2937 !important;
background: #f9fafb !important;
border-color: #2563eb !important;
color: #2563eb !important;
background: #eff6ff !important;
transform: translateY(-1px) !important;
box-shadow: 0 3px 10px rgba(31,41,55,.14) !important;
box-shadow: 0 2px 6px rgba(37, 99, 235, .12) !important;
}
.student-training-shell .training-actions .el-button.training-action.primary,
.student-training-shell .training-actions button.training-action.primary {
border: 1px solid #1f2937 !important;
border: 1px solid #2563eb !important;
color: #ffffff !important;
background: #1f2937 !important;
box-shadow: 0 2px 6px rgba(31,41,55,.16) !important;
background: #2563eb !important;
box-shadow: 0 2px 6px rgba(37, 99, 235, .2) !important;
}
.student-training-shell .training-actions .el-button.training-action.primary:hover:not(.is-disabled),
.student-training-shell .training-actions button.training-action.primary:hover:not(:disabled) {
background: #111827 !important;
border-color: #111827 !important;
box-shadow: 0 4px 12px rgba(31,41,55,.24) !important;
background: #1d4ed8 !important;
border-color: #1d4ed8 !important;
box-shadow: 0 4px 12px rgba(29, 78, 216, .24) !important;
}
.student-training-shell .training-actions .el-button.training-action.is-disabled,
@ -638,7 +744,7 @@
min-height: var(--student-action-height) !important;
padding: 0 16px !important;
font-size: var(--student-action-font) !important;
font-weight: 800 !important;
font-weight: 600 !important;
line-height: 1 !important;
}
@ -658,7 +764,7 @@
min-height: var(--student-action-height) !important;
padding: 0 16px !important;
font-size: var(--student-action-font) !important;
font-weight: 800 !important;
font-weight: 600 !important;
line-height: 1 !important;
}
@ -674,42 +780,42 @@
.student-training-shell .training-actions button.training-action,
.student-training-shell .task-actions > button,
.student-training-shell .taskfooter .el-button {
border: 1px solid rgba(31, 41, 55, 0.4) !important;
border-radius: 10px !important;
color: var(--student-text, #1f2937) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
font-weight: 700 !important;
font-weight: 600 !important;
}
.student-training-shell .training-actions .training-action--submit,
.student-training-shell .task-actions > .btn-submit,
.student-training-shell .task-actions > .btn-primary,
.student-training-shell .taskfooter .el-button:first-child {
border-color: var(--student-accent, #1f2937) !important;
border-color: #2563eb !important;
color: #ffffff !important;
background: var(--student-accent, #1f2937) !important;
box-shadow: 0 3px 10px rgba(31, 41, 55, 0.28) !important;
background: #2563eb !important;
box-shadow: 0 3px 10px rgba(37, 99, 235, 0.28) !important;
}
.student-training-shell .training-actions button.training-action:hover:not(:disabled),
.student-training-shell .task-actions > button:hover:not(:disabled),
.student-training-shell .taskfooter .el-button:hover:not(.is-disabled) {
border-color: var(--student-accent, #1f2937) !important;
background: var(--student-accent-soft, #f3f4f6) !important;
color: var(--student-accent, #1f2937) !important;
border-color: #2563eb !important;
background: #eff6ff !important;
color: #2563eb !important;
transform: translateY(-1px) !important;
box-shadow: 0 3px 10px rgba(31, 41, 55, 0.12) !important;
box-shadow: 0 2px 6px rgba(37, 99, 235, 0.12) !important;
}
.student-training-shell .training-actions .training-action--submit:hover:not(:disabled),
.student-training-shell .task-actions > .btn-primary:hover:not(:disabled),
.student-training-shell .task-actions > .btn-submit:hover:not(:disabled),
.student-training-shell .taskfooter .el-button:first-child:hover:not(.is-disabled) {
border-color: var(--student-accent-deep, #111827) !important;
background: var(--student-accent-deep, #111827) !important;
border-color: #1d4ed8 !important;
background: #1d4ed8 !important;
color: #ffffff !important;
transform: translateY(-1px) !important;
box-shadow: 0 5px 14px rgba(17, 24, 39, 0.32) !important;
box-shadow: 0 5px 14px rgba(29, 78, 216, 0.32) !important;
}
.student-training-shell .task-actions > button .el-icon {
@ -728,16 +834,16 @@
gap: 8px !important;
min-width: 0 !important;
width: auto !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(31, 41, 55, 0.4) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: var(--student-accent, #1f2937) !important;
color: #2563eb !important;
background: #ffffff !important;
box-shadow: none !important;
font-size: 13px !important;
font-weight: 700 !important;
font-weight: 600 !important;
line-height: 1 !important;
letter-spacing: 0 !important;
transition: border-color 0.16s ease, background 0.16s ease, color 0.16s ease, transform 0.16s ease, box-shadow 0.16s ease !important;
@ -750,10 +856,10 @@
.student-training-shell button.outline-action:hover:not(:disabled),
.student-training-shell .workbench-actions button.material-download:hover:not(:disabled) {
transform: translateY(-1px) !important;
border-color: var(--student-accent, #1f2937) !important;
color: var(--student-accent, #1f2937) !important;
background: var(--student-accent-soft, #f3f4f6) !important;
box-shadow: 0 3px 10px rgba(31, 41, 55, 0.12) !important;
border-color: #2563eb !important;
color: #2563eb !important;
background: #eff6ff !important;
box-shadow: 0 2px 6px rgba(37, 99, 235, 0.12) !important;
}
/*
@ -790,27 +896,27 @@
flex: 0 0 auto !important;
min-width: 0 !important;
width: auto !important;
height: 36px !important;
min-height: 36px !important;
max-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
max-height: 34px !important;
margin: 0 !important;
padding: 0 14px !important;
border: 1px solid #e5e7eb !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #1f2937 !important;
color: #2563eb !important;
background: #ffffff !important;
font-size: 13px !important;
font-weight: 700 !important;
font-weight: 600 !important;
line-height: 1 !important;
white-space: nowrap !important;
cursor: pointer;
transition: background-color .16s ease, border-color .16s ease, transform .16s ease, box-shadow .16s ease !important;
&:hover {
border-color: #1f2937 !important;
background: #f9fafb !important;
color: #1f2937 !important;
border-color: #2563eb !important;
background: #eff6ff !important;
color: #2563eb !important;
transform: translateY(-1px) !important;
box-shadow: 0 3px 10px rgba(31,41,55,.14) !important;
box-shadow: 0 2px 6px rgba(37, 99, 235, .12) !important;
}
}
@ -825,22 +931,22 @@
gap: 8px !important;
min-width: 0 !important;
width: auto !important;
height: 40px !important;
min-height: 40px !important;
padding: 0 18px !important;
border: 1px solid #1f2937 !important;
border-radius: 10px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid #2563eb !important;
border-radius: 8px !important;
color: #ffffff !important;
background: #1f2937 !important;
box-shadow: 0 2px 6px rgba(31,41,55,.16) !important;
background: #2563eb !important;
box-shadow: 0 2px 6px rgba(37, 99, 235, .2) !important;
font-size: var(--student-upload-font) !important;
font-weight: 700 !important;
font-weight: 600 !important;
line-height: 1 !important;
letter-spacing: 0 !important;
white-space: nowrap !important;
&:hover {
background: #111827 !important;
border-color: #111827 !important;
background: #1d4ed8 !important;
border-color: #1d4ed8 !important;
}
}
@ -909,9 +1015,9 @@
.legacy-training-page .top_item .el-button.active,
.legacy-training-page .top_item .active {
transform: none !important;
border-color: #1f2937 !important;
border-color: var(--student-accent, #1f2937) !important;
color: #ffffff !important;
background: #1f2937 !important;
background: var(--student-accent, #1f2937) !important;
}
// Keep long step names inside the navigation rail. Their complete name remains
@ -1242,3 +1348,138 @@ body.student-light-mode {
&:hover, &.is-focus { border-color: #1f2937 !important; box-shadow: 0 0 0 2px rgba(31, 41, 55, 0.1) !important; }
}
}
/* ============================================================
* Legacy 实训页 · 教育蓝主题
* 适用:根元素带 .legacy-training-page 的旧版式学生实训页
* (demand/user、test/channel、test/marketing、assessment/index)
* 令牌复刻 foundation/new-product-survey.vue 的教育蓝主题。
* 页面内写死墨黑的全局规则(training-step-area 按钮、top_item active、
* training-actions 提交按钮等)均已变量化,读取此处令牌自动转蓝。
* ============================================================ */
#app .studentLayout .app-main:has(.legacy-training-page) .legacy-training-page,
#app .teacherLayout .app-main:has(.legacy-training-page) .legacy-training-page {
/* 主色:教育蓝 */
--student-accent: #2563eb;
--student-accent-deep: #1d4ed8;
--student-accent-light: #3b82f6;
--student-accent-soft: #eff6ff;
--student-accent-border: #bfdbfe;
--student-shadow-color: rgba(15, 23, 42, 0.08);
/* 语义色 */
--student-danger: #ef4444;
--student-success: #2ba471;
/* 三层次标识色 */
--student-layer-1: #1d4ed8;
--student-layer-2: #3b82f6;
--student-layer-3: #93c5fd;
/* Element Plus 主色:教育蓝 */
--el-color-primary: #2563eb;
--el-color-primary-light-3: #60a5fa;
--el-color-primary-light-5: #93c5fd;
--el-color-primary-light-7: #bfdbfe;
--el-color-primary-light-8: #dbeafe;
--el-color-primary-light-9: #eff6ff;
--el-color-primary-dark-2: #1d4ed8;
--el-input-hover-border-color: #3b82f6;
--el-input-focus-border-color: #2563eb;
--el-input-focus-ring-color: rgba(59, 130, 246, 0.15);
--el-textarea-hover-border-color: #3b82f6;
--el-textarea-focus-border-color: #2563eb;
/* 紧凑字号梯度:与 new-product-survey 一致(11→17px) */
--student-fs-display: 17px;
--student-fs-h1: 15px;
--student-fs-h2: 14px;
--student-fs-h3: 13px;
--student-fs-body: 13px;
--student-fs-body-sm: 12px;
--student-fs-caption: 11px;
--student-fs-button: 13px;
--student-fs-button-lg: 13px;
--student-fs-data: 14px;
}
/* legacy 页顶部工具栏按钮(TrainingTaskToolbar):教育蓝统一,
覆盖组件 scoped 的暗色默认样式 */
#app .studentLayout .app-main:has(.legacy-training-page) .legacy-training-page .task-toolbar-button.el-button,
#app .teacherLayout .app-main:has(.legacy-training-page) .legacy-training-page .task-toolbar-button.el-button {
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
min-height: 34px !important;
height: 34px !important;
padding: 0 12px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
box-shadow: none !important;
text-shadow: none !important;
font-size: 13px !important;
font-weight: 600 !important;
transition: all 0.16s ease !important;
}
#app .studentLayout .app-main:has(.legacy-training-page) .legacy-training-page .task-toolbar-button.el-button .el-icon,
#app .teacherLayout .app-main:has(.legacy-training-page) .legacy-training-page .task-toolbar-button.el-button .el-icon {
font-size: 14px !important;
color: inherit !important;
}
#app .studentLayout .app-main:has(.legacy-training-page) .legacy-training-page .task-toolbar-button.el-button:hover,
#app .studentLayout .app-main:has(.legacy-training-page) .legacy-training-page .task-toolbar-button.el-button:focus,
#app .teacherLayout .app-main:has(.legacy-training-page) .legacy-training-page .task-toolbar-button.el-button:hover,
#app .teacherLayout .app-main:has(.legacy-training-page) .legacy-training-page .task-toolbar-button.el-button:focus {
border-color: #2563eb !important;
color: #2563eb !important;
background: #eff6ff !important;
transform: translateY(-1px) !important;
box-shadow: 0 2px 6px rgba(37, 99, 235, 0.12) !important;
}
#app .studentLayout .app-main:has(.legacy-training-page) .legacy-training-page .task-toolbar-button--submit.el-button,
#app .teacherLayout .app-main:has(.legacy-training-page) .legacy-training-page .task-toolbar-button--submit.el-button {
border-color: #2563eb !important;
color: #ffffff !important;
background: #2563eb !important;
box-shadow: 0 1px 2px rgba(37, 99, 235, 0.2), 0 2px 8px rgba(37, 99, 235, 0.15) !important;
}
#app .studentLayout .app-main:has(.legacy-training-page) .legacy-training-page .task-toolbar-button--submit.el-button:hover,
#app .studentLayout .app-main:has(.legacy-training-page) .legacy-training-page .task-toolbar-button--submit.el-button:focus,
#app .teacherLayout .app-main:has(.legacy-training-page) .legacy-training-page .task-toolbar-button--submit.el-button:hover,
#app .teacherLayout .app-main:has(.legacy-training-page) .legacy-training-page .task-toolbar-button--submit.el-button:focus {
border-color: #1d4ed8 !important;
color: #ffffff !important;
background: #1d4ed8 !important;
box-shadow: 0 2px 6px rgba(29, 78, 216, 0.3), 0 4px 12px rgba(29, 78, 216, 0.22) !important;
}
#app .studentLayout .app-main:has(.legacy-training-page) .legacy-training-page .training-task-toolbar .material-button.el-button,
#app .teacherLayout .app-main:has(.legacy-training-page) .legacy-training-page .training-task-toolbar .material-button.el-button {
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
min-height: 34px !important;
height: 34px !important;
padding: 0 12px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
box-shadow: none !important;
font-size: 13px !important;
font-weight: 600 !important;
transition: all 0.16s ease !important;
}
#app .studentLayout .app-main:has(.legacy-training-page) .legacy-training-page .training-task-toolbar .material-button.el-button:hover,
#app .teacherLayout .app-main:has(.legacy-training-page) .legacy-training-page .training-task-toolbar .material-button.el-button:hover {
border-color: #2563eb !important;
color: #2563eb !important;
background: #eff6ff !important;
transform: translateY(-1px) !important;
box-shadow: 0 2px 6px rgba(37, 99, 235, 0.12) !important;
}

@ -198,7 +198,7 @@ onMounted(() => {
});
</script>
<style lang="scss" scoped>
/* 墨黑极简:纯白画布、杂志章节式头部、白底描边分析卡片 */
/* 教育蓝 · 精炼文档风:纯白画布 + 教育蓝点缀(对齐 new-product-survey) */
.stu-analysis-page {
box-sizing: border-box;
width: 100%;
@ -214,7 +214,7 @@ onMounted(() => {
.analysis-eyebrow {
display: block;
margin-bottom: 8px;
color: #6b7280;
color: #2563eb;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.16em;
@ -262,7 +262,7 @@ onMounted(() => {
.card-no {
flex: 0 0 auto;
color: #1f2937;
color: #1d4ed8;
font-family: "SF Mono", "JetBrains Mono", Consolas, monospace;
font-size: 30px;
font-weight: 700;
@ -304,13 +304,13 @@ onMounted(() => {
}
&:hover {
border-color: #1f2937;
box-shadow: 0 6px 18px rgba(17, 24, 39, 0.08);
border-color: #2563eb;
box-shadow: 0 6px 18px rgba(37, 99, 235, 0.1);
transform: translateY(-2px);
.card-arrow {
border-color: #1f2937;
background: #1f2937;
border-color: #2563eb;
background: #2563eb;
color: #ffffff;
}
}

@ -188,12 +188,12 @@ function exportTeachingPlan(item) {
const documentHtml = `<!DOCTYPE html><html><head><meta charset="utf-8"><style>
@page { size: A4; margin: 20mm; }
body { color: #1f2937; font-family: "Microsoft YaHei", Arial, sans-serif; font-size: 11pt; line-height: 1.7; }
h1 { margin: 0 0 20px; color: #0f4c81; font-size: 20pt; }
h2, h3 { color: #0f4c81; }
h1 { margin: 0 0 20px; color: #1d4ed8; font-size: 20pt; }
h2, h3 { color: #1d4ed8; }
table { width: 100%; margin: 14px 0; border-collapse: collapse; table-layout: fixed; }
th, td { padding: 8px 10px; border: 1px solid #8ca7c1; vertical-align: top; word-break: break-word; }
th { color: #102a43; background: #dceeff; font-weight: 700; }
pre { padding: 12px; overflow-wrap: break-word; white-space: pre-wrap; background: #f4f7fa; }
th, td { padding: 8px 10px; border: 1px solid #93c5fd; vertical-align: top; word-break: break-word; }
th { color: #1f2937; background: #dbeafe; font-weight: 700; }
pre { padding: 12px; overflow-wrap: break-word; white-space: pre-wrap; background: #eff6ff; }
img { max-width: 100%; }
</style></head><body><h1>AI 实训教案</h1>${marked.parse(item.content, { gfm: true, breaks: true })}</body></html>`;
const blob = new Blob(["\ufeff", documentHtml], { type: "application/msword;charset=utf-8" });
@ -268,7 +268,7 @@ const exportData = () => {
};
</script>
<style lang="scss" scoped>
/* 墨黑极简:纯白画布、白卡片气泡、墨黑发送按钮、非胶囊输入区 */
/* 教育蓝 · 精炼文档风:纯白画布、白卡片气泡、教育蓝发送按钮(对齐 new-product-survey) */
.ai-dialogue-page {
display: flex;
flex-direction: column;
@ -303,15 +303,15 @@ const exportData = () => {
transition: all 0.16s ease;
&:hover {
border-color: #1f2937;
background: #1f2937;
border-color: #2563eb;
background: #2563eb;
color: #ffffff;
}
}
.head-eyebrow {
display: block;
color: #6b7280;
color: #2563eb;
font-size: 10px;
font-weight: 700;
letter-spacing: 0.14em;
@ -346,7 +346,7 @@ const exportData = () => {
}
}
/* 用户消息:右侧墨黑气泡 */
/* 用户消息:右侧教育蓝气泡 */
.questionItem {
display: flex;
justify-content: flex-end;
@ -357,9 +357,9 @@ const exportData = () => {
.msg-bubble {
padding: 10px 14px;
border: 1px solid #1f2937;
border: 1px solid #2563eb;
border-radius: 12px 12px 2px 12px;
background: #1f2937;
background: #2563eb;
color: #ffffff;
font-size: 13px;
line-height: 1.6;
@ -451,7 +451,7 @@ const exportData = () => {
}
:deep(a) {
color: #1f2937;
color: #2563eb;
text-decoration: underline;
}
@ -465,7 +465,7 @@ const exportData = () => {
}
:deep(blockquote) {
border-left: 3px solid #1f2937;
border-left: 3px solid #2563eb;
color: #6b7280;
}
@ -505,8 +505,8 @@ const exportData = () => {
}
&:hover {
border-color: #1f2937;
background: #1f2937;
border-color: #2563eb;
background: #2563eb;
.svg-icon {
fill: #ffffff;
@ -609,11 +609,11 @@ const exportData = () => {
}
&:hover {
border-color: #1f2937;
background: #f9fafb;
border-color: #2563eb;
background: #eff6ff;
.svg-icon {
fill: #1f2937;
fill: #2563eb;
}
}
}
@ -625,9 +625,9 @@ const exportData = () => {
width: 36px;
height: 36px;
padding: 0;
border: 1px solid #1f2937;
border: 1px solid #2563eb;
border-radius: 9px;
background: #1f2937;
background: #2563eb;
cursor: pointer;
transition: all 0.16s ease;
@ -638,8 +638,8 @@ const exportData = () => {
}
&:hover {
background: #111827;
border-color: #111827;
background: #1d4ed8;
border-color: #1d4ed8;
}
/* 生成中:中断按钮改白底描边 */

@ -3,7 +3,6 @@
<main class="diagnosis-core">
<section class="task-header">
<div class="task-head-main">
<span class="task-badge"><el-icon><DataAnalysis /></el-icon> 核心实训 · 产品上线与运营推广</span>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -413,18 +412,6 @@ onMounted(async () => { try { taskConfig.value = (await getTrainingTaskByKey(TAS
flex: 1 1 auto;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
}
.task-title {
margin: 0;
@ -553,7 +540,7 @@ onMounted(async () => { try { taskConfig.value = (await getTrainingTaskByKey(TAS
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-text);
background: #ffffff;
@ -590,7 +577,7 @@ onMounted(async () => { try { taskConfig.value = (await getTrainingTaskByKey(TAS
}
.table-button.ghost {
border-color: rgba(37, 99, 235, 0.45);
border-color: rgba(37, 99, 235, 0.35);
color: var(--student-text-secondary);
background: #ffffff;
font-weight: 600;
@ -1083,13 +1070,13 @@ button.is-disabled {
</style>
<style lang="scss">
/* ===== 步骤导航:按钮切换风 ===== */
/* ===== 步骤导航:分段连接胶囊(教育蓝) ===== */
#app .studentLayout section.app-main:has(.diagnosis-page) .step-indicator {
display: flex !important;
flex-wrap: nowrap !important;
align-items: stretch !important;
justify-content: center !important;
gap: 10px !important;
gap: 0 !important;
width: 100% !important;
margin: 4px 0 16px !important;
padding: 0 !important;
@ -1101,20 +1088,27 @@ button.is-disabled {
.step-connector { display: none !important; }
.step-tab {
flex: 0 0 auto !important;
min-width: auto !important;
max-width: none !important;
flex: 1 1 0 !important;
min-width: 0 !important;
max-width: 240px !important;
display: flex !important;
flex-direction: row !important;
align-items: center !important;
justify-content: center !important;
gap: 8px !important;
height: auto !important;
min-height: 42px !important;
min-height: 40px !important;
margin: 0 !important;
padding: 8px 14px !important;
border: 1px solid #e5e7eb !important;
border-radius: 8px !important;
border-right: none !important;
border-radius: 0 !important;
&:first-child { border-radius: 8px 0 0 8px !important; }
&:last-child {
border-radius: 0 8px 8px 0 !important;
border-right: 1px solid #e5e7eb !important;
}
background: #ffffff !important;
box-shadow: none !important;
color: #6b7280 !important;
@ -1171,6 +1165,7 @@ button.is-disabled {
border-color: #2563eb !important;
background: #eff6ff !important;
color: #2563eb !important;
z-index: 1 !important;
.step-marker { background: #2563eb !important; color: #ffffff !important; }
}
@ -1182,6 +1177,7 @@ button.is-disabled {
&:hover {
border-color: #2ba471 !important;
background: #f0fdf6 !important;
z-index: 1 !important;
.step-marker { background: #2ba471 !important; color: #ffffff !important; }
}
}
@ -1192,6 +1188,8 @@ button.is-disabled {
background: #2563eb !important;
color: #ffffff !important;
font-weight: 700 !important;
box-shadow: none !important;
z-index: 2 !important;
.step-marker { background: #ffffff !important; color: #2563eb !important; }
&:hover {
background: #1d4ed8 !important;
@ -1205,11 +1203,10 @@ button.is-disabled {
@media (max-width: 900px) {
#app .studentLayout section.app-main:has(.diagnosis-page) .step-indicator {
justify-content: flex-start !important;
gap: 8px !important;
overflow-x: auto !important;
}
#app .studentLayout section.app-main:has(.diagnosis-page) .step-indicator .step-tab {
flex: 0 0 auto !important;
flex: 0 0 140px !important;
max-width: none !important;
}
}
@ -1225,7 +1222,7 @@ button.is-disabled {
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: #2563eb;
background: #ffffff;
@ -1263,7 +1260,7 @@ button.is-disabled {
}
.diagnosis-page .task-toolbar-button.el-button.is-loading {
border-color: rgba(37, 99, 235, 0.45);
border-color: rgba(37, 99, 235, 0.35);
color: #2563eb;
background: #ffffff;
}

@ -71,9 +71,9 @@
border
style="width: 60%; margin-top: 10px"
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#1e88e5!important',
color: '#6b7280',
fontSize: '12px',
backgroundColor: '#f9fafb',
}"
>
<el-table-column prop="name" label="指标" align="center"></el-table-column>
@ -87,9 +87,9 @@
border
style="width: 40%; margin-top: 10px"
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#1e88e5!important',
color: '#6b7280',
fontSize: '12px',
backgroundColor: '#f9fafb',
}"
>
<el-table-column prop="indicator" label="指标" align="center"></el-table-column>
@ -105,9 +105,9 @@
border
style="width: 40%; margin-top: 10px"
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#1e88e5!important',
color: '#6b7280',
fontSize: '12px',
backgroundColor: '#f9fafb',
}"
>
<el-table-column prop="indicator" label="指标" align="center"></el-table-column>
@ -123,9 +123,9 @@
border
style="width: 40%; margin-top: 10px"
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#1e88e5!important',
color: '#6b7280',
fontSize: '12px',
backgroundColor: '#f9fafb',
}"
>
<el-table-column prop="indicator" label="指标" align="center"></el-table-column>

@ -3,7 +3,6 @@
<main class="optimization-core">
<section class="task-header">
<div class="task-head-main">
<span class="task-badge"><el-icon><TrendCharts /></el-icon>核心实训 · 产品上线与运营推广</span>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -414,6 +413,8 @@ onMounted(async () => {
--student-accent-deep: #1d4ed8;
--student-accent-light: #3b82f6;
--student-accent-soft: #eff6ff;
--student-accent-border: #bfdbfe;
--student-shadow-color: rgba(15, 23, 42, 0.08);
--student-danger: #ef4444;
--student-success: #2ba471;
--student-layer-1: #1d4ed8;
@ -471,20 +472,6 @@ onMounted(async () => {
flex: 1 1 auto;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
text-transform: none;
letter-spacing: 0;
}
.task-title {
margin: 0;
@ -589,7 +576,7 @@ onMounted(async () => {
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-text);
background: #ffffff;
@ -1105,13 +1092,13 @@ button:disabled {
</style>
<style lang="scss">
/* ===== 步骤导航:按钮切换风 ===== */
/* ===== 步骤导航:分段连接胶囊(教育蓝) ===== */
#app .studentLayout section.app-main:has(.optimization-page) .step-indicator {
display: flex !important;
flex-wrap: nowrap !important;
align-items: stretch !important;
justify-content: center !important;
gap: 10px !important;
gap: 0 !important;
width: 100% !important;
margin: 4px 0 16px !important;
padding: 0 !important;
@ -1124,20 +1111,27 @@ button:disabled {
.step-connector { display: none !important; }
.step-tab {
flex: 0 0 auto !important;
min-width: auto !important;
max-width: none !important;
flex: 1 1 0 !important;
min-width: 0 !important;
max-width: 240px !important;
display: flex !important;
flex-direction: row !important;
align-items: center !important;
justify-content: center !important;
gap: 8px !important;
height: auto !important;
min-height: 42px !important;
min-height: 40px !important;
margin: 0 !important;
padding: 8px 14px !important;
border: 1px solid #e5e7eb !important;
border-radius: 8px !important;
border-right: none !important;
border-radius: 0 !important;
&:first-child { border-radius: 8px 0 0 8px !important; }
&:last-child {
border-radius: 0 8px 8px 0 !important;
border-right: 1px solid #e5e7eb !important;
}
background: #ffffff !important;
box-shadow: none !important;
color: #6b7280 !important;
@ -1176,6 +1170,7 @@ button:disabled {
border-color: #2563eb !important;
background: #eff6ff !important;
color: #2563eb !important;
z-index: 1 !important;
span { background: #2563eb !important; color: #ffffff !important; }
}
@ -1187,6 +1182,7 @@ button:disabled {
&:hover {
border-color: #2ba471 !important;
background: #f0fdf6 !important;
z-index: 1 !important;
span { background: #2ba471 !important; color: #ffffff !important; }
}
}
@ -1197,6 +1193,8 @@ button:disabled {
background: #2563eb !important;
color: #ffffff !important;
font-weight: 700 !important;
box-shadow: none !important;
z-index: 2 !important;
span { background: #ffffff !important; color: #2563eb !important; }
&:hover {
background: #1d4ed8 !important;
@ -1210,11 +1208,10 @@ button:disabled {
@media (max-width: 900px) {
#app .studentLayout section.app-main:has(.optimization-page) .step-indicator {
justify-content: flex-start !important;
gap: 8px !important;
overflow-x: auto !important;
}
#app .studentLayout section.app-main:has(.optimization-page) .step-indicator .step-tab {
flex: 0 0 auto !important;
flex: 0 0 140px !important;
max-width: none !important;
}
}

@ -1,12 +1,8 @@
<template>
<template>
<div class="channel student-training-shell">
<main class="training-core">
<section class="task-header">
<div class="task-head-main">
<div class="task-head-top">
<span class="task-badge"><el-icon><TrendCharts /></el-icon> 产品开发与测试验证</span>
<span class="task-status">进行中 · Step {{ String(activeStep).padStart(2, "0") }}</span>
</div>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -975,10 +971,6 @@ onMounted(async () => {
.training-core { min-width: 0; padding: 28px; border: 1px solid var(--student-panel-border); border-radius: 36px; background: var(--student-card-bg); box-shadow: 0 6px 18px rgba(0,0,0,.06); }
.task-header { position: relative; display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin: 0; padding: 18px 20px 18px 24px; border: 1px solid var(--student-panel-border); border-radius: 12px; background: var(--student-card-bg); overflow: hidden; &::before { content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 4px; background: var(--student-accent); } }
.task-head-main { display: grid; justify-items: start; gap: 8px; min-width: 0; flex: 1 1 auto; }
.task-head-top { display: flex; align-items: center; gap: 10px; flex-wrap: nowrap; margin-bottom: 8px; }
.task-badge { display: inline-flex; align-items: center; gap: 7px; padding: 4px 12px; border: 1px solid var(--student-panel-border); border-radius: 999px; color: var(--student-accent-deep); background: var(--student-accent-soft); font-size: 12px; font-weight: 700; }
.task-status { display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px; border-radius: 999px; color: var(--student-text-secondary); background: #f3f4f6; font-family: var(--student-font-data); font-size: var(--student-fs-caption); font-weight: 600; white-space: nowrap; &::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--student-accent-light); animation: pulse 1.8s ease-in-out infinite; } }
@keyframes pulse { 0%, 100% { opacity: 0.4; } 50% { opacity: 1; } }
.task-title { margin: 0; color: var(--student-text); font-size: var(--student-fs-display); font-weight: 700; line-height: 1.35; }
.task-brief { margin: 0; color: var(--student-text-secondary); font-size: 12px; line-height: 1.6; }
.task-brief-text { display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical; -webkit-line-clamp: 1; }
@ -987,7 +979,7 @@ onMounted(async () => {
.channel-toolbar { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 10px; flex-shrink: 0; }
.task-card,.step-card { border: 1px solid var(--student-panel-border); border-radius: 26px; background: var(--student-card-bg); }.task-card { margin-top: 28px; padding: 18px 22px 22px; }.workbench-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 18px; margin-bottom: 22px; padding-bottom: 18px; border-bottom: 1px solid var(--student-panel-border); }.section-eyebrow { margin: 0; color: var(--student-accent); font-size: var(--student-fs-caption); font-weight: 800; line-height: 1.4; }.workbench-head h3 { margin: 4px 0 8px; color: var(--student-text); font-size: var(--student-fs-h1); font-weight: 800; line-height: 1.3; }.workbench-description { margin: 0; color: var(--student-text-secondary); font-size: var(--student-fs-body); line-height: 1.8; }.workbench-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; margin-left: auto; gap: 10px; flex-shrink: 0; }
.outline-action,.btn-nav { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 36px; height: 36px; padding: 0 14px; border: 1px solid var(--student-panel-border); border-radius: 8px; color: var(--student-text); background: var(--student-accent-soft); font: inherit; font-size: var(--student-fs-button); font-weight: 800; cursor: pointer; }.step-indicator { display:flex; align-items:center; gap:12px; width:calc(100% + 24px); min-height:0; margin:0 -12px 32px; padding:18px 22px; overflow-x:auto; border:1px solid var(--student-panel-border); border-radius:18px; background:var(--student-card-bg); box-shadow:inset 0 1px 0 rgba(31, 41, 55, 0.04); }.step-tab { display:flex; flex:1 0 145px; align-items:center; min-height:66px; padding:8px 10px; border:1px solid var(--student-panel-border); border-radius:8px; color:var(--student-text-secondary); background:var(--student-card-bg); font:inherit; font-size:var(--student-fs-body); font-weight:800; text-align:left; cursor:pointer; transition:transform .2s,color .2s,background .2s,border-color .2s,box-shadow .2s; }.step-tab:hover,.step-tab:focus-visible { transform:translateY(-2px); border-color:var(--student-accent); color:#ffffff; background:var(--student-accent-light); box-shadow:0 8px 18px rgba(0,0,0,.1); outline:none; }.step-tab.active { border-color:var(--student-accent); color:#ffffff; background:var(--student-accent); box-shadow:0 8px 20px rgba(31, 41, 55, 0.18); }.step-marker { display:inline-flex; flex:0 0 38px; align-items:center; justify-content:center; width:38px; height:38px; border:1px solid var(--student-panel-border); border-radius:50%; color:var(--student-text-secondary); background:var(--student-card-bg); font-size:var(--student-fs-body-sm); font-weight:900; }.step-copy { display:grid; min-width:0; gap:4px; margin-left:10px; }.step-copy strong { display:-webkit-box; overflow:hidden; color:inherit; font-size:var(--student-fs-body); line-height:1.25; -webkit-box-orient:vertical; -webkit-line-clamp:2; }.step-copy span { color:var(--student-text-secondary); font-size:var(--student-fs-caption); font-weight:700; }.step-tab.active .step-marker { border-color:var(--student-accent); color:#ffffff; background:var(--student-accent); box-shadow:0 0 0 4px rgba(31, 41, 55, 0.1); }.step-tab.complete .step-marker { border-color:var(--student-success); color:#ffffff; background:var(--student-success); }.step-connector { flex:0 0 28px; height:2px; background:var(--student-panel-border); color:var(--student-text-secondary); font-size:var(--student-fs-h2); line-height:0; text-align:right; }.step-connector.complete { background:var(--student-success); color:var(--student-success); }.step-card { margin-top: 32px; padding: 18px 22px 22px; }.step-indicator + .step-card,.workbench-head + .step-card { margin-top: 0; }.step-title-row { margin-bottom: 14px; }.step-title-row h3 { margin: 4px 0 0; color: var(--student-text); font-size: var(--student-fs-h2); font-weight: 900; line-height: 1.3; }.caseBacktitle { display: flex; align-items: center; gap: 8px; margin: 20px 0 10px; color: var(--student-text-secondary); font-size: var(--student-fs-h2); font-weight: 800; }.caseBacktitle img { display: none; }.step-card > p { color: var(--student-text-secondary); font-size: var(--student-fs-body); line-height: 1.8; }
:deep(.el-table) { width: 100% !important; max-width: 100%; border-radius: 18px; }:deep(.el-table th.el-table__cell) { background: #fafbfc !important; }:deep(.el-input__wrapper) { min-height: 42px; border-radius: 14px; background: #ffffff; }.online { border-radius: 14px; background: var(--student-panel-bg); }.step-navigation { display: flex; justify-content: center; gap: 14px; margin-top: 22px; }.btn-nav.btn-save,.btn-nav.btn-primary { border-color: var(--student-accent); color: #ffffff; background: var(--student-accent); min-height: 36px; height: 36px; padding: 0 14px; border-radius: 8px; }.btn-nav:disabled { cursor: not-allowed; opacity: .45; }.taskfooter { gap: 52px; margin-top: 36px; padding-top: 0; border-top: 0; }.taskfooter :deep(.el-button) { min-width: 140px; height: 36px; padding: 0 14px; border: 1px solid var(--student-panel-border) !important; border-radius: 8px; color: var(--student-text) !important; background: var(--student-accent-soft) !important; font-size: var(--student-fs-h1); font-weight: 900; }
:deep(.el-table) { width: 100% !important; max-width: 100%; border-radius: 18px; }:deep(.el-table th.el-table__cell) { background: #fafbfc !important; }:deep(.el-input__wrapper) { min-height: 42px; border-radius: 14px; background: #ffffff; }.online { border-radius: 14px; background: var(--student-panel-bg); }.step-navigation { display: flex; justify-content: center; gap: 14px; margin-top: 22px; }.btn-nav.btn-save,.btn-nav.btn-primary { border-color: var(--student-accent); color: #ffffff; background: var(--student-accent); min-height: 36px; height: 36px; padding: 0 14px; border-radius: 8px; }.btn-nav:disabled { cursor: not-allowed; opacity: .45; }.taskfooter { gap: 52px; margin-top: 36px; padding-top: 0; border-top: 0; }.taskfooter :deep(.el-button) { min-width: 112px; height: 34px; padding: 0 16px; border: 1px solid rgba(37, 99, 235, 0.35) !important; border-radius: 8px; color: #2563eb !important; background: #ffffff !important; font-size: 13px; font-weight: 600; }
}
@media (max-width: 1100px) { .channel { grid-template-columns: 1fr; } }
@media (max-width: 900px) { .channel { padding: 14px; .training-core { padding: 18px; border-radius: 24px; }.workbench-head,.workbench-actions,.step-navigation { flex-direction: column; align-items: stretch; }.workbench-actions,.outline-action,.btn-nav,.taskfooter :deep(.el-button) { width: 100%; }.step-indicator { align-items:stretch; flex-direction:column; width:100%; margin-right:0; margin-left:0; overflow:visible; border-radius:20px; }.step-tab { flex:0 0 auto; width:100%; }.step-connector { flex:0 0 22px; width:2px; height:22px; margin-left:29px; text-align:center; writing-mode:vertical-rl; }.taskfooter { gap: 14px; } } }
@ -1472,9 +1464,9 @@ onMounted(async () => {
* 共用组件换肤:TrainingMaterialButton 资料按钮
* ============================================================ */
.channel .workbench-actions .material-button.el-button {
height: 36px !important;
min-height: 36px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
height: 34px !important;
min-height: 34px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1513,10 +1505,10 @@ onMounted(async () => {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1551,15 +1543,15 @@ onMounted(async () => {
align-items: center !important;
justify-content: center !important;
gap: 8px !important;
height: 40px !important;
min-height: 40px !important;
padding: 0 18px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border-radius: 10px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
font-size: 13px !important;
font-weight: 700 !important;
font-weight: 600 !important;
line-height: 1 !important;
transition:
transform 0.16s ease,
@ -1610,15 +1602,15 @@ onMounted(async () => {
align-items: center !important;
justify-content: center !important;
gap: 8px !important;
height: 40px !important;
min-height: 40px !important;
padding: 0 18px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border-radius: 10px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
font-size: 13px !important;
font-weight: 700 !important;
font-weight: 600 !important;
transition:
transform 0.16s ease,
border-color 0.16s ease,
@ -1649,8 +1641,8 @@ onMounted(async () => {
.channel .step-navigation .btn-nav.btn-save {
border: 1px solid #e5e7eb !important;
background: #f3f4f6 !important;
color: #374151 !important;
background: #ffffff !important;
color: #6b7280 !important;
}
/* ============================================================
@ -1664,7 +1656,7 @@ onMounted(async () => {
min-height: 34px !important;
height: 34px !important;
padding: 0 12px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;

@ -11,10 +11,6 @@
<main class="purchase-core">
<section class="task-header">
<div class="task-head-main">
<div class="task-head-top">
<span class="task-badge"><el-icon><Goods /></el-icon> 核心实训 · 采购需求预测</span>
<span class="task-status">进行中 · Step 01</span>
</div>
<h1 class="task-title">卡拉杰克模型分析</h1>
<p class="task-brief">
<span class="task-brief-text">采购定位在电商企业中具有极其重要的战略意义。使用卡拉杰克模型,根据生鲜电商平台运营模式及主要品类,分析采购产品定位,给出品类采购管理措施。</span>
@ -603,54 +599,9 @@ onMounted(() => {
flex: 1 1 auto;
}
.task-head-top {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: nowrap;
margin-bottom: 8px;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
}
.task-status {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 3px 10px;
border-radius: 999px;
color: var(--student-text-secondary);
background: #f3f4f6;
font-family: var(--student-font-data);
font-size: var(--student-fs-caption);
font-weight: 600;
white-space: nowrap;
&::before {
content: "";
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--student-accent-light);
animation: pulse 1.8s ease-in-out infinite;
}
}
@keyframes pulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 1; }
}
.task-title {
margin: 0;
@ -844,7 +795,7 @@ onMounted(() => {
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -1053,9 +1004,9 @@ onMounted(() => {
* 共用组件换肤:TrainingMaterialButton 资料按钮
* ============================================================ */
.purchase-page .workbench-actions .material-button.el-button {
height: 36px !important;
min-height: 36px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
height: 34px !important;
min-height: 34px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1094,10 +1045,10 @@ onMounted(() => {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1132,11 +1083,11 @@ onMounted(() => {
align-items: center !important;
justify-content: center !important;
gap: 8px !important;
height: 40px !important;
min-height: 40px !important;
padding: 0 18px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border-radius: 10px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
font-size: 13px !important;
@ -1183,7 +1134,7 @@ onMounted(() => {
min-height: 34px !important;
height: 34px !important;
padding: 0 12px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;

@ -3,10 +3,6 @@
<main class="supplier-core">
<section class="task-header">
<div class="task-head-main">
<div class="task-head-top">
<span class="task-badge"><el-icon><DataAnalysis /></el-icon> 核心实训 · 供应渠道评估</span>
<span class="task-status">进行中 · Step {{ String(currentStep).padStart(2, "0") }}</span>
</div>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -627,55 +623,9 @@ onMounted(async () => {
flex: 1 1 auto;
}
.task-head-top {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: nowrap;
margin-bottom: 8px;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
white-space: nowrap;
}
.task-status {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 3px 10px;
border-radius: 999px;
color: var(--student-text-secondary);
background: #f3f4f6;
font-family: var(--student-font-data);
font-size: var(--student-fs-caption);
font-weight: 600;
white-space: nowrap;
&::before {
content: "";
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--student-accent-light);
animation: pulse 1.8s ease-in-out infinite;
}
}
@keyframes pulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 1; }
}
.task-title {
margin: 0;
@ -1185,9 +1135,9 @@ onMounted(async () => {
* ============================================================ */
.supplier-page .workbench-actions .material-button.el-button,
.supplier-page .supplier-toolbar .material-button.el-button {
height: 36px !important;
min-height: 36px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
height: 34px !important;
min-height: 34px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1226,10 +1176,10 @@ onMounted(async () => {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1259,11 +1209,11 @@ onMounted(async () => {
align-items: center !important;
justify-content: center !important;
gap: 8px !important;
height: 40px !important;
min-height: 40px !important;
padding: 0 18px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border-radius: 10px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
font-size: 13px !important;

@ -356,8 +356,8 @@ function plainText(value) {
* - 中文按 M3「中高语言」类别行高上调,正文 14/22(≈1.6)
*/
.training-ai-sidebar {
--ai-accent: #1f2937;
--ai-accent-deep: #111827;
--ai-accent: #2563eb;
--ai-accent-deep: #1d4ed8;
--ai-gray: #6b7280;
--ai-gray-light: #9ca3af;
--ai-soft: #f3f4f6;
@ -423,14 +423,14 @@ function plainText(value) {
border-radius: 50%;
color: #ffffff;
background: var(--ai-accent);
box-shadow: 0 8px 24px rgba(31, 41, 55, 0.32);
box-shadow: 0 8px 24px rgba(37, 99, 235, 0.32);
cursor: pointer;
transition: background 0.16s ease, box-shadow 0.16s ease, transform 0.16s ease;
}
.ai-fab__icon { font-size: 23px; color: #ffffff; }
.ai-fab:hover {
background: var(--ai-accent-deep);
box-shadow: 0 10px 28px rgba(31, 41, 55, 0.4);
box-shadow: 0 10px 28px rgba(37, 99, 235, 0.4);
transform: translateY(-2px);
}
@ -513,7 +513,7 @@ function plainText(value) {
&.on {
color: #ffffff;
background: var(--ai-accent);
box-shadow: 0 2px 6px rgba(31, 41, 55, 0.22);
box-shadow: 0 2px 6px rgba(37, 99, 235, 0.22);
}
}
@ -647,7 +647,7 @@ function plainText(value) {
&:focus-within {
border-color: var(--ai-accent);
box-shadow: 0 0 0 3px rgba(31, 41, 55, 0.1);
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
}
textarea {
@ -833,7 +833,7 @@ function plainText(value) {
border-radius: 10px;
color: #ffffff;
background: var(--ai-accent);
box-shadow: 0 3px 10px rgba(31, 41, 55, 0.22);
box-shadow: 0 3px 10px rgba(37, 99, 235, 0.22);
font-family: inherit;
font-size: var(--ai-fs-body);
font-weight: var(--ai-fw-emphasized);
@ -843,7 +843,7 @@ function plainText(value) {
&:hover:not(:disabled) {
border-color: var(--ai-accent-deep);
background: var(--ai-accent-deep);
box-shadow: 0 4px 12px rgba(31, 41, 55, 0.28);
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.28);
}
&:disabled { cursor: not-allowed; opacity: 0.5; box-shadow: none; }
}

@ -75,52 +75,62 @@ async function loadRemoteTask(taskKey) {
</script>
<style lang="scss" scoped>
/* 教育蓝 · 精炼文档风:纯白画布 + 教育蓝点缀(对齐 new-product-survey) */
.training-intro {
margin-bottom: 24px;
overflow: hidden;
border: 1px solid #cfe2f5;
border-radius: 32px;
background: #f0f6fd;
box-shadow: 0 22px 48px rgba(30, 58, 95, 0.22), inset 0 1px 0 rgba(187, 222, 251, 0.08);
backdrop-filter: blur(8px);
border: 1px solid #e5e7eb;
border-radius: 12px;
background: #ffffff;
box-shadow: none;
&__head {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24px 28px 14px;
border-bottom: 1px solid rgba(187, 222, 251, 0.18);
padding: 18px 20px 14px 24px;
border-bottom: 1px solid #e5e7eb;
position: relative;
&::before {
content: "";
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 4px;
background: #2563eb;
}
h2 {
margin: 4px 0 0;
color: transparent;
background: linear-gradient(135deg, #1e3a5f, #1e88e5);
-webkit-background-clip: text;
background-clip: text;
font-size: 28px;
line-height: 1.3;
font-weight: 800;
letter-spacing: 0;
color: #1f2937;
font-size: var(--student-fs-display);
line-height: 1.4;
font-weight: 700;
letter-spacing: -0.01em;
}
}
&__eyebrow {
margin: 0;
color: #1e88e5;
color: #2563eb;
font-size: var(--student-fs-caption);
font-weight: 800;
letter-spacing: 0;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
font-family: var(--student-font-data);
}
&__hint {
flex: 0 0 auto;
padding: 7px 14px;
border: 1px solid #cfe2f5;
padding: 4px 10px;
border: 1px solid #bfdbfe;
border-radius: 999px;
color: #2c4a6a;
background: rgba(187, 222, 251, 0.14);
color: #1d4ed8;
background: #eff6ff;
font-size: var(--student-fs-caption);
font-weight: 700;
font-weight: 600;
}
&__body {
@ -128,12 +138,12 @@ async function loadRemoteTask(taskKey) {
gap: 14px;
margin: 0 24px 24px;
padding: 18px 20px;
border: 1px solid #90caf9;
border-radius: 24px;
background: #f0f6fd;
color: #2c4a6a;
border: 1px solid #e5e7eb;
border-radius: 10px;
background: #fafbfc;
color: #374151;
font-size: var(--student-fs-body);
line-height: 1.85;
line-height: 1.65;
p,
ol {
@ -147,7 +157,7 @@ async function loadRemoteTask(taskKey) {
&__section + &__section {
padding-top: 12px;
border-top: 1px solid rgba(187, 222, 251, 0.15);
border-top: 1px solid #e5e7eb;
}
&__subtitle {
@ -155,12 +165,86 @@ async function loadRemoteTask(taskKey) {
align-items: center;
gap: 8px;
margin-bottom: 8px;
color: #2c4a6a;
font-weight: 800;
color: #1f2937;
font-weight: 700;
}
&__steps {
margin: 0 24px 24px !important;
margin: 0 24px 20px !important;
}
}
/* 步骤导航:胶囊分段 + 教育蓝激活态(覆盖全局墨黑 !important 规则) */
.training-intro__steps.step-indicator {
display: flex !important;
flex-wrap: nowrap !important;
align-items: stretch !important;
justify-content: center !important;
gap: 0 !important;
width: auto !important;
padding: 0 !important;
border: none !important;
border-radius: 0 !important;
background: transparent !important;
box-shadow: none !important;
.step-tab {
flex: 1 1 0 !important;
max-width: 240px !important;
min-width: 0 !important;
display: flex !important;
flex-direction: row !important;
align-items: center !important;
justify-content: center !important;
gap: 8px !important;
height: auto !important;
min-height: 40px !important;
margin: 0 !important;
padding: 8px 14px !important;
border: 1px solid #e5e7eb !important;
border-right: none !important;
border-radius: 0 !important;
background: #ffffff !important;
box-shadow: none !important;
color: #6b7280 !important;
font-size: 13px !important;
font-weight: 600 !important;
line-height: 1.3 !important;
white-space: normal !important;
text-align: center !important;
cursor: pointer;
transition: all 0.16s ease !important;
&:first-child {
border-radius: 8px 0 0 8px !important;
}
&:last-child {
border-radius: 0 8px 8px 0 !important;
border-right: 1px solid #e5e7eb !important;
}
&:hover:not(.active) {
border-color: #2563eb !important;
background: #eff6ff !important;
color: #2563eb !important;
position: relative;
z-index: 1;
}
&.active {
border-color: #2563eb !important;
background: #2563eb !important;
color: #ffffff !important;
font-weight: 700 !important;
position: relative;
z-index: 2;
&:hover {
background: #1d4ed8 !important;
border-color: #1d4ed8 !important;
}
}
}
}
</style>

@ -123,25 +123,25 @@ async function downloadMaterial(material, label) {
align-items: center;
justify-content: center;
gap: 6px;
min-height: 40px;
min-height: 34px;
padding: 0 14px;
border: 1px solid rgba(31, 41, 55, 0.4);
border-radius: 10px;
color: #1f2937;
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: #2563eb;
background: #ffffff;
font-family: inherit;
font-size: 13px;
font-weight: 700;
font-weight: 600;
cursor: pointer;
transition: border-color 0.16s ease, background 0.16s ease, color 0.16s ease, transform 0.16s ease, box-shadow 0.16s ease;
}
.material-button:hover {
color: #1f2937;
border-color: #1f2937;
background: #f3f4f6;
color: #2563eb;
border-color: #2563eb;
background: #eff6ff;
transform: translateY(-1px);
box-shadow: 0 3px 10px rgba(31, 41, 55, 0.12);
box-shadow: 0 2px 6px rgba(37, 99, 235, 0.12);
}
.image-preview {

@ -130,12 +130,13 @@ function normalizeGoals(value) {
<style lang="scss" scoped>
.training-task-brief {
--brief-accent: #1f2937;
--brief-accent-deep: #111827;
--brief-accent-soft: #f3f4f6;
--brief-panel-border: #e5e7eb;
--brief-text: #1f2937;
--brief-text-secondary: #6b7280;
/* 令牌继承宿主页面主题(教育蓝页传蓝,墨黑页/无令牌时回退墨黑) */
--brief-accent: var(--student-accent, #1f2937);
--brief-accent-deep: var(--student-accent-deep, #111827);
--brief-accent-soft: var(--student-accent-soft, #f3f4f6);
--brief-panel-border: var(--student-panel-border, #e5e7eb);
--brief-text: var(--student-text, #1f2937);
--brief-text-secondary: var(--student-text-secondary, #6b7280);
margin-bottom: 10px;
padding: 12px 16px;

@ -261,9 +261,9 @@ function exportLegacyTraining() {
<style lang="scss" scoped>
.training-task-toolbar { display:flex; flex-wrap:wrap; align-items:center; justify-content:flex-end; gap:8px; }
.task-toolbar-button { min-height:36px; height:36px; padding:0 14px; border-color:rgba(99,217,255,.55); border-radius:8px; color:#e9fbff; background:rgba(17,126,178,.36); font-size:13px; font-weight:800; }
.task-toolbar-button:hover { border-color:rgba(116,235,255,.85); color:#e9fbff; background:rgba(18,146,204,.5); }
.task-toolbar-button--submit { border-color:rgba(66,224,187,.7); background:rgba(13,137,111,.34); }
.task-toolbar-button--submit:hover { border-color:rgba(100,245,208,.9); background:rgba(14,164,132,.45); }
.task-toolbar-button { min-height:34px; height:34px; padding:0 14px; border-color:rgba(37,99,235,.35); border-radius:8px; color:#2563eb; background:#fff; font-size:13px; font-weight:600; }
.task-toolbar-button:hover { border-color:#2563eb; color:#1d4ed8; background:#eff6ff; }
.task-toolbar-button--submit { border-color:#2563eb; color:#fff; background:#2563eb; }
.task-toolbar-button--submit:hover { border-color:#1d4ed8; color:#fff; background:#1d4ed8; }
@media (max-width:768px) { .training-task-toolbar { justify-content:stretch; } .training-task-toolbar > * { flex:1 1 auto; } }
</style>

@ -3,7 +3,6 @@
<main class="feasibility-core">
<section class="task-header">
<div class="task-head-main">
<span class="task-badge">DEMAND INSIGHT · BUSINESS CASE</span>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -547,18 +546,6 @@ function exportOutcome() { const blob = new Blob([JSON.stringify({ task: taskTit
min-width: 0;
}
.task-badge {
display: inline-flex;
align-items: center;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
letter-spacing: 0;
}
.task-title {
margin: 0;
@ -643,7 +630,7 @@ function exportOutcome() { const blob = new Blob([JSON.stringify({ task: taskTit
gap: 6px;
min-height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -1556,9 +1543,9 @@ td:last-child {
* 顶部工具栏:TrainingMaterialButton 资料按钮 → 教育蓝
* ============================================================ */
.feasibility-page .workbench-actions .material-button.el-button {
height: 36px !important;
min-height: 36px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
height: 34px !important;
min-height: 34px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1593,10 +1580,10 @@ td:last-child {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;

@ -3,7 +3,6 @@
<main class="analysis-core">
<section class="task-header">
<div class="task-head-main">
<span class="task-badge"><el-icon><TrendCharts /></el-icon> 核心实训 · 市场洞察与需求分析</span>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -226,20 +225,6 @@ function exportOutcome() { const blob = new Blob([JSON.stringify(buildDraft(), n
text-transform: uppercase;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
text-transform: none;
letter-spacing: 0;
}
.task-header h1 {
margin: 0;
@ -601,7 +586,7 @@ function exportOutcome() { const blob = new Blob([JSON.stringify(buildDraft(), n
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-text);
background: #ffffff;
@ -650,7 +635,7 @@ function exportOutcome() { const blob = new Blob([JSON.stringify(buildDraft(), n
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -831,7 +816,7 @@ function exportOutcome() { const blob = new Blob([JSON.stringify(buildDraft(), n
min-height: 34px !important;
height: 34px !important;
padding: 0 12px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -863,9 +848,9 @@ function exportOutcome() { const blob = new Blob([JSON.stringify(buildDraft(), n
* 顶部工具栏:TrainingMaterialButton 资料按钮 → 教育蓝
* ============================================================ */
.competitive-analysis-page .analysis-toolbar .material-button.el-button {
height: 36px !important;
min-height: 36px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
height: 34px !important;
min-height: 34px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -900,10 +885,10 @@ function exportOutcome() { const blob = new Blob([JSON.stringify(buildDraft(), n
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -934,11 +919,11 @@ function exportOutcome() { const blob = new Blob([JSON.stringify(buildDraft(), n
align-items: center !important;
justify-content: center !important;
gap: 8px !important;
height: 40px !important;
min-height: 40px !important;
padding: 0 18px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border-radius: 10px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
font-size: 13px !important;

@ -3,7 +3,6 @@
<main class="training-core">
<section class="task-header">
<div class="task-head-main">
<span class="task-badge">市场洞察与需求分析</span>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -1032,17 +1031,6 @@ function downloadSurveyReportTemplate() {
min-width: 0;
}
.task-badge {
display: inline-flex;
align-items: center;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
}
.task-title {
margin: 0;
@ -1134,7 +1122,7 @@ function downloadSurveyReportTemplate() {
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -1207,7 +1195,7 @@ function downloadSurveyReportTemplate() {
justify-self: end;
min-width: 124px;
height: 36px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 10px;
color: var(--student-accent);
background: #ffffff;
@ -1234,7 +1222,7 @@ function downloadSurveyReportTemplate() {
min-width: 120px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 10px;
color: var(--student-accent);
background: #ffffff;
@ -1423,7 +1411,7 @@ function downloadSurveyReportTemplate() {
min-width: 140px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 10px;
color: var(--student-accent);
background: #ffffff;
@ -1555,7 +1543,7 @@ function downloadSurveyReportTemplate() {
}
.questionnaire-editor-add {
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 10px;
color: var(--student-accent);
background: #ffffff;
@ -1945,10 +1933,10 @@ function downloadSurveyReportTemplate() {
#app .studentLayout section.app-main:has(.consumer-behavior-page) .training-actions .el-button.training-action,
#app .studentLayout section.app-main:has(.consumer-behavior-page) .training-actions button.training-action {
min-width: 140px !important;
min-height: 36px !important;
height: 36px !important;
min-height: 34px !important;
height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: var(--student-accent) !important;
background: #ffffff !important;
@ -1987,10 +1975,10 @@ function downloadSurveyReportTemplate() {
/* === nav-action (step-actions) === */
#app .studentLayout section.app-main:has(.consumer-behavior-page) .step-actions .el-button.nav-action {
min-height: 36px !important;
height: 36px !important;
min-height: 34px !important;
height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: var(--student-accent) !important;
background: #ffffff !important;
@ -2047,9 +2035,9 @@ function downloadSurveyReportTemplate() {
* 顶部工具栏:TrainingMaterialButton 资料按钮 → 教育蓝
* ============================================================ */
.consumer-behavior-page .workbench-actions .material-button.el-button {
height: 36px !important;
min-height: 36px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
height: 34px !important;
min-height: 34px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -2084,10 +2072,10 @@ function downloadSurveyReportTemplate() {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -2110,7 +2098,7 @@ function downloadSurveyReportTemplate() {
* ============================================================ */
#app .studentLayout section.app-main:has(.consumer-behavior-page) .el-button.hypothesis-action,
#app .studentLayout section.app-main:has(.consumer-behavior-page) .el-button.training-eight-action {
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
color: #2563eb !important;
background: #ffffff !important;
box-shadow: none !important;
@ -2129,7 +2117,7 @@ function downloadSurveyReportTemplate() {
background: #ffffff !important;
&:hover:not(.is-disabled) {
border-color: rgba(37, 99, 235, 0.45) !important;
border-color: rgba(37, 99, 235, 0.35) !important;
color: #2563eb !important;
background: #eff6ff !important;
}
@ -2142,7 +2130,7 @@ function downloadSurveyReportTemplate() {
#app .studentLayout section.app-main:has(.consumer-behavior-page) .el-button.questionnaire-editor-launcher__action,
#app .studentLayout section.app-main:has(.consumer-behavior-page) .el-button.questionnaire-template-action,
#app .studentLayout section.app-main:has(.consumer-behavior-page) .el-button.survey-report-template-action {
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
color: #2563eb !important;
background: #ffffff !important;
box-shadow: none !important;
@ -2161,7 +2149,7 @@ function downloadSurveyReportTemplate() {
* ============================================================ */
body.student-light-mode .el-button:not(.is-text):not(.is-link):not(.el-button--primary):not(.el-button--success):not(.el-button--danger):not(.el-button--warning):not(.task-toolbar-button):not(.material-button).questionnaire-editor-add {
min-height: 36px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 10px !important;
color: #2563eb !important;
background: #ffffff !important;

@ -3,7 +3,6 @@
<main class="consumer-scenario-core">
<section class="task-header">
<div class="task-head-main">
<div class="task-badge">市场洞察与需求分析</div>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -1013,18 +1012,6 @@ function exportOutcome() {
flex: 1 1 auto;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
}
.task-title {
margin: 0;
@ -1603,7 +1590,7 @@ function exportOutcome() {
min-width: 112px;
min-height: 36px;
padding: 0 18px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 10px;
color: var(--student-text);
background: #ffffff;
@ -1843,9 +1830,9 @@ function exportOutcome() {
* 顶部工具栏:TrainingMaterialButton 资料按钮 → 教育蓝
* ============================================================ */
.consumer-scenario-page .workbench-actions .material-button.el-button {
height: 36px !important;
min-height: 36px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
height: 34px !important;
min-height: 34px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1880,10 +1867,10 @@ function exportOutcome() {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1906,12 +1893,12 @@ function exportOutcome() {
* 底部提交/清空按钮:training-actions
* ============================================================ */
#app .studentLayout section.app-main:has(.consumer-scenario-page) .training-actions .el-button.training-action {
min-width: 140px !important;
min-height: 36px !important;
height: 36px !important;
padding: 0 20px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border-radius: 10px !important;
min-width: 112px !important;
min-height: 34px !important;
height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
font-size: 13px !important;
@ -1962,10 +1949,10 @@ function exportOutcome() {
* ============================================================ */
#app .studentLayout section.app-main:has(.consumer-scenario-page) .journey-map-actions .el-button,
#app .studentLayout section.app-main:has(.consumer-scenario-page) .journey-map-helper .el-button {
min-height: 36px !important;
height: 36px !important;
min-height: 34px !important;
height: 34px !important;
padding: 0 16px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;

@ -2,7 +2,6 @@
<div class="competitive-page student-training-shell">
<main class="training-core">
<section class="task-header">
<div class="task-badge">市场洞察与需求分析</div>
<h1 class="task-title">{{ taskTitle }}</h1>
</section>
@ -483,18 +482,6 @@ function exportOutcome() {
}
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
}
.task-title {
margin: 0;
@ -1293,9 +1280,9 @@ function exportOutcome() {
* 共用组件换肤:TrainingMaterialButton + outline-action → 教育蓝
* ============================================================ */
.competitive-page .workbench-actions .material-button.el-button {
height: 36px !important;
min-height: 36px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
height: 34px !important;
min-height: 34px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1327,10 +1314,10 @@ function exportOutcome() {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1354,15 +1341,15 @@ function exportOutcome() {
* ============================================================ */
#app .studentLayout section.app-main:has(.competitive-page) .step-actions .el-button,
#app .studentLayout section.app-main:has(.competitive-page) .training-actions .el-button {
height: 40px !important;
min-height: 40px !important;
border-radius: 10px !important;
height: 34px !important;
min-height: 34px !important;
border-radius: 8px !important;
font-weight: 700 !important;
font-size: 13px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
background: #ffffff !important;
color: #2563eb !important;
padding: 0 18px !important;
padding: 0 14px !important;
transition: transform 0.16s ease, border-color 0.16s ease, background 0.16s ease, box-shadow 0.16s ease, color 0.16s ease !important;
box-shadow: none !important;
}

@ -3,7 +3,6 @@
<main class="feature-conversion-core">
<section class="task-header">
<div class="task-head-main">
<div class="task-badge">市场洞察与需求分析</div>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -799,20 +798,6 @@ function exportOutcome() {
flex: 1 1 auto;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
text-transform: none;
letter-spacing: 0;
}
.task-title {
margin: 0;
@ -904,7 +889,7 @@ function exportOutcome() {
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -1315,7 +1300,7 @@ function exportOutcome() {
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-text);
background: #ffffff;
@ -1560,9 +1545,9 @@ function exportOutcome() {
* 共用组件换肤:TrainingMaterialButton 资料按钮 → 教育蓝
* ============================================================ */
.feature-conversion-page .workbench-actions .material-button.el-button {
height: 36px !important;
min-height: 36px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
height: 34px !important;
min-height: 34px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1597,10 +1582,10 @@ function exportOutcome() {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1631,11 +1616,11 @@ function exportOutcome() {
align-items: center !important;
justify-content: center !important;
gap: 8px !important;
height: 40px !important;
min-height: 40px !important;
padding: 0 18px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border-radius: 10px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
font-size: 13px !important;
@ -1677,7 +1662,7 @@ function exportOutcome() {
min-height: 34px !important;
height: 34px !important;
padding: 0 12px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1715,10 +1700,10 @@ function exportOutcome() {
#app .studentLayout section.app-main:has(.feature-conversion-page) .training-actions .el-button.training-action {
min-width: 140px !important;
min-height: 36px !important;
height: 36px !important;
min-height: 34px !important;
height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;

@ -2,7 +2,6 @@
<div class="industry-demand-page student-training-shell">
<main class="training-core">
<section class="task-header">
<div class="task-badge">市场洞察与需求分析</div>
<h1 class="task-title">{{ taskTitle }}</h1>
</section>
@ -487,18 +486,6 @@ function exportOutcome() {
}
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
}
.task-title {
margin: 0;
@ -1296,9 +1283,9 @@ function exportOutcome() {
* 共用组件换肤:TrainingMaterialButton + outline-action → 教育蓝
* ============================================================ */
.industry-demand-page .workbench-actions .material-button.el-button {
height: 36px !important;
min-height: 36px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
height: 34px !important;
min-height: 34px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1330,10 +1317,10 @@ function exportOutcome() {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1356,15 +1343,15 @@ function exportOutcome() {
* ============================================================ */
#app .studentLayout section.app-main:has(.industry-demand-page) .step-actions .el-button,
#app .studentLayout section.app-main:has(.industry-demand-page) .training-actions .el-button {
height: 40px !important;
min-height: 40px !important;
border-radius: 10px !important;
height: 34px !important;
min-height: 34px !important;
border-radius: 8px !important;
font-weight: 700 !important;
font-size: 13px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
background: #ffffff !important;
color: #2563eb !important;
padding: 0 18px !important;
padding: 0 14px !important;
transition: transform 0.16s ease, border-color 0.16s ease, background 0.16s ease, box-shadow 0.16s ease, color 0.16s ease !important;
box-shadow: none !important;
}

@ -3,7 +3,6 @@
<main class="industry-core">
<section class="task-header">
<div class="task-head-main">
<span class="task-badge"><el-icon><DataAnalysis /></el-icon> 核心实训 · 市场洞察与需求分析</span>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -305,20 +304,6 @@ function exportOutcome() { const blob = new Blob([JSON.stringify(buildDraft(), n
text-transform: uppercase;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
text-transform: none;
letter-spacing: 0;
}
.task-title {
margin: 0;
@ -624,7 +609,7 @@ function exportOutcome() { const blob = new Blob([JSON.stringify(buildDraft(), n
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-text);
background: #ffffff;
@ -831,7 +816,7 @@ function exportOutcome() { const blob = new Blob([JSON.stringify(buildDraft(), n
min-height: 34px !important;
height: 34px !important;
padding: 0 12px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;

@ -3,7 +3,6 @@
<main class="training-core">
<section class="task-header">
<div class="task-head-main">
<span class="task-badge">市场洞察与需求分析</span>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -959,18 +958,6 @@ function exportOutcome() {
min-width: 0;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
}
.task-title {
margin: 0;
@ -1082,7 +1069,7 @@ function exportOutcome() {
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -1211,7 +1198,7 @@ function exportOutcome() {
.preview-action {
min-height: 40px;
padding: 0 18px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 10px;
color: var(--student-accent);
background: #ffffff;
@ -1543,7 +1530,7 @@ function exportOutcome() {
.interview-tab {
min-height: 36px;
padding: 0 16px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 10px;
color: var(--student-accent);
background: #ffffff;
@ -1758,7 +1745,7 @@ function exportOutcome() {
.market-segment-toolbar__actions :deep(.segment-action) {
min-height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -1776,7 +1763,7 @@ function exportOutcome() {
&:hover:not(.is-disabled) {
color: var(--student-accent);
border-color: rgba(37, 99, 235, 0.45);
border-color: rgba(37, 99, 235, 0.35);
}
}
}
@ -1962,7 +1949,7 @@ function exportOutcome() {
.step-actions :deep(.step-action) {
min-height: 40px;
padding: 0 18px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 10px;
color: var(--student-accent);
background: #ffffff;
@ -2014,7 +2001,7 @@ function exportOutcome() {
height: 36px;
min-height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -2265,9 +2252,9 @@ function exportOutcome() {
* 顶部工具栏:TrainingMaterialButton 资料按钮 → 教育蓝
* ============================================================ */
.target-profile-page .workbench-actions .material-button.el-button {
height: 36px !important;
min-height: 36px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
height: 34px !important;
min-height: 34px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -2302,10 +2289,10 @@ function exportOutcome() {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -2340,7 +2327,7 @@ function exportOutcome() {
}
#app .studentLayout section.app-main:has(.target-profile-page) .el-button.preview-action {
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
color: #2563eb !important;
background: #ffffff !important;
box-shadow: none !important;
@ -2357,7 +2344,7 @@ function exportOutcome() {
* 细分市场行操作按钮(segment-action)
* ============================================================ */
#app .studentLayout section.app-main:has(.target-profile-page) .market-segment-toolbar__actions .el-button.segment-action {
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
color: #2563eb !important;
background: #ffffff !important;
box-shadow: none !important;
@ -2374,7 +2361,7 @@ function exportOutcome() {
background: #ffffff !important;
&:hover:not(.is-disabled) {
border-color: rgba(37, 99, 235, 0.45) !important;
border-color: rgba(37, 99, 235, 0.35) !important;
color: #2563eb !important;
background: #eff6ff !important;
}
@ -2385,10 +2372,10 @@ function exportOutcome() {
* 底部步骤按钮:step-action
* ============================================================ */
#app .studentLayout section.app-main:has(.target-profile-page) .step-actions .el-button.step-action {
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -2433,10 +2420,10 @@ function exportOutcome() {
* 底部提交/清空:training-actions
* ============================================================ */
#app .studentLayout section.app-main:has(.target-profile-page) .training-actions .el-button.training-action {
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;

@ -250,13 +250,13 @@ onMounted(() => {
background: #f9fafb;
span {
color: #1f2937;
color: #2563eb;
}
}
}
.is-active {
background: #1f2937;
background: #2563eb;
span {
color: #ffffff;
@ -264,7 +264,7 @@ onMounted(() => {
}
&:hover {
background: #111827;
background: #1d4ed8;
span {
color: #ffffff;
@ -284,10 +284,10 @@ onMounted(() => {
:deep(.el-button) {
width: 100%;
height: 38px;
border: 1px solid #1f2937;
border: 1px solid #2563eb;
border-radius: 10px;
color: #ffffff;
background: #1f2937;
background: #2563eb;
box-shadow: none;
font-size: 13px;
font-weight: 700;
@ -295,8 +295,8 @@ onMounted(() => {
:deep(.el-button:hover),
:deep(.el-button:focus) {
border-color: #111827;
background: #111827;
border-color: #1d4ed8;
background: #1d4ed8;
color: #ffffff;
}
}
@ -362,7 +362,7 @@ onMounted(() => {
.bi-data-page :deep(.el-pagination) {
--el-pagination-bg-color: transparent;
--el-pagination-button-bg-color: #ffffff;
--el-pagination-hover-color: #1f2937;
--el-pagination-hover-color: #2563eb;
color: #4b5563;
font-size: 13px;
@ -384,14 +384,14 @@ onMounted(() => {
button:hover,
.el-pager li:hover {
border-color: #1f2937;
color: #1f2937;
border-color: #2563eb;
color: #2563eb;
background: #f9fafb;
}
.el-pager li.is-active {
border-color: #1f2937;
background: #1f2937;
border-color: #2563eb;
background: #2563eb;
color: #ffffff;
}

@ -1,8 +1,8 @@
<template>
<!-- <el-scrollbar ref="scrollbar" height="800px"> -->
<div class="main-top">
<span style="font-weight: bold; font-size: 18px; color: #1e88e5">任务描述</span>
<p style="font-weight: 400; font-size: 15px; color: #2c4a6a">使用“客户细分数据”,对客户进行聚类分析,并提交实训任务。</p>
<span style="font-weight: bold; font-size: 18px; color: var(--student-accent, #1e88e5)">任务描述</span>
<p style="font-weight: 400; font-size: 15px; color: var(--student-text, #2c4a6a)">使用“客户细分数据”,对客户进行聚类分析,并提交实训任务。</p>
</div>
<div class="main-but">
<el-button @click="algorithmicKnowledge()">
@ -50,18 +50,18 @@
<span>三、模型参数设置</span>
</div>
<div class="metrics-table" style="margin-top: 10px">
<span style="font-weight: 400; font-size: 12px; color: #2c4a6a">聚类方法:</span>
<span style="font-weight: 400; font-size: 12px; color: var(--student-text, #2c4a6a)">聚类方法:</span>
<div class="metrics" style="margin-top: 10px">
<el-select v-model="input4" placeholder="请选择" style="width: 180px">
<el-option v-for="item in options4" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
<div style="margin-top: 10px">
<span style="font-weight: 400; font-size: 12px; color: #2c4a6a">设置簇数K值:</span>
<span style="font-weight: 400; font-size: 12px; color: var(--student-text, #2c4a6a)">设置簇数K值:</span>
<el-input v-model="input5" style="width: 180px; margin-top: 5px" />
</div>
<div style="margin-top: 10px">
<span style="font-weight: 400; font-size: 12px; color: #2c4a6a">最大迭代次数:</span>
<span style="font-weight: 400; font-size: 12px; color: var(--student-text, #2c4a6a)">最大迭代次数:</span>
<el-input v-model="input6" style="width: 180px; margin-top: 5px" />
</div>
<el-button @click="clusterAnalysisCalculation">计算</el-button>
@ -78,21 +78,21 @@
<div class="main-right">
<el-scrollbar height="500px" ref="scrollbar" style="padding: 20px">
<div>
<span style="font-weight: bold; font-size: 18px; color: #1e88e5">分析数据:</span>
<span style="font-weight: bold; font-size: 18px; color: var(--student-accent, #1e88e5)">分析数据:</span>
<el-table ref="exportTableRef" v-loading="loading2" :data="tableData2" style="width: 100%; margin-top: 10px" :header-cell-style="headerCellStyle" height="350">
<el-table-column v-for="column in tableLabel" :key="column.prop" :prop="column.prop" :label="column.label" align="center" />
</el-table>
<!-- <el-pagination style="margin-top:10px" background layout="prev, pager, next" :total="1000" /> -->
</div>
<div class="analysisResults" style="margin-top: 20px">
<span style="font-weight: bold; font-size: 18px; color: #1e88e5; display: block">分析结果:</span>
<span style="font-weight: bold; font-size: 18px; color: var(--student-accent, #1e88e5); display: block">分析结果:</span>
<el-button @click="upLoad" v-if="showChart">下载</el-button>
<el-table :data="tableData3" v-loading="loading3" row-key="TSuid" style="width: 100%; margin-top: 10px" :header-cell-style="headerCellStyle" height="350">
<el-table-column v-for="column in tableLabel" :key="column.prop" :prop="column.prop" :label="column.label" align="center" />
</el-table>
<!-- <el-pagination style="margin-top:10px" background layout="prev, pager, next" :total="1000" /> -->
</div>
<div style="color: #2c4a6a" v-show="showChart">最大迭代次数:{{ iterations }}</div>
<div style="color: var(--student-text, #2c4a6a)" v-show="showChart">最大迭代次数:{{ iterations }}</div>
<div class="pdfRef" id="pdfRef" style="margin-top: 20px; gap: 25px; display: flex" v-show="showChart">
<!-- <img src="../../../assets/images/图1.png" alt=""> -->
<div style="background: #ffffff">
@ -513,8 +513,8 @@ const taskSubmit = () => {
const tableData = ref([]);
const headerCellStyle = () => {
return {
backgroundColor: "#1882DE !important", // 设置表头背景颜色
color: "#ffffff !important",
backgroundColor: "var(--student-panel-bg, #1882DE) !important", // 设置表头背景颜色
color: "var(--student-text-secondary, #ffffff) !important",
};
};
const optionData2 = () => {
@ -702,8 +702,8 @@ const handleExport = async (name) => {
margin: 20px 20px 0;
margin-top: 10px;
height: 85px;
background: #f0f6fd;
border: 1px solid #cfe2f5;
background: var(--student-accent-soft, #f0f6fd);
border: 1px solid var(--student-accent-border, #cfe2f5);
padding: 5px 20px;
}
.app-main {
@ -720,14 +720,14 @@ const handleExport = async (name) => {
display: flex;
width: 205px;
height: 100%;
background: #f0f6fd;
background: var(--student-accent-soft, #f0f6fd);
// padding: 0px 10px;
.left-top {
padding: 10px;
span {
font-weight: bold;
font-size: var(--student-fs-h1);
color: #1565c0;
color: var(--student-accent-deep, #1565c0);
}
}
.metrics-table {
@ -741,15 +741,15 @@ const handleExport = async (name) => {
margin: 15px;
}
.el-input {
--el-input-text-color: #1e3a5f;
--el-input-text-color: var(--student-text, #1e3a5f);
--el-input-bg-color: #ffffff;
--el-input-border-color: #cfe2f5;
--el-input-border-color: var(--student-accent-border, #cfe2f5);
}
}
.startOver {
width: 150px;
height: 40px;
background: #1e88e5;
background: var(--student-accent, #1e88e5);
color: #ffffff;
margin: auto;
display: flex;
@ -758,11 +758,11 @@ const handleExport = async (name) => {
cursor: pointer;
}
:deep(.el-table) {
--el-table-row-hover-bg-color: rgba(30, 136, 229, 0.08) !important;
--el-table-border-color: #cfe2f5;
--el-table-row-hover-bg-color: var(--student-accent-soft, rgba(30, 136, 229, 0.08)) !important;
--el-table-border-color: var(--student-accent-border, #cfe2f5);
.el-table__row {
background-color: #dcebfb !important;
color: #2c4a6a;
background-color: var(--student-card-bg, #dcebfb) !important;
color: var(--student-text, #2c4a6a);
}
}
}
@ -770,19 +770,19 @@ const handleExport = async (name) => {
width: 1639px;
// height: 100%;
// padding: 20px;
border: 1px solid #cfe2f5;
border: 1px solid var(--student-accent-border, #cfe2f5);
:deep(.el-table__header) {
.el-table__cell {
background: linear-gradient(180deg, #42a5f5 0%, #1e88e5 100%) !important;
background: var(--student-panel-bg, linear-gradient(180deg, #42a5f5 0%, #1e88e5 100%)) !important;
}
}
:deep(.el-table) {
--el-table-row-hover-bg-color: rgba(30, 136, 229, 0.08) !important;
--el-table-border-color: #cfe2f5;
--el-table-row-hover-bg-color: var(--student-accent-soft, rgba(30, 136, 229, 0.08)) !important;
--el-table-border-color: var(--student-accent-border, #cfe2f5);
--el-table-bg-color: #ffffff00;
.el-table__row {
background-color: #dcebfb !important;
color: #2c4a6a;
background-color: var(--student-card-bg, #dcebfb) !important;
color: var(--student-text, #2c4a6a);
}
}
}
@ -818,21 +818,21 @@ const handleExport = async (name) => {
}
}
:deep(.el-form-item__label) {
color: #2c4a6a;
color: var(--student-text, #2c4a6a);
}
.from-item {
padding: 20px;
.el-input {
--el-input-text-color: #1e3a5f;
--el-input-text-color: var(--student-text, #1e3a5f);
--el-input-bg-color: #ffffff;
--el-input-border-color: #cfe2f5;
--el-input-border-color: var(--student-accent-border, #cfe2f5);
}
}
.dialog-footer {
margin-bottom: 20px;
}
:deep(.el-table__expand-icon) {
color: #1e88e5;
color: var(--student-accent, #1e88e5);
.el-icon {
font-size: 16px;
}

@ -1,7 +1,7 @@
<template>
<div class="main-top">
<span style="font-weight: bold; font-size: 18px; color: #1e88e5">任务描述</span>
<p style="font-weight: 400; font-size: 15px; color: #2c4a6a !important">使用“客户细分数据”,对“消费得分(Spending Score)”指标进行描述性统计分析,并提交实训任务。</p>
<span style="font-weight: bold; font-size: 18px; color: var(--student-accent, #1e88e5)">任务描述</span>
<p style="font-weight: 400; font-size: 15px; color: var(--student-text, #2c4a6a) !important">使用“客户细分数据”,对“消费得分(Spending Score)”指标进行描述性统计分析,并提交实训任务。</p>
</div>
<div class="main-but">
<el-button @click="knowledgeImport">
@ -68,7 +68,7 @@
<div class="main-right">
<el-scrollbar height="550px" style="padding: 20px">
<div>
<span style="font-weight: bold; font-size: 18px; color: #1e88e5">分析数据:</span>
<span style="font-weight: bold; font-size: 18px; color: var(--student-accent, #1e88e5)">分析数据:</span>
<el-table :data="analysisData" style="width: 100%; margin-top: 10px" :header-cell-style="headerCellStyle">
<el-table-column v-for="column in analysisHanderKry" :key="column" :prop="column" :label="column" align="center">
<template #default="scope">
@ -79,7 +79,7 @@
<pagination v-show="n_analyzeTheNumberOfDataItems > 0" :total="n_analyzeTheNumberOfDataItems" v-model:page="n_dataTableQuery.index" v-model:limit="n_dataTableQuery.size" @pagination="analyzeDataNext" />
</div>
<div class="analysisResults" style="margin-top: 20px">
<span style="font-weight: bold; font-size: 18px; color: #1e88e5; display: block">分析结果:</span>
<span style="font-weight: bold; font-size: 18px; color: var(--student-accent, #1e88e5); display: block">分析结果:</span>
<el-button @click="download">下载</el-button>
<el-table :data="tableData" style="width: 100%; margin-top: 10px" :header-cell-style="headerCellStyle" height="350" v-loading="loading">
<el-table-column v-for="column in tableLabel" :key="column.label" :prop="column.prop" :label="column.label" align="center">
@ -386,8 +386,8 @@ const taskSubmit = () => {
const tableData = ref([]);
const headerCellStyle = () => {
return {
backgroundColor: "#1882DE !important", // 设置表头背景颜色
color: "#ffffff !important",
backgroundColor: "var(--student-panel-bg, #1882DE) !important", // 设置表头背景颜色
color: "var(--student-text-secondary, #ffffff) !important",
};
};
// 选择指标
@ -573,8 +573,8 @@ const closeDialog = () => {
margin: 20px 20px 0;
margin-top: 10px;
height: 85px;
background: #f0f6fd;
border: 1px solid #cfe2f5;
background: var(--student-accent-soft, #f0f6fd);
border: 1px solid var(--student-accent-border, #cfe2f5);
padding: 5px 20px;
}
.app-main {
@ -591,7 +591,7 @@ const closeDialog = () => {
display: flex;
width: 205px;
height: 100%;
background: #f0f6fd;
background: var(--student-accent-soft, #f0f6fd);
// padding: 0px 10px;
padding-left: 10px;
.left-top {
@ -599,7 +599,7 @@ const closeDialog = () => {
span {
font-weight: bold;
font-size: var(--student-fs-h1);
color: #1565c0;
color: var(--student-accent-deep, #1565c0);
}
}
.metrics-table {
@ -616,7 +616,7 @@ const closeDialog = () => {
.startOver {
width: 150px;
height: 40px;
background: #1e88e5;
background: var(--student-accent, #1e88e5);
color: #ffffff;
margin: auto;
display: flex;
@ -625,11 +625,11 @@ const closeDialog = () => {
cursor: pointer;
}
:deep(.el-table) {
--el-table-row-hover-bg-color: rgba(30, 136, 229, 0.08) !important;
--el-table-border-color: #cfe2f5;
--el-table-row-hover-bg-color: var(--student-accent-soft, rgba(30, 136, 229, 0.08)) !important;
--el-table-border-color: var(--student-accent-border, #cfe2f5);
.el-table__row {
background-color: #dcebfb !important;
color: #2c4a6a;
background-color: var(--student-card-bg, #dcebfb) !important;
color: var(--student-text, #2c4a6a);
}
}
}
@ -637,19 +637,19 @@ const closeDialog = () => {
width: 100%;
// height: 100%;
// padding: 20px;
border: 1px solid #cfe2f5;
border: 1px solid var(--student-accent-border, #cfe2f5);
:deep(.el-table__header) {
.el-table__cell {
background: linear-gradient(180deg, #42a5f5 0%, #1e88e5 100%) !important;
background: var(--student-panel-bg, linear-gradient(180deg, #42a5f5 0%, #1e88e5 100%)) !important;
}
}
:deep(.el-table) {
--el-table-row-hover-bg-color: rgba(30, 136, 229, 0.08) !important;
--el-table-border-color: #cfe2f5;
--el-table-row-hover-bg-color: var(--student-accent-soft, rgba(30, 136, 229, 0.08)) !important;
--el-table-border-color: var(--student-accent-border, #cfe2f5);
--el-table-bg-color: #ffffff00;
.el-table__row {
background-color: #dcebfb !important;
color: #2c4a6a;
background-color: var(--student-card-bg, #dcebfb) !important;
color: var(--student-text, #2c4a6a);
}
}
}
@ -685,14 +685,14 @@ const closeDialog = () => {
}
}
:deep(.el-form-item__label) {
color: #2c4a6a;
color: var(--student-text, #2c4a6a);
}
.from-item {
padding: 20px;
.el-input {
--el-input-text-color: #1e3a5f;
--el-input-text-color: var(--student-text, #1e3a5f);
--el-input-bg-color: #ffffff;
--el-input-border-color: #cfe2f5;
--el-input-border-color: var(--student-accent-border, #cfe2f5);
}
}
.dialog-footer {

@ -11,5 +11,5 @@ const router=useRouter(),loading=ref(false),exams=ref([]),filter=ref("ALL"); con
async function load(){loading.value=true;try{exams.value=(await examApi.getStudentExams()).data||[]}finally{loading.value=false}} async function enter(exam){try{const token=deviceToken(exam.id);await examApi.enterExam(exam.id,token);router.push(`/examination/take/${exam.id}`)}catch(error){ElMessage.error(error?.message||"进入考试失败")}} function deviceToken(id){const key=`exam-device-${id}`;let value=localStorage.getItem(key);if(!value){value=crypto?.randomUUID?.()||`${Date.now()}-${Math.random().toString(36).slice(2)}`;localStorage.setItem(key,value)}return value} function count(value){return value==="ALL"?exams.value.length:exams.value.filter((item)=>item.status===value).length} function day(value){return value?String(new Date(value).getDate()).padStart(2,"0"):"--"} function month(value){return value?`${new Date(value).getMonth()+1}月`:"—"} function formatTime(value){return value?new Date(value).toLocaleString("zh-CN",{hour12:false}).replaceAll("/","-"):"—"} function durationBetween(row){return row.startTime&&row.endTime?Math.max(0,Math.round((new Date(row.endTime)-new Date(row.startTime))/60000)):0} function countdown(value){const minutes=Math.max(0,Math.ceil((new Date(value)-Date.now())/60000));return minutes<60?`${minutes} 分钟后开始`:`${Math.ceil(minutes/60)} 小时后开始`}
</script>
<style scoped lang="scss">
.student-exams{--student-accent:#1f2937;--student-accent-soft:#f3f4f6;--student-success:#4a9d6e;--student-border:#e5e7eb;--student-text:#1f2937;--student-muted:#6b7280;width:100%;margin:0;color:var(--student-text);line-height:1.55}.page-head{display:flex;justify-content:space-between;align-items:flex-start}.page-head h1{margin:6px 0 0;font-size:17px}.page-head p{margin:4px 0 0;color:var(--student-muted);font-size:12px}.page-eyebrow{color:var(--student-muted);font-size:11px;font-weight:700;letter-spacing:.12em}.refresh-btn{width:36px;height:36px;border:1px solid #d1d5db;border-radius:8px;background:#fff;color:#374151}.status-filter{display:flex;gap:28px;margin-top:20px;border-bottom:1px solid var(--student-border)}.status-filter button{position:relative;padding:10px 2px;border:0;background:none;color:var(--student-muted);font-size:13px;cursor:pointer}.status-filter button b{margin-left:7px;font-weight:500}.status-filter button.active{color:var(--student-text);font-weight:700}.status-filter button.active:after{position:absolute;right:0;bottom:-1px;left:0;height:3px;background:var(--student-accent);content:""}.exam-list{margin-top:14px;overflow:hidden;border:1px solid var(--student-border);border-radius:16px;background:#fff}.exam-row{display:grid;grid-template-columns:78px 1fr 150px;gap:22px;align-items:center;padding:20px;border-bottom:1px solid var(--student-border)}.exam-row:last-child{border-bottom:0}.date-block{display:grid;border-right:1px solid var(--student-border);text-align:center}.date-block strong{font-size:24px;line-height:1.2}.date-block span{color:var(--student-muted);font-size:12px}.exam-info h2{margin:8px 0;color:var(--student-text);font-size:15px}.exam-info p{display:flex;align-items:center;gap:5px;margin:4px 0 0;color:var(--student-muted);font-size:12px}.submitted{margin-left:8px;color:var(--student-success);font-size:12px}.exam-action{color:var(--student-muted);font-size:12px;text-align:right}.student-exams:deep(.el-tag){height:22px;padding:0 9px;border:1px solid var(--student-border);border-radius:6px;background:var(--student-accent-soft);color:#4b5563;font-size:11px}.student-exams:deep(.el-button){height:36px;padding:0 16px;border-radius:8px;font-size:13px;font-weight:600}.student-exams:deep(.el-button--primary){border-color:var(--student-accent);background:var(--student-accent);color:#fff}.student-exams:deep(.el-button--primary.is-plain){border-color:rgba(31,41,55,.4);background:#fff;color:var(--student-accent)}@media(max-width:650px){.exam-row{grid-template-columns:58px 1fr}.exam-action{grid-column:2;text-align:left}.status-filter{gap:14px;overflow-x:auto}}
.student-exams{--student-accent:#2563eb;--student-accent-soft:#eff6ff;--student-success:#4a9d6e;--student-border:#e5e7eb;--student-text:#1f2937;--student-muted:#6b7280;width:100%;margin:0;color:var(--student-text);line-height:1.55}.page-head{display:flex;justify-content:space-between;align-items:flex-start}.page-head h1{margin:6px 0 0;font-size:17px}.page-head p{margin:4px 0 0;color:var(--student-muted);font-size:12px}.page-eyebrow{color:var(--student-muted);font-size:11px;font-weight:700;letter-spacing:.12em}.refresh-btn{width:36px;height:36px;border:1px solid #d1d5db;border-radius:8px;background:#fff;color:#374151}.status-filter{display:flex;gap:28px;margin-top:20px;border-bottom:1px solid var(--student-border)}.status-filter button{position:relative;padding:10px 2px;border:0;background:none;color:var(--student-muted);font-size:13px;cursor:pointer}.status-filter button b{margin-left:7px;font-weight:500}.status-filter button.active{color:var(--student-text);font-weight:700}.status-filter button.active:after{position:absolute;right:0;bottom:-1px;left:0;height:3px;background:var(--student-accent);content:""}.exam-list{margin-top:14px;overflow:hidden;border:1px solid var(--student-border);border-radius:16px;background:#fff}.exam-row{display:grid;grid-template-columns:78px 1fr 150px;gap:22px;align-items:center;padding:20px;border-bottom:1px solid var(--student-border)}.exam-row:last-child{border-bottom:0}.date-block{display:grid;border-right:1px solid var(--student-border);text-align:center}.date-block strong{font-size:24px;line-height:1.2}.date-block span{color:var(--student-muted);font-size:12px}.exam-info h2{margin:8px 0;color:var(--student-text);font-size:15px}.exam-info p{display:flex;align-items:center;gap:5px;margin:4px 0 0;color:var(--student-muted);font-size:12px}.submitted{margin-left:8px;color:var(--student-success);font-size:12px}.exam-action{color:var(--student-muted);font-size:12px;text-align:right}.student-exams:deep(.el-tag){height:22px;padding:0 9px;border:1px solid var(--student-border);border-radius:6px;background:var(--student-accent-soft);color:#4b5563;font-size:11px}.student-exams:deep(.el-button){height:36px;padding:0 16px;border-radius:8px;font-size:13px;font-weight:600}.student-exams:deep(.el-button--primary){border-color:var(--student-accent);background:var(--student-accent);color:#fff}.student-exams:deep(.el-button--primary.is-plain){border-color:rgba(37,99,235,.35);background:#fff;color:var(--student-accent)}@media(max-width:650px){.exam-row{grid-template-columns:58px 1fr}.exam-action{grid-column:2;text-align:left}.status-filter{gap:14px;overflow-x:auto}}
</style>

@ -6,5 +6,5 @@ import { computed,onMounted,ref } from "vue"; import { useRoute } from "vue-rout
const route=useRoute(),loading=ref(false),result=ref({questions:[]}),currentId=ref(null); const current=computed(()=>result.value.questions?.find(q=>q.id===currentId.value)); const currentIndex=computed(()=>result.value.questions?.findIndex(q=>q.id===currentId.value)??-1); onMounted(async()=>{loading.value=true;try{result.value=(await getExamResult(route.params.id)).data;currentId.value=result.value.questions?.[0]?.id}finally{loading.value=false}}); function select(id){currentId.value=id} function move(step){currentId.value=result.value.questions[currentIndex.value+step]?.id} function display(v){if(Array.isArray(v))return v.join("、");if(v===true)return"正确";if(v===false)return"错误";return v||"未作答"} function answerClass(q){return{current:q.id===currentId.value,wrong:q.correct===false,right:q.correct===true,subjective:q.type==="SHORT_ANSWER"}}
</script>
<style scoped lang="scss">
.result-page{--accent:#1f2937;--danger:#d9554c;--success:#4a9d6e;--border:#e5e7eb;--muted:#6b7280;width:100%;margin:0;color:var(--accent);line-height:1.55}.result-page>header h1{margin:10px 0 4px;font-size:17px}.result-page>header p{margin:0;color:var(--muted);font-size:12px}.result-page:deep(.el-button--text){padding:0;color:#4b5563;font-size:12px}.score-band{display:grid;grid-template-columns:1.25fr repeat(4,1fr);margin:18px 0;overflow:hidden;border:1px solid var(--border);border-radius:14px;background:#fff}.score-band>div{display:grid;gap:6px;padding:16px 18px;border-right:1px solid var(--border)}.score-band>div:last-child{border-right:0}.score-band span{color:var(--muted);font-size:12px}.score-band b{font-size:18px}.score-band .total{grid-template-columns:auto auto 1fr;align-items:end}.score-band .total span{grid-column:1/4}.score-band strong{font-size:34px;line-height:1}.score-band small{padding-bottom:4px;color:var(--muted)}.result-layout{display:grid;grid-template-columns:230px 1fr;gap:20px;align-items:start}.result-layout aside,.result-question{border:1px solid var(--border);border-radius:14px;background:#fff}.result-layout aside{padding:16px}.result-layout aside h2{margin:0 0 14px;font-size:14px}.result-layout aside>div{display:grid;grid-template-columns:repeat(5,1fr);gap:7px}.result-layout aside button{aspect-ratio:1;border:1px solid var(--border);border-radius:6px;background:#fff;color:var(--muted);cursor:pointer}.result-layout aside button.right{border-color:var(--success);color:var(--success)}.result-layout aside button.wrong{border-color:var(--danger);color:var(--danger)}.result-layout aside button.subjective{border-color:#9ca3af}.result-layout aside button.current{outline:2px solid var(--accent);outline-offset:2px}.result-question{padding:18px 20px}.result-question>header{display:flex;justify-content:space-between;align-items:center}.result-question>header b{font-size:13px}.question-meta{display:flex;justify-content:space-between;align-items:center;color:var(--muted);font-size:12px}.question-meta a{margin:0}.result-question h2{margin:16px 0;color:var(--accent);font-size:15px;line-height:1.65}.result-question p{margin:6px 0;color:#4b5563;font-size:13px}.result-question dl{display:grid;grid-template-columns:90px 1fr;gap:10px 14px;margin-top:18px;padding:14px 16px;border:1px solid var(--border);border-radius:10px;font-size:13px}.result-question dt{color:var(--muted);font-size:12px}.result-question dd{margin:0;white-space:pre-wrap;line-height:1.6}.result-question a{display:inline-block;margin-top:12px;color:var(--accent);font-size:12px;font-weight:600}.result-navigation{display:flex;justify-content:flex-end;gap:10px;margin-top:18px}.result-page:deep(.el-tag){height:22px;padding:0 9px;border-radius:6px;font-size:11px;font-weight:700}.result-page:deep(.el-tag--success){border-color:var(--success);background:#fff;color:var(--success)}.result-page:deep(.el-tag--danger){border-color:var(--danger);background:#fff;color:var(--danger)}@media(max-width:760px){.score-band{grid-template-columns:1fr 1fr}.result-layout{grid-template-columns:1fr}.result-navigation{justify-content:stretch}.result-navigation .el-button{flex:1}}
.result-page{--accent:#2563eb;--danger:#d9554c;--success:#4a9d6e;--border:#e5e7eb;--muted:#6b7280;width:100%;margin:0;color:#1f2937;line-height:1.55}.result-page>header h1{margin:10px 0 4px;font-size:17px}.result-page>header p{margin:0;color:var(--muted);font-size:12px}.result-page:deep(.el-button--text){padding:0;color:#4b5563;font-size:12px}.score-band{display:grid;grid-template-columns:1.25fr repeat(4,1fr);margin:18px 0;overflow:hidden;border:1px solid var(--border);border-radius:14px;background:#fff}.score-band>div{display:grid;gap:6px;padding:16px 18px;border-right:1px solid var(--border)}.score-band>div:last-child{border-right:0}.score-band span{color:var(--muted);font-size:12px}.score-band b{font-size:18px}.score-band .total{grid-template-columns:auto auto 1fr;align-items:end}.score-band .total span{grid-column:1/4}.score-band strong{font-size:34px;line-height:1;color:#1d4ed8}.score-band small{padding-bottom:4px;color:var(--muted)}.result-layout{display:grid;grid-template-columns:230px 1fr;gap:20px;align-items:start}.result-layout aside,.result-question{border:1px solid var(--border);border-radius:14px;background:#fff}.result-layout aside{padding:16px}.result-layout aside h2{margin:0 0 14px;font-size:14px}.result-layout aside>div{display:grid;grid-template-columns:repeat(5,1fr);gap:7px}.result-layout aside button{aspect-ratio:1;border:1px solid var(--border);border-radius:6px;background:#fff;color:var(--muted);cursor:pointer}.result-layout aside button.right{border-color:var(--success);color:var(--success)}.result-layout aside button.wrong{border-color:var(--danger);color:var(--danger)}.result-layout aside button.subjective{border-color:#9ca3af}.result-layout aside button.current{outline:2px solid var(--accent);outline-offset:2px}.result-question{padding:18px 20px}.result-question>header{display:flex;justify-content:space-between;align-items:center}.result-question>header b{font-size:13px}.question-meta{display:flex;justify-content:space-between;align-items:center;color:var(--muted);font-size:12px}.question-meta a{margin:0}.result-question h2{margin:16px 0;color:#1f2937;font-size:15px;line-height:1.65}.result-question p{margin:6px 0;color:#4b5563;font-size:13px}.result-question dl{display:grid;grid-template-columns:90px 1fr;gap:10px 14px;margin-top:18px;padding:14px 16px;border:1px solid var(--border);border-radius:10px;font-size:13px}.result-question dt{color:var(--muted);font-size:12px}.result-question dd{margin:0;white-space:pre-wrap;line-height:1.6}.result-question a{display:inline-block;margin-top:12px;color:var(--accent);font-size:12px;font-weight:600}.result-navigation{display:flex;justify-content:flex-end;gap:10px;margin-top:18px}.result-page:deep(.el-tag){height:22px;padding:0 9px;border-radius:6px;font-size:11px;font-weight:700}.result-page:deep(.el-tag--success){border-color:var(--success);background:#fff;color:var(--success)}.result-page:deep(.el-tag--danger){border-color:var(--danger);background:#fff;color:var(--danger)}@media(max-width:760px){.score-band{grid-template-columns:1fr 1fr}.result-layout{grid-template-columns:1fr}.result-navigation{justify-content:stretch}.result-navigation .el-button{flex:1}}
</style>

@ -10,5 +10,5 @@ const route=useRoute(),router=useRouter(),examId=route.params.id,loading=ref(fal
async function load(){loading.value=true;try{const token=deviceToken();paper.value=(await examApi.getActivePaper(examId,token)).data;paper.value.questions.forEach(q=>{answers[q.id]=q.studentAnswer??(q.type==="MULTIPLE"?[]:"");if(q.answerFileUrl)files[q.id]={name:q.answerFileName,url:q.answerFileUrl}});currentId.value=paper.value.questions[0]?.id;remaining.value=Math.max(0,Math.floor((new Date(paper.value.endTime)-Date.now())/1000));ticker=setInterval(()=>{remaining.value=Math.max(0,remaining.value-1);if(remaining.value===0){clearInterval(ticker);autoSubmit()}},1000)}finally{loading.value=false}} function deviceToken(){return localStorage.getItem(`exam-device-${examId}`)||""} function select(id){currentId.value=id} function move(step){currentId.value=paper.value.questions[currentIndex.value+step]?.id} function isAnswered(q){const answer=answers[q.id];return(Array.isArray(answer)?answer.length:Boolean(String(answer??"").trim()))||Boolean(files[q.id])} function guardCopy(event){if(paper.value.allowCopyQuestion||event.target?.closest("textarea,input"))return;event.preventDefault();ElMessage.warning("该考试不允许复制试题")} function guardContextMenu(event){if(paper.value.allowCopyQuestion||event.target?.closest("textarea,input"))return;event.preventDefault()} function guardPaste(event){if(!paper.value.allowPasteAnswer){event.preventDefault();ElMessage.warning("该考试不允许粘贴答案")}} async function persist(q){await examApi.saveExamAnswer(examId,q.id,{deviceToken:deviceToken(),answer:answers[q.id]})} async function uploadAnswer({file}){const form=new FormData();form.append("file",file);const data=(await examApi.uploadExamAnswerFile(examId,current.value.id,deviceToken(),form)).data;files[current.value.id]={name:data.name,url:data.url};ElMessage.success("作答文件已上传")} async function confirmSubmit(){const unanswered=paper.value.questions.filter(q=>!isAnswered(q)).length;await ElMessageBox.confirm(unanswered?`还有 ${unanswered} 道题未作答,确认交卷?`:"确认提交试卷?","确认交卷",{type:"warning",confirmButtonText:"确认交卷"});await doSubmit()} async function doSubmit(){await examApi.submitExam(examId,deviceToken());ElMessage.success("交卷成功");router.replace(`/examination/result/${examId}`)} async function autoSubmit(){try{await doSubmit()}catch{router.replace("/examination/index")}} function formatTime(v){return v?new Date(v).toLocaleString("zh-CN",{hour12:false}).replaceAll("/","-"):"—"}
</script>
<style scoped lang="scss">
.take-page{--accent:#1f2937;--border:#e5e7eb;--muted:#6b7280;min-height:calc(100vh - 84px);background:#f8fafc;color:#1f2937}.take-head{height:72px;display:grid;grid-template-columns:1fr auto 1fr;align-items:center;padding:0 28px;border-bottom:1px solid var(--border);background:#fff}.take-head h1{margin:0;font-size:17px}.take-head p{margin:4px 0 0;color:var(--muted);font-size:12px}.take-head>button{justify-self:end}.timer{display:grid;gap:2px;text-align:center;color:var(--muted);font-size:12px}.timer strong{color:var(--accent);font-size:18px;font-variant-numeric:tabular-nums}.timer.urgent strong{color:#c2413b}.exam-body{display:grid;grid-template-columns:250px minmax(0,1fr);gap:20px;padding:20px 22px}.answer-sheet,.question-panel{border:1px solid var(--border);border-radius:14px;background:#fff}.answer-sheet{align-self:start;padding:16px;position:sticky;top:16px}.answer-sheet h2{margin:0 0 14px;font-size:14px}.sheet-group{margin-bottom:18px}.sheet-group h3{margin:0 0 10px;color:var(--muted);font-size:12px}.sheet-group>div{display:grid;grid-template-columns:repeat(5,1fr);gap:7px}.sheet-group button{aspect-ratio:1;border:1px solid var(--border);border-radius:6px;background:#fff;color:var(--muted);cursor:pointer}.sheet-group button.answered{border-color:#4a9d6e;color:#4a9d6e;background:#f0fdf4}.sheet-group button.current{outline:2px solid var(--accent);outline-offset:2px}.answer-sheet footer{display:flex;gap:14px;color:var(--muted);font-size:11px}.answer-sheet i{display:inline-block;width:8px;height:8px;margin-right:4px;border:1px solid #d1d5db;border-radius:50%}.answer-sheet i.answered-dot{border-color:#4a9d6e;background:#4a9d6e}.question-panel{min-height:610px;padding:22px 28px 80px;position:relative}.question-panel>header{display:flex;justify-content:space-between;color:var(--muted);font-size:13px}.question-panel>header b{color:var(--accent)}.question-panel h2{margin:18px 0;color:#1f2937;font-size:17px;line-height:1.65}.material{display:inline-flex;gap:6px;margin-bottom:16px;color:var(--accent);font-size:12px;text-decoration:none}.choice-list{display:grid;gap:10px;width:100%}.question-panel:deep(.el-radio),.question-panel:deep(.el-checkbox){height:auto;margin:0;padding:13px 16px;border:1px solid var(--border);border-radius:8px;background:#fff}.question-panel:deep(.el-radio:hover),.question-panel:deep(.el-checkbox:hover),.question-panel:deep(.is-checked){border-color:var(--accent);background:#f9fafb}.question-panel:deep(.el-radio__label),.question-panel:deep(.el-checkbox__label){display:flex;gap:12px;color:#1f2937;font-size:13px;line-height:1.55}.judgement{grid-template-columns:1fr 1fr}.question-panel:deep(.el-textarea__inner){border-color:var(--border);border-radius:8px;box-shadow:none}.file-answer{display:flex;align-items:center;gap:12px;margin-top:12px;color:var(--muted);font-size:12px}.file-answer a{color:var(--accent)}.question-actions{position:absolute;right:28px;bottom:24px;left:28px;display:flex;justify-content:space-between}.take-page:deep(.el-button){height:40px;border-radius:10px;font-weight:700}.take-page:deep(.el-button--primary){border-color:var(--accent);background:var(--accent)}.take-page:deep(.el-button--danger.is-plain){border-color:rgba(31,41,55,.4);background:#fff;color:var(--accent)}@media(max-width:760px){.take-head{grid-template-columns:1fr auto;height:auto;padding:10px 14px}.timer{grid-column:1/3;margin-top:8px}.exam-body{grid-template-columns:1fr;padding:12px}.answer-sheet{position:static}.question-panel{padding:20px 18px 78px}.question-actions{right:18px;left:18px}}
.take-page{--accent:#2563eb;--border:#e5e7eb;--muted:#6b7280;min-height:calc(100vh - 84px);background:#ffffff;color:#1f2937}.take-head{height:72px;display:grid;grid-template-columns:1fr auto 1fr;align-items:center;padding:0 28px;border-bottom:1px solid var(--border);background:#fff}.take-head h1{margin:0;font-size:17px}.take-head p{margin:4px 0 0;color:var(--muted);font-size:12px}.take-head>button{justify-self:end}.timer{display:grid;gap:2px;text-align:center;color:var(--muted);font-size:12px}.timer strong{color:var(--accent);font-size:18px;font-variant-numeric:tabular-nums}.timer.urgent strong{color:#c2413b}.exam-body{display:grid;grid-template-columns:250px minmax(0,1fr);gap:20px;padding:20px 22px}.answer-sheet,.question-panel{border:1px solid var(--border);border-radius:14px;background:#fff}.answer-sheet{align-self:start;padding:16px;position:sticky;top:16px}.answer-sheet h2{margin:0 0 14px;font-size:14px}.sheet-group{margin-bottom:18px}.sheet-group h3{margin:0 0 10px;color:var(--muted);font-size:12px}.sheet-group>div{display:grid;grid-template-columns:repeat(5,1fr);gap:7px}.sheet-group button{aspect-ratio:1;border:1px solid var(--border);border-radius:6px;background:#fff;color:var(--muted);cursor:pointer}.sheet-group button.answered{border-color:#2563eb;color:#2563eb;background:#eff6ff}.sheet-group button.current{outline:2px solid var(--accent);outline-offset:2px}.answer-sheet footer{display:flex;gap:14px;color:var(--muted);font-size:11px}.answer-sheet i{display:inline-block;width:8px;height:8px;margin-right:4px;border:1px solid #d1d5db;border-radius:50%}.answer-sheet i.answered-dot{border-color:#2563eb;background:#2563eb}.question-panel{min-height:610px;padding:22px 28px 80px;position:relative}.question-panel>header{display:flex;justify-content:space-between;color:var(--muted);font-size:13px}.question-panel>header b{color:var(--accent)}.question-panel h2{margin:18px 0;color:#1f2937;font-size:17px;line-height:1.65}.material{display:inline-flex;gap:6px;margin-bottom:16px;color:var(--accent);font-size:12px;text-decoration:none}.choice-list{display:grid;gap:10px;width:100%}.question-panel:deep(.el-radio),.question-panel:deep(.el-checkbox){height:auto;margin:0;padding:13px 16px;border:1px solid var(--border);border-radius:8px;background:#fff}.question-panel:deep(.el-radio:hover),.question-panel:deep(.el-checkbox:hover),.question-panel:deep(.is-checked){border-color:var(--accent);background:#eff6ff}.question-panel:deep(.el-radio__label),.question-panel:deep(.el-checkbox__label){display:flex;gap:12px;color:#1f2937;font-size:13px;line-height:1.55}.judgement{grid-template-columns:1fr 1fr}.question-panel:deep(.el-textarea__inner){border-color:var(--border);border-radius:8px;box-shadow:none}.file-answer{display:flex;align-items:center;gap:12px;margin-top:12px;color:var(--muted);font-size:12px}.file-answer a{color:var(--accent)}.question-actions{position:absolute;right:28px;bottom:24px;left:28px;display:flex;justify-content:space-between}.take-page:deep(.el-button){height:40px;border-radius:10px;font-weight:700}.take-page:deep(.el-button--primary){border-color:var(--accent);background:var(--accent)}.take-page:deep(.el-button--danger.is-plain){border-color:rgba(217,85,76,.45);background:#fff;color:#d9554c}@media(max-width:760px){.take-head{grid-template-columns:1fr auto;height:auto;padding:10px 14px}.timer{grid-column:1/3;margin-top:8px}.exam-body{grid-template-columns:1fr;padding:12px}.answer-sheet{position:static}.question-panel{padding:20px 18px 78px}.question-actions{right:18px;left:18px}}
</style>

@ -3,13 +3,6 @@
<main class="training-core">
<section class="task-header">
<div class="task-head-main">
<div class="task-head-top">
<span class="task-badge">
<el-icon><Operation /></el-icon>
核心实训 · 产品开发基础
</span>
<span class="task-status">进行中 · Step {{ String(currentStep).padStart(2, "0") }}</span>
</div>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -987,58 +980,9 @@ function exportOutcome() {
flex: 1 1 auto;
}
.task-head-top {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: nowrap;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 3px 10px;
border: 1px solid #bfdbfe;
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: var(--student-fs-caption);
font-weight: 600;
white-space: nowrap;
.el-icon {
font-size: 13px;
}
}
.task-status {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 3px 10px;
border-radius: 999px;
color: var(--student-text-secondary);
background: #f3f4f6;
font-family: var(--student-font-data);
font-size: var(--student-fs-caption);
font-weight: 600;
white-space: nowrap;
&::before {
content: "";
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--student-accent-light);
animation: pulse 1.8s ease-in-out infinite;
}
}
@keyframes pulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 1; }
}
.task-title {
margin: 0;

@ -3,13 +3,6 @@
<main class="factors-core">
<section class="task-header">
<div class="task-head-main">
<div class="task-head-top">
<span class="task-badge">
<el-icon><Operation /></el-icon>
核心实训 · 互联网产品开发基础
</span>
<span class="task-status">进行中 · Step {{ String(currentStep + 1).padStart(2, "0") }}</span>
</div>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -584,53 +577,9 @@ function exportOutcome() {
min-width: 0;
}
.task-head-top {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: nowrap;
}
.task-status {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 3px 10px;
border-radius: 999px;
color: var(--student-accent);
background: var(--student-accent-soft);
font-family: var(--student-font-data);
font-size: var(--student-fs-caption);
font-weight: 600;
white-space: nowrap;
&::before {
content: "";
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--student-accent-light);
animation: pulse 1.8s ease-in-out infinite;
}
}
@keyframes pulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 1; }
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
}
.task-title {
margin: 0;
@ -913,7 +862,7 @@ function exportOutcome() {
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -976,7 +925,7 @@ function exportOutcome() {
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: #2563eb;
background: #ffffff;
@ -1013,9 +962,9 @@ function exportOutcome() {
/* ===== 共用组件换肤:TrainingMaterialButton 资料按钮 → 教育蓝 ===== */
.product-factors .workbench-actions .material-button.el-button {
height: 36px !important;
min-height: 36px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
height: 34px !important;
min-height: 34px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1200,11 +1149,11 @@ function exportOutcome() {
justify-content: center !important;
gap: 6px !important;
width: auto !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
max-height: none !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1237,10 +1186,10 @@ function exportOutcome() {
gap: 8px !important;
min-width: 0 !important;
width: auto !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;

@ -1,12 +1,8 @@
<template>
<template>
<div class="product-process student-training-shell">
<main class="process-core">
<section class="task-header">
<div class="task-head-main">
<div class="task-head-top">
<span class="task-badge"><el-icon><Operation /></el-icon>核心实训 · 产品开发基础</span>
<span class="task-status">进行中 · Step {{ String(currentStep).padStart(2, "0") }}</span>
</div>
<h1 class="task-title">{{ taskTitle }}</h1>
<div class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -40,6 +36,7 @@
</div>
</section>
<section class="process-workbench">
<nav v-if="trainingSteps.length" class="step-indicator" aria-label="产品开发主要流程步骤">
<button
v-for="(step, index) in trainingSteps"
@ -714,53 +711,9 @@ function exportOutcome() {
min-width: 0;
}
.task-head-top {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: nowrap;
}
.task-status {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 3px 10px;
border-radius: 999px;
color: var(--student-accent);
background: var(--student-accent-soft);
font-family: var(--student-font-data);
font-size: var(--student-fs-caption);
font-weight: 600;
white-space: nowrap;
&::before {
content: "";
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--student-accent-light);
animation: pulse 1.8s ease-in-out infinite;
}
}
@keyframes pulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 1; }
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
}
.task-title {
margin: 0;
@ -857,7 +810,7 @@ function exportOutcome() {
gap: 7px;
min-height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: #2563eb;
background: #ffffff;
@ -1082,7 +1035,7 @@ tr.is-incorrect .classification-feedback {
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -1305,7 +1258,7 @@ tr.is-incorrect .classification-feedback {
align-items: center;
margin-left: 8px;
padding: 2px 10px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 6px;
color: var(--student-accent);
background: #ffffff;
@ -1575,9 +1528,9 @@ tr.is-incorrect .classification-feedback {
* 共用组件换肤:TrainingMaterialButton 资料按钮 → 教育蓝
* ============================================================ */
.product-process .workbench-actions .material-button.el-button {
height: 36px !important;
min-height: 36px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
height: 34px !important;
min-height: 34px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1623,11 +1576,11 @@ tr.is-incorrect .classification-feedback {
justify-content: center !important;
gap: 6px !important;
width: auto !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
max-height: none !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1654,10 +1607,10 @@ tr.is-incorrect .classification-feedback {
justify-content: center !important;
gap: 5px !important;
width: auto !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1694,10 +1647,10 @@ tr.is-incorrect .classification-feedback {
gap: 8px !important;
min-width: 0 !important;
width: auto !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;

@ -19,9 +19,9 @@
style="width: 650px"
border
:header-cell-style="{
color: '#fff',
color: 'var(--student-text-secondary, #fff)',
fontSize: '14px',
backgroundColor: '#1e88e5',
backgroundColor: 'var(--student-panel-bg, #1e88e5)',
}"
>
<el-table-column label="交易单号" align="center" prop="id"></el-table-column>
@ -44,9 +44,9 @@
style="width: 450px"
border
:header-cell-style="{
color: '#fff',
color: 'var(--student-text-secondary, #fff)',
fontSize: '14px',
backgroundColor: '#1e88e5',
backgroundColor: 'var(--student-panel-bg, #1e88e5)',
}"
>
<el-table-column label="商品名称" align="center" prop="name"></el-table-column>
@ -78,9 +78,9 @@
style="width: 650px"
border
:header-cell-style="{
color: '#fff',
color: 'var(--student-text-secondary, #fff)',
fontSize: '14px',
backgroundColor: '#1e88e5',
backgroundColor: 'var(--student-panel-bg, #1e88e5)',
}"
>
<el-table-column label="商品名称" align="center" prop="name"></el-table-column>
@ -110,9 +110,9 @@
style="width: 650px"
border
:header-cell-style="{
color: '#fff',
color: 'var(--student-text-secondary, #fff)',
fontSize: '14px',
backgroundColor: '#1e88e5',
backgroundColor: 'var(--student-panel-bg, #1e88e5)',
}"
>
<el-table-column label="商品名称" align="center" prop="data1"></el-table-column>
@ -158,9 +158,9 @@
style="width: 580px; margin-top: 10px"
border
:header-cell-style="{
color: '#fff',
color: 'var(--student-text-secondary, #fff)',
fontSize: '14px',
backgroundColor: '#1e88e5',
backgroundColor: 'var(--student-panel-bg, #1e88e5)',
}"
>
<el-table-column label="用户ID" align="center" prop="data1" width="160"></el-table-column>
@ -172,9 +172,9 @@
style="width: 680px"
border
:header-cell-style="{
color: '#fff',
color: 'var(--student-text-secondary, #fff)',
fontSize: '14px',
backgroundColor: '#1e88e5',
backgroundColor: 'var(--student-panel-bg, #1e88e5)',
}"
>
<el-table-column label="商品名称" align="center" prop="data1"></el-table-column>
@ -1274,14 +1274,14 @@ const submitTimeCount = () => {
<style scoped lang="scss">
.box {
width: 100%;
color: #2c4a6a;
color: var(--student-text, #2c4a6a);
background:
radial-gradient(circle at 12% 0%, rgba(30, 136, 229, 0.1), transparent 30%),
radial-gradient(circle at 12% 0%, var(--student-shadow-color, rgba(30, 136, 229, 0.1)), transparent 30%),
#ffffff;
border: 1px solid #cfe2f5;
border: 1px solid var(--student-accent-border, #cfe2f5);
border-radius: 12px;
padding: 18px;
box-shadow: inset 0 1px 0 rgba(30, 136, 229, 0.15);
box-shadow: inset 0 1px 0 var(--student-shadow-color, rgba(30, 136, 229, 0.15));
.import {
display: flex;
@ -1289,7 +1289,7 @@ const submitTimeCount = () => {
font-weight: bold;
width: 150px;
height: 50px;
background: linear-gradient(95deg, #1e88e5, #1565c0);
background: linear-gradient(95deg, var(--student-accent, #1e88e5), var(--student-accent-deep, #1565c0));
text-align: center;
align-items: center;
line-height: 50px;
@ -1300,7 +1300,7 @@ const submitTimeCount = () => {
}
}
.caseBack {
color: #2c4a6a;
color: var(--student-text, #2c4a6a);
.title {
font-weight: bold;
margin-top: 10px;
@ -1320,7 +1320,7 @@ const submitTimeCount = () => {
line-height: 31px;
width: 89px;
height: 31px;
background: linear-gradient(95deg, #1e88e5, #1565c0);
background: linear-gradient(95deg, var(--student-accent, #1e88e5), var(--student-accent-deep, #1565c0));
}
.submit {
cursor: pointer;
@ -1332,7 +1332,7 @@ const submitTimeCount = () => {
line-height: 31px;
width: 99px;
height: 31px;
background: linear-gradient(95deg, #1e88e5, #1565c0);
background: linear-gradient(95deg, var(--student-accent, #1e88e5), var(--student-accent-deep, #1565c0));
}
.customerType {
padding-left: 10px;
@ -1341,7 +1341,7 @@ const submitTimeCount = () => {
width: 945px;
height: 26px;
// background: #003b75;
background: #f0f6fd;
background: var(--student-accent-soft, #f0f6fd);
border-radius: 10px;
// border: 1px solid #0052a3;
font-size: var(--student-fs-caption);
@ -1364,7 +1364,7 @@ const submitTimeCount = () => {
width: min(1400px, 100%);
height: 1px;
border: 0;
background: #cfe2f5;
background: var(--student-accent-border, #cfe2f5);
margin-top: 20px;
margin-bottom: 20px;
}
@ -1375,11 +1375,11 @@ const submitTimeCount = () => {
// }
::v-deep .el-table tr {
background-color: #ffffff !important;
color: #2c4a6a;
color: var(--student-text, #2c4a6a);
}
/* 将悬停背景色改为红色 */
::v-deep .el-table--enable-row-hover .el-table__body tr:hover > td {
background-color: rgba(30, 136, 229, 0.1) !important;
background-color: var(--student-accent-soft, rgba(30, 136, 229, 0.1)) !important;
}
::v-deep .el-table td {
padding-top: 4px;
@ -1387,38 +1387,38 @@ const submitTimeCount = () => {
}
:deep(.el-table) {
--el-table-border-color: #cfe2f5;
--el-table-header-bg-color: #1565c0;
--el-table-header-text-color: #ffffff;
--el-table-row-hover-bg-color: rgba(30, 136, 229, 0.1);
--el-table-border-color: var(--student-accent-border, #cfe2f5);
--el-table-header-bg-color: var(--student-panel-bg, #1565c0);
--el-table-header-text-color: var(--student-text-secondary, #ffffff);
--el-table-row-hover-bg-color: var(--student-accent-soft, rgba(30, 136, 229, 0.1));
--el-table-bg-color: #ffffff;
--el-table-tr-bg-color: #ffffff;
--el-table-text-color: #2c4a6a;
--el-table-text-color: var(--student-text, #2c4a6a);
overflow: hidden;
border: 1px solid #cfe2f5;
border: 1px solid var(--student-accent-border, #cfe2f5);
border-radius: 10px;
}
:deep(.el-table th.el-table__cell) {
color: #ffffff !important;
background: linear-gradient(180deg, #1e88e5, #1565c0) !important;
color: var(--student-text-secondary, #ffffff) !important;
background: var(--student-panel-bg, linear-gradient(180deg, #1e88e5, #1565c0)) !important;
font-weight: 800;
}
:deep(.el-table tr),
:deep(.el-table td.el-table__cell) {
color: #2c4a6a !important;
color: var(--student-text, #2c4a6a) !important;
background: #ffffff !important;
}
:deep(.el-table--enable-row-hover .el-table__body tr:hover > td) {
background-color: rgba(30, 136, 229, 0.1) !important;
background-color: var(--student-accent-soft, rgba(30, 136, 229, 0.1)) !important;
}
:deep(.el-input__wrapper),
:deep(.el-select__wrapper) {
border: 1px solid #cfe2f5;
color: #1e3a5f;
border: 1px solid var(--student-accent-border, #cfe2f5);
color: var(--student-text, #1e3a5f);
box-shadow: none !important;
background: #ffffff;
}
@ -1429,11 +1429,11 @@ const submitTimeCount = () => {
min-width: 156px;
height: 40px;
padding: 0 16px;
border: 1px solid #cfe2f5;
border: 1px solid var(--student-accent-border, #cfe2f5);
border-radius: 999px;
color: #ffffff;
background: linear-gradient(180deg, #1e88e5, #1565c0);
box-shadow: 0 8px 18px rgba(30, 136, 229, 0.15);
background: linear-gradient(180deg, var(--student-accent, #1e88e5), var(--student-accent-deep, #1565c0));
box-shadow: 0 8px 18px var(--student-shadow-color, rgba(30, 136, 229, 0.15));
}
.import img {
@ -1450,18 +1450,18 @@ const submitTimeCount = () => {
min-width: 92px;
min-height: 40px;
padding: 0 16px;
border: 1px solid #cfe2f5;
border: 1px solid var(--student-accent-border, #cfe2f5);
border-radius: 999px;
color: #ffffff;
line-height: 1;
background: linear-gradient(180deg, #1e88e5, #1565c0) !important;
box-shadow: 0 6px 14px rgba(30, 136, 229, 0.15);
background: linear-gradient(180deg, var(--student-accent, #1e88e5), var(--student-accent-deep, #1565c0)) !important;
box-shadow: 0 6px 14px var(--student-shadow-color, rgba(30, 136, 229, 0.15));
}
.download:hover,
.submit:hover {
border-color: #42a5f5;
background: linear-gradient(180deg, #42a5f5, #1e88e5) !important;
border-color: var(--student-accent-light, #42a5f5);
background: linear-gradient(180deg, var(--student-accent-light, #42a5f5), var(--student-accent, #1e88e5)) !important;
}
.customerType {
@ -1470,10 +1470,10 @@ const submitTimeCount = () => {
min-height: 48px;
height: auto;
padding: 11px 14px;
color: #2c4a6a;
color: var(--student-text, #2c4a6a);
line-height: 1.6;
background: linear-gradient(90deg, rgba(30, 136, 229, 0.1), rgba(30, 136, 229, 0.04));
border: 1px solid #cfe2f5;
background: var(--student-accent-soft, linear-gradient(90deg, rgba(30, 136, 229, 0.1), rgba(30, 136, 229, 0.04)));
border: 1px solid var(--student-accent-border, #cfe2f5);
border-radius: 9px;
}

@ -24,9 +24,9 @@
style="width: 650px"
border
:header-cell-style="{
color: '#fff',
color: 'var(--student-text-secondary, #fff)',
fontSize: '14px',
backgroundColor: '#1e88e5',
backgroundColor: 'var(--student-panel-bg, #1e88e5)',
}"
>
<el-table-column label="购物篮ID/订单ID" align="center" prop="id"></el-table-column>
@ -111,9 +111,9 @@
style="width: 350px"
border
:header-cell-style="{
color: '#fff',
color: 'var(--student-text-secondary, #fff)',
fontSize: '14px',
backgroundColor: '#1e88e5',
backgroundColor: 'var(--student-panel-bg, #1e88e5)',
}"
>
<el-table-column label="商品组合" align="center" prop="name"></el-table-column>
@ -148,9 +148,9 @@
style="width: 650px"
border
:header-cell-style="{
color: '#fff',
color: 'var(--student-text-secondary, #fff)',
fontSize: '14px',
backgroundColor: '#1e88e5',
backgroundColor: 'var(--student-panel-bg, #1e88e5)',
}"
>
<el-table-column label="商品组合" align="center" prop="data1"></el-table-column>
@ -207,9 +207,9 @@
style="width: 350px"
border
:header-cell-style="{
color: '#fff',
color: 'var(--student-text-secondary, #fff)',
fontSize: '14px',
backgroundColor: '#1e88e5',
backgroundColor: 'var(--student-panel-bg, #1e88e5)',
}"
>
<el-table-column label="商品组合" align="center" prop="data1" width="120"></el-table-column>
@ -1174,14 +1174,14 @@ const submitTimeCount = () => {
<style scoped lang="scss">
.content {
width: 100%;
color: #2c4a6a;
color: var(--student-text, #2c4a6a);
background:
radial-gradient(circle at 12% 0%, rgba(30, 136, 229, 0.1), transparent 30%),
radial-gradient(circle at 12% 0%, var(--student-shadow-color, rgba(30, 136, 229, 0.1)), transparent 30%),
#ffffff;
border: 1px solid #cfe2f5;
border: 1px solid var(--student-accent-border, #cfe2f5);
border-radius: 12px;
padding: 18px;
box-shadow: inset 0 1px 0 rgba(30, 136, 229, 0.15);
box-shadow: inset 0 1px 0 var(--student-shadow-color, rgba(30, 136, 229, 0.15));
.import {
display: flex;
@ -1189,7 +1189,7 @@ const submitTimeCount = () => {
font-weight: bold;
width: 150px;
height: 50px;
background: linear-gradient(95deg, #1e88e5, #1565c0);
background: linear-gradient(95deg, var(--student-accent, #1e88e5), var(--student-accent-deep, #1565c0));
text-align: center;
align-items: center;
line-height: 50px;
@ -1200,7 +1200,7 @@ const submitTimeCount = () => {
}
}
.caseBack {
color: #2c4a6a;
color: var(--student-text, #2c4a6a);
.title {
font-weight: bold;
margin-top: 10px;
@ -1220,7 +1220,7 @@ const submitTimeCount = () => {
line-height: 31px;
width: 89px;
height: 31px;
background: linear-gradient(95deg, #1e88e5, #1565c0);
background: linear-gradient(95deg, var(--student-accent, #1e88e5), var(--student-accent-deep, #1565c0));
}
.submit {
cursor: pointer;
@ -1232,7 +1232,7 @@ const submitTimeCount = () => {
line-height: 31px;
width: 99px;
height: 31px;
background: linear-gradient(95deg, #1e88e5, #1565c0);
background: linear-gradient(95deg, var(--student-accent, #1e88e5), var(--student-accent-deep, #1565c0));
}
.customerType {
padding-left: 10px;
@ -1241,7 +1241,7 @@ const submitTimeCount = () => {
width: 945px;
height: 26px;
// background: #003b75;
background: #f0f6fd;
background: var(--student-accent-soft, #f0f6fd);
border-radius: 10px;
// border: 1px solid #0052a3;
font-size: var(--student-fs-caption);
@ -1255,15 +1255,15 @@ const submitTimeCount = () => {
width: min(1400px, 100%);
height: 1px;
border: 0;
background: #cfe2f5;
background: var(--student-accent-border, #cfe2f5);
margin-top: 20px;
margin-bottom: 20px;
}
.addBtn {
background-color: #1e88e5;
background-color: var(--student-accent, #1e88e5);
color: #ffffff;
height: 31px;
border: 1px solid #1e88e5;
border: 1px solid var(--student-accent, #1e88e5);
margin-left: 10px;
}
.comList {
@ -1271,7 +1271,7 @@ const submitTimeCount = () => {
ul {
text-align: center;
list-style-type: none;
border: 1px solid #cfe2f5;
border: 1px solid var(--student-accent-border, #cfe2f5);
border-bottom: none;
width: 124px;
padding: 0;
@ -1281,7 +1281,7 @@ const submitTimeCount = () => {
width: 122px;
height: 40px;
line-height: 40px;
background: linear-gradient(180deg, #1e88e5, #1565c0);
background: var(--student-panel-bg, linear-gradient(180deg, #1e88e5, #1565c0));
margin: 0;
}
li {
@ -1291,8 +1291,8 @@ const submitTimeCount = () => {
width: 122px;
height: 30px;
// background: #003b75;
background: #f0f6fd;
border-bottom: 1px solid #cfe2f5;
background: var(--student-accent-soft, #f0f6fd);
border-bottom: 1px solid var(--student-accent-border, #cfe2f5);
font-size: var(--student-fs-body);
}
}
@ -1304,11 +1304,11 @@ const submitTimeCount = () => {
// }
::v-deep .el-table tr {
background-color: #ffffff !important;
color: #2c4a6a;
color: var(--student-text, #2c4a6a);
}
/* 将悬停背景色改为红色 */
::v-deep .el-table--enable-row-hover .el-table__body tr:hover > td {
background-color: rgba(30, 136, 229, 0.1) !important;
background-color: var(--student-accent-soft, rgba(30, 136, 229, 0.1)) !important;
}
::v-deep .el-table td {
padding-top: 4px;
@ -1316,38 +1316,38 @@ const submitTimeCount = () => {
}
:deep(.el-table) {
--el-table-border-color: #cfe2f5;
--el-table-header-bg-color: #1565c0;
--el-table-header-text-color: #ffffff;
--el-table-row-hover-bg-color: rgba(30, 136, 229, 0.1);
--el-table-border-color: var(--student-accent-border, #cfe2f5);
--el-table-header-bg-color: var(--student-panel-bg, #1565c0);
--el-table-header-text-color: var(--student-text-secondary, #ffffff);
--el-table-row-hover-bg-color: var(--student-accent-soft, rgba(30, 136, 229, 0.1));
--el-table-bg-color: #ffffff;
--el-table-tr-bg-color: #ffffff;
--el-table-text-color: #2c4a6a;
--el-table-text-color: var(--student-text, #2c4a6a);
overflow: hidden;
border: 1px solid #cfe2f5;
border: 1px solid var(--student-accent-border, #cfe2f5);
border-radius: 10px;
}
:deep(.el-table th.el-table__cell) {
color: #ffffff !important;
background: linear-gradient(180deg, #1e88e5, #1565c0) !important;
color: var(--student-text-secondary, #ffffff) !important;
background: var(--student-panel-bg, linear-gradient(180deg, #1e88e5, #1565c0)) !important;
font-weight: 800;
}
:deep(.el-table tr),
:deep(.el-table td.el-table__cell) {
color: #2c4a6a !important;
color: var(--student-text, #2c4a6a) !important;
background: #ffffff !important;
}
:deep(.el-table--enable-row-hover .el-table__body tr:hover > td) {
background-color: rgba(30, 136, 229, 0.1) !important;
background-color: var(--student-accent-soft, rgba(30, 136, 229, 0.1)) !important;
}
:deep(.el-input__wrapper),
:deep(.el-select__wrapper) {
border: 1px solid #cfe2f5;
color: #1e3a5f;
border: 1px solid var(--student-accent-border, #cfe2f5);
color: var(--student-text, #1e3a5f);
box-shadow: none !important;
background: #ffffff;
}
@ -1358,11 +1358,11 @@ const submitTimeCount = () => {
min-width: 156px;
height: 40px;
padding: 0 16px;
border: 1px solid #cfe2f5;
border: 1px solid var(--student-accent-border, #cfe2f5);
border-radius: 999px;
color: #ffffff;
background: linear-gradient(180deg, #1e88e5, #1565c0);
box-shadow: 0 8px 18px rgba(30, 136, 229, 0.15);
background: linear-gradient(180deg, var(--student-accent, #1e88e5), var(--student-accent-deep, #1565c0));
box-shadow: 0 8px 18px var(--student-shadow-color, rgba(30, 136, 229, 0.15));
}
.import img {
@ -1379,18 +1379,18 @@ const submitTimeCount = () => {
min-width: 92px;
min-height: 40px;
padding: 0 16px;
border: 1px solid #cfe2f5;
border: 1px solid var(--student-accent-border, #cfe2f5);
border-radius: 999px;
color: #ffffff;
line-height: 1;
background: linear-gradient(180deg, #1e88e5, #1565c0) !important;
box-shadow: 0 6px 14px rgba(30, 136, 229, 0.15);
background: linear-gradient(180deg, var(--student-accent, #1e88e5), var(--student-accent-deep, #1565c0)) !important;
box-shadow: 0 6px 14px var(--student-shadow-color, rgba(30, 136, 229, 0.15));
}
.download:hover,
.submit:hover {
border-color: #42a5f5;
background: linear-gradient(180deg, #42a5f5, #1e88e5) !important;
border-color: var(--student-accent-light, #42a5f5);
background: linear-gradient(180deg, var(--student-accent-light, #42a5f5), var(--student-accent, #1e88e5)) !important;
}
.customerType {
@ -1399,10 +1399,10 @@ const submitTimeCount = () => {
min-height: 48px;
height: auto;
padding: 11px 14px;
color: #2c4a6a;
color: var(--student-text, #2c4a6a);
line-height: 1.6;
background: linear-gradient(90deg, rgba(30, 136, 229, 0.1), rgba(30, 136, 229, 0.04));
border: 1px solid #cfe2f5;
background: var(--student-accent-soft, linear-gradient(90deg, rgba(30, 136, 229, 0.1), rgba(30, 136, 229, 0.04)));
border: 1px solid var(--student-accent-border, #cfe2f5);
border-radius: 9px;
}
@ -1415,26 +1415,26 @@ const submitTimeCount = () => {
min-height: 40px;
padding: 0 18px;
border-radius: 999px;
border-color: #cfe2f5;
border-color: var(--student-accent-border, #cfe2f5);
color: #ffffff;
background: linear-gradient(180deg, #1e88e5, #1565c0);
background: linear-gradient(180deg, var(--student-accent, #1e88e5), var(--student-accent-deep, #1565c0));
}
.comList ul {
overflow: hidden;
border-color: #cfe2f5;
border-color: var(--student-accent-border, #cfe2f5);
border-radius: 8px;
}
.comList ul p {
color: #ffffff !important;
background: linear-gradient(180deg, #1e88e5, #1565c0);
color: var(--student-text-secondary, #ffffff) !important;
background: var(--student-panel-bg, linear-gradient(180deg, #1e88e5, #1565c0));
}
.comList ul li {
color: #2c4a6a;
background: #f0f6fd;
border-bottom-color: #cfe2f5;
color: var(--student-text, #2c4a6a);
background: var(--student-accent-soft, #f0f6fd);
border-bottom-color: var(--student-accent-border, #cfe2f5);
}
}

@ -28,9 +28,9 @@
style="width: 650px"
border
:header-cell-style="{
color: '#fff',
color: 'var(--student-text-secondary, #fff)',
fontSize: '14px',
backgroundColor: '#1e88e5!important',
backgroundColor: 'var(--student-panel-bg, #1e88e5)!important',
}"
>
<el-table-column label="" align="center" prop="data1"></el-table-column>
@ -65,9 +65,9 @@
style="width: 900px"
border
:header-cell-style="{
color: '#fff',
color: 'var(--student-text-secondary, #fff)',
fontSize: '14px',
backgroundColor: '#1e88e5!important',
backgroundColor: 'var(--student-panel-bg, #1e88e5)!important',
}"
>
<el-table-column label="" align="center" prop="data1"></el-table-column>
@ -1287,9 +1287,9 @@ const submitTimeCount = () => {
align-items: center;
width: 945px;
height: 26px;
background: #bbdefb;
background: var(--student-accent-soft, #bbdefb);
border-radius: 10px;
border: 1px solid #cfe2f5;
border: 1px solid var(--student-accent-border, #cfe2f5);
font-size: var(--student-fs-caption);
margin-top: 10px;
img {
@ -1300,7 +1300,7 @@ const submitTimeCount = () => {
.line {
width: 1400px;
height: 1px;
border: 1px solid #cfe2f5;
border: 1px solid var(--student-accent-border, #cfe2f5);
opacity: 0.5;
margin-top: 20px;
margin-bottom: 20px;

@ -3,10 +3,6 @@
<main class="after-sales-core">
<section class="task-header">
<div class="task-head-main">
<div class="task-head-top">
<span class="task-badge"><el-icon><Service /></el-icon> 核心实训 · 产品售后与服务设计</span>
<span class="task-status">进行中 · Step {{ String(currentStep).padStart(2, "0") }}</span>
</div>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -553,25 +549,7 @@ function exportOutcome() { const blob = new Blob([JSON.stringify({ currentStep:
flex: 1 1 auto;
}
.task-head-top {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: nowrap;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid #bfdbfe;
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
}
.task-title {
margin: 0;
@ -619,33 +597,7 @@ function exportOutcome() { const blob = new Blob([JSON.stringify({ currentStep:
p { margin: 0; }
}
.task-status {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 3px 10px;
border-radius: 999px;
color: var(--student-text-secondary);
background: #f3f4f6;
font-family: var(--student-font-data);
font-size: var(--student-fs-caption);
font-weight: 600;
white-space: nowrap;
&::before {
content: "";
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--student-accent-light);
animation: pulse 1.8s ease-in-out infinite;
}
}
@keyframes pulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 1; }
}
.after-sales-toolbar {
display: flex;
@ -745,7 +697,7 @@ function exportOutcome() { const blob = new Blob([JSON.stringify({ currentStep:
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -1121,7 +1073,7 @@ button:disabled {
.example-button {
margin-top: 8px;
padding: 3px 10px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 6px;
color: var(--student-accent);
background: #ffffff;
@ -1381,10 +1333,10 @@ button:disabled {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
min-height: 36px !important;
height: 36px !important;
min-height: 34px !important;
height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1419,10 +1371,10 @@ button:disabled {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
min-height: 36px !important;
height: 36px !important;
min-height: 34px !important;
height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;

@ -3,10 +3,6 @@
<main class="training-core">
<section class="task-header">
<div class="task-head-main">
<div class="task-head-top">
<span class="task-badge"><el-icon><Document /></el-icon> {{ badgeText }}</span>
<span v-if="hasConfiguredSteps" class="task-status">进行中 · Step {{ String(activeStep).padStart(2, '0') }}</span>
</div>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -250,26 +246,7 @@ function exportOutcome() { const blob = new Blob([JSON.stringify(buildProgress()
flex: 1 1 auto;
}
.task-head-top {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: nowrap;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 3px 10px;
border: 1px solid #bfdbfe;
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: var(--student-fs-caption);
font-weight: 600;
white-space: nowrap;
}
.task-title {
margin: 0;
@ -340,33 +317,7 @@ function exportOutcome() { const blob = new Blob([JSON.stringify(buildProgress()
}
}
.task-status {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 3px 10px;
border-radius: 999px;
color: var(--student-text-secondary);
background: #f3f4f6;
font-family: var(--student-font-data);
font-size: var(--student-fs-caption);
font-weight: 600;
white-space: nowrap;
&::before {
content: "";
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--student-accent-light);
animation: pulse 1.8s ease-in-out infinite;
}
}
@keyframes pulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 1; }
}
/* ============================================================
* 工作台容器
@ -445,7 +396,7 @@ function exportOutcome() { const blob = new Blob([JSON.stringify(buildProgress()
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -836,7 +787,7 @@ function exportOutcome() { const blob = new Blob([JSON.stringify(buildProgress()
min-width: 120px;
height: 40px;
padding: 0 20px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 10px;
color: var(--student-accent);
background: #ffffff;
@ -1077,10 +1028,10 @@ function exportOutcome() { const blob = new Blob([JSON.stringify(buildProgress()
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
min-height: 36px !important;
height: 36px !important;
min-height: 34px !important;
height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1115,10 +1066,10 @@ function exportOutcome() { const blob = new Blob([JSON.stringify(buildProgress()
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
min-height: 36px !important;
height: 36px !important;
min-height: 34px !important;
height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;

@ -3,13 +3,6 @@
<main class="product-positioning-core">
<section class="task-header">
<div class="task-head-main">
<div class="task-head-top">
<span class="task-badge">
<el-icon><Operation /></el-icon>
市场洞察与需求分析
</span>
<span class="task-status">进行中 · Step {{ String(form.activeStep).padStart(2, "0") }}</span>
</div>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -774,55 +767,9 @@ async function handleValueCanvasUpload(event) {
flex: 1 1 auto;
}
/* task-head-top:badge + 脉动状态横排 */
.task-head-top {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: nowrap;
}
.task-status {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 3px 10px;
border-radius: 999px;
color: var(--student-text-secondary);
background: #f3f4f6;
font-size: var(--student-fs-caption);
font-weight: 600;
white-space: nowrap;
&::before {
content: "";
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--student-accent-light);
animation: pulse 1.8s ease-in-out infinite;
}
}
@keyframes pulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 1; }
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
line-height: 1.4;
letter-spacing: 0;
}
.task-title {
margin: 4px 0 0;
@ -917,7 +864,7 @@ async function handleValueCanvasUpload(event) {
height: 36px;
min-height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -1132,7 +1079,7 @@ async function handleValueCanvasUpload(event) {
align-items: center;
justify-content: center;
gap: 7px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -1423,7 +1370,7 @@ async function handleValueCanvasUpload(event) {
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -1656,9 +1603,9 @@ async function handleValueCanvasUpload(event) {
* 顶部工具栏:TrainingMaterialButton 资料按钮 → 教育蓝
* ============================================================ */
.product-positioning-page .workbench-actions .material-button.el-button {
height: 36px !important;
min-height: 36px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
height: 34px !important;
min-height: 34px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1693,10 +1640,10 @@ async function handleValueCanvasUpload(event) {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1719,10 +1666,10 @@ async function handleValueCanvasUpload(event) {
* ============================================================ */
#app .studentLayout section.app-main:has(.product-positioning-page) .training-actions .el-button.training-action {
min-width: 140px !important;
min-height: 36px !important;
height: 36px !important;
min-height: 34px !important;
height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;

@ -3,10 +3,6 @@
<main class="hardware-core">
<section class="task-header">
<div class="task-head-main">
<div class="task-head-top">
<span class="task-badge"><el-icon><DataAnalysis /></el-icon> 核心实训 · 智能硬件成本估算</span>
<span class="task-status">进行中 · Step {{ String(currentStep).padStart(2, "0") }}</span>
</div>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -893,40 +889,8 @@ onMounted(async () => {
flex: 1 1 auto;
}
/* task-head-top:badge + 脉动状态横排 */
.task-head-top {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: nowrap;
}
.task-status {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 3px 10px;
border-radius: 999px;
color: var(--student-text-secondary);
background: #f3f4f6;
font-size: var(--student-fs-caption);
font-weight: 600;
white-space: nowrap;
&::before {
content: "";
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--student-accent-light);
animation: pulse 1.8s ease-in-out infinite;
}
}
@keyframes pulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 1; }
}
.task-badge,
.section-eyebrow {
@ -937,20 +901,6 @@ onMounted(async () => {
text-transform: uppercase;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
text-transform: none;
letter-spacing: 0;
}
.task-title {
margin: 0;
@ -1264,7 +1214,7 @@ onMounted(async () => {
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -1635,10 +1585,10 @@ onMounted(async () => {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
min-height: 36px !important;
height: 36px !important;
min-height: 34px !important;
height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1676,10 +1626,10 @@ onMounted(async () => {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
min-height: 36px !important;
height: 36px !important;
min-height: 34px !important;
height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1705,10 +1655,10 @@ onMounted(async () => {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
min-height: 36px !important;
height: 36px !important;
min-height: 34px !important;
height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;

@ -3,13 +3,6 @@
<main class="training-core">
<section class="task-header">
<div class="task-head-main">
<div class="task-head-top">
<span class="task-badge">
<el-icon><DataLine /></el-icon>
核心实训 · 产品规划与设计
</span>
<span class="task-status">进行中 · Step {{ String(currentStep).padStart(2, "0") }}</span>
</div>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -592,58 +585,9 @@ function exportOutcome() {
flex: 1 1 auto;
}
.task-head-top {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: nowrap;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 3px 10px;
border: 1px solid #bfdbfe;
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: var(--student-fs-caption);
font-weight: 600;
white-space: nowrap;
.el-icon {
font-size: 13px;
}
}
.task-status {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 3px 10px;
border-radius: 999px;
color: var(--student-text-secondary);
background: #f3f4f6;
font-family: var(--student-font-data);
font-size: var(--student-fs-caption);
font-weight: 600;
white-space: nowrap;
&::before {
content: "";
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--student-accent-light);
animation: pulse 1.8s ease-in-out infinite;
}
}
@keyframes pulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 1; }
}
.task-title {
margin: 0;
@ -732,7 +676,7 @@ function exportOutcome() {
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -1482,9 +1426,9 @@ function exportOutcome() {
* 共用组件换肤:TrainingMaterialButton 资料按钮
* ============================================================ */
.market-selection-page .market-selection-toolbar .material-button.el-button {
height: 36px !important;
min-height: 36px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
height: 34px !important;
min-height: 34px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1523,10 +1467,10 @@ function exportOutcome() {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1564,11 +1508,11 @@ function exportOutcome() {
align-items: center !important;
justify-content: center !important;
gap: 8px !important;
height: 40px !important;
min-height: 40px !important;
padding: 0 18px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border-radius: 10px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
font-size: 13px !important;
@ -1591,7 +1535,7 @@ function exportOutcome() {
.market-selection-page .step-actions .step-action-btn--next,
.market-selection-page .step-actions .step-action-btn--previous {
border-color: rgba(37, 99, 235, 0.45) !important;
border-color: rgba(37, 99, 235, 0.35) !important;
color: #2563eb !important;
}
@ -1605,11 +1549,11 @@ function exportOutcome() {
* 底部提交/重置按钮(training-actions)
* ============================================================ */
.market-selection-page .training-actions .el-button {
min-width: 140px !important;
height: 40px !important;
padding: 0 18px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border-radius: 10px !important;
min-width: 112px !important;
height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
font-size: 13px !important;

@ -3,10 +3,6 @@
<main class="opportunity-core">
<section class="task-header">
<div class="task-head-main">
<div class="task-head-top">
<span class="task-badge"><el-icon><DataAnalysis /></el-icon> 核心实训 · 市场洞察与需求分析</span>
<span class="task-status">进行中 · Step {{ String(currentStep).padStart(2, "0") }}</span>
</div>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -311,20 +307,6 @@ function exportOutcome() { const blob = new Blob([JSON.stringify({ taskName: tas
text-transform: uppercase;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
text-transform: none;
letter-spacing: 0;
}
.task-header h1 {
margin: 0;
@ -343,40 +325,8 @@ function exportOutcome() { const blob = new Blob([JSON.stringify({ taskName: tas
flex: 1 1 auto;
}
/* task-head-top:badge + 脉动状态横排 */
.task-head-top {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: nowrap;
}
.task-status {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 3px 10px;
border-radius: 999px;
color: var(--student-text-secondary);
background: #f3f4f6;
font-size: var(--student-fs-caption);
font-weight: 600;
white-space: nowrap;
&::before {
content: "";
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--student-accent-light);
animation: pulse 1.8s ease-in-out infinite;
}
}
@keyframes pulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 1; }
}
.task-brief {
margin: 0;
@ -802,7 +752,7 @@ function exportOutcome() { const blob = new Blob([JSON.stringify({ taskName: tas
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -1012,9 +962,9 @@ function exportOutcome() { const blob = new Blob([JSON.stringify({ taskName: tas
* 顶部工具栏:TrainingMaterialButton 资料按钮 → 教育蓝
* ============================================================ */
.opportunity-page .opportunity-toolbar .material-button.el-button {
height: 36px !important;
min-height: 36px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
height: 34px !important;
min-height: 34px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1049,10 +999,10 @@ function exportOutcome() { const blob = new Blob([JSON.stringify({ taskName: tas
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;

@ -3,10 +3,6 @@
<main class="price-core">
<section class="task-header">
<div class="task-head-main">
<div class="task-head-top">
<span class="task-badge">核心实训 · 新产品定价</span>
<span class="task-status">进行中 · Step {{ String(currentStep).padStart(2, "0") }}</span>
</div>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -1639,54 +1635,9 @@ onMounted(async () => {
flex: 1 1 auto;
}
.task-head-top {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: nowrap;
margin-bottom: 8px;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
}
.task-status {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 3px 10px;
border-radius: 999px;
color: var(--student-text-secondary);
background: #f3f4f6;
font-family: var(--student-font-data);
font-size: var(--student-fs-caption);
font-weight: 600;
white-space: nowrap;
&::before {
content: "";
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--student-accent-light);
animation: pulse 1.8s ease-in-out infinite;
}
}
@keyframes pulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 1; }
}
.task-title {
margin: 0;
@ -2546,9 +2497,9 @@ onMounted(async () => {
* ============================================================ */
.price-page .price-toolbar .material-button.el-button,
.price-page .workbench-actions .material-button.el-button {
height: 36px !important;
min-height: 36px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
height: 34px !important;
min-height: 34px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -2588,10 +2539,10 @@ onMounted(async () => {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -2621,11 +2572,11 @@ onMounted(async () => {
align-items: center !important;
justify-content: center !important;
gap: 8px !important;
height: 40px !important;
min-height: 40px !important;
padding: 0 18px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border-radius: 10px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
font-size: 13px !important;
@ -2668,10 +2619,10 @@ onMounted(async () => {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -2697,8 +2648,8 @@ onMounted(async () => {
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
height: 36px !important;
min-height: 36px !important;
height: 34px !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid #e5e7eb !important;
border-radius: 8px !important;

@ -3,10 +3,6 @@
<main class="requirements-core">
<section class="task-header">
<div class="task-head-main">
<div class="task-head-top">
<span class="task-badge"><el-icon><Document /></el-icon> 产品规划与设计</span>
<span class="task-status">进行中 · Step {{ String(currentStep).padStart(2, "0") }}</span>
</div>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -630,53 +626,9 @@ function exportOutcome() { if (currentStep.value === 2) { exportStepTwoTable();
flex: 1 1 auto;
}
.task-head-top {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: nowrap;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid #bfdbfe;
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
}
.task-status {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 3px 10px;
border-radius: 999px;
color: var(--student-text-secondary);
background: #f3f4f6;
font-family: var(--student-font-data);
font-size: var(--student-fs-caption);
font-weight: 600;
white-space: nowrap;
&::before {
content: "";
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--student-accent-light);
animation: pulse 1.8s ease-in-out infinite;
}
}
@keyframes pulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 1; }
}
.task-title {
margin: 0;
@ -1138,7 +1090,7 @@ function exportOutcome() { if (currentStep.value === 2) { exportStepTwoTable();
.example-bar button {
flex: 0 0 auto;
padding: 4px 10px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 6px;
color: var(--student-accent);
background: #ffffff;
@ -1363,7 +1315,7 @@ function exportOutcome() { if (currentStep.value === 2) { exportStepTwoTable();
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -1605,10 +1557,10 @@ function exportOutcome() { if (currentStep.value === 2) { exportStepTwoTable();
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
min-height: 36px !important;
height: 36px !important;
min-height: 34px !important;
height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
@ -1643,10 +1595,10 @@ function exportOutcome() { if (currentStep.value === 2) { exportStepTwoTable();
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
min-height: 36px !important;
height: 36px !important;
min-height: 34px !important;
height: 34px !important;
padding: 0 14px !important;
border: 1px solid rgba(37, 99, 235, 0.45) !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;

@ -3,10 +3,6 @@
<main class="architecture-core">
<section class="task-header">
<div class="task-head-main">
<div class="task-head-top">
<span class="task-badge"><el-icon><Operation /></el-icon> 核心实训 · 产品规划与设计</span>
<span class="task-status">进行中 · Step {{ String(currentStep).padStart(2, "0") }}</span>
</div>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -494,58 +490,9 @@ function exportOutcome() { const blob = new Blob([JSON.stringify(buildAnswer(),
flex: 1 1 auto;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 3px 10px;
border: 1px solid #bfdbfe;
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: var(--student-fs-caption);
font-weight: 600;
white-space: nowrap;
.el-icon {
font-size: 13px;
}
}
/* task-head-top:badge + 脉动状态横排 */
.task-head-top {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: nowrap;
}
.task-status {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 3px 10px;
border-radius: 999px;
color: var(--student-text-secondary);
background: #f3f4f6;
font-size: var(--student-fs-caption);
font-weight: 600;
white-space: nowrap;
&::before {
content: "";
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--student-accent-light);
animation: pulse 1.8s ease-in-out infinite;
}
}
@keyframes pulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 1; }
}
.task-title {
margin: 0;
@ -634,7 +581,7 @@ function exportOutcome() { const blob = new Blob([JSON.stringify(buildAnswer(),
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;
@ -1197,7 +1144,7 @@ button:disabled {
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: var(--student-accent);
background: #ffffff;

@ -97,7 +97,7 @@ const projectStudyTimes = ref([]);
const loading = ref(true);
const loadError = ref("");
const MODULE_COLORS = ["#1f2937", "#4b5563", "#6b7280", "#9ca3af", "#c4c9d1", "#374151"];
const MODULE_COLORS = ["#1d4ed8", "#2563eb", "#3b82f6", "#60a5fa", "#93c5fd", "#bfdbfe"];
let scoreChart;
let studyTimeChart;
@ -180,7 +180,7 @@ const renderProgressChart = () => {
type: "bar",
stack: "tasks",
barMaxWidth: 18,
itemStyle: { color: "#1f2937", borderRadius: [9, 0, 0, 9] },
itemStyle: { color: "#2563eb", 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: "#e5e7eb", borderRadius: [0, 9, 9, 0] },
itemStyle: { color: "#dbeafe", 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: "#4b5563", borderRadius: [0, 9, 9, 0] },
itemStyle: { color: "#3b82f6", borderRadius: [0, 9, 9, 0] },
data: projects.map((item) => Number((item.studySeconds / 60).toFixed(1))),
}],
}, true);
@ -325,7 +325,7 @@ onBeforeUnmount(() => {
}
.score-metric { display: inline-flex; align-items: baseline; gap: 4px; }
.score-metric--ai { color: #1f2937; }
.score-metric--ai { color: #1d4ed8; }
.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; }
@ -378,9 +378,9 @@ onBeforeUnmount(() => {
width: 108px;
height: 108px;
text-align: center;
border: 3px solid #1f2937;
border: 3px solid #2563eb;
border-radius: 50%;
box-shadow: inset 0 0 0 7px #f3f4f6;
box-shadow: inset 0 0 0 7px #eff6ff;
}
.time-value { font-size: 25px; font-weight: 800; line-height: 1; }

@ -24,7 +24,7 @@ onMounted(async()=>{const res=await getCurrentExperimentReport(); report.value=r
.report-eyebrow {
display: block;
margin-bottom: 6px;
color: #6b7280;
color: #2563eb;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.12em;
@ -66,7 +66,7 @@ onMounted(async()=>{const res=await getCurrentExperimentReport(); report.value=r
}
.score-value {
color: #1f2937;
color: #1d4ed8;
font-family: "PingFang SC", "SF Mono", Consolas, monospace;
font-variant-numeric: tabular-nums;
font-weight: 700;

@ -3,7 +3,6 @@
<main class="release-channel-core">
<section class="task-header">
<div class="task-head-main">
<span class="task-badge"><el-icon><Document /></el-icon> 核心实训 · 产品上线与运营推广</span>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -346,18 +345,6 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
flex: 1 1 auto;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
}
.task-title {
margin: 0;
@ -424,6 +411,13 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
background: transparent;
display: grid;
gap: 10px;
min-width: 0;
}
/* grid 子项默认 min-width:auto 会被宽表格(评分表 1780px)撑开,
导致 .table-wrap 的 overflow-x:auto 失效、整页横向溢出 */
.task-card > * {
min-width: 0;
}
.workbench-head {
@ -523,6 +517,7 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
.table-wrap {
overflow-x: auto;
min-width: 0;
border: 1px solid var(--student-panel-border);
border-radius: 10px;
}
@ -682,15 +677,15 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
</style>
<style lang="scss">
/* ===== 步骤条:按钮切换风 ===== */
/* ===== 步骤条:分段连接胶囊(教育蓝极简) ===== */
#app .studentLayout section.app-main:has(.release-channel-page) .step-tabs {
display: flex !important;
flex-wrap: nowrap !important;
align-items: stretch !important;
justify-content: center !important;
gap: 10px !important;
gap: 0 !important;
width: 100% !important;
margin: 4px 0 16px !important;
margin: 0 0 20px !important;
padding: 0 !important;
border: none !important;
border-radius: 0 !important;
@ -700,20 +695,21 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
.step-connector { display: none !important; }
.step-tab {
flex: 0 0 auto !important;
min-width: auto !important;
max-width: none !important;
flex: 1 1 0 !important;
max-width: 240px !important;
display: flex !important;
flex-direction: row !important;
align-items: center !important;
justify-content: center !important;
gap: 8px !important;
min-width: 0 !important;
height: auto !important;
min-height: 42px !important;
min-height: 40px !important;
margin: 0 !important;
padding: 8px 14px !important;
border: 1px solid #e5e7eb !important;
border-radius: 8px !important;
border-right: none !important;
border-radius: 0 !important;
background: #ffffff !important;
box-shadow: none !important;
color: #6b7280 !important;
@ -721,10 +717,18 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
font-weight: 600 !important;
line-height: 1.3 !important;
letter-spacing: 0 !important;
white-space: nowrap !important;
white-space: normal !important;
text-align: center !important;
cursor: pointer;
transition: background-color 0.16s ease, color 0.16s ease, border-color 0.16s ease !important;
transition: all 0.16s ease !important;
&:first-child {
border-radius: 8px 0 0 8px !important;
}
&:last-child {
border-radius: 0 8px 8px 0 !important;
border-right: 1px solid #e5e7eb !important;
}
.step-marker {
display: inline-flex !important;
@ -739,11 +743,11 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
border-radius: 6px !important;
background: #f3f4f6 !important;
color: #6b7280 !important;
font-family: ui-monospace, "SF Mono", Consolas, monospace !important;
font-family: var(--student-font-data), ui-monospace, "SF Mono", Consolas, monospace !important;
font-size: 12px !important;
font-weight: 700 !important;
line-height: 1 !important;
transition: background-color 0.16s ease, color 0.16s ease !important;
transition: all 0.16s ease !important;
}
.step-copy {
@ -751,6 +755,7 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
flex-direction: column !important;
gap: 0 !important;
min-width: 0 !important;
margin-left: 0 !important;
}
.step-copy b {
@ -769,6 +774,7 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
border-color: #2563eb !important;
background: #eff6ff !important;
color: #2563eb !important;
z-index: 1 !important;
.step-marker { background: #2563eb !important; color: #ffffff !important; }
}
@ -779,6 +785,7 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
&:hover {
border-color: #2ba471 !important;
background: #f0fdf6 !important;
z-index: 1 !important;
.step-marker { background: #2ba471 !important; color: #ffffff !important; }
}
}
@ -789,6 +796,7 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
color: #ffffff !important;
font-weight: 700 !important;
box-shadow: none !important;
z-index: 2 !important;
.step-marker { background: #ffffff !important; color: #2563eb !important; }
&:hover {
background: #1d4ed8 !important;
@ -802,19 +810,51 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
@media (max-width: 900px) {
#app .studentLayout section.app-main:has(.release-channel-page) .step-tabs {
justify-content: flex-start !important;
gap: 8px !important;
overflow-x: auto !important;
}
#app .studentLayout section.app-main:has(.release-channel-page) .step-tabs .step-tab {
flex: 0 0 auto !important;
flex: 0 0 140px !important;
max-width: none !important;
}
}
/* ============================================================
* 共用组件换肤:TrainingMaterialButton 资料按钮 → 教育蓝
* ============================================================ */
.release-channel-page .task-header .material-button.el-button {
height: 34px !important;
min-height: 34px !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #2563eb !important;
background: #ffffff !important;
font-size: 13px !important;
font-weight: 600 !important;
transition: border-color 0.16s ease, background 0.16s ease, color 0.16s ease, box-shadow 0.16s ease !important;
&:hover {
border-color: #2563eb !important;
color: #2563eb !important;
background: #eff6ff !important;
box-shadow: 0 2px 6px rgba(37, 99, 235, 0.12) !important;
}
&.is-plain {
border-color: #e5e7eb !important;
color: #9ca3af !important;
&:hover {
border-color: #e5e7eb !important;
color: #9ca3af !important;
background: #ffffff !important;
box-shadow: none !important;
}
}
}
/* ===== 表格操作按钮换肤 ===== */
.release-channel-page .table-actions .el-button,
.release-channel-page .footer-actions .el-button {
border-radius: 10px !important;
border-radius: 8px !important;
font-size: 13px !important;
font-weight: 700 !important;
}
@ -832,7 +872,7 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
box-shadow: 0 5px 14px rgba(29, 78, 216, 0.32) !important;
}
.release-channel-page .footer-actions .el-button:not(.el-button--primary) {
border-color: rgba(37, 99, 235, 0.45) !important;
border-color: rgba(37, 99, 235, 0.35) !important;
background: #ffffff !important;
color: #2563eb !important;
}

@ -46,9 +46,9 @@
border
style="width: 60%"
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#1e88e5!important',
color: '#6b7280',
fontSize: '12px',
backgroundColor: '#f9fafb',
}"
>
<el-table-column label="广告" align="center" prop="channel"></el-table-column>

@ -3,7 +3,6 @@
<main class="promotion-core">
<section class="task-header">
<div class="task-head-main">
<span class="task-badge"><el-icon><Document /></el-icon> 核心实训 · 产品上线与运营推广</span>
<h1 class="task-title">{{ taskTitle }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -355,18 +354,6 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
flex: 1 1 auto;
}
.task-badge {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 4px 12px;
border: 1px solid var(--student-panel-border);
border-radius: 999px;
color: var(--student-accent-deep);
background: var(--student-accent-soft);
font-size: 12px;
font-weight: 700;
}
.task-title {
margin: 0;
@ -713,13 +700,13 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
</style>
<style lang="scss">
/* ===== 步骤导航:按钮切换风 ===== */
/* ===== 步骤导航:分段连接胶囊(教育蓝) ===== */
#app .studentLayout section.app-main:has(.promotion-page) .step-indicator {
display: flex !important;
flex-wrap: nowrap !important;
align-items: stretch !important;
justify-content: center !important;
gap: 10px !important;
gap: 0 !important;
width: 100% !important;
margin: 4px 0 16px !important;
padding: 0 !important;
@ -731,20 +718,27 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
.step-connector { display: none !important; }
.step-tab {
flex: 0 0 auto !important;
min-width: auto !important;
max-width: none !important;
flex: 1 1 0 !important;
min-width: 0 !important;
max-width: 240px !important;
display: flex !important;
flex-direction: row !important;
align-items: center !important;
justify-content: center !important;
gap: 8px !important;
height: auto !important;
min-height: 42px !important;
min-height: 40px !important;
margin: 0 !important;
padding: 8px 14px !important;
border: 1px solid #e5e7eb !important;
border-radius: 8px !important;
border-right: none !important;
border-radius: 0 !important;
&:first-child { border-radius: 8px 0 0 8px !important; }
&:last-child {
border-radius: 0 8px 8px 0 !important;
border-right: 1px solid #e5e7eb !important;
}
background: #ffffff !important;
box-shadow: none !important;
color: #6b7280 !important;
@ -800,6 +794,7 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
border-color: #2563eb !important;
background: #eff6ff !important;
color: #2563eb !important;
z-index: 1 !important;
.step-marker { background: #2563eb !important; color: #ffffff !important; }
}
@ -811,6 +806,7 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
&:hover {
border-color: #2ba471 !important;
background: #f0fdf6 !important;
z-index: 1 !important;
.step-marker { background: #2ba471 !important; color: #ffffff !important; }
}
}
@ -821,6 +817,8 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
background: #2563eb !important;
color: #ffffff !important;
font-weight: 700 !important;
box-shadow: none !important;
z-index: 2 !important;
.step-marker { background: #ffffff !important; color: #2563eb !important; }
&:hover {
background: #1d4ed8 !important;
@ -834,11 +832,10 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
@media (max-width: 900px) {
#app .studentLayout section.app-main:has(.promotion-page) .step-indicator {
justify-content: flex-start !important;
gap: 8px !important;
overflow-x: auto !important;
}
#app .studentLayout section.app-main:has(.promotion-page) .step-indicator .step-tab {
flex: 0 0 auto !important;
flex: 0 0 140px !important;
max-width: none !important;
}
}
@ -854,7 +851,7 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
min-height: 36px;
height: 36px;
padding: 0 14px;
border: 1px solid rgba(37, 99, 235, 0.45);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 8px;
color: #2563eb;
background: #ffffff;
@ -894,7 +891,7 @@ onMounted(async () => { try { const result = await getTrainingTaskByKey(TASK_KEY
}
.promotion-page .task-toolbar-button.el-button.is-loading {
border-color: rgba(37, 99, 235, 0.45);
border-color: rgba(37, 99, 235, 0.35);
color: #2563eb;
background: #ffffff;
}

@ -3,7 +3,6 @@
<main class="training-core">
<section class="task-header">
<div class="task-head-main">
<span class="task-badge">核心实训 · 产品开发基础</span>
<h1 class="task-title">{{ page.title }}</h1>
<p class="task-brief">
<span class="task-brief-text">{{ taskBackground }}</span>
@ -1749,18 +1748,6 @@ function exportOutcome() {
min-width: 0;
}
.task-badge {
display: inline-flex;
align-items: center;
margin-bottom: 0;
padding: 4px 12px;
border: 1px solid #e5e7eb;
border-radius: 999px;
color: #111827;
background: #f3f4f6;
font-size: 12px;
font-weight: 700;
}
.task-title {
margin: 0;
@ -1787,7 +1774,7 @@ function exportOutcome() {
.task-brief-toggle {
padding: 0;
border: 0;
color: #111827;
color: #2563eb;
background: transparent;
font: inherit;
font-weight: 700;
@ -1952,36 +1939,36 @@ function exportOutcome() {
min-width: 112px;
height: 40px;
margin: 0;
border: 1px solid rgba(31, 41, 55, 0.4);
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 10px;
color: #1f2937;
color: #2563eb;
background: #ffffff;
font-weight: 700;
}
:deep(.el-button--primary) {
border-color: #1f2937;
border-color: #2563eb;
color: #ffffff;
background: #1f2937;
box-shadow: 0 2px 6px rgba(31, 41, 55, 0.16);
background: #2563eb;
box-shadow: 0 2px 6px rgba(37, 99, 235, 0.16);
}
:deep(.el-button.is-plain) {
border-color: rgba(31, 41, 55, 0.4);
color: #1f2937;
border-color: rgba(37, 99, 235, 0.35);
color: #2563eb;
background: #ffffff;
}
:deep(.el-button:hover:not(:disabled)) {
border-color: #1f2937;
color: #1f2937;
background: #f3f4f6;
border-color: #2563eb;
color: #2563eb;
background: #eff6ff;
}
:deep(.el-button--primary:hover:not(:disabled)) {
border-color: #111827;
border-color: #1d4ed8;
color: #ffffff;
background: #111827;
background: #1d4ed8;
}
.btn-save {
@ -2008,9 +1995,9 @@ function exportOutcome() {
max-width: 260px;
min-height: 40px;
padding: 0 18px;
border: 1px solid #e5e7eb;
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 10px;
color: #1f2937;
color: #2563eb;
background: #ffffff;
font-size: 13px;
font-weight: 700;
@ -2018,9 +2005,9 @@ function exportOutcome() {
text-decoration: none;
&:hover {
color: #1f2937;
border-color: #1f2937;
background: #f9fafb;
color: #1d4ed8;
border-color: #2563eb;
background: #eff6ff;
}
}
@ -2067,44 +2054,44 @@ function exportOutcome() {
transition: color 0.2s ease, background 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
&:hover {
border-color: #1f2937;
color: #1f2937;
background: #f9fafb;
box-shadow: 0 3px 10px rgba(31, 41, 55, 0.12);
border-color: #2563eb;
color: #1d4ed8;
background: #eff6ff;
box-shadow: 0 3px 10px rgba(37, 99, 235, 0.12);
transform: translateY(-1px);
.step-action {
color: #1f2937;
color: #2563eb;
}
}
&:focus-visible {
outline: 2px solid #1f2937;
outline: 2px solid #2563eb;
outline-offset: 4px;
}
&.active {
border-color: #1f2937;
border-color: #1d4ed8;
color: #ffffff;
background: #1f2937;
box-shadow: 0 2px 6px rgba(31, 41, 55, 0.16);
background: #2563eb;
box-shadow: 0 2px 6px rgba(37, 99, 235, 0.2);
.step-marker {
border-color: #ffffff;
color: #1f2937;
color: #1d4ed8;
background: #ffffff;
box-shadow: none;
}
}
&.complete {
border-color: #dce9e2;
color: #374151;
border-color: #dbeafe;
color: #1d4ed8;
.step-marker {
border-color: transparent;
color: #3f8a5f;
background: rgba(74, 157, 110, 0.12);
color: #1d4ed8;
background: rgba(37, 99, 235, 0.1);
box-shadow: none;
}
}
@ -2180,12 +2167,12 @@ function exportOutcome() {
}
.step-tab.complete + .step-connector {
background: #4a9d6e;
background: #93c5fd;
box-shadow: none;
}
.step-tab.complete + .step-connector::after {
border-color: #4a9d6e;
border-color: #93c5fd;
}
.comprehensive-step-nav {
@ -2366,9 +2353,9 @@ function exportOutcome() {
}
&:focus {
border-color: #1f2937;
background: #f9fafb;
box-shadow: 0 0 0 3px rgba(31, 41, 55, 0.14);
border-color: #2563eb;
background: #eff6ff;
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.14);
}
}
@ -2396,10 +2383,10 @@ function exportOutcome() {
gap: 8px;
min-height: 40px;
padding: 0 18px;
border: 1px solid #1f2937;
border: 1px solid #2563eb;
border-radius: 10px;
color: #ffffff;
background: #1f2937;
background: #2563eb;
box-shadow: none;
font-size: var(--student-fs-body);
font-weight: 700;
@ -2537,9 +2524,9 @@ function exportOutcome() {
min-height: 36px;
padding: 0 14px;
border-radius: 8px;
border: 1px solid #e5e7eb;
border: 1px solid rgba(37, 99, 235, 0.35);
border-radius: 10px;
color: #1f2937;
color: #2563eb;
background: #ffffff;
box-shadow: none;
font-size: var(--student-fs-body);
@ -2558,28 +2545,28 @@ function exportOutcome() {
}
.training-actions :deep(.training-action--submit) {
border-color: #1f2937;
border-color: #2563eb;
color: #ffffff;
background: #1f2937;
background: #2563eb;
}
.training-actions :deep(.training-action--reset) {
border-color: #e5e7eb;
color: #1f2937;
border-color: rgba(37, 99, 235, 0.35);
color: #2563eb;
background: #ffffff;
}
.training-actions :deep(.training-action--submit:hover:not(.is-disabled)) {
border-color: #111827;
border-color: #1d4ed8;
color: #ffffff;
background: #111827;
background: #1d4ed8;
}
.training-actions :deep(.training-action--reset:hover:not(.is-disabled)),
.training-actions :deep(.training-action:hover:not(.is-disabled)) {
border-color: #1f2937;
color: #1f2937;
background: #f9fafb;
border-color: #2563eb;
color: #1d4ed8;
background: #eff6ff;
}
.product-development-process-page {
@ -2623,12 +2610,12 @@ function exportOutcome() {
.workbench-actions :deep(.material-download),
.workbench-actions :deep(.outline-action) {
min-width: 0 !important;
min-height: 36px !important;
height: 36px !important;
min-height: 34px !important;
height: 34px !important;
padding: 0 14px !important;
border: 1px solid #e5e7eb !important;
border: 1px solid rgba(37, 99, 235, 0.35) !important;
border-radius: 8px !important;
color: #1f2937 !important;
color: #2563eb !important;
background: #ffffff !important;
box-shadow: none !important;
font-size: 13px !important;
@ -2711,12 +2698,12 @@ function exportOutcome() {
.upload-btn {
min-width: 0 !important;
min-height: 40px !important;
height: 40px !important;
padding: 0 18px !important;
border: 1px solid #1f2937 !important;
border-radius: 10px !important;
background: #1f2937 !important;
min-height: 34px !important;
height: 34px !important;
padding: 0 14px !important;
border: 1px solid #2563eb !important;
border-radius: 8px !important;
background: #2563eb !important;
box-shadow: none !important;
font-size: 13px !important;
font-weight: 700 !important;
@ -3315,10 +3302,10 @@ function exportOutcome() {
width: 58px;
height: 58px;
place-items: center;
border: 1px solid #1f2937;
border: 1px solid #2563eb;
border-radius: 50%;
color: #ffffff;
background: #1f2937;
background: #2563eb;
box-shadow: none;
font-size: 15px;
font-weight: 700;
@ -3784,7 +3771,7 @@ function exportOutcome() {
.sentiment-visualization i {
height: 9px;
border-radius: 999px;
background: #1f2937;
background: #2563eb;
box-shadow: none;
}

@ -51,16 +51,16 @@ const biIframeSrc = import.meta.env.VITE_APP_BI_URL || "/bi/";
}
:deep(.el-tabs__item:hover) {
color: #1f2937;
color: #2563eb;
}
:deep(.el-tabs__item.is-active) {
color: #1f2937;
color: #2563eb;
font-weight: 700;
}
:deep(.el-tabs__active-bar) {
background-color: #1f2937;
background-color: #2563eb;
}
:deep(.el-tabs__nav-wrap::after) {

Loading…
Cancel
Save