feat: improve student training experience

dev-QQq^2
陈沅 5 days ago
parent d604db38ba
commit 7b8644a8ec

@ -64,6 +64,175 @@ export function uploadStudentTrainingFile(data) {
});
}
export function validateProductPricingStepOne(payload) {
const value = payload || {};
const rows = Array.isArray(value.pricingRows) ? value.pricingRows : [];
if (isStudentDemo()) {
const ranges = { dealer: [15, 25], "direct-retail": [40, 60], "premium-brand": [70, 80] };
const unitCost = Number(value.unitCost);
if (!Number.isFinite(unitCost) || unitCost <= 0) return Promise.reject(new Error("单台综合成本必须大于 0"));
if (rows.length !== 3) return Promise.reject(new Error("请填写三个渠道的加成率"));
try {
const pricingRows = Object.keys(ranges).map((id) => {
const markupRate = Number(rows.find((item) => item?.id === id)?.markupRate);
const [min, max] = ranges[id];
if (!Number.isFinite(markupRate) || markupRate < min || markupRate > max) {
throw new Error(`渠道加成率需在 ${min}%~${max}% 范围内`);
}
return { id, markupRate: Number(markupRate.toFixed(2)), salePrice: Number((unitCost * (1 + markupRate / 100)).toFixed(2)) };
});
return Promise.resolve({ code: 200, data: { valid: true, message: "渠道加成定价已校验", unitCost: Number(unitCost.toFixed(2)), pricingRows } });
} catch (error) {
return Promise.reject(error);
}
}
return request({ url: "/api/student-training-answers/product-pricing/step-1/validate", method: "post", data: value, headers: { repeatSubmit: false } });
}
export function validateProductPricingStepTwo(payload) {
const value = payload || {};
const rows = Array.isArray(value.competitorRows) ? value.competitorRows : [];
const decision = value.decision || {};
if (isStudentDemo()) {
const unitCost = Number(value.unitCost);
if (!Number.isFinite(unitCost) || unitCost <= 0) return Promise.reject(new Error("请先完成第 1 步并填写单台综合成本"));
if (rows.length !== 4) return Promise.reject(new Error("请完整填写 4 个竞品信息"));
try {
const productTypes = rows.map((row, index) => {
const productType = String(row?.productType || "").trim();
const brand = String(row?.brand || "").trim();
const differentiator = String(row?.differentiator || "").trim();
const ecommercePrice = Number(row?.ecommercePrice);
if (!productType || !brand || !differentiator || !Number.isFinite(ecommercePrice) || ecommercePrice <= 0) throw new Error(`请完整填写竞品 ${index + 1} 的信息`);
return productType;
});
if (new Set(productTypes).size !== productTypes.length) {
throw new Error("竞品产品类型不能重复,请使用可区分的竞品名称");
}
const targetPrice = Number(decision.targetPrice);
if (!productTypes.includes(String(decision.benchmarkCompetitor || "").trim())) throw new Error("对标竞品必须从上方已填写的竞品中选择");
if (!Number.isFinite(targetPrice) || targetPrice <= 0 || !String(decision.differentiator || "").trim() || !String(decision.pricingReason || "").trim()) throw new Error("请完整填写本产品定价、差异化优势和定价原因");
return Promise.resolve({ code: 200, data: { valid: true, message: "竞品价格带与定价已校验", competitorRows: rows, decision: { ...decision, targetPrice: Number(targetPrice.toFixed(2)), grossMarginRate: Number((((targetPrice - unitCost) / targetPrice) * 100).toFixed(2)) } } });
} catch (error) {
return Promise.reject(error);
}
}
return request({ url: "/api/student-training-answers/product-pricing/step-2/validate", method: "post", data: value, headers: { repeatSubmit: false } });
}
export function validateProductPricingStepThree(payload) {
const value = payload || {};
const valueItems = Array.isArray(value.valueItems) ? value.valueItems : [];
if (isStudentDemo()) {
try {
if (!valueItems.length) throw new Error("请至少填写一项可替代产品或功能的价值感知");
const normalizedItems = valueItems.map((item, index) => {
const name = String(item?.name || "").trim();
const perceivedValue = Number(item?.perceivedValue);
if (!String(item?.id || "").trim() || !name || !Number.isFinite(perceivedValue) || perceivedValue <= 0) {
throw new Error(`请完整填写第 ${index + 1} 项价值感知`);
}
return { ...item, id: String(item.id).trim(), name, perceivedValue: Number(perceivedValue.toFixed(2)) };
});
if (new Set(normalizedItems.map((item) => item.id)).size !== normalizedItems.length) throw new Error("价值感知条目不能重复");
const discountRate = Number(value.discountRate);
if (!Number.isFinite(discountRate) || discountRate <= 0 || discountRate > 100) throw new Error("利润让渡折扣率应大于 0 且不超过 100%");
const perceivedValueTotal = Number(normalizedItems.reduce((total, item) => total + item.perceivedValue, 0).toFixed(2));
return Promise.resolve({
code: 200,
data: {
valid: true,
message: "用户感知价值定价已校验",
valueItems: normalizedItems,
perceivedValueTotal,
discountRate: Number(discountRate.toFixed(2)),
valueBasedPrice: Number((perceivedValueTotal * discountRate / 100).toFixed(2)),
},
});
} catch (error) {
return Promise.reject(error);
}
}
return request({ url: "/api/student-training-answers/product-pricing/step-3/validate", method: "post", data: value, headers: { repeatSubmit: false } });
}
export function validateProductPricingStepFour(payload) {
const value = payload || {};
const psmRows = Array.isArray(value.psmRows) ? value.psmRows : [];
const pricePoints = value.pricePoints || {};
if (isStudentDemo()) {
try {
const requiredRanges = ["≤100元", "100~150元", "150~200元", "200~250元", "250~300元", "≥300元"];
if (psmRows.length < requiredRanges.length) throw new Error("请完整填写 6 个固定价格区间的 PSM 累计占比");
const seenIds = new Set();
const seenRanges = new Set();
const normalizedRows = psmRows.map((row, index) => {
const id = String(row?.id || "").trim();
const priceRange = String(row?.priceRange || "").trim();
if (!id || !priceRange || seenIds.has(id) || seenRanges.has(priceRange)) throw new Error("PSM 价格区间不能重复且不能为空");
seenIds.add(id);
seenRanges.add(priceRange);
const normalized = { ...row, id, priceRange };
[["tooExpensive", "太贵不买"], ["tooCheap", "太便宜不买"], ["expensiveAcceptable", "偏高可接受"], ["cheapValue", "便宜划算"]].forEach(([field, label]) => {
const percentage = Number(row?.[field]);
if (!Number.isFinite(percentage) || percentage < 0 || percentage > 100) throw new Error(`${index + 1} 行“${label}”累计占比应在 0%100% 之间`);
normalized[field] = Number(percentage.toFixed(2));
});
return normalized;
});
if (!requiredRanges.every((range) => seenRanges.has(range))) throw new Error("请保留并填写 6 个固定价格区间");
const optimalPrice = Number(pricePoints.optimalPrice);
const acceptablePrice = Number(pricePoints.acceptablePrice);
const acceptableRange = String(pricePoints.acceptableRange || "").trim();
if (!Number.isFinite(optimalPrice) || optimalPrice <= 0 || !Number.isFinite(acceptablePrice) || acceptablePrice <= 0 || !acceptableRange) {
throw new Error("请完整填写最优价格点、可接受价格点和可接受价格范围");
}
return Promise.resolve({ code: 200, data: {
valid: true,
message: "PSM 价格敏感度测试已校验",
psmRows: normalizedRows,
pricePoints: { optimalPrice: Number(optimalPrice.toFixed(2)), acceptablePrice: Number(acceptablePrice.toFixed(2)), acceptableRange },
} });
} catch (error) {
return Promise.reject(error);
}
}
return request({ url: "/api/student-training-answers/product-pricing/step-4/validate", method: "post", data: value, headers: { repeatSubmit: false } });
}
export function validateProductPricingStepFive(payload) {
const value = payload || {};
const methodResults = Array.isArray(value.methodResults) ? value.methodResults : [];
if (isStudentDemo()) {
try {
const requiredKeys = ["cost-markup", "competitive", "value-based", "psm"];
const selectedCostMarkupChannel = String(value.selectedCostMarkupChannel || "").trim();
if (!selectedCostMarkupChannel) throw new Error("请选择用于汇总的成本加成定价渠道");
if (methodResults.length !== requiredKeys.length) throw new Error("请完整汇总四种定价方法的测算结果");
const seenKeys = new Set();
const normalizedResults = methodResults.map((item) => {
const key = String(item?.key || "").trim();
const methodName = String(item?.methodName || "").trim();
const measuredPrice = Number(item?.measuredPrice);
const grossMarginRate = Number(item?.grossMarginRate);
if (!requiredKeys.includes(key) || seenKeys.has(key) || !methodName || !Number.isFinite(measuredPrice) || measuredPrice <= 0 || !Number.isFinite(grossMarginRate)) {
throw new Error("请完整填写四种定价方法的测算结果和毛利润率");
}
if (grossMarginRate < -100 || grossMarginRate > 100) throw new Error("毛利润率应在 -100% 至 100% 之间");
seenKeys.add(key);
return { key, methodName, measuredPrice: Number(measuredPrice.toFixed(2)), grossMarginRate: Number(grossMarginRate.toFixed(2)) };
});
if (!requiredKeys.every((key) => seenKeys.has(key))) throw new Error("定价方法汇总项不正确或重复");
const finalAnalysis = String(value.finalAnalysis || "").trim();
if (!finalAnalysis) throw new Error("请填写最终量产定价分析");
return Promise.resolve({ code: 200, data: { valid: true, message: "最终量产定价汇总已校验", selectedCostMarkupChannel, methodResults: normalizedResults, finalAnalysis } });
} catch (error) {
return Promise.reject(error);
}
}
return request({ url: "/api/student-training-answers/product-pricing/step-5/validate", method: "post", data: value, headers: { repeatSubmit: false } });
}
export function checkNewProductSurveyStepOne(items) {
if (isStudentDemo()) {
const results = Array.isArray(items)

@ -28,17 +28,47 @@
#app .teacherLayout .app-main:has(.student-training-shell) .student-training-shell {
box-sizing: border-box !important;
display: grid !important;
grid-template-columns: minmax(720px, 1fr) 340px !important;
grid-template-columns: minmax(660px, 1fr) 300px !important;
align-items: start !important;
gap: 24px !important;
gap: 14px !important;
width: 100% !important;
max-width: none !important;
min-height: calc(100vh - 90px) !important;
margin: 0 !important;
padding: 24px 24px 32px !important;
padding: 14px 14px 20px !important;
background: #06111d !important;
}
/*
* Student pages use different local names for their main and workbench cards.
* Keep the layout density here so a page-specific card cannot reclaim the
* space reserved for the hands-on activity area.
*/
.student-training-shell > main {
min-width: 0 !important;
padding: 20px !important;
border-radius: 24px !important;
}
.student-training-shell > main > .task-card,
.student-training-shell > main > .process-workbench,
.student-training-shell > main > .factors-workbench,
.student-training-shell > main > .workbench {
padding: 14px 16px !important;
border-radius: 20px !important;
}
.student-training-shell .step-card,
.student-training-shell .process-step-card,
.student-training-shell .factor-step-card {
padding: 16px !important;
border-radius: 20px !important;
}
.student-training-shell .task-header {
margin-bottom: 16px !important;
}
.student-training-shell .task-header .task-title {
font-size: 30px !important;
line-height: 1.3 !important;
@ -76,7 +106,7 @@
justify-content: space-between !important;
gap: 6px !important;
width: 100% !important;
margin: 0 0 32px !important;
margin: 0 0 18px !important;
padding: 6px !important;
border: 1px solid var(--student-panel-border) !important;
border-radius: var(--student-radius-pill) !important;
@ -443,7 +473,7 @@
display: flex !important;
align-items: flex-start !important;
justify-content: space-between !important;
gap: 18px !important;
gap: 10px !important;
}
.student-training-shell .workbench-actions {
@ -453,7 +483,7 @@
align-items: center !important;
justify-content: flex-end !important;
align-self: flex-start !important;
gap: 10px !important;
gap: 8px !important;
min-width: max-content !important;
margin: 0 0 0 auto !important;
padding: 0 !important;
@ -467,16 +497,16 @@
flex: 0 0 auto !important;
min-width: 0 !important;
width: auto !important;
height: 40px !important;
min-height: 40px !important;
max-height: 40px !important;
height: 34px !important;
min-height: 34px !important;
max-height: 34px !important;
margin: 0 !important;
padding: 0 18px !important;
padding: 0 12px !important;
border: 1px solid rgba(99, 217, 255, 0.55) !important;
border-radius: var(--student-radius-pill) !important;
color: #e9fbff !important;
background: rgba(17, 126, 178, 0.36) !important;
font-size: 14px !important;
font-size: 13px !important;
font-weight: 800 !important;
line-height: 1 !important;
white-space: nowrap !important;
@ -527,10 +557,13 @@
.legacy-training-page {
display: grid !important;
grid-template-columns: minmax(0, 1fr) 360px !important;
gap: 24px !important;
box-sizing: border-box !important;
grid-template-columns: minmax(0, 1fr) 300px !important;
gap: 14px !important;
align-items: start !important;
width: 100% !important;
padding: 14px !important;
background: #06111d !important;
}
.legacy-training-page > :not(.training-ai-sidebar) {
@ -553,22 +586,22 @@
}
.legacy-training-page .top_item {
margin-bottom: 18px !important;
margin-bottom: 12px !important;
}
.legacy-training-page .top_item .el-button {
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
min-width: 150px !important;
height: 42px !important;
padding: 0 18px !important;
min-width: 136px !important;
height: 36px !important;
padding: 0 12px !important;
border: 1px solid #2c83aa !important;
border-radius: 6px !important;
color: #e9fbff !important;
background: rgba(13, 64, 88, 0.62) !important;
box-shadow: none !important;
font-size: 15px !important;
font-size: 14px !important;
font-weight: 800 !important;
line-height: 1 !important;
letter-spacing: 0 !important;
@ -628,6 +661,10 @@
padding: 14px 14px 18px !important;
}
.legacy-training-page {
padding: 12px !important;
}
.student-training-shell .workbench-head {
flex-direction: column !important;
}

@ -163,12 +163,12 @@ async function requestEvaluation() {
.training-ai-sidebar {
display: flex;
flex-direction: column;
gap: 22px;
gap: 16px;
align-self: start;
min-height: calc(100vh - 106px);
padding: 10px;
padding: 8px;
border: 1px solid rgba(0, 174, 255, 0.22);
border-radius: 26px;
border-radius: 22px;
background:
linear-gradient(180deg, rgba(13, 30, 44, 0.92), rgba(5, 15, 26, 0.96)),
radial-gradient(circle at 50% 0%, rgba(0, 220, 255, 0.16), transparent 42%);

@ -47,5 +47,5 @@ function handleDownload() {
</script>
<style lang="scss" scoped>
.material-actions{display:flex;flex-wrap:wrap;gap:10px}.material-button{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:40px;padding:0 16px;border-color:rgba(99,217,255,.55);border-radius:9px;color:#e9fbff;background:rgba(17,126,178,.36);font-size:14px;font-weight:800}.material-button:hover{color:#e9fbff;border-color:rgba(116,235,255,.85);background:rgba(18,146,204,.5)}.image-preview{display:flex;justify-content:center;max-height:68vh;overflow:auto;background:#0b1720}.image-preview img{display:block;max-width:100%;height:auto;object-fit:contain}.pdf-preview{width:100%;height:68vh;border:0;background:#fff}
.material-actions{display:flex;flex-wrap:wrap;gap:8px}.material-button{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:32px;padding:0 10px;border-color:rgba(99,217,255,.55);border-radius:7px;color:#e9fbff;background:rgba(17,126,178,.36);font-size:13px;font-weight:800}.material-button:hover{color:#e9fbff;border-color:rgba(116,235,255,.85);background:rgba(18,146,204,.5)}.image-preview{display:flex;justify-content:center;max-height:68vh;overflow:auto;background:#0b1720}.image-preview img{display:block;max-width:100%;height:auto;object-fit:contain}.pdf-preview{width:100%;height:68vh;border:0;background:#fff}
</style>

@ -131,10 +131,10 @@ function normalizeGoals(value) {
<style lang="scss" scoped>
.training-task-brief {
margin-bottom: 28px;
padding: 16px 20px;
margin-bottom: 14px;
padding: 12px 16px;
border: 1px solid #2d5f7e;
border-radius: 24px;
border-radius: 20px;
background: rgba(0, 35, 55, 0.6);
box-shadow: none;
}
@ -143,7 +143,7 @@ function normalizeGoals(value) {
display: flex;
align-items: stretch;
gap: 10px;
margin-bottom: 14px;
margin-bottom: 10px;
}
.brief-tabs {
@ -233,8 +233,8 @@ function normalizeGoals(value) {
}
.brief-scroll {
max-height: 178px;
min-height: 126px;
max-height: 160px;
min-height: 110px;
overflow-y: auto;
overscroll-behavior: contain;
scrollbar-width: thin;
@ -243,10 +243,10 @@ function normalizeGoals(value) {
.brief-content {
margin: 0;
padding: 14px 16px 16px;
padding: 10px 16px 12px;
color: #d9efff;
font-size: 15px;
line-height: 1.85;
line-height: 1.55;
}
.brief-goals {
@ -254,12 +254,12 @@ function normalizeGoals(value) {
list-style: none;
li {
padding: 8px 0 8px 12px;
padding: 5px 0 5px 12px;
border-left: 2px solid rgba(105, 221, 255, 0.5);
}
li + li {
margin-top: 4px;
margin-top: 2px;
}
}
@ -296,7 +296,7 @@ function normalizeGoals(value) {
}
.brief-scroll {
height: 160px;
height: 140px;
}
}
</style>

@ -582,25 +582,25 @@ function exportOutcome() {
.process-core {
min-width: 0;
padding: 28px;
padding: 20px;
border: 1px solid rgba(0, 180, 255, 0.25);
border-radius: 36px;
border-radius: 24px;
background: rgba(8, 18, 28, 0.6);
box-shadow: 0 22px 48px rgba(0, 0, 0, 0.22), inset 0 1px 0 rgba(169, 229, 255, 0.08);
backdrop-filter: blur(8px);
}
.task-header { margin-bottom: 24px; }
.task-header { margin-bottom: 16px; }
.task-badge { display: inline-flex; align-items: center; gap: 7px; margin-bottom: 12px; padding: 4px 14px; border: 1px solid rgba(0, 170, 255, 0.5); border-radius: 30px; color: #d6f6ff; background: rgba(0, 170, 255, 0.2); font-size: 12px; font-weight: 700; }
.task-title { margin: 0; color: transparent; background: linear-gradient(135deg, #fff, #8bcbff); -webkit-background-clip: text; background-clip: text; font-size: 30px; font-weight: 900; line-height: 1.3; }
.process-workbench { min-width: 0; margin: 0; padding: 18px 22px; border: 1px solid rgba(82, 174, 226, 0.42); border-radius: 26px; background: rgba(0, 25, 42, 0.64); }
.process-workbench { min-width: 0; margin: 0; padding: 14px 16px; border: 1px solid rgba(82, 174, 226, 0.42); border-radius: 20px; background: rgba(0, 25, 42, 0.64); }
.process-workbench::before { display: none !important; content: none !important; }
.workbench-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 18px; margin-bottom: 22px; padding-bottom: 18px; border-bottom: 1px solid rgba(0, 180, 255, 0.2); }
.workbench-actions { display: flex; flex: 0 0 auto; flex-wrap: wrap; justify-content: flex-end; gap: 10px; }
.outline-action, .btn-nav { display: inline-flex; align-items: center; justify-content: center; gap: 8px; font-family: inherit; cursor: pointer; }
.outline-action, .workbench-actions :deep(.material-download) { min-height: 40px; padding: 0 18px; border: 1px solid rgba(99, 217, 255, 0.55); border-radius: 999px; color: #e9fbff; background: rgba(17, 126, 178, 0.36); box-shadow: none; font-size: 14px; font-weight: 800; line-height: 1; }
.outline-action:hover, .workbench-actions :deep(.material-download:hover) { border-color: rgba(116, 235, 255, 0.85); color: #fff; background: rgba(18, 146, 204, 0.5); transform: translateY(-1px); }
.workbench-head--actions-only { justify-content: flex-end; margin-bottom: 18px; padding-bottom: 0; border-bottom: 0; }
.workbench-head--actions-only { justify-content: flex-end; margin-bottom: 10px; padding-bottom: 0; border-bottom: 0; }
.step-indicator { position: relative; display: flex; align-items: center; gap: 0; width: calc(100% + 24px); margin: 0 -12px 32px; padding: 18px 22px; overflow-x: auto; border: 1px solid rgba(0, 180, 255, 0.3); border-radius: 18px; background: linear-gradient(90deg, rgba(6, 42, 61, 0.58), rgba(1, 18, 31, 0.42)), rgba(0, 0, 0, 0.3); box-shadow: inset 0 1px 0 rgba(145, 233, 255, 0.08); scrollbar-width: thin; }
.step-tab { display: flex; flex: 1 0 145px; align-items: center; min-width: 0; min-height: 66px; padding: 8px 10px; border: 1px solid rgba(68, 141, 177, 0.35); border-radius: 8px; color: #9ab3d0; background: rgba(3, 27, 43, 0.52); box-shadow: inset 0 1px 0 rgba(135, 221, 255, 0.04); font-family: inherit; cursor: pointer; text-align: left; transition: transform .2s ease, color .2s ease, border-color .2s ease, background .2s ease, box-shadow .2s ease; }
@ -608,7 +608,7 @@ function exportOutcome() {
.step-tab.active { border-color: rgba(89, 226, 255, .85); color: #fff; background: linear-gradient(115deg, rgba(4, 109, 155, .78), rgba(5, 62, 102, .64)); box-shadow: 0 0 18px rgba(24, 183, 235, .22), inset 0 1px 0 rgba(176, 246, 255, .2); }.step-tab.active .step-marker { border-color: #72e8ff; color: #fff; background: linear-gradient(135deg, #08b7e8, #1375d0); box-shadow: 0 0 0 5px rgba(25, 179, 237, .14), 0 0 18px rgba(46, 208, 255, .58); }.step-tab.complete { color: #dffbff; }.step-tab.complete .step-marker { border-color: rgba(84, 230, 221, .85); color: #062b37; background: #6ef0e1; box-shadow: 0 0 12px rgba(79, 231, 218, .35); }
.step-marker { display: inline-flex; flex: 0 0 38px; align-items: center; justify-content: center; width: 38px; height: 38px; border: 1px solid rgba(101, 176, 208, .6); border-radius: 50%; color: #a6c4d9; background: rgba(3, 25, 40, .8); font-size: 12px; font-weight: 900; letter-spacing: .04em; }.step-copy { display: grid; min-width: 0; gap: 4px; margin-left: 10px; }.step-name { display: -webkit-box; overflow: hidden; color: inherit; font-size: 14px; font-weight: 800; line-height: 1.25; text-overflow: ellipsis; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }.step-action { color: #66b6d4; font-size: 10px; font-weight: 800; letter-spacing: .06em; line-height: 1; }.step-connector { position: relative; flex: 0 1 40px; min-width: 18px; height: 2px; margin: 0 8px; background: rgba(98, 169, 201, .34); }.step-connector::after { position: absolute; top: 50%; right: -1px; width: 6px; height: 6px; border-top: 1px solid #73b1ce; border-right: 1px solid #73b1ce; content: ''; transform: translateY(-50%) rotate(45deg); }.step-tab.complete + .step-connector { background: linear-gradient(90deg, #6ef0e1, #1cb8e9); box-shadow: 0 0 9px rgba(53, 218, 235, .46); }.step-tab.complete + .step-connector::after { border-color: #63e6f1; }
.process-step-card { margin: 0; padding: 18px 22px; border: 1px solid rgba(82, 174, 226, 0.42); border-radius: 26px; background: rgba(0, 25, 42, 0.64); }.step-title-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 18px; margin-bottom: 14px; }.step-title-row h3 { margin: 4px 0 0; color: #fff; font-size: 22px; font-weight: 900; line-height: 1.3; }.section-eyebrow { margin: 0; color: #71dfff; font-size: 12px; font-weight: 800; line-height: 1.4; }.step-chip { padding: 6px 12px; border: 1px solid rgba(94, 219, 255, .54); border-radius: 999px; color: #a6ebff; background: rgba(9, 104, 149, .2); font-size: 13px; font-weight: 800; }
.process-step-card { margin: 0; padding: 16px; border: 1px solid rgba(82, 174, 226, 0.42); border-radius: 20px; background: rgba(0, 25, 42, 0.64); }.step-title-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 18px; margin-bottom: 12px; }.step-title-row h3 { margin: 4px 0 0; color: #fff; font-size: 22px; font-weight: 900; line-height: 1.3; }.section-eyebrow { margin: 0; color: #71dfff; font-size: 12px; font-weight: 800; line-height: 1.4; }.step-chip { padding: 6px 12px; border: 1px solid rgba(94, 219, 255, .54); border-radius: 999px; color: #a6ebff; background: rgba(9, 104, 149, .2); font-size: 13px; font-weight: 800; }
.process-intro { margin: 0 0 18px; color: #d7ecff; font-size: 15px; line-height: 1.8; }.training-table-wrap { overflow-x: auto; border: 1px solid rgba(0, 180, 255, .22); border-radius: 22px; background: rgba(1, 14, 26, .72); }.process-table { width: 100%; min-width: 920px; border-collapse: collapse; table-layout: fixed; }.process-table th { padding: 12px; border-right: 1px solid rgba(77, 167, 220, .2); color: #eaffff; background: rgba(8, 55, 82, .98); font-size: 14px; font-weight: 900; text-align: center; }.process-table td { padding: 12px; border-top: 1px solid rgba(77, 167, 220, .2); border-right: 1px solid rgba(77, 167, 220, .2); color: #d7f1ff; background: rgba(1, 14, 26, .48); vertical-align: middle; }.process-table th:last-child, .process-table td:last-child { border-right: 0; }.stage-cell { width: 17%; color: #eafaff; font-size: 14px; font-weight: 900; text-align: center; }.task-no-cell { width: 12%; color: #eafaff; font-size: 14px; font-weight: 800; text-align: center; }.task-cell { color: #cfe8f8; font-size: 14px; line-height: 1.7; text-align: center; }.select-cell { width: 23%; }.select-cell select, .schedule-table input { box-sizing: border-box; width: 100%; min-height: 38px; padding: 7px 10px; border: 1px solid rgba(45, 95, 126, .95); border-radius: 10px; outline: none; color: #eef5ff; background: #0f1a24; font: inherit; }.select-cell select:focus, .schedule-table input:focus { border-color: rgba(92, 224, 255, .7); box-shadow: 0 0 0 3px rgba(0, 174, 255, .13); }.classification-feedback { margin: 6px 0 0; color: #ff9b8f; font-size: 12px; line-height: 1.5; }.is-correct { background: rgba(55, 196, 147, .08); }.is-incorrect { background: rgba(255, 91, 82, .1); }.classification-summary { margin: 16px 0 0; color: #ffbc86; }.classification-summary.is-success { color: #6ee8b1; }
.task-actions { display: flex; justify-content: center; gap: 52px; margin-top: 36px; }.btn-nav { min-width: 172px; min-height: 64px; padding: 0 28px; border: 1px solid #2c83aa; border-radius: 6px; color: #dff7ff; background: rgba(13, 64, 88, .62); box-shadow: none; font-size: 24px; font-weight: 900; line-height: 1; }.btn-submit { border-color: #2c83aa; background: rgba(13, 64, 88, .62); }.task-actions .btn-nav .el-icon { display: none; }.btn-nav:hover:not(:disabled) { border-color: #46b5e7; color: #fff; background: rgba(18, 85, 116, .78); }.btn-nav:disabled { cursor: not-allowed; opacity: .6; }.step-placeholder { display: grid; place-items: center; min-height: 280px; padding: 28px; border: 1px dashed rgba(101, 207, 239, .42); border-radius: 18px; color: #b8d9ec; background: rgba(1, 14, 26, .42); text-align: center; }.step-placeholder p { margin: 0 0 8px; color: #eaffff; font-size: 20px; font-weight: 800; }
.step-warning { margin: 0 0 16px; padding: 10px 14px; border: 1px solid rgba(255, 173, 93, .62); border-radius: 10px; color: #ffd19f; background: rgba(187, 102, 27, .16); }.schedule-table { min-width: 1180px; }.schedule-table .stage-cell { width: 12%; }.schedule-table .task-no-cell { width: 8%; }.schedule-table .task-cell { width: 21%; }.classification-cell { width: 13%; color: #eafaff; font-weight: 800; text-align: center; }.schedule-table .dependency-input { min-width: 180px; }.schedule-table input:disabled { cursor: not-allowed; opacity: .6; }

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save