You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dianshang-qianduan/src/views/components/TrainingIntro.vue

241 lines
6.6 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<section class="training-intro">
<div class="training-intro__head">
<div>
<p class="training-intro__eyebrow">Training Brief</p>
<h2>{{ displayTitle }}</h2>
</div>
<span class="training-intro__hint">实训说明</span>
</div>
<TrainingTaskBrief :background="briefBackground" :goals="remoteGoals" :requirements="briefRequirements"
:material-name="remoteTask?.materialName" :material-url="remoteTask?.materialUrl" />
<nav v-if="remoteSteps.length" class="step-indicator training-intro__steps" aria-label="实训步骤">
<button v-for="(step, index) in remoteSteps" :key="`${step}-${index}`" type="button"
:class="['step-tab', { active: activeStep === index }]" @click="activeStep = index">
<span>{{ step }}</span>
</button>
</nav>
</section>
</template>
<script setup>
import { getTrainingTaskByKey } from "@/api/trainingTask"
import { parseTrainingArray, resolveTrainingTaskKey } from "@/views/training/taskKeyMap"
import TrainingTaskBrief from "@/views/components/TrainingTaskBrief.vue"
const route = useRoute()
const props = defineProps({
title: {
type: String,
default: "实训任务",
},
taskKey: {
type: String,
default: "",
},
})
const remoteTask = ref(null)
const activeStep = ref(0)
const currentTaskKey = computed(() => resolveTrainingTaskKey(route, props.taskKey))
const displayTitle = computed(() => remoteTask.value?.taskName || props.title)
const remoteGoals = computed(() => parseTrainingArray(remoteTask.value?.objectives))
const remoteSteps = computed(() => parseTrainingArray(remoteTask.value?.steps).slice(0, 4))
const briefBackground = computed(() => remoteTask.value?.background || "")
const briefRequirements = computed(() => remoteTask.value?.requirements || "")
watch(
() => currentTaskKey.value,
loadRemoteTask,
{ immediate: true }
)
async function loadRemoteTask(taskKey) {
remoteTask.value = null
if (!taskKey) return
try {
const res = await getTrainingTaskByKey(taskKey)
remoteTask.value = res?.data || null
} catch (error) {
remoteTask.value = null
}
}
</script>
<style lang="scss" scoped>
/* 教育蓝 · 精炼文档风:纯白画布 + 教育蓝点缀(对齐 new-product-survey) */
.training-intro {
margin-bottom: 24px;
overflow: hidden;
border: 1px solid #e5e7eb;
border-radius: 12px;
background: #ffffff;
box-shadow: none;
&__head {
display: flex;
justify-content: space-between;
align-items: center;
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: #1f2937;
font-size: var(--student-fs-display);
line-height: 1.4;
font-weight: 700;
letter-spacing: -0.01em;
}
}
&__eyebrow {
margin: 0;
color: #2563eb;
font-size: var(--student-fs-caption);
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
font-family: var(--student-font-data);
}
&__hint {
flex: 0 0 auto;
padding: 4px 10px;
border: 1px solid #bfdbfe;
border-radius: 999px;
color: #1d4ed8;
background: #eff6ff;
font-size: var(--student-fs-caption);
font-weight: 600;
}
&__body {
display: grid;
gap: 14px;
margin: 0 24px 24px;
padding: 18px 20px;
border: 1px solid #e5e7eb;
border-radius: 10px;
background: #fafbfc;
color: #374151;
font-size: var(--student-fs-body);
line-height: 1.65;
p,
ol {
margin: 0;
}
ol {
padding-left: 18px;
}
}
&__section+&__section {
padding-top: 12px;
border-top: 1px solid #e5e7eb;
}
&__subtitle {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 8px;
color: #1f2937;
font-weight: 700;
}
&__steps {
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 {
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: var(--student-fs-body) !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>