Files
cma-management/frontend/src/views/NewUserGuide.vue
T
Hermes CI Fix 3dddd36866 init: 管理会计OS初始代码
包含前后端完整代码:
- 前端:Vue3+Vite+ElementPlus
- 后端:FastAPI+SQLAlchemy
- 模块:驾驶舱/KPI/战略地图/预警/预算/成本/预测/改善行动
- 当前版本:v1.0.0
2026-05-28 17:32:22 +08:00

245 lines
10 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="guide-page">
<div class="guide-header">
<h3>🚀 新手引导</h3>
<p class="guide-subtitle">5分钟快速上手管理会计OS开始你的数据驱动管理之旅</p>
</div>
<!-- 快速开始引导 -->
<div class="quick-start-card" @click="startOnboarding">
<div class="qs-icon">🚀</div>
<div class="qs-body">
<div class="qs-title">快速开始引导</div>
<div class="qs-desc">按步骤带你完成系统配置和首次使用</div>
<el-tag size="small" type="danger">推荐新手</el-tag>
</div>
<el-button type="primary" size="large" class="qs-btn">开始引导</el-button>
</div>
<!-- 流程概览 -->
<div class="flow-section">
<h4>使用流程</h4>
<div class="flow-steps">
<div v-for="(step, i) in steps" :key="i" class="flow-step">
<div class="flow-num">{{ i + 1 }}</div>
<div class="flow-icon">{{ step.icon }}</div>
<div class="flow-title">{{ step.title }}</div>
<div class="flow-desc">{{ step.desc }}</div>
</div>
</div>
</div>
<!-- 视频教程 -->
<div class="video-section">
<h4>📹 视频教程</h4>
<div class="video-grid">
<div v-for="(v, i) in videos" :key="i" class="video-card" @click="openVideo(v)">
<div class="video-thumb">
<span class="play-icon"></span>
<span class="video-duration">{{ v.duration }}</span>
</div>
<div class="video-title">{{ v.title }}</div>
<div class="video-desc">{{ v.desc }}</div>
</div>
</div>
</div>
<!-- 引导遮罩弹窗 -->
<teleport to="body">
<div v-if="showWalkthrough" class="walkthrough-overlay" @click="skipWalkthrough">
<div class="walkthrough-box" @click.stop>
<div class="wt-header">
<span class="wt-step">{{ currentStep + 1 }} / {{ walkthroughSteps.length }}</span>
<el-button text size="small" @click="skipWalkthrough" style="color:#999;">跳过</el-button>
</div>
<div class="wt-body">
<div class="wt-icon">{{ walkthroughSteps[currentStep].icon }}</div>
<div class="wt-title">{{ walkthroughSteps[currentStep].title }}</div>
<div class="wt-desc">{{ walkthroughSteps[currentStep].desc }}</div>
<div class="wt-action" v-if="walkthroughSteps[currentStep].action">
<el-button type="primary" @click="goAction(walkthroughSteps[currentStep].action!)">前往{{ walkthroughSteps[currentStep].actionLabel }}</el-button>
</div>
</div>
<div class="wt-footer">
<div class="wt-dots">
<span v-for="(_, i) in walkthroughSteps" :key="i" class="wt-dot" :class="{ active: i === currentStep }"></span>
</div>
<div class="wt-btns">
<el-button v-if="currentStep > 0" @click="prevStep">上一步</el-button>
<el-button v-if="currentStep < walkthroughSteps.length - 1" type="primary" @click="nextStep">下一步</el-button>
<el-button v-else type="success" @click="finishWalkthrough">🎉 完成引导</el-button>
</div>
</div>
</div>
</div>
</teleport>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue"
import { useRouter } from "vue-router"
import { ElMessage } from "element-plus"
const router = useRouter()
// ── 流程步骤 ──
const steps = [
{ icon: "📊", title: "查看驾驶舱", desc: "总览企业KPI整体状况" },
{ icon: "🎯", title: "配置KPI", desc: "在KPI字典中设置关键指标" },
{ icon: "🗺️", title: "绘制战略地图", desc: "把你的战略目标画出来" },
{ icon: "⚡", title: "设定预警", desc: "配置红黄绿灯阈值" },
{ icon: "📋", title: "日常管理", desc: "通过工作台持续跟进" },
]
// ── 视频教程 ──
const videos = [
{ title: "如何设置KPI", desc: "KPI字典的创建、编辑和配置", duration: "3:20", url: "" },
{ title: "如何绘制战略地图", desc: "创建目标、关联KPI、画因果连线", duration: "4:15", url: "" },
{ title: "如何配置预警", desc: "设置红黄绿灯阈值和通知渠道", duration: "2:50", url: "" },
{ title: "如何进行差异分析", desc: "对比实际与预算,找出偏差原因", duration: "3:45", url: "" },
{ title: "如何使用战略回顾会", desc: "周会月会的复盘操作方法", duration: "3:00", url: "" },
{ title: "如何提交改善行动", desc: "从预警到行动计划的全流程", duration: "2:30", url: "" },
]
// ── 引导步骤 ──
const walkthroughSteps = [
{
icon: "👋",
title: "欢迎使用管理会计OS",
desc: "这是你的企业管理驾驶舱。我们将带你快速完成首次配置,让你在5分钟内上手。",
},
{
icon: "📊",
title: "Step 1: 先看驾驶舱",
desc: "驾驶舱是你了解企业整体状况的第一站。这里展示了所有KPI的红黄绿灯状态,以及你的个人KPI。",
action: "/dashboard",
actionLabel: "驾驶舱",
},
{
icon: "🎯",
title: "Step 2: 配置你的KPI",
desc: "在KPI字典中管理和配置你的关键绩效指标。你可以新建KPI、设置目标值和预警阈值。",
action: "/kpis",
actionLabel: "KPI字典",
},
{
icon: "🗺️",
title: "Step 3: 绘制战略地图",
desc: "使用BSC四维框架,把你的战略目标可视化。在画布上添加目标、关联KPI、画因果连线。",
action: "/maps",
actionLabel: "战略地图",
},
{
icon: "📋",
title: "Step 4: 开始日常管理",
desc: "通过「我的工作台」查看个人KPI和改善行动,通过「战略回顾会」进行周月复盘。",
action: "/my-dashboard",
actionLabel: "我的工作台",
},
]
const showWalkthrough = ref(false)
const currentStep = ref(0)
const FIRST_LOGIN_KEY = "cma_first_login_done"
// ── 方法 ──
function startOnboarding() {
currentStep.value = 0
showWalkthrough.value = true
}
function nextStep() {
if (currentStep.value < walkthroughSteps.length - 1) {
currentStep.value++
}
}
function prevStep() {
if (currentStep.value > 0) {
currentStep.value--
}
}
function skipWalkthrough() {
showWalkthrough.value = false
}
function finishWalkthrough() {
localStorage.setItem(FIRST_LOGIN_KEY, "true")
showWalkthrough.value = false
ElMessage.success("🎉 引导完成,开始你的管理会计之旅吧!")
}
function goAction(path: string) {
router.push(path)
showWalkthrough.value = false
}
function openVideo(v: any) {
if (v.url) {
window.open(v.url, "_blank")
} else {
ElMessage.info("视频教程正在制作中,敬请期待")
}
}
onMounted(() => {
// 检查是否首次登录
const done = localStorage.getItem(FIRST_LOGIN_KEY)
if (!done) {
// 延迟1秒后再弹出,让页面先加载完
setTimeout(() => {
showWalkthrough.value = true
}, 1000)
}
})
</script>
<style scoped>
.guide-page { padding: 20px; height: calc(100vh - 60px); overflow-y: auto; }
.guide-header { margin-bottom: 24px; }
.guide-header h3 { margin: 0; font-size: 20px; }
.guide-subtitle { color: #999; margin: 4px 0 0; font-size: 14px; }
.quick-start-card { display: flex; align-items: center; gap: 16px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: #fff; border-radius: 12px; padding: 20px; margin-bottom: 24px; cursor: pointer; }
.qs-icon { font-size: 40px; }
.qs-body { flex: 1; }
.qs-title { font-size: 18px; font-weight: 600; margin-bottom: 4px; }
.qs-desc { font-size: 13px; opacity: 0.8; margin-bottom: 6px; }
.qs-btn { flex-shrink: 0; }
.flow-section { margin-bottom: 24px; }
.flow-section h4 { margin: 0 0 16px; font-size: 16px; }
.flow-steps { display: flex; gap: 12px; }
.flow-step { flex: 1; text-align: center; padding: 16px; background: #fff; border-radius: 10px; box-shadow: 0 1px 4px rgba(0,0,0,0.06); }
.flow-num { width: 28px; height: 28px; border-radius: 50%; background: #409eff; color: #fff; display: flex; align-items: center; justify-content: center; margin: 0 auto 8px; font-size: 13px; font-weight: 600; }
.flow-icon { font-size: 28px; margin-bottom: 6px; }
.flow-title { font-size: 14px; font-weight: 600; margin-bottom: 4px; }
.flow-desc { font-size: 12px; color: #999; }
.video-section { margin-bottom: 24px; }
.video-section h4 { margin: 0 0 16px; font-size: 16px; }
.video-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.video-card { background: #fff; border-radius: 10px; overflow: hidden; box-shadow: 0 1px 4px rgba(0,0,0,0.06); cursor: pointer; transition: transform 0.2s; }
.video-card:hover { transform: translateY(-2px); }
.video-thumb { position: relative; background: #304156; height: 120px; display: flex; align-items: center; justify-content: center; }
.play-icon { font-size: 40px; color: #fff; opacity: 0.8; }
.video-duration { position: absolute; bottom: 6px; right: 8px; background: rgba(0,0,0,0.6); color: #fff; padding: 2px 6px; border-radius: 4px; font-size: 11px; }
.video-title { padding: 10px 12px 2px; font-size: 14px; font-weight: 500; }
.video-desc { padding: 0 12px 10px; font-size: 12px; color: #999; }
/* 引导遮罩 */
.walkthrough-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 9999; display: flex; align-items: center; justify-content: center; }
.walkthrough-box { background: #fff; border-radius: 16px; width: 480px; max-width: 90vw; box-shadow: 0 8px 32px rgba(0,0,0,0.2); overflow: hidden; }
.wt-header { display: flex; justify-content: space-between; align-items: center; padding: 12px 20px; border-bottom: 1px solid #f0f0f0; }
.wt-step { font-size: 12px; color: #999; }
.wt-body { padding: 32px 20px; text-align: center; }
.wt-icon { font-size: 56px; margin-bottom: 16px; }
.wt-title { font-size: 20px; font-weight: 600; margin-bottom: 12px; }
.wt-desc { font-size: 14px; color: #666; line-height: 1.6; margin-bottom: 20px; }
.wt-action { margin-top: 8px; }
.wt-footer { padding: 12px 20px; border-top: 1px solid #f0f0f0; display: flex; justify-content: space-between; align-items: center; }
.wt-dots { display: flex; gap: 6px; }
.wt-dot { width: 8px; height: 8px; border-radius: 50%; background: #ddd; transition: background 0.3s; }
.wt-dot.active { background: #409eff; }
.wt-btns { display: flex; gap: 8px; }
</style>