mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-06-06 00:01:33 +08:00
增强配置向导功能
This commit is contained in:
@@ -3,11 +3,59 @@ import { useI18n } from 'vue-i18n'
|
||||
import { useSetupWizard } from '@/composables/useSetupWizard'
|
||||
|
||||
const { t } = useI18n()
|
||||
const { wizardData, createRandomString, copyValue } = useSetupWizard()
|
||||
const { wizardData, createRandomString, copyValue, validateCurrentStep } = useSetupWizard()
|
||||
|
||||
// 密码可见性控制
|
||||
const isPasswordVisible = ref(false)
|
||||
const isConfirmPasswordVisible = ref(false)
|
||||
|
||||
// 验证状态
|
||||
const validation = computed(() => validateCurrentStep())
|
||||
const hasErrors = computed(() => !validation.value.isValid)
|
||||
|
||||
// 密码相关验证
|
||||
const passwordError = computed(() => {
|
||||
if (!wizardData.value.basic.password) return false
|
||||
return wizardData.value.basic.password.length < 6
|
||||
})
|
||||
|
||||
const confirmPasswordError = computed(() => {
|
||||
if (!wizardData.value.basic.password) return false
|
||||
if (!wizardData.value.basic.confirmPassword) return true
|
||||
return wizardData.value.basic.password !== wizardData.value.basic.confirmPassword
|
||||
})
|
||||
|
||||
const passwordErrorMessage = computed(() => {
|
||||
if (passwordError.value) return t('dialog.userAddEdit.passwordMinLength')
|
||||
return ''
|
||||
})
|
||||
|
||||
const confirmPasswordErrorMessage = computed(() => {
|
||||
if (!wizardData.value.basic.password) return ''
|
||||
if (!wizardData.value.basic.confirmPassword) return t('dialog.userAddEdit.confirmPasswordRequired')
|
||||
if (confirmPasswordError.value) return t('dialog.userAddEdit.passwordMismatch')
|
||||
return ''
|
||||
})
|
||||
|
||||
// API Token验证
|
||||
const apiTokenError = computed(() => {
|
||||
return !wizardData.value.basic.apiToken && hasErrors.value
|
||||
})
|
||||
|
||||
const apiTokenErrorMessage = computed(() => {
|
||||
if (apiTokenError.value) return t('setupWizard.basic.apiTokenRequired')
|
||||
return ''
|
||||
})
|
||||
|
||||
// 用户名验证(虽然是只读的,但为了完整性)
|
||||
const usernameError = computed(() => {
|
||||
return !wizardData.value.basic.username && hasErrors.value
|
||||
})
|
||||
|
||||
const usernameErrorMessage = computed(() => {
|
||||
if (usernameError.value) return t('dialog.userAddEdit.usernameRequired')
|
||||
return ''
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -32,10 +80,12 @@ const isConfirmPasswordVisible = ref(false)
|
||||
<VTextField
|
||||
v-model="wizardData.basic.username"
|
||||
:label="t('user.username')"
|
||||
:hint="t('user.usernameHint')"
|
||||
:hint="t('setupWizard.basic.currentUserHint')"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-account"
|
||||
:rules="[(v: string) => !!v || t('user.usernameRequired')]"
|
||||
readonly
|
||||
:error="usernameError"
|
||||
:error-messages="usernameError ? [usernameErrorMessage] : []"
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -43,12 +93,14 @@ const isConfirmPasswordVisible = ref(false)
|
||||
v-model="wizardData.basic.password"
|
||||
:type="isPasswordVisible ? 'text' : 'password'"
|
||||
:label="t('user.password')"
|
||||
:hint="t('user.passwordHint')"
|
||||
:hint="t('setupWizard.basic.passwordOptionalHint')"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-lock"
|
||||
:append-inner-icon="isPasswordVisible ? 'mdi-eye-off-outline' : 'mdi-eye-outline'"
|
||||
@click:append-inner="isPasswordVisible = !isPasswordVisible"
|
||||
:rules="[(v: string) => !!v || t('user.passwordRequired'), (v: string) => v.length >= 6 || t('user.passwordMinLength')]"
|
||||
:error="passwordError"
|
||||
:error-messages="passwordError ? [passwordErrorMessage] : []"
|
||||
clearable
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -56,15 +108,15 @@ const isConfirmPasswordVisible = ref(false)
|
||||
v-model="wizardData.basic.confirmPassword"
|
||||
:type="isConfirmPasswordVisible ? 'text' : 'password'"
|
||||
:label="t('user.confirmPassword')"
|
||||
:hint="t('user.confirmPasswordHint')"
|
||||
:hint="t('setupWizard.basic.confirmPasswordHint')"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-lock-check"
|
||||
:append-inner-icon="isConfirmPasswordVisible ? 'mdi-eye-off-outline' : 'mdi-eye-outline'"
|
||||
@click:append-inner="isConfirmPasswordVisible = !isConfirmPasswordVisible"
|
||||
:rules="[
|
||||
(v: string) => !!v || t('user.confirmPasswordRequired'),
|
||||
(v: string) => v === wizardData.basic.password || t('user.passwordMismatch')
|
||||
]"
|
||||
:disabled="!wizardData.basic.password"
|
||||
:error="confirmPasswordError"
|
||||
:error-messages="confirmPasswordError ? [confirmPasswordErrorMessage] : []"
|
||||
clearable
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -98,10 +150,11 @@ const isConfirmPasswordVisible = ref(false)
|
||||
@click:append-inner="
|
||||
wizardData.basic.apiToken ? copyValue(wizardData.basic.apiToken) : createRandomString()
|
||||
"
|
||||
readonly
|
||||
:error="apiTokenError"
|
||||
:error-messages="apiTokenError ? [apiTokenErrorMessage] : []"
|
||||
/>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useI18n } from 'vue-i18n'
|
||||
import { useSetupWizard } from '@/composables/useSetupWizard'
|
||||
|
||||
const { t } = useI18n()
|
||||
const { wizardData, selectDownloader } = useSetupWizard()
|
||||
const { wizardData, selectDownloader, validationErrors } = useSetupWizard()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -34,12 +34,7 @@ const { wizardData, selectDownloader } = useSetupWizard()
|
||||
@click="selectDownloader('qbittorrent')"
|
||||
>
|
||||
<VCardText class="text-center">
|
||||
<VImg
|
||||
src="/src/assets/images/logos/qbittorrent.png"
|
||||
height="48"
|
||||
width="48"
|
||||
class="mx-auto mb-2"
|
||||
/>
|
||||
<VImg src="/src/assets/images/logos/qbittorrent.png" height="48" width="48" class="mx-auto mb-2" />
|
||||
<div class="text-h6">qBittorrent</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
@@ -52,12 +47,7 @@ const { wizardData, selectDownloader } = useSetupWizard()
|
||||
@click="selectDownloader('transmission')"
|
||||
>
|
||||
<VCardText class="text-center">
|
||||
<VImg
|
||||
src="/src/assets/images/logos/transmission.png"
|
||||
height="48"
|
||||
width="48"
|
||||
class="mx-auto mb-2"
|
||||
/>
|
||||
<VImg src="/src/assets/images/logos/transmission.png" height="48" width="48" class="mx-auto mb-2" />
|
||||
<div class="text-h6">Transmission</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
@@ -78,9 +68,12 @@ const { wizardData, selectDownloader } = useSetupWizard()
|
||||
:label="t('downloader.name')"
|
||||
:placeholder="t('downloader.nameRequired')"
|
||||
:hint="t('downloader.name')"
|
||||
:error="validationErrors.downloader.name"
|
||||
:error-messages="validationErrors.downloader.name ? [t('downloader.nameRequired')] : []"
|
||||
persistent-hint
|
||||
active
|
||||
prepend-inner-icon="mdi-label"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -89,9 +82,12 @@ const { wizardData, selectDownloader } = useSetupWizard()
|
||||
:label="t('downloader.host')"
|
||||
placeholder="http(s)://ip:port"
|
||||
:hint="t('downloader.host')"
|
||||
:error="validationErrors.downloader.host"
|
||||
:error-messages="validationErrors.downloader.host ? [t('downloader.hostRequired')] : []"
|
||||
persistent-hint
|
||||
active
|
||||
prepend-inner-icon="mdi-server"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -99,9 +95,12 @@ const { wizardData, selectDownloader } = useSetupWizard()
|
||||
v-model="wizardData.downloader.config.username"
|
||||
:label="t('downloader.username')"
|
||||
:hint="t('downloader.username')"
|
||||
:error="validationErrors.downloader.username"
|
||||
:error-messages="validationErrors.downloader.username ? [t('downloader.usernameRequired')] : []"
|
||||
persistent-hint
|
||||
active
|
||||
prepend-inner-icon="mdi-account"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -110,9 +109,12 @@ const { wizardData, selectDownloader } = useSetupWizard()
|
||||
type="password"
|
||||
:label="t('downloader.password')"
|
||||
:hint="t('downloader.password')"
|
||||
:error="validationErrors.downloader.password"
|
||||
:error-messages="validationErrors.downloader.password ? [t('downloader.passwordRequired')] : []"
|
||||
persistent-hint
|
||||
active
|
||||
prepend-inner-icon="mdi-lock"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -159,9 +161,12 @@ const { wizardData, selectDownloader } = useSetupWizard()
|
||||
:label="t('downloader.name')"
|
||||
:placeholder="t('downloader.nameRequired')"
|
||||
:hint="t('downloader.name')"
|
||||
:error="validationErrors.downloader.name"
|
||||
:error-messages="validationErrors.downloader.name ? [t('downloader.nameRequired')] : []"
|
||||
persistent-hint
|
||||
active
|
||||
prepend-inner-icon="mdi-label"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -170,9 +175,12 @@ const { wizardData, selectDownloader } = useSetupWizard()
|
||||
:label="t('downloader.host')"
|
||||
placeholder="http(s)://ip:port"
|
||||
:hint="t('downloader.host')"
|
||||
:error="validationErrors.downloader.host"
|
||||
:error-messages="validationErrors.downloader.host ? [t('downloader.hostRequired')] : []"
|
||||
persistent-hint
|
||||
active
|
||||
prepend-inner-icon="mdi-server"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -180,9 +188,12 @@ const { wizardData, selectDownloader } = useSetupWizard()
|
||||
v-model="wizardData.downloader.config.username"
|
||||
:label="t('downloader.username')"
|
||||
:hint="t('downloader.username')"
|
||||
:error="validationErrors.downloader.username"
|
||||
:error-messages="validationErrors.downloader.username ? [t('downloader.usernameRequired')] : []"
|
||||
persistent-hint
|
||||
active
|
||||
prepend-inner-icon="mdi-account"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -191,9 +202,12 @@ const { wizardData, selectDownloader } = useSetupWizard()
|
||||
type="password"
|
||||
:label="t('downloader.password')"
|
||||
:hint="t('downloader.password')"
|
||||
:error="validationErrors.downloader.password"
|
||||
:error-messages="validationErrors.downloader.password ? [t('downloader.passwordRequired')] : []"
|
||||
persistent-hint
|
||||
active
|
||||
prepend-inner-icon="mdi-lock"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
</VRow>
|
||||
@@ -251,4 +265,4 @@ const { wizardData, selectDownloader } = useSetupWizard()
|
||||
.v-card--variant-tonal.v-theme--dark {
|
||||
background-color: rgb(var(--v-theme-primary), 0.2);
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useI18n } from 'vue-i18n'
|
||||
import { useSetupWizard } from '@/composables/useSetupWizard'
|
||||
|
||||
const { t } = useI18n()
|
||||
const { wizardData, selectMediaServer } = useSetupWizard()
|
||||
const { wizardData, selectMediaServer, validationErrors } = useSetupWizard()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -34,12 +34,7 @@ const { wizardData, selectMediaServer } = useSetupWizard()
|
||||
@click="selectMediaServer('emby')"
|
||||
>
|
||||
<VCardText class="text-center">
|
||||
<VImg
|
||||
src="/src/assets/images/logos/emby.png"
|
||||
height="48"
|
||||
width="48"
|
||||
class="mx-auto mb-2"
|
||||
/>
|
||||
<VImg src="/src/assets/images/logos/emby.png" height="48" width="48" class="mx-auto mb-2" />
|
||||
<div class="text-h6">Emby</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
@@ -52,12 +47,7 @@ const { wizardData, selectMediaServer } = useSetupWizard()
|
||||
@click="selectMediaServer('jellyfin')"
|
||||
>
|
||||
<VCardText class="text-center">
|
||||
<VImg
|
||||
src="/src/assets/images/logos/jellyfin.png"
|
||||
height="48"
|
||||
width="48"
|
||||
class="mx-auto mb-2"
|
||||
/>
|
||||
<VImg src="/src/assets/images/logos/jellyfin.png" height="48" width="48" class="mx-auto mb-2" />
|
||||
<div class="text-h6">Jellyfin</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
@@ -70,12 +60,7 @@ const { wizardData, selectMediaServer } = useSetupWizard()
|
||||
@click="selectMediaServer('plex')"
|
||||
>
|
||||
<VCardText class="text-center">
|
||||
<VImg
|
||||
src="/src/assets/images/logos/plex.png"
|
||||
height="48"
|
||||
width="48"
|
||||
class="mx-auto mb-2"
|
||||
/>
|
||||
<VImg src="/src/assets/images/logos/plex.png" height="48" width="48" class="mx-auto mb-2" />
|
||||
<div class="text-h6">Plex</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
@@ -88,12 +73,7 @@ const { wizardData, selectMediaServer } = useSetupWizard()
|
||||
@click="selectMediaServer('trimemedia')"
|
||||
>
|
||||
<VCardText class="text-center">
|
||||
<VImg
|
||||
src="/src/assets/images/logos/trimemedia.png"
|
||||
height="48"
|
||||
width="48"
|
||||
class="mx-auto mb-2"
|
||||
/>
|
||||
<VImg src="/src/assets/images/logos/trimemedia.png" height="48" width="48" class="mx-auto mb-2" />
|
||||
<div class="text-h6">飞牛影视</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
@@ -114,9 +94,12 @@ const { wizardData, selectMediaServer } = useSetupWizard()
|
||||
:label="t('common.name')"
|
||||
:placeholder="t('mediaserver.nameRequired')"
|
||||
:hint="t('mediaserver.serverAlias')"
|
||||
:error="validationErrors.mediaServer.name"
|
||||
:error-messages="validationErrors.mediaServer.name ? [t('mediaserver.nameRequired')] : []"
|
||||
persistent-hint
|
||||
active
|
||||
prepend-inner-icon="mdi-label"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -125,9 +108,12 @@ const { wizardData, selectMediaServer } = useSetupWizard()
|
||||
:label="t('mediaserver.host')"
|
||||
:placeholder="t('mediaserver.hostPlaceholder')"
|
||||
:hint="t('mediaserver.hostHint')"
|
||||
:error="validationErrors.mediaServer.host"
|
||||
:error-messages="validationErrors.mediaServer.host ? [t('mediaserver.hostRequired')] : []"
|
||||
persistent-hint
|
||||
active
|
||||
prepend-inner-icon="mdi-server"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -146,9 +132,12 @@ const { wizardData, selectMediaServer } = useSetupWizard()
|
||||
v-model="wizardData.mediaServer.config.apikey"
|
||||
:label="t('mediaserver.apiKey')"
|
||||
:hint="t('mediaserver.embyApiKeyHint')"
|
||||
:error="validationErrors.mediaServer.apikey"
|
||||
:error-messages="validationErrors.mediaServer.apikey ? [t('mediaserver.apiKeyRequired')] : []"
|
||||
persistent-hint
|
||||
active
|
||||
prepend-inner-icon="mdi-key"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12">
|
||||
@@ -174,9 +163,12 @@ const { wizardData, selectMediaServer } = useSetupWizard()
|
||||
:label="t('common.name')"
|
||||
:placeholder="t('mediaserver.nameRequired')"
|
||||
:hint="t('mediaserver.serverAlias')"
|
||||
:error="validationErrors.mediaServer.name"
|
||||
:error-messages="validationErrors.mediaServer.name ? [t('mediaserver.nameRequired')] : []"
|
||||
persistent-hint
|
||||
active
|
||||
prepend-inner-icon="mdi-label"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -185,9 +177,12 @@ const { wizardData, selectMediaServer } = useSetupWizard()
|
||||
:label="t('mediaserver.host')"
|
||||
:placeholder="t('mediaserver.hostPlaceholder')"
|
||||
:hint="t('mediaserver.hostHint')"
|
||||
:error="validationErrors.mediaServer.host"
|
||||
:error-messages="validationErrors.mediaServer.host ? [t('mediaserver.hostRequired')] : []"
|
||||
persistent-hint
|
||||
active
|
||||
prepend-inner-icon="mdi-server"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -206,9 +201,12 @@ const { wizardData, selectMediaServer } = useSetupWizard()
|
||||
v-model="wizardData.mediaServer.config.apikey"
|
||||
:label="t('mediaserver.apiKey')"
|
||||
:hint="t('mediaserver.jellyfinApiKeyHint')"
|
||||
:error="validationErrors.mediaServer.apikey"
|
||||
:error-messages="validationErrors.mediaServer.apikey ? [t('mediaserver.apiKeyRequired')] : []"
|
||||
persistent-hint
|
||||
active
|
||||
prepend-inner-icon="mdi-key"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12">
|
||||
@@ -234,9 +232,12 @@ const { wizardData, selectMediaServer } = useSetupWizard()
|
||||
:label="t('common.name')"
|
||||
:placeholder="t('mediaserver.nameRequired')"
|
||||
:hint="t('mediaserver.serverAlias')"
|
||||
:error="validationErrors.mediaServer.name"
|
||||
:error-messages="validationErrors.mediaServer.name ? [t('mediaserver.nameRequired')] : []"
|
||||
persistent-hint
|
||||
active
|
||||
prepend-inner-icon="mdi-label"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -245,9 +246,12 @@ const { wizardData, selectMediaServer } = useSetupWizard()
|
||||
:label="t('mediaserver.host')"
|
||||
:placeholder="t('mediaserver.hostPlaceholder')"
|
||||
:hint="t('mediaserver.hostHint')"
|
||||
:error="validationErrors.mediaServer.host"
|
||||
:error-messages="validationErrors.mediaServer.host ? [t('mediaserver.hostRequired')] : []"
|
||||
persistent-hint
|
||||
active
|
||||
prepend-inner-icon="mdi-server"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12">
|
||||
@@ -265,8 +269,11 @@ const { wizardData, selectMediaServer } = useSetupWizard()
|
||||
<VTextField
|
||||
v-model="wizardData.mediaServer.config.username"
|
||||
:label="t('mediaserver.username')"
|
||||
:error="validationErrors.mediaServer.username"
|
||||
:error-messages="validationErrors.mediaServer.username ? [t('mediaserver.usernameRequired')] : []"
|
||||
active
|
||||
prepend-inner-icon="mdi-account"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -274,8 +281,11 @@ const { wizardData, selectMediaServer } = useSetupWizard()
|
||||
type="password"
|
||||
v-model="wizardData.mediaServer.config.password"
|
||||
:label="t('mediaserver.password')"
|
||||
:error="validationErrors.mediaServer.password"
|
||||
:error-messages="validationErrors.mediaServer.password ? [t('mediaserver.passwordRequired')] : []"
|
||||
active
|
||||
prepend-inner-icon="mdi-lock"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12">
|
||||
@@ -301,9 +311,12 @@ const { wizardData, selectMediaServer } = useSetupWizard()
|
||||
:label="t('common.name')"
|
||||
:placeholder="t('mediaserver.nameRequired')"
|
||||
:hint="t('mediaserver.serverAlias')"
|
||||
:error="validationErrors.mediaServer.name"
|
||||
:error-messages="validationErrors.mediaServer.name ? [t('mediaserver.nameRequired')] : []"
|
||||
persistent-hint
|
||||
active
|
||||
prepend-inner-icon="mdi-label"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -312,9 +325,12 @@ const { wizardData, selectMediaServer } = useSetupWizard()
|
||||
:label="t('mediaserver.host')"
|
||||
:placeholder="t('mediaserver.hostPlaceholder')"
|
||||
:hint="t('mediaserver.hostHint')"
|
||||
:error="validationErrors.mediaServer.host"
|
||||
:error-messages="validationErrors.mediaServer.host ? [t('mediaserver.hostRequired')] : []"
|
||||
persistent-hint
|
||||
active
|
||||
prepend-inner-icon="mdi-server"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -333,9 +349,12 @@ const { wizardData, selectMediaServer } = useSetupWizard()
|
||||
v-model="wizardData.mediaServer.config.token"
|
||||
:label="t('mediaserver.plexToken')"
|
||||
:hint="t('mediaserver.plexTokenHint')"
|
||||
:error="validationErrors.mediaServer.token"
|
||||
:error-messages="validationErrors.mediaServer.token ? [t('mediaserver.tokenRequired')] : []"
|
||||
persistent-hint
|
||||
active
|
||||
prepend-inner-icon="mdi-key"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12">
|
||||
@@ -406,4 +425,4 @@ const { wizardData, selectMediaServer } = useSetupWizard()
|
||||
.v-card--variant-tonal.v-theme--dark {
|
||||
background-color: rgb(var(--v-theme-primary), 0.2);
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useI18n } from 'vue-i18n'
|
||||
import { useSetupWizard } from '@/composables/useSetupWizard'
|
||||
|
||||
const { t } = useI18n()
|
||||
const { wizardData, selectNotification } = useSetupWizard()
|
||||
const { wizardData, selectNotification, validationErrors } = useSetupWizard()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -34,12 +34,7 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
@click="selectNotification('wechat')"
|
||||
>
|
||||
<VCardText class="text-center">
|
||||
<VImg
|
||||
src="/src/assets/images/logos/wechat.png"
|
||||
height="48"
|
||||
width="48"
|
||||
class="mx-auto mb-2"
|
||||
/>
|
||||
<VImg src="/src/assets/images/logos/wechat.png" height="48" width="48" class="mx-auto mb-2" />
|
||||
<div class="text-h6">微信</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
@@ -52,12 +47,7 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
@click="selectNotification('telegram')"
|
||||
>
|
||||
<VCardText class="text-center">
|
||||
<VImg
|
||||
src="/src/assets/images/logos/telegram.webp"
|
||||
height="48"
|
||||
width="48"
|
||||
class="mx-auto mb-2"
|
||||
/>
|
||||
<VImg src="/src/assets/images/logos/telegram.webp" height="48" width="48" class="mx-auto mb-2" />
|
||||
<div class="text-h6">Telegram</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
@@ -70,12 +60,7 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
@click="selectNotification('slack')"
|
||||
>
|
||||
<VCardText class="text-center">
|
||||
<VImg
|
||||
src="/src/assets/images/logos/slack.webp"
|
||||
height="48"
|
||||
width="48"
|
||||
class="mx-auto mb-2"
|
||||
/>
|
||||
<VImg src="/src/assets/images/logos/slack.webp" height="48" width="48" class="mx-auto mb-2" />
|
||||
<div class="text-h6">Slack</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
@@ -88,12 +73,7 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
@click="selectNotification('synologychat')"
|
||||
>
|
||||
<VCardText class="text-center">
|
||||
<VImg
|
||||
src="/src/assets/images/logos/synologychat.png"
|
||||
height="48"
|
||||
width="48"
|
||||
class="mx-auto mb-2"
|
||||
/>
|
||||
<VImg src="/src/assets/images/logos/synologychat.png" height="48" width="48" class="mx-auto mb-2" />
|
||||
<div class="text-h6">Synology Chat</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
@@ -106,12 +86,7 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
@click="selectNotification('vocechat')"
|
||||
>
|
||||
<VCardText class="text-center">
|
||||
<VImg
|
||||
src="/src/assets/images/logos/vocechat.png"
|
||||
height="48"
|
||||
width="48"
|
||||
class="mx-auto mb-2"
|
||||
/>
|
||||
<VImg src="/src/assets/images/logos/vocechat.png" height="48" width="48" class="mx-auto mb-2" />
|
||||
<div class="text-h6">VoceChat</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
@@ -139,13 +114,10 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
<VCardText>
|
||||
<VForm>
|
||||
<VRow>
|
||||
<VCol cols="12" md="6">
|
||||
<VSwitch v-model="wizardData.notification.enabled" :label="t('notification.enabled')" />
|
||||
</VCol>
|
||||
<VCol cols="12">
|
||||
<VAutocomplete
|
||||
v-model="wizardData.notification.switchs"
|
||||
:items="[]"
|
||||
:items="[] as string[]"
|
||||
:label="t('notification.type')"
|
||||
:hint="t('notification.typeHint')"
|
||||
multiple
|
||||
@@ -163,8 +135,11 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
:label="t('notification.name')"
|
||||
:placeholder="t('notification.name')"
|
||||
:hint="t('notification.nameHint')"
|
||||
:error="validationErrors.notification.name"
|
||||
:error-messages="validationErrors.notification.name ? [t('notification.nameRequired')] : []"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-label"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -172,8 +147,13 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
v-model="wizardData.notification.config.WECHAT_CORPID"
|
||||
:label="t('notification.wechat.corpId')"
|
||||
:hint="t('notification.wechat.corpIdHint')"
|
||||
:error="validationErrors.notification.WECHAT_CORPID"
|
||||
:error-messages="
|
||||
validationErrors.notification.WECHAT_CORPID ? [t('notification.wechat.corpIdRequired')] : []
|
||||
"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-domain"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -181,8 +161,13 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
v-model="wizardData.notification.config.WECHAT_APP_ID"
|
||||
:label="t('notification.wechat.appId')"
|
||||
:hint="t('notification.wechat.appIdHint')"
|
||||
:error="validationErrors.notification.WECHAT_APP_ID"
|
||||
:error-messages="
|
||||
validationErrors.notification.WECHAT_APP_ID ? [t('notification.wechat.appIdRequired')] : []
|
||||
"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-application"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -190,8 +175,15 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
v-model="wizardData.notification.config.WECHAT_APP_SECRET"
|
||||
:label="t('notification.wechat.appSecret')"
|
||||
:hint="t('notification.wechat.appSecretHint')"
|
||||
:error="validationErrors.notification.WECHAT_APP_SECRET"
|
||||
:error-messages="
|
||||
validationErrors.notification.WECHAT_APP_SECRET
|
||||
? [t('notification.wechat.appSecretRequired')]
|
||||
: []
|
||||
"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-key"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -239,8 +231,11 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
:label="t('notification.name')"
|
||||
:placeholder="t('notification.name')"
|
||||
:hint="t('notification.nameHint')"
|
||||
:error="validationErrors.notification.name"
|
||||
:error-messages="validationErrors.notification.name ? [t('notification.nameRequired')] : []"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-label"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -248,8 +243,13 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
v-model="wizardData.notification.config.TELEGRAM_TOKEN"
|
||||
:label="t('notification.telegram.token')"
|
||||
:hint="t('notification.telegram.tokenHint')"
|
||||
:error="validationErrors.notification.TELEGRAM_TOKEN"
|
||||
:error-messages="
|
||||
validationErrors.notification.TELEGRAM_TOKEN ? [t('notification.telegram.tokenRequired')] : []
|
||||
"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-key"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -257,8 +257,15 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
v-model="wizardData.notification.config.TELEGRAM_CHAT_ID"
|
||||
:label="t('notification.telegram.chatId')"
|
||||
:hint="t('notification.telegram.chatIdHint')"
|
||||
:error="validationErrors.notification.TELEGRAM_CHAT_ID"
|
||||
:error-messages="
|
||||
validationErrors.notification.TELEGRAM_CHAT_ID
|
||||
? [t('notification.telegram.chatIdRequired')]
|
||||
: []
|
||||
"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-chat"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -299,8 +306,11 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
:label="t('notification.name')"
|
||||
:placeholder="t('notification.name')"
|
||||
:hint="t('notification.nameHint')"
|
||||
:error="validationErrors.notification.name"
|
||||
:error-messages="validationErrors.notification.name ? [t('notification.nameRequired')] : []"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-label"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -309,8 +319,15 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
:label="t('notification.slack.oauthToken')"
|
||||
:placeholder="t('notification.slack.oauthTokenPlaceholder')"
|
||||
:hint="t('notification.slack.oauthTokenHint')"
|
||||
:error="validationErrors.notification.SLACK_OAUTH_TOKEN"
|
||||
:error-messages="
|
||||
validationErrors.notification.SLACK_OAUTH_TOKEN
|
||||
? [t('notification.slack.oauthTokenRequired')]
|
||||
: []
|
||||
"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-key"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -329,8 +346,13 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
:label="t('notification.slack.channel')"
|
||||
:placeholder="t('notification.slack.channelPlaceholder')"
|
||||
:hint="t('notification.slack.channelHint')"
|
||||
:error="validationErrors.notification.SLACK_CHANNEL"
|
||||
:error-messages="
|
||||
validationErrors.notification.SLACK_CHANNEL ? [t('notification.slack.channelRequired')] : []
|
||||
"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-pound"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
</VRow>
|
||||
@@ -341,8 +363,11 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
:label="t('notification.name')"
|
||||
:placeholder="t('notification.name')"
|
||||
:hint="t('notification.nameHint')"
|
||||
:error="validationErrors.notification.name"
|
||||
:error-messages="validationErrors.notification.name ? [t('notification.nameRequired')] : []"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-label"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -350,8 +375,15 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
v-model="wizardData.notification.config.SYNOLOGYCHAT_WEBHOOK"
|
||||
:label="t('notification.synologychat.webhook')"
|
||||
:hint="t('notification.synologychat.webhookHint')"
|
||||
:error="validationErrors.notification.SYNOLOGYCHAT_WEBHOOK"
|
||||
:error-messages="
|
||||
validationErrors.notification.SYNOLOGYCHAT_WEBHOOK
|
||||
? [t('notification.synologychat.webhookRequired')]
|
||||
: []
|
||||
"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-webhook"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -371,8 +403,11 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
:label="t('notification.name')"
|
||||
:placeholder="t('notification.name')"
|
||||
:hint="t('notification.nameHint')"
|
||||
:error="validationErrors.notification.name"
|
||||
:error-messages="validationErrors.notification.name ? [t('notification.nameRequired')] : []"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-label"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -380,8 +415,13 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
v-model="wizardData.notification.config.VOCECHAT_HOST"
|
||||
:label="t('notification.vocechat.host')"
|
||||
:hint="t('notification.vocechat.hostHint')"
|
||||
:error="validationErrors.notification.VOCECHAT_HOST"
|
||||
:error-messages="
|
||||
validationErrors.notification.VOCECHAT_HOST ? [t('notification.vocechat.hostRequired')] : []
|
||||
"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-server"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -389,8 +429,15 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
v-model="wizardData.notification.config.VOCECHAT_API_KEY"
|
||||
:label="t('notification.vocechat.apiKey')"
|
||||
:hint="t('notification.vocechat.apiKeyHint')"
|
||||
:error="validationErrors.notification.VOCECHAT_API_KEY"
|
||||
:error-messages="
|
||||
validationErrors.notification.VOCECHAT_API_KEY
|
||||
? [t('notification.vocechat.apiKeyRequired')]
|
||||
: []
|
||||
"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-key"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -411,8 +458,11 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
:label="t('notification.name')"
|
||||
:placeholder="t('notification.name')"
|
||||
:hint="t('notification.nameHint')"
|
||||
:error="validationErrors.notification.name"
|
||||
:error-messages="validationErrors.notification.name ? [t('notification.nameRequired')] : []"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-label"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -420,8 +470,15 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
v-model="wizardData.notification.config.WEBPUSH_USERNAME"
|
||||
:label="t('notification.webpush.username')"
|
||||
:hint="t('notification.webpush.usernameHint')"
|
||||
:error="validationErrors.notification.WEBPUSH_USERNAME"
|
||||
:error-messages="
|
||||
validationErrors.notification.WEBPUSH_USERNAME
|
||||
? [t('notification.webpush.usernameRequired')]
|
||||
: []
|
||||
"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-account"
|
||||
required
|
||||
/>
|
||||
</VCol>
|
||||
</VRow>
|
||||
@@ -478,4 +535,4 @@ const { wizardData, selectNotification } = useSetupWizard()
|
||||
.v-card--variant-tonal.v-theme--dark {
|
||||
background-color: rgb(var(--v-theme-primary), 0.2);
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -3,7 +3,11 @@ import { useI18n } from 'vue-i18n'
|
||||
import { useSetupWizard } from '@/composables/useSetupWizard'
|
||||
|
||||
const { t } = useI18n()
|
||||
const { wizardData } = useSetupWizard()
|
||||
const { wizardData, validateCurrentStep } = useSetupWizard()
|
||||
|
||||
// 验证状态
|
||||
const validation = computed(() => validateCurrentStep())
|
||||
const hasErrors = computed(() => !validation.value.isValid)
|
||||
|
||||
// 整理方式选项
|
||||
const transferTypeItems = [
|
||||
@@ -44,6 +48,10 @@ const overwriteModeItems = [
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-download"
|
||||
placeholder="/downloads"
|
||||
:error="!wizardData.storage.downloadPath && hasErrors"
|
||||
:error-messages="
|
||||
!wizardData.storage.downloadPath && hasErrors ? [t('setupWizard.storage.downloadPathRequired')] : []
|
||||
"
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
@@ -54,10 +62,14 @@ const overwriteModeItems = [
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-folder-multiple"
|
||||
placeholder="/media"
|
||||
:error="!wizardData.storage.libraryPath && hasErrors"
|
||||
:error-messages="
|
||||
!wizardData.storage.libraryPath && hasErrors ? [t('setupWizard.storage.libraryPathRequired')] : []
|
||||
"
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
<VSelect
|
||||
<VAutocomplete
|
||||
v-model="wizardData.storage.transferType"
|
||||
:label="t('directory.transferType')"
|
||||
:hint="t('directory.transferTypeHint')"
|
||||
@@ -67,7 +79,7 @@ const overwriteModeItems = [
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
<VSelect
|
||||
<VAutocomplete
|
||||
v-model="wizardData.storage.overwriteMode"
|
||||
:label="t('directory.overwriteMode')"
|
||||
:hint="t('directory.overwriteModeHint')"
|
||||
@@ -79,4 +91,4 @@ const overwriteModeItems = [
|
||||
</VRow>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user