feat(frontend): 实现新手引导功能

- 添加 Guide 组件和引导步骤配置
- 实现 useOnboardingTour 和 useTourStepDescription composables
- 添加 onboarding store 管理引导状态
- 更新多个视图和组件以支持引导功能
- 添加国际化支持(中英文)
- 删除旧的实现指南文档
This commit is contained in:
IanShaw027
2025-12-29 15:21:05 +08:00
parent c01db6b180
commit dd247e55e9
30 changed files with 3968 additions and 36 deletions

View File

@@ -6,6 +6,7 @@
export { useAuthStore } from './auth'
export { useAppStore } from './app'
export { useSubscriptionStore } from './subscriptions'
export { useOnboardingStore } from './onboarding'
// Re-export types for convenience
export type { User, LoginRequest, RegisterRequest, AuthResponse } from '@/types'

View File

@@ -0,0 +1,88 @@
/**
* Onboarding Store
* Manages onboarding tour state and control methods
*/
import { defineStore } from 'pinia'
import { markRaw, ref, shallowRef } from 'vue'
import type { Driver } from 'driver.js'
type VoidCallback = () => void
type NextStepCallback = (delay?: number) => Promise<void>
type IsCurrentStepCallback = (selector: string) => boolean
export const useOnboardingStore = defineStore('onboarding', () => {
const replayCallback = ref<VoidCallback | null>(null)
const nextStepCallback = ref<NextStepCallback | null>(null)
const isCurrentStepCallback = ref<IsCurrentStepCallback | null>(null)
// 全局 driver 实例,跨组件保持
const driverInstance = shallowRef<Driver | null>(null)
function setReplayCallback(callback: VoidCallback | null): void {
replayCallback.value = callback
}
function setControlMethods(methods: {
nextStep: NextStepCallback,
isCurrentStep: IsCurrentStepCallback
}): void {
nextStepCallback.value = methods.nextStep
isCurrentStepCallback.value = methods.isCurrentStep
}
function clearControlMethods(): void {
nextStepCallback.value = null
isCurrentStepCallback.value = null
}
function setDriverInstance(driver: Driver | null): void {
driverInstance.value = driver ? markRaw(driver) : null
}
function getDriverInstance(): Driver | null {
return driverInstance.value
}
function isDriverActive(): boolean {
return driverInstance.value?.isActive?.() ?? false
}
function replay(): void {
if (replayCallback.value) {
replayCallback.value()
}
}
/**
* Manually advance to the next step
* @param delay Optional delay in ms (useful for waiting for animations)
*/
async function nextStep(delay = 0): Promise<void> {
if (nextStepCallback.value) {
await nextStepCallback.value(delay)
}
}
/**
* Check if the tour is currently highlighting a specific element
*/
function isCurrentStep(selector: string): boolean {
if (isCurrentStepCallback.value) {
return isCurrentStepCallback.value(selector)
}
return false
}
return {
setReplayCallback,
setControlMethods,
clearControlMethods,
setDriverInstance,
getDriverInstance,
isDriverActive,
replay,
nextStep,
isCurrentStep
}
})