mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-06-14 04:01:12 +08:00
更新配置向导
This commit is contained in:
@@ -2892,31 +2892,21 @@ export default {
|
||||
completed: 'Setup Wizard completed!',
|
||||
failed: 'Setup Wizard failed, please try again',
|
||||
complete: 'Complete Configuration',
|
||||
step1: {
|
||||
title: 'Basic',
|
||||
description: 'Set access domain, background wallpaper and recognition data source',
|
||||
},
|
||||
step2: {
|
||||
title: 'Storage Directory',
|
||||
description: 'Configure download directory and media library directory',
|
||||
},
|
||||
step3: {
|
||||
title: 'Downloader',
|
||||
description: 'Configure downloader (optional)',
|
||||
},
|
||||
step4: {
|
||||
title: 'Media Server',
|
||||
description: 'Configure media server (optional)',
|
||||
},
|
||||
step5: {
|
||||
title: 'Notification',
|
||||
description: 'Configure notification channels (optional)',
|
||||
},
|
||||
step6: {
|
||||
title: 'Resource Preferences',
|
||||
description: 'Set resource download preferences',
|
||||
},
|
||||
testing: 'Testing',
|
||||
connectivityTestSuccess: 'Connectivity test passed',
|
||||
connectivityTestFailed: 'Connectivity test failed',
|
||||
testingStorage: 'Testing storage',
|
||||
checkingStorage: 'Checking storage connectivity',
|
||||
testingDownloader: 'Testing downloader',
|
||||
checkingDownloader: 'Checking downloader connectivity',
|
||||
testingMediaServer: 'Testing media server',
|
||||
checkingMediaServer: 'Checking media server connectivity',
|
||||
testingNotification: 'Testing notification',
|
||||
checkingNotification: 'Checking notification connectivity',
|
||||
testFailedHint: 'Please check if the configuration is correct, you can retest after modification',
|
||||
basic: {
|
||||
title: 'Basic Settings',
|
||||
description: 'Set access domain, username/password and network configuration',
|
||||
appDomain: 'App Domain',
|
||||
appDomainHint: 'Used to add quick jump links when sending notifications',
|
||||
wallpaper: 'Background Wallpaper',
|
||||
@@ -2927,6 +2917,8 @@ export default {
|
||||
apiTokenHint: 'System automatically generated API access token',
|
||||
},
|
||||
storage: {
|
||||
title: 'Storage Configuration',
|
||||
description: 'Configure download directory and media library directory',
|
||||
info: 'Storage Configuration',
|
||||
infoDesc: 'Configure local storage directories for download and media library management',
|
||||
downloadPath: 'Download Directory',
|
||||
@@ -2935,6 +2927,8 @@ export default {
|
||||
libraryPathHint: 'Set the storage path for media files',
|
||||
},
|
||||
downloader: {
|
||||
title: 'Downloader Configuration',
|
||||
description: 'Configure downloader (optional)',
|
||||
info: 'Downloader Configuration',
|
||||
infoDesc: 'Configure downloader for automatic resource download (optional)',
|
||||
type: 'Downloader Type',
|
||||
@@ -2949,6 +2943,8 @@ export default {
|
||||
downloadPath: 'Download Path',
|
||||
},
|
||||
mediaServer: {
|
||||
title: 'Media Server',
|
||||
description: 'Configure media server (optional)',
|
||||
info: 'Media Server Configuration',
|
||||
infoDesc: 'Configure media server for media library management (optional)',
|
||||
type: 'Media Server Type',
|
||||
@@ -2963,6 +2959,8 @@ export default {
|
||||
token: 'Access Token',
|
||||
},
|
||||
notification: {
|
||||
title: 'Notification Settings',
|
||||
description: 'Configure notification channels (optional)',
|
||||
info: 'Notification Configuration',
|
||||
infoDesc: 'Configure notification channels for receiving system messages (optional)',
|
||||
type: 'Notification Type',
|
||||
@@ -2980,6 +2978,8 @@ export default {
|
||||
receiverEmail: 'Receiver Email',
|
||||
},
|
||||
preferences: {
|
||||
title: 'Resource Preferences',
|
||||
description: 'Set resource download preferences',
|
||||
info: 'Resource Preferences',
|
||||
infoDesc:
|
||||
'Set resource download preferences, the system will automatically select the best resources based on these preferences',
|
||||
|
||||
@@ -2859,31 +2859,21 @@ export default {
|
||||
completed: '配置向导完成!',
|
||||
failed: '配置向导失败,请重试',
|
||||
complete: '完成配置',
|
||||
step1: {
|
||||
title: '基础',
|
||||
description: '设置访问域名、背景壁纸和识别数据源',
|
||||
},
|
||||
step2: {
|
||||
title: '存储目录',
|
||||
description: '配置下载目录和媒体库目录',
|
||||
},
|
||||
step3: {
|
||||
title: '下载器',
|
||||
description: '配置下载器(可选)',
|
||||
},
|
||||
step4: {
|
||||
title: '媒体服务器',
|
||||
description: '配置媒体服务器(可选)',
|
||||
},
|
||||
step5: {
|
||||
title: '通知',
|
||||
description: '配置通知渠道(可选)',
|
||||
},
|
||||
step6: {
|
||||
title: '资源偏好',
|
||||
description: '设置资源下载偏好',
|
||||
},
|
||||
testing: '正在测试',
|
||||
connectivityTestSuccess: '连通性测试通过',
|
||||
connectivityTestFailed: '连通性测试失败',
|
||||
testingStorage: '正在测试存储目录',
|
||||
checkingStorage: '检查存储目录连通性',
|
||||
testingDownloader: '正在测试下载器',
|
||||
checkingDownloader: '检查下载器连通性',
|
||||
testingMediaServer: '正在测试媒体服务器',
|
||||
checkingMediaServer: '检查媒体服务器连通性',
|
||||
testingNotification: '正在测试消息通知',
|
||||
checkingNotification: '检查消息通知连通性',
|
||||
testFailedHint: '请检查配置是否正确,修改后可以重新测试',
|
||||
basic: {
|
||||
title: '基础设置',
|
||||
description: '设置访问域名、用户名密码和网络配置',
|
||||
appDomain: '访问域名',
|
||||
appDomainHint: '用于发送通知时,添加快捷跳转地址',
|
||||
wallpaper: '背景壁纸',
|
||||
@@ -2894,6 +2884,8 @@ export default {
|
||||
apiTokenHint: '系统自动生成的 API 访问令牌',
|
||||
},
|
||||
storage: {
|
||||
title: '存储配置',
|
||||
description: '配置下载目录和媒体库目录',
|
||||
info: '存储配置说明',
|
||||
infoDesc: '配置本地存储目录,用于下载和媒体库管理',
|
||||
downloadPath: '下载目录',
|
||||
@@ -2902,6 +2894,8 @@ export default {
|
||||
libraryPathHint: '设置媒体文件的存储路径',
|
||||
},
|
||||
downloader: {
|
||||
title: '下载器配置',
|
||||
description: '配置下载器(可选)',
|
||||
info: '下载器配置说明',
|
||||
infoDesc: '配置下载器用于自动下载资源(可选)',
|
||||
type: '下载器类型',
|
||||
@@ -2916,6 +2910,8 @@ export default {
|
||||
downloadPath: '下载路径',
|
||||
},
|
||||
mediaServer: {
|
||||
title: '媒体服务器',
|
||||
description: '配置媒体服务器(可选)',
|
||||
info: '媒体服务器配置说明',
|
||||
infoDesc: '配置媒体服务器用于媒体库管理(可选)',
|
||||
type: '媒体服务器类型',
|
||||
@@ -2930,6 +2926,8 @@ export default {
|
||||
token: '访问令牌',
|
||||
},
|
||||
notification: {
|
||||
title: '通知设置',
|
||||
description: '配置通知渠道(可选)',
|
||||
info: '通知配置说明',
|
||||
infoDesc: '配置通知渠道用于接收系统消息(可选)',
|
||||
type: '通知类型',
|
||||
@@ -2947,6 +2945,8 @@ export default {
|
||||
receiverEmail: '接收邮箱',
|
||||
},
|
||||
preferences: {
|
||||
title: '资源偏好',
|
||||
description: '设置资源下载偏好',
|
||||
info: '资源偏好说明',
|
||||
infoDesc: '设置资源下载的偏好,系统将根据这些偏好自动选择最佳资源',
|
||||
quality: '质量偏好',
|
||||
|
||||
@@ -2858,31 +2858,21 @@ export default {
|
||||
completed: '設定精靈完成!',
|
||||
failed: '設定精靈失敗,請重試',
|
||||
complete: '完成設定',
|
||||
step1: {
|
||||
title: '基礎',
|
||||
description: '設定存取網域、背景桌布和識別資料來源',
|
||||
},
|
||||
step2: {
|
||||
title: '儲存目錄',
|
||||
description: '設定下載目錄和媒體庫目錄',
|
||||
},
|
||||
step3: {
|
||||
title: '下載器',
|
||||
description: '設定下載器(可選)',
|
||||
},
|
||||
step4: {
|
||||
title: '媒體伺服器',
|
||||
description: '設定媒體伺服器(可選)',
|
||||
},
|
||||
step5: {
|
||||
title: '通知',
|
||||
description: '設定通知管道(可選)',
|
||||
},
|
||||
step6: {
|
||||
title: '資源偏好',
|
||||
description: '設定資源下載偏好',
|
||||
},
|
||||
testing: '正在測試',
|
||||
connectivityTestSuccess: '連通性測試通過',
|
||||
connectivityTestFailed: '連通性測試失敗',
|
||||
testingStorage: '正在測試存儲目錄',
|
||||
checkingStorage: '檢查存儲目錄連通性',
|
||||
testingDownloader: '正在測試下載器',
|
||||
checkingDownloader: '檢查下載器連通性',
|
||||
testingMediaServer: '正在測試媒體服務器',
|
||||
checkingMediaServer: '檢查媒體服務器連通性',
|
||||
testingNotification: '正在測試消息通知',
|
||||
checkingNotification: '檢查消息通知連通性',
|
||||
testFailedHint: '請檢查配置是否正確,修改後可以重新測試',
|
||||
basic: {
|
||||
title: '基礎設定',
|
||||
description: '設定存取網域、用戶名密碼和網路配置',
|
||||
appDomain: '存取網域',
|
||||
appDomainHint: '用於發送通知時,新增快速跳轉位址',
|
||||
wallpaper: '背景桌布',
|
||||
@@ -2893,6 +2883,8 @@ export default {
|
||||
apiTokenHint: '系統自動產生的 API 存取權杖',
|
||||
},
|
||||
storage: {
|
||||
title: '儲存配置',
|
||||
description: '設定下載目錄和媒體庫目錄',
|
||||
info: '儲存設定說明',
|
||||
infoDesc: '設定本機儲存目錄,用於下載和媒體庫管理',
|
||||
downloadPath: '下載目錄',
|
||||
@@ -2901,6 +2893,8 @@ export default {
|
||||
libraryPathHint: '設定媒體檔案的儲存路徑',
|
||||
},
|
||||
downloader: {
|
||||
title: '下載器配置',
|
||||
description: '設定下載器(可選)',
|
||||
info: '下載器設定說明',
|
||||
infoDesc: '設定下載器用於自動下載資源(可選)',
|
||||
type: '下載器類型',
|
||||
@@ -2915,6 +2909,8 @@ export default {
|
||||
downloadPath: '下載路徑',
|
||||
},
|
||||
mediaServer: {
|
||||
title: '媒體伺服器',
|
||||
description: '設定媒體伺服器(可選)',
|
||||
info: '媒體伺服器設定說明',
|
||||
infoDesc: '設定媒體伺服器用於媒體庫管理(可選)',
|
||||
type: '媒體伺服器類型',
|
||||
@@ -2929,6 +2925,8 @@ export default {
|
||||
token: '存取權杖',
|
||||
},
|
||||
notification: {
|
||||
title: '通知設定',
|
||||
description: '設定通知管道(可選)',
|
||||
info: '通知設定說明',
|
||||
infoDesc: '設定通知管道用於接收系統訊息(可選)',
|
||||
type: '通知類型',
|
||||
@@ -2946,6 +2944,8 @@ export default {
|
||||
receiverEmail: '接收信箱',
|
||||
},
|
||||
preferences: {
|
||||
title: '資源偏好',
|
||||
description: '設定資源下載偏好',
|
||||
info: '資源偏好說明',
|
||||
infoDesc: '設定資源下載的偏好,系統將根據這些偏好自動選擇最佳資源',
|
||||
quality: '品質偏好',
|
||||
|
||||
@@ -117,12 +117,17 @@ async function subscribeForPushNotifications() {
|
||||
|
||||
// 登录后处理
|
||||
async function afterLogin(superuser: boolean, userPayload: userState, filteredMenus: any[]) {
|
||||
// 如果有原始路径,优先跳转到原始路径
|
||||
if (authStore.originalPath && authStore.originalPath !== '/') {
|
||||
router.push(authStore.originalPath)
|
||||
// 如果需要显示设置向导,跳转到设置向导页面
|
||||
if (userPayload.wizard) {
|
||||
router.push('/setup-wizard')
|
||||
} else {
|
||||
// 跳转到第一个有权限的菜单
|
||||
router.push(filteredMenus[0].to)
|
||||
// 如果有原始路径,优先跳转到原始路径
|
||||
if (authStore.originalPath && authStore.originalPath !== '/') {
|
||||
router.push(authStore.originalPath)
|
||||
} else {
|
||||
// 跳转到第一个有权限的菜单
|
||||
router.push(filteredMenus[0].to)
|
||||
}
|
||||
}
|
||||
|
||||
// 订阅推送通知
|
||||
@@ -165,6 +170,7 @@ function login() {
|
||||
avatar: response.avatar,
|
||||
level: response.level,
|
||||
permissions: response.permissions,
|
||||
wizard: response.wizard,
|
||||
}
|
||||
|
||||
// 在保存用户信息之前检查权限
|
||||
|
||||
@@ -66,28 +66,37 @@ const wizardData = ref({
|
||||
|
||||
// 步骤标题
|
||||
const stepTitles = [
|
||||
t('setupWizard.step1.title'),
|
||||
t('setupWizard.step2.title'),
|
||||
t('setupWizard.step3.title'),
|
||||
t('setupWizard.step4.title'),
|
||||
t('setupWizard.step5.title'),
|
||||
t('setupWizard.step6.title'),
|
||||
t('setupWizard.basic.title'),
|
||||
t('setupWizard.storage.title'),
|
||||
t('setupWizard.downloader.title'),
|
||||
t('setupWizard.mediaServer.title'),
|
||||
t('setupWizard.notification.title'),
|
||||
t('setupWizard.preferences.title'),
|
||||
]
|
||||
|
||||
// 步骤描述
|
||||
const stepDescriptions = [
|
||||
t('setupWizard.step1.description'),
|
||||
t('setupWizard.step2.description'),
|
||||
t('setupWizard.step3.description'),
|
||||
t('setupWizard.step4.description'),
|
||||
t('setupWizard.step5.description'),
|
||||
t('setupWizard.step6.description'),
|
||||
t('setupWizard.basic.description'),
|
||||
t('setupWizard.storage.description'),
|
||||
t('setupWizard.downloader.description'),
|
||||
t('setupWizard.mediaServer.description'),
|
||||
t('setupWizard.notification.description'),
|
||||
t('setupWizard.preferences.description'),
|
||||
]
|
||||
|
||||
// 密码可见性控制
|
||||
const isPasswordVisible = ref(false)
|
||||
const isConfirmPasswordVisible = ref(false)
|
||||
|
||||
// 连通性测试状态
|
||||
const connectivityTest = ref({
|
||||
isTesting: false,
|
||||
testMessage: '',
|
||||
testProgress: 0,
|
||||
testResult: null as 'success' | 'error' | null,
|
||||
showResult: false,
|
||||
})
|
||||
|
||||
// 整理方式选项
|
||||
const transferTypeItems = [
|
||||
{ title: '硬链接', value: 'link' },
|
||||
@@ -192,12 +201,201 @@ function selectPreset(preset: string) {
|
||||
}
|
||||
}
|
||||
|
||||
// 连通性测试函数
|
||||
async function testConnectivity(step: number) {
|
||||
connectivityTest.value.isTesting = true
|
||||
connectivityTest.value.testMessage = ''
|
||||
connectivityTest.value.testProgress = 0
|
||||
connectivityTest.value.testResult = null
|
||||
connectivityTest.value.showResult = false
|
||||
|
||||
try {
|
||||
let testResult: { success: boolean; message: string | null } = { success: false, message: null }
|
||||
|
||||
switch (step) {
|
||||
case 2: // 存储目录测试
|
||||
testResult = await testStorageConnectivity()
|
||||
break
|
||||
case 3: // 下载器测试
|
||||
testResult = await testDownloaderConnectivity()
|
||||
break
|
||||
case 4: // 媒体服务器测试
|
||||
testResult = await testMediaServerConnectivity()
|
||||
break
|
||||
case 5: // 消息通知测试
|
||||
testResult = await testNotificationConnectivity()
|
||||
break
|
||||
}
|
||||
|
||||
// 设置测试结果
|
||||
connectivityTest.value.isTesting = false
|
||||
connectivityTest.value.testResult = testResult.success ? 'success' : 'error'
|
||||
connectivityTest.value.showResult = true
|
||||
|
||||
// 根据结果显示不同的消息
|
||||
if (testResult.success) {
|
||||
connectivityTest.value.testMessage = t('setupWizard.connectivityTestSuccess')
|
||||
} else {
|
||||
// 显示API返回的具体错误原因
|
||||
connectivityTest.value.testMessage = testResult.message || t('setupWizard.connectivityTestFailed')
|
||||
}
|
||||
|
||||
// 成功时2秒后隐藏结果,失败时保持显示直到用户操作
|
||||
if (testResult.success) {
|
||||
setTimeout(() => {
|
||||
connectivityTest.value.showResult = false
|
||||
connectivityTest.value.testResult = null
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
return testResult.success
|
||||
} catch (error) {
|
||||
console.error('Connectivity test failed:', error)
|
||||
connectivityTest.value.isTesting = false
|
||||
connectivityTest.value.testResult = 'error'
|
||||
connectivityTest.value.showResult = true
|
||||
connectivityTest.value.testMessage = (error as Error).message || t('setupWizard.connectivityTestFailed')
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 存储目录连通性测试
|
||||
async function testStorageConnectivity() {
|
||||
try {
|
||||
connectivityTest.value.testProgress = 30
|
||||
connectivityTest.value.testMessage = t('setupWizard.testingStorage')
|
||||
|
||||
// 等待设置生效
|
||||
await new Promise(resolve => setTimeout(resolve, 2000))
|
||||
|
||||
connectivityTest.value.testProgress = 60
|
||||
connectivityTest.value.testMessage = t('setupWizard.checkingStorage')
|
||||
|
||||
// 调用存储测试API
|
||||
const result = await api.get('system/storagetest')
|
||||
connectivityTest.value.testProgress = 100
|
||||
|
||||
if (result.data?.success) {
|
||||
return { success: true, message: null }
|
||||
} else {
|
||||
return { success: false, message: result.data?.message || t('setupWizard.storageTestFailed') }
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Storage test failed:', error)
|
||||
return { success: false, message: (error as Error).message || t('setupWizard.storageTestFailed') }
|
||||
}
|
||||
}
|
||||
|
||||
// 下载器连通性测试
|
||||
async function testDownloaderConnectivity() {
|
||||
try {
|
||||
connectivityTest.value.testProgress = 30
|
||||
connectivityTest.value.testMessage = t('setupWizard.testingDownloader')
|
||||
|
||||
// 等待设置生效
|
||||
await new Promise(resolve => setTimeout(resolve, 2000))
|
||||
|
||||
connectivityTest.value.testProgress = 60
|
||||
connectivityTest.value.testMessage = t('setupWizard.checkingDownloader')
|
||||
|
||||
// 调用下载器测试API
|
||||
const moduleid = wizardData.value.downloader.type
|
||||
if (!moduleid) {
|
||||
return { success: false, message: t('setupWizard.downloaderNotSelected') }
|
||||
}
|
||||
|
||||
const result: { [key: string]: any } = await api.get(`system/moduletest/${moduleid}`)
|
||||
connectivityTest.value.testProgress = 100
|
||||
|
||||
if (result.data?.success) {
|
||||
return { success: true, message: null }
|
||||
} else {
|
||||
return { success: false, message: result.data?.message || t('setupWizard.downloaderTestFailed') }
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Downloader test failed:', error)
|
||||
return { success: false, message: (error as Error).message || t('setupWizard.downloaderTestFailed') }
|
||||
}
|
||||
}
|
||||
|
||||
// 媒体服务器连通性测试
|
||||
async function testMediaServerConnectivity() {
|
||||
try {
|
||||
connectivityTest.value.testProgress = 30
|
||||
connectivityTest.value.testMessage = t('setupWizard.testingMediaServer')
|
||||
|
||||
// 等待设置生效
|
||||
await new Promise(resolve => setTimeout(resolve, 2000))
|
||||
|
||||
connectivityTest.value.testProgress = 60
|
||||
connectivityTest.value.testMessage = t('setupWizard.checkingMediaServer')
|
||||
|
||||
// 调用媒体服务器测试API
|
||||
const moduleid = wizardData.value.mediaServer.type
|
||||
if (!moduleid) {
|
||||
return { success: false, message: t('setupWizard.mediaServerNotSelected') }
|
||||
}
|
||||
|
||||
const result: { [key: string]: any } = await api.get(`system/moduletest/${moduleid}`)
|
||||
connectivityTest.value.testProgress = 100
|
||||
|
||||
if (result.data?.success) {
|
||||
return { success: true, message: null }
|
||||
} else {
|
||||
return { success: false, message: result.data?.message || t('setupWizard.mediaServerTestFailed') }
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Media server test failed:', error)
|
||||
return { success: false, message: (error as Error).message || t('setupWizard.mediaServerTestFailed') }
|
||||
}
|
||||
}
|
||||
|
||||
// 消息通知连通性测试
|
||||
async function testNotificationConnectivity() {
|
||||
try {
|
||||
connectivityTest.value.testProgress = 30
|
||||
connectivityTest.value.testMessage = t('setupWizard.testingNotification')
|
||||
|
||||
// 等待设置生效
|
||||
await new Promise(resolve => setTimeout(resolve, 2000))
|
||||
|
||||
connectivityTest.value.testProgress = 60
|
||||
connectivityTest.value.testMessage = t('setupWizard.checkingNotification')
|
||||
|
||||
// 调用通知测试API
|
||||
const moduleid = wizardData.value.notification.type
|
||||
if (!moduleid) {
|
||||
return { success: false, message: t('setupWizard.notificationNotSelected') }
|
||||
}
|
||||
|
||||
const result: { [key: string]: any } = await api.get(`system/moduletest/${moduleid}`)
|
||||
connectivityTest.value.testProgress = 100
|
||||
|
||||
if (result.data?.success) {
|
||||
return { success: true, message: null }
|
||||
} else {
|
||||
return { success: false, message: result.data?.message || t('setupWizard.notificationTestFailed') }
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Notification test failed:', error)
|
||||
return { success: false, message: (error as Error).message || t('setupWizard.notificationTestFailed') }
|
||||
}
|
||||
}
|
||||
|
||||
// 下一步
|
||||
async function nextStep() {
|
||||
if (currentStep.value < totalSteps) {
|
||||
// 保存当前步骤的设置
|
||||
await saveCurrentStepSettings()
|
||||
|
||||
// 对于需要测试的步骤,进行连通性测试
|
||||
if ([2, 3, 4, 5].includes(currentStep.value)) {
|
||||
const testResult = await testConnectivity(currentStep.value)
|
||||
if (!testResult) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
currentStep.value++
|
||||
}
|
||||
}
|
||||
@@ -1907,22 +2105,83 @@ onMounted(async () => {
|
||||
</VStepperWindowItem>
|
||||
</VStepperWindow>
|
||||
|
||||
<!-- 连通性测试进度条 -->
|
||||
<VCard v-if="connectivityTest.isTesting || connectivityTest.showResult" variant="outlined" class="mx-4 mb-4">
|
||||
<VCardText class="text-center py-4">
|
||||
<!-- 测试中 -->
|
||||
<div v-if="connectivityTest.isTesting">
|
||||
<VIcon icon="mdi-cog-sync" class="rotating mb-2" color="primary" size="24" />
|
||||
<div class="text-body-2 mb-2">{{ connectivityTest.testMessage }}</div>
|
||||
<VProgressLinear
|
||||
v-model="connectivityTest.testProgress"
|
||||
color="primary"
|
||||
height="6"
|
||||
rounded
|
||||
class="mb-2"
|
||||
/>
|
||||
<div class="text-caption text-medium-emphasis">{{ Math.round(connectivityTest.testProgress) }}%</div>
|
||||
</div>
|
||||
|
||||
<!-- 测试结果 -->
|
||||
<div v-else-if="connectivityTest.showResult">
|
||||
<VIcon
|
||||
:icon="connectivityTest.testResult === 'success' ? 'mdi-check-circle' : 'mdi-alert-circle'"
|
||||
:color="connectivityTest.testResult === 'success' ? 'success' : 'error'"
|
||||
size="24"
|
||||
class="mb-2"
|
||||
/>
|
||||
<div
|
||||
:class="connectivityTest.testResult === 'success' ? 'text-success' : 'text-error'"
|
||||
class="text-body-2 mb-2 font-weight-medium"
|
||||
>
|
||||
{{ connectivityTest.testMessage }}
|
||||
</div>
|
||||
<div v-if="connectivityTest.testResult === 'error'" class="text-caption text-medium-emphasis">
|
||||
{{ t('setupWizard.testFailedHint') }}
|
||||
</div>
|
||||
</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<VCardActions class="justify-space-between">
|
||||
<div class="d-flex gap-2">
|
||||
<VBtn v-if="currentStep !== 1" prepend-icon="mdi-chevron-left" @click="prevStep">
|
||||
<VBtn
|
||||
v-if="currentStep !== 1"
|
||||
prepend-icon="mdi-chevron-left"
|
||||
@click="prevStep"
|
||||
:disabled="connectivityTest.isTesting"
|
||||
>
|
||||
{{ t('common.previous') }}
|
||||
</VBtn>
|
||||
<VBtn v-else color="primary" prepend-icon="mdi-keyboard-return" @click="router.push('/')">
|
||||
<VBtn
|
||||
v-else
|
||||
color="primary"
|
||||
prepend-icon="mdi-keyboard-return"
|
||||
@click="router.push('/')"
|
||||
:disabled="connectivityTest.isTesting"
|
||||
>
|
||||
{{ t('common.skip') }}
|
||||
</VBtn>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<VBtn v-if="currentStep < totalSteps" color="primary" append-icon="mdi-chevron-right" @click="nextStep">
|
||||
{{ t('common.next') }}
|
||||
<VBtn
|
||||
v-if="currentStep < totalSteps"
|
||||
color="primary"
|
||||
append-icon="mdi-chevron-right"
|
||||
@click="nextStep"
|
||||
:disabled="connectivityTest.isTesting"
|
||||
>
|
||||
{{ connectivityTest.isTesting ? t('setupWizard.testing') : t('common.next') }}
|
||||
</VBtn>
|
||||
<VBtn v-else color="success" prepend-icon="mdi-check" @click="completeWizard">
|
||||
<VBtn
|
||||
v-else
|
||||
color="success"
|
||||
prepend-icon="mdi-check"
|
||||
@click="completeWizard"
|
||||
:disabled="connectivityTest.isTesting"
|
||||
>
|
||||
{{ t('setupWizard.complete') }}
|
||||
</VBtn>
|
||||
</div>
|
||||
@@ -1986,4 +2245,19 @@ onMounted(async () => {
|
||||
.v-card--variant-tonal.v-theme--dark {
|
||||
background-color: rgb(var(--v-theme-primary), 0.2);
|
||||
}
|
||||
|
||||
/* 旋转动画 */
|
||||
.rotating {
|
||||
animation: rotate 2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -20,6 +20,8 @@ export interface userState {
|
||||
level: number
|
||||
// 权限
|
||||
permissions: { [key: string]: any }
|
||||
// 是否需要显示设置向导
|
||||
wizard: boolean
|
||||
}
|
||||
|
||||
export interface globalSettingsState {
|
||||
|
||||
@@ -10,6 +10,7 @@ export const useUserStore = defineStore('user', {
|
||||
avatar: '',
|
||||
level: 1,
|
||||
permissions: DEFAULT_PERMISSIONS,
|
||||
wizard: false,
|
||||
}),
|
||||
|
||||
// 全局持久化
|
||||
@@ -34,6 +35,9 @@ export const useUserStore = defineStore('user', {
|
||||
setPermissions(permissions: object) {
|
||||
this.permissions = { ...DEFAULT_PERMISSIONS, ...permissions }
|
||||
},
|
||||
setWizard(wizard: boolean) {
|
||||
this.wizard = wizard
|
||||
},
|
||||
loginUser(payload: userState) {
|
||||
this.setSuperUser(payload.superUser)
|
||||
this.setUserID(payload.userID)
|
||||
@@ -41,6 +45,7 @@ export const useUserStore = defineStore('user', {
|
||||
this.setAvatar(payload.avatar)
|
||||
this.setLevel(payload.level)
|
||||
this.setPermissions(payload.permissions)
|
||||
this.setWizard(payload.wizard)
|
||||
},
|
||||
reset() {
|
||||
this.setSuperUser(false)
|
||||
@@ -49,6 +54,7 @@ export const useUserStore = defineStore('user', {
|
||||
this.setAvatar('')
|
||||
this.setLevel(1)
|
||||
this.setPermissions(DEFAULT_PERMISSIONS)
|
||||
this.setWizard(false)
|
||||
},
|
||||
},
|
||||
|
||||
@@ -59,5 +65,6 @@ export const useUserStore = defineStore('user', {
|
||||
getAvatar: state => state.avatar,
|
||||
getLevel: state => state.level,
|
||||
getPermissions: state => state.permissions,
|
||||
getWizard: state => state.wizard,
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user