162 lines
5.8 KiB
Vue
162 lines
5.8 KiB
Vue
<template>
|
||
<el-dialog v-model="visible" title="" :width="560" :show-close="true" :close-on-click-modal="false" class="cma-welcome-dialog">
|
||
<div class="welcome-body">
|
||
<div class="welcome-header">
|
||
<div class="welcome-icon">👋</div>
|
||
<h2>欢迎使用管理会计OS</h2>
|
||
<p class="welcome-sub">三步开启从战略到执行的管理闭环</p>
|
||
</div>
|
||
|
||
<div class="steps-wrap">
|
||
<div class="step-item" :class="{ active: currentStep === 0, done: currentStep > 0 }">
|
||
<div class="step-num">
|
||
<span v-if="currentStep > 0">✅</span>
|
||
<span v-else>1</span>
|
||
</div>
|
||
<div class="step-content">
|
||
<h4>① 绘制战略地图</h4>
|
||
<p>在战略画布上定义财务、客户、内部流程、学习成长四个维度的战略主题和因果关系链,让战略"可视化"。</p>
|
||
<div class="step-preview">🗺️ 战略地图 → KPI目标对齐 → 预算配置</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="step-connector" :class="{ active: currentStep >= 1 }">↓</div>
|
||
|
||
<div class="step-item" :class="{ active: currentStep === 1, done: currentStep > 1 }">
|
||
<div class="step-num">
|
||
<span v-if="currentStep > 1">✅</span>
|
||
<span v-else>2</span>
|
||
</div>
|
||
<div class="step-content">
|
||
<h4>② 对齐KPI目标</h4>
|
||
<p>将战略地图上的战略主题分解为可衡量的KPI,支持纵向分解(公司→部门)、横向支撑(因果传导)和BSC瀑布链三种对齐模式。</p>
|
||
<div class="step-preview">🎯 KPI目标对齐 → 资源按目标分配</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="step-connector" :class="{ active: currentStep >= 2 }">↓</div>
|
||
|
||
<div class="step-item" :class="{ active: currentStep === 2, done: currentStep > 2 }">
|
||
<div class="step-num">
|
||
<span v-if="currentStep > 2">✅</span>
|
||
<span v-else>3</span>
|
||
</div>
|
||
<div class="step-content">
|
||
<h4>③ 编制全面预算</h4>
|
||
<p>按对齐后的目标分配资源,编制收入/成本/费用/投资预算。从此预算不再是财务部闭门造,而是从战略自上而下对齐出来的。</p>
|
||
<div class="step-preview">💰 预算管理 → 驾驶舱监控执行 → 差异分析 → 改善行动</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 完整闭环说明 -->
|
||
<div class="pdca-hint" v-if="currentStep >= 2">
|
||
<div class="hint-title">三步走完后,系统进入持续管理闭环</div>
|
||
<div class="hint-flow">
|
||
<span>🎯 P 战略规划</span>
|
||
<span>→</span>
|
||
<span>📊 D 执行监控</span>
|
||
<span>→</span>
|
||
<span>🔍 C 复盘评估</span>
|
||
<span>→</span>
|
||
<span>🔄 A 优化调整</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="welcome-footer">
|
||
<el-button v-if="currentStep < 2" type="primary" size="large" @click="currentStep++">继续了解 →</el-button>
|
||
<el-button v-else type="primary" size="large" @click="startUsing">开始使用 →</el-button>
|
||
<el-button text @click="skip">跳过引导</el-button>
|
||
</div>
|
||
</div>
|
||
</el-dialog>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, onMounted } from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
|
||
const router = useRouter()
|
||
const visible = ref(false)
|
||
const currentStep = ref(0)
|
||
|
||
const GUIDE_SHOWN_KEY = 'cma_guide_shown'
|
||
|
||
function show() {
|
||
visible.value = true
|
||
currentStep.value = 0
|
||
}
|
||
|
||
function skip() {
|
||
visible.value = false
|
||
localStorage.setItem(GUIDE_SHOWN_KEY, '1')
|
||
}
|
||
|
||
function startUsing() {
|
||
visible.value = false
|
||
localStorage.setItem(GUIDE_SHOWN_KEY, '1')
|
||
router.push('/maps')
|
||
}
|
||
|
||
// 暴露show方法供父组件调用
|
||
defineExpose({ show })
|
||
|
||
onMounted(() => {
|
||
// 自动检测是否显示过引导
|
||
const shown = localStorage.getItem(GUIDE_SHOWN_KEY)
|
||
if (!shown) {
|
||
// 延迟弹窗让页面先渲染
|
||
setTimeout(() => { visible.value = true }, 500)
|
||
}
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.welcome-body { text-align: center; }
|
||
.welcome-header { margin-bottom: 24px; }
|
||
.welcome-icon { font-size: 48px; margin-bottom: 8px; }
|
||
.welcome-header h2 { margin: 0 0 6px; font-size: 22px; }
|
||
.welcome-sub { color: #666; font-size: 14px; margin: 0; }
|
||
|
||
.steps-wrap { text-align: left; margin-bottom: 20px; }
|
||
.step-item {
|
||
display: flex; gap: 14px; padding: 14px 16px;
|
||
border: 1px solid #eee; border-radius: 10px;
|
||
margin-bottom: 4px; transition: all 0.3s;
|
||
}
|
||
.step-item.active { border-color: #409eff; background: #f0f7ff; }
|
||
.step-item.done { border-color: #b7eb8f; background: #f6ffed; }
|
||
.step-num {
|
||
flex-shrink: 0; width: 32px; height: 32px;
|
||
display: flex; align-items: center; justify-content: center;
|
||
border-radius: 50%; font-weight: 700; font-size: 14px;
|
||
background: #eee; color: #999;
|
||
}
|
||
.step-item.active .step-num { background: #409eff; color: #fff; }
|
||
.step-item.done .step-num { background: transparent; }
|
||
.step-content { flex: 1; }
|
||
.step-content h4 { margin: 0 0 4px; font-size: 15px; }
|
||
.step-content p { margin: 0 0 6px; font-size: 13px; color: #666; line-height: 1.5; }
|
||
.step-preview {
|
||
font-size: 12px; color: #909399;
|
||
background: #f5f7fa; padding: 4px 8px; border-radius: 4px;
|
||
display: inline-block;
|
||
}
|
||
|
||
.step-connector { text-align: center; color: #ddd; font-size: 18px; padding: 2px 0; }
|
||
.step-connector.active { color: #409eff; }
|
||
|
||
.pdca-hint {
|
||
background: #f0f7ff; border: 1px solid #d9ecff; border-radius: 10px;
|
||
padding: 14px; margin-bottom: 20px;
|
||
}
|
||
.hint-title { font-size: 14px; font-weight: 600; margin-bottom: 8px; }
|
||
.hint-flow {
|
||
display: flex; align-items: center; justify-content: center;
|
||
gap: 8px; font-size: 13px; flex-wrap: wrap;
|
||
}
|
||
.hint-flow span { white-space: nowrap; }
|
||
|
||
.welcome-footer { display: flex; align-items: center; justify-content: center; gap: 12px; }
|
||
</style>
|