mirror of
https://github.com/Kuingsmile/PicList.git
synced 2026-05-06 20:42:57 +08:00
✨ Feature(custom): optimize manage main page
This commit is contained in:
@@ -31,6 +31,7 @@
|
||||
### 🐛 问题修复
|
||||
|
||||
- 修复了管理页面中排序下拉框显示异常的问题
|
||||
- 修复了管理页面图床列表没有正确为当前选中图床高亮的问题
|
||||
- 修复了暗色模式下任务页面的显示问题
|
||||
- 修复了图床设置页面设置为默认图床按钮状态没有及时更新的问题
|
||||
- 修复了预处理设置页面,图床水印独立设置的按钮状态没有及时更新的问题
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
:title="t('pages.configForm.configName')"
|
||||
:placeholder="t('pages.configForm.configNamePlaceholder')"
|
||||
required
|
||||
:class="{ 'border-error!': validationErrors._configName }"
|
||||
@blur="validateForm"
|
||||
@input="clearFieldError('_configName')"
|
||||
/>
|
||||
<template v-if="validationErrors._configName" #extra>
|
||||
@@ -27,24 +29,10 @@
|
||||
:class="{ 'border-error!': validationErrors[item.name] }"
|
||||
:title="item.alias || item.name"
|
||||
:required="item.required || false"
|
||||
:tips="item.tips"
|
||||
@blur="validateForm"
|
||||
@input="clearFieldError(item.name)"
|
||||
>
|
||||
<template #title-extra>
|
||||
<div v-if="showTooltips && item.tips" class="relative">
|
||||
<div
|
||||
class="flex h-[20px] w-[20px] cursor-pointer items-center justify-center rounded-full p-[2px] text-secondary hover:bg-bg-secondary hover:text-accent"
|
||||
@click="toggleTooltip(item.name + index)"
|
||||
>
|
||||
<Info :size="15" />
|
||||
</div>
|
||||
<div
|
||||
v-show="visibleTooltips[item.name + index]"
|
||||
class="absolute top-full left-0 z-1000 max-w-[300px] min-w-[200px] rounded-md border border-border bg-bg-secondary p-3 text-xs leading-[1.4] text-main shadow-lg max-md:max-w-[250px] max-md:min-w-[150px]"
|
||||
v-html="transformMarkdownToHTML(item.tips)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</CustomInput>
|
||||
/>
|
||||
<CustomSwitch
|
||||
v-if="item.type === 'confirm'"
|
||||
v-model="ruleForm[item.name]"
|
||||
@@ -114,8 +102,6 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { cloneDeep, union } from 'lodash-es'
|
||||
import { Info } from 'lucide-vue-next'
|
||||
import { marked } from 'marked'
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRoute } from 'vue-router'
|
||||
@@ -133,10 +119,9 @@ interface IProps {
|
||||
type: 'uploader' | 'transformer' | 'plugin'
|
||||
id: string
|
||||
mode?: 'picbed' | 'plugin'
|
||||
showTooltips?: boolean
|
||||
}
|
||||
|
||||
const { config: configProp, type, id, mode = 'picbed', showTooltips = true } = defineProps<IProps>()
|
||||
const { config: configProp, type, id, mode = 'picbed' } = defineProps<IProps>()
|
||||
|
||||
const $route = useRoute()
|
||||
const { t } = useI18n()
|
||||
@@ -144,7 +129,6 @@ const { t } = useI18n()
|
||||
const configList = ref<IPicGoPluginConfig[]>([])
|
||||
const ruleForm = reactive<IStringKeyMap>({})
|
||||
const validationErrors = reactive<IStringKeyMap>({})
|
||||
const visibleTooltips = reactive<Record<string, boolean>>({})
|
||||
|
||||
// Watch for config changes
|
||||
watch(
|
||||
@@ -197,16 +181,6 @@ function clearFieldError(fieldName: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function toggleTooltip(key: string) {
|
||||
visibleTooltips[key] = !visibleTooltips[key]
|
||||
|
||||
Object.keys(visibleTooltips).forEach(otherKey => {
|
||||
if (otherKey !== key) {
|
||||
visibleTooltips[otherKey] = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function validate(): Promise<IStringKeyMap | false> {
|
||||
return new Promise(resolve => {
|
||||
const isValid = validateForm()
|
||||
@@ -218,14 +192,6 @@ async function validate(): Promise<IStringKeyMap | false> {
|
||||
})
|
||||
}
|
||||
|
||||
function transformMarkdownToHTML(markdown: string) {
|
||||
try {
|
||||
return marked.parse(markdown)
|
||||
} catch (_e) {
|
||||
return markdown
|
||||
}
|
||||
}
|
||||
|
||||
function getConfigType() {
|
||||
switch (type) {
|
||||
case 'plugin': {
|
||||
|
||||
@@ -1,11 +1,24 @@
|
||||
<template>
|
||||
<div class="flex flex-col">
|
||||
<div class="flex items-center gap-2">
|
||||
<label class="mb-2 text-sm font-semibold text-secondary"
|
||||
<div class="mb-1 flex items-center gap-2">
|
||||
<label class="text-sm font-semibold text-secondary"
|
||||
>{{ title }}
|
||||
<span v-if="required" class="ml-1 text-danger">*</span>
|
||||
</label>
|
||||
<slot name="title-extra"></slot>
|
||||
<div v-if="tips" class="relative">
|
||||
<div
|
||||
class="flex h-[20px] w-[20px] cursor-pointer items-center justify-center rounded-full p-[2px] text-secondary hover:bg-bg-secondary hover:text-accent"
|
||||
@click="toggleTooltip()"
|
||||
>
|
||||
<Info :size="16" />
|
||||
</div>
|
||||
<div
|
||||
v-show="visibleTooltips"
|
||||
class="absolute top-full left-0 z-1000 max-w-[300px] min-w-[200px] rounded-md border border-border bg-bg-secondary p-3 text-xs leading-[1.4] text-main shadow-lg max-md:max-w-[250px] max-md:min-w-[150px]"
|
||||
v-html="transformMarkdownToHTML(tips)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative w-full">
|
||||
<input
|
||||
@@ -15,7 +28,6 @@
|
||||
class="box-border w-full rounded-md border border-border bg-bg-tertiary p-3 pr-10 text-sm text-main transition-all duration-200 ease-apple focus:border-accent focus:outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
||||
:placeholder="placeholder"
|
||||
/>
|
||||
|
||||
<button
|
||||
v-if="isPassword"
|
||||
type="button"
|
||||
@@ -31,7 +43,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { EyeClosedIcon, EyeIcon } from 'lucide-vue-next'
|
||||
import { EyeClosedIcon, EyeIcon, Info } from 'lucide-vue-next'
|
||||
import { marked } from 'marked'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
const [modelValue, modifiers] = defineModel<any>({
|
||||
@@ -49,12 +62,14 @@ const [modelValue, modifiers] = defineModel<any>({
|
||||
})
|
||||
|
||||
const type = ref('text')
|
||||
const visibleTooltips = ref(false)
|
||||
|
||||
const {
|
||||
isPassword = false,
|
||||
title,
|
||||
inputType = 'text',
|
||||
placeholder,
|
||||
tips = '',
|
||||
required = false,
|
||||
} = defineProps<{
|
||||
isPassword?: boolean
|
||||
@@ -62,8 +77,21 @@ const {
|
||||
inputType?: string
|
||||
placeholder: string
|
||||
required?: boolean
|
||||
tips?: string
|
||||
}>()
|
||||
|
||||
function toggleTooltip() {
|
||||
visibleTooltips.value = !visibleTooltips.value
|
||||
}
|
||||
|
||||
function transformMarkdownToHTML(markdown: string) {
|
||||
try {
|
||||
return marked.parse(markdown)
|
||||
} catch (_e) {
|
||||
return markdown
|
||||
}
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
class="flex cursor-pointer items-center gap-4 rounded-lg border border-border p-4 transition-all duration-200 ease-apple hover:border-accent"
|
||||
:class="noBorder ? 'border-none' : ''"
|
||||
>
|
||||
<input v-model="modelValue" type="checkbox" class="peer hidden" />
|
||||
<input v-model="modelValue" type="checkbox" class="peer hidden" @change.stop="emit('change', modelValue)" />
|
||||
<span
|
||||
class="bg-linear-180-r relative shrink-0 rounded-full bg-gray-400/80 shadow-sm transition-all duration-medium ease-standard peer-checked:bg-accent peer-checked:shadow-[inset_0_1px_3px_rgba(0,0,0,0.1),0_2px_8px_color-mix(in_srgb,var(--color-accent),transparent_30%)] before:absolute before:rounded-full before:bg-white before:shadow-sm before:transition-all before:duration-200 before:ease-apple before:content-[''] peer-checked:before:translate-x-[24px]"
|
||||
:class="
|
||||
@@ -26,7 +26,7 @@
|
||||
</div>
|
||||
</label>
|
||||
<slot name="title-extra"></slot>
|
||||
<div v-if="showTooltips && tips !== ''" class="relative">
|
||||
<div v-if="tips" class="relative">
|
||||
<div
|
||||
class="flex h-[20px] w-[20px] cursor-pointer items-center justify-center rounded-full p-[2px] text-secondary hover:bg-bg-secondary hover:text-accent"
|
||||
@click="toggleTooltip()"
|
||||
@@ -47,6 +47,8 @@ import { Info } from 'lucide-vue-next'
|
||||
import { marked } from 'marked'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
const emit = defineEmits(['change'])
|
||||
|
||||
const visibleTooltips = ref(false)
|
||||
|
||||
const modelValue = defineModel<boolean>()
|
||||
@@ -55,7 +57,6 @@ const {
|
||||
description = '',
|
||||
noBorder = false,
|
||||
small = false,
|
||||
showTooltips = true,
|
||||
tips = '',
|
||||
required = false,
|
||||
} = defineProps<{
|
||||
@@ -63,7 +64,6 @@ const {
|
||||
title?: string
|
||||
description?: string
|
||||
small?: boolean
|
||||
showTooltips?: boolean
|
||||
tips?: string
|
||||
required?: boolean
|
||||
}>()
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<div
|
||||
v-show="dropDownOpen"
|
||||
ref="optionsRef"
|
||||
class="sort-options fixed z-10 mt-[2px] min-w-[150px] overflow-hidden rounded-md border border-border-secondary bg-bg-tertiary shadow-lg"
|
||||
class="sort-options fixed z-10 mt-[2px] max-h-[200px] min-w-[150px] overflow-hidden overflow-y-auto rounded-md border border-border-secondary bg-bg-tertiary shadow-lg"
|
||||
>
|
||||
<button
|
||||
v-for="key in keyList"
|
||||
|
||||
@@ -521,6 +521,7 @@
|
||||
"noDataDesc": "Please create a bucket or upload images first"
|
||||
},
|
||||
"login": {
|
||||
"aliasExistMsg": "Alias duplicate ",
|
||||
"aliasMsg": "Alias may only contain Chinese characters, letters, numbers, underscores, and hyphens",
|
||||
"configChangeMsg": "Configuration changed",
|
||||
"configSaveMsg": "Configuration saved",
|
||||
|
||||
@@ -521,6 +521,7 @@
|
||||
"noDataDesc": "请先创建存储桶或上传图片"
|
||||
},
|
||||
"login": {
|
||||
"aliasExistMsg": "别名与已有配置重复",
|
||||
"aliasMsg": "别名只能包含中文、英文、数字、下划线和中划线",
|
||||
"configChangeMsg": "配置已更改",
|
||||
"configSaveMsg": "配置已保存",
|
||||
|
||||
@@ -521,6 +521,7 @@
|
||||
"noDataDesc": "請先建立儲存桶或上傳圖片"
|
||||
},
|
||||
"login": {
|
||||
"aliasExistMsg": "別名與已有配置重複",
|
||||
"aliasMsg": "別名只能包含中文、英文、數字、底線和連字號",
|
||||
"configChangeMsg": "設定已變更",
|
||||
"configSaveMsg": "設定已儲存",
|
||||
|
||||
@@ -1263,7 +1263,6 @@ import { marked } from 'marked'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { computed, nextTick, onBeforeMount, onBeforeUnmount, reactive, ref, useTemplateRef, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
import ImageLocal from '@/components/ImageLocal.vue'
|
||||
import ImagePreSign from '@/components/ImagePreSign.vue'
|
||||
@@ -1290,9 +1289,6 @@ import { trimPath } from '@/utils/common'
|
||||
import { IRPCActionType } from '@/utils/enum'
|
||||
import { cancelDownloadLoadingFileList, refreshDownloadFileTransferList } from '@/utils/static'
|
||||
|
||||
const { t } = useI18n()
|
||||
const message = useMessage()
|
||||
const confirm = useConfirm()
|
||||
/*
|
||||
configMap:{
|
||||
prefix: string, -> baseDir
|
||||
@@ -1304,37 +1300,28 @@ configMap:{
|
||||
bucketConfig
|
||||
}
|
||||
*/
|
||||
const getExtension = (fileName: string) => window.node.path.extname(fileName).slice(1)
|
||||
const linkFormatArray = [
|
||||
{ key: 'Url', value: 'url' },
|
||||
{ key: 'Markdown', value: 'markdown' },
|
||||
{ key: 'Markdown-link', value: 'markdown-with-link' },
|
||||
{ key: 'Html', value: 'html' },
|
||||
{ key: 'BBCode', value: 'bbcode' },
|
||||
{ key: 'Custom', value: 'custom' },
|
||||
]
|
||||
const linkFormatList = ['url', 'markdown', 'markdown-with-link', 'html', 'bbcode', 'custom']
|
||||
|
||||
const props = defineProps<{
|
||||
configMap: Record<string, any>
|
||||
}>()
|
||||
|
||||
type ISortTypeList = 'name' | 'size' | 'time' | 'ext' | 'check' | 'init'
|
||||
const sortTypeList = ['name', 'size', 'time', 'ext', 'check', 'init']
|
||||
const currentSortType = ref<ISortTypeList>('name')
|
||||
|
||||
// 路由相关
|
||||
const route = useRoute()
|
||||
let fileTransferInterval: NodeJS.Timeout | undefined
|
||||
let downloadInterval: NodeJS.Timeout | undefined
|
||||
let scrollTimeout: ReturnType<typeof setTimeout> | undefined
|
||||
const { t } = useI18n()
|
||||
const message = useMessage()
|
||||
const confirm = useConfirm()
|
||||
// 页面状态变量相关
|
||||
const manageStore = useManageStore()
|
||||
const configMap = reactive(JSON.parse(route.query.configMap as string))
|
||||
const configMap = ref<Record<string, any>>(JSON.parse(JSON.stringify(props.configMap)))
|
||||
// 页面布局控制
|
||||
const isLoadingData = ref(false)
|
||||
const isShowLoadingPage = ref(false)
|
||||
const isShowImagePreview = ref(false)
|
||||
const layoutStyle = ref<'list' | 'grid'>('grid')
|
||||
// Refs for scroll handling
|
||||
const virtualScrollerRef = useTemplateRef('virtualScrollerRef')
|
||||
const bucketContainerRef = useTemplateRef('bucketContainerRef')
|
||||
// 全屏控制变量
|
||||
const isContentFullscreen = ref(false)
|
||||
// 新增的UI控制变量
|
||||
const layoutStyle = ref<'list' | 'grid'>('grid')
|
||||
const copyDropdownOpen = ref(false)
|
||||
const sortDropdownOpen = ref(false)
|
||||
const copyDropdownIndex = ref(-1)
|
||||
@@ -1376,57 +1363,26 @@ const uploadPanelFilesList = ref([] as any[])
|
||||
const cancelToken = ref('')
|
||||
const isLoadingUploadPanelFiles = ref(false)
|
||||
const isUploadKeepDirStructure = ref(manageStore.config.settings.isUploadKeepDirStructure ?? true)
|
||||
const uploadingTaskList = computed(() =>
|
||||
uploadTaskList.value.filter(item => ['uploading', 'queuing', 'paused'].includes(item.status)),
|
||||
)
|
||||
const uploadedTaskList = computed(() =>
|
||||
uploadTaskList.value.filter(item => ['uploaded', 'failed', 'canceled'].includes(item.status)),
|
||||
)
|
||||
const currentSortType = ref<ISortTypeList>('name')
|
||||
// 下载页面相关
|
||||
const isShowDownloadPanel = ref(false)
|
||||
const isLoadingDownloadData = ref(false)
|
||||
const activeDownLoadTab = ref('downloading')
|
||||
const currentDownloadFileList = reactive([] as any[])
|
||||
const downloadTaskList = ref([] as IDownloadTask[])
|
||||
|
||||
const refreshDownloadTaskId = ref<NodeJS.Timeout | undefined>(undefined)
|
||||
const downloadCancelToken = ref('')
|
||||
const downloadingTaskList = computed(() =>
|
||||
downloadTaskList.value.filter(item => ['downloading', 'queuing', 'paused'].includes(item.status)),
|
||||
)
|
||||
const downloadedTaskList = computed(() =>
|
||||
downloadTaskList.value.filter(item => ['downloaded', 'failed', 'canceled'].includes(item.status)),
|
||||
)
|
||||
// 上传文件相关
|
||||
const dialogVisible = ref(false)
|
||||
const urlToUpload = ref('')
|
||||
// 图片预览相关
|
||||
const previewedImage = ref('')
|
||||
const filterList = computed(() => {
|
||||
return getList()
|
||||
})
|
||||
const selectedItems = computed(() => filterList.value.filter(item => item.checked))
|
||||
|
||||
const ImagePreviewList = computed(() => filterList.value.filter(item => item.isImage).map(item => item.url))
|
||||
|
||||
const getCurrentPreviewIndex = computed(() => ImagePreviewList.value.indexOf(previewedImage.value))
|
||||
// 快捷键相关
|
||||
const isShiftKeyPress = ref<boolean>(false)
|
||||
const lastChoosed = ref<number>(-1)
|
||||
// 自定义域名相关
|
||||
const customDomainList = ref([] as any[])
|
||||
const currentCustomDomain = ref('')
|
||||
const isShowCustomDomainSelectList = computed(() =>
|
||||
['tcyun', 'aliyun', 'qiniu', 'github'].includes(currentPicBedName.value),
|
||||
)
|
||||
const isShowCustomDomainInput = computed(() =>
|
||||
['aliyun', 'qiniu', 'tcyun', 's3plist', 'webdavplist', 'local', 'sftp'].includes(currentPicBedName.value),
|
||||
)
|
||||
const isAutoCustomDomain = computed(() =>
|
||||
manageStore.config.picBed[configMap.alias].isAutoCustomUrl === undefined
|
||||
? true
|
||||
: manageStore.config.picBed[configMap.alias].isAutoCustomUrl,
|
||||
)
|
||||
const refreshDownloadTaskId = ref<NodeJS.Timeout | undefined>(undefined)
|
||||
const downloadCancelToken = ref('')
|
||||
// 文件预览相关
|
||||
const isShowMarkDownDialog = ref(false)
|
||||
const markDownContent = ref('')
|
||||
@@ -1439,25 +1395,73 @@ const videoPlayerHeaders = ref({})
|
||||
const isShowCreateFolderDialog = ref(false)
|
||||
const newFolderName = ref('')
|
||||
const folderNameInput = useTemplateRef('folderNameInput')
|
||||
// 重命名相关
|
||||
const isShowRenameFileIcon = computed(() =>
|
||||
['tcyun', 'aliyun', 'qiniu', 'upyun', 's3plist', 'webdavplist', 'local', 'sftp'].includes(currentPicBedName.value),
|
||||
)
|
||||
// Refs for scroll handling
|
||||
const virtualScrollerRef = useTemplateRef('virtualScrollerRef')
|
||||
const bucketContainerRef = useTemplateRef('bucketContainerRef')
|
||||
const isShowBatchRenameDialog = ref(false)
|
||||
const batchRenameMatch = ref('')
|
||||
const batchRenameReplace = ref('')
|
||||
const isRenameIncludeExt = ref(false)
|
||||
const isSingleRename = ref(false)
|
||||
const itemToBeRenamed = ref({} as any)
|
||||
const previousPageNumber = ref(1)
|
||||
|
||||
let fileTransferInterval: NodeJS.Timeout | undefined
|
||||
const linkFormatArray = [
|
||||
{ key: 'Url', value: 'url' },
|
||||
{ key: 'Markdown', value: 'markdown' },
|
||||
{ key: 'Markdown-link', value: 'markdown-with-link' },
|
||||
{ key: 'Html', value: 'html' },
|
||||
{ key: 'BBCode', value: 'bbcode' },
|
||||
{ key: 'Custom', value: 'custom' },
|
||||
]
|
||||
const linkFormatList = ['url', 'markdown', 'markdown-with-link', 'html', 'bbcode', 'custom']
|
||||
const sortTypeList = ['name', 'size', 'time', 'ext', 'check', 'init']
|
||||
|
||||
let downloadInterval: NodeJS.Timeout | undefined
|
||||
const uploadingTaskList = computed(() =>
|
||||
uploadTaskList.value.filter(item => ['uploading', 'queuing', 'paused'].includes(item.status)),
|
||||
)
|
||||
const uploadedTaskList = computed(() =>
|
||||
uploadTaskList.value.filter(item => ['uploaded', 'failed', 'canceled'].includes(item.status)),
|
||||
)
|
||||
|
||||
const downloadingTaskList = computed(() =>
|
||||
downloadTaskList.value.filter(item => ['downloading', 'queuing', 'paused'].includes(item.status)),
|
||||
)
|
||||
const downloadedTaskList = computed(() =>
|
||||
downloadTaskList.value.filter(item => ['downloaded', 'failed', 'canceled'].includes(item.status)),
|
||||
)
|
||||
|
||||
const filterList = computed(() => {
|
||||
return getList()
|
||||
})
|
||||
|
||||
const selectedItems = computed(() => filterList.value.filter(item => item.checked))
|
||||
|
||||
const ImagePreviewList = computed(() => filterList.value.filter(item => item.isImage).map(item => item.url))
|
||||
|
||||
const getCurrentPreviewIndex = computed(() => ImagePreviewList.value.indexOf(previewedImage.value))
|
||||
|
||||
const isShowCustomDomainSelectList = computed(() =>
|
||||
['tcyun', 'aliyun', 'qiniu', 'github'].includes(currentPicBedName.value),
|
||||
)
|
||||
const isShowCustomDomainInput = computed(() =>
|
||||
['aliyun', 'qiniu', 'tcyun', 's3plist', 'webdavplist', 'local', 'sftp'].includes(currentPicBedName.value),
|
||||
)
|
||||
const isAutoCustomDomain = computed(() =>
|
||||
manageStore.config.picBed[configMap.value.alias].isAutoCustomUrl === undefined
|
||||
? true
|
||||
: manageStore.config.picBed[configMap.value.alias].isAutoCustomUrl,
|
||||
)
|
||||
|
||||
// 重命名相关
|
||||
const isShowRenameFileIcon = computed(() =>
|
||||
['tcyun', 'aliyun', 'qiniu', 'upyun', 's3plist', 'webdavplist', 'local', 'sftp'].includes(currentPicBedName.value),
|
||||
)
|
||||
|
||||
// 当前页面信息相关
|
||||
const currentPicBedName = computed<string>(() => manageStore.config.picBed[configMap.alias].picBedName)
|
||||
const paging = computed(() => manageStore.config.picBed[configMap.alias].paging)
|
||||
const itemsPerPage = computed(() => manageStore.config.picBed[configMap.alias].itemsPerPage)
|
||||
const currentPicBedName = computed<string>(() => manageStore.config.picBed[configMap.value.alias].picBedName)
|
||||
const paging = computed(() => manageStore.config.picBed[configMap.value.alias].paging)
|
||||
const itemsPerPage = computed(() => manageStore.config.picBed[configMap.value.alias].itemsPerPage)
|
||||
const calculateAllFileSize = computed(
|
||||
() =>
|
||||
formatFileSize(currentPageFilesInfo.reduce((total: any, item: { fileSize: any }) => total + item.fileSize, 0)) ||
|
||||
@@ -1479,6 +1483,56 @@ const isShowPresignedUrl = computed(() =>
|
||||
['aliyun', 'github', 'qiniu', 's3plist', 'tcyun', 'webdavplist'].includes(currentPicBedName.value),
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.configMap,
|
||||
async newValue => {
|
||||
isShowLoadingPage.value = true
|
||||
configMap.value = JSON.parse(JSON.stringify(newValue))
|
||||
await initCustomDomainList()
|
||||
await resetParam(true)
|
||||
await manageStore.refreshConfig()
|
||||
isShowLoadingPage.value = false
|
||||
},
|
||||
{ deep: true, immediate: true },
|
||||
)
|
||||
|
||||
watch(currentPageNumber, (newVal, oldVal) => {
|
||||
if (typeof newVal !== 'number') {
|
||||
currentPageNumber.value = 1
|
||||
}
|
||||
// Update previousPageNumber when currentPageNumber changes programmatically
|
||||
if (oldVal && typeof oldVal === 'number') {
|
||||
previousPageNumber.value = oldVal
|
||||
}
|
||||
})
|
||||
|
||||
// Watch upload panel visibility to start/stop refresh task
|
||||
watch(isShowUploadPanel, newValue => {
|
||||
if (newValue) {
|
||||
startRefreshUploadTask()
|
||||
} else {
|
||||
stopRefreshUploadTask()
|
||||
}
|
||||
})
|
||||
|
||||
// Watch download panel visibility to start/stop refresh task
|
||||
watch(isShowDownloadPanel, newValue => {
|
||||
if (newValue) {
|
||||
startRefreshDownloadTask()
|
||||
} else {
|
||||
stopRefreshDownloadTask()
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => manageStore.config.settings.isUploadKeepDirStructure,
|
||||
newValue => {
|
||||
isUploadKeepDirStructure.value = newValue ?? true
|
||||
},
|
||||
)
|
||||
|
||||
const getExtension = (fileName: string) => window.node.path.extname(fileName).slice(1)
|
||||
|
||||
function getList() {
|
||||
if (!searchText.value) {
|
||||
return currentPageFilesInfo
|
||||
@@ -1492,8 +1546,6 @@ function getList() {
|
||||
})
|
||||
}
|
||||
|
||||
// 上传相关函数
|
||||
|
||||
function handleUploadKeepDirChange() {
|
||||
saveConfig('settings.isUploadKeepDirStructure', isUploadKeepDirStructure.value)
|
||||
manageStore.refreshConfig()
|
||||
@@ -1516,7 +1568,7 @@ function stopRefreshUploadTask() {
|
||||
}
|
||||
|
||||
function handleGetWebdavConfig() {
|
||||
return manageStore.config.picBed[configMap.alias]
|
||||
return manageStore.config.picBed[configMap.value.alias]
|
||||
}
|
||||
|
||||
// 下载相关函数
|
||||
@@ -1550,7 +1602,6 @@ function toggleContentFullscreen() {
|
||||
isContentFullscreen.value = !isContentFullscreen.value
|
||||
}
|
||||
|
||||
let scrollTimeout: ReturnType<typeof setTimeout> | undefined
|
||||
function handleBucketContainerScroll() {
|
||||
if (scrollTimeout) {
|
||||
clearTimeout(scrollTimeout)
|
||||
@@ -1760,18 +1811,18 @@ function uploadFiles() {
|
||||
}
|
||||
formateduploadPanelFilesList.forEach((item: any) => {
|
||||
param.fileArray.push({
|
||||
alias: configMap.alias,
|
||||
bucketName: configMap.bucketName,
|
||||
region: configMap.bucketConfig.Location,
|
||||
alias: configMap.value.alias,
|
||||
bucketName: configMap.value.bucketName,
|
||||
region: configMap.value.bucketConfig.Location,
|
||||
key: item.key,
|
||||
filePath: item.path,
|
||||
fileSize: item.size,
|
||||
fileName: item.rawName,
|
||||
githubBranch: currentCustomDomain.value,
|
||||
aclForUpload: manageStore.config.picBed[configMap.alias].aclForUpload,
|
||||
aclForUpload: manageStore.config.picBed[configMap.value.alias].aclForUpload,
|
||||
})
|
||||
})
|
||||
window.electron.sendRPC(IRPCActionType.MANAGE_UPLOAD_BUCKET_FILE, configMap.alias, param)
|
||||
window.electron.sendRPC(IRPCActionType.MANAGE_UPLOAD_BUCKET_FILE, configMap.value.alias, param)
|
||||
}
|
||||
|
||||
function handleCopyUploadingTaskInfo() {
|
||||
@@ -1827,7 +1878,7 @@ async function handleBreadcrumbClick(index: number) {
|
||||
isLoadingData.value = false
|
||||
window.electron.sendToMain('cancelLoadingFileList', cancelToken.value)
|
||||
}
|
||||
configMap.prefix = targetPrefix
|
||||
configMap.value.prefix = targetPrefix
|
||||
isShowLoadingPage.value = true
|
||||
resetParam(false)
|
||||
isShowLoadingPage.value = false
|
||||
@@ -1837,7 +1888,7 @@ async function handleClickFile(item: any) {
|
||||
const options = {} as any
|
||||
if (currentPicBedName.value === 'webdavplist') {
|
||||
options.headers = {
|
||||
Authorization: `Basic ${window.node.buffer.from(`${manageStore.config.picBed[configMap.alias].username}:${manageStore.config.picBed[configMap.alias].password}`).toString('base64')}`,
|
||||
Authorization: `Basic ${window.node.buffer.from(`${manageStore.config.picBed[configMap.value.alias].username}:${manageStore.config.picBed[configMap.value.alias].password}`).toString('base64')}`,
|
||||
}
|
||||
}
|
||||
if (item.isImage) {
|
||||
@@ -1848,7 +1899,7 @@ async function handleClickFile(item: any) {
|
||||
isLoadingData.value = false
|
||||
window.electron.sendToMain('cancelLoadingFileList', cancelToken.value)
|
||||
}
|
||||
configMap.prefix = `/${item.key}`
|
||||
configMap.value.prefix = `/${item.key}`
|
||||
isShowLoadingPage.value = true
|
||||
await resetParam(false)
|
||||
isShowLoadingPage.value = false
|
||||
@@ -1892,17 +1943,17 @@ async function handleChangeCustomUrlInput() {
|
||||
async function handleChangeCustomUrl() {
|
||||
if (['aliyun', 'tcyun', 'qiniu', 's3plist', 'webdavplist', 'local', 'sftp'].includes(currentPicBedName.value)) {
|
||||
const currentConfigs = await getConfig<any>('picBed')
|
||||
const currentConfig = currentConfigs[configMap.alias]
|
||||
const currentConfig = currentConfigs[configMap.value.alias]
|
||||
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
||||
if (currentTransformedConfig[configMap.bucketName]) {
|
||||
currentTransformedConfig[configMap.bucketName].customUrl = currentCustomDomain.value
|
||||
if (currentTransformedConfig[configMap.value.bucketName]) {
|
||||
currentTransformedConfig[configMap.value.bucketName].customUrl = currentCustomDomain.value
|
||||
} else {
|
||||
currentTransformedConfig[configMap.bucketName] = {
|
||||
currentTransformedConfig[configMap.value.bucketName] = {
|
||||
customUrl: currentCustomDomain.value,
|
||||
}
|
||||
}
|
||||
currentConfig.transformedConfig = JSON.stringify(currentTransformedConfig)
|
||||
saveConfig(`picBed.${configMap.alias}`, currentConfig)
|
||||
saveConfig(`picBed.${configMap.value.alias}`, currentConfig)
|
||||
await manageStore.refreshConfig()
|
||||
}
|
||||
}
|
||||
@@ -1911,23 +1962,27 @@ async function handleChangeCustomUrl() {
|
||||
async function initCustomDomainList() {
|
||||
if (
|
||||
(['aliyun', 'tcyun', 'qiniu'].includes(currentPicBedName.value) &&
|
||||
(manageStore.config.picBed[configMap.alias].isAutoCustomUrl === undefined ||
|
||||
manageStore.config.picBed[configMap.alias].isAutoCustomUrl === true)) ||
|
||||
(manageStore.config.picBed[configMap.value.alias].isAutoCustomUrl === undefined ||
|
||||
manageStore.config.picBed[configMap.value.alias].isAutoCustomUrl === true)) ||
|
||||
['github', 'smms', 'upyun', 'imgur'].includes(currentPicBedName.value)
|
||||
) {
|
||||
const param = {
|
||||
bucketName: configMap.bucketName,
|
||||
region: configMap.bucketConfig.Location,
|
||||
bucketName: configMap.value.bucketName,
|
||||
region: configMap.value.bucketConfig.Location,
|
||||
}
|
||||
let defaultUrl = ''
|
||||
if (currentPicBedName.value === 'tcyun') {
|
||||
defaultUrl = `https://${configMap.bucketName}.cos.${configMap.bucketConfig.Location}.myqcloud.com`
|
||||
defaultUrl = `https://${configMap.value.bucketName}.cos.${configMap.value.bucketConfig.Location}.myqcloud.com`
|
||||
} else if (currentPicBedName.value === 'aliyun') {
|
||||
defaultUrl = `https://${configMap.bucketName}.${configMap.bucketConfig.Location}.aliyuncs.com`
|
||||
defaultUrl = `https://${configMap.value.bucketName}.${configMap.value.bucketConfig.Location}.aliyuncs.com`
|
||||
} else if (currentPicBedName.value === 'github') {
|
||||
defaultUrl = 'main'
|
||||
}
|
||||
const res = await window.electron.triggerRPC<any>(IRPCActionType.MANAGE_GET_BUCKET_DOMAIN, configMap.alias, param)
|
||||
const res = await window.electron.triggerRPC<any>(
|
||||
IRPCActionType.MANAGE_GET_BUCKET_DOMAIN,
|
||||
configMap.value.alias,
|
||||
param,
|
||||
)
|
||||
if (res.length > 0) {
|
||||
customDomainList.value.length = 0
|
||||
res.forEach((item: any) => {
|
||||
@@ -1958,49 +2013,52 @@ async function initCustomDomainList() {
|
||||
}
|
||||
} else if (['aliyun', 'tcyun', 'qiniu'].includes(currentPicBedName.value)) {
|
||||
const currentConfigs = await getConfig<any>('picBed')
|
||||
const currentConfig = currentConfigs[configMap.alias]
|
||||
const currentConfig = currentConfigs[configMap.value.alias]
|
||||
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
||||
if (currentTransformedConfig[configMap.bucketName]) {
|
||||
currentCustomDomain.value = currentTransformedConfig[configMap.bucketName].customUrl ?? ''
|
||||
if (currentTransformedConfig[configMap.value.bucketName]) {
|
||||
currentCustomDomain.value = currentTransformedConfig[configMap.value.bucketName].customUrl ?? ''
|
||||
} else {
|
||||
currentCustomDomain.value = ''
|
||||
}
|
||||
} else if (currentPicBedName.value === 's3plist') {
|
||||
const currentConfigs = await getConfig<any>('picBed')
|
||||
const currentConfig = currentConfigs[configMap.alias]
|
||||
const currentConfig = currentConfigs[configMap.value.alias]
|
||||
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
||||
if (currentTransformedConfig[configMap.bucketName]) {
|
||||
currentCustomDomain.value = currentTransformedConfig[configMap.bucketName].customUrl ?? ''
|
||||
if (currentTransformedConfig[configMap.value.bucketName]) {
|
||||
currentCustomDomain.value = currentTransformedConfig[configMap.value.bucketName].customUrl ?? ''
|
||||
} else {
|
||||
if (manageStore.config.picBed[configMap.alias].endpoint) {
|
||||
const endpoint = manageStore.config.picBed[configMap.alias].endpoint
|
||||
const s3ForcePathStyle = manageStore.config.picBed[configMap.alias].s3ForcePathStyle
|
||||
if (manageStore.config.picBed[configMap.value.alias].endpoint) {
|
||||
const endpoint = manageStore.config.picBed[configMap.value.alias].endpoint
|
||||
const s3ForcePathStyle = manageStore.config.picBed[configMap.value.alias].s3ForcePathStyle
|
||||
let url
|
||||
if (/^https?:\/\//.test(endpoint)) {
|
||||
url = new URL(endpoint)
|
||||
} else {
|
||||
url = new URL(
|
||||
manageStore.config.picBed[configMap.alias].sslEnabled ? `https://${endpoint}` : `http://${endpoint}`,
|
||||
manageStore.config.picBed[configMap.value.alias].sslEnabled ? `https://${endpoint}` : `http://${endpoint}`,
|
||||
)
|
||||
}
|
||||
if (s3ForcePathStyle) {
|
||||
currentCustomDomain.value = `${url.protocol}//${url.hostname}${url.port ? ':' + url.port : ''}/${configMap.bucketName}`
|
||||
currentCustomDomain.value = `${url.protocol}//${url.hostname}${url.port ? ':' + url.port : ''}/${configMap.value.bucketName}`
|
||||
} else {
|
||||
currentCustomDomain.value = `${url.protocol}//${configMap.bucketName}.${url.hostname}${url.port ? ':' + url.port : ''}`
|
||||
currentCustomDomain.value = `${url.protocol}//${configMap.value.bucketName}.${url.hostname}${url.port ? ':' + url.port : ''}`
|
||||
}
|
||||
} else {
|
||||
currentCustomDomain.value = `https://${configMap.bucketName}.s3.amazonaws.com`
|
||||
currentCustomDomain.value = `https://${configMap.value.bucketName}.s3.amazonaws.com`
|
||||
}
|
||||
}
|
||||
await handleChangeCustomUrl()
|
||||
} else if (currentPicBedName.value === 'webdavplist') {
|
||||
const currentConfigs = await getConfig<any>('picBed')
|
||||
const currentConfig = currentConfigs[configMap.alias]
|
||||
const currentConfig = currentConfigs[configMap.value.alias]
|
||||
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
||||
if (currentTransformedConfig[configMap.bucketName] && currentTransformedConfig[configMap.bucketName]?.customUrl) {
|
||||
currentCustomDomain.value = currentTransformedConfig[configMap.bucketName].customUrl
|
||||
if (
|
||||
currentTransformedConfig[configMap.value.bucketName] &&
|
||||
currentTransformedConfig[configMap.value.bucketName]?.customUrl
|
||||
) {
|
||||
currentCustomDomain.value = currentTransformedConfig[configMap.value.bucketName].customUrl
|
||||
} else {
|
||||
let endpoint = manageStore.config.picBed[configMap.alias].endpoint
|
||||
let endpoint = manageStore.config.picBed[configMap.value.alias].endpoint
|
||||
if (!/^https?:\/\//.test(endpoint)) {
|
||||
endpoint = 'http://' + endpoint
|
||||
}
|
||||
@@ -2009,10 +2067,13 @@ async function initCustomDomainList() {
|
||||
await handleChangeCustomUrl()
|
||||
} else if (currentPicBedName.value === 'local' || currentPicBedName.value === 'sftp') {
|
||||
const currentConfigs = await getConfig<any>('picBed')
|
||||
const currentConfig = currentConfigs[configMap.alias]
|
||||
const currentConfig = currentConfigs[configMap.value.alias]
|
||||
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
||||
if (currentTransformedConfig[configMap.bucketName] && currentTransformedConfig[configMap.bucketName]?.customUrl) {
|
||||
currentCustomDomain.value = currentTransformedConfig[configMap.bucketName].customUrl ?? ''
|
||||
if (
|
||||
currentTransformedConfig[configMap.value.bucketName] &&
|
||||
currentTransformedConfig[configMap.value.bucketName]?.customUrl
|
||||
) {
|
||||
currentCustomDomain.value = currentTransformedConfig[configMap.value.bucketName].customUrl ?? ''
|
||||
if (manageStore.config.settings.isForceCustomUrlHttps && currentCustomDomain.value.startsWith('http://')) {
|
||||
currentCustomDomain.value = currentCustomDomain.value.replace('http://', 'https://')
|
||||
}
|
||||
@@ -2036,7 +2097,7 @@ async function resetParam(force: boolean = false) {
|
||||
}
|
||||
cancelToken.value = ''
|
||||
pagingMarker.value = ''
|
||||
currentPrefix.value = configMap.prefix
|
||||
currentPrefix.value = configMap.value.prefix
|
||||
currentPageNumber.value = 1
|
||||
currentPageFilesInfo.length = 0
|
||||
currentDownloadFileList.length = 0
|
||||
@@ -2085,18 +2146,6 @@ async function resetParam(force: boolean = false) {
|
||||
}
|
||||
}
|
||||
|
||||
watch(route, async newRoute => {
|
||||
const queryConfigMap = newRoute.query.configMap as string
|
||||
if (queryConfigMap) {
|
||||
isShowLoadingPage.value = true
|
||||
const parsedConfigMap = JSON.parse(queryConfigMap)
|
||||
Object.assign(configMap, parsedConfigMap)
|
||||
await initCustomDomainList()
|
||||
await resetParam(true)
|
||||
isShowLoadingPage.value = false
|
||||
}
|
||||
})
|
||||
|
||||
async function forceRefreshFileList() {
|
||||
if (isLoadingData.value) {
|
||||
message.error(t('pages.manage.bucket.isLoadingMsg'))
|
||||
@@ -2107,16 +2156,6 @@ async function forceRefreshFileList() {
|
||||
isShowLoadingPage.value = false
|
||||
}
|
||||
|
||||
watch(currentPageNumber, (newVal, oldVal) => {
|
||||
if (typeof newVal !== 'number') {
|
||||
currentPageNumber.value = 1
|
||||
}
|
||||
// Update previousPageNumber when currentPageNumber changes programmatically
|
||||
if (oldVal && typeof oldVal === 'number') {
|
||||
previousPageNumber.value = oldVal
|
||||
}
|
||||
})
|
||||
|
||||
const changePage = async (cur: number | undefined, prev: number | undefined) => {
|
||||
if (!cur || !prev) {
|
||||
currentPageNumber.value = 1
|
||||
@@ -2161,33 +2200,6 @@ const changePage = async (cur: number | undefined, prev: number | undefined) =>
|
||||
}
|
||||
}
|
||||
|
||||
// Watch upload panel visibility to start/stop refresh task
|
||||
watch(isShowUploadPanel, newValue => {
|
||||
if (newValue) {
|
||||
startRefreshUploadTask()
|
||||
} else {
|
||||
stopRefreshUploadTask()
|
||||
}
|
||||
})
|
||||
|
||||
// Watch download panel visibility to start/stop refresh task
|
||||
watch(isShowDownloadPanel, newValue => {
|
||||
if (newValue) {
|
||||
startRefreshDownloadTask()
|
||||
} else {
|
||||
stopRefreshDownloadTask()
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => manageStore.config.settings.isUploadKeepDirStructure,
|
||||
newValue => {
|
||||
isUploadKeepDirStructure.value = newValue ?? true
|
||||
},
|
||||
)
|
||||
|
||||
const previousPageNumber = ref(1)
|
||||
|
||||
const handlePageNumberInput = async (event: Event) => {
|
||||
const target = event.target as HTMLInputElement
|
||||
const value = parseInt(target.value, 10)
|
||||
@@ -2294,9 +2306,9 @@ async function handleFolderBatchDownload(item: any) {
|
||||
cancelToken.value = uuidv4()
|
||||
const paramGet = {
|
||||
// tcyun
|
||||
bucketName: configMap.bucketName,
|
||||
bucketName: configMap.value.bucketName,
|
||||
bucketConfig: {
|
||||
Location: configMap.bucketConfig.Location,
|
||||
Location: configMap.value.bucketConfig.Location,
|
||||
},
|
||||
paging: paging.value,
|
||||
prefix: `/${item.key.replace(/^\/+|\/+$/, '')}/`,
|
||||
@@ -2305,12 +2317,12 @@ async function handleFolderBatchDownload(item: any) {
|
||||
customUrl: currentCustomDomain.value,
|
||||
currentPage: currentPageNumber.value,
|
||||
cancelToken: cancelToken.value,
|
||||
cdnUrl: configMap.cdnUrl,
|
||||
cdnUrl: configMap.value.cdnUrl,
|
||||
}
|
||||
isLoadingDownloadData.value = true
|
||||
const downloadFileTransferStore = useDownloadFileTransferStore()
|
||||
downloadFileTransferStore.resetDownloadFileTransferList()
|
||||
window.electron.sendRPC(IRPCActionType.MANAGE_GET_BUCKET_LIST_RECURSIVELY, configMap.alias, paramGet)
|
||||
window.electron.sendRPC(IRPCActionType.MANAGE_GET_BUCKET_LIST_RECURSIVELY, configMap.value.alias, paramGet)
|
||||
window.electron.ipcRendererOn(refreshDownloadFileTransferList, data => {
|
||||
downloadFileTransferStore.refreshDownloadFileTransferList(data)
|
||||
})
|
||||
@@ -2326,9 +2338,9 @@ async function handleFolderBatchDownload(item: any) {
|
||||
if (currentDownloadFileList.length) {
|
||||
currentDownloadFileList.forEach((item: any) => {
|
||||
param.fileArray.push({
|
||||
alias: configMap.alias,
|
||||
bucketName: configMap.bucketName,
|
||||
region: configMap.bucketConfig.Location,
|
||||
alias: configMap.value.alias,
|
||||
bucketName: configMap.value.bucketName,
|
||||
region: configMap.value.bucketConfig.Location,
|
||||
key: item.key,
|
||||
fileName: [undefined, true].includes(manageStore.config.settings.isDownloadFolderKeepDirStructure)
|
||||
? `/${item.key.replace(/^\/+|\/+$/, '')}`
|
||||
@@ -2336,11 +2348,11 @@ async function handleFolderBatchDownload(item: any) {
|
||||
customUrl: currentCustomDomain.value,
|
||||
downloadUrl: item.downloadUrl,
|
||||
githubUrl: item.url,
|
||||
githubPrivate: configMap.bucketConfig.private,
|
||||
githubPrivate: configMap.value.bucketConfig.private,
|
||||
})
|
||||
})
|
||||
}
|
||||
window.electron.sendRPC(IRPCActionType.MANAGE_DOWNLOAD_BUCKET_FILE, configMap.alias, param)
|
||||
window.electron.sendRPC(IRPCActionType.MANAGE_DOWNLOAD_BUCKET_FILE, configMap.value.alias, param)
|
||||
isShowDownloadPanel.value = true
|
||||
} else {
|
||||
message.error(t('pages.manage.bucket.getDownloadListFailed'))
|
||||
@@ -2367,9 +2379,9 @@ async function handleBatchDownload() {
|
||||
selectedItems.value.forEach((item: any) => {
|
||||
if (!item.isDir) {
|
||||
param.fileArray.push({
|
||||
alias: configMap.alias,
|
||||
bucketName: configMap.bucketName,
|
||||
region: configMap.bucketConfig.Location,
|
||||
alias: configMap.value.alias,
|
||||
bucketName: configMap.value.bucketName,
|
||||
region: configMap.value.bucketConfig.Location,
|
||||
key: item.key,
|
||||
fileName: manageStore.config.settings.isDownloadFileKeepDirStructure
|
||||
? `/${item.key.replace(/^\/+|\/+$/, '')}`
|
||||
@@ -2377,11 +2389,11 @@ async function handleBatchDownload() {
|
||||
customUrl: currentCustomDomain.value,
|
||||
downloadUrl: item.downloadUrl,
|
||||
githubUrl: item.url,
|
||||
githubPrivate: configMap.bucketConfig.private,
|
||||
githubPrivate: configMap.value.bucketConfig.private,
|
||||
})
|
||||
}
|
||||
})
|
||||
window.electron.sendRPC(IRPCActionType.MANAGE_DOWNLOAD_BUCKET_FILE, configMap.alias, param)
|
||||
window.electron.sendRPC(IRPCActionType.MANAGE_DOWNLOAD_BUCKET_FILE, configMap.value.alias, param)
|
||||
handleCancelCheck()
|
||||
isShowDownloadPanel.value = true
|
||||
}
|
||||
@@ -2415,14 +2427,14 @@ async function confirmCreateFolder() {
|
||||
formatedPath = trimPath(formatedPath)
|
||||
const param = {
|
||||
// tcyun
|
||||
bucketName: configMap.bucketName,
|
||||
region: configMap.bucketConfig.Location,
|
||||
bucketName: configMap.value.bucketName,
|
||||
region: configMap.value.bucketConfig.Location,
|
||||
key: currentPrefix.value.slice(1) + formatedPath + '/',
|
||||
githubBranch: currentCustomDomain.value,
|
||||
}
|
||||
const res = await window.electron.triggerRPC<any>(
|
||||
IRPCActionType.MANAGE_CREATE_BUCKET_FOLDER,
|
||||
configMap.alias,
|
||||
configMap.value.alias,
|
||||
param,
|
||||
)
|
||||
if (res) {
|
||||
@@ -2540,14 +2552,14 @@ async function BatchRename() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const param = {
|
||||
// tcyun
|
||||
bucketName: configMap.bucketName,
|
||||
region: configMap.bucketConfig.Location,
|
||||
bucketName: configMap.value.bucketName,
|
||||
region: configMap.value.bucketConfig.Location,
|
||||
oldKey: item.key,
|
||||
newKey: (item.key.slice(0, item.key.lastIndexOf('/') + 1) + item.newName).replaceAll('//', '/'),
|
||||
customUrl: currentCustomDomain.value,
|
||||
}
|
||||
window.electron
|
||||
.triggerRPC<any>(IRPCActionType.MANAGE_RENAME_BUCKET_FILE, configMap.alias, param)
|
||||
.triggerRPC<any>(IRPCActionType.MANAGE_RENAME_BUCKET_FILE, configMap.value.alias, param)
|
||||
.then((res: any) => {
|
||||
if (res) {
|
||||
successCount++
|
||||
@@ -2714,9 +2726,9 @@ async function getBucketFileListBackStage() {
|
||||
cancelToken.value = uuidv4()
|
||||
const param = {
|
||||
// tcyun
|
||||
bucketName: configMap.bucketName,
|
||||
bucketName: configMap.value.bucketName,
|
||||
bucketConfig: {
|
||||
Location: configMap.bucketConfig.Location,
|
||||
Location: configMap.value.bucketConfig.Location,
|
||||
},
|
||||
paging: paging.value,
|
||||
prefix: currentPrefix.value,
|
||||
@@ -2725,17 +2737,17 @@ async function getBucketFileListBackStage() {
|
||||
customUrl: currentCustomDomain.value,
|
||||
currentPage: currentPageNumber.value,
|
||||
cancelToken: cancelToken.value,
|
||||
cdnUrl: configMap.cdnUrl,
|
||||
cdnUrl: configMap.value.cdnUrl,
|
||||
} as IStringKeyMap
|
||||
isLoadingData.value = true
|
||||
const fileTransferStore = useFileTransferStore()
|
||||
fileTransferStore.resetFileTransferList()
|
||||
const picBedNamesArr = ['webdavplist', 'local', 'sftp']
|
||||
if (picBedNamesArr.includes(currentPicBedName.value)) {
|
||||
param.baseDir = configMap.baseDir
|
||||
param.webPath = configMap.webPath
|
||||
param.baseDir = configMap.value.baseDir
|
||||
param.webPath = configMap.value.webPath
|
||||
}
|
||||
window.electron.sendRPC(IRPCActionType.MANAGE_GET_BUCKET_LIST_BACKSTAGE, configMap.alias, param)
|
||||
window.electron.sendRPC(IRPCActionType.MANAGE_GET_BUCKET_LIST_BACKSTAGE, configMap.value.alias, param)
|
||||
window.electron.ipcRendererOn('refreshFileTransferList', data => {
|
||||
fileTransferStore.refreshFileTransferList(data)
|
||||
})
|
||||
@@ -2769,9 +2781,9 @@ async function getBucketFileListBackStage() {
|
||||
async function getBucketFileList() {
|
||||
const param = {
|
||||
// tcyun
|
||||
bucketName: configMap.bucketName,
|
||||
bucketName: configMap.value.bucketName,
|
||||
bucketConfig: {
|
||||
Location: configMap.bucketConfig.Location,
|
||||
Location: configMap.value.bucketConfig.Location,
|
||||
},
|
||||
paging: paging.value,
|
||||
prefix: currentPrefix.value,
|
||||
@@ -2780,7 +2792,7 @@ async function getBucketFileList() {
|
||||
customUrl: currentCustomDomain.value,
|
||||
currentPage: currentPageNumber.value,
|
||||
}
|
||||
return await window.electron.triggerRPC<any>(IRPCActionType.MANAGE_GET_BUCKET_FILE_LIST, configMap.alias, param)
|
||||
return await window.electron.triggerRPC<any>(IRPCActionType.MANAGE_GET_BUCKET_FILE_LIST, configMap.value.alias, param)
|
||||
}
|
||||
|
||||
async function handleBatchDeleteInfo() {
|
||||
@@ -2800,15 +2812,19 @@ async function handleBatchDeleteInfo() {
|
||||
|
||||
for (const item of copiedSelectedItems) {
|
||||
const param = {
|
||||
bucketName: configMap.bucketName,
|
||||
region: configMap.bucketConfig.Location,
|
||||
bucketName: configMap.value.bucketName,
|
||||
region: configMap.value.bucketConfig.Location,
|
||||
key: item.key,
|
||||
DeleteHash: item.sha,
|
||||
githubBranch: currentCustomDomain.value,
|
||||
}
|
||||
const result = item.isDir
|
||||
? await window.electron.triggerRPC<any>(IRPCActionType.MANAGE_DELETE_BUCKET_FOLDER, configMap.alias, param)
|
||||
: await window.electron.triggerRPC<any>(IRPCActionType.MANAGE_DELETE_BUCKET_FILE, configMap.alias, param)
|
||||
? await window.electron.triggerRPC<any>(
|
||||
IRPCActionType.MANAGE_DELETE_BUCKET_FOLDER,
|
||||
configMap.value.alias,
|
||||
param,
|
||||
)
|
||||
: await window.electron.triggerRPC<any>(IRPCActionType.MANAGE_DELETE_BUCKET_FILE, configMap.value.alias, param)
|
||||
if (result) {
|
||||
successCount++
|
||||
currentPageFilesInfo.splice(
|
||||
@@ -2856,17 +2872,25 @@ async function handleDeleteFile(item: any) {
|
||||
if (!result) return
|
||||
let res = false
|
||||
const param = {
|
||||
bucketName: configMap.bucketName,
|
||||
region: configMap.bucketConfig.Location,
|
||||
bucketName: configMap.value.bucketName,
|
||||
region: configMap.value.bucketConfig.Location,
|
||||
key: item.key,
|
||||
DeleteHash: item.sha,
|
||||
githubBranch: currentCustomDomain.value,
|
||||
}
|
||||
if (item.isDir) {
|
||||
message.info(t('pages.manage.bucket.deletingMsg'))
|
||||
res = await window.electron.triggerRPC<any>(IRPCActionType.MANAGE_DELETE_BUCKET_FOLDER, configMap.alias, param)
|
||||
res = await window.electron.triggerRPC<any>(
|
||||
IRPCActionType.MANAGE_DELETE_BUCKET_FOLDER,
|
||||
configMap.value.alias,
|
||||
param,
|
||||
)
|
||||
} else {
|
||||
res = await window.electron.triggerRPC<any>(IRPCActionType.MANAGE_DELETE_BUCKET_FILE, configMap.alias, param)
|
||||
res = await window.electron.triggerRPC<any>(
|
||||
IRPCActionType.MANAGE_DELETE_BUCKET_FILE,
|
||||
configMap.value.alias,
|
||||
param,
|
||||
)
|
||||
}
|
||||
if (res) {
|
||||
message.success(t('pages.manage.bucket.deleteSuccess'))
|
||||
@@ -2927,74 +2951,76 @@ function singleRename() {
|
||||
const item = currentPageFilesInfo[index]
|
||||
const param = {
|
||||
// tcyun
|
||||
bucketName: configMap.bucketName,
|
||||
region: configMap.bucketConfig.Location,
|
||||
bucketName: configMap.value.bucketName,
|
||||
region: configMap.value.bucketConfig.Location,
|
||||
oldKey: item.key,
|
||||
newKey: (item.key.slice(0, item.key.lastIndexOf('/') + 1) + itemToBeRenamed.value.newName).replaceAll('//', '/'),
|
||||
customUrl: currentCustomDomain.value,
|
||||
}
|
||||
window.electron.triggerRPC<any>(IRPCActionType.MANAGE_RENAME_BUCKET_FILE, configMap.alias, param).then((res: any) => {
|
||||
if (res) {
|
||||
const oldKey = currentPrefix.value + item.fileName
|
||||
if (pagingMarker.value === oldKey.slice(1)) {
|
||||
pagingMarker.value = currentPrefix.value.slice(1) + itemToBeRenamed.value.newName
|
||||
}
|
||||
const oldName = item.fileName
|
||||
if (itemToBeRenamed.value.newName.includes('/')) {
|
||||
item.fileName = itemToBeRenamed.value.newName.slice(0, itemToBeRenamed.value.newName.indexOf('/'))
|
||||
item.isDir = true
|
||||
item.fileSize = 0
|
||||
item.formatedTime = ''
|
||||
} else {
|
||||
item.fileName = itemToBeRenamed.value.newName
|
||||
}
|
||||
item.key = (item.key.slice(0, item.key.lastIndexOf('/') + 1) + itemToBeRenamed.value.newName).replaceAll(
|
||||
'//',
|
||||
'/',
|
||||
)
|
||||
item.url = `${currentCustomDomain.value}${currentPrefix.value}${itemToBeRenamed.value.newName}`
|
||||
item.formatedTime = new Date().toLocaleString()
|
||||
if (!paging.value) {
|
||||
const table = fileCacheDbInstance.table(currentPicBedName.value)
|
||||
table
|
||||
.where('key')
|
||||
.equals(getTableKeyOfDb())
|
||||
.modify((l: any) => {
|
||||
l.value.fullList.forEach((i: any) => {
|
||||
if (i.fileName === oldName) {
|
||||
if (itemToBeRenamed.value.newName.includes('/')) {
|
||||
i.fileName = itemToBeRenamed.value.newName.slice(0, itemToBeRenamed.value.newName.indexOf('/'))
|
||||
i.isDir = true
|
||||
i.fileSize = 0
|
||||
i.formatedTime = ''
|
||||
} else {
|
||||
i.fileName = itemToBeRenamed.value.newName
|
||||
window.electron
|
||||
.triggerRPC<any>(IRPCActionType.MANAGE_RENAME_BUCKET_FILE, configMap.value.alias, param)
|
||||
.then((res: any) => {
|
||||
if (res) {
|
||||
const oldKey = currentPrefix.value + item.fileName
|
||||
if (pagingMarker.value === oldKey.slice(1)) {
|
||||
pagingMarker.value = currentPrefix.value.slice(1) + itemToBeRenamed.value.newName
|
||||
}
|
||||
const oldName = item.fileName
|
||||
if (itemToBeRenamed.value.newName.includes('/')) {
|
||||
item.fileName = itemToBeRenamed.value.newName.slice(0, itemToBeRenamed.value.newName.indexOf('/'))
|
||||
item.isDir = true
|
||||
item.fileSize = 0
|
||||
item.formatedTime = ''
|
||||
} else {
|
||||
item.fileName = itemToBeRenamed.value.newName
|
||||
}
|
||||
item.key = (item.key.slice(0, item.key.lastIndexOf('/') + 1) + itemToBeRenamed.value.newName).replaceAll(
|
||||
'//',
|
||||
'/',
|
||||
)
|
||||
item.url = `${currentCustomDomain.value}${currentPrefix.value}${itemToBeRenamed.value.newName}`
|
||||
item.formatedTime = new Date().toLocaleString()
|
||||
if (!paging.value) {
|
||||
const table = fileCacheDbInstance.table(currentPicBedName.value)
|
||||
table
|
||||
.where('key')
|
||||
.equals(getTableKeyOfDb())
|
||||
.modify((l: any) => {
|
||||
l.value.fullList.forEach((i: any) => {
|
||||
if (i.fileName === oldName) {
|
||||
if (itemToBeRenamed.value.newName.includes('/')) {
|
||||
i.fileName = itemToBeRenamed.value.newName.slice(0, itemToBeRenamed.value.newName.indexOf('/'))
|
||||
i.isDir = true
|
||||
i.fileSize = 0
|
||||
i.formatedTime = ''
|
||||
} else {
|
||||
i.fileName = itemToBeRenamed.value.newName
|
||||
}
|
||||
i.key = (i.key.slice(0, i.key.lastIndexOf('/') + 1) + itemToBeRenamed.value.newName).replaceAll(
|
||||
'//',
|
||||
'/',
|
||||
)
|
||||
i.url = `${currentCustomDomain.value}${currentPrefix.value}${itemToBeRenamed.value.newName}`
|
||||
i.formatedTime = new Date().toLocaleString()
|
||||
}
|
||||
i.key = (i.key.slice(0, i.key.lastIndexOf('/') + 1) + itemToBeRenamed.value.newName).replaceAll(
|
||||
'//',
|
||||
'/',
|
||||
)
|
||||
i.url = `${currentCustomDomain.value}${currentPrefix.value}${itemToBeRenamed.value.newName}`
|
||||
i.formatedTime = new Date().toLocaleString()
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
message.success(t('pages.manage.bucket.renameSuccess'))
|
||||
} else {
|
||||
message.error(t('pages.manage.bucket.renameFailed'))
|
||||
}
|
||||
message.success(t('pages.manage.bucket.renameSuccess'))
|
||||
} else {
|
||||
message.error(t('pages.manage.bucket.renameFailed'))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function handleGetS3Config(item: any) {
|
||||
return {
|
||||
bucketName: configMap.bucketName,
|
||||
region: configMap.bucketConfig.Location,
|
||||
bucketName: configMap.value.bucketName,
|
||||
region: configMap.value.bucketConfig.Location,
|
||||
key: item.key,
|
||||
customUrl: currentCustomDomain.value,
|
||||
expires: manageStore.config.settings.PreSignedExpire,
|
||||
githubPrivate: configMap.bucketConfig.private,
|
||||
githubPrivate: configMap.value.bucketConfig.private,
|
||||
rawUrl: item.url,
|
||||
}
|
||||
}
|
||||
@@ -3002,15 +3028,15 @@ function handleGetS3Config(item: any) {
|
||||
async function getPreSignedUrl(item: any) {
|
||||
const param = {
|
||||
// tcyun
|
||||
bucketName: configMap.bucketName,
|
||||
region: configMap.bucketConfig.Location,
|
||||
bucketName: configMap.value.bucketName,
|
||||
region: configMap.value.bucketConfig.Location,
|
||||
key: item.key,
|
||||
customUrl: currentCustomDomain.value,
|
||||
expires: manageStore.config.settings.PreSignedExpire,
|
||||
githubPrivate: configMap.bucketConfig.private,
|
||||
githubPrivate: configMap.value.bucketConfig.private,
|
||||
rawUrl: item.url,
|
||||
}
|
||||
return await window.electron.triggerRPC<any>(IRPCActionType.MANAGE_GET_PRE_SIGNED_URL, configMap.alias, param)
|
||||
return await window.electron.triggerRPC<any>(IRPCActionType.MANAGE_GET_PRE_SIGNED_URL, configMap.value.alias, param)
|
||||
}
|
||||
|
||||
function copyToClipboard(text: string) {
|
||||
@@ -3094,9 +3120,9 @@ function getTableKeyOfDb() {
|
||||
let tableKey
|
||||
if (currentPicBedName.value === 'github') {
|
||||
// customUrl is branch
|
||||
tableKey = `${configMap.alias}@${configMap.bucketConfig.githubUsername}@${configMap.bucketName}@${currentCustomDomain.value}@${currentPrefix.value}`
|
||||
tableKey = `${configMap.value.alias}@${configMap.value.bucketConfig.githubUsername}@${configMap.value.bucketName}@${currentCustomDomain.value}@${currentPrefix.value}`
|
||||
} else {
|
||||
tableKey = `${configMap.alias}@${configMap.bucketName}@${currentPrefix.value}`
|
||||
tableKey = `${configMap.value.alias}@${configMap.value.bucketName}@${currentPrefix.value}`
|
||||
}
|
||||
return tableKey
|
||||
}
|
||||
@@ -3123,11 +3149,6 @@ function handleDetectShiftKey(event: KeyboardEvent) {
|
||||
}
|
||||
|
||||
onBeforeMount(async () => {
|
||||
await manageStore.refreshConfig()
|
||||
isShowLoadingPage.value = true
|
||||
await initCustomDomainList()
|
||||
await resetParam(true)
|
||||
isShowLoadingPage.value = false
|
||||
document.addEventListener('keydown', handleDetectShiftKey)
|
||||
document.addEventListener('keyup', handleDetectShiftKey)
|
||||
document.addEventListener('click', handleClickOutside)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<h3 class="mb-2 text-xl font-semibold text-main">
|
||||
{{ t('pages.manage.empty.noData') }}
|
||||
</h3>
|
||||
<p class="text-sm leading-[1.5] text-secondary">
|
||||
<p v-if="!noDesc" class="text-sm leading-[1.5] text-secondary">
|
||||
{{ t('pages.manage.empty.noDataDesc') }}
|
||||
</p>
|
||||
</div>
|
||||
@@ -21,4 +21,8 @@ import { FolderOpenIcon } from 'lucide-vue-next'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const { noDesc = false } = defineProps<{
|
||||
noDesc?: boolean
|
||||
}>()
|
||||
</script>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div>
|
||||
<h1 class="m-0 text-2xl font-semibold tracking-tight text-main">{{ t('pages.manage.login.title') }}</h1>
|
||||
<p class="m-0 text-sm text-secondary">
|
||||
{{ sortedAllConfigAliasMap.length }} {{ t('pages.manage.login.savedConfigs') }}
|
||||
{{ sortedAllConfigAliasList.length }} {{ t('pages.manage.login.savedConfigs') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -40,7 +40,7 @@
|
||||
v-for="item in tabItems"
|
||||
:key="item.key"
|
||||
class="transition-al flex min-w-fit flex-none cursor-pointer items-center gap-2 rounded-md border border-border-secondary bg-bg-secondary px-4 py-2 text-sm font-semibold whitespace-nowrap text-secondary no-underline duration-200 ease-apple hover:border-border hover:bg-accent/10 hover:text-main [.active]:border-accent [.active]:bg-accent [.active]:text-white"
|
||||
:class="{ active: activeName === item.key }"
|
||||
:class="{ active: activePlatform === item.key }"
|
||||
@click="handleTabChange(item.key)"
|
||||
>
|
||||
<FolderIcon v-if="item.key === 'login'" :size="16" />
|
||||
@@ -62,9 +62,9 @@
|
||||
>
|
||||
<div class="no-scrollbar h-full w-full flex-1 overflow-auto rounded-2xl border-none">
|
||||
<!-- Main Config List Tab -->
|
||||
<div v-if="activeName === 'login'" class="h-full w-full p-4">
|
||||
<div v-if="activePlatform === 'login'" class="h-full w-full p-4">
|
||||
<div
|
||||
v-if="sortedAllConfigAliasMap.length === 0"
|
||||
v-if="sortedAllConfigAliasList.length === 0"
|
||||
class="flex h-full w-full flex-col items-center justify-center p-4"
|
||||
>
|
||||
<div class="mb-2 text-accent/50">
|
||||
@@ -78,7 +78,7 @@
|
||||
class="grid w-full grid-cols-[repeat(auto-fill,minmax(300px,1fr))] gap-5 border-none p-1 max-md:gap-4"
|
||||
>
|
||||
<div
|
||||
v-for="item in sortedAllConfigAliasMap"
|
||||
v-for="item in sortedAllConfigAliasList"
|
||||
:key="item.alias"
|
||||
class="group relative flex cursor-pointer flex-row gap-6 overflow-visible rounded-xl border border-border-secondary p-4 shadow-md transition-all duration-fast ease-apple hover:border-2 hover:border-accent"
|
||||
>
|
||||
@@ -106,9 +106,9 @@
|
||||
>
|
||||
<InfoIcon :size="14" />
|
||||
{{ t('pages.manage.login.viewDetails') }}
|
||||
<ChevronDownIcon :size="14" :class="{ 'rotate-180': expandedConfigs.includes(item.alias) }" />
|
||||
<ChevronDownIcon :size="14" :class="{ 'rotate-180': visibleConfigItems.includes(item.alias) }" />
|
||||
</button>
|
||||
<Teleport v-if="expandedConfigs.includes(item.alias)" to="body">
|
||||
<Teleport v-if="visibleConfigItems.includes(item.alias)" to="body">
|
||||
<div
|
||||
class="fixed top-1/3 left-1/2 z-1000 h-auto max-h-[400px] w-auto max-w-[900px] min-w-[200px] -translate-x-1/2 overflow-auto rounded-xl border border-slate-200 bg-white shadow-xl ring-1 ring-black/5"
|
||||
>
|
||||
@@ -185,7 +185,7 @@
|
||||
class="grid w-full grid-cols-[repeat(auto-fill,minmax(300px,1fr))] gap-5 border-none p-1 max-md:gap-4"
|
||||
>
|
||||
<div
|
||||
v-for="(item, index) in existingConfiguration"
|
||||
v-for="(item, index) in platformConfigList"
|
||||
:key="item.alias + index"
|
||||
class="relative flex min-h-[180px] cursor-pointer flex-col gap-6 overflow-hidden rounded-xl border border-border p-5 shadow-md transition-all duration-fast ease-apple hover:border-2 hover:border-accent hover:shadow-md"
|
||||
>
|
||||
@@ -241,7 +241,12 @@
|
||||
</div>
|
||||
</div>
|
||||
<template v-else-if="editMode">
|
||||
<ManageEditPage v-model:edit-mode="editMode" :alias-name="editingAlias" :active-name="activeName" />
|
||||
<ManageEditPage
|
||||
v-model:edit-mode="editMode"
|
||||
:alias-name="editingAlias"
|
||||
:platform-name="activePlatform"
|
||||
@update:edit-mode="loadExistingSettings(activePlatform)"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@@ -266,7 +271,7 @@ import {
|
||||
TrashIcon,
|
||||
XIcon,
|
||||
} from 'lucide-vue-next'
|
||||
import { computed, onMounted, reactive, ref } from 'vue'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
@@ -280,7 +285,7 @@ import { supportedPicBedList } from '@/manage/utils/constants'
|
||||
import { getConfig, removeConfig, saveConfig } from '@/manage/utils/dataSender'
|
||||
import { formatEndpoint } from '@/utils/common'
|
||||
import { configPaths } from '@/utils/configPaths'
|
||||
import { getConfig as getPicBedsConfig } from '@/utils/dataSender'
|
||||
import { getConfig as getPicListConfig } from '@/utils/dataSender'
|
||||
import { II18nLanguage, IRPCActionType } from '@/utils/enum'
|
||||
|
||||
const { t } = useI18n()
|
||||
@@ -291,101 +296,71 @@ const { confirm } = useConfirm()
|
||||
|
||||
const editMode = ref(false)
|
||||
const editingAlias = ref('')
|
||||
const activeName = ref('login')
|
||||
const expandedConfigs = ref<string[]>([])
|
||||
const configResult: IStringKeyMap = reactive({})
|
||||
const existingConfiguration = reactive({} as IStringKeyMap)
|
||||
const dataForTable = reactive([] as any[])
|
||||
const allConfigAliasMap = reactive({} as IStringKeyMap)
|
||||
const currentAliasList = reactive([] as string[])
|
||||
const formErrors = reactive({} as IStringKeyMap)
|
||||
const activePlatform = ref('login')
|
||||
const visibleConfigItems = ref<string[]>([])
|
||||
const platformConfigList = ref<IStringKeyMap[]>([])
|
||||
const allConfigAliasList = ref<IStringKeyMap[]>([])
|
||||
const importedNewConfig: IStringKeyMap = {}
|
||||
|
||||
const sortedAllConfigAliasMap = computed(() => {
|
||||
return Object.values(allConfigAliasMap).sort((a, b) => {
|
||||
const PB_LIST = [
|
||||
'aliyun',
|
||||
'aws-s3',
|
||||
'aws-s3-plist',
|
||||
'github',
|
||||
'imgur',
|
||||
'local',
|
||||
'qiniu',
|
||||
'sftpplist',
|
||||
'smms',
|
||||
'tcyun',
|
||||
'upyun',
|
||||
'webdavplist',
|
||||
] as const
|
||||
|
||||
const sortedAllConfigAliasList = computed(() => {
|
||||
return allConfigAliasList.value.slice().sort((a, b) => {
|
||||
return a.picBedName.localeCompare(b.picBedName)
|
||||
})
|
||||
})
|
||||
|
||||
const tabItems = computed(() => {
|
||||
const items = [
|
||||
{
|
||||
key: 'login',
|
||||
name: t('pages.manage.login.savedConfigs'),
|
||||
icon: null,
|
||||
iconComponent: FolderIcon,
|
||||
},
|
||||
]
|
||||
const staticItem = {
|
||||
key: 'login',
|
||||
name: t('pages.manage.login.savedConfigs'),
|
||||
icon: null,
|
||||
iconComponent: FolderIcon,
|
||||
}
|
||||
|
||||
Object.values(supportedPicBedList).forEach((item: any) => {
|
||||
items.push({
|
||||
key: item.icon,
|
||||
name: item.name,
|
||||
icon: item.icon,
|
||||
iconComponent: null as any,
|
||||
})
|
||||
})
|
||||
const dynamicItems = Object.values(supportedPicBedList).map((item: any) => ({
|
||||
key: item.icon,
|
||||
name: item.name,
|
||||
icon: item.icon,
|
||||
iconComponent: null,
|
||||
}))
|
||||
|
||||
return items
|
||||
return [staticItem, ...dynamicItems]
|
||||
})
|
||||
|
||||
const importedNewConfig: IStringKeyMap = {}
|
||||
|
||||
const notifyUser = (msg: string, type: 'success' | 'error' | 'warning' = 'success') => {
|
||||
message[type](`${msg}`)
|
||||
}
|
||||
|
||||
const initializeDefaultValues = (picBedName: string) => {
|
||||
if (!supportedPicBedList[picBedName]) return
|
||||
|
||||
const options = supportedPicBedList[picBedName].options || []
|
||||
for (const option of options) {
|
||||
const fieldKey = `${picBedName}.${option}`
|
||||
const configOption = supportedPicBedList[picBedName].configOptions[option]
|
||||
|
||||
if (configResult[fieldKey] === undefined || configResult[fieldKey] === '') {
|
||||
if (configOption.default !== undefined) {
|
||||
configResult[fieldKey] = configOption.default
|
||||
} else if (configOption.type === 'boolean') {
|
||||
configResult[fieldKey] = false
|
||||
} else if (configOption.type === 'number') {
|
||||
configResult[fieldKey] = 0
|
||||
} else {
|
||||
configResult[fieldKey] = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getDataForTable() {
|
||||
for (const key in existingConfiguration) {
|
||||
dataForTable.push({ ...(existingConfiguration[key] as IStringKeyMap) })
|
||||
}
|
||||
}
|
||||
|
||||
async function getExistingConfig(name: string) {
|
||||
async function loadExistingSettings(name: string) {
|
||||
if (name === 'login') {
|
||||
getAllConfigAliasArray()
|
||||
return
|
||||
}
|
||||
currentAliasList.length = 0
|
||||
const result = await getConfig<any>('picBed')
|
||||
for (const key in existingConfiguration) {
|
||||
delete existingConfiguration[key]
|
||||
}
|
||||
if (!result || typeof result !== 'object' || Object.keys(result).length === 0) {
|
||||
existingConfiguration[name] = { fail: '暂无配置' }
|
||||
} else {
|
||||
for (const key in result) {
|
||||
if (result[key].picBedName === name) {
|
||||
existingConfiguration[key] = result[key]
|
||||
currentAliasList.push(result[key].alias)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dataForTable.length = 0
|
||||
getDataForTable()
|
||||
handleConfigImport(currentAliasList[0])
|
||||
const result = await getConfig<any>('picBed')
|
||||
const newConfig: IStringKeyMap[] = []
|
||||
if (result && typeof result === 'object' && Object.keys(result).length > 0) {
|
||||
Object.values(result).forEach((value: any) => {
|
||||
if (value.picBedName === name) {
|
||||
newConfig.push(value)
|
||||
}
|
||||
})
|
||||
}
|
||||
platformConfigList.value = newConfig
|
||||
}
|
||||
|
||||
function openBucketPageSetting() {
|
||||
@@ -408,7 +383,7 @@ const handleConfigRemove = async (name: string) => {
|
||||
removeConfig('picBed', name)
|
||||
notifyUser(t('pages.manage.login.deleteConfigSuccessMsg'), 'success')
|
||||
manageStore.refreshConfig()
|
||||
getAllConfigAliasArray()
|
||||
loadExistingSettings(activePlatform.value)
|
||||
} catch (_error) {
|
||||
notifyUser(t('pages.manage.login.deleteConfigFailedMsg'), 'error')
|
||||
}
|
||||
@@ -417,17 +392,16 @@ const handleConfigRemove = async (name: string) => {
|
||||
|
||||
const getAllConfigAliasArray = async () => {
|
||||
const result = await getConfig<any>('picBed')
|
||||
for (const key in allConfigAliasMap) {
|
||||
delete allConfigAliasMap[key]
|
||||
}
|
||||
const newConfig: IStringKeyMap[] = []
|
||||
if (!result) return
|
||||
Object.entries(result).forEach(([, value]: [string, any], index) => {
|
||||
allConfigAliasMap[index] = {
|
||||
Object.values(result).forEach((value: any) => {
|
||||
newConfig.push({
|
||||
alias: value.alias,
|
||||
config: value,
|
||||
picBedName: value.picBedName,
|
||||
}
|
||||
})
|
||||
})
|
||||
allConfigAliasList.value = newConfig
|
||||
}
|
||||
|
||||
const copyToClipboard = (text: string) => {
|
||||
@@ -456,37 +430,18 @@ function openEditPage(alias: string) {
|
||||
editMode.value = true
|
||||
}
|
||||
|
||||
function handleConfigImport(alias: string) {
|
||||
const selectedConfig = existingConfiguration[alias]
|
||||
if (!selectedConfig) return
|
||||
|
||||
supportedPicBedList[selectedConfig.picBedName].options.forEach((option: any) => {
|
||||
if (selectedConfig[option] !== undefined) {
|
||||
configResult[selectedConfig.picBedName + '.' + option] = selectedConfig[option]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleTabChange = (tabName: string) => {
|
||||
editMode.value = false
|
||||
activeName.value = tabName
|
||||
getExistingConfig(tabName)
|
||||
|
||||
for (const key in formErrors) {
|
||||
delete formErrors[key]
|
||||
}
|
||||
|
||||
if (tabName !== 'login') {
|
||||
initializeDefaultValues(tabName)
|
||||
}
|
||||
activePlatform.value = tabName
|
||||
loadExistingSettings(tabName)
|
||||
}
|
||||
|
||||
const toggleConfigDetails = async (alias: string) => {
|
||||
const index = expandedConfigs.value.indexOf(alias)
|
||||
const index = visibleConfigItems.value.indexOf(alias)
|
||||
if (index > -1) {
|
||||
expandedConfigs.value.splice(index, 1)
|
||||
visibleConfigItems.value.splice(index, 1)
|
||||
} else {
|
||||
expandedConfigs.value.push(alias)
|
||||
visibleConfigItems.value.push(alias)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,37 +450,19 @@ const refreshConfigs = () => {
|
||||
notifyUser(t('pages.manage.login.configurationRefreshMsg'), 'success')
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getCurrentConfigList()
|
||||
})
|
||||
|
||||
async function getCurrentConfigList() {
|
||||
await manageStore.refreshConfig()
|
||||
const configList = (await getPicBedsConfig<any>('uploader')) ?? {}
|
||||
const pbList = [
|
||||
'aliyun',
|
||||
'aws-s3',
|
||||
'aws-s3-plist',
|
||||
'github',
|
||||
'imgur',
|
||||
'local',
|
||||
'qiniu',
|
||||
'sftpplist',
|
||||
'smms',
|
||||
'tcyun',
|
||||
'upyun',
|
||||
'webdavplist',
|
||||
]
|
||||
const configList = (await getPicListConfig<any>('uploader')) ?? {}
|
||||
|
||||
const filteredConfigList = pbList.flatMap(pb => {
|
||||
const filteredConfigList = PB_LIST.flatMap(pb => {
|
||||
const config = configList[pb]
|
||||
return config?.configList?.length ? config.configList.map((item: any) => ({ ...item, type: pb })) : []
|
||||
})
|
||||
|
||||
const autoImport = (await getPicBedsConfig<boolean>('settings.autoImport')) || false
|
||||
const autoImport = (await getPicListConfig<boolean>('settings.autoImport')) || false
|
||||
if (autoImport) {
|
||||
const autoImportPicBed = initArray(
|
||||
(await getPicBedsConfig<string | string[]>('settings.autoImportPicBed')) || '',
|
||||
(await getPicListConfig<string | string[]>('settings.autoImportPicBed')) || '',
|
||||
[],
|
||||
)
|
||||
await Promise.all(filteredConfigList.flatMap(config => transUpToManage(config, config.type, autoImportPicBed)))
|
||||
@@ -547,7 +484,7 @@ async function goConfigPage() {
|
||||
}
|
||||
|
||||
function isImported(alias: string) {
|
||||
return Object.values(allConfigAliasMap).some(item => item.alias === alias)
|
||||
return Object.values(allConfigAliasList.value).some(item => item.alias === alias)
|
||||
}
|
||||
|
||||
function initArray(arrayT: string | string[], defaultValue: string[]) {
|
||||
@@ -557,16 +494,18 @@ function initArray(arrayT: string | string[], defaultValue: string[]) {
|
||||
return arrayT
|
||||
}
|
||||
|
||||
function getPicBedAlias(name: string) {
|
||||
const mapping: Record<string, string> = {
|
||||
webdavplist: 'webdav',
|
||||
sftpplist: 'sftp',
|
||||
'aws-s3': 's3plist',
|
||||
'aws-s3-plist': 's3plist',
|
||||
}
|
||||
return mapping[name] || name
|
||||
}
|
||||
|
||||
async function transUpToManage(config: IUploaderConfigListItem, picBedName: string, autoImportPicBed: string[]) {
|
||||
const alias = `${
|
||||
picBedName === 'webdavplist'
|
||||
? 'webdav'
|
||||
: picBedName === 'sftpplist'
|
||||
? 'sftp'
|
||||
: picBedName === 'aws-s3' || picBedName === 'aws-s3-plist'
|
||||
? 's3plist'
|
||||
: picBedName
|
||||
}-${config._configName ?? 'Default'}-imp`
|
||||
const alias = `${getPicBedAlias(picBedName)}-${config._configName ?? 'Default'}-imp`
|
||||
if (!autoImportPicBed.includes(picBedName) || isImported(alias)) return
|
||||
const commonConfig = {
|
||||
alias,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
>
|
||||
<InfoIcon :size="20" />
|
||||
<p class="m-0 text-sm leading-[1.5] font-semibold text-secondary">
|
||||
{{ supportedPicBedList[activeName].explain }}
|
||||
{{ supportedPicBedList[platformName].explain }}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
@@ -14,9 +14,9 @@
|
||||
>
|
||||
<LinkIcon :size="20" />
|
||||
<p class="m-0 text-sm leading-[1.5] font-semibold text-secondary">
|
||||
{{ supportedPicBedList[activeName].referenceText }}
|
||||
<button class="link-button" @click="handleReferenceClick(supportedPicBedList[activeName].refLink)">
|
||||
{{ supportedPicBedList[activeName].refLink }}
|
||||
{{ supportedPicBedList[platformName].referenceText }}
|
||||
<button class="link-button" @click="handleReferenceClick(supportedPicBedList[platformName].refLink)">
|
||||
{{ supportedPicBedList[platformName].refLink }}
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
@@ -24,92 +24,94 @@
|
||||
<div class="grid w-full grid-cols-1 gap-3">
|
||||
<SettingCard>
|
||||
<CustomInput
|
||||
v-model.trim="configResult[activeName + '.alias']"
|
||||
v-model.trim="configResult.alias"
|
||||
type="text"
|
||||
:placeholder="supportedPicBedList[activeName].configOptions.alias.placeholder || ''"
|
||||
:title="supportedPicBedList[activeName].configOptions.alias.description"
|
||||
:required="supportedPicBedList[activeName].configOptions.alias.required"
|
||||
:class="{ 'border-danger': formErrors[activeName + '.' + 'alias'] }"
|
||||
@blur="validateField(activeName, 'alias')"
|
||||
@input="clearFieldError(activeName + '.alias')"
|
||||
:placeholder="supportedPicBedList[platformName].configOptions.alias.placeholder || ''"
|
||||
:title="supportedPicBedList[platformName].configOptions.alias.description"
|
||||
:required="supportedPicBedList[platformName].configOptions.alias.required"
|
||||
:class="{ 'border-danger': formErrors.alias }"
|
||||
@blur="validateField(platformName, 'alias')"
|
||||
@input="clearFieldError('alias')"
|
||||
/>
|
||||
<template v-if="formErrors[activeName + '.' + 'alias']" #extra>
|
||||
<template v-if="formErrors.alias" #extra>
|
||||
<div class="mt-1 text-xs text-danger">
|
||||
{{ formErrors[activeName + '.' + 'alias'] }}
|
||||
{{ formErrors.alias }}
|
||||
</div>
|
||||
</template>
|
||||
</SettingCard>
|
||||
<template v-for="option in supportedPicBedList[activeName].options" :key="option">
|
||||
<template v-for="option in supportedPicBedList[platformName].options" :key="option">
|
||||
<SettingCard
|
||||
v-if="supportedPicBedList[activeName].configOptions[option].type === 'string' && option !== 'alias'"
|
||||
v-if="supportedPicBedList[platformName].configOptions[option].type === 'string' && option !== 'alias'"
|
||||
>
|
||||
<CustomInput
|
||||
v-model.trim="configResult[activeName + '.' + option]"
|
||||
v-model.trim="configResult[option]"
|
||||
type="text"
|
||||
:placeholder="supportedPicBedList[activeName].configOptions[option].placeholder || ''"
|
||||
:class="{ 'border-danger': formErrors[activeName + '.' + option] }"
|
||||
:title="supportedPicBedList[activeName].configOptions[option].description"
|
||||
:required="supportedPicBedList[activeName].configOptions[option].required"
|
||||
:disabled="!!supportedPicBedList[activeName].configOptions[option].disabled"
|
||||
@blur="validateField(activeName, option)"
|
||||
@input="clearFieldError(activeName + '.' + option)"
|
||||
:placeholder="supportedPicBedList[platformName].configOptions[option].placeholder || ''"
|
||||
:class="{ 'border-danger': formErrors[option] }"
|
||||
:title="supportedPicBedList[platformName].configOptions[option].description"
|
||||
:required="supportedPicBedList[platformName].configOptions[option].required"
|
||||
:disabled="!!supportedPicBedList[platformName].configOptions[option].disabled"
|
||||
:tips="supportedPicBedList[platformName].configOptions[option].tooltip || ''"
|
||||
@blur="validateField(platformName, option)"
|
||||
@input="clearFieldError(option)"
|
||||
/>
|
||||
<template v-if="formErrors[activeName + '.' + option]" #extra>
|
||||
<template v-if="formErrors[option]" #extra>
|
||||
<div class="mt-1 text-xs text-danger">
|
||||
{{ formErrors[activeName + '.' + option] }}
|
||||
{{ formErrors[option] }}
|
||||
</div>
|
||||
</template>
|
||||
</SettingCard>
|
||||
</template>
|
||||
<template v-for="option in supportedPicBedList[activeName].options" :key="option">
|
||||
<SettingCard v-if="supportedPicBedList[activeName].configOptions[option].type === 'number'">
|
||||
<template v-for="option in supportedPicBedList[platformName].options" :key="option">
|
||||
<SettingCard v-if="supportedPicBedList[platformName].configOptions[option].type === 'number'">
|
||||
<CustomInput
|
||||
v-model.number="configResult[activeName + '.' + option]"
|
||||
v-model.number="configResult[option]"
|
||||
type="number"
|
||||
:placeholder="supportedPicBedList[activeName].configOptions[option].placeholder || ''"
|
||||
:class="{ 'border-danger': formErrors[activeName + '.' + option] }"
|
||||
:title="supportedPicBedList[activeName].configOptions[option].description"
|
||||
:required="supportedPicBedList[activeName].configOptions[option].required"
|
||||
@blur="validateField(activeName, option)"
|
||||
@input="clearFieldError(activeName + '.' + option)"
|
||||
:placeholder="supportedPicBedList[platformName].configOptions[option].placeholder || ''"
|
||||
:class="{ 'border-danger': formErrors[option] }"
|
||||
:title="supportedPicBedList[platformName].configOptions[option].description"
|
||||
:required="supportedPicBedList[platformName].configOptions[option].required"
|
||||
:tips="supportedPicBedList[platformName].configOptions[option].tooltip || ''"
|
||||
@blur="validateField(platformName, option)"
|
||||
@input="clearFieldError(option)"
|
||||
/>
|
||||
<template v-if="formErrors[activeName + '.' + option]" #extra>
|
||||
<template v-if="formErrors[option]" #extra>
|
||||
<div class="mt-1 text-xs text-danger">
|
||||
{{ formErrors[activeName + '.' + option] }}
|
||||
{{ formErrors[option] }}
|
||||
</div>
|
||||
</template>
|
||||
</SettingCard>
|
||||
</template>
|
||||
<template v-for="option in supportedPicBedList[activeName].options" :key="option">
|
||||
<SettingCard v-if="supportedPicBedList[activeName].configOptions[option].type === 'boolean'" p1>
|
||||
<template v-for="option in supportedPicBedList[platformName].options" :key="option">
|
||||
<SettingCard v-if="supportedPicBedList[platformName].configOptions[option].type === 'boolean'" p1>
|
||||
<CustomSwitch
|
||||
v-model="configResult[activeName + '.' + option]"
|
||||
v-model="configResult[option]"
|
||||
no-border
|
||||
small
|
||||
:required="supportedPicBedList[activeName].configOptions[option].required"
|
||||
:title="supportedPicBedList[activeName].configOptions[option].description"
|
||||
:tips="supportedPicBedList[activeName].configOptions[option].tooltip || ''"
|
||||
@update:model-value="validateField(activeName, option)"
|
||||
:required="supportedPicBedList[platformName].configOptions[option].required"
|
||||
:title="supportedPicBedList[platformName].configOptions[option].description"
|
||||
:tips="supportedPicBedList[platformName].configOptions[option].tooltip || ''"
|
||||
@update:model-value="validateField(platformName, option)"
|
||||
>
|
||||
</CustomSwitch>
|
||||
</SettingCard>
|
||||
</template>
|
||||
<template v-for="option in supportedPicBedList[activeName].options" :key="option">
|
||||
<SettingCard v-if="supportedPicBedList[activeName].configOptions[option].type === 'select'">
|
||||
<template v-for="option in supportedPicBedList[platformName].options" :key="option">
|
||||
<SettingCard v-if="supportedPicBedList[platformName].configOptions[option].type === 'select'">
|
||||
<CustomSelect
|
||||
v-model="configResult[activeName + '.' + option]"
|
||||
:title="supportedPicBedList[activeName].configOptions[option].description"
|
||||
:required="supportedPicBedList[activeName].configOptions[option].required"
|
||||
v-model="configResult[option]"
|
||||
:title="supportedPicBedList[platformName].configOptions[option].description"
|
||||
:required="supportedPicBedList[platformName].configOptions[option].required"
|
||||
:select-list="
|
||||
Object.entries(supportedPicBedList[activeName].configOptions[option].selectOptions || {}).map(
|
||||
Object.entries(supportedPicBedList[platformName].configOptions[option].selectOptions || {}).map(
|
||||
([key, value]) => ({
|
||||
value: key,
|
||||
label: value as string,
|
||||
}),
|
||||
)
|
||||
"
|
||||
:class="{ 'border-danger': formErrors[activeName + '.' + option] }"
|
||||
@change="validateField(activeName, option)"
|
||||
:class="{ 'border-danger': formErrors[option] }"
|
||||
@change="validateField(platformName, option)"
|
||||
>
|
||||
<template #pre-info>
|
||||
<option value="" disabled>
|
||||
@@ -117,9 +119,9 @@
|
||||
</option>
|
||||
</template>
|
||||
</CustomSelect>
|
||||
<template v-if="formErrors[activeName + '.' + option]" #extra>
|
||||
<template v-if="formErrors[option]" #extra>
|
||||
<div class="mt-1 text-xs text-danger">
|
||||
{{ formErrors[activeName + '.' + option] }}
|
||||
{{ formErrors[option] }}
|
||||
</div>
|
||||
</template>
|
||||
</SettingCard>
|
||||
@@ -141,13 +143,13 @@
|
||||
type="primary"
|
||||
:text="t('pages.manage.login.save')"
|
||||
:icon="SaveIcon"
|
||||
@click="handleConfigChange(activeName)"
|
||||
@click="handleConfigChange()"
|
||||
/>
|
||||
<CustomButton
|
||||
class="bg-danger/70"
|
||||
:text="t('pages.manage.login.reset')"
|
||||
:icon="RotateCcwIcon"
|
||||
@click="handleConfigReset(activeName)"
|
||||
@click="handleConfigReset()"
|
||||
/>
|
||||
<CustomButton class="bg-warning/70" :text="t('common.cancel')" :icon="XIcon" @click="cancelEditMode" />
|
||||
</div>
|
||||
@@ -157,7 +159,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DownloadIcon, InfoIcon, LinkIcon, RotateCcwIcon, SaveIcon, XIcon } from 'lucide-vue-next'
|
||||
import { onMounted, reactive, ref, watch } from 'vue'
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import CustomButton from '@/components/common/CustomButton.vue'
|
||||
@@ -173,22 +175,23 @@ import { getConfig, saveConfig } from '@/manage/utils/dataSender'
|
||||
import { formatEndpoint } from '@/utils/common'
|
||||
import { IRPCActionType } from '@/utils/enum'
|
||||
|
||||
const editMode = defineModel<boolean>('editMode')
|
||||
const emit = defineEmits<(e: 'update:editMode', value: boolean) => void>()
|
||||
|
||||
const { aliasName, platformName } = defineProps<{
|
||||
aliasName: string
|
||||
platformName: string
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
const manageStore = useManageStore()
|
||||
const message = useMessage()
|
||||
const formErrors = reactive({} as IStringKeyMap)
|
||||
const configResult: IStringKeyMap = reactive({})
|
||||
const existingConfiguration = reactive({} as IStringKeyMap)
|
||||
const currentAliasList = reactive([] as string[])
|
||||
const dataForTable = reactive([] as any[])
|
||||
const editMode = defineModel<boolean>('editMode')
|
||||
const formErrors = ref<IStringKeyMap>({})
|
||||
const configResult = ref<IStringKeyMap>({})
|
||||
const existingConfiguration = ref<IStringKeyMap>({})
|
||||
const currentAliasList = ref<string[]>([])
|
||||
const selectedAlias = ref('')
|
||||
|
||||
const { aliasName, activeName } = defineProps<{
|
||||
aliasName: string
|
||||
activeName: string
|
||||
}>()
|
||||
|
||||
watch(selectedAlias, newAlias => {
|
||||
if (newAlias) {
|
||||
handleConfigImport(newAlias)
|
||||
@@ -198,18 +201,17 @@ watch(selectedAlias, newAlias => {
|
||||
const handleReferenceClick = (url: string) => window.electron.sendRPC(IRPCActionType.OPEN_URL, url)
|
||||
|
||||
const validateField = (picBedName: string, optionKey: string) => {
|
||||
const fieldKey = `${picBedName}.${optionKey}`
|
||||
const configOption = supportedPicBedList[picBedName]?.configOptions?.[optionKey]
|
||||
const value = configResult[fieldKey]
|
||||
const value = configResult.value[optionKey]
|
||||
|
||||
if (!configOption) return
|
||||
|
||||
delete formErrors[fieldKey]
|
||||
delete formErrors.value[optionKey]
|
||||
|
||||
if (configOption.required) {
|
||||
if (configOption.type === 'boolean') {
|
||||
} else if (!value || value === '') {
|
||||
formErrors[fieldKey] = t('pages.manage.constant.pleaseInput', { name: configOption.description })
|
||||
formErrors.value[optionKey] = t('pages.manage.constant.pleaseInput', { name: configOption.description })
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -220,7 +222,7 @@ const validateField = (picBedName: string, optionKey: string) => {
|
||||
try {
|
||||
rule.validator(rule, value, (error: Error | null) => {
|
||||
if (error) {
|
||||
formErrors[fieldKey] = error.message
|
||||
formErrors.value[optionKey] = error.message
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
@@ -228,7 +230,7 @@ const validateField = (picBedName: string, optionKey: string) => {
|
||||
}
|
||||
} else if (rule.type === 'number' && value !== undefined && value !== '') {
|
||||
if (isNaN(Number(value))) {
|
||||
formErrors[fieldKey] = rule.message || t('pages.manage.constant.itemsPPBeNumber')
|
||||
formErrors.value[optionKey] = rule.message || t('pages.manage.constant.itemsPPBeNumber')
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -238,53 +240,56 @@ const validateField = (picBedName: string, optionKey: string) => {
|
||||
if (optionKey === 'alias' && value) {
|
||||
const reg = /^[\p{Unified_Ideograph}_a-zA-Z0-9-]+$/u
|
||||
if (!reg.test(value)) {
|
||||
formErrors[fieldKey] = t('pages.manage.login.aliasMsg')
|
||||
formErrors.value[optionKey] = t('pages.manage.login.aliasMsg')
|
||||
}
|
||||
}
|
||||
|
||||
if (optionKey === 'itemsPerPage' && value !== undefined && value !== '') {
|
||||
const numValue = Number(value)
|
||||
if (numValue < 20 || numValue > 1000) {
|
||||
formErrors[fieldKey] = t('pages.manage.login.itemsPerPageMsg')
|
||||
formErrors.value[optionKey] = t('pages.manage.login.itemsPerPageMsg')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const clearFieldError = (fieldKey: string) => {
|
||||
delete formErrors[fieldKey]
|
||||
delete formErrors.value[fieldKey]
|
||||
}
|
||||
|
||||
async function handleConfigChange(name: string) {
|
||||
if (!validateAllFields(name)) {
|
||||
async function handleConfigChange() {
|
||||
if (!validateAllFields(platformName)) {
|
||||
notifyUser(t('pages.manage.login.noRequiredMsg'), 'error')
|
||||
return
|
||||
}
|
||||
|
||||
const aliasList = getAliasList()
|
||||
const allKeys = Object.keys(supportedPicBedList[name].configOptions)
|
||||
const aliasList = Object.values(existingConfiguration.value).map(item => item.alias)
|
||||
const allKeys = Object.keys(supportedPicBedList[platformName].configOptions)
|
||||
const resultMap: IStringKeyMap = {}
|
||||
if (aliasList.includes(configResult.value.alias) && aliasName !== configResult.value.alias) {
|
||||
notifyUser(t('pages.manage.login.aliasExistMsg'), 'error')
|
||||
return
|
||||
}
|
||||
|
||||
for (const key of allKeys) {
|
||||
const resultKey = name + '.' + key
|
||||
if (key === 'customUrl' && configResult[resultKey] !== undefined && configResult[resultKey] !== '') {
|
||||
if (name !== 'upyun') {
|
||||
configResult[resultKey] = formatEndpoint(configResult[resultKey], false)
|
||||
if (key === 'customUrl' && configResult.value[key] !== undefined && configResult.value[key] !== '') {
|
||||
if (platformName !== 'upyun') {
|
||||
configResult.value[key] = formatEndpoint(configResult.value[key], false)
|
||||
}
|
||||
}
|
||||
|
||||
if (supportedPicBedList[name].configOptions[key].default !== undefined && configResult[resultKey] === '') {
|
||||
resultMap[key] = supportedPicBedList[name].configOptions[key].default
|
||||
} else if (configResult[resultKey] === undefined) {
|
||||
if (supportedPicBedList[name].configOptions[key].default !== undefined) {
|
||||
resultMap[key] = supportedPicBedList[name].configOptions[key].default
|
||||
if (supportedPicBedList[platformName].configOptions[key].default !== undefined && configResult.value[key] === '') {
|
||||
resultMap[key] = supportedPicBedList[platformName].configOptions[key].default
|
||||
} else if (configResult.value[key] === undefined) {
|
||||
if (supportedPicBedList[platformName].configOptions[key].default !== undefined) {
|
||||
resultMap[key] = supportedPicBedList[platformName].configOptions[key].default
|
||||
} else {
|
||||
resultMap[key] = ''
|
||||
}
|
||||
} else {
|
||||
resultMap[key] = configResult[resultKey]
|
||||
resultMap[key] = configResult.value[key]
|
||||
}
|
||||
}
|
||||
resultMap.picBedName = name
|
||||
resultMap.picBedName = platformName
|
||||
if (resultMap.bucketName !== undefined) {
|
||||
resultMap.transformedConfig = {}
|
||||
const bucketName = resultMap.bucketName.split(',')
|
||||
@@ -310,56 +315,51 @@ async function handleConfigChange(name: string) {
|
||||
}
|
||||
saveConfig(`picBed.${resultMap.alias}`, resultMap)
|
||||
await manageStore.refreshConfig()
|
||||
await getExistingConfig(activeName)
|
||||
dataForTable.length = 0
|
||||
getDataForTable()
|
||||
if (aliasList.includes(resultMap.alias)) {
|
||||
notifyUser(`${t('pages.manage.login.configChangeMsg')}${resultMap.alias}`, 'warning')
|
||||
} else {
|
||||
notifyUser(`${t('pages.manage.login.configSaveMsg')}${resultMap.alias}`, 'success')
|
||||
}
|
||||
await getExistingConfig(platformName)
|
||||
notifyUser(`${t('pages.manage.login.configSaveMsg')}${resultMap.alias}`, 'success')
|
||||
editMode.value = false
|
||||
emit('update:editMode', false)
|
||||
}
|
||||
|
||||
const notifyUser = (msg: string, type: 'success' | 'error' | 'warning' = 'success') => {
|
||||
message[type](`${msg}`)
|
||||
}
|
||||
|
||||
function getDataForTable() {
|
||||
for (const key in existingConfiguration) {
|
||||
dataForTable.push({ ...(existingConfiguration[key] as IStringKeyMap) })
|
||||
}
|
||||
}
|
||||
|
||||
async function getExistingConfig(name: string) {
|
||||
currentAliasList.length = 0
|
||||
const newList: string[] = []
|
||||
const result = await getConfig<any>('picBed')
|
||||
for (const key in existingConfiguration) {
|
||||
delete existingConfiguration[key]
|
||||
}
|
||||
const newConfiguration: IStringKeyMap = {}
|
||||
if (!result || typeof result !== 'object' || Object.keys(result).length === 0) {
|
||||
existingConfiguration[name] = { fail: '暂无配置' }
|
||||
newConfiguration[name] = { fail: '暂无配置' }
|
||||
} else {
|
||||
for (const key in result) {
|
||||
if (result[key].picBedName === name) {
|
||||
existingConfiguration[key] = result[key]
|
||||
currentAliasList.push(result[key].alias)
|
||||
newConfiguration[key] = result[key]
|
||||
newList.push(result[key].alias)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dataForTable.length = 0
|
||||
getDataForTable()
|
||||
existingConfiguration.value = newConfiguration
|
||||
currentAliasList.value = newList
|
||||
handleConfigImport(aliasName)
|
||||
}
|
||||
|
||||
function handleConfigImport(alias: string) {
|
||||
const selectedConfig = existingConfiguration[alias]
|
||||
if (alias === '') {
|
||||
supportedPicBedList[platformName].options.forEach((option: any) => {
|
||||
const defaultValue = supportedPicBedList[platformName].configOptions[option].default
|
||||
if (defaultValue !== undefined && option !== 'alias') {
|
||||
configResult.value[option] = defaultValue
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
const selectedConfig = existingConfiguration.value[alias]
|
||||
if (!selectedConfig) return
|
||||
|
||||
supportedPicBedList[selectedConfig.picBedName].options.forEach((option: any) => {
|
||||
if (selectedConfig[option] !== undefined) {
|
||||
configResult[selectedConfig.picBedName + '.' + option] = selectedConfig[option]
|
||||
configResult.value[option] = selectedConfig[option]
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -370,7 +370,7 @@ const validateAllFields = (picBedName: string): boolean => {
|
||||
|
||||
for (const option of options) {
|
||||
validateField(picBedName, option)
|
||||
if (formErrors[`${picBedName}.${option}`]) {
|
||||
if (formErrors.value[`${picBedName}.${option}`]) {
|
||||
isValid = false
|
||||
}
|
||||
}
|
||||
@@ -378,41 +378,36 @@ const validateAllFields = (picBedName: string): boolean => {
|
||||
return isValid
|
||||
}
|
||||
|
||||
function getAliasList() {
|
||||
return Object.values(existingConfiguration).map(item => item.alias)
|
||||
}
|
||||
|
||||
const handleConfigReset = (name: string) => {
|
||||
const keys = Object.keys(formErrors).filter(key => key.startsWith(name))
|
||||
const handleConfigReset = () => {
|
||||
const keys = Object.keys(formErrors.value).filter(key => key.startsWith(platformName))
|
||||
keys.forEach(key => {
|
||||
delete formErrors[key]
|
||||
delete formErrors.value[key]
|
||||
})
|
||||
|
||||
const configKeys = Object.keys(configResult).filter(key => key.startsWith(name))
|
||||
const configKeys = Object.keys(configResult.value).filter(key => key.startsWith(platformName))
|
||||
configKeys.forEach(key => {
|
||||
delete configResult[key]
|
||||
delete configResult.value[key]
|
||||
})
|
||||
|
||||
initializeDefaultValues(name)
|
||||
initializeDefaultValues()
|
||||
}
|
||||
|
||||
const initializeDefaultValues = (picBedName: string) => {
|
||||
if (!supportedPicBedList[picBedName]) return
|
||||
const initializeDefaultValues = () => {
|
||||
if (!supportedPicBedList[platformName]) return
|
||||
|
||||
const options = supportedPicBedList[picBedName].options || []
|
||||
const options = supportedPicBedList[platformName].options || []
|
||||
for (const option of options) {
|
||||
const fieldKey = `${picBedName}.${option}`
|
||||
const configOption = supportedPicBedList[picBedName].configOptions[option]
|
||||
const configOption = supportedPicBedList[platformName].configOptions[option]
|
||||
|
||||
if (configResult[fieldKey] === undefined || configResult[fieldKey] === '') {
|
||||
if (configResult.value[option] === undefined || configResult.value[option] === '') {
|
||||
if (configOption.default !== undefined) {
|
||||
configResult[fieldKey] = configOption.default
|
||||
configResult.value[option] = configOption.default
|
||||
} else if (configOption.type === 'boolean') {
|
||||
configResult[fieldKey] = false
|
||||
configResult.value[option] = false
|
||||
} else if (configOption.type === 'number') {
|
||||
configResult[fieldKey] = 0
|
||||
configResult.value[option] = 0
|
||||
} else {
|
||||
configResult[fieldKey] = ''
|
||||
configResult.value[option] = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -423,7 +418,7 @@ const cancelEditMode = () => {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
getExistingConfig(activeName)
|
||||
getExistingConfig(platformName)
|
||||
await manageStore.refreshConfig()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -56,27 +56,27 @@
|
||||
/>
|
||||
<span class="text-sm font-semibold text-secondary">{{ t('pages.manage.main.loading') }}</span>
|
||||
</div>
|
||||
<div v-else class="menu-list">
|
||||
<div
|
||||
v-for="item in bucketNameList"
|
||||
:key="item"
|
||||
class="menu-item"
|
||||
:class="{ active: item === currentSelectedBucket }"
|
||||
@click="handleSelectMenu(item)"
|
||||
>
|
||||
<span
|
||||
class="group/badge overflow-hidden text-sm font-medium text-ellipsis whitespace-nowrap text-secondary"
|
||||
<div v-else class="flex flex-col gap-1">
|
||||
<template v-for="item in bucketNameList" :key="item">
|
||||
<div
|
||||
class="flex cursor-pointer items-center gap-3 rounded-sm p-3 text-sm shadow-xs hover:bg-surface [.active]:bg-accent/20"
|
||||
:class="{ active: item === currentSelectedBucket }"
|
||||
@click="handleSelectMenu(item)"
|
||||
>
|
||||
<div class="min-w-0 flex-1 overflow-hidden">
|
||||
<div
|
||||
class="flex overflow-hidden text-ellipsis whitespace-nowrap group-hover/badge:w-fit group-hover/badge:animate-[badge-scroll_5s_linear_infinite] group-hover/badge:text-clip"
|
||||
>
|
||||
<span class="leading-none whitespace-nowrap group-hover/badge:pr-[20px]">{{ item }}</span>
|
||||
<span class="hidden leading-none whitespace-nowrap group-hover/badge:block">{{ item }}</span>
|
||||
<span
|
||||
class="group/badge overflow-hidden text-sm font-medium text-ellipsis whitespace-nowrap text-secondary"
|
||||
>
|
||||
<div class="min-w-0 flex-1 overflow-hidden">
|
||||
<div
|
||||
class="flex overflow-hidden text-ellipsis whitespace-nowrap group-hover/badge:w-fit group-hover/badge:animate-[badge-scroll_5s_linear_infinite] group-hover/badge:text-clip"
|
||||
>
|
||||
<span class="leading-none whitespace-nowrap group-hover/badge:pr-[20px]">{{ item }}</span>
|
||||
<span class="hidden leading-none whitespace-nowrap group-hover/badge:block">{{ item }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
</div></template
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
:text="t('pages.manage.main.settings')"
|
||||
:icon="SettingsIcon"
|
||||
class="border-none"
|
||||
@click="openBucketPageSetting"
|
||||
@click="openSettingPage"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -113,8 +113,16 @@
|
||||
@mousedown="startResize"
|
||||
></div>
|
||||
|
||||
<div class="content-area">
|
||||
<router-view />
|
||||
<div class="m-0 box-border flex h-full w-full flex-1 flex-col overflow-hidden border-none">
|
||||
<template v-if="currentPageInMain === 'bucket'">
|
||||
<BucketPage :config-map="configMap" />
|
||||
</template>
|
||||
<template v-else-if="currentPageInMain === 'setting'">
|
||||
<ManageSetting />
|
||||
</template>
|
||||
<template v-else>
|
||||
<EmptyPage no-desc />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -173,110 +181,68 @@
|
||||
</div>
|
||||
</CustomModal>
|
||||
</transition>
|
||||
|
||||
<!-- New Bucket Drawer -->
|
||||
<div v-if="nweBucketDrawerVisible" class="drawer-overlay" @click="nweBucketDrawerVisible = false">
|
||||
<div class="drawer-container" @click.stop>
|
||||
<div class="drawer-header">
|
||||
<h3 class="drawer-title">
|
||||
{{ t('pages.manage.main.newBucket') }}
|
||||
</h3>
|
||||
<button class="drawer-close" @click="nweBucketDrawerVisible = false">
|
||||
<XIcon class="close-icon" />
|
||||
</button>
|
||||
</div>
|
||||
<transition
|
||||
name="modal-bucket"
|
||||
enter-active-class="transition-all duration-200 ease-apple"
|
||||
leave-active-class="transition-all duration-200 ease-apple"
|
||||
enter-from-class="opacity-0"
|
||||
leave-to-class="opacity-0"
|
||||
>
|
||||
<!-- New Bucket Drawer -->
|
||||
<CustomModal
|
||||
v-if="bucketDrawerVisible"
|
||||
v-model:visible="bucketDrawerVisible"
|
||||
:title="t('pages.manage.main.newBucket')"
|
||||
width="600px"
|
||||
height="auto"
|
||||
>
|
||||
<div class="drawer-content">
|
||||
<form @submit.prevent="createNewBucket(currentPicBedName)">
|
||||
<div class="form-header">
|
||||
<div class="form-icon">
|
||||
<img :src="`./assets/${currentPicBedName}.webp`" class="picbed-form-icon" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-divider" />
|
||||
|
||||
<div v-for="option in newBucketConfig[currentPicBedName].options" :key="option" class="form-group">
|
||||
<label class="form-label">
|
||||
{{ newBucketConfig[currentPicBedName].configOptions[option].description }}
|
||||
</label>
|
||||
|
||||
<!-- Input field -->
|
||||
<input
|
||||
v-if="
|
||||
newBucketConfig[currentPicBedName].configOptions[option].component === 'input' &&
|
||||
currentPicBedName !== 'tcyun'
|
||||
"
|
||||
v-model.trim="newBucketConfigResult[currentPicBedName + '.' + option]"
|
||||
type="text"
|
||||
class="form-input"
|
||||
:placeholder="newBucketConfig[currentPicBedName].configOptions[option].placeholder"
|
||||
/>
|
||||
|
||||
<!-- TCyun special input with append -->
|
||||
<div
|
||||
v-if="
|
||||
currentPicBedName === 'tcyun' &&
|
||||
newBucketConfig[currentPicBedName].configOptions[option].component === 'input'
|
||||
"
|
||||
class="input-group"
|
||||
>
|
||||
<input
|
||||
<SettingSection :title="supportedPicBedList[currentPicBedName].name" :icon="Database" only-one-row>
|
||||
<template v-for="option in newBucketConfig[currentPicBedName].options" :key="option">
|
||||
<SettingCard :p1="newBucketConfig[currentPicBedName].configOptions[option].component === 'switch'">
|
||||
<CustomInput
|
||||
v-if="newBucketConfig[currentPicBedName].configOptions[option].component === 'input'"
|
||||
v-model.trim="newBucketConfigResult[currentPicBedName + '.' + option]"
|
||||
type="text"
|
||||
class="form-input group-input"
|
||||
:title="newBucketConfig[currentPicBedName].configOptions[option].description"
|
||||
:placeholder="newBucketConfig[currentPicBedName].configOptions[option].placeholder"
|
||||
/>
|
||||
<span class="input-append">{{ '-' + currentPagePicBedConfig.appId }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Select field -->
|
||||
<div
|
||||
v-if="newBucketConfig[currentPicBedName].configOptions[option].component === 'select'"
|
||||
class="select-wrapper"
|
||||
>
|
||||
<select v-model="newBucketConfigResult[currentPicBedName + '.' + option]" class="form-select">
|
||||
<option
|
||||
v-for="(label, value) in newBucketConfig[currentPicBedName].configOptions[option].options"
|
||||
:key="value"
|
||||
:value="value"
|
||||
>
|
||||
{{ label }}
|
||||
</option>
|
||||
</select>
|
||||
<ChevronDownIcon class="select-arrow" />
|
||||
</div>
|
||||
|
||||
<!-- Switch field -->
|
||||
<label
|
||||
v-if="newBucketConfig[currentPicBedName].configOptions[option].component === 'switch'"
|
||||
class="switch-label"
|
||||
>
|
||||
<input
|
||||
>
|
||||
<template v-if="currentPicBedName === 'tcyun'" #input-extra>
|
||||
<span
|
||||
class="absolute top-0.5 right-0 flex cursor-not-allowed items-center justify-center rounded-xl border border-border bg-gray-300 p-2.5 text-sm font-semibold text-secondary"
|
||||
>{{ '-' + currentPagePicBedConfig.appId }}</span
|
||||
>
|
||||
</template>
|
||||
</CustomInput>
|
||||
<CustomSwitch
|
||||
v-if="newBucketConfig[currentPicBedName].configOptions[option].component === 'switch'"
|
||||
v-model="newBucketConfigResult[currentPicBedName + '.' + option]"
|
||||
type="checkbox"
|
||||
class="switch-input"
|
||||
:true-value="true"
|
||||
:false-value="false"
|
||||
:title="newBucketConfig[currentPicBedName].configOptions[option].description"
|
||||
small
|
||||
no-border
|
||||
/>
|
||||
<span class="switch-slider">
|
||||
<span class="switch-button" />
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="button" class="action-button secondary" @click="nweBucketDrawerVisible = false">
|
||||
{{ $t('common.cancel') }}
|
||||
</button>
|
||||
<button type="submit" class="action-button primary">
|
||||
<CheckIcon class="button-icon" />
|
||||
{{ t('common.submit') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<SingleSelect
|
||||
v-if="newBucketConfig[currentPicBedName].configOptions[option].component === 'select'"
|
||||
v-model="newBucketConfigResult[currentPicBedName + '.' + option]"
|
||||
:title="newBucketConfig[currentPicBedName].configOptions[option].description"
|
||||
:key-list="Object.keys(newBucketConfig[currentPicBedName].configOptions[option].options)"
|
||||
:fronticon="false"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
{{ newBucketConfig[currentPicBedName].configOptions[option].options[item] }}
|
||||
</template>
|
||||
</SingleSelect>
|
||||
</SettingCard>
|
||||
</template>
|
||||
</SettingSection>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<CustomButton type="secondary" :text="$t('common.cancel')" @click="bucketDrawerVisible = false" />
|
||||
<CustomButton type="primary" :text="$t('common.submit')" @click="createNewBucket(currentPicBedName)" />
|
||||
</template>
|
||||
</CustomModal>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -284,20 +250,27 @@
|
||||
import {
|
||||
ArrowLeftRightIcon,
|
||||
CheckIcon,
|
||||
ChevronDownIcon,
|
||||
Database,
|
||||
ExternalLinkIcon,
|
||||
HomeIcon,
|
||||
PlusIcon,
|
||||
SettingsIcon,
|
||||
XIcon,
|
||||
} from 'lucide-vue-next'
|
||||
import { onBeforeMount, reactive, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
import CustomButton from '@/components/common/CustomButton.vue'
|
||||
import CustomInput from '@/components/common/CustomInput.vue'
|
||||
import CustomModal from '@/components/common/CustomModal.vue'
|
||||
import CustomSwitch from '@/components/common/CustomSwitch.vue'
|
||||
import SettingCard from '@/components/common/SettingCard.vue'
|
||||
import SettingSection from '@/components/common/SettingSection.vue'
|
||||
import SingleSelect from '@/components/common/SingleSelect.vue'
|
||||
import useMessage from '@/hooks/useMessage'
|
||||
import BucketPage from '@/manage/pages/BucketPage.vue'
|
||||
import EmptyPage from '@/manage/pages/EmptyPage.vue'
|
||||
import ManageSetting from '@/manage/pages/ManageSetting.vue'
|
||||
import { useManageStore } from '@/manage/store/manageStore'
|
||||
import { supportedPicBedList } from '@/manage/utils/constants'
|
||||
import { newBucketConfig } from '@/manage/utils/newBucketConfig'
|
||||
@@ -308,6 +281,8 @@ const manageStore = useManageStore() as any
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const message = useMessage()
|
||||
const currentPageInMain = ref<'bucket' | 'setting' | 'empty'>('empty')
|
||||
const configMap = ref<any>(null)
|
||||
|
||||
const currentAlias = ref(route.query.alias as string)
|
||||
const currentPicBedName = ref(route.query.picBedName as string)
|
||||
@@ -324,7 +299,7 @@ const currentSelectedBucket = ref('')
|
||||
const bucketNameList = ref([] as string[])
|
||||
|
||||
const isLoadingBucketList = ref(false)
|
||||
const nweBucketDrawerVisible = ref(false)
|
||||
const bucketDrawerVisible = ref(false)
|
||||
const picBedSwitchDialogVisible = ref(false)
|
||||
|
||||
watch(
|
||||
@@ -380,7 +355,7 @@ const menuTitleMap: IStringKeyMap = {
|
||||
const openPicBedUrl = () => window.electron.sendRPC(IRPCActionType.OPEN_URL, urlMap[currentPagePicBedConfig.picBedName])
|
||||
|
||||
function openNewBucketDrawer() {
|
||||
nweBucketDrawerVisible.value = true
|
||||
bucketDrawerVisible.value = true
|
||||
}
|
||||
|
||||
function createNewBucket(picBedName: string) {
|
||||
@@ -403,7 +378,7 @@ function createNewBucket(picBedName: string) {
|
||||
if (result) {
|
||||
// Show success notification
|
||||
message.success(t('pages.manage.main.createSuccess'))
|
||||
nweBucketDrawerVisible.value = false
|
||||
bucketDrawerVisible.value = false
|
||||
setTimeout(() => {
|
||||
getBucketList()
|
||||
}, 2000)
|
||||
@@ -452,7 +427,7 @@ function handleSelectMenu(bucketName: string) {
|
||||
prefix = prefix.endsWith('/') ? prefix : `${prefix}/`
|
||||
}
|
||||
|
||||
const configMap = {
|
||||
const configMapT = {
|
||||
prefix,
|
||||
bucketName,
|
||||
customUrl: transformedConfig[bucketName]?.customUrl ?? '',
|
||||
@@ -464,16 +439,8 @@ function handleSelectMenu(bucketName: string) {
|
||||
webPath: currentPicBedConfig.webPath || '',
|
||||
}
|
||||
currentSelectedBucket.value = bucketName
|
||||
router.push({
|
||||
path: '/main-page/manage-main-page/manage-bucket-page',
|
||||
query: {
|
||||
configMap: JSON.stringify(configMap),
|
||||
alias: currentAlias.value,
|
||||
picBedName: currentPicBedName.value,
|
||||
config: JSON.stringify(currentPagePicBedConfig),
|
||||
allPicBedConfigure: JSON.stringify(allPicBedConfigure),
|
||||
},
|
||||
})
|
||||
configMap.value = configMapT
|
||||
currentPageInMain.value = 'bucket'
|
||||
}
|
||||
|
||||
function switchPicBed(picBedAlias: string) {
|
||||
@@ -511,16 +478,8 @@ function changePicBed() {
|
||||
picBedSwitchDialogVisible.value = true
|
||||
}
|
||||
|
||||
function openBucketPageSetting() {
|
||||
router.push({
|
||||
path: '/main-page/manage-main-page/manage-setting-page',
|
||||
query: {
|
||||
alias: currentAlias.value,
|
||||
picBedName: currentPicBedName.value,
|
||||
config: JSON.stringify(currentPagePicBedConfig),
|
||||
allPicBedConfigure: JSON.stringify(allPicBedConfigure),
|
||||
},
|
||||
})
|
||||
function openSettingPage() {
|
||||
currentPageInMain.value = 'setting'
|
||||
}
|
||||
|
||||
function startResize(event: MouseEvent) {
|
||||
@@ -554,5 +513,3 @@ onBeforeMount(() => {
|
||||
getBucketList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style src="./css/ManageMain.css" scoped></style>
|
||||
|
||||
@@ -1,688 +0,0 @@
|
||||
/* ManageMain Page Styles */
|
||||
|
||||
html, body {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.manage-container {
|
||||
display: flex;
|
||||
height: calc(100vh - 32px);
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.manage-card {
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
background: var(--color-background-secondary);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.header-card {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 68px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.header-icon-img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.header-text .header-title {
|
||||
margin: 0 0 0.01rem;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.header-text .header-subtitle {
|
||||
margin: 0;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.main-card {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
min-height: 0; /* Fix for flex overflow */
|
||||
}
|
||||
|
||||
.main-layout {
|
||||
display: flex;
|
||||
height:100%;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
display: flex;
|
||||
border-right: 1px solid var(--color-border);
|
||||
min-width: 120px;
|
||||
max-width: 400px;
|
||||
min-height: 0; /* Fix for flex overflow */
|
||||
background: var(--color-surface-secondary);
|
||||
transition: width 0.1s ease-out;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.resize-handle {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 4px;
|
||||
background: transparent;
|
||||
cursor: col-resize;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.resize-handle:hover {
|
||||
background: var(--color-border);
|
||||
}
|
||||
|
||||
.resize-handle:hover .resize-line {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.resize-line {
|
||||
border-radius: 1px;
|
||||
width: 2px;
|
||||
height: 40px;
|
||||
background: var(--color-accent);
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
padding: 1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.sidebar-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 0.5rem;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 2rem;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
border: 2px solid var(--color-border);
|
||||
border-top: 2px solid var(--color-accent);
|
||||
border-radius: var(--radius-round);
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 0.75rem;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.menu-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
transition: var(--transition-fast);
|
||||
gap: 0.75rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.menu-item:hover {
|
||||
background: var(--color-surface);
|
||||
}
|
||||
|
||||
.menu-item.active {
|
||||
color: white;
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
.menu-item.active .menu-icon {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: var(--color-text-secondary);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.menu-icon.active {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
.menu-text {
|
||||
overflow: hidden;
|
||||
min-width: 0;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
overflow-wrap: break-word;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sidebar-footer {
|
||||
border-top: 1px solid var(--color-border);
|
||||
padding: 0.5rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.footer-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.footer-action-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: none;
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.75rem;
|
||||
width: 100%;
|
||||
font-size: 0.875rem;
|
||||
text-align: left;
|
||||
color: var(--color-text-primary);
|
||||
background: none;
|
||||
transition: var(--transition-fast);
|
||||
gap: 0.75rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.footer-action-item:hover {
|
||||
background: var(--color-surface);
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: var(--color-text-secondary);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.action-text {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.content-area {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: none;
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.8rem;
|
||||
font-family: inherit;
|
||||
font-weight: 500;
|
||||
transition: var(--transition-fast);
|
||||
gap: 0.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.action-button.primary {
|
||||
color: white;
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
.action-button.primary:hover {
|
||||
background: var(--color-accent-hover);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.action-button.secondary {
|
||||
border: 1px solid var(--color-border);
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
.action-button.secondary:hover {
|
||||
border-color: var(--color-accent);
|
||||
}
|
||||
|
||||
.button-icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
/* Dialog styles */
|
||||
.dialog-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 2000;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: rgb(0 0 0 / 50%);
|
||||
}
|
||||
|
||||
.dialog-container {
|
||||
overflow: auto;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-2xl);
|
||||
padding: 0.75rem;
|
||||
width: 85vw;
|
||||
max-width: 90vw;
|
||||
max-height: 85vh;
|
||||
background: var(--color-background-tertiary);
|
||||
box-shadow: var(--shadow-xl);
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 1.5rem 1.5rem 0;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
font-size: 1.25rem;
|
||||
margin-bottom: 10px;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.dialog-close {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
font-size: 1.5rem;
|
||||
color: var(--color-text-secondary);
|
||||
background: none;
|
||||
transition: all 0.2s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dialog-close:hover {
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-surface);
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
overflow-y: auto;
|
||||
margin-bottom: 1.5rem;
|
||||
padding: 0.2rem;
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
|
||||
.choice-cos {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.picbed-card {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: 2px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 1.5rem;
|
||||
background: var(--color-background-secondary);
|
||||
transition: var(--transition-fast);
|
||||
flex-direction: column;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.picbed-card:hover {
|
||||
border-color: var(--color-accent);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.picbed-card.active {
|
||||
border-color: var(--color-accent);
|
||||
background-color: var(--color-surface);
|
||||
}
|
||||
|
||||
.picbed-card.main-card {
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.picbed-card.main-card:hover {
|
||||
border-color: var(--color-primary);
|
||||
background-color: var(--color-surface);
|
||||
}
|
||||
|
||||
.card-icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-bottom: 0.75rem;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.picbed-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.main-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: var(--color-error);
|
||||
}
|
||||
|
||||
.card-content {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.main-title {
|
||||
color: var(--color-error);
|
||||
}
|
||||
|
||||
.check-icon {
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
/* Drawer styles */
|
||||
.drawer-overlay {
|
||||
position: fixed;
|
||||
inset: 32px 0 0;
|
||||
z-index: 2000;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
background: rgb(0 0 0 / 50%);
|
||||
}
|
||||
|
||||
.drawer-container {
|
||||
overflow-y: auto;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-2xl);
|
||||
width: 400px;
|
||||
max-width: 90vw;
|
||||
height: calc(100vh - 32px);
|
||||
background: var(--color-background-tertiary);
|
||||
box-shadow: var(--shadow-xl);
|
||||
}
|
||||
|
||||
.drawer-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.drawer-title {
|
||||
margin: 0;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.drawer-close {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border: none;
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 0.25rem;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: var(--color-text-secondary);
|
||||
background: none;
|
||||
transition: var(--transition-fast);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.drawer-close:hover {
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
.drawer-content {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.form-header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 2rem 0;
|
||||
}
|
||||
|
||||
.form-icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.picbed-form-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.form-divider {
|
||||
margin: 1.5rem 0;
|
||||
height: 1px;
|
||||
background: var(--color-border);
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.form-input {
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.75rem;
|
||||
width: 100%;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-secondary);
|
||||
background: var(--color-surface);
|
||||
transition: var(--transition-fast);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
border-color: var(--color-accent);
|
||||
background: white;
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 2px rgb(0 122 255 / 20%);
|
||||
}
|
||||
|
||||
.input-group {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.group-input {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.input-append {
|
||||
border: 1px solid var(--color-border);
|
||||
border-left: none;
|
||||
padding: 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-secondary);
|
||||
background: var(--color-background-secondary);
|
||||
border-top-right-radius: var(--radius-md);
|
||||
border-bottom-right-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
.select-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.form-select {
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.75rem 2.5rem 0.75rem 0.75rem;
|
||||
width: 100%;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-background-tertiary);
|
||||
transition: var(--transition-fast);
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.form-select:focus {
|
||||
border-color: var(--color-accent);
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 2px rgb(0 122 255 / 20%);
|
||||
}
|
||||
|
||||
.select-arrow {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0.75rem;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: var(--color-text-secondary);
|
||||
transform: translateY(-50%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.switch-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.switch-input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.switch-slider {
|
||||
position: relative;
|
||||
border-radius: 0.75rem;
|
||||
width: 3rem;
|
||||
height: 1.5rem;
|
||||
background: var(--color-border);
|
||||
transition: var(--transition-fast);
|
||||
}
|
||||
|
||||
.switch-button {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
border-radius: var(--radius-round);
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
background: white;
|
||||
box-shadow: var(--shadow-sm);
|
||||
transition: var(--transition-fast);
|
||||
}
|
||||
|
||||
.switch-input:checked + .switch-slider {
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
.switch-input:checked + .switch-slider .switch-button {
|
||||
transform: translateX(1.5rem);
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 2rem;
|
||||
gap: 1rem;
|
||||
}
|
||||
@@ -71,6 +71,7 @@
|
||||
small
|
||||
:title="t('pages.settings.system.isDisableGPU')"
|
||||
:description="t('pages.settings.system.isDisableGPUDesc')"
|
||||
@update:model-value="handleIsDisableGPUChange"
|
||||
/>
|
||||
</SettingCard>
|
||||
|
||||
@@ -189,13 +190,16 @@
|
||||
<!-- Startup & Shortcuts Section -->
|
||||
<SettingSection :icon="Keyboard" :title="t('pages.settings.system.startupAndShortcuts')">
|
||||
<!-- Auto Launch Toggle -->
|
||||
<CustomSwitch
|
||||
v-model="formOfSetting.autoStart"
|
||||
small
|
||||
:title="t('pages.settings.system.autoLaunch')"
|
||||
:description="t('pages.settings.system.autoLaunchDesc')"
|
||||
@change="handleAutoStartChange(formOfSetting.autoStart)"
|
||||
/>
|
||||
<SettingCard p1>
|
||||
<CustomSwitch
|
||||
v-model="formOfSetting.autoStart"
|
||||
small
|
||||
no-border
|
||||
:title="t('pages.settings.system.autoLaunch')"
|
||||
:description="t('pages.settings.system.autoLaunchDesc')"
|
||||
@change="handleAutoStartChange(formOfSetting.autoStart)"
|
||||
/>
|
||||
</SettingCard>
|
||||
<CustomNavCard
|
||||
:title="t('pages.settings.system.setShortCuts')"
|
||||
:description="t('pages.settings.system.setShortCutsDesc')"
|
||||
@@ -1570,11 +1574,6 @@ const addWatch = () => {
|
||||
}
|
||||
})
|
||||
|
||||
watch(isDisableGPU, newVal => {
|
||||
message.info(t('pages.settings.system.needRestart'))
|
||||
saveConfig({ [configPaths.settings.isDisableGPU]: newVal })
|
||||
})
|
||||
|
||||
watch(
|
||||
advancedRename,
|
||||
newVal => {
|
||||
@@ -1744,6 +1743,12 @@ async function handleThemeChange(theme: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function handleIsDisableGPUChange(value: boolean | undefined) {
|
||||
if (value === undefined) return
|
||||
message.info(t('pages.settings.system.needRestart'))
|
||||
saveConfig({ [configPaths.settings.isDisableGPU]: value })
|
||||
}
|
||||
|
||||
async function initData() {
|
||||
const config = (await getConfig<IConfig>()) || ({} as IConfig)
|
||||
const settings = config.settings || {}
|
||||
|
||||
@@ -270,14 +270,7 @@
|
||||
height="auto"
|
||||
>
|
||||
<div class="flex-1 overflow-y-auto p-4">
|
||||
<config-form
|
||||
:id="configName"
|
||||
ref="$configForm"
|
||||
:config="config"
|
||||
:type="currentType"
|
||||
mode="plugin"
|
||||
:show-tooltips="false"
|
||||
/>
|
||||
<config-form :id="configName" ref="$configForm" :config="config" :type="currentType" mode="plugin" />
|
||||
</div>
|
||||
<template #footer>
|
||||
<CustomButton type="secondary" :text="t('common.cancel')" @click="dialogVisible = false" />
|
||||
|
||||
Reference in New Issue
Block a user