<template>
  <div class="supplier-page student-training-shell" v-loading="loading">
    <main class="training-core">
    <section class="workspace-shell">
      <header class="workspace-header">
        <div>
          <p class="eyebrow">SUPPLIER CHANNEL EVALUATION</p>
          <h1>{{ taskTitle }}</h1>
          <p>分别从试产与量产场景评估供应渠道，形成可执行的采购与风险管理建议。</p>
        </div>
        <span class="task-badge">实训任务</span>
      </header>

      <TrainingTaskBrief
        :background="taskBackground"
        :goals="taskGoals"
        :requirements="taskRequirement"
        :show-material="false"
      />

      <nav class="step-nav" aria-label="供应渠道评估步骤">
        <button :class="['step-tab', { active: currentStep === 1, complete: currentStep > 1 }]" :aria-current="currentStep === 1 ? 'step' : undefined" @click="currentStep = 1">
          <span class="step-marker">01</span><span class="step-copy"><b>设置评估权重</b><small>{{ currentStep === 1 ? '当前步骤 →' : '点击切换 →' }}</small></span>
        </button>
        <i></i>
        <button :class="['step-tab', { active: currentStep === 2, complete: currentStep > 2 }]" :aria-current="currentStep === 2 ? 'step' : undefined" @click="openStepTwo">
          <span class="step-marker">02</span><span class="step-copy"><b>渠道评分与对比</b><small>{{ currentStep === 2 ? '当前步骤 →' : '点击切换 →' }}</small></span>
        </button>
        <i></i>
        <button :class="['step-tab', { active: currentStep === 3 }]" :aria-current="currentStep === 3 ? 'step' : undefined" @click="openStepThree">
          <span class="step-marker">03</span><span class="step-copy"><b>采购建议与风险</b><small>{{ currentStep === 3 ? '当前步骤 →' : '点击切换 →' }}</small></span>
        </button>
      </nav>

      <template v-if="currentStep === 1">
        <section class="intro-card">
          <p class="step-caption">Step 01</p>
          <h2>设置两种采购场景的评估权重</h2>
          <p>试产更关注交付周期和采购灵活性；量产更关注采购成本和品质可靠性。每个场景的权重合计必须为 100%。</p>
        </section>

        <section class="weights-grid">
          <article class="weight-card">
            <div class="card-title">
              <div><span>场景 A</span><h3>小批量试产（100台）</h3></div>
              <strong :class="{ danger: smallWeightTotal !== 100 }">{{ smallWeightTotal }}%</strong>
            </div>
            <table class="training-table">
              <thead><tr><th>评估维度</th><th>维度说明</th><th>权重（%）</th></tr></thead>
              <tbody>
                <tr v-for="row in rows" :key="row.key">
                  <td>{{ row.name }}</td><td>{{ row.description }}</td>
                  <td><el-input-number v-model="row.smallBatchWeight" :min="0" :max="100" :precision="0" controls-position="right" /></td>
                </tr>
              </tbody>
            </table>
          </article>

          <article class="weight-card">
            <div class="card-title">
              <div><span>场景 B</span><h3>大规模量产（10000台）</h3></div>
              <strong :class="{ danger: largeWeightTotal !== 100 }">{{ largeWeightTotal }}%</strong>
            </div>
            <table class="training-table">
              <thead><tr><th>评估维度</th><th>维度说明</th><th>权重（%）</th></tr></thead>
              <tbody>
                <tr v-for="row in rows" :key="row.key">
                  <td>{{ row.name }}</td><td>{{ row.description }}</td>
                  <td><el-input-number v-model="row.largeBatchWeight" :min="0" :max="100" :precision="0" controls-position="right" /></td>
                </tr>
              </tbody>
            </table>
          </article>
        </section>

        <footer class="page-actions">
          <el-button type="primary" size="large" @click="saveStepOne">保存并进入渠道评分 <el-icon><CircleCheck /></el-icon></el-button>
        </footer>
      </template>

      <template v-else-if="currentStep === 2">
        <section class="intro-card compact">
          <p class="step-caption">Step 02</p>
          <h2>为供应渠道评分并比较结果</h2>
          <p>每项评分为 0–10 分，渠道名称和评分均由学生填写；系统会按第一步已保存的权重自动计算加权总分。</p>
        </section>

        <section v-for="section in scoreSections" :key="section.key" class="score-section">
          <div class="section-heading">
            <div><span>{{ section.label }}</span><h3>{{ section.title }}</h3></div>
            <small>加权总分 = Σ（维度评分 × 权重）</small>
          </div>
          <div class="table-scroll">
            <table class="training-table score-table">
              <thead>
                <tr><th>渠道</th><th v-for="dimension in rows" :key="dimension.key">{{ dimension.name }}</th><th>加权总分</th></tr>
              </thead>
              <tbody>
                <tr v-for="row in section.rows" :key="row.id">
                  <td><el-input v-model.trim="row.channel" maxlength="40" placeholder="填写渠道名称" :disabled="section.key === 'large'" @input="section.key === 'small' && syncChannelNames()" /></td>
                  <td v-for="dimension in rows" :key="dimension.key">
                    <el-input-number v-model="scoreFor(row, dimension.key).score" :min="0" :max="10" :precision="0" controls-position="right" />
                  </td>
                  <td class="total-score">{{ weightedScore(row, section.weights) }}</td>
                </tr>
              </tbody>
            </table>
          </div>
        </section>

        <footer class="page-actions split-actions">
          <el-button size="large" @click="currentStep = 1">上一步</el-button>
          <el-button type="primary" size="large" @click="saveStepTwo">保存评分结果</el-button>
        </footer>
      </template>

      <template v-else>
        <section class="intro-card compact">
          <p class="step-caption">Step 03</p>
          <h2>渠道优选、采购建议与供应风险</h2>
          <p>最优和次优渠道由第二步的加权评分自动排名生成，学生需要分析差异、形成采购建议，并完成供应风险评估。</p>
        </section>

        <section class="analysis-panel">
          <div class="section-heading">
            <div><span>（一）渠道优选与场景分析</span><h3>根据评分结果形成综合采购建议</h3></div>
            <small>排名结果为只读数据</small>
          </div>
          <div class="table-scroll">
            <table class="training-table ranking-table">
              <thead><tr><th>采购场景</th><th>最优渠道（排名1）</th><th>次优渠道（排名2）</th><th>分差与分析</th></tr></thead>
              <tbody>
                <tr v-for="analysis in scenarioAnalyses" :key="analysis.scenario">
                  <td class="scene-name">{{ analysis.label }}</td>
                  <td><div class="rank-result"><strong>{{ rankAt(analysis.scenario, 0).channel || '--' }}</strong><span>{{ formatScore(rankAt(analysis.scenario, 0).score) }} 分</span></div></td>
                  <td><div class="rank-result"><strong>{{ rankAt(analysis.scenario, 1).channel || '--' }}</strong><span>{{ formatScore(rankAt(analysis.scenario, 1).score) }} 分</span></div></td>
                  <td><el-input v-model.trim="analysis.differenceAnalysis" type="textarea" :rows="3" maxlength="2000" show-word-limit placeholder="结合分差、采购侧重点与渠道能力进行分析" /></td>
                </tr>
              </tbody>
            </table>
          </div>
          <div class="recommendation-card">
            <label for="procurement-recommendation">综合采购建议</label>
            <el-input id="procurement-recommendation" v-model.trim="procurementRecommendation" type="textarea" :rows="5" maxlength="3000" show-word-limit placeholder="说明试产与量产阶段的采购组合、切换原则及执行建议" />
          </div>
        </section>

        <section class="analysis-panel">
          <div class="section-heading risk-heading">
            <div><span>（二）供应风险评估</span><h3>识别风险并制定应对措施</h3></div>
            <div class="row-actions">
              <el-button :icon="Plus" @click="addRiskRow">增加一行</el-button>
              <el-button :icon="Delete" @click="removeRiskRow">删除一行</el-button>
            </div>
          </div>
          <p class="panel-tip">默认的 4 条风险示例不可删除；可新增至 10 条，删除操作仅作用于最后一条新增风险。斜体内容为可直接修改或复制的填写示例。</p>
          <div class="table-scroll">
            <table class="training-table risk-table">
              <thead><tr><th>风险维度</th><th>风险说明</th><th>风险等级（高/中/低）</th><th>应对措施</th></tr></thead>
              <tbody>
                <tr v-for="(risk, index) in riskRows" :key="risk.id" :class="{ 'default-risk-row': risk.locked }">
                  <td><el-input v-model.trim="risk.dimension" maxlength="80" placeholder="填写风险维度" /></td>
                  <td><el-input v-model.trim="risk.description" type="textarea" :rows="3" maxlength="1000" placeholder="填写风险说明" /></td>
                  <td><el-select v-model="risk.level" placeholder="请选择"><el-option label="高" value="高" /><el-option label="中" value="中" /><el-option label="低" value="低" /></el-select></td>
                  <td><el-input v-model.trim="risk.measure" type="textarea" :rows="3" maxlength="2000" placeholder="填写应对措施" /></td>
                </tr>
              </tbody>
            </table>
          </div>
        </section>

        <footer class="page-actions split-actions">
          <el-button size="large" @click="currentStep = 2">上一步</el-button>
          <el-button type="primary" size="large" @click="saveStepThree">保存第 3 步</el-button>
        </footer>
      </template>
    </section>
    </main>

    <TrainingAiSidebar
      :task-key="TASK_KEY"
      :has-saved-answer="hasSavedAnswer"
      :progress-items="progressItems"
      :study-tip="currentStudyTip"
      reference-title="供应渠道评估提示"
      reference-text="· 试产阶段重点关注交付周期与采购灵活性<br />· 量产阶段重点关注采购成本与质量可靠性<br />· 风险建议应包含明确的应对措施"
      assist-text="建议先区分试产与量产的评估侧重点，再基于评分结果形成采购建议和供应风险应对方案。"
    />
  </div>
</template>

<script setup>
import { computed, onMounted, ref } from "vue";
import { CircleCheck, Delete, Plus } from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";
import TrainingAiSidebar from "@/views/components/TrainingAiSidebar.vue";
import TrainingTaskBrief from "@/views/components/TrainingTaskBrief.vue";
import { getTrainingTaskByKey } from "@/api/trainingTask";
import { parseTrainingArray } from "@/views/training/taskKeyMap";
import {
  getStudentTrainingAnswer,
  saveStudentTrainingAnswer,
  validateSupplierEvaluationStepOne,
  validateSupplierEvaluationStepTwo,
  validateSupplierEvaluationStepThree,
} from "@/api/studentTrainingAnswer";

const TASK_KEY = "supplier-evaluation";
const loading = ref(false);
const currentStep = ref(1);
const stepOneSaved = ref(false);
const stepTwoSaved = ref(false);
const taskConfig = ref({});
const taskTitle = computed(() => taskConfig.value?.taskName || "供应渠道评估");
const taskBackground = computed(() => taskConfig.value?.background || "供应渠道会直接影响产品的采购成本、交付稳定性与质量风险，需要分别针对试产和量产场景建立评估标准。 ");
const taskGoals = computed(() => parseTrainingArray(taskConfig.value?.objectives ?? taskConfig.value?.goals, ["根据试产与量产场景设置供应渠道评估权重", "完成渠道评分、采购建议与供应风险分析"]));
const taskRequirement = computed(() => taskConfig.value?.requirements || taskConfig.value?.requirement || "完成各步骤校验并保存，渠道评分、采购建议和供应风险应与案例资料及评估结果保持一致。");
const hasSavedAnswer = computed(() => stepOneSaved.value || stepTwoSaved.value || Boolean(procurementRecommendation.value.trim()));
const currentStudyTip = computed(() => {
  const tips = {
    1: "先区分试产与量产的采购重点，确保每个场景的权重合计为 100%。",
    2: "逐项填写渠道评分，重点检查渠道名称和加权评分是否与已保存权重一致。",
    3: "根据排序结果形成采购建议，并为每类供应风险制定可执行的应对措施。",
  };
  return tips[currentStep.value] || tips[1];
});
const progressItems = computed(() => [
  { text: "设置评估权重", status: stepOneSaved.value ? "done" : currentStep.value === 1 ? "doing" : "" },
  { text: "渠道评分与对比", status: stepTwoSaved.value ? "done" : currentStep.value === 2 ? "doing" : "" },
  { text: "采购建议与风险", status: currentStep.value === 3 ? "doing" : "" },
]);

const rows = ref([
  { key: "procurementCost", name: "采购成本", description: "元器件/模组的单台采购总成本，含运费、税费", smallBatchWeight: 20, largeBatchWeight: 35 },
  { key: "deliveryCycle", name: "交货周期", description: "从下单到收货的时间，影响试产/生产进度", smallBatchWeight: 30, largeBatchWeight: 15 },
  { key: "qualityReliability", name: "品质可靠性", description: "元器件是否为正品，有无翻新/故障，规格匹配度", smallBatchWeight: 20, largeBatchWeight: 30 },
  { key: "procurementFlexibility", name: "采购灵活性", description: "是否支持小批量拆卖、零散采购、退换货", smallBatchWeight: 20, largeBatchWeight: 10 },
  { key: "serviceSupport", name: "服务支持", description: "是否提供技术文档、售后支持，退换货是否方便", smallBatchWeight: 10, largeBatchWeight: 10 },
]);

const DEFAULT_RISKS = [
  { dimension: "独家供应风险", description: "仅依赖单一渠道，供应中断时无替代方案", level: "中", measure: "建立2-3家备选渠道，试产阶段分散下单验证品质，量产阶段保留备选供应商每季度询价" },
  { dimension: "交期延误风险", description: "供应商交期不稳定，影响生产排期", level: "中", measure: "建立2-3家备选供应商，试产阶段零散采购，量产阶段多家供应商共同供货" },
  { dimension: "品质波动风险", description: "元器件批次间品质不一致，影响产品一致性", level: "高", measure: "建立2-3家备选供应商，不间断引入新供应商，每批次元器件到货后进行严格质检再入库" },
  { dimension: "价格波动风险", description: "原材料价格波动或供应商调价导致采购成本变化", level: "中", measure: "建立2-3家备选供应商，尝试引入新供应商，每季度询价，研判原料价格走势提前备货" },
];

function normalizeScores(source = {}) {
  const savedScores = Array.isArray(source)
    ? new Map(source.map((item) => [item?.dimension, item?.score]))
    : null;
  return rows.value.reduce((result, item) => {
    result[item.key] = Number(savedScores ? savedScores.get(item.name) : source[item.key]) || 0;
    return result;
  }, {});
}

function createScoreRows(savedRows = []) {
  const source = Array.isArray(savedRows) ? savedRows : [];
  return Array.from({ length: 5 }, (_, index) => {
    const saved = source[index] || {};
    return {
      id: `${Date.now()}-${index}-${Math.random().toString(16).slice(2)}`,
      channel: String(saved.channel || ""),
      scores: normalizeScores(saved.scores),
      weightedTotal: saved.weightedTotal ?? null,
    };
  });
}

function createScenarioAnalyses(savedRows = []) {
  const source = Array.isArray(savedRows) ? savedRows : [];
  const byScenario = new Map(source.map((item) => [item?.scenario, item]));
  return [
    { scenario: "smallBatch", label: "小批量试产（100台）", differenceAnalysis: String(byScenario.get("smallBatch")?.differenceAnalysis || "") },
    { scenario: "largeBatch", label: "大规模量产（10000台）", differenceAnalysis: String(byScenario.get("largeBatch")?.differenceAnalysis || "") },
  ];
}

function createRiskRows(savedRows = []) {
  const source = Array.isArray(savedRows) && savedRows.length ? savedRows : DEFAULT_RISKS;
  return source.map((item, index) => ({
    id: `${Date.now()}-${index}-${Math.random().toString(16).slice(2)}`,
    dimension: String(item?.dimension || ""),
    description: String(item?.description || ""),
    level: ["高", "中", "低"].includes(item?.level) ? item.level : "中",
    measure: String(item?.measure || ""),
    locked: index < DEFAULT_RISKS.length,
  }));
}

const smallBatchRows = ref(createScoreRows());
const largeBatchRows = ref(createScoreRows());
const scenarioAnalyses = ref(createScenarioAnalyses());
const procurementRecommendation = ref("");
const riskRows = ref(createRiskRows());

const smallWeightTotal = computed(() => rows.value.reduce((sum, row) => sum + Number(row.smallBatchWeight || 0), 0));
const largeWeightTotal = computed(() => rows.value.reduce((sum, row) => sum + Number(row.largeBatchWeight || 0), 0));
const smallWeights = computed(() => rows.value.reduce((result, row) => ({ ...result, [row.key]: Number(row.smallBatchWeight || 0) }), {}));
const largeWeights = computed(() => rows.value.reduce((result, row) => ({ ...result, [row.key]: Number(row.largeBatchWeight || 0) }), {}));
const scoreSections = computed(() => [
  { key: "small", label: "场景 A", title: "小批量试产（100台）渠道评分", rows: smallBatchRows.value, weights: smallWeights.value },
  { key: "large", label: "场景 B", title: "大规模量产（10000台）渠道评分", rows: largeBatchRows.value, weights: largeWeights.value },
]);

function scoreFor(row, key) {
  if (!Object.prototype.hasOwnProperty.call(row.scores, key)) row.scores[key] = 0;
  return {
    get score() { return row.scores[key]; },
    set score(value) { row.scores[key] = value; row.weightedTotal = null; },
  };
}

function toNumber(value) {
  const numeric = Number(value);
  return Number.isFinite(numeric) ? numeric : 0;
}

function weightedScore(row, weights) {
  const score = rows.value.reduce((sum, item) => sum + toNumber(row.scores[item.key]) * toNumber(weights[item.key]) / 100, 0);
  return score.toFixed(2);
}

function channelRanking(scenario) {
  const source = scenario === "smallBatch" ? smallBatchRows.value : largeBatchRows.value;
  const weights = scenario === "smallBatch" ? smallWeights.value : largeWeights.value;
  return source
    .map((row) => {
      const stored = Number(row.weightedTotal);
      return { channel: String(row.channel || "").trim(), score: Number.isFinite(stored) ? stored : Number(weightedScore(row, weights)) };
    })
    .filter((item) => item.channel)
    .sort((left, right) => right.score - left.score || left.channel.localeCompare(right.channel, "zh-CN"));
}

function rankAt(scenario, index) {
  return channelRanking(scenario)[index] || {};
}

function formatScore(value) {
  const score = Number(value);
  return Number.isFinite(score) ? score.toFixed(2) : "--";
}

function syncChannelNames() {
  largeBatchRows.value.forEach((row, index) => {
    row.channel = String(smallBatchRows.value[index]?.channel || "").trim();
  });
}

function buildStepOnePayload() {
  return {
    items: rows.value.map((row) => ({
      dimension: row.name,
      smallBatchWeight: Number(row.smallBatchWeight || 0),
      largeBatchWeight: Number(row.largeBatchWeight || 0),
    })),
  };
}

function buildStepTwoPayload() {
  const serializeChannels = (source) => source.map((row) => ({
    channel: String(row.channel || "").trim(),
    scores: rows.value.map((dimension) => ({
      dimension: dimension.name,
      score: toNumber(row.scores[dimension.key]),
    })),
  }));
  return {
    smallBatchChannels: serializeChannels(smallBatchRows.value),
    largeBatchChannels: serializeChannels(largeBatchRows.value),
  };
}

function buildStepThreePayload() {
  return {
    scenarioAnalyses: scenarioAnalyses.value.map((item) => ({
      scenario: item.scenario,
      bestChannel: rankAt(item.scenario, 0).channel || "",
      secondChannel: rankAt(item.scenario, 1).channel || "",
      differenceAnalysis: item.differenceAnalysis,
    })),
    procurementRecommendation: procurementRecommendation.value,
    risks: riskRows.value.map((item) => ({ dimension: item.dimension, description: item.description, level: item.level, measure: item.measure })),
  };
}

function parseJson(value) {
  if (!value) return null;
  if (typeof value === "object") return value;
  try { return JSON.parse(value); } catch { return null; }
}

function applyStepOne(answer) {
  const result = parseJson(answer?.step1Answer);
  if (!Array.isArray(result?.items)) return false;
  const source = new Map(result.items.map((item) => [item.dimension, item]));
  rows.value.forEach((row) => {
    const saved = source.get(row.name);
    if (!saved) return;
    row.smallBatchWeight = toNumber(saved.smallBatchWeight);
    row.largeBatchWeight = toNumber(saved.largeBatchWeight);
  });
  return true;
}

function applyStepTwo(answer) {
  const result = parseJson(answer?.step2Answer);
  if (!Array.isArray(result?.smallBatchChannels) || !Array.isArray(result?.largeBatchChannels)) return false;
  smallBatchRows.value = createScoreRows(result.smallBatchChannels);
  largeBatchRows.value = createScoreRows(result.largeBatchChannels);
  syncChannelNames();
  return true;
}

function applyStepThree(answer) {
  const result = parseJson(answer?.step3Answer);
  if (!Array.isArray(result?.scenarioAnalyses) || !Array.isArray(result?.risks)) return false;
  scenarioAnalyses.value = createScenarioAnalyses(result.scenarioAnalyses);
  procurementRecommendation.value = String(result.procurementRecommendation || "");
  riskRows.value = createRiskRows(result.risks);
  return true;
}

async function saveStepOne() {
  try {
    const result = await validateSupplierEvaluationStepOne(buildStepOnePayload());
    if (!result?.valid) throw new Error(result?.message || "权重校验未通过");
    await saveStudentTrainingAnswer({ taskKey: TASK_KEY, currentStep: 1, saveAction: "SAVE", progressStatus: "IN_PROGRESS", step1Answer: JSON.stringify({ items: result.items }) });
    stepOneSaved.value = true;
    currentStep.value = 2;
    ElMessage.success("权重已保存，请继续完成渠道评分");
  } catch (error) {
    ElMessage.error(error?.message || "保存失败，请检查权重填写");
  }
}

async function saveStepTwo() {
  try {
    syncChannelNames();
    const result = await validateSupplierEvaluationStepTwo(buildStepTwoPayload());
    if (!result?.valid) throw new Error(result?.message || "渠道评分校验未通过");
    smallBatchRows.value = createScoreRows(result.smallBatchChannels);
    largeBatchRows.value = createScoreRows(result.largeBatchChannels);
    await saveStudentTrainingAnswer({ taskKey: TASK_KEY, currentStep: 2, saveAction: "SAVE", progressStatus: "IN_PROGRESS", step2Answer: JSON.stringify({ weights: result.weights, smallBatchChannels: result.smallBatchChannels, largeBatchChannels: result.largeBatchChannels }) });
    stepTwoSaved.value = true;
    syncChannelNames();
    ElMessage.success("渠道评分已保存，可进入第 3 步形成采购建议");
  } catch (error) {
    ElMessage.error(error?.message || "保存失败，请检查渠道和评分");
  }
}

async function saveStepThree() {
  try {
    const result = await validateSupplierEvaluationStepThree(buildStepThreePayload());
    if (!result?.valid) throw new Error(result?.message || "第 3 步校验未通过");
    const step3Answer = { scenarioAnalyses: result.scenarioAnalyses, procurementRecommendation: result.procurementRecommendation, risks: result.risks };
    await saveStudentTrainingAnswer({ taskKey: TASK_KEY, currentStep: 3, saveAction: "SAVE", progressStatus: "IN_PROGRESS", step3Answer: JSON.stringify(step3Answer) });
    applyStepThree({ step3Answer });
    ElMessage.success("采购建议与供应风险已保存");
  } catch (error) {
    ElMessage.error(error?.message || "保存失败，请检查填写内容");
  }
}

function openStepTwo() {
  if (!stepOneSaved.value) {
    ElMessage.warning("请先完成并保存第一步权重设置");
    return;
  }
  currentStep.value = 2;
}

function openStepThree() {
  if (!stepOneSaved.value || !stepTwoSaved.value) {
    ElMessage.warning("请先完成并保存前两步内容");
    return;
  }
  currentStep.value = 3;
}

function addRiskRow() {
  if (riskRows.value.length >= 10) {
    ElMessage.warning("供应风险最多填写 10 条");
    return;
  }
  riskRows.value.push({ id: `${Date.now()}-${Math.random().toString(16).slice(2)}`, dimension: "", description: "", level: "中", measure: "", locked: false });
}

function removeRiskRow() {
  const index = [...riskRows.value].map((row, index) => ({ row, index })).reverse().find((item) => !item.row.locked)?.index;
  if (index === undefined) {
    ElMessage.warning("默认的 4 条供应风险不可删除");
    return;
  }
  riskRows.value.splice(index, 1);
}

onMounted(async () => {
  loading.value = true;
  try {
    taskConfig.value = (await getTrainingTaskByKey(TASK_KEY))?.data || {};
  } catch (_) {
    taskConfig.value = {};
  }
  try {
    const answer = await getStudentTrainingAnswer(TASK_KEY);
    stepOneSaved.value = applyStepOne(answer);
    stepTwoSaved.value = applyStepTwo(answer);
    applyStepThree(answer);
    if (Number(answer?.currentStep) === 3 && stepOneSaved.value && stepTwoSaved.value) currentStep.value = 3;
    else if (Number(answer?.currentStep) === 2 && stepOneSaved.value) currentStep.value = 2;
  } catch (error) {
    ElMessage.error(error?.message || "页面数据加载失败");
  } finally {
    loading.value = false;
  }
});
</script>

<style scoped>
.supplier-page { min-height: 100%; padding: 24px; color: #dce9f2; background: #06111d; }
.workspace-shell { box-sizing: border-box; width: min(100%, 1520px); margin: 0 auto; padding: 28px; border: 1px solid rgba(0, 180, 255, .25); border-radius: 36px; background: rgba(8, 18, 28, .6); box-shadow: inset 0 1px 0 rgba(169, 229, 255, .08), 0 22px 48px rgba(0, 0, 0, .22); }
.supplier-page .training-core { box-sizing: border-box; min-width: 0; width: 100%; margin: 0; padding: 28px; border: 1px solid rgba(0, 180, 255, .25); border-radius: 36px; background: rgba(8, 18, 28, .6); box-shadow: inset 0 1px 0 rgba(169, 229, 255, .08), 0 22px 48px rgba(0, 0, 0, .22); }
.supplier-page .workspace-shell { width: 100%; max-width: none; margin: 0; padding: 0; border: 0; border-radius: 0; background: transparent; box-shadow: none; }
.workspace-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; margin-bottom: 24px; }
.eyebrow, .step-caption { margin: 0 0 7px; color: #63dcff; font-weight: 700; letter-spacing: .1em; }
.workspace-header h1, .intro-card h2 { margin: 0; color: #fff; }.workspace-header h1 { margin-top: 12px; font-size: var(--student-fs-display); font-weight: 900; line-height: 1.3; }
.workspace-header p:not(.eyebrow), .intro-card > p:last-child { margin: 10px 0 0; color: #9db4c4; line-height: 1.75; }
.task-badge { display: inline-flex; align-items: center; min-height: 28px; padding: 4px 14px; border: 1px solid rgba(99, 217, 255, .55); border-radius: 999px; color: #dff5ff; background: rgba(17, 126, 178, .36); white-space: nowrap; }
.step-nav { display: grid; grid-template-columns: minmax(0, 1fr) 40px minmax(0, 1fr) 40px minmax(0, 1fr); align-items: center; gap: 8px; margin: 0 0 30px; padding: 18px 22px; border: 1px solid rgba(0, 180, 255, .3); border-radius: 22px; background: rgba(1, 18, 31, .62); }
.step-nav i { position: relative; height: 2px; background: rgba(86, 198, 235, .48); }.step-nav i::after { position: absolute; top: 50%; right: 0; width: 7px; height: 7px; border-top: 1px solid #73b1ce; border-right: 1px solid #73b1ce; content: ''; transform: translateY(-50%) rotate(45deg); }
.step-tab { display: flex; align-items: center; min-width: 0; min-height: 66px; gap: 10px; padding: 8px 12px; border: 1px solid rgba(68, 141, 177, .35); border-radius: 12px; color: #9ab3d0; background: rgba(3, 27, 43, .52); cursor: pointer; font: inherit; text-align: left; transition: .2s ease; }
.step-tab:hover { border-color: rgba(89, 223, 255, .82); color: #fff; background: rgba(8, 92, 131, .52); transform: translateY(-1px); }.step-tab:focus-visible { outline: 2px solid #72e8ff; outline-offset: 3px; }
.step-marker { display: grid; flex: 0 0 38px; width: 38px; height: 38px; place-items: center; border: 1px solid rgba(101, 176, 208, .6); border-radius: 50%; color: #a6c4d9; background: rgba(3, 25, 40, .8); font-size: var(--student-fs-caption); font-weight: 900; }.step-copy { display: grid; min-width: 0; gap: 4px; }.step-copy b { overflow: hidden; font-size: var(--student-fs-body); font-weight: 800; text-overflow: ellipsis; white-space: nowrap; }.step-copy small { color: #66b6d4; font-size: var(--student-fs-caption); font-weight: 800; letter-spacing: .06em; }
.step-tab.active { color: white; border-color: #53d8fb; background: linear-gradient(135deg, rgba(7, 156, 207, .85), rgba(13, 105, 161, .92)); box-shadow: inset 0 0 24px rgba(77, 213, 255, .22); }.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; }
.intro-card, .analysis-panel { padding: 24px; border: 1px solid rgba(82, 174, 226, .42); border-radius: 26px; background: rgba(0, 25, 42, .64); }
.intro-card.compact { margin-bottom: 20px; }
.weights-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; margin-top: 20px; }
.weight-card, .score-section { padding: 20px; border: 1px solid rgba(71, 167, 209, .28); border-radius: 14px; background: rgba(4, 23, 36, .68); }
.card-title, .section-heading { display: flex; align-items: center; justify-content: space-between; gap: 18px; margin-bottom: 16px; }
.card-title span, .section-heading span { color: #52cef6; font-size: var(--student-fs-body-sm); font-weight: 700; letter-spacing: .07em; }
.card-title h3, .section-heading h3 { margin: 4px 0 0; color: #fff; font-size: var(--student-fs-display); }
.card-title strong { color: #6de4ff; font-size: 25px; }.card-title strong.danger { color: #ff8888; }
.training-table { width: 100%; border-collapse: collapse; table-layout: fixed; overflow: hidden; border: 1px solid #2b5c73; }
.training-table th { padding: 13px 10px; color: #effbff; background: #0c91c8; font-weight: 700; }
.training-table td { padding: 10px; border: 1px solid #2b5c73; color: #cfe2ec; vertical-align: middle; text-align: center; }
.training-table tbody tr:nth-child(even) { background: rgba(15, 48, 66, .42); }
.training-table :deep(.el-input__wrapper), .training-table :deep(.el-textarea__inner), .training-table :deep(.el-select__wrapper) { background: rgba(2, 15, 24, .7); box-shadow: 0 0 0 1px #315f75 inset; }
.training-table :deep(.el-input__inner), .training-table :deep(.el-textarea__inner), .training-table :deep(.el-select__selected-item), .training-table :deep(.el-input-number__decrease), .training-table :deep(.el-input-number__increase) { color: #e7f6fd; }
.training-table :deep(.el-textarea__inner) { min-height: 70px !important; resize: vertical; }
.page-actions { display: flex; justify-content: center; padding-top: 28px; }.split-actions { justify-content: space-between; }
.page-actions :deep(.el-button--primary), .row-actions :deep(.el-button) { border-color: #18b6ec; background: #0e96ca; }
.score-section { margin-bottom: 20px; }.section-heading small { color: #93adbd; }.table-scroll { overflow-x: auto; }
.score-table { min-width: 960px; }.score-table th:first-child, .score-table td:first-child { width: 175px; }.score-table :deep(.el-input-number) { width: 100%; }.total-score { color: #6de4ff !important; font-size: 17px; font-weight: 700; }
.analysis-panel + .analysis-panel { margin-top: 20px; }.ranking-table { min-width: 940px; }.ranking-table th:first-child { width: 18%; }.ranking-table th:nth-child(2), .ranking-table th:nth-child(3) { width: 19%; }.scene-name { color: #71dcfb !important; font-weight: 700; }.rank-result { display: flex; flex-direction: column; gap: 5px; }.rank-result strong { color: #f3fbff; }.rank-result span { color: #62cef1; font-size: var(--student-fs-body-sm); }
.recommendation-card { margin-top: 20px; }.recommendation-card label { display: block; margin-bottom: 9px; color: #e7f5fb; font-weight: 700; }.recommendation-card :deep(.el-textarea__inner) { min-height: 130px !important; color: #e7f6fd; background: rgba(2, 15, 24, .7); box-shadow: 0 0 0 1px #315f75 inset; }
.risk-heading { align-items: flex-end; }.row-actions { display: flex; gap: 10px; }.panel-tip { margin: -4px 0 16px; color: #9db8c6; line-height: 1.7; }.risk-table { min-width: 1080px; }.risk-table th:nth-child(1) { width: 15%; }.risk-table th:nth-child(2) { width: 29%; }.risk-table th:nth-child(3) { width: 16%; }.risk-table :deep(.el-select) { width: 100%; }.default-risk-row :deep(.el-input__inner), .default-risk-row :deep(.el-textarea__inner), .default-risk-row :deep(.el-select__selected-item) { color: #b7cbd6; font-style: italic; }
@media (max-width: 980px) { .weights-grid { grid-template-columns: 1fr; }.step-nav { grid-template-columns: 1fr; gap: 8px; }.step-nav i { display: none; }.workspace-header { flex-direction: column; }.risk-heading { align-items: flex-start; flex-direction: column; }.split-actions { gap: 12px; }.supplier-page { padding: 12px; }.workspace-shell { padding: 16px; } }
</style>
