更新存储卡组件,添加自定义存储配置对话框,优化存储名称显示,并完善国际化文本

This commit is contained in:
jxxghp
2025-05-01 19:35:08 +08:00
parent 900dd6e958
commit f56d1c68c7
7 changed files with 55 additions and 19 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

+2 -3
View File
@@ -187,8 +187,8 @@ onUnmounted(() => {
</VCardText> </VCardText>
</VCard> </VCard>
</VHover> </VHover>
<VDialog v-if="downloaderInfoDialog" v-model="downloaderInfoDialog" scrollable max-width="40rem" persistent> <VDialog v-if="downloaderInfoDialog" v-model="downloaderInfoDialog" scrollable max-width="40rem">
<VCard :title="`${props.downloader.name} - ${t('downloader.title')}`" class="rounded-t"> <VCard :title="`${props.downloader.name} - ${t('downloader.title')}`">
<VDialogCloseBtn v-model="downloaderInfoDialog" /> <VDialogCloseBtn v-model="downloaderInfoDialog" />
<VDivider /> <VDivider />
<VCardText> <VCardText>
@@ -329,7 +329,6 @@ onUnmounted(() => {
v-model="downloaderInfo.name" v-model="downloaderInfo.name"
:label="t('downloader.name')" :label="t('downloader.name')"
:placeholder="t('downloader.nameRequired')" :placeholder="t('downloader.nameRequired')"
:hint="t('downloader.name')"
persistent-hint persistent-hint
active active
/> />
+40 -9
View File
@@ -6,6 +6,7 @@ import alipan_png from '@images/misc/alipan.webp'
import u115_png from '@images/misc/u115.png' import u115_png from '@images/misc/u115.png'
import rclone_png from '@images/misc/rclone.png' import rclone_png from '@images/misc/rclone.png'
import alist_png from '@images/misc/alist.svg' import alist_png from '@images/misc/alist.svg'
import custom_png from '@images/misc/database.png'
import api from '@/api' import api from '@/api'
import AliyunAuthDialog from '../dialog/AliyunAuthDialog.vue' import AliyunAuthDialog from '../dialog/AliyunAuthDialog.vue'
import U115AuthDialog from '../dialog/U115AuthDialog.vue' import U115AuthDialog from '../dialog/U115AuthDialog.vue'
@@ -14,7 +15,6 @@ import AlistConfigDialog from '../dialog/AlistConfigDialog.vue'
import { useToast } from 'vue-toast-notification' import { useToast } from 'vue-toast-notification'
import { isNullOrEmptyObject } from '@/@core/utils' import { isNullOrEmptyObject } from '@/@core/utils'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { storageOptions } from '@/api/constants'
// 国际化 // 国际化
const { t } = useI18n() const { t } = useI18n()
@@ -44,6 +44,12 @@ const used = computed(() => {
return total.value - available.value return total.value - available.value
}) })
// 存储
const storage_ref = ref(props.storage)
// 自定义存储名称
const customName = ref(props.storage.name)
// 阿里云盘认证对话框 // 阿里云盘认证对话框
const aliyunAuthDialog = ref(false) const aliyunAuthDialog = ref(false)
// 115网盘认证对话框 // 115网盘认证对话框
@@ -52,6 +58,8 @@ const u115AuthDialog = ref(false)
const rcloneConfigDialog = ref(false) const rcloneConfigDialog = ref(false)
// AList配置对话框 // AList配置对话框
const aListConfigDialog = ref(false) const aListConfigDialog = ref(false)
// 自定义存储配置对话框
const customConfigDialog = ref(false)
// 打开存储对话框 // 打开存储对话框
function openStorageDialog() { function openStorageDialog() {
@@ -68,6 +76,9 @@ function openStorageDialog() {
case 'alist': case 'alist':
aListConfigDialog.value = true aListConfigDialog.value = true
break break
case 'custom':
customConfigDialog.value = true
break
default: default:
$toast.info(t('storage.noConfigNeeded')) $toast.info(t('storage.noConfigNeeded'))
break break
@@ -87,6 +98,8 @@ const getIcon = computed(() => {
return rclone_png return rclone_png
case 'alist': case 'alist':
return alist_png return alist_png
case 'custom':
return custom_png
default: default:
return storage_png return storage_png
} }
@@ -125,12 +138,9 @@ function handleDone() {
u115AuthDialog.value = false u115AuthDialog.value = false
rcloneConfigDialog.value = false rcloneConfigDialog.value = false
aListConfigDialog.value = false aListConfigDialog.value = false
emit('done') customConfigDialog.value = false
} storage_ref.value.name = customName.value
emit('done', storage_ref.value)
// 根据存储类型获取文本
function getStorageTypeText(type: string) {
return storageOptions.find(option => option.value === type)?.title
} }
onMounted(() => { onMounted(() => {
@@ -148,7 +158,7 @@ function onClose() {
<VDialogCloseBtn v-if="storage.type == 'custom'" @click="onClose" /> <VDialogCloseBtn v-if="storage.type == 'custom'" @click="onClose" />
<VCardText class="flex justify-space-between align-center gap-3"> <VCardText class="flex justify-space-between align-center gap-3">
<div class="align-self-start flex-1"> <div class="align-self-start flex-1">
<h5 class="text-h6 mb-1">{{ getStorageTypeText(storage.type) }}</h5> <h5 class="text-h6 mb-1">{{ storage.name }}</h5>
<template v-if="storage.type != 'custom'"> <template v-if="storage.type != 'custom'">
<div class="mb-3 text-sm" v-if="total">{{ formatBytes(used, 1) }} / {{ formatBytes(total, 1) }}</div> <div class="mb-3 text-sm" v-if="total">{{ formatBytes(used, 1) }} / {{ formatBytes(total, 1) }}</div>
<div v-else-if="isNullOrEmptyObject(storage.config)">{{ t('storage.notConfigured') }}</div> <div v-else-if="isNullOrEmptyObject(storage.config)">{{ t('storage.notConfigured') }}</div>
@@ -157,7 +167,7 @@ function onClose() {
<div class="mb-3 text-sm">{{ t('storage.custom') }}</div> <div class="mb-3 text-sm">{{ t('storage.custom') }}</div>
</template> </template>
</div> </div>
<VImg :src="getIcon" cover class="mt-5" max-width="3rem" min-width="3rem" /> <VImg :src="getIcon" cover class="mt-7" max-width="3rem" min-width="3rem" />
</VCardText> </VCardText>
<div class="w-full absolute bottom-0"> <div class="w-full absolute bottom-0">
<VProgressLinear v-if="usage > 0" :model-value="usage" :bg-color="progressColor" :color="progressColor" /> <VProgressLinear v-if="usage > 0" :model-value="usage" :bg-color="progressColor" :color="progressColor" />
@@ -191,5 +201,26 @@ function onClose() {
@close="aListConfigDialog = false" @close="aListConfigDialog = false"
@done="handleDone" @done="handleDone"
/> />
<VDialog v-if="customConfigDialog" v-model="customConfigDialog" scrollable max-width="30rem">
<VCard>
<VCardItem>
<VCardTitle>{{ t('storage.custom') }}</VCardTitle>
<VDialogCloseBtn v-model="customConfigDialog" />
</VCardItem>
<VDivider />
<VCardText>
<VRow>
<VCol cols="12" md="6">
<VTextField v-model="customName" :label="t('storage.name')" persistent-hint active />
</VCol>
</VRow>
</VCardText>
<VCardActions class="pt-3">
<VBtn @click="handleDone" variant="elevated" prepend-icon="mdi-content-save" class="px-5">
{{ t('common.save') }}
</VBtn>
</VCardActions>
</VCard>
</VDialog>
</div> </div>
</template> </template>
+1
View File
@@ -727,6 +727,7 @@ export default {
episode: 'Episode {number}', episode: 'Episode {number}',
}, },
storage: { storage: {
name: 'Name',
usedPercent: '{percent}% Used', usedPercent: '{percent}% Used',
noConfigNeeded: 'This storage type does not require configuration, please configure the directory directly!', noConfigNeeded: 'This storage type does not require configuration, please configure the directory directly!',
notConfigured: 'Not Configured', notConfigured: 'Not Configured',
+1
View File
@@ -724,6 +724,7 @@ export default {
episode: '第{number}集', episode: '第{number}集',
}, },
storage: { storage: {
name: '名称',
usedPercent: '已使用 {percent}%', usedPercent: '已使用 {percent}%',
noConfigNeeded: '此存储类型无需配置参数,请直接配置目录!', noConfigNeeded: '此存储类型无需配置参数,请直接配置目录!',
notConfigured: '未配置', notConfigured: '未配置',
+1
View File
@@ -725,6 +725,7 @@ export default {
episode: '第{number}集', episode: '第{number}集',
}, },
storage: { storage: {
name: '名稱',
usedPercent: '已使用 {percent}%', usedPercent: '已使用 {percent}%',
noConfigNeeded: '此存儲類型無需配置參數,請直接配置目錄!', noConfigNeeded: '此存儲類型無需配置參數,請直接配置目錄!',
notConfigured: '未配置', notConfigured: '未配置',
+10 -7
View File
@@ -102,11 +102,6 @@ async function saveStorages() {
} }
} }
// 修改后生效
async function updatedStorage() {
await loadStorages()
}
// 查询目录 // 查询目录
async function loadDirectories() { async function loadDirectories() {
try { try {
@@ -177,7 +172,7 @@ async function loadMediaCategories() {
// 添加存储 // 添加存储
function addStorage() { function addStorage() {
storages.value.push({ storages.value.push({
name: '自定义存储', name: `${t('storage.custom')} ${storages.value.length + 1}`,
type: 'custom', type: 'custom',
config: {}, config: {},
}) })
@@ -191,6 +186,14 @@ function removeStorage(storage: StorageConf) {
} }
} }
// 更新存储
async function updatedStorage(storage: StorageConf) {
const index = storages.value.indexOf(storage)
if (index > -1) {
storages.value[index] = storage
}
}
// 保存设置 // 保存设置
async function saveSystemSettings(value: any) { async function saveSystemSettings(value: any) {
try { try {
@@ -229,7 +232,7 @@ onMounted(() => {
:component-data="{ 'class': 'grid gap-3 grid-app-card' }" :component-data="{ 'class': 'grid gap-3 grid-app-card' }"
> >
<template #item="{ element }"> <template #item="{ element }">
<StorageCard :storage="element" @done="updatedStorage" @close="removeStorage(element)" /> <StorageCard :storage="element" @close="removeStorage(element)" @done="updatedStorage" />
</template> </template>
</draggable> </draggable>
</VCardText> </VCardText>