|
|
|
|
|
<template>
|
|
|
|
|
|
<div class="feasibility-page student-training-shell">
|
|
|
|
|
|
<main class="feasibility-core">
|
|
|
|
|
|
<header class="task-header">
|
|
|
|
|
|
<span>DEMAND INSIGHT · BUSINESS CASE</span>
|
|
|
|
|
|
<h1>{{ taskTitle }}</h1>
|
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
|
|
<TrainingTaskBrief :background="taskBackground" :goals="taskGoals" :requirements="taskRequirement" :show-material="false" />
|
|
|
|
|
|
|
|
|
|
|
|
<section class="workbench">
|
|
|
|
|
|
<div class="workbench-actions">
|
|
|
|
|
|
<TrainingMaterialButton :material-name="taskConfig?.materialName" :material-url="taskConfig?.materialUrl" />
|
|
|
|
|
|
<button class="action-button" type="button" @click="exportOutcome"><el-icon><Download /></el-icon>导出实训成果</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<nav class="step-indicator" aria-label="商业可行性论证步骤">
|
|
|
|
|
|
<template v-for="(step, index) in trainingSteps" :key="step">
|
|
|
|
|
|
<button type="button" :class="['step-tab', { active: currentStep === index + 1, complete: currentStep > index + 1 }]" @click="switchStep(index + 1)">
|
|
|
|
|
|
<b>{{ String(index + 1).padStart(2, '0') }}</b><span><strong>{{ step }}</strong><small>{{ currentStep === index + 1 ? '当前步骤' : '点击切换' }} →</small></span>
|
|
|
|
|
|
</button><i v-if="index < trainingSteps.length - 1" />
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</nav>
|
|
|
|
|
|
|
|
|
|
|
|
<section v-if="currentStep === 1" class="step-card">
|
|
|
|
|
|
<div class="step-heading"><div><p>Step 01</p><h2>商业可行性论证</h2></div><em>结构化论证</em></div>
|
|
|
|
|
|
<p class="intro">商业可行性论证需要从多个维度系统展开。请基于案例信息,完成项目、市场、用户、商业模式、成本收益和风险的论证。</p>
|
|
|
|
|
|
|
|
|
|
|
|
<section class="form-section">
|
|
|
|
|
|
<div class="section-title"><span>01</span><div><h3>项目概述</h3><p>结合前序 PEST、SWOT 分析,说明项目为何值得推进。</p></div></div>
|
|
|
|
|
|
<div class="form-table overview-table">
|
|
|
|
|
|
<label v-for="field in overviewFields" :key="field.key"><span>{{ field.label }}</span><textarea v-model.trim="form.projectOverview[field.key]" :placeholder="field.placeholder" rows="3" /></label>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
|
|
<section class="form-section">
|
|
|
|
|
|
<div class="section-title"><span>02</span><div><h3>市场规模与竞争格局</h3><p>填写可验证的市场数据,比例项目以百分数填写,例如 12.5。</p></div></div>
|
|
|
|
|
|
<div class="form-table market-table">
|
|
|
|
|
|
<label v-for="field in marketFields" :key="field.key"><span>{{ field.label }}</span><div class="input-with-suffix"><input v-model="form.marketAnalysis[field.key]" :type="field.type || 'text'" :min="field.type === 'number' ? 0 : undefined" :step="field.type === 'number' ? '0.01' : undefined" :placeholder="field.placeholder" /><b v-if="field.suffix">{{ field.suffix }}</b></div></label>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
|
|
<section class="form-section">
|
|
|
|
|
|
<div class="section-title"><span>03</span><div><h3>目标用户群体分析</h3><p>从不同消费能力和使用场景中识别最有价值的用户。</p></div></div>
|
|
|
|
|
|
<div class="table-wrap"><table><thead><tr><th>用户群体</th><th>典型场景</th><th>核心需求</th><th>消费能力</th></tr></thead><tbody><tr v-for="(user, index) in form.targetUsers" :key="index"><td><textarea v-model.trim="user.userGroup" placeholder="例如:25-35 岁健身爱好者" /></td><td><textarea v-model.trim="user.scenario" placeholder="例如:居家训练" /></td><td><textarea v-model.trim="user.coreNeed" placeholder="例如:专业指导与反馈" /></td><td><input v-model.trim="user.spendingPower" placeholder="高 / 中 / 低" /></td></tr></tbody></table></div>
|
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
|
|
<section class="form-section">
|
|
|
|
|
|
<div class="section-title"><span>04</span><div><h3>商业模式梳理</h3><p>分别说明基础销售和持续增值服务如何形成收入。</p></div></div>
|
|
|
|
|
|
<div class="table-wrap"><table><thead><tr><th>模块</th><th>案例公司的策略</th><th>说明</th></tr></thead><tbody><tr v-for="model in form.businessModels" :key="model.module"><td class="fixed-cell">{{ model.module }}</td><td><textarea v-model.trim="model.strategy" placeholder="填写渠道、产品组合或服务策略" /></td><td><textarea v-model.trim="model.explanation" placeholder="说明策略与用户、成本的关系" /></td></tr></tbody></table></div>
|
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
|
|
<section class="form-section cost-section">
|
|
|
|
|
|
<div class="section-title"><span>05</span><div><h3>成本结构、定价与毛利</h3><p>单位总成本、单位毛利和毛利率由系统自动汇总;毛利率按照原型公式“单位毛利 ÷ 单位总成本”计算。</p></div></div>
|
|
|
|
|
|
<div class="cost-layout">
|
|
|
|
|
|
<div class="table-wrap"><table><thead><tr><th>成本项目</th><th>金额(元/台)</th></tr></thead><tbody><tr v-for="cost in form.costs" :key="cost.id"><td>{{ cost.label }}</td><td><input v-model="cost.amount" type="number" min="0" step="0.01" placeholder="0.00" /></td></tr><tr class="total-row"><td>单位总成本</td><td>{{ currency(totalCost) }}</td></tr></tbody></table></div>
|
|
|
|
|
|
<div class="profit-panel"><div class="profit-formula">单位毛利 = 目标售价 − 单位总成本<br />毛利率 = 单位毛利 ÷ 单位总成本</div><label><span>目标售价(元/台)</span><input v-model="form.targetPrice" type="number" min="0" step="0.01" placeholder="填写目标售价" /></label><div class="computed"><span>单位毛利</span><b>{{ currency(unitGrossProfit) }} 元</b></div><div class="computed"><span>毛利率</span><b>{{ percent(grossMargin) }}</b></div></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
|
|
<section class="form-section">
|
|
|
|
|
|
<div class="section-title"><span>06</span><div><h3>风险识别与评估</h3><p>识别项目主要风险,并明确影响程度及可执行的应对措施。</p></div></div>
|
|
|
|
|
|
<div class="table-wrap"><table><thead><tr><th>风险类型</th><th>具体风险描述</th><th>影响程度</th><th>应对措施</th></tr></thead><tbody><tr v-for="risk in form.risks" :key="risk.type"><td class="fixed-cell">{{ risk.type }}</td><td><textarea v-model.trim="risk.description" placeholder="填写具体风险" /></td><td><select v-model="risk.impact"><option value="">请选择</option><option value="高">高</option><option value="中">中</option><option value="低">低</option></select></td><td><textarea v-model.trim="risk.response" placeholder="填写应对措施" /></td></tr></tbody></table></div>
|
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="step-actions"><button class="action-button primary" type="button" :disabled="saving" @click="validateAndContinue">{{ saving ? '校验并保存中…' : '校验并进入第 2 步' }}</button><button class="action-button" type="button" :disabled="saving" @click="resetForm"><el-icon><RefreshLeft /></el-icon>清空填写</button></div>
|
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
|
|
<section v-else class="step-card placeholder"><p>第 {{ currentStep }} 步将在后续实训页面中配置。</p><button class="action-button" type="button" @click="currentStep = 1">返回第 1 步</button></section>
|
|
|
|
|
|
</section>
|
|
|
|
|
|
</main>
|
|
|
|
|
|
<TrainingAiSidebar study-tip="先从案例资料中提炼可验证的市场、用户与成本依据,再形成一致的商业论证。" reference-title="可行性论证提示" reference-text="• 结论要有数据或前序分析支撑<br />• 价格、成本和毛利需要逻辑一致<br />• 风险应附带可执行的应对措施" :progress-items="progressItems" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
import { Download, RefreshLeft } from "@element-plus/icons-vue";
|
|
|
|
|
|
import { checkBusinessFeasibilityStepOne, getStudentTrainingAnswer, saveStudentTrainingAnswer } from "@/api/studentTrainingAnswer";
|
|
|
|
|
|
import { getTrainingTaskByKey } from "@/api/trainingTask";
|
|
|
|
|
|
import TrainingAiSidebar from "@/views/components/TrainingAiSidebar.vue";
|
|
|
|
|
|
import TrainingMaterialButton from "@/views/components/TrainingMaterialButton.vue";
|
|
|
|
|
|
import TrainingTaskBrief from "@/views/components/TrainingTaskBrief.vue";
|
|
|
|
|
|
|
|
|
|
|
|
const TASK_KEY = "business-feasibility";
|
|
|
|
|
|
const DEFAULT_STEPS = ["商业可行性论证", "收益测算", "实施规划", "决策结论"];
|
|
|
|
|
|
const overviewFields = [
|
|
|
|
|
|
{ key: "projectBackground", label: "项目背景", placeholder: "概述公司与相关品类市场的发展、需求情况" },
|
|
|
|
|
|
{ key: "productPositioning", label: "产品定位", placeholder: "说明目标用户、核心卖点、使用场景与差异化理由" },
|
|
|
|
|
|
{ key: "projectGoals", label: "项目目标", placeholder: "填写短期、中期和长期可衡量目标" },
|
|
|
|
|
|
{ key: "macroEnvironmentConclusion", label: "宏观环境分析结论", placeholder: "总结 PEST 分析对项目的影响" },
|
|
|
|
|
|
{ key: "competitiveLandscapeConclusion", label: "竞争态势分析结论", placeholder: "总结 SWOT / 竞争分析带来的机会与压力" },
|
|
|
|
|
|
];
|
|
|
|
|
|
const marketFields = [
|
|
|
|
|
|
{ key: "annualMarketSize", label: "年度市场规模", type: "number", suffix: "亿元", placeholder: "例如 80" },
|
|
|
|
|
|
{ key: "monthlyGrowthRate", label: "月均增长率", type: "number", suffix: "%", placeholder: "例如 2.5" },
|
|
|
|
|
|
{ key: "topBrandMarketShare", label: "头部第一品牌市场份额", type: "number", suffix: "%", placeholder: "例如 26" },
|
|
|
|
|
|
{ key: "competitorsPriceRange", label: "主要竞品售价区间", suffix: "元", placeholder: "例如 299 - 899" },
|
|
|
|
|
|
{ key: "marketConcentrationCr3", label: "市场集中度(CR3)", type: "number", suffix: "%", placeholder: "例如 58" },
|
|
|
|
|
|
];
|
|
|
|
|
|
const defaultTask = { title: "商业可行性论证", background: "在产品开发前,综合市场机会、用户需求、竞争态势、成本收益和风险,判断项目是否具有可推进的商业价值。", goals: ["掌握商业可行性论证的基本维度", "形成市场、用户、成本与收益的一致判断", "识别主要风险并提出应对措施"], requirement: "请以案例资料和前序分析为依据,完成表格全部内容;成本与价格数据需真实、合理且逻辑一致。" };
|
|
|
|
|
|
const { proxy } = getCurrentInstance();
|
|
|
|
|
|
const taskConfig = ref(null); const currentStep = ref(1); const saving = ref(false); const completed = ref(false); const form = ref(createForm());
|
|
|
|
|
|
const taskTitle = computed(() => taskConfig.value?.taskName || defaultTask.title); const taskBackground = computed(() => taskConfig.value?.background || defaultTask.background); const taskGoals = computed(() => parseArray(taskConfig.value?.objectives, defaultTask.goals)); const taskRequirement = computed(() => taskConfig.value?.requirements || defaultTask.requirement); const trainingSteps = computed(() => parseArray(taskConfig.value?.steps, DEFAULT_STEPS));
|
|
|
|
|
|
const totalCost = computed(() => form.value.costs.reduce((sum, cost) => sum + numeric(cost.amount), 0)); const unitGrossProfit = computed(() => numeric(form.value.targetPrice) - totalCost.value); const grossMargin = computed(() => totalCost.value > 0 ? unitGrossProfit.value / totalCost.value * 100 : null);
|
|
|
|
|
|
const progressItems = computed(() => [{ text: completed.value ? "项目论证已保存" : "待完成项目论证", status: completed.value ? "done" : "" }, { text: totalCost.value > 0 ? "成本与毛利已计算" : "待填写成本与售价", status: totalCost.value > 0 ? "done" : "" }, { text: form.value.risks.filter((risk) => risk.description && risk.response && risk.impact).length === 4 ? "风险评估已完成" : "待完成风险评估", status: form.value.risks.filter((risk) => risk.description && risk.response && risk.impact).length === 4 ? "done" : "" }]);
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(async () => { await loadTaskConfig(); await loadSavedAnswer(); });
|
|
|
|
|
|
function createForm() { return { projectOverview: { projectBackground: "", productPositioning: "", projectGoals: "", macroEnvironmentConclusion: "", competitiveLandscapeConclusion: "" }, marketAnalysis: { annualMarketSize: "", monthlyGrowthRate: "", topBrandMarketShare: "", competitorsPriceRange: "", marketConcentrationCr3: "" }, targetUsers: Array.from({ length: 3 }, () => ({ userGroup: "", scenario: "", coreNeed: "", spendingPower: "" })), businessModels: [{ module: "产品销售渠道", strategy: "", explanation: "" }, { module: "增值服务", strategy: "", explanation: "" }], costs: [{ id: "hardware-bom", label: "硬件 BOM 成本", amount: "" }, { id: "manufacturing", label: "生产制造费用", amount: "" }, { id: "rd-amortization", label: "研发费用摊销", amount: "" }, { id: "channel-marketing", label: "渠道与营销费用", amount: "" }, { id: "logistics-warehouse", label: "物流仓储费用", amount: "" }], targetPrice: "", risks: ["技术风险", "市场风险", "供应链风险", "资金风险"].map((type) => ({ type, description: "", impact: "", response: "" })) }; }
|
|
|
|
|
|
function numeric(value) { const number = Number(value); return Number.isFinite(number) ? number : 0; }
|
|
|
|
|
|
function currency(value) { return Number(value || 0).toFixed(2); }
|
|
|
|
|
|
function percent(value) { return value === null || !Number.isFinite(value) ? "--" : `${Number(value).toFixed(2)}%`; }
|
|
|
|
|
|
function parseArray(value, fallback) { if (Array.isArray(value) && value.length) return value; if (!value) return fallback; try { const parsed = JSON.parse(value); return Array.isArray(parsed) && parsed.length ? parsed.map((item) => String(item?.name ?? item).trim()).filter(Boolean) : fallback; } catch (_) { const items = String(value).split(/[,,|]/).map((item) => item.trim()).filter(Boolean); return items.length ? items : fallback; } }
|
|
|
|
|
|
async function loadTaskConfig() { try { taskConfig.value = (await getTrainingTaskByKey(TASK_KEY))?.data || null; } catch (_) { taskConfig.value = null; } }
|
|
|
|
|
|
async function loadSavedAnswer() { try { const saved = (await getStudentTrainingAnswer(TASK_KEY))?.data; if (!saved?.step1Answer) return; const parsed = JSON.parse(saved.step1Answer); form.value = mergeForm(parsed?.form || parsed); completed.value = true; if (Number(saved.currentStep) > 1) currentStep.value = Number(saved.currentStep); } catch (_) { /* keep a new answer editable */ } }
|
|
|
|
|
|
function mergeForm(value) { const fallback = createForm(); const merged = { ...fallback, ...(value || {}), projectOverview: { ...fallback.projectOverview, ...(value?.projectOverview || {}) }, marketAnalysis: { ...fallback.marketAnalysis, ...(value?.marketAnalysis || {}) }, targetUsers: Array.isArray(value?.targetUsers) && value.targetUsers.length === 3 ? value.targetUsers : fallback.targetUsers, businessModels: Array.isArray(value?.businessModels) && value.businessModels.length === 2 ? value.businessModels : fallback.businessModels, costs: fallback.costs.map((cost) => ({ ...cost, ...(value?.costs || []).find((item) => item?.id === cost.id) })), risks: fallback.risks.map((risk) => ({ ...risk, ...(value?.risks || []).find((item) => item?.type === risk.type) })) }; return merged; }
|
|
|
|
|
|
function payload() { return { ...form.value, costs: form.value.costs.map(({ id, amount }) => ({ id, amount: amount === "" ? null : Number(amount) })), targetPrice: form.value.targetPrice === "" ? null : Number(form.value.targetPrice) }; }
|
|
|
|
|
|
async function validateAndContinue() { if (saving.value) return; saving.value = true; try { const result = await checkBusinessFeasibilityStepOne(payload()); const calculated = result?.data || {}; form.value.costs = form.value.costs.map((cost) => ({ ...cost, amount: cost.amount === "" ? "" : Number(cost.amount) })); await saveStudentTrainingAnswer(TASK_KEY, { step1Answer: JSON.stringify({ form: form.value, calculations: { unitTotalCost: calculated.unitTotalCost ?? totalCost.value, unitGrossProfit: calculated.unitGrossProfit ?? unitGrossProfit.value, grossMargin: calculated.grossMargin ?? grossMargin.value } }), currentStep: 2, submitted: false, saveAction: "SAVE" }); completed.value = true; currentStep.value = 2; proxy?.$modal?.msgSuccess("已完成校验并保存,已进入第 2 步"); } catch (error) { proxy?.$modal?.msgError?.(error?.message || "请完整填写本步骤内容后再提交"); } finally { saving.value = false; } }
|
|
|
|
|
|
function resetForm() { form.value = createForm(); completed.value = false; proxy?.$modal?.msgSuccess("已清空第 1 步填写内容"); }
|
|
|
|
|
|
function switchStep(step) { if (step > 1 && !completed.value) { proxy?.$modal?.msgWarning("请先完成并保存第 1 步"); return; } currentStep.value = step; }
|
|
|
|
|
|
function exportOutcome() { const blob = new Blob([JSON.stringify({ task: taskTitle.value, step: 1, ...payload(), calculations: { unitTotalCost: totalCost.value, unitGrossProfit: unitGrossProfit.value, grossMargin: grossMargin.value } }, null, 2)], { type: "application/json;charset=utf-8" }); const link = document.createElement("a"); link.href = URL.createObjectURL(blob); link.download = "商业可行性论证-第1步.json"; link.click(); URL.revokeObjectURL(link.href); }
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.feasibility-page { display:grid; grid-template-columns:minmax(0,1fr) 310px; gap:20px; min-height:100%; padding:22px; color:#d9f2fb; background:radial-gradient(circle at 22% 2%,rgba(21,135,181,.18),transparent 34%),#061521; }.feasibility-core { min-width:0; }.task-header { position:relative; overflow:hidden; padding:28px 32px; border:1px solid rgba(63,204,255,.28); border-radius:20px; background:linear-gradient(108deg,rgba(9,43,63,.97),rgba(5,25,41,.88)); box-shadow:0 20px 46px rgba(0,0,0,.22); }.task-header::after { position:absolute; top:-50px; right:8%; width:180px; height:180px; border:1px solid rgba(79,221,255,.22); border-radius:50%; content:""; }.task-header span { color:#58d9ff; font-size:12px; font-weight:800; letter-spacing:.16em; }.task-header h1 { margin:8px 0 0; color:#fff; font-size:32px; letter-spacing:.03em; }.workbench { margin-top:20px; padding:24px; border:1px solid rgba(73,200,248,.25); border-radius:20px; background:rgba(4,27,43,.82); }.workbench-actions { display:flex; justify-content:flex-end; gap:12px; }.action-button { display:inline-flex; align-items:center; justify-content:center; gap:8px; min-height:40px; padding:0 17px; border:1px solid rgba(101,218,255,.52); border-radius:10px; color:#e9fbff; background:rgba(14,109,153,.32); font:inherit; font-weight:800; cursor:pointer; transition:.2s; }.action-button:hover:not(:disabled) { transform:translateY(-1px); border-color:#6ee5ff; background:rgba(20,148,203,.48); }.action-button.primary { border-color:#42d4ff; background:linear-gradient(105deg,#0ca8dc,#08739f); }.action-button:disabled { cursor:not-allowed; opacity:.62; }.step-indicator { display:flex; align-items:stretch; margin:26px 0; padding:10px; border:1px solid rgba(69,201,248,.2); border-radius:15px; background:rgba(1,17,29,.52); }.step-tab { display:flex; flex:1; align-items:center; gap:11px; min-width:0; padding:11px 12px; border:0; border-radius:11px; color:#8eb7c8; background:transparent; text-align:left; cursor:pointer; }.step-tab b { display:grid; flex:0 0 35px; width:35px; height:35px; place-items:center; border:1px solid currentColor; border-radius:50%; }.step-tab span { min-width:0; }.step-tab strong,.step-tab small { display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }.step-tab strong { color:inherit; font-size:14px; }.step-tab small { margin-top:4px; color:#5791aa; font-size:11px; }.step-tab.active { color:#fff; background:linear-gradient(90deg,rgba(20,170,223,.82),rgba(10,111,155,.72)); box-shadow:0 7px 18px rgba(4,130,184,.22); }.step-tab.active b { border-color:#96edff; background:rgba(5,48,74,.28); }.step-tab.complete { color:#5cddf9; }.step-indicator i { width:1px; margin:10px 3px; background:rgba(88,190,223,.24); }.step-card { padding:24px; border:1px solid rgba(75,205,248,.26); border-radius:16px; background:linear-gradient(145deg,rgba(10,50,72,.64),rgba(3,24,39,.76)); }.step-heading { display:flex; align-items:flex-start; justify-content:space-between; gap:14px; }.step-heading p { margin:0 0 4px; color:#57d8fa; font-size:13px; font-weight:800; letter-spacing:.1em; }.step-heading h2 { margin:0; color:#fff; font-size:26px; }.step-heading em { padding:7px 11px; border:1px solid rgba(83,219,255,.45); border-radius:999px; color:#81e6ff; font-size:12px; font-style:normal; }.intro { margin:15px 0 0; color:#b7d8e4; line-height:1.8; }.form-section { margin-top:34px; }.section-title { display:flex; align-items:center; gap:12px; margin-bottom:14px; }.section-title > span { display:grid; width:31px; height:31px; place-items:center; border:1px solid rgba(91,220,255,.6); border-radius:9px; color:#6ee8ff; background:rgba(14,117,160,.24); font-weight:900; }.section-title h3 { margin:0; color:#fff; font-size:18px; }.section-title p { margin:3px 0 0; color:#87b6c7; font-size:13px; }.form-table { display:grid; border:1px solid rgba(96,202,235,.28); border-radius:12px; overflow:hidden; background:rgba(1,18,29,.42); }.form-table label { display:grid; grid-template-columns:190px 1fr; border-bottom:1px solid rgba(96,202,235,.22); }.form-table label:last-child { border-
|
|
|
|
|
|
@media (max-width:1280px) { .feasibility-page { grid-template-columns:1fr; }.step-indicator { overflow-x:auto; }.step-tab { min-width:170px; }.market-table { grid-template-columns:1fr; }.market-table label { border-right:0; }.cost-layout { grid-template-columns:1fr; } }
|
|
|
|
|
|
@media (max-width:720px) { .feasibility-page { padding:10px; }.task-header,.workbench,.step-card { padding:16px; }.task-header h1 { font-size:25px; }.workbench-actions { justify-content:flex-start; flex-wrap:wrap; }.form-table label { grid-template-columns:1fr; }.form-table label > span { justify-content:flex-start; }.step-heading em { display:none; }.step-actions { flex-wrap:wrap; } }
|
|
|
|
|
|
</style>
|