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')"
|
:title="t('pages.configForm.configName')"
|
||||||
:placeholder="t('pages.configForm.configNamePlaceholder')"
|
:placeholder="t('pages.configForm.configNamePlaceholder')"
|
||||||
required
|
required
|
||||||
|
:class="{ 'border-error!': validationErrors._configName }"
|
||||||
|
@blur="validateForm"
|
||||||
@input="clearFieldError('_configName')"
|
@input="clearFieldError('_configName')"
|
||||||
/>
|
/>
|
||||||
<template v-if="validationErrors._configName" #extra>
|
<template v-if="validationErrors._configName" #extra>
|
||||||
@@ -27,24 +29,10 @@
|
|||||||
:class="{ 'border-error!': validationErrors[item.name] }"
|
:class="{ 'border-error!': validationErrors[item.name] }"
|
||||||
:title="item.alias || item.name"
|
:title="item.alias || item.name"
|
||||||
:required="item.required || false"
|
:required="item.required || false"
|
||||||
|
:tips="item.tips"
|
||||||
|
@blur="validateForm"
|
||||||
@input="clearFieldError(item.name)"
|
@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
|
<CustomSwitch
|
||||||
v-if="item.type === 'confirm'"
|
v-if="item.type === 'confirm'"
|
||||||
v-model="ruleForm[item.name]"
|
v-model="ruleForm[item.name]"
|
||||||
@@ -114,8 +102,6 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { cloneDeep, union } from 'lodash-es'
|
import { cloneDeep, union } from 'lodash-es'
|
||||||
import { Info } from 'lucide-vue-next'
|
|
||||||
import { marked } from 'marked'
|
|
||||||
import { reactive, ref, watch } from 'vue'
|
import { reactive, ref, watch } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
@@ -133,10 +119,9 @@ interface IProps {
|
|||||||
type: 'uploader' | 'transformer' | 'plugin'
|
type: 'uploader' | 'transformer' | 'plugin'
|
||||||
id: string
|
id: string
|
||||||
mode?: 'picbed' | 'plugin'
|
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 $route = useRoute()
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
@@ -144,7 +129,6 @@ const { t } = useI18n()
|
|||||||
const configList = ref<IPicGoPluginConfig[]>([])
|
const configList = ref<IPicGoPluginConfig[]>([])
|
||||||
const ruleForm = reactive<IStringKeyMap>({})
|
const ruleForm = reactive<IStringKeyMap>({})
|
||||||
const validationErrors = reactive<IStringKeyMap>({})
|
const validationErrors = reactive<IStringKeyMap>({})
|
||||||
const visibleTooltips = reactive<Record<string, boolean>>({})
|
|
||||||
|
|
||||||
// Watch for config changes
|
// Watch for config changes
|
||||||
watch(
|
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> {
|
async function validate(): Promise<IStringKeyMap | false> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const isValid = validateForm()
|
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() {
|
function getConfigType() {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'plugin': {
|
case 'plugin': {
|
||||||
|
|||||||
@@ -1,11 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<div class="flex items-center gap-2">
|
<div class="mb-1 flex items-center gap-2">
|
||||||
<label class="mb-2 text-sm font-semibold text-secondary"
|
<label class="text-sm font-semibold text-secondary"
|
||||||
>{{ title }}
|
>{{ title }}
|
||||||
<span v-if="required" class="ml-1 text-danger">*</span>
|
<span v-if="required" class="ml-1 text-danger">*</span>
|
||||||
</label>
|
</label>
|
||||||
<slot name="title-extra"></slot>
|
<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>
|
||||||
<div class="relative w-full">
|
<div class="relative w-full">
|
||||||
<input
|
<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"
|
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"
|
:placeholder="placeholder"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
v-if="isPassword"
|
v-if="isPassword"
|
||||||
type="button"
|
type="button"
|
||||||
@@ -31,7 +43,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<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'
|
import { onMounted, ref } from 'vue'
|
||||||
|
|
||||||
const [modelValue, modifiers] = defineModel<any>({
|
const [modelValue, modifiers] = defineModel<any>({
|
||||||
@@ -49,12 +62,14 @@ const [modelValue, modifiers] = defineModel<any>({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const type = ref('text')
|
const type = ref('text')
|
||||||
|
const visibleTooltips = ref(false)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isPassword = false,
|
isPassword = false,
|
||||||
title,
|
title,
|
||||||
inputType = 'text',
|
inputType = 'text',
|
||||||
placeholder,
|
placeholder,
|
||||||
|
tips = '',
|
||||||
required = false,
|
required = false,
|
||||||
} = defineProps<{
|
} = defineProps<{
|
||||||
isPassword?: boolean
|
isPassword?: boolean
|
||||||
@@ -62,8 +77,21 @@ const {
|
|||||||
inputType?: string
|
inputType?: string
|
||||||
placeholder: string
|
placeholder: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
|
tips?: string
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
function toggleTooltip() {
|
||||||
|
visibleTooltips.value = !visibleTooltips.value
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformMarkdownToHTML(markdown: string) {
|
||||||
|
try {
|
||||||
|
return marked.parse(markdown)
|
||||||
|
} catch (_e) {
|
||||||
|
return markdown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
inheritAttrs: false,
|
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="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' : ''"
|
: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
|
<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="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="
|
:class="
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<slot name="title-extra"></slot>
|
<slot name="title-extra"></slot>
|
||||||
<div v-if="showTooltips && tips !== ''" class="relative">
|
<div v-if="tips" class="relative">
|
||||||
<div
|
<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"
|
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()"
|
@click="toggleTooltip()"
|
||||||
@@ -47,6 +47,8 @@ import { Info } from 'lucide-vue-next'
|
|||||||
import { marked } from 'marked'
|
import { marked } from 'marked'
|
||||||
import { onMounted, ref } from 'vue'
|
import { onMounted, ref } from 'vue'
|
||||||
|
|
||||||
|
const emit = defineEmits(['change'])
|
||||||
|
|
||||||
const visibleTooltips = ref(false)
|
const visibleTooltips = ref(false)
|
||||||
|
|
||||||
const modelValue = defineModel<boolean>()
|
const modelValue = defineModel<boolean>()
|
||||||
@@ -55,7 +57,6 @@ const {
|
|||||||
description = '',
|
description = '',
|
||||||
noBorder = false,
|
noBorder = false,
|
||||||
small = false,
|
small = false,
|
||||||
showTooltips = true,
|
|
||||||
tips = '',
|
tips = '',
|
||||||
required = false,
|
required = false,
|
||||||
} = defineProps<{
|
} = defineProps<{
|
||||||
@@ -63,7 +64,6 @@ const {
|
|||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
small?: boolean
|
small?: boolean
|
||||||
showTooltips?: boolean
|
|
||||||
tips?: string
|
tips?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<div
|
<div
|
||||||
v-show="dropDownOpen"
|
v-show="dropDownOpen"
|
||||||
ref="optionsRef"
|
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
|
<button
|
||||||
v-for="key in keyList"
|
v-for="key in keyList"
|
||||||
|
|||||||
@@ -521,6 +521,7 @@
|
|||||||
"noDataDesc": "Please create a bucket or upload images first"
|
"noDataDesc": "Please create a bucket or upload images first"
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
|
"aliasExistMsg": "Alias duplicate ",
|
||||||
"aliasMsg": "Alias may only contain Chinese characters, letters, numbers, underscores, and hyphens",
|
"aliasMsg": "Alias may only contain Chinese characters, letters, numbers, underscores, and hyphens",
|
||||||
"configChangeMsg": "Configuration changed",
|
"configChangeMsg": "Configuration changed",
|
||||||
"configSaveMsg": "Configuration saved",
|
"configSaveMsg": "Configuration saved",
|
||||||
|
|||||||
@@ -521,6 +521,7 @@
|
|||||||
"noDataDesc": "请先创建存储桶或上传图片"
|
"noDataDesc": "请先创建存储桶或上传图片"
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
|
"aliasExistMsg": "别名与已有配置重复",
|
||||||
"aliasMsg": "别名只能包含中文、英文、数字、下划线和中划线",
|
"aliasMsg": "别名只能包含中文、英文、数字、下划线和中划线",
|
||||||
"configChangeMsg": "配置已更改",
|
"configChangeMsg": "配置已更改",
|
||||||
"configSaveMsg": "配置已保存",
|
"configSaveMsg": "配置已保存",
|
||||||
|
|||||||
@@ -521,6 +521,7 @@
|
|||||||
"noDataDesc": "請先建立儲存桶或上傳圖片"
|
"noDataDesc": "請先建立儲存桶或上傳圖片"
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
|
"aliasExistMsg": "別名與已有配置重複",
|
||||||
"aliasMsg": "別名只能包含中文、英文、數字、底線和連字號",
|
"aliasMsg": "別名只能包含中文、英文、數字、底線和連字號",
|
||||||
"configChangeMsg": "設定已變更",
|
"configChangeMsg": "設定已變更",
|
||||||
"configSaveMsg": "設定已儲存",
|
"configSaveMsg": "設定已儲存",
|
||||||
|
|||||||
@@ -1263,7 +1263,6 @@ import { marked } from 'marked'
|
|||||||
import { v4 as uuidv4 } from 'uuid'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
import { computed, nextTick, onBeforeMount, onBeforeUnmount, reactive, ref, useTemplateRef, watch } from 'vue'
|
import { computed, nextTick, onBeforeMount, onBeforeUnmount, reactive, ref, useTemplateRef, watch } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useRoute } from 'vue-router'
|
|
||||||
|
|
||||||
import ImageLocal from '@/components/ImageLocal.vue'
|
import ImageLocal from '@/components/ImageLocal.vue'
|
||||||
import ImagePreSign from '@/components/ImagePreSign.vue'
|
import ImagePreSign from '@/components/ImagePreSign.vue'
|
||||||
@@ -1290,9 +1289,6 @@ import { trimPath } from '@/utils/common'
|
|||||||
import { IRPCActionType } from '@/utils/enum'
|
import { IRPCActionType } from '@/utils/enum'
|
||||||
import { cancelDownloadLoadingFileList, refreshDownloadFileTransferList } from '@/utils/static'
|
import { cancelDownloadLoadingFileList, refreshDownloadFileTransferList } from '@/utils/static'
|
||||||
|
|
||||||
const { t } = useI18n()
|
|
||||||
const message = useMessage()
|
|
||||||
const confirm = useConfirm()
|
|
||||||
/*
|
/*
|
||||||
configMap:{
|
configMap:{
|
||||||
prefix: string, -> baseDir
|
prefix: string, -> baseDir
|
||||||
@@ -1304,37 +1300,28 @@ configMap:{
|
|||||||
bucketConfig
|
bucketConfig
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
const getExtension = (fileName: string) => window.node.path.extname(fileName).slice(1)
|
|
||||||
const linkFormatArray = [
|
const props = defineProps<{
|
||||||
{ key: 'Url', value: 'url' },
|
configMap: Record<string, any>
|
||||||
{ 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']
|
|
||||||
|
|
||||||
type ISortTypeList = 'name' | 'size' | 'time' | 'ext' | 'check' | 'init'
|
type ISortTypeList = 'name' | 'size' | 'time' | 'ext' | 'check' | 'init'
|
||||||
const sortTypeList = ['name', 'size', 'time', 'ext', 'check', 'init']
|
|
||||||
const currentSortType = ref<ISortTypeList>('name')
|
|
||||||
|
|
||||||
// 路由相关
|
let fileTransferInterval: NodeJS.Timeout | undefined
|
||||||
const route = useRoute()
|
let downloadInterval: NodeJS.Timeout | undefined
|
||||||
|
let scrollTimeout: ReturnType<typeof setTimeout> | undefined
|
||||||
|
const { t } = useI18n()
|
||||||
|
const message = useMessage()
|
||||||
|
const confirm = useConfirm()
|
||||||
// 页面状态变量相关
|
// 页面状态变量相关
|
||||||
const manageStore = useManageStore()
|
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 isLoadingData = ref(false)
|
||||||
const isShowLoadingPage = ref(false)
|
const isShowLoadingPage = ref(false)
|
||||||
const isShowImagePreview = 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)
|
const isContentFullscreen = ref(false)
|
||||||
// 新增的UI控制变量
|
const layoutStyle = ref<'list' | 'grid'>('grid')
|
||||||
const copyDropdownOpen = ref(false)
|
const copyDropdownOpen = ref(false)
|
||||||
const sortDropdownOpen = ref(false)
|
const sortDropdownOpen = ref(false)
|
||||||
const copyDropdownIndex = ref(-1)
|
const copyDropdownIndex = ref(-1)
|
||||||
@@ -1376,57 +1363,26 @@ const uploadPanelFilesList = ref([] as any[])
|
|||||||
const cancelToken = ref('')
|
const cancelToken = ref('')
|
||||||
const isLoadingUploadPanelFiles = ref(false)
|
const isLoadingUploadPanelFiles = ref(false)
|
||||||
const isUploadKeepDirStructure = ref(manageStore.config.settings.isUploadKeepDirStructure ?? true)
|
const isUploadKeepDirStructure = ref(manageStore.config.settings.isUploadKeepDirStructure ?? true)
|
||||||
const uploadingTaskList = computed(() =>
|
const currentSortType = ref<ISortTypeList>('name')
|
||||||
uploadTaskList.value.filter(item => ['uploading', 'queuing', 'paused'].includes(item.status)),
|
|
||||||
)
|
|
||||||
const uploadedTaskList = computed(() =>
|
|
||||||
uploadTaskList.value.filter(item => ['uploaded', 'failed', 'canceled'].includes(item.status)),
|
|
||||||
)
|
|
||||||
// 下载页面相关
|
// 下载页面相关
|
||||||
const isShowDownloadPanel = ref(false)
|
const isShowDownloadPanel = ref(false)
|
||||||
const isLoadingDownloadData = ref(false)
|
const isLoadingDownloadData = ref(false)
|
||||||
const activeDownLoadTab = ref('downloading')
|
const activeDownLoadTab = ref('downloading')
|
||||||
const currentDownloadFileList = reactive([] as any[])
|
const currentDownloadFileList = reactive([] as any[])
|
||||||
const downloadTaskList = ref([] as IDownloadTask[])
|
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 dialogVisible = ref(false)
|
||||||
const urlToUpload = ref('')
|
const urlToUpload = ref('')
|
||||||
// 图片预览相关
|
// 图片预览相关
|
||||||
const previewedImage = 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 isShiftKeyPress = ref<boolean>(false)
|
||||||
const lastChoosed = ref<number>(-1)
|
const lastChoosed = ref<number>(-1)
|
||||||
// 自定义域名相关
|
// 自定义域名相关
|
||||||
const customDomainList = ref([] as any[])
|
const customDomainList = ref([] as any[])
|
||||||
const currentCustomDomain = ref('')
|
const currentCustomDomain = ref('')
|
||||||
const isShowCustomDomainSelectList = computed(() =>
|
const refreshDownloadTaskId = ref<NodeJS.Timeout | undefined>(undefined)
|
||||||
['tcyun', 'aliyun', 'qiniu', 'github'].includes(currentPicBedName.value),
|
const downloadCancelToken = ref('')
|
||||||
)
|
|
||||||
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 isShowMarkDownDialog = ref(false)
|
const isShowMarkDownDialog = ref(false)
|
||||||
const markDownContent = ref('')
|
const markDownContent = ref('')
|
||||||
@@ -1439,25 +1395,73 @@ const videoPlayerHeaders = ref({})
|
|||||||
const isShowCreateFolderDialog = ref(false)
|
const isShowCreateFolderDialog = ref(false)
|
||||||
const newFolderName = ref('')
|
const newFolderName = ref('')
|
||||||
const folderNameInput = useTemplateRef('folderNameInput')
|
const folderNameInput = useTemplateRef('folderNameInput')
|
||||||
// 重命名相关
|
// Refs for scroll handling
|
||||||
const isShowRenameFileIcon = computed(() =>
|
const virtualScrollerRef = useTemplateRef('virtualScrollerRef')
|
||||||
['tcyun', 'aliyun', 'qiniu', 'upyun', 's3plist', 'webdavplist', 'local', 'sftp'].includes(currentPicBedName.value),
|
const bucketContainerRef = useTemplateRef('bucketContainerRef')
|
||||||
)
|
|
||||||
const isShowBatchRenameDialog = ref(false)
|
const isShowBatchRenameDialog = ref(false)
|
||||||
const batchRenameMatch = ref('')
|
const batchRenameMatch = ref('')
|
||||||
const batchRenameReplace = ref('')
|
const batchRenameReplace = ref('')
|
||||||
const isRenameIncludeExt = ref(false)
|
const isRenameIncludeExt = ref(false)
|
||||||
const isSingleRename = ref(false)
|
const isSingleRename = ref(false)
|
||||||
const itemToBeRenamed = ref({} as any)
|
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 currentPicBedName = computed<string>(() => manageStore.config.picBed[configMap.value.alias].picBedName)
|
||||||
const paging = computed(() => manageStore.config.picBed[configMap.alias].paging)
|
const paging = computed(() => manageStore.config.picBed[configMap.value.alias].paging)
|
||||||
const itemsPerPage = computed(() => manageStore.config.picBed[configMap.alias].itemsPerPage)
|
const itemsPerPage = computed(() => manageStore.config.picBed[configMap.value.alias].itemsPerPage)
|
||||||
const calculateAllFileSize = computed(
|
const calculateAllFileSize = computed(
|
||||||
() =>
|
() =>
|
||||||
formatFileSize(currentPageFilesInfo.reduce((total: any, item: { fileSize: any }) => total + item.fileSize, 0)) ||
|
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),
|
['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() {
|
function getList() {
|
||||||
if (!searchText.value) {
|
if (!searchText.value) {
|
||||||
return currentPageFilesInfo
|
return currentPageFilesInfo
|
||||||
@@ -1492,8 +1546,6 @@ function getList() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 上传相关函数
|
|
||||||
|
|
||||||
function handleUploadKeepDirChange() {
|
function handleUploadKeepDirChange() {
|
||||||
saveConfig('settings.isUploadKeepDirStructure', isUploadKeepDirStructure.value)
|
saveConfig('settings.isUploadKeepDirStructure', isUploadKeepDirStructure.value)
|
||||||
manageStore.refreshConfig()
|
manageStore.refreshConfig()
|
||||||
@@ -1516,7 +1568,7 @@ function stopRefreshUploadTask() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleGetWebdavConfig() {
|
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
|
isContentFullscreen.value = !isContentFullscreen.value
|
||||||
}
|
}
|
||||||
|
|
||||||
let scrollTimeout: ReturnType<typeof setTimeout> | undefined
|
|
||||||
function handleBucketContainerScroll() {
|
function handleBucketContainerScroll() {
|
||||||
if (scrollTimeout) {
|
if (scrollTimeout) {
|
||||||
clearTimeout(scrollTimeout)
|
clearTimeout(scrollTimeout)
|
||||||
@@ -1760,18 +1811,18 @@ function uploadFiles() {
|
|||||||
}
|
}
|
||||||
formateduploadPanelFilesList.forEach((item: any) => {
|
formateduploadPanelFilesList.forEach((item: any) => {
|
||||||
param.fileArray.push({
|
param.fileArray.push({
|
||||||
alias: configMap.alias,
|
alias: configMap.value.alias,
|
||||||
bucketName: configMap.bucketName,
|
bucketName: configMap.value.bucketName,
|
||||||
region: configMap.bucketConfig.Location,
|
region: configMap.value.bucketConfig.Location,
|
||||||
key: item.key,
|
key: item.key,
|
||||||
filePath: item.path,
|
filePath: item.path,
|
||||||
fileSize: item.size,
|
fileSize: item.size,
|
||||||
fileName: item.rawName,
|
fileName: item.rawName,
|
||||||
githubBranch: currentCustomDomain.value,
|
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() {
|
function handleCopyUploadingTaskInfo() {
|
||||||
@@ -1827,7 +1878,7 @@ async function handleBreadcrumbClick(index: number) {
|
|||||||
isLoadingData.value = false
|
isLoadingData.value = false
|
||||||
window.electron.sendToMain('cancelLoadingFileList', cancelToken.value)
|
window.electron.sendToMain('cancelLoadingFileList', cancelToken.value)
|
||||||
}
|
}
|
||||||
configMap.prefix = targetPrefix
|
configMap.value.prefix = targetPrefix
|
||||||
isShowLoadingPage.value = true
|
isShowLoadingPage.value = true
|
||||||
resetParam(false)
|
resetParam(false)
|
||||||
isShowLoadingPage.value = false
|
isShowLoadingPage.value = false
|
||||||
@@ -1837,7 +1888,7 @@ async function handleClickFile(item: any) {
|
|||||||
const options = {} as any
|
const options = {} as any
|
||||||
if (currentPicBedName.value === 'webdavplist') {
|
if (currentPicBedName.value === 'webdavplist') {
|
||||||
options.headers = {
|
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) {
|
if (item.isImage) {
|
||||||
@@ -1848,7 +1899,7 @@ async function handleClickFile(item: any) {
|
|||||||
isLoadingData.value = false
|
isLoadingData.value = false
|
||||||
window.electron.sendToMain('cancelLoadingFileList', cancelToken.value)
|
window.electron.sendToMain('cancelLoadingFileList', cancelToken.value)
|
||||||
}
|
}
|
||||||
configMap.prefix = `/${item.key}`
|
configMap.value.prefix = `/${item.key}`
|
||||||
isShowLoadingPage.value = true
|
isShowLoadingPage.value = true
|
||||||
await resetParam(false)
|
await resetParam(false)
|
||||||
isShowLoadingPage.value = false
|
isShowLoadingPage.value = false
|
||||||
@@ -1892,17 +1943,17 @@ async function handleChangeCustomUrlInput() {
|
|||||||
async function handleChangeCustomUrl() {
|
async function handleChangeCustomUrl() {
|
||||||
if (['aliyun', 'tcyun', 'qiniu', 's3plist', 'webdavplist', 'local', 'sftp'].includes(currentPicBedName.value)) {
|
if (['aliyun', 'tcyun', 'qiniu', 's3plist', 'webdavplist', 'local', 'sftp'].includes(currentPicBedName.value)) {
|
||||||
const currentConfigs = await getConfig<any>('picBed')
|
const currentConfigs = await getConfig<any>('picBed')
|
||||||
const currentConfig = currentConfigs[configMap.alias]
|
const currentConfig = currentConfigs[configMap.value.alias]
|
||||||
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
||||||
if (currentTransformedConfig[configMap.bucketName]) {
|
if (currentTransformedConfig[configMap.value.bucketName]) {
|
||||||
currentTransformedConfig[configMap.bucketName].customUrl = currentCustomDomain.value
|
currentTransformedConfig[configMap.value.bucketName].customUrl = currentCustomDomain.value
|
||||||
} else {
|
} else {
|
||||||
currentTransformedConfig[configMap.bucketName] = {
|
currentTransformedConfig[configMap.value.bucketName] = {
|
||||||
customUrl: currentCustomDomain.value,
|
customUrl: currentCustomDomain.value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
currentConfig.transformedConfig = JSON.stringify(currentTransformedConfig)
|
currentConfig.transformedConfig = JSON.stringify(currentTransformedConfig)
|
||||||
saveConfig(`picBed.${configMap.alias}`, currentConfig)
|
saveConfig(`picBed.${configMap.value.alias}`, currentConfig)
|
||||||
await manageStore.refreshConfig()
|
await manageStore.refreshConfig()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1911,23 +1962,27 @@ async function handleChangeCustomUrl() {
|
|||||||
async function initCustomDomainList() {
|
async function initCustomDomainList() {
|
||||||
if (
|
if (
|
||||||
(['aliyun', 'tcyun', 'qiniu'].includes(currentPicBedName.value) &&
|
(['aliyun', 'tcyun', 'qiniu'].includes(currentPicBedName.value) &&
|
||||||
(manageStore.config.picBed[configMap.alias].isAutoCustomUrl === undefined ||
|
(manageStore.config.picBed[configMap.value.alias].isAutoCustomUrl === undefined ||
|
||||||
manageStore.config.picBed[configMap.alias].isAutoCustomUrl === true)) ||
|
manageStore.config.picBed[configMap.value.alias].isAutoCustomUrl === true)) ||
|
||||||
['github', 'smms', 'upyun', 'imgur'].includes(currentPicBedName.value)
|
['github', 'smms', 'upyun', 'imgur'].includes(currentPicBedName.value)
|
||||||
) {
|
) {
|
||||||
const param = {
|
const param = {
|
||||||
bucketName: configMap.bucketName,
|
bucketName: configMap.value.bucketName,
|
||||||
region: configMap.bucketConfig.Location,
|
region: configMap.value.bucketConfig.Location,
|
||||||
}
|
}
|
||||||
let defaultUrl = ''
|
let defaultUrl = ''
|
||||||
if (currentPicBedName.value === 'tcyun') {
|
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') {
|
} 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') {
|
} else if (currentPicBedName.value === 'github') {
|
||||||
defaultUrl = 'main'
|
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) {
|
if (res.length > 0) {
|
||||||
customDomainList.value.length = 0
|
customDomainList.value.length = 0
|
||||||
res.forEach((item: any) => {
|
res.forEach((item: any) => {
|
||||||
@@ -1958,49 +2013,52 @@ async function initCustomDomainList() {
|
|||||||
}
|
}
|
||||||
} else if (['aliyun', 'tcyun', 'qiniu'].includes(currentPicBedName.value)) {
|
} else if (['aliyun', 'tcyun', 'qiniu'].includes(currentPicBedName.value)) {
|
||||||
const currentConfigs = await getConfig<any>('picBed')
|
const currentConfigs = await getConfig<any>('picBed')
|
||||||
const currentConfig = currentConfigs[configMap.alias]
|
const currentConfig = currentConfigs[configMap.value.alias]
|
||||||
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
||||||
if (currentTransformedConfig[configMap.bucketName]) {
|
if (currentTransformedConfig[configMap.value.bucketName]) {
|
||||||
currentCustomDomain.value = currentTransformedConfig[configMap.bucketName].customUrl ?? ''
|
currentCustomDomain.value = currentTransformedConfig[configMap.value.bucketName].customUrl ?? ''
|
||||||
} else {
|
} else {
|
||||||
currentCustomDomain.value = ''
|
currentCustomDomain.value = ''
|
||||||
}
|
}
|
||||||
} else if (currentPicBedName.value === 's3plist') {
|
} else if (currentPicBedName.value === 's3plist') {
|
||||||
const currentConfigs = await getConfig<any>('picBed')
|
const currentConfigs = await getConfig<any>('picBed')
|
||||||
const currentConfig = currentConfigs[configMap.alias]
|
const currentConfig = currentConfigs[configMap.value.alias]
|
||||||
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
||||||
if (currentTransformedConfig[configMap.bucketName]) {
|
if (currentTransformedConfig[configMap.value.bucketName]) {
|
||||||
currentCustomDomain.value = currentTransformedConfig[configMap.bucketName].customUrl ?? ''
|
currentCustomDomain.value = currentTransformedConfig[configMap.value.bucketName].customUrl ?? ''
|
||||||
} else {
|
} else {
|
||||||
if (manageStore.config.picBed[configMap.alias].endpoint) {
|
if (manageStore.config.picBed[configMap.value.alias].endpoint) {
|
||||||
const endpoint = manageStore.config.picBed[configMap.alias].endpoint
|
const endpoint = manageStore.config.picBed[configMap.value.alias].endpoint
|
||||||
const s3ForcePathStyle = manageStore.config.picBed[configMap.alias].s3ForcePathStyle
|
const s3ForcePathStyle = manageStore.config.picBed[configMap.value.alias].s3ForcePathStyle
|
||||||
let url
|
let url
|
||||||
if (/^https?:\/\//.test(endpoint)) {
|
if (/^https?:\/\//.test(endpoint)) {
|
||||||
url = new URL(endpoint)
|
url = new URL(endpoint)
|
||||||
} else {
|
} else {
|
||||||
url = new URL(
|
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) {
|
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 {
|
} 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 {
|
} else {
|
||||||
currentCustomDomain.value = `https://${configMap.bucketName}.s3.amazonaws.com`
|
currentCustomDomain.value = `https://${configMap.value.bucketName}.s3.amazonaws.com`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await handleChangeCustomUrl()
|
await handleChangeCustomUrl()
|
||||||
} else if (currentPicBedName.value === 'webdavplist') {
|
} else if (currentPicBedName.value === 'webdavplist') {
|
||||||
const currentConfigs = await getConfig<any>('picBed')
|
const currentConfigs = await getConfig<any>('picBed')
|
||||||
const currentConfig = currentConfigs[configMap.alias]
|
const currentConfig = currentConfigs[configMap.value.alias]
|
||||||
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
||||||
if (currentTransformedConfig[configMap.bucketName] && currentTransformedConfig[configMap.bucketName]?.customUrl) {
|
if (
|
||||||
currentCustomDomain.value = currentTransformedConfig[configMap.bucketName].customUrl
|
currentTransformedConfig[configMap.value.bucketName] &&
|
||||||
|
currentTransformedConfig[configMap.value.bucketName]?.customUrl
|
||||||
|
) {
|
||||||
|
currentCustomDomain.value = currentTransformedConfig[configMap.value.bucketName].customUrl
|
||||||
} else {
|
} else {
|
||||||
let endpoint = manageStore.config.picBed[configMap.alias].endpoint
|
let endpoint = manageStore.config.picBed[configMap.value.alias].endpoint
|
||||||
if (!/^https?:\/\//.test(endpoint)) {
|
if (!/^https?:\/\//.test(endpoint)) {
|
||||||
endpoint = 'http://' + endpoint
|
endpoint = 'http://' + endpoint
|
||||||
}
|
}
|
||||||
@@ -2009,10 +2067,13 @@ async function initCustomDomainList() {
|
|||||||
await handleChangeCustomUrl()
|
await handleChangeCustomUrl()
|
||||||
} else if (currentPicBedName.value === 'local' || currentPicBedName.value === 'sftp') {
|
} else if (currentPicBedName.value === 'local' || currentPicBedName.value === 'sftp') {
|
||||||
const currentConfigs = await getConfig<any>('picBed')
|
const currentConfigs = await getConfig<any>('picBed')
|
||||||
const currentConfig = currentConfigs[configMap.alias]
|
const currentConfig = currentConfigs[configMap.value.alias]
|
||||||
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
||||||
if (currentTransformedConfig[configMap.bucketName] && currentTransformedConfig[configMap.bucketName]?.customUrl) {
|
if (
|
||||||
currentCustomDomain.value = currentTransformedConfig[configMap.bucketName].customUrl ?? ''
|
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://')) {
|
if (manageStore.config.settings.isForceCustomUrlHttps && currentCustomDomain.value.startsWith('http://')) {
|
||||||
currentCustomDomain.value = currentCustomDomain.value.replace('http://', 'https://')
|
currentCustomDomain.value = currentCustomDomain.value.replace('http://', 'https://')
|
||||||
}
|
}
|
||||||
@@ -2036,7 +2097,7 @@ async function resetParam(force: boolean = false) {
|
|||||||
}
|
}
|
||||||
cancelToken.value = ''
|
cancelToken.value = ''
|
||||||
pagingMarker.value = ''
|
pagingMarker.value = ''
|
||||||
currentPrefix.value = configMap.prefix
|
currentPrefix.value = configMap.value.prefix
|
||||||
currentPageNumber.value = 1
|
currentPageNumber.value = 1
|
||||||
currentPageFilesInfo.length = 0
|
currentPageFilesInfo.length = 0
|
||||||
currentDownloadFileList.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() {
|
async function forceRefreshFileList() {
|
||||||
if (isLoadingData.value) {
|
if (isLoadingData.value) {
|
||||||
message.error(t('pages.manage.bucket.isLoadingMsg'))
|
message.error(t('pages.manage.bucket.isLoadingMsg'))
|
||||||
@@ -2107,16 +2156,6 @@ async function forceRefreshFileList() {
|
|||||||
isShowLoadingPage.value = false
|
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) => {
|
const changePage = async (cur: number | undefined, prev: number | undefined) => {
|
||||||
if (!cur || !prev) {
|
if (!cur || !prev) {
|
||||||
currentPageNumber.value = 1
|
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 handlePageNumberInput = async (event: Event) => {
|
||||||
const target = event.target as HTMLInputElement
|
const target = event.target as HTMLInputElement
|
||||||
const value = parseInt(target.value, 10)
|
const value = parseInt(target.value, 10)
|
||||||
@@ -2294,9 +2306,9 @@ async function handleFolderBatchDownload(item: any) {
|
|||||||
cancelToken.value = uuidv4()
|
cancelToken.value = uuidv4()
|
||||||
const paramGet = {
|
const paramGet = {
|
||||||
// tcyun
|
// tcyun
|
||||||
bucketName: configMap.bucketName,
|
bucketName: configMap.value.bucketName,
|
||||||
bucketConfig: {
|
bucketConfig: {
|
||||||
Location: configMap.bucketConfig.Location,
|
Location: configMap.value.bucketConfig.Location,
|
||||||
},
|
},
|
||||||
paging: paging.value,
|
paging: paging.value,
|
||||||
prefix: `/${item.key.replace(/^\/+|\/+$/, '')}/`,
|
prefix: `/${item.key.replace(/^\/+|\/+$/, '')}/`,
|
||||||
@@ -2305,12 +2317,12 @@ async function handleFolderBatchDownload(item: any) {
|
|||||||
customUrl: currentCustomDomain.value,
|
customUrl: currentCustomDomain.value,
|
||||||
currentPage: currentPageNumber.value,
|
currentPage: currentPageNumber.value,
|
||||||
cancelToken: cancelToken.value,
|
cancelToken: cancelToken.value,
|
||||||
cdnUrl: configMap.cdnUrl,
|
cdnUrl: configMap.value.cdnUrl,
|
||||||
}
|
}
|
||||||
isLoadingDownloadData.value = true
|
isLoadingDownloadData.value = true
|
||||||
const downloadFileTransferStore = useDownloadFileTransferStore()
|
const downloadFileTransferStore = useDownloadFileTransferStore()
|
||||||
downloadFileTransferStore.resetDownloadFileTransferList()
|
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 => {
|
window.electron.ipcRendererOn(refreshDownloadFileTransferList, data => {
|
||||||
downloadFileTransferStore.refreshDownloadFileTransferList(data)
|
downloadFileTransferStore.refreshDownloadFileTransferList(data)
|
||||||
})
|
})
|
||||||
@@ -2326,9 +2338,9 @@ async function handleFolderBatchDownload(item: any) {
|
|||||||
if (currentDownloadFileList.length) {
|
if (currentDownloadFileList.length) {
|
||||||
currentDownloadFileList.forEach((item: any) => {
|
currentDownloadFileList.forEach((item: any) => {
|
||||||
param.fileArray.push({
|
param.fileArray.push({
|
||||||
alias: configMap.alias,
|
alias: configMap.value.alias,
|
||||||
bucketName: configMap.bucketName,
|
bucketName: configMap.value.bucketName,
|
||||||
region: configMap.bucketConfig.Location,
|
region: configMap.value.bucketConfig.Location,
|
||||||
key: item.key,
|
key: item.key,
|
||||||
fileName: [undefined, true].includes(manageStore.config.settings.isDownloadFolderKeepDirStructure)
|
fileName: [undefined, true].includes(manageStore.config.settings.isDownloadFolderKeepDirStructure)
|
||||||
? `/${item.key.replace(/^\/+|\/+$/, '')}`
|
? `/${item.key.replace(/^\/+|\/+$/, '')}`
|
||||||
@@ -2336,11 +2348,11 @@ async function handleFolderBatchDownload(item: any) {
|
|||||||
customUrl: currentCustomDomain.value,
|
customUrl: currentCustomDomain.value,
|
||||||
downloadUrl: item.downloadUrl,
|
downloadUrl: item.downloadUrl,
|
||||||
githubUrl: item.url,
|
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
|
isShowDownloadPanel.value = true
|
||||||
} else {
|
} else {
|
||||||
message.error(t('pages.manage.bucket.getDownloadListFailed'))
|
message.error(t('pages.manage.bucket.getDownloadListFailed'))
|
||||||
@@ -2367,9 +2379,9 @@ async function handleBatchDownload() {
|
|||||||
selectedItems.value.forEach((item: any) => {
|
selectedItems.value.forEach((item: any) => {
|
||||||
if (!item.isDir) {
|
if (!item.isDir) {
|
||||||
param.fileArray.push({
|
param.fileArray.push({
|
||||||
alias: configMap.alias,
|
alias: configMap.value.alias,
|
||||||
bucketName: configMap.bucketName,
|
bucketName: configMap.value.bucketName,
|
||||||
region: configMap.bucketConfig.Location,
|
region: configMap.value.bucketConfig.Location,
|
||||||
key: item.key,
|
key: item.key,
|
||||||
fileName: manageStore.config.settings.isDownloadFileKeepDirStructure
|
fileName: manageStore.config.settings.isDownloadFileKeepDirStructure
|
||||||
? `/${item.key.replace(/^\/+|\/+$/, '')}`
|
? `/${item.key.replace(/^\/+|\/+$/, '')}`
|
||||||
@@ -2377,11 +2389,11 @@ async function handleBatchDownload() {
|
|||||||
customUrl: currentCustomDomain.value,
|
customUrl: currentCustomDomain.value,
|
||||||
downloadUrl: item.downloadUrl,
|
downloadUrl: item.downloadUrl,
|
||||||
githubUrl: item.url,
|
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()
|
handleCancelCheck()
|
||||||
isShowDownloadPanel.value = true
|
isShowDownloadPanel.value = true
|
||||||
}
|
}
|
||||||
@@ -2415,14 +2427,14 @@ async function confirmCreateFolder() {
|
|||||||
formatedPath = trimPath(formatedPath)
|
formatedPath = trimPath(formatedPath)
|
||||||
const param = {
|
const param = {
|
||||||
// tcyun
|
// tcyun
|
||||||
bucketName: configMap.bucketName,
|
bucketName: configMap.value.bucketName,
|
||||||
region: configMap.bucketConfig.Location,
|
region: configMap.value.bucketConfig.Location,
|
||||||
key: currentPrefix.value.slice(1) + formatedPath + '/',
|
key: currentPrefix.value.slice(1) + formatedPath + '/',
|
||||||
githubBranch: currentCustomDomain.value,
|
githubBranch: currentCustomDomain.value,
|
||||||
}
|
}
|
||||||
const res = await window.electron.triggerRPC<any>(
|
const res = await window.electron.triggerRPC<any>(
|
||||||
IRPCActionType.MANAGE_CREATE_BUCKET_FOLDER,
|
IRPCActionType.MANAGE_CREATE_BUCKET_FOLDER,
|
||||||
configMap.alias,
|
configMap.value.alias,
|
||||||
param,
|
param,
|
||||||
)
|
)
|
||||||
if (res) {
|
if (res) {
|
||||||
@@ -2540,14 +2552,14 @@ async function BatchRename() {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const param = {
|
const param = {
|
||||||
// tcyun
|
// tcyun
|
||||||
bucketName: configMap.bucketName,
|
bucketName: configMap.value.bucketName,
|
||||||
region: configMap.bucketConfig.Location,
|
region: configMap.value.bucketConfig.Location,
|
||||||
oldKey: item.key,
|
oldKey: item.key,
|
||||||
newKey: (item.key.slice(0, item.key.lastIndexOf('/') + 1) + item.newName).replaceAll('//', '/'),
|
newKey: (item.key.slice(0, item.key.lastIndexOf('/') + 1) + item.newName).replaceAll('//', '/'),
|
||||||
customUrl: currentCustomDomain.value,
|
customUrl: currentCustomDomain.value,
|
||||||
}
|
}
|
||||||
window.electron
|
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) => {
|
.then((res: any) => {
|
||||||
if (res) {
|
if (res) {
|
||||||
successCount++
|
successCount++
|
||||||
@@ -2714,9 +2726,9 @@ async function getBucketFileListBackStage() {
|
|||||||
cancelToken.value = uuidv4()
|
cancelToken.value = uuidv4()
|
||||||
const param = {
|
const param = {
|
||||||
// tcyun
|
// tcyun
|
||||||
bucketName: configMap.bucketName,
|
bucketName: configMap.value.bucketName,
|
||||||
bucketConfig: {
|
bucketConfig: {
|
||||||
Location: configMap.bucketConfig.Location,
|
Location: configMap.value.bucketConfig.Location,
|
||||||
},
|
},
|
||||||
paging: paging.value,
|
paging: paging.value,
|
||||||
prefix: currentPrefix.value,
|
prefix: currentPrefix.value,
|
||||||
@@ -2725,17 +2737,17 @@ async function getBucketFileListBackStage() {
|
|||||||
customUrl: currentCustomDomain.value,
|
customUrl: currentCustomDomain.value,
|
||||||
currentPage: currentPageNumber.value,
|
currentPage: currentPageNumber.value,
|
||||||
cancelToken: cancelToken.value,
|
cancelToken: cancelToken.value,
|
||||||
cdnUrl: configMap.cdnUrl,
|
cdnUrl: configMap.value.cdnUrl,
|
||||||
} as IStringKeyMap
|
} as IStringKeyMap
|
||||||
isLoadingData.value = true
|
isLoadingData.value = true
|
||||||
const fileTransferStore = useFileTransferStore()
|
const fileTransferStore = useFileTransferStore()
|
||||||
fileTransferStore.resetFileTransferList()
|
fileTransferStore.resetFileTransferList()
|
||||||
const picBedNamesArr = ['webdavplist', 'local', 'sftp']
|
const picBedNamesArr = ['webdavplist', 'local', 'sftp']
|
||||||
if (picBedNamesArr.includes(currentPicBedName.value)) {
|
if (picBedNamesArr.includes(currentPicBedName.value)) {
|
||||||
param.baseDir = configMap.baseDir
|
param.baseDir = configMap.value.baseDir
|
||||||
param.webPath = configMap.webPath
|
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 => {
|
window.electron.ipcRendererOn('refreshFileTransferList', data => {
|
||||||
fileTransferStore.refreshFileTransferList(data)
|
fileTransferStore.refreshFileTransferList(data)
|
||||||
})
|
})
|
||||||
@@ -2769,9 +2781,9 @@ async function getBucketFileListBackStage() {
|
|||||||
async function getBucketFileList() {
|
async function getBucketFileList() {
|
||||||
const param = {
|
const param = {
|
||||||
// tcyun
|
// tcyun
|
||||||
bucketName: configMap.bucketName,
|
bucketName: configMap.value.bucketName,
|
||||||
bucketConfig: {
|
bucketConfig: {
|
||||||
Location: configMap.bucketConfig.Location,
|
Location: configMap.value.bucketConfig.Location,
|
||||||
},
|
},
|
||||||
paging: paging.value,
|
paging: paging.value,
|
||||||
prefix: currentPrefix.value,
|
prefix: currentPrefix.value,
|
||||||
@@ -2780,7 +2792,7 @@ async function getBucketFileList() {
|
|||||||
customUrl: currentCustomDomain.value,
|
customUrl: currentCustomDomain.value,
|
||||||
currentPage: currentPageNumber.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() {
|
async function handleBatchDeleteInfo() {
|
||||||
@@ -2800,15 +2812,19 @@ async function handleBatchDeleteInfo() {
|
|||||||
|
|
||||||
for (const item of copiedSelectedItems) {
|
for (const item of copiedSelectedItems) {
|
||||||
const param = {
|
const param = {
|
||||||
bucketName: configMap.bucketName,
|
bucketName: configMap.value.bucketName,
|
||||||
region: configMap.bucketConfig.Location,
|
region: configMap.value.bucketConfig.Location,
|
||||||
key: item.key,
|
key: item.key,
|
||||||
DeleteHash: item.sha,
|
DeleteHash: item.sha,
|
||||||
githubBranch: currentCustomDomain.value,
|
githubBranch: currentCustomDomain.value,
|
||||||
}
|
}
|
||||||
const result = item.isDir
|
const result = item.isDir
|
||||||
? await window.electron.triggerRPC<any>(IRPCActionType.MANAGE_DELETE_BUCKET_FOLDER, configMap.alias, param)
|
? await window.electron.triggerRPC<any>(
|
||||||
: await window.electron.triggerRPC<any>(IRPCActionType.MANAGE_DELETE_BUCKET_FILE, configMap.alias, param)
|
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) {
|
if (result) {
|
||||||
successCount++
|
successCount++
|
||||||
currentPageFilesInfo.splice(
|
currentPageFilesInfo.splice(
|
||||||
@@ -2856,17 +2872,25 @@ async function handleDeleteFile(item: any) {
|
|||||||
if (!result) return
|
if (!result) return
|
||||||
let res = false
|
let res = false
|
||||||
const param = {
|
const param = {
|
||||||
bucketName: configMap.bucketName,
|
bucketName: configMap.value.bucketName,
|
||||||
region: configMap.bucketConfig.Location,
|
region: configMap.value.bucketConfig.Location,
|
||||||
key: item.key,
|
key: item.key,
|
||||||
DeleteHash: item.sha,
|
DeleteHash: item.sha,
|
||||||
githubBranch: currentCustomDomain.value,
|
githubBranch: currentCustomDomain.value,
|
||||||
}
|
}
|
||||||
if (item.isDir) {
|
if (item.isDir) {
|
||||||
message.info(t('pages.manage.bucket.deletingMsg'))
|
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 {
|
} 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) {
|
if (res) {
|
||||||
message.success(t('pages.manage.bucket.deleteSuccess'))
|
message.success(t('pages.manage.bucket.deleteSuccess'))
|
||||||
@@ -2927,13 +2951,15 @@ function singleRename() {
|
|||||||
const item = currentPageFilesInfo[index]
|
const item = currentPageFilesInfo[index]
|
||||||
const param = {
|
const param = {
|
||||||
// tcyun
|
// tcyun
|
||||||
bucketName: configMap.bucketName,
|
bucketName: configMap.value.bucketName,
|
||||||
region: configMap.bucketConfig.Location,
|
region: configMap.value.bucketConfig.Location,
|
||||||
oldKey: item.key,
|
oldKey: item.key,
|
||||||
newKey: (item.key.slice(0, item.key.lastIndexOf('/') + 1) + itemToBeRenamed.value.newName).replaceAll('//', '/'),
|
newKey: (item.key.slice(0, item.key.lastIndexOf('/') + 1) + itemToBeRenamed.value.newName).replaceAll('//', '/'),
|
||||||
customUrl: currentCustomDomain.value,
|
customUrl: currentCustomDomain.value,
|
||||||
}
|
}
|
||||||
window.electron.triggerRPC<any>(IRPCActionType.MANAGE_RENAME_BUCKET_FILE, configMap.alias, param).then((res: any) => {
|
window.electron
|
||||||
|
.triggerRPC<any>(IRPCActionType.MANAGE_RENAME_BUCKET_FILE, configMap.value.alias, param)
|
||||||
|
.then((res: any) => {
|
||||||
if (res) {
|
if (res) {
|
||||||
const oldKey = currentPrefix.value + item.fileName
|
const oldKey = currentPrefix.value + item.fileName
|
||||||
if (pagingMarker.value === oldKey.slice(1)) {
|
if (pagingMarker.value === oldKey.slice(1)) {
|
||||||
@@ -2989,12 +3015,12 @@ function singleRename() {
|
|||||||
|
|
||||||
function handleGetS3Config(item: any) {
|
function handleGetS3Config(item: any) {
|
||||||
return {
|
return {
|
||||||
bucketName: configMap.bucketName,
|
bucketName: configMap.value.bucketName,
|
||||||
region: configMap.bucketConfig.Location,
|
region: configMap.value.bucketConfig.Location,
|
||||||
key: item.key,
|
key: item.key,
|
||||||
customUrl: currentCustomDomain.value,
|
customUrl: currentCustomDomain.value,
|
||||||
expires: manageStore.config.settings.PreSignedExpire,
|
expires: manageStore.config.settings.PreSignedExpire,
|
||||||
githubPrivate: configMap.bucketConfig.private,
|
githubPrivate: configMap.value.bucketConfig.private,
|
||||||
rawUrl: item.url,
|
rawUrl: item.url,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3002,15 +3028,15 @@ function handleGetS3Config(item: any) {
|
|||||||
async function getPreSignedUrl(item: any) {
|
async function getPreSignedUrl(item: any) {
|
||||||
const param = {
|
const param = {
|
||||||
// tcyun
|
// tcyun
|
||||||
bucketName: configMap.bucketName,
|
bucketName: configMap.value.bucketName,
|
||||||
region: configMap.bucketConfig.Location,
|
region: configMap.value.bucketConfig.Location,
|
||||||
key: item.key,
|
key: item.key,
|
||||||
customUrl: currentCustomDomain.value,
|
customUrl: currentCustomDomain.value,
|
||||||
expires: manageStore.config.settings.PreSignedExpire,
|
expires: manageStore.config.settings.PreSignedExpire,
|
||||||
githubPrivate: configMap.bucketConfig.private,
|
githubPrivate: configMap.value.bucketConfig.private,
|
||||||
rawUrl: item.url,
|
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) {
|
function copyToClipboard(text: string) {
|
||||||
@@ -3094,9 +3120,9 @@ function getTableKeyOfDb() {
|
|||||||
let tableKey
|
let tableKey
|
||||||
if (currentPicBedName.value === 'github') {
|
if (currentPicBedName.value === 'github') {
|
||||||
// customUrl is branch
|
// 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 {
|
} else {
|
||||||
tableKey = `${configMap.alias}@${configMap.bucketName}@${currentPrefix.value}`
|
tableKey = `${configMap.value.alias}@${configMap.value.bucketName}@${currentPrefix.value}`
|
||||||
}
|
}
|
||||||
return tableKey
|
return tableKey
|
||||||
}
|
}
|
||||||
@@ -3123,11 +3149,6 @@ function handleDetectShiftKey(event: KeyboardEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
onBeforeMount(async () => {
|
||||||
await manageStore.refreshConfig()
|
|
||||||
isShowLoadingPage.value = true
|
|
||||||
await initCustomDomainList()
|
|
||||||
await resetParam(true)
|
|
||||||
isShowLoadingPage.value = false
|
|
||||||
document.addEventListener('keydown', handleDetectShiftKey)
|
document.addEventListener('keydown', handleDetectShiftKey)
|
||||||
document.addEventListener('keyup', handleDetectShiftKey)
|
document.addEventListener('keyup', handleDetectShiftKey)
|
||||||
document.addEventListener('click', handleClickOutside)
|
document.addEventListener('click', handleClickOutside)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<h3 class="mb-2 text-xl font-semibold text-main">
|
<h3 class="mb-2 text-xl font-semibold text-main">
|
||||||
{{ t('pages.manage.empty.noData') }}
|
{{ t('pages.manage.empty.noData') }}
|
||||||
</h3>
|
</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') }}
|
{{ t('pages.manage.empty.noDataDesc') }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -21,4 +21,8 @@ import { FolderOpenIcon } from 'lucide-vue-next'
|
|||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
const { noDesc = false } = defineProps<{
|
||||||
|
noDesc?: boolean
|
||||||
|
}>()
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<h1 class="m-0 text-2xl font-semibold tracking-tight text-main">{{ t('pages.manage.login.title') }}</h1>
|
<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">
|
<p class="m-0 text-sm text-secondary">
|
||||||
{{ sortedAllConfigAliasMap.length }} {{ t('pages.manage.login.savedConfigs') }}
|
{{ sortedAllConfigAliasList.length }} {{ t('pages.manage.login.savedConfigs') }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
v-for="item in tabItems"
|
v-for="item in tabItems"
|
||||||
:key="item.key"
|
: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="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)"
|
@click="handleTabChange(item.key)"
|
||||||
>
|
>
|
||||||
<FolderIcon v-if="item.key === 'login'" :size="16" />
|
<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">
|
<div class="no-scrollbar h-full w-full flex-1 overflow-auto rounded-2xl border-none">
|
||||||
<!-- Main Config List Tab -->
|
<!-- 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
|
<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"
|
class="flex h-full w-full flex-col items-center justify-center p-4"
|
||||||
>
|
>
|
||||||
<div class="mb-2 text-accent/50">
|
<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"
|
class="grid w-full grid-cols-[repeat(auto-fill,minmax(300px,1fr))] gap-5 border-none p-1 max-md:gap-4"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-for="item in sortedAllConfigAliasMap"
|
v-for="item in sortedAllConfigAliasList"
|
||||||
:key="item.alias"
|
: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"
|
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" />
|
<InfoIcon :size="14" />
|
||||||
{{ t('pages.manage.login.viewDetails') }}
|
{{ 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>
|
</button>
|
||||||
<Teleport v-if="expandedConfigs.includes(item.alias)" to="body">
|
<Teleport v-if="visibleConfigItems.includes(item.alias)" to="body">
|
||||||
<div
|
<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"
|
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"
|
class="grid w-full grid-cols-[repeat(auto-fill,minmax(300px,1fr))] gap-5 border-none p-1 max-md:gap-4"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-for="(item, index) in existingConfiguration"
|
v-for="(item, index) in platformConfigList"
|
||||||
:key="item.alias + index"
|
: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"
|
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>
|
||||||
</div>
|
</div>
|
||||||
<template v-else-if="editMode">
|
<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>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -266,7 +271,7 @@ import {
|
|||||||
TrashIcon,
|
TrashIcon,
|
||||||
XIcon,
|
XIcon,
|
||||||
} from 'lucide-vue-next'
|
} from 'lucide-vue-next'
|
||||||
import { computed, onMounted, reactive, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
@@ -280,7 +285,7 @@ import { supportedPicBedList } from '@/manage/utils/constants'
|
|||||||
import { getConfig, removeConfig, saveConfig } from '@/manage/utils/dataSender'
|
import { getConfig, removeConfig, saveConfig } from '@/manage/utils/dataSender'
|
||||||
import { formatEndpoint } from '@/utils/common'
|
import { formatEndpoint } from '@/utils/common'
|
||||||
import { configPaths } from '@/utils/configPaths'
|
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'
|
import { II18nLanguage, IRPCActionType } from '@/utils/enum'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
@@ -291,101 +296,71 @@ const { confirm } = useConfirm()
|
|||||||
|
|
||||||
const editMode = ref(false)
|
const editMode = ref(false)
|
||||||
const editingAlias = ref('')
|
const editingAlias = ref('')
|
||||||
const activeName = ref('login')
|
const activePlatform = ref('login')
|
||||||
const expandedConfigs = ref<string[]>([])
|
const visibleConfigItems = ref<string[]>([])
|
||||||
const configResult: IStringKeyMap = reactive({})
|
const platformConfigList = ref<IStringKeyMap[]>([])
|
||||||
const existingConfiguration = reactive({} as IStringKeyMap)
|
const allConfigAliasList = ref<IStringKeyMap[]>([])
|
||||||
const dataForTable = reactive([] as any[])
|
const importedNewConfig: IStringKeyMap = {}
|
||||||
const allConfigAliasMap = reactive({} as IStringKeyMap)
|
|
||||||
const currentAliasList = reactive([] as string[])
|
|
||||||
const formErrors = reactive({} as IStringKeyMap)
|
|
||||||
|
|
||||||
const sortedAllConfigAliasMap = computed(() => {
|
const PB_LIST = [
|
||||||
return Object.values(allConfigAliasMap).sort((a, b) => {
|
'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)
|
return a.picBedName.localeCompare(b.picBedName)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const tabItems = computed(() => {
|
const tabItems = computed(() => {
|
||||||
const items = [
|
const staticItem = {
|
||||||
{
|
|
||||||
key: 'login',
|
key: 'login',
|
||||||
name: t('pages.manage.login.savedConfigs'),
|
name: t('pages.manage.login.savedConfigs'),
|
||||||
icon: null,
|
icon: null,
|
||||||
iconComponent: FolderIcon,
|
iconComponent: FolderIcon,
|
||||||
},
|
}
|
||||||
]
|
|
||||||
|
|
||||||
Object.values(supportedPicBedList).forEach((item: any) => {
|
const dynamicItems = Object.values(supportedPicBedList).map((item: any) => ({
|
||||||
items.push({
|
|
||||||
key: item.icon,
|
key: item.icon,
|
||||||
name: item.name,
|
name: item.name,
|
||||||
icon: item.icon,
|
icon: item.icon,
|
||||||
iconComponent: null as any,
|
iconComponent: null,
|
||||||
})
|
}))
|
||||||
})
|
|
||||||
|
|
||||||
return items
|
return [staticItem, ...dynamicItems]
|
||||||
})
|
})
|
||||||
|
|
||||||
const importedNewConfig: IStringKeyMap = {}
|
|
||||||
|
|
||||||
const notifyUser = (msg: string, type: 'success' | 'error' | 'warning' = 'success') => {
|
const notifyUser = (msg: string, type: 'success' | 'error' | 'warning' = 'success') => {
|
||||||
message[type](`${msg}`)
|
message[type](`${msg}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const initializeDefaultValues = (picBedName: string) => {
|
async function loadExistingSettings(name: 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) {
|
|
||||||
if (name === 'login') {
|
if (name === 'login') {
|
||||||
getAllConfigAliasArray()
|
getAllConfigAliasArray()
|
||||||
return
|
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
|
const result = await getConfig<any>('picBed')
|
||||||
getDataForTable()
|
const newConfig: IStringKeyMap[] = []
|
||||||
handleConfigImport(currentAliasList[0])
|
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() {
|
function openBucketPageSetting() {
|
||||||
@@ -408,7 +383,7 @@ const handleConfigRemove = async (name: string) => {
|
|||||||
removeConfig('picBed', name)
|
removeConfig('picBed', name)
|
||||||
notifyUser(t('pages.manage.login.deleteConfigSuccessMsg'), 'success')
|
notifyUser(t('pages.manage.login.deleteConfigSuccessMsg'), 'success')
|
||||||
manageStore.refreshConfig()
|
manageStore.refreshConfig()
|
||||||
getAllConfigAliasArray()
|
loadExistingSettings(activePlatform.value)
|
||||||
} catch (_error) {
|
} catch (_error) {
|
||||||
notifyUser(t('pages.manage.login.deleteConfigFailedMsg'), 'error')
|
notifyUser(t('pages.manage.login.deleteConfigFailedMsg'), 'error')
|
||||||
}
|
}
|
||||||
@@ -417,17 +392,16 @@ const handleConfigRemove = async (name: string) => {
|
|||||||
|
|
||||||
const getAllConfigAliasArray = async () => {
|
const getAllConfigAliasArray = async () => {
|
||||||
const result = await getConfig<any>('picBed')
|
const result = await getConfig<any>('picBed')
|
||||||
for (const key in allConfigAliasMap) {
|
const newConfig: IStringKeyMap[] = []
|
||||||
delete allConfigAliasMap[key]
|
|
||||||
}
|
|
||||||
if (!result) return
|
if (!result) return
|
||||||
Object.entries(result).forEach(([, value]: [string, any], index) => {
|
Object.values(result).forEach((value: any) => {
|
||||||
allConfigAliasMap[index] = {
|
newConfig.push({
|
||||||
alias: value.alias,
|
alias: value.alias,
|
||||||
config: value,
|
config: value,
|
||||||
picBedName: value.picBedName,
|
picBedName: value.picBedName,
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
allConfigAliasList.value = newConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
const copyToClipboard = (text: string) => {
|
const copyToClipboard = (text: string) => {
|
||||||
@@ -456,37 +430,18 @@ function openEditPage(alias: string) {
|
|||||||
editMode.value = true
|
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) => {
|
const handleTabChange = (tabName: string) => {
|
||||||
editMode.value = false
|
editMode.value = false
|
||||||
activeName.value = tabName
|
activePlatform.value = tabName
|
||||||
getExistingConfig(tabName)
|
loadExistingSettings(tabName)
|
||||||
|
|
||||||
for (const key in formErrors) {
|
|
||||||
delete formErrors[key]
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tabName !== 'login') {
|
|
||||||
initializeDefaultValues(tabName)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleConfigDetails = async (alias: string) => {
|
const toggleConfigDetails = async (alias: string) => {
|
||||||
const index = expandedConfigs.value.indexOf(alias)
|
const index = visibleConfigItems.value.indexOf(alias)
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
expandedConfigs.value.splice(index, 1)
|
visibleConfigItems.value.splice(index, 1)
|
||||||
} else {
|
} else {
|
||||||
expandedConfigs.value.push(alias)
|
visibleConfigItems.value.push(alias)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,37 +450,19 @@ const refreshConfigs = () => {
|
|||||||
notifyUser(t('pages.manage.login.configurationRefreshMsg'), 'success')
|
notifyUser(t('pages.manage.login.configurationRefreshMsg'), 'success')
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
getCurrentConfigList()
|
|
||||||
})
|
|
||||||
|
|
||||||
async function getCurrentConfigList() {
|
async function getCurrentConfigList() {
|
||||||
await manageStore.refreshConfig()
|
await manageStore.refreshConfig()
|
||||||
const configList = (await getPicBedsConfig<any>('uploader')) ?? {}
|
const configList = (await getPicListConfig<any>('uploader')) ?? {}
|
||||||
const pbList = [
|
|
||||||
'aliyun',
|
|
||||||
'aws-s3',
|
|
||||||
'aws-s3-plist',
|
|
||||||
'github',
|
|
||||||
'imgur',
|
|
||||||
'local',
|
|
||||||
'qiniu',
|
|
||||||
'sftpplist',
|
|
||||||
'smms',
|
|
||||||
'tcyun',
|
|
||||||
'upyun',
|
|
||||||
'webdavplist',
|
|
||||||
]
|
|
||||||
|
|
||||||
const filteredConfigList = pbList.flatMap(pb => {
|
const filteredConfigList = PB_LIST.flatMap(pb => {
|
||||||
const config = configList[pb]
|
const config = configList[pb]
|
||||||
return config?.configList?.length ? config.configList.map((item: any) => ({ ...item, type: 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) {
|
if (autoImport) {
|
||||||
const autoImportPicBed = initArray(
|
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)))
|
await Promise.all(filteredConfigList.flatMap(config => transUpToManage(config, config.type, autoImportPicBed)))
|
||||||
@@ -547,7 +484,7 @@ async function goConfigPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isImported(alias: string) {
|
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[]) {
|
function initArray(arrayT: string | string[], defaultValue: string[]) {
|
||||||
@@ -557,16 +494,18 @@ function initArray(arrayT: string | string[], defaultValue: string[]) {
|
|||||||
return arrayT
|
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[]) {
|
async function transUpToManage(config: IUploaderConfigListItem, picBedName: string, autoImportPicBed: string[]) {
|
||||||
const alias = `${
|
const alias = `${getPicBedAlias(picBedName)}-${config._configName ?? 'Default'}-imp`
|
||||||
picBedName === 'webdavplist'
|
|
||||||
? 'webdav'
|
|
||||||
: picBedName === 'sftpplist'
|
|
||||||
? 'sftp'
|
|
||||||
: picBedName === 'aws-s3' || picBedName === 'aws-s3-plist'
|
|
||||||
? 's3plist'
|
|
||||||
: picBedName
|
|
||||||
}-${config._configName ?? 'Default'}-imp`
|
|
||||||
if (!autoImportPicBed.includes(picBedName) || isImported(alias)) return
|
if (!autoImportPicBed.includes(picBedName) || isImported(alias)) return
|
||||||
const commonConfig = {
|
const commonConfig = {
|
||||||
alias,
|
alias,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
>
|
>
|
||||||
<InfoIcon :size="20" />
|
<InfoIcon :size="20" />
|
||||||
<p class="m-0 text-sm leading-[1.5] font-semibold text-secondary">
|
<p class="m-0 text-sm leading-[1.5] font-semibold text-secondary">
|
||||||
{{ supportedPicBedList[activeName].explain }}
|
{{ supportedPicBedList[platformName].explain }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -14,9 +14,9 @@
|
|||||||
>
|
>
|
||||||
<LinkIcon :size="20" />
|
<LinkIcon :size="20" />
|
||||||
<p class="m-0 text-sm leading-[1.5] font-semibold text-secondary">
|
<p class="m-0 text-sm leading-[1.5] font-semibold text-secondary">
|
||||||
{{ supportedPicBedList[activeName].referenceText }}
|
{{ supportedPicBedList[platformName].referenceText }}
|
||||||
<button class="link-button" @click="handleReferenceClick(supportedPicBedList[activeName].refLink)">
|
<button class="link-button" @click="handleReferenceClick(supportedPicBedList[platformName].refLink)">
|
||||||
{{ supportedPicBedList[activeName].refLink }}
|
{{ supportedPicBedList[platformName].refLink }}
|
||||||
</button>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -24,92 +24,94 @@
|
|||||||
<div class="grid w-full grid-cols-1 gap-3">
|
<div class="grid w-full grid-cols-1 gap-3">
|
||||||
<SettingCard>
|
<SettingCard>
|
||||||
<CustomInput
|
<CustomInput
|
||||||
v-model.trim="configResult[activeName + '.alias']"
|
v-model.trim="configResult.alias"
|
||||||
type="text"
|
type="text"
|
||||||
:placeholder="supportedPicBedList[activeName].configOptions.alias.placeholder || ''"
|
:placeholder="supportedPicBedList[platformName].configOptions.alias.placeholder || ''"
|
||||||
:title="supportedPicBedList[activeName].configOptions.alias.description"
|
:title="supportedPicBedList[platformName].configOptions.alias.description"
|
||||||
:required="supportedPicBedList[activeName].configOptions.alias.required"
|
:required="supportedPicBedList[platformName].configOptions.alias.required"
|
||||||
:class="{ 'border-danger': formErrors[activeName + '.' + 'alias'] }"
|
:class="{ 'border-danger': formErrors.alias }"
|
||||||
@blur="validateField(activeName, 'alias')"
|
@blur="validateField(platformName, 'alias')"
|
||||||
@input="clearFieldError(activeName + '.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">
|
<div class="mt-1 text-xs text-danger">
|
||||||
{{ formErrors[activeName + '.' + 'alias'] }}
|
{{ formErrors.alias }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</SettingCard>
|
</SettingCard>
|
||||||
<template v-for="option in supportedPicBedList[activeName].options" :key="option">
|
<template v-for="option in supportedPicBedList[platformName].options" :key="option">
|
||||||
<SettingCard
|
<SettingCard
|
||||||
v-if="supportedPicBedList[activeName].configOptions[option].type === 'string' && option !== 'alias'"
|
v-if="supportedPicBedList[platformName].configOptions[option].type === 'string' && option !== 'alias'"
|
||||||
>
|
>
|
||||||
<CustomInput
|
<CustomInput
|
||||||
v-model.trim="configResult[activeName + '.' + option]"
|
v-model.trim="configResult[option]"
|
||||||
type="text"
|
type="text"
|
||||||
:placeholder="supportedPicBedList[activeName].configOptions[option].placeholder || ''"
|
:placeholder="supportedPicBedList[platformName].configOptions[option].placeholder || ''"
|
||||||
:class="{ 'border-danger': formErrors[activeName + '.' + option] }"
|
:class="{ 'border-danger': formErrors[option] }"
|
||||||
:title="supportedPicBedList[activeName].configOptions[option].description"
|
:title="supportedPicBedList[platformName].configOptions[option].description"
|
||||||
:required="supportedPicBedList[activeName].configOptions[option].required"
|
:required="supportedPicBedList[platformName].configOptions[option].required"
|
||||||
:disabled="!!supportedPicBedList[activeName].configOptions[option].disabled"
|
:disabled="!!supportedPicBedList[platformName].configOptions[option].disabled"
|
||||||
@blur="validateField(activeName, option)"
|
:tips="supportedPicBedList[platformName].configOptions[option].tooltip || ''"
|
||||||
@input="clearFieldError(activeName + '.' + option)"
|
@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">
|
<div class="mt-1 text-xs text-danger">
|
||||||
{{ formErrors[activeName + '.' + option] }}
|
{{ formErrors[option] }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</SettingCard>
|
</SettingCard>
|
||||||
</template>
|
</template>
|
||||||
<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 === 'number'">
|
<SettingCard v-if="supportedPicBedList[platformName].configOptions[option].type === 'number'">
|
||||||
<CustomInput
|
<CustomInput
|
||||||
v-model.number="configResult[activeName + '.' + option]"
|
v-model.number="configResult[option]"
|
||||||
type="number"
|
type="number"
|
||||||
:placeholder="supportedPicBedList[activeName].configOptions[option].placeholder || ''"
|
:placeholder="supportedPicBedList[platformName].configOptions[option].placeholder || ''"
|
||||||
:class="{ 'border-danger': formErrors[activeName + '.' + option] }"
|
:class="{ 'border-danger': formErrors[option] }"
|
||||||
:title="supportedPicBedList[activeName].configOptions[option].description"
|
:title="supportedPicBedList[platformName].configOptions[option].description"
|
||||||
:required="supportedPicBedList[activeName].configOptions[option].required"
|
:required="supportedPicBedList[platformName].configOptions[option].required"
|
||||||
@blur="validateField(activeName, option)"
|
:tips="supportedPicBedList[platformName].configOptions[option].tooltip || ''"
|
||||||
@input="clearFieldError(activeName + '.' + option)"
|
@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">
|
<div class="mt-1 text-xs text-danger">
|
||||||
{{ formErrors[activeName + '.' + option] }}
|
{{ formErrors[option] }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</SettingCard>
|
</SettingCard>
|
||||||
</template>
|
</template>
|
||||||
<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 === 'boolean'" p1>
|
<SettingCard v-if="supportedPicBedList[platformName].configOptions[option].type === 'boolean'" p1>
|
||||||
<CustomSwitch
|
<CustomSwitch
|
||||||
v-model="configResult[activeName + '.' + option]"
|
v-model="configResult[option]"
|
||||||
no-border
|
no-border
|
||||||
small
|
small
|
||||||
:required="supportedPicBedList[activeName].configOptions[option].required"
|
:required="supportedPicBedList[platformName].configOptions[option].required"
|
||||||
:title="supportedPicBedList[activeName].configOptions[option].description"
|
:title="supportedPicBedList[platformName].configOptions[option].description"
|
||||||
:tips="supportedPicBedList[activeName].configOptions[option].tooltip || ''"
|
:tips="supportedPicBedList[platformName].configOptions[option].tooltip || ''"
|
||||||
@update:model-value="validateField(activeName, option)"
|
@update:model-value="validateField(platformName, option)"
|
||||||
>
|
>
|
||||||
</CustomSwitch>
|
</CustomSwitch>
|
||||||
</SettingCard>
|
</SettingCard>
|
||||||
</template>
|
</template>
|
||||||
<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 === 'select'">
|
<SettingCard v-if="supportedPicBedList[platformName].configOptions[option].type === 'select'">
|
||||||
<CustomSelect
|
<CustomSelect
|
||||||
v-model="configResult[activeName + '.' + option]"
|
v-model="configResult[option]"
|
||||||
:title="supportedPicBedList[activeName].configOptions[option].description"
|
:title="supportedPicBedList[platformName].configOptions[option].description"
|
||||||
:required="supportedPicBedList[activeName].configOptions[option].required"
|
:required="supportedPicBedList[platformName].configOptions[option].required"
|
||||||
:select-list="
|
:select-list="
|
||||||
Object.entries(supportedPicBedList[activeName].configOptions[option].selectOptions || {}).map(
|
Object.entries(supportedPicBedList[platformName].configOptions[option].selectOptions || {}).map(
|
||||||
([key, value]) => ({
|
([key, value]) => ({
|
||||||
value: key,
|
value: key,
|
||||||
label: value as string,
|
label: value as string,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
:class="{ 'border-danger': formErrors[activeName + '.' + option] }"
|
:class="{ 'border-danger': formErrors[option] }"
|
||||||
@change="validateField(activeName, option)"
|
@change="validateField(platformName, option)"
|
||||||
>
|
>
|
||||||
<template #pre-info>
|
<template #pre-info>
|
||||||
<option value="" disabled>
|
<option value="" disabled>
|
||||||
@@ -117,9 +119,9 @@
|
|||||||
</option>
|
</option>
|
||||||
</template>
|
</template>
|
||||||
</CustomSelect>
|
</CustomSelect>
|
||||||
<template v-if="formErrors[activeName + '.' + option]" #extra>
|
<template v-if="formErrors[option]" #extra>
|
||||||
<div class="mt-1 text-xs text-danger">
|
<div class="mt-1 text-xs text-danger">
|
||||||
{{ formErrors[activeName + '.' + option] }}
|
{{ formErrors[option] }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</SettingCard>
|
</SettingCard>
|
||||||
@@ -141,13 +143,13 @@
|
|||||||
type="primary"
|
type="primary"
|
||||||
:text="t('pages.manage.login.save')"
|
:text="t('pages.manage.login.save')"
|
||||||
:icon="SaveIcon"
|
:icon="SaveIcon"
|
||||||
@click="handleConfigChange(activeName)"
|
@click="handleConfigChange()"
|
||||||
/>
|
/>
|
||||||
<CustomButton
|
<CustomButton
|
||||||
class="bg-danger/70"
|
class="bg-danger/70"
|
||||||
:text="t('pages.manage.login.reset')"
|
:text="t('pages.manage.login.reset')"
|
||||||
:icon="RotateCcwIcon"
|
:icon="RotateCcwIcon"
|
||||||
@click="handleConfigReset(activeName)"
|
@click="handleConfigReset()"
|
||||||
/>
|
/>
|
||||||
<CustomButton class="bg-warning/70" :text="t('common.cancel')" :icon="XIcon" @click="cancelEditMode" />
|
<CustomButton class="bg-warning/70" :text="t('common.cancel')" :icon="XIcon" @click="cancelEditMode" />
|
||||||
</div>
|
</div>
|
||||||
@@ -157,7 +159,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { DownloadIcon, InfoIcon, LinkIcon, RotateCcwIcon, SaveIcon, XIcon } from 'lucide-vue-next'
|
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 { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
import CustomButton from '@/components/common/CustomButton.vue'
|
import CustomButton from '@/components/common/CustomButton.vue'
|
||||||
@@ -173,22 +175,23 @@ import { getConfig, saveConfig } from '@/manage/utils/dataSender'
|
|||||||
import { formatEndpoint } from '@/utils/common'
|
import { formatEndpoint } from '@/utils/common'
|
||||||
import { IRPCActionType } from '@/utils/enum'
|
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 { t } = useI18n()
|
||||||
const manageStore = useManageStore()
|
const manageStore = useManageStore()
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
const formErrors = reactive({} as IStringKeyMap)
|
const formErrors = ref<IStringKeyMap>({})
|
||||||
const configResult: IStringKeyMap = reactive({})
|
const configResult = ref<IStringKeyMap>({})
|
||||||
const existingConfiguration = reactive({} as IStringKeyMap)
|
const existingConfiguration = ref<IStringKeyMap>({})
|
||||||
const currentAliasList = reactive([] as string[])
|
const currentAliasList = ref<string[]>([])
|
||||||
const dataForTable = reactive([] as any[])
|
|
||||||
const editMode = defineModel<boolean>('editMode')
|
|
||||||
const selectedAlias = ref('')
|
const selectedAlias = ref('')
|
||||||
|
|
||||||
const { aliasName, activeName } = defineProps<{
|
|
||||||
aliasName: string
|
|
||||||
activeName: string
|
|
||||||
}>()
|
|
||||||
|
|
||||||
watch(selectedAlias, newAlias => {
|
watch(selectedAlias, newAlias => {
|
||||||
if (newAlias) {
|
if (newAlias) {
|
||||||
handleConfigImport(newAlias)
|
handleConfigImport(newAlias)
|
||||||
@@ -198,18 +201,17 @@ watch(selectedAlias, newAlias => {
|
|||||||
const handleReferenceClick = (url: string) => window.electron.sendRPC(IRPCActionType.OPEN_URL, url)
|
const handleReferenceClick = (url: string) => window.electron.sendRPC(IRPCActionType.OPEN_URL, url)
|
||||||
|
|
||||||
const validateField = (picBedName: string, optionKey: string) => {
|
const validateField = (picBedName: string, optionKey: string) => {
|
||||||
const fieldKey = `${picBedName}.${optionKey}`
|
|
||||||
const configOption = supportedPicBedList[picBedName]?.configOptions?.[optionKey]
|
const configOption = supportedPicBedList[picBedName]?.configOptions?.[optionKey]
|
||||||
const value = configResult[fieldKey]
|
const value = configResult.value[optionKey]
|
||||||
|
|
||||||
if (!configOption) return
|
if (!configOption) return
|
||||||
|
|
||||||
delete formErrors[fieldKey]
|
delete formErrors.value[optionKey]
|
||||||
|
|
||||||
if (configOption.required) {
|
if (configOption.required) {
|
||||||
if (configOption.type === 'boolean') {
|
if (configOption.type === 'boolean') {
|
||||||
} else if (!value || value === '') {
|
} 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
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,7 +222,7 @@ const validateField = (picBedName: string, optionKey: string) => {
|
|||||||
try {
|
try {
|
||||||
rule.validator(rule, value, (error: Error | null) => {
|
rule.validator(rule, value, (error: Error | null) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
formErrors[fieldKey] = error.message
|
formErrors.value[optionKey] = error.message
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -228,7 +230,7 @@ const validateField = (picBedName: string, optionKey: string) => {
|
|||||||
}
|
}
|
||||||
} else if (rule.type === 'number' && value !== undefined && value !== '') {
|
} else if (rule.type === 'number' && value !== undefined && value !== '') {
|
||||||
if (isNaN(Number(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
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,53 +240,56 @@ const validateField = (picBedName: string, optionKey: string) => {
|
|||||||
if (optionKey === 'alias' && value) {
|
if (optionKey === 'alias' && value) {
|
||||||
const reg = /^[\p{Unified_Ideograph}_a-zA-Z0-9-]+$/u
|
const reg = /^[\p{Unified_Ideograph}_a-zA-Z0-9-]+$/u
|
||||||
if (!reg.test(value)) {
|
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 !== '') {
|
if (optionKey === 'itemsPerPage' && value !== undefined && value !== '') {
|
||||||
const numValue = Number(value)
|
const numValue = Number(value)
|
||||||
if (numValue < 20 || numValue > 1000) {
|
if (numValue < 20 || numValue > 1000) {
|
||||||
formErrors[fieldKey] = t('pages.manage.login.itemsPerPageMsg')
|
formErrors.value[optionKey] = t('pages.manage.login.itemsPerPageMsg')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const clearFieldError = (fieldKey: string) => {
|
const clearFieldError = (fieldKey: string) => {
|
||||||
delete formErrors[fieldKey]
|
delete formErrors.value[fieldKey]
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleConfigChange(name: string) {
|
async function handleConfigChange() {
|
||||||
if (!validateAllFields(name)) {
|
if (!validateAllFields(platformName)) {
|
||||||
notifyUser(t('pages.manage.login.noRequiredMsg'), 'error')
|
notifyUser(t('pages.manage.login.noRequiredMsg'), 'error')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const aliasList = getAliasList()
|
const aliasList = Object.values(existingConfiguration.value).map(item => item.alias)
|
||||||
const allKeys = Object.keys(supportedPicBedList[name].configOptions)
|
const allKeys = Object.keys(supportedPicBedList[platformName].configOptions)
|
||||||
const resultMap: IStringKeyMap = {}
|
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) {
|
for (const key of allKeys) {
|
||||||
const resultKey = name + '.' + key
|
if (key === 'customUrl' && configResult.value[key] !== undefined && configResult.value[key] !== '') {
|
||||||
if (key === 'customUrl' && configResult[resultKey] !== undefined && configResult[resultKey] !== '') {
|
if (platformName !== 'upyun') {
|
||||||
if (name !== 'upyun') {
|
configResult.value[key] = formatEndpoint(configResult.value[key], false)
|
||||||
configResult[resultKey] = formatEndpoint(configResult[resultKey], false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (supportedPicBedList[name].configOptions[key].default !== undefined && configResult[resultKey] === '') {
|
if (supportedPicBedList[platformName].configOptions[key].default !== undefined && configResult.value[key] === '') {
|
||||||
resultMap[key] = supportedPicBedList[name].configOptions[key].default
|
resultMap[key] = supportedPicBedList[platformName].configOptions[key].default
|
||||||
} else if (configResult[resultKey] === undefined) {
|
} else if (configResult.value[key] === undefined) {
|
||||||
if (supportedPicBedList[name].configOptions[key].default !== undefined) {
|
if (supportedPicBedList[platformName].configOptions[key].default !== undefined) {
|
||||||
resultMap[key] = supportedPicBedList[name].configOptions[key].default
|
resultMap[key] = supportedPicBedList[platformName].configOptions[key].default
|
||||||
} else {
|
} else {
|
||||||
resultMap[key] = ''
|
resultMap[key] = ''
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resultMap[key] = configResult[resultKey]
|
resultMap[key] = configResult.value[key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resultMap.picBedName = name
|
resultMap.picBedName = platformName
|
||||||
if (resultMap.bucketName !== undefined) {
|
if (resultMap.bucketName !== undefined) {
|
||||||
resultMap.transformedConfig = {}
|
resultMap.transformedConfig = {}
|
||||||
const bucketName = resultMap.bucketName.split(',')
|
const bucketName = resultMap.bucketName.split(',')
|
||||||
@@ -310,56 +315,51 @@ async function handleConfigChange(name: string) {
|
|||||||
}
|
}
|
||||||
saveConfig(`picBed.${resultMap.alias}`, resultMap)
|
saveConfig(`picBed.${resultMap.alias}`, resultMap)
|
||||||
await manageStore.refreshConfig()
|
await manageStore.refreshConfig()
|
||||||
await getExistingConfig(activeName)
|
await getExistingConfig(platformName)
|
||||||
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')
|
notifyUser(`${t('pages.manage.login.configSaveMsg')}${resultMap.alias}`, 'success')
|
||||||
}
|
|
||||||
editMode.value = false
|
editMode.value = false
|
||||||
|
emit('update:editMode', false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const notifyUser = (msg: string, type: 'success' | 'error' | 'warning' = 'success') => {
|
const notifyUser = (msg: string, type: 'success' | 'error' | 'warning' = 'success') => {
|
||||||
message[type](`${msg}`)
|
message[type](`${msg}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDataForTable() {
|
|
||||||
for (const key in existingConfiguration) {
|
|
||||||
dataForTable.push({ ...(existingConfiguration[key] as IStringKeyMap) })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getExistingConfig(name: string) {
|
async function getExistingConfig(name: string) {
|
||||||
currentAliasList.length = 0
|
const newList: string[] = []
|
||||||
const result = await getConfig<any>('picBed')
|
const result = await getConfig<any>('picBed')
|
||||||
for (const key in existingConfiguration) {
|
const newConfiguration: IStringKeyMap = {}
|
||||||
delete existingConfiguration[key]
|
|
||||||
}
|
|
||||||
if (!result || typeof result !== 'object' || Object.keys(result).length === 0) {
|
if (!result || typeof result !== 'object' || Object.keys(result).length === 0) {
|
||||||
existingConfiguration[name] = { fail: '暂无配置' }
|
newConfiguration[name] = { fail: '暂无配置' }
|
||||||
} else {
|
} else {
|
||||||
for (const key in result) {
|
for (const key in result) {
|
||||||
if (result[key].picBedName === name) {
|
if (result[key].picBedName === name) {
|
||||||
existingConfiguration[key] = result[key]
|
newConfiguration[key] = result[key]
|
||||||
currentAliasList.push(result[key].alias)
|
newList.push(result[key].alias)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
existingConfiguration.value = newConfiguration
|
||||||
dataForTable.length = 0
|
currentAliasList.value = newList
|
||||||
getDataForTable()
|
|
||||||
handleConfigImport(aliasName)
|
handleConfigImport(aliasName)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleConfigImport(alias: string) {
|
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
|
if (!selectedConfig) return
|
||||||
|
|
||||||
supportedPicBedList[selectedConfig.picBedName].options.forEach((option: any) => {
|
supportedPicBedList[selectedConfig.picBedName].options.forEach((option: any) => {
|
||||||
if (selectedConfig[option] !== undefined) {
|
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) {
|
for (const option of options) {
|
||||||
validateField(picBedName, option)
|
validateField(picBedName, option)
|
||||||
if (formErrors[`${picBedName}.${option}`]) {
|
if (formErrors.value[`${picBedName}.${option}`]) {
|
||||||
isValid = false
|
isValid = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -378,41 +378,36 @@ const validateAllFields = (picBedName: string): boolean => {
|
|||||||
return isValid
|
return isValid
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAliasList() {
|
const handleConfigReset = () => {
|
||||||
return Object.values(existingConfiguration).map(item => item.alias)
|
const keys = Object.keys(formErrors.value).filter(key => key.startsWith(platformName))
|
||||||
}
|
|
||||||
|
|
||||||
const handleConfigReset = (name: string) => {
|
|
||||||
const keys = Object.keys(formErrors).filter(key => key.startsWith(name))
|
|
||||||
keys.forEach(key => {
|
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 => {
|
configKeys.forEach(key => {
|
||||||
delete configResult[key]
|
delete configResult.value[key]
|
||||||
})
|
})
|
||||||
|
|
||||||
initializeDefaultValues(name)
|
initializeDefaultValues()
|
||||||
}
|
}
|
||||||
|
|
||||||
const initializeDefaultValues = (picBedName: string) => {
|
const initializeDefaultValues = () => {
|
||||||
if (!supportedPicBedList[picBedName]) return
|
if (!supportedPicBedList[platformName]) return
|
||||||
|
|
||||||
const options = supportedPicBedList[picBedName].options || []
|
const options = supportedPicBedList[platformName].options || []
|
||||||
for (const option of options) {
|
for (const option of options) {
|
||||||
const fieldKey = `${picBedName}.${option}`
|
const configOption = supportedPicBedList[platformName].configOptions[option]
|
||||||
const configOption = supportedPicBedList[picBedName].configOptions[option]
|
|
||||||
|
|
||||||
if (configResult[fieldKey] === undefined || configResult[fieldKey] === '') {
|
if (configResult.value[option] === undefined || configResult.value[option] === '') {
|
||||||
if (configOption.default !== undefined) {
|
if (configOption.default !== undefined) {
|
||||||
configResult[fieldKey] = configOption.default
|
configResult.value[option] = configOption.default
|
||||||
} else if (configOption.type === 'boolean') {
|
} else if (configOption.type === 'boolean') {
|
||||||
configResult[fieldKey] = false
|
configResult.value[option] = false
|
||||||
} else if (configOption.type === 'number') {
|
} else if (configOption.type === 'number') {
|
||||||
configResult[fieldKey] = 0
|
configResult.value[option] = 0
|
||||||
} else {
|
} else {
|
||||||
configResult[fieldKey] = ''
|
configResult.value[option] = ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -423,7 +418,7 @@ const cancelEditMode = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
getExistingConfig(activeName)
|
getExistingConfig(platformName)
|
||||||
await manageStore.refreshConfig()
|
await manageStore.refreshConfig()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -56,11 +56,10 @@
|
|||||||
/>
|
/>
|
||||||
<span class="text-sm font-semibold text-secondary">{{ t('pages.manage.main.loading') }}</span>
|
<span class="text-sm font-semibold text-secondary">{{ t('pages.manage.main.loading') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="menu-list">
|
<div v-else class="flex flex-col gap-1">
|
||||||
|
<template v-for="item in bucketNameList" :key="item">
|
||||||
<div
|
<div
|
||||||
v-for="item in bucketNameList"
|
class="flex cursor-pointer items-center gap-3 rounded-sm p-3 text-sm shadow-xs hover:bg-surface [.active]:bg-accent/20"
|
||||||
:key="item"
|
|
||||||
class="menu-item"
|
|
||||||
:class="{ active: item === currentSelectedBucket }"
|
:class="{ active: item === currentSelectedBucket }"
|
||||||
@click="handleSelectMenu(item)"
|
@click="handleSelectMenu(item)"
|
||||||
>
|
>
|
||||||
@@ -76,7 +75,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div></template
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@
|
|||||||
:text="t('pages.manage.main.settings')"
|
:text="t('pages.manage.main.settings')"
|
||||||
:icon="SettingsIcon"
|
:icon="SettingsIcon"
|
||||||
class="border-none"
|
class="border-none"
|
||||||
@click="openBucketPageSetting"
|
@click="openSettingPage"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -113,8 +113,16 @@
|
|||||||
@mousedown="startResize"
|
@mousedown="startResize"
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
<div class="content-area">
|
<div class="m-0 box-border flex h-full w-full flex-1 flex-col overflow-hidden border-none">
|
||||||
<router-view />
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -173,110 +181,68 @@
|
|||||||
</div>
|
</div>
|
||||||
</CustomModal>
|
</CustomModal>
|
||||||
</transition>
|
</transition>
|
||||||
|
<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 -->
|
<!-- New Bucket Drawer -->
|
||||||
<div v-if="nweBucketDrawerVisible" class="drawer-overlay" @click="nweBucketDrawerVisible = false">
|
<CustomModal
|
||||||
<div class="drawer-container" @click.stop>
|
v-if="bucketDrawerVisible"
|
||||||
<div class="drawer-header">
|
v-model:visible="bucketDrawerVisible"
|
||||||
<h3 class="drawer-title">
|
:title="t('pages.manage.main.newBucket')"
|
||||||
{{ t('pages.manage.main.newBucket') }}
|
width="600px"
|
||||||
</h3>
|
height="auto"
|
||||||
<button class="drawer-close" @click="nweBucketDrawerVisible = false">
|
>
|
||||||
<XIcon class="close-icon" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="drawer-content">
|
<div class="drawer-content">
|
||||||
<form @submit.prevent="createNewBucket(currentPicBedName)">
|
<SettingSection :title="supportedPicBedList[currentPicBedName].name" :icon="Database" only-one-row>
|
||||||
<div class="form-header">
|
<template v-for="option in newBucketConfig[currentPicBedName].options" :key="option">
|
||||||
<div class="form-icon">
|
<SettingCard :p1="newBucketConfig[currentPicBedName].configOptions[option].component === 'switch'">
|
||||||
<img :src="`./assets/${currentPicBedName}.webp`" class="picbed-form-icon" />
|
<CustomInput
|
||||||
</div>
|
v-if="newBucketConfig[currentPicBedName].configOptions[option].component === 'input'"
|
||||||
</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]"
|
v-model.trim="newBucketConfigResult[currentPicBedName + '.' + option]"
|
||||||
type="text"
|
type="text"
|
||||||
class="form-input"
|
:title="newBucketConfig[currentPicBedName].configOptions[option].description"
|
||||||
:placeholder="newBucketConfig[currentPicBedName].configOptions[option].placeholder"
|
: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
|
<template v-if="currentPicBedName === 'tcyun'" #input-extra>
|
||||||
v-model.trim="newBucketConfigResult[currentPicBedName + '.' + option]"
|
<span
|
||||||
type="text"
|
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"
|
||||||
class="form-input group-input"
|
>{{ '-' + currentPagePicBedConfig.appId }}</span
|
||||||
: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">
|
</template>
|
||||||
<option
|
</CustomInput>
|
||||||
v-for="(label, value) in newBucketConfig[currentPicBedName].configOptions[option].options"
|
<CustomSwitch
|
||||||
:key="value"
|
|
||||||
:value="value"
|
|
||||||
>
|
|
||||||
{{ label }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
<ChevronDownIcon class="select-arrow" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Switch field -->
|
|
||||||
<label
|
|
||||||
v-if="newBucketConfig[currentPicBedName].configOptions[option].component === 'switch'"
|
v-if="newBucketConfig[currentPicBedName].configOptions[option].component === 'switch'"
|
||||||
class="switch-label"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
v-model="newBucketConfigResult[currentPicBedName + '.' + option]"
|
v-model="newBucketConfigResult[currentPicBedName + '.' + option]"
|
||||||
type="checkbox"
|
:title="newBucketConfig[currentPicBedName].configOptions[option].description"
|
||||||
class="switch-input"
|
small
|
||||||
:true-value="true"
|
no-border
|
||||||
:false-value="false"
|
|
||||||
/>
|
/>
|
||||||
<span class="switch-slider">
|
<SingleSelect
|
||||||
<span class="switch-button" />
|
v-if="newBucketConfig[currentPicBedName].configOptions[option].component === 'select'"
|
||||||
</span>
|
v-model="newBucketConfigResult[currentPicBedName + '.' + option]"
|
||||||
</label>
|
:title="newBucketConfig[currentPicBedName].configOptions[option].description"
|
||||||
</div>
|
:key-list="Object.keys(newBucketConfig[currentPicBedName].configOptions[option].options)"
|
||||||
|
:fronticon="false"
|
||||||
<div class="form-actions">
|
>
|
||||||
<button type="button" class="action-button secondary" @click="nweBucketDrawerVisible = false">
|
<template #item="{ item }">
|
||||||
{{ $t('common.cancel') }}
|
{{ newBucketConfig[currentPicBedName].configOptions[option].options[item] }}
|
||||||
</button>
|
</template>
|
||||||
<button type="submit" class="action-button primary">
|
</SingleSelect>
|
||||||
<CheckIcon class="button-icon" />
|
</SettingCard>
|
||||||
{{ t('common.submit') }}
|
</template>
|
||||||
</button>
|
</SettingSection>
|
||||||
</div>
|
<div></div>
|
||||||
</form>
|
|
||||||
</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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -284,20 +250,27 @@
|
|||||||
import {
|
import {
|
||||||
ArrowLeftRightIcon,
|
ArrowLeftRightIcon,
|
||||||
CheckIcon,
|
CheckIcon,
|
||||||
ChevronDownIcon,
|
Database,
|
||||||
ExternalLinkIcon,
|
ExternalLinkIcon,
|
||||||
HomeIcon,
|
HomeIcon,
|
||||||
PlusIcon,
|
PlusIcon,
|
||||||
SettingsIcon,
|
SettingsIcon,
|
||||||
XIcon,
|
|
||||||
} from 'lucide-vue-next'
|
} from 'lucide-vue-next'
|
||||||
import { onBeforeMount, reactive, ref, watch } from 'vue'
|
import { onBeforeMount, reactive, ref, watch } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
|
||||||
import CustomButton from '@/components/common/CustomButton.vue'
|
import CustomButton from '@/components/common/CustomButton.vue'
|
||||||
|
import CustomInput from '@/components/common/CustomInput.vue'
|
||||||
import CustomModal from '@/components/common/CustomModal.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 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 { useManageStore } from '@/manage/store/manageStore'
|
||||||
import { supportedPicBedList } from '@/manage/utils/constants'
|
import { supportedPicBedList } from '@/manage/utils/constants'
|
||||||
import { newBucketConfig } from '@/manage/utils/newBucketConfig'
|
import { newBucketConfig } from '@/manage/utils/newBucketConfig'
|
||||||
@@ -308,6 +281,8 @@ const manageStore = useManageStore() as any
|
|||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
|
const currentPageInMain = ref<'bucket' | 'setting' | 'empty'>('empty')
|
||||||
|
const configMap = ref<any>(null)
|
||||||
|
|
||||||
const currentAlias = ref(route.query.alias as string)
|
const currentAlias = ref(route.query.alias as string)
|
||||||
const currentPicBedName = ref(route.query.picBedName as string)
|
const currentPicBedName = ref(route.query.picBedName as string)
|
||||||
@@ -324,7 +299,7 @@ const currentSelectedBucket = ref('')
|
|||||||
const bucketNameList = ref([] as string[])
|
const bucketNameList = ref([] as string[])
|
||||||
|
|
||||||
const isLoadingBucketList = ref(false)
|
const isLoadingBucketList = ref(false)
|
||||||
const nweBucketDrawerVisible = ref(false)
|
const bucketDrawerVisible = ref(false)
|
||||||
const picBedSwitchDialogVisible = ref(false)
|
const picBedSwitchDialogVisible = ref(false)
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
@@ -380,7 +355,7 @@ const menuTitleMap: IStringKeyMap = {
|
|||||||
const openPicBedUrl = () => window.electron.sendRPC(IRPCActionType.OPEN_URL, urlMap[currentPagePicBedConfig.picBedName])
|
const openPicBedUrl = () => window.electron.sendRPC(IRPCActionType.OPEN_URL, urlMap[currentPagePicBedConfig.picBedName])
|
||||||
|
|
||||||
function openNewBucketDrawer() {
|
function openNewBucketDrawer() {
|
||||||
nweBucketDrawerVisible.value = true
|
bucketDrawerVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function createNewBucket(picBedName: string) {
|
function createNewBucket(picBedName: string) {
|
||||||
@@ -403,7 +378,7 @@ function createNewBucket(picBedName: string) {
|
|||||||
if (result) {
|
if (result) {
|
||||||
// Show success notification
|
// Show success notification
|
||||||
message.success(t('pages.manage.main.createSuccess'))
|
message.success(t('pages.manage.main.createSuccess'))
|
||||||
nweBucketDrawerVisible.value = false
|
bucketDrawerVisible.value = false
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
getBucketList()
|
getBucketList()
|
||||||
}, 2000)
|
}, 2000)
|
||||||
@@ -452,7 +427,7 @@ function handleSelectMenu(bucketName: string) {
|
|||||||
prefix = prefix.endsWith('/') ? prefix : `${prefix}/`
|
prefix = prefix.endsWith('/') ? prefix : `${prefix}/`
|
||||||
}
|
}
|
||||||
|
|
||||||
const configMap = {
|
const configMapT = {
|
||||||
prefix,
|
prefix,
|
||||||
bucketName,
|
bucketName,
|
||||||
customUrl: transformedConfig[bucketName]?.customUrl ?? '',
|
customUrl: transformedConfig[bucketName]?.customUrl ?? '',
|
||||||
@@ -464,16 +439,8 @@ function handleSelectMenu(bucketName: string) {
|
|||||||
webPath: currentPicBedConfig.webPath || '',
|
webPath: currentPicBedConfig.webPath || '',
|
||||||
}
|
}
|
||||||
currentSelectedBucket.value = bucketName
|
currentSelectedBucket.value = bucketName
|
||||||
router.push({
|
configMap.value = configMapT
|
||||||
path: '/main-page/manage-main-page/manage-bucket-page',
|
currentPageInMain.value = 'bucket'
|
||||||
query: {
|
|
||||||
configMap: JSON.stringify(configMap),
|
|
||||||
alias: currentAlias.value,
|
|
||||||
picBedName: currentPicBedName.value,
|
|
||||||
config: JSON.stringify(currentPagePicBedConfig),
|
|
||||||
allPicBedConfigure: JSON.stringify(allPicBedConfigure),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchPicBed(picBedAlias: string) {
|
function switchPicBed(picBedAlias: string) {
|
||||||
@@ -511,16 +478,8 @@ function changePicBed() {
|
|||||||
picBedSwitchDialogVisible.value = true
|
picBedSwitchDialogVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function openBucketPageSetting() {
|
function openSettingPage() {
|
||||||
router.push({
|
currentPageInMain.value = 'setting'
|
||||||
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 startResize(event: MouseEvent) {
|
function startResize(event: MouseEvent) {
|
||||||
@@ -554,5 +513,3 @@ onBeforeMount(() => {
|
|||||||
getBucketList()
|
getBucketList()
|
||||||
})
|
})
|
||||||
</script>
|
</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
|
small
|
||||||
:title="t('pages.settings.system.isDisableGPU')"
|
:title="t('pages.settings.system.isDisableGPU')"
|
||||||
:description="t('pages.settings.system.isDisableGPUDesc')"
|
:description="t('pages.settings.system.isDisableGPUDesc')"
|
||||||
|
@update:model-value="handleIsDisableGPUChange"
|
||||||
/>
|
/>
|
||||||
</SettingCard>
|
</SettingCard>
|
||||||
|
|
||||||
@@ -189,13 +190,16 @@
|
|||||||
<!-- Startup & Shortcuts Section -->
|
<!-- Startup & Shortcuts Section -->
|
||||||
<SettingSection :icon="Keyboard" :title="t('pages.settings.system.startupAndShortcuts')">
|
<SettingSection :icon="Keyboard" :title="t('pages.settings.system.startupAndShortcuts')">
|
||||||
<!-- Auto Launch Toggle -->
|
<!-- Auto Launch Toggle -->
|
||||||
|
<SettingCard p1>
|
||||||
<CustomSwitch
|
<CustomSwitch
|
||||||
v-model="formOfSetting.autoStart"
|
v-model="formOfSetting.autoStart"
|
||||||
small
|
small
|
||||||
|
no-border
|
||||||
:title="t('pages.settings.system.autoLaunch')"
|
:title="t('pages.settings.system.autoLaunch')"
|
||||||
:description="t('pages.settings.system.autoLaunchDesc')"
|
:description="t('pages.settings.system.autoLaunchDesc')"
|
||||||
@change="handleAutoStartChange(formOfSetting.autoStart)"
|
@change="handleAutoStartChange(formOfSetting.autoStart)"
|
||||||
/>
|
/>
|
||||||
|
</SettingCard>
|
||||||
<CustomNavCard
|
<CustomNavCard
|
||||||
:title="t('pages.settings.system.setShortCuts')"
|
:title="t('pages.settings.system.setShortCuts')"
|
||||||
:description="t('pages.settings.system.setShortCutsDesc')"
|
: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(
|
watch(
|
||||||
advancedRename,
|
advancedRename,
|
||||||
newVal => {
|
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() {
|
async function initData() {
|
||||||
const config = (await getConfig<IConfig>()) || ({} as IConfig)
|
const config = (await getConfig<IConfig>()) || ({} as IConfig)
|
||||||
const settings = config.settings || {}
|
const settings = config.settings || {}
|
||||||
|
|||||||
@@ -270,14 +270,7 @@
|
|||||||
height="auto"
|
height="auto"
|
||||||
>
|
>
|
||||||
<div class="flex-1 overflow-y-auto p-4">
|
<div class="flex-1 overflow-y-auto p-4">
|
||||||
<config-form
|
<config-form :id="configName" ref="$configForm" :config="config" :type="currentType" mode="plugin" />
|
||||||
:id="configName"
|
|
||||||
ref="$configForm"
|
|
||||||
:config="config"
|
|
||||||
:type="currentType"
|
|
||||||
mode="plugin"
|
|
||||||
:show-tooltips="false"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<CustomButton type="secondary" :text="t('common.cancel')" @click="dialogVisible = false" />
|
<CustomButton type="secondary" :text="t('common.cancel')" @click="dialogVisible = false" />
|
||||||
|
|||||||
Reference in New Issue
Block a user