83 lines
3.1 KiB
Vue
83 lines
3.1 KiB
Vue
<script setup lang="ts">
|
||
/** 当前页面操作提示条:对齐旧版 admin-interactions.js 的 adminOperationGuide(14 页有独立文案,余用通用 fallback)。
|
||
* 挂在 AdminLayout 内容区顶部,随 route.meta.menuKey 切换文案;折叠态存 localStorage。 */
|
||
import { computed, ref, watch } from 'vue'
|
||
import { useRoute } from 'vue-router'
|
||
import { OPERATION_GUIDE_STORAGE_KEY, operationGuideFor } from '@/layout/operation-guides'
|
||
|
||
const route = useRoute()
|
||
const guide = computed(() => operationGuideFor(route.meta.menuKey))
|
||
|
||
function readCollapsed(): boolean {
|
||
try {
|
||
return localStorage.getItem(OPERATION_GUIDE_STORAGE_KEY) === '1'
|
||
} catch {
|
||
return false
|
||
}
|
||
}
|
||
function persistCollapsed(value: boolean) {
|
||
try {
|
||
localStorage.setItem(OPERATION_GUIDE_STORAGE_KEY, value ? '1' : '0')
|
||
} catch {
|
||
// 忽略隐私模式写入失败
|
||
}
|
||
}
|
||
const collapsed = ref(readCollapsed())
|
||
function toggle() {
|
||
collapsed.value = !collapsed.value
|
||
persistCollapsed(collapsed.value)
|
||
}
|
||
watch(collapsed, (v) => persistCollapsed(v))
|
||
</script>
|
||
|
||
<template>
|
||
<aside v-if="guide" class="operation-guide" :class="{ 'is-collapsed': collapsed }" aria-label="当前页面操作提示">
|
||
<div class="og-head">
|
||
<span class="og-title">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"></circle><path d="M12 11v5"></path><path d="M12 8h.01"></path></svg>
|
||
当前页面操作提示
|
||
</span>
|
||
<button type="button" class="og-toggle" :aria-expanded="!collapsed" @click="toggle">
|
||
{{ collapsed ? '展开提示' : '收起提示' }}
|
||
</button>
|
||
</div>
|
||
<div v-show="!collapsed" class="og-body">
|
||
<p class="og-text">{{ guide.text }}</p>
|
||
<ol v-if="guide.steps.length" class="og-steps">
|
||
<li v-for="step in guide.steps" :key="step">{{ step }}</li>
|
||
</ol>
|
||
</div>
|
||
</aside>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.operation-guide {
|
||
display: flex; flex-direction: column;
|
||
margin: 0 0 18px; padding: 12px 16px;
|
||
border: 1px solid #cddbe6; border-radius: 12px;
|
||
background: linear-gradient(180deg, #fbfdfe, #f4f8fc);
|
||
box-shadow: 0 10px 26px -24px rgba(39, 67, 94, 0.3);
|
||
color: var(--admin-text);
|
||
}
|
||
.operation-guide.is-collapsed { padding: 8px 16px; }
|
||
.og-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
||
.og-title {
|
||
display: inline-flex; align-items: center; gap: 7px;
|
||
font-size: 13px; font-weight: 650; color: var(--admin-primary-strong);
|
||
}
|
||
.og-title svg { width: 15px; height: 15px; }
|
||
.og-toggle {
|
||
padding: 0; border: 0; background: none; cursor: pointer;
|
||
font: inherit; font-size: 12px; color: #6b8096;
|
||
}
|
||
.og-toggle:hover { color: var(--admin-primary-strong); }
|
||
.og-body { margin-top: 8px; padding-left: 22px; }
|
||
.og-text { margin: 0; color: #40586e; font-size: 13px; line-height: 1.7; }
|
||
.og-steps { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 0; padding: 0; list-style: none; }
|
||
.og-steps li {
|
||
padding: 2px 10px; border-radius: 999px;
|
||
background: #e9f1f8; border: 1px solid #d3e0ea;
|
||
color: #2f4a63; font-size: 12px; line-height: 1.7;
|
||
}
|
||
</style>
|