feat(frontend): 实现新手引导功能
- 添加 Guide 组件和引导步骤配置 - 实现 useOnboardingTour 和 useTourStepDescription composables - 添加 onboarding store 管理引导状态 - 更新多个视图和组件以支持引导功能 - 添加国际化支持(中英文) - 删除旧的实现指南文档
This commit is contained in:
@@ -38,7 +38,7 @@
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<button @click="showCreateModal = true" class="btn btn-primary">
|
||||
<button @click="showCreateModal = true" class="btn btn-primary" data-tour="accounts-create-btn">
|
||||
<svg
|
||||
class="mr-2 h-5 w-5"
|
||||
fill="none"
|
||||
@@ -373,7 +373,7 @@
|
||||
:proxies="proxies"
|
||||
:groups="groups"
|
||||
@close="showCreateModal = false"
|
||||
@created="loadAccounts"
|
||||
@created="() => { loadAccounts(); if (onboardingStore.isCurrentStep(`[data-tour='account-form-submit']`)) onboardingStore.nextStep(500) }"
|
||||
/>
|
||||
|
||||
<!-- Edit Account Modal -->
|
||||
@@ -495,6 +495,7 @@ import { ref, reactive, computed, onMounted, onUnmounted, type ComponentPublicIn
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useAppStore } from '@/stores/app'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useOnboardingStore } from '@/stores/onboarding'
|
||||
import { adminAPI } from '@/api/admin'
|
||||
import type { Account, Proxy, Group } from '@/types'
|
||||
import type { Column } from '@/components/common/types'
|
||||
@@ -524,6 +525,7 @@ import { formatRelativeTime } from '@/utils/format'
|
||||
const { t } = useI18n()
|
||||
const appStore = useAppStore()
|
||||
const authStore = useAuthStore()
|
||||
const onboardingStore = useOnboardingStore()
|
||||
|
||||
// Table columns
|
||||
const columns = computed<Column[]>(() => {
|
||||
|
||||
@@ -23,7 +23,11 @@
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<button @click="showCreateModal = true" class="btn btn-primary">
|
||||
<button
|
||||
@click="showCreateModal = true"
|
||||
class="btn btn-primary"
|
||||
data-tour="groups-create-btn"
|
||||
>
|
||||
<svg
|
||||
class="mr-2 h-5 w-5"
|
||||
fill="none"
|
||||
@@ -244,6 +248,7 @@
|
||||
required
|
||||
class="input"
|
||||
:placeholder="t('admin.groups.enterGroupName')"
|
||||
data-tour="group-form-name"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
@@ -257,7 +262,11 @@
|
||||
</div>
|
||||
<div>
|
||||
<label class="input-label">{{ t('admin.groups.form.platform') }}</label>
|
||||
<Select v-model="createForm.platform" :options="platformOptions" />
|
||||
<Select
|
||||
v-model="createForm.platform"
|
||||
:options="platformOptions"
|
||||
data-tour="group-form-platform"
|
||||
/>
|
||||
<p class="input-hint">{{ t('admin.groups.platformHint') }}</p>
|
||||
</div>
|
||||
<div v-if="createForm.subscription_type !== 'subscription'">
|
||||
@@ -269,10 +278,11 @@
|
||||
min="0.001"
|
||||
required
|
||||
class="input"
|
||||
data-tour="group-form-multiplier"
|
||||
/>
|
||||
<p class="input-hint">{{ t('admin.groups.rateMultiplierHint') }}</p>
|
||||
</div>
|
||||
<div v-if="createForm.subscription_type !== 'subscription'">
|
||||
<div v-if="createForm.subscription_type !== 'subscription'" data-tour="group-form-exclusive">
|
||||
<div class="mb-1.5 flex items-center gap-1">
|
||||
<label class="text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ t('admin.groups.form.exclusive') }}
|
||||
@@ -390,6 +400,7 @@
|
||||
form="create-group-form"
|
||||
:disabled="submitting"
|
||||
class="btn btn-primary"
|
||||
data-tour="group-form-submit"
|
||||
>
|
||||
<svg
|
||||
v-if="submitting"
|
||||
@@ -432,7 +443,13 @@
|
||||
>
|
||||
<div>
|
||||
<label class="input-label">{{ t('admin.groups.form.name') }}</label>
|
||||
<input v-model="editForm.name" type="text" required class="input" />
|
||||
<input
|
||||
v-model="editForm.name"
|
||||
type="text"
|
||||
required
|
||||
class="input"
|
||||
data-tour="edit-group-form-name"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="input-label">{{ t('admin.groups.form.description') }}</label>
|
||||
@@ -440,7 +457,12 @@
|
||||
</div>
|
||||
<div>
|
||||
<label class="input-label">{{ t('admin.groups.form.platform') }}</label>
|
||||
<Select v-model="editForm.platform" :options="platformOptions" :disabled="true" />
|
||||
<Select
|
||||
v-model="editForm.platform"
|
||||
:options="platformOptions"
|
||||
:disabled="true"
|
||||
data-tour="group-form-platform"
|
||||
/>
|
||||
<p class="input-hint">{{ t('admin.groups.platformNotEditable') }}</p>
|
||||
</div>
|
||||
<div v-if="editForm.subscription_type !== 'subscription'">
|
||||
@@ -452,6 +474,7 @@
|
||||
min="0.001"
|
||||
required
|
||||
class="input"
|
||||
data-tour="group-form-multiplier"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="editForm.subscription_type !== 'subscription'">
|
||||
@@ -580,6 +603,7 @@
|
||||
form="edit-group-form"
|
||||
:disabled="submitting"
|
||||
class="btn btn-primary"
|
||||
data-tour="group-form-submit"
|
||||
>
|
||||
<svg
|
||||
v-if="submitting"
|
||||
@@ -625,6 +649,7 @@
|
||||
import { ref, reactive, computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useAppStore } from '@/stores/app'
|
||||
import { useOnboardingStore } from '@/stores/onboarding'
|
||||
import { adminAPI } from '@/api/admin'
|
||||
import type { Group, GroupPlatform, SubscriptionType } from '@/types'
|
||||
import type { Column } from '@/components/common/types'
|
||||
@@ -640,6 +665,7 @@ import PlatformIcon from '@/components/common/PlatformIcon.vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const appStore = useAppStore()
|
||||
const onboardingStore = useOnboardingStore()
|
||||
|
||||
const columns = computed<Column[]>(() => [
|
||||
{ key: 'name', label: t('admin.groups.columns.name'), sortable: true },
|
||||
@@ -809,9 +835,14 @@ const handleCreateGroup = async () => {
|
||||
appStore.showSuccess(t('admin.groups.groupCreated'))
|
||||
closeCreateModal()
|
||||
loadGroups()
|
||||
// Only advance tour if active, on submit step, and creation succeeded
|
||||
if (onboardingStore.isCurrentStep('[data-tour="group-form-submit"]')) {
|
||||
onboardingStore.nextStep(500)
|
||||
}
|
||||
} catch (error: any) {
|
||||
appStore.showError(error.response?.data?.detail || t('admin.groups.failedToCreate'))
|
||||
console.error('Error creating group:', error)
|
||||
// Don't advance tour on error
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user