Files
BYW-VoiceHub/app/components/Admin/AdminOnboardingTutorial.vue
T
Henry_Du 573e168702 feat(admin-ui): 管理后台整体切换为浅色主题(ModernLight) + 新增 lightbulb 图标
1. layout(管理控制台 dashboard.vue): main bg-[#09090b] text-zinc-100 → bg-[#f8fafc] text-zinc-900; header bg-zinc-950/60 border-zinc-800 → bg-white/80 border-zinc-200; 移动菜单按钮/新手引导按钮 text-zinc-300/400 hover:bg-zinc-800 → text-zinc-600 hover:bg-zinc-100 border-zinc-200

2. Admin/Sidebar.vue: bg-[#09090b] border-zinc-800 → bg-white border-zinc-200 + shadow-sm; 标题 text-zinc-100 → 900; activeTab bg-blue-600/10 text-blue-400 → bg-blue-50 text-blue-700 border-blue-200; 未选中 text-zinc-500 hover:text-zinc-200 hover:bg-zinc-800/40 → text-zinc-600 hover:text-zinc-900 hover:bg-zinc-100; 用户卡 avatar/首字母 bg-white/70 border-zinc-200 + 退出按钮 hover:bg-red-50 text-red-600

3. 批量 33 个 Admin 组件硬编码深色原子类 1414 处替换(bg-zinc-9xx / border-zinc-8xx / text-zinc-100,200,300 / shadow-black/ -> 对应 light 版本) + style 块原生 CSS rgba(255,255,255,x) 16 处改为 rgba(0,0,0,x) / var 浅色主题 + 硬编码 bg-[#0c0c0e] / border-white/10 / color:white / surface-primary fallback 对应浅色修正

4. 二轮批量追加: bg-zinc-950 + opacity 变体(80/60/50/40/30/20/10) 共 431 处 → bg-white 对应 opacity 版本;placeholder:text-zinc-800 → 500;text-blue/red/emerald/amber/rose/purple 400 版 → 700/600 深浅一致版;border color /500 /30 → 200;focus:ring /20 → /30;shadow color 阴影降低强度

5. hover:text-white 扫尾: 13 处 DataAnalysisPanel/DatabaseManager/NotificationSender/SemesterManager/SongManagement/UserSongsModal hover 文本从 white → zinc-900;按钮三态从 hover:bg-*600 白字 → hover:bg-*-100/200 对应深字色,和前台 indigo/浅色体系保持一致

6. BlacklistManager 前台可见提示 💡→ <Icon lightbulb amber-600 size=13>;ChangelogManager 徽章色从 emerald-300/blue-300/zinc-400 → emerald-700/blue-700/zinc-600 可读;Icon.vue 新增 lightbulb 分支 stroke 图标

7. 受影响文件: dashboard.vue + Sidebar.vue + Icon.vue + Admin/* (33个组件共 1874 处批量替换 + 20 处手工精细化修正)
2026-09-19 08:30:59 +08:00

145 lines
4.5 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>
<Teleport to="body">
<div
v-if="visible"
class="fixed inset-0 z-[70] bg-black/70 backdrop-blur-sm px-4 py-6 flex items-end sm:items-center justify-center"
>
<div
class="w-full max-w-xl rounded-2xl border border-zinc-200 bg-white shadow-2xl overflow-hidden"
>
<div class="px-5 py-4 border-b border-zinc-200 flex items-center justify-between gap-3">
<div>
<p class="text-[10px] uppercase tracking-[0.2em] text-zinc-500 font-black">后台引导</p>
<h3 class="text-lg font-black text-zinc-900 mt-1">{{ currentStep.title }}</h3>
</div>
<button
class="h-9 w-9 rounded-lg border border-zinc-200 text-zinc-400 hover:text-zinc-700 hover:bg-white transition-colors"
@click="handleClose"
>
<X :size="16" class="mx-auto" />
</button>
</div>
<div class="px-5 py-5 space-y-4">
<p class="text-sm leading-relaxed text-zinc-600">{{ currentStep.description }}</p>
<div class="rounded-xl border border-blue-200 bg-blue-500/5 p-3">
<p class="text-xs text-zinc-400">
建议操作:
<span class="text-zinc-700 font-semibold">{{ currentStep.actionHint }}</span>
</p>
</div>
</div>
<div
class="px-5 py-4 border-t border-zinc-200 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3"
>
<p class="text-xs text-zinc-500 font-semibold">{{ stepIndex + 1 }} / {{ steps.length }}</p>
<div class="flex items-center gap-2">
<button
v-if="stepIndex > 0"
class="px-3.5 py-2 rounded-lg border border-zinc-200 text-zinc-600 hover:bg-white text-sm"
@click="prevStep"
>
上一步
</button>
<button
class="px-3.5 py-2 rounded-lg border border-zinc-200 text-zinc-700 hover:bg-white text-sm"
@click="goCurrentStep"
>
前往此功能
</button>
<button
class="px-4 py-2 rounded-lg bg-blue-600 hover:bg-blue-500 text-white text-sm font-bold"
@click="nextStep"
>
{{ stepIndex === steps.length - 1 ? '完成引导' : '下一步' }}
</button>
</div>
</div>
</div>
</div>
</Teleport>
</template>
<script setup>
import { computed, ref, watch } from 'vue'
import { X } from '@lucide/vue'
const props = defineProps({
visible: {
type: Boolean,
default: false
}
})
const emit = defineEmits(['navigate', 'close', 'complete'])
const steps = [
{
tab: 'overview',
title: '先看数据概览',
description: '这里会显示待处理歌曲、播放数据和系统运行状态,建议每次值班先看这一页。',
actionHint: '进入“数据概览”快速确认今日状态。'
},
{
tab: 'songs',
title: '处理歌曲审核',
description: '在歌曲管理中可试听、拒绝或保留歌曲,确保内容合规后再进入排期流程。',
actionHint: '优先处理新提交和被举报的歌曲。'
},
{
tab: 'schedule',
title: '安排节目排期',
description: '将审核通过的歌曲拖拽到目标日期与时段,调整顺序后发布,用户即可看到最新排期。',
actionHint: '排期完成后记得点击发布,避免用户看到旧数据。'
},
{
tab: 'site-config',
title: '维护站点配置',
description: '可统一修改站点标题、版本号和投稿规则,保存后会对前台页面立即生效。',
actionHint: '发布新版本时,建议同步更新“站点版本号”。'
},
{
tab: 'workflow-tutorial',
title: '查看完整流程教程',
description: '如果需要标准值班流程和FAQ,可在“流程与教程”页面查看详细图文说明。',
actionHint: '把该页面作为新人培训材料。'
}
]
const stepIndex = ref(0)
const currentStep = computed(() => steps[stepIndex.value])
watch(
() => props.visible,
(visible) => {
if (visible) {
stepIndex.value = 0
}
}
)
const goCurrentStep = () => {
emit('navigate', currentStep.value.tab)
}
const prevStep = () => {
if (stepIndex.value > 0) {
stepIndex.value -= 1
}
}
const nextStep = () => {
goCurrentStep()
if (stepIndex.value < steps.length - 1) {
stepIndex.value += 1
return
}
emit('complete')
}
const handleClose = () => {
emit('close')
}
</script>