Feature(custom): support use presigned url for image preview

ISSUES CLOSED: #265
This commit is contained in:
Kuingsmile 2024-11-14 17:28:59 +08:00
parent cd48b24a21
commit 4209838925
9 changed files with 217 additions and 34 deletions

View File

@ -392,6 +392,7 @@ MANAGE_SETTING_CLEAR_CACHE_TIPS: After clearing, the file list will be reloaded
MANAGE_SETTING_CLEAR_CACHE_PROMPT: Are you sure you want to clear the file list cache database?
MANAGE_SETTING_CLEAR_CACHE_BUTTON: Clear
MANAGE_SETTING_ISSHOWTHUMBNAIL_TITLE: Display the original image instead of format icon (requires public access permissions)
MANAGE_SETTING_ISUSEPRESIGNEDURL_TITLE: Use presigned URL for image display
MANAGE_SETTING_ISSHOWLIST_TITLE: Default display mode for the file list
MANAGE_SETTING_ISSHOWLIST_ON: List
MANAGE_SETTING_ISSHOWLIST_OFF: Card

View File

@ -394,6 +394,7 @@ MANAGE_SETTING_CLEAR_CACHE_TIPS: 清空后下次进入新目录时将会重新
MANAGE_SETTING_CLEAR_CACHE_PROMPT: 确定要清空文件列表缓存数据库吗?
MANAGE_SETTING_CLEAR_CACHE_BUTTON: 清空
MANAGE_SETTING_ISSHOWTHUMBNAIL_TITLE: 图片显示为原图而非默认文件格式图标(需要存储桶可公开访问)
MANAGE_SETTING_ISUSEPRESIGNEDURL_TITLE: 使用预签名URL预览图片
MANAGE_SETTING_ISSHOWLIST_TITLE: 文件列表默认显示方式
MANAGE_SETTING_ISSHOWLIST_ON: 列表
MANAGE_SETTING_ISSHOWLIST_OFF: 卡片

View File

@ -392,6 +392,7 @@ MANAGE_SETTING_CLEAR_CACHE_TIPS: 清空後下次進入新目錄時將會重新
MANAGE_SETTING_CLEAR_CACHE_PROMPT: 確定要清空檔案列表快取資料庫嗎?
MANAGE_SETTING_CLEAR_CACHE_BUTTON: 清空
MANAGE_SETTING_ISSHOWTHUMBNAIL_TITLE: 顯示圖片的原始圖像而非預設的檔案格式圖示(需要存儲桶公開訪問權限)
MANAGE_SETTING_ISUSEPRESIGNEDURL_TITLE: 使用預簽名URL预览圖片
MANAGE_SETTING_ISSHOWLIST_TITLE: 檔案列表預設顯示方式
MANAGE_SETTING_ISSHOWLIST_ON: 列表
MANAGE_SETTING_ISSHOWLIST_OFF: 卡片

View File

@ -0,0 +1,51 @@
<template>
<el-image :src="imageSource" fit="contain" style="height: 100px; width: 100%; margin: 0 auto">
<template #placeholder>
<el-icon>
<Loading />
</el-icon>
</template>
<template #error>
<el-image :src="iconPath" fit="contain" style="height: 100px; width: 100%; margin: 0 auto" />
</template>
</el-image>
</template>
<script lang="ts" setup>
import { ref, onMounted, watch, computed } from 'vue'
import { Loading } from '@element-plus/icons-vue'
import { getFileIconPath } from '@/manage/utils/common'
import { IRPCActionType } from '#/types/enum'
import { triggerRPC } from '@/utils/common'
const preSignedUrl = ref('')
const props = defineProps<{
item: {
key: string
isImage: boolean
fileName: string | null | undefined
}
alias: string
url: string
config: any
isShowThumbnail: boolean
}>()
const imageSource = computed(() => {
return props.isShowThumbnail && props.item.isImage
? preSignedUrl.value
: require(`../manage/pages/assets/icons/${getFileIconPath(props.item.fileName ?? '')}`)
})
const iconPath = computed(() => require(`../manage/pages/assets/icons/${getFileIconPath(props.item.fileName ?? '')}`))
async function getUrl() {
preSignedUrl.value = await triggerRPC<any>(IRPCActionType.MANAGE_GET_PRE_SIGNED_URL, props.alias, props.config)
}
watch(() => [props.url, props.item], getUrl, { deep: true })
onMounted(getUrl)
</script>

View File

@ -0,0 +1,65 @@
import { ElImage, ElIcon } from 'element-plus'
import { defineComponent, ref, onMounted, watch, computed } from 'vue'
import { Loading } from '@element-plus/icons-vue'
import { getFileIconPath } from '@/manage/utils/common'
import { IRPCActionType } from '#/types/enum'
import { triggerRPC } from '@/utils/common'
export default defineComponent({
props: {
isShowThumbnail: {
type: Boolean,
required: true
},
item: {
type: Object,
required: true
},
alias: {
type: String,
required: true
},
url: {
type: String,
required: true
},
config: {
type: Object,
required: true
}
},
setup(props) {
const preSignedUrl = ref('')
const imageSource = computed(() => {
return props.isShowThumbnail && props.item.isImage
? preSignedUrl.value
: require(`../manage/pages/assets/icons/${getFileIconPath(props.item.fileName ?? '')}`)
})
const iconPath = computed(() =>
require(`../manage/pages/assets/icons/${getFileIconPath(props.item.fileName ?? '')}`)
)
async function getUrl() {
preSignedUrl.value = await triggerRPC<any>(IRPCActionType.MANAGE_GET_PRE_SIGNED_URL, props.alias, props.config)
}
watch(() => [props.url, props.item], getUrl, { deep: true })
onMounted(getUrl)
return () => (
<ElImage src={imageSource.value} fit='contain' style='height: 100px;width: 100%;margin: 0 auto;'>
{{
placeholder: () => (
<ElIcon>
<Loading />
</ElIcon>
),
error: () => <ElImage src={iconPath.value} fit='contain' style='height: 100px;width: 100%;margin: 0 auto;' />
}}
</ElImage>
)
}
})

View File

@ -5,7 +5,7 @@
<span v-for="(segment, index) in segments" :key="index" :style="segment.style">
{{ segment.text }}
</span>
<el-tooltip :content="tooltip" effect="dark" placement="right" :persistent="false" teleported>
<el-tooltip v-if="tooltip" :content="tooltip" effect="dark" placement="right" :persistent="false" teleported>
<el-icon>
<InfoFilled />
</el-icon>

View File

@ -391,12 +391,7 @@ https://www.baidu.com/img/bd_logo1.png"
shadow="hover"
>
<el-image
v-if="
!item.isDir &&
currentPicBedName !== 'webdavplist' &&
currentPicBedName !== 'sftp' &&
currentPicBedName !== 'local'
"
v-if="!item.isDir && !['webdavplist', 'sftp', 'local', 's3plist'].includes(currentPicBedName)"
:src="
isShowThumbnail && item.isImage
? item.url
@ -419,6 +414,39 @@ https://www.baidu.com/img/bd_logo1.png"
/>
</template>
</el-image>
<el-image
v-else-if="!item.isDir && currentPicBedName === 's3plist' && !isUsePreSignedUrl"
:src="
isShowThumbnail && item.isImage
? item.url
: require(`./assets/icons/${getFileIconPath(item.fileName ?? '')}`)
"
fit="contain"
style="height: 100px; width: 100%; margin: 0 auto"
@click="handleClickFile(item)"
>
<template #placeholder>
<el-icon>
<Loading />
</el-icon>
</template>
<template #error>
<el-image
:src="require(`./assets/icons/${getFileIconPath(item.fileName ?? '')}`)"
fit="contain"
style="height: 100px; width: 100%; margin: 0 auto"
/>
</template>
</el-image>
<ImagePreSign
v-else-if="!item.isDir && currentPicBedName === 's3plist' && isUsePreSignedUrl"
:is-show-thumbnail="isShowThumbnail"
:item="item"
:alias="configMap.alias"
:url="item.url"
:config="handleGetS3Config(item)"
@click="handleClickFile(item)"
/>
<ImageWebdav
v-else-if="!item.isDir && currentPicBedName === 'webdavplist' && item.isImage"
:is-show-thumbnail="isShowThumbnail"
@ -1222,8 +1250,10 @@ import { textFileExt } from '@/manage/utils/textfile'
import { videoExt } from '@/manage/utils/videofile'
import ImageWebdav from '@/components/ImageWebdav.vue'
import ImagePreSign from '@/components/ImagePreSign.vue'
import ImageLocal from '@/components/ImageLocal.vue'
import ImageWebdavTsx from '@/components/ImageWebdavTsx'
import ImagePreSignTsx from '@/components/ImagePreSignTsx'
import { T as $T } from '@/i18n'
@ -1231,7 +1261,7 @@ import { getExtension, trimPath } from '#/utils/common'
import { cancelDownloadLoadingFileList, refreshDownloadFileTransferList } from '#/utils/static'
import { IUploadTask, IDownloadTask } from '#/types/manage'
import { sendRPC, triggerRPC } from '@/utils/common'
import { IRPCActionType } from 'root/src/universal/types/enum'
import { IRPCActionType } from '#/types/enum'
/*
configMap:{
@ -1378,6 +1408,7 @@ const calculateAllFileSize = computed(
'0'
)
const isShowThumbnail = computed(() => manageStore.config.settings.isShowThumbnail ?? false)
const isUsePreSignedUrl = computed(() => manageStore.config.settings.isUsePreSignedUrl ?? false)
const isAutoRefresh = computed(() => manageStore.config.settings.isAutoRefresh ?? false)
const isIgnoreCase = computed(() => manageStore.config.settings.isIgnoreCase ?? false)
@ -2901,6 +2932,18 @@ function singleRename() {
})
}
function handleGetS3Config(item: any) {
return {
bucketName: configMap.bucketName,
region: configMap.bucketConfig.Location,
key: item.key,
customUrl: currentCustomDomain.value,
expires: manageStore.config.settings.PreSignedExpire,
githubPrivate: configMap.bucketConfig.private,
rawUrl: item.url
}
}
async function getPreSignedUrl(item: any) {
const param = {
// tcyun
@ -3180,32 +3223,42 @@ const columns: Column<any>[] = [
reference: () =>
!item.isDir ? (
currentPicBedName.value !== 'webdavplist' ? (
<ElImage
src={
isShowThumbnail.value
? item.isImage
? item.url
currentPicBedName.value === 's3plist' && item.isImage && isUsePreSignedUrl.value ? (
<ImagePreSignTsx
isShowThumbnail={isShowThumbnail.value}
item={item}
config={handleGetS3Config(item)}
url={item.url}
alias={configMap.alias}
/>
) : (
<ElImage
src={
isShowThumbnail.value
? item.isImage
? item.url
: require(`./assets/icons/${getFileIconPath(item.fileName ?? '')}`)
: require(`./assets/icons/${getFileIconPath(item.fileName ?? '')}`)
: require(`./assets/icons/${getFileIconPath(item.fileName ?? '')}`)
}
fit='contain'
style={{ width: '20px', height: '20px' }}
>
{{
placeholder: () => (
<ElIcon>
<Loading />
</ElIcon>
),
error: () => (
<ElImage
src={require(`./assets/icons/${getFileIconPath(item.fileName ?? '')}`)}
fit='contain'
style={{ width: '20px', height: '20px' }}
/>
)
}}
</ElImage>
}
fit='contain'
style={{ width: '20px', height: '20px' }}
>
{{
placeholder: () => (
<ElIcon>
<Loading />
</ElIcon>
),
error: () => (
<ElImage
src={require(`./assets/icons/${getFileIconPath(item.fileName ?? '')}`)}
fit='contain'
style={{ width: '20px', height: '20px' }}
/>
)
}}
</ElImage>
)
) : item.isImage ? (
<ImageWebdavTsx
isShowThumbnail={isShowThumbnail.value}
@ -3235,6 +3288,14 @@ const columns: Column<any>[] = [
config={handleGetWebdavConfig()}
url={item.url}
/>
) : currentPicBedName.value === 's3plist' && item.isImage && isUsePreSignedUrl.value ? (
<ImagePreSignTsx
isShowThumbnail={isShowThumbnail.value}
item={item}
config={handleGetS3Config(item)}
url={item.url}
alias={configMap.alias}
/>
) : (
<ElImage
src={item.isImage ? item.url : require(`./assets/icons/${getFileIconPath(item.fileName ?? '')}`)}

View File

@ -214,6 +214,7 @@ const form = ref<IStringKeyMap>({
isAutoRefresh: false,
isShowThumbnail: false,
isShowList: false,
isUsePreSignedUrl: false,
isIgnoreCase: false,
isForceCustomUrlHttps: false,
isEncodeUrl: false,
@ -246,6 +247,7 @@ const switchFieldsList = [
'isAutoRefresh',
'isShowThumbnail',
'isShowList',
'isUsePreSignedUrl',
'isForceCustomUrlHttps',
'isEncodeUrl',
'isUploadKeepDirStructure',
@ -254,7 +256,7 @@ const switchFieldsList = [
'randomStringRename',
'customRename'
]
const switchFieldsNoTipsList = ['isShowThumbnail', 'isShowList']
const switchFieldsNoTipsList = ['isShowThumbnail', 'isShowList', 'isUsePreSignedUrl']
const switchFieldsHasActiveTextList = ['isShowList']
const switchFieldsConfigList = switchFieldsList.map(item => ({

View File

@ -368,6 +368,7 @@ interface ILocales {
MANAGE_SETTING_CLEAR_CACHE_PROMPT: string
MANAGE_SETTING_CLEAR_CACHE_BUTTON: string
MANAGE_SETTING_ISSHOWTHUMBNAIL_TITLE: string
MANAGE_SETTING_ISUSEPRESIGNEDURL_TITLE: string
MANAGE_SETTING_ISSHOWLIST_TITLE: string
MANAGE_SETTING_ISSHOWLIST_ON: string
MANAGE_SETTING_ISSHOWLIST_OFF: string