mirror of
https://github.com/Kuingsmile/PicList.git
synced 2026-07-07 23:51:41 +08:00
✨ Feature: s3-compatible storage is supported now
This commit is contained in:
@@ -4,11 +4,11 @@ export default class AwsS3Api {
|
||||
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
||||
const { imgUrl, config: { accessKeyID, secretAccessKey, bucketName, region, endpoint, pathStyleAccess, bucketEndpoint, rejectUnauthorized } } = configMap
|
||||
try {
|
||||
const url = new URL((!imgUrl.startsWith('http') && !imgUrl.startsWith('https')) ? `http://${imgUrl}` : imgUrl)
|
||||
const url = new URL(!/^https?:\/\//.test(imgUrl) ? `http://${imgUrl}` : imgUrl)
|
||||
const fileKey = url.pathname
|
||||
let endpointUrl
|
||||
if (endpoint) {
|
||||
if (!endpoint.startsWith('http') && !endpoint.startsWith('https')) {
|
||||
if (!/^https?:\/\//.test(endpoint)) {
|
||||
endpointUrl = `http://${endpoint}`
|
||||
} else {
|
||||
endpointUrl = endpoint
|
||||
@@ -29,7 +29,8 @@ export default class AwsS3Api {
|
||||
s3BucketEndpoint: bucketEndpoint,
|
||||
httpOptions: {
|
||||
agent: new http.Agent({
|
||||
rejectUnauthorized
|
||||
rejectUnauthorized,
|
||||
timeout: 30000
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -11,7 +11,7 @@ export default class ImgurApi {
|
||||
try {
|
||||
const res = await axios.delete(fullUrl, {
|
||||
headers,
|
||||
timeout: 10000
|
||||
timeout: 30000
|
||||
})
|
||||
return res.status === 200
|
||||
} catch (error) {
|
||||
|
||||
@@ -15,7 +15,7 @@ export default class SmmsApi {
|
||||
hash,
|
||||
format: 'json'
|
||||
},
|
||||
timeout: 10000
|
||||
timeout: 30000
|
||||
})
|
||||
return res.status === 200
|
||||
}
|
||||
|
||||
BIN
src/renderer/manage/pages/assets/s3plist.png
Normal file
BIN
src/renderer/manage/pages/assets/s3plist.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -15,7 +15,7 @@
|
||||
style="flex-grow: 1;margin-left: 16px"
|
||||
>
|
||||
<el-select
|
||||
v-if="showCustomUrlSelectList && customUrlList.length > 1"
|
||||
v-if="showCustomUrlSelectList && customUrlList.length > 1 && isAutoCustomUrl"
|
||||
v-model="currentCustomUrl"
|
||||
placeholder="请选择自定义域名"
|
||||
style="width: 200px;"
|
||||
@@ -28,6 +28,13 @@
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
<el-input
|
||||
v-else-if="['aliyun', 'qiniu', 'tcyun', 's3plist'].includes(currentPicBedName)"
|
||||
v-model="currentCustomUrl"
|
||||
placeholder="请输入自定义域名"
|
||||
style="width: 200px;"
|
||||
@blur="handelChangeCustomUrl"
|
||||
/>
|
||||
<el-link
|
||||
v-else
|
||||
:underline="false"
|
||||
@@ -140,7 +147,7 @@
|
||||
<Link />
|
||||
</el-icon>
|
||||
<template #dropdown>
|
||||
<template v-if="['tcyun', 'qiniu', 'aliyun', 'github'].includes(currentPicBedName)">
|
||||
<template v-if="showPresignedUrl">
|
||||
<el-dropdown-item
|
||||
v-for="i in [...linkArray, { key: '预签名链接', value: 'preSignedUrl' }]"
|
||||
:key="i.key"
|
||||
@@ -790,6 +797,7 @@ import { v4 as uuidv4 } from 'uuid'
|
||||
import path from 'path'
|
||||
import { IUploadTask, IDownloadTask } from '~/main/manage/datastore/upDownTaskQueue'
|
||||
import fs from 'fs-extra'
|
||||
import { getConfig, saveConfig } from '../utils/dataSender'
|
||||
|
||||
/*
|
||||
configMap:{
|
||||
@@ -866,9 +874,11 @@ const currentCustomUrl = ref('')
|
||||
|
||||
const showCustomUrlSelectList = computed(() => ['tcyun', 'aliyun', 'qiniu', 'github'].includes(currentPicBedName.value))
|
||||
|
||||
const showCreateNewFolder = computed(() => ['tcyun', 'aliyun', 'qiniu', 'upyun', 'github'].includes(currentPicBedName.value))
|
||||
const showCreateNewFolder = computed(() => ['tcyun', 'aliyun', 'qiniu', 'upyun', 'github', 's3plist'].includes(currentPicBedName.value))
|
||||
|
||||
const showRenameFileIcon = computed(() => ['tcyun', 'aliyun', 'qiniu', 'upyun'].includes(currentPicBedName.value))
|
||||
const showRenameFileIcon = computed(() => ['tcyun', 'aliyun', 'qiniu', 'upyun', 's3plist'].includes(currentPicBedName.value))
|
||||
|
||||
const showPresignedUrl = computed(() => ['tcyun', 'aliyun', 'qiniu', 'github', 's3plist'].includes(currentPicBedName.value))
|
||||
|
||||
const uploadingTaskList = computed(() => uploadTaskList.value.filter(item => ['uploading', 'queuing', 'paused'].includes(item.status)))
|
||||
|
||||
@@ -878,6 +888,8 @@ const downloadingTaskList = computed(() => downloadTaskList.value.filter(item =>
|
||||
|
||||
const downloadedTaskList = computed(() => downloadTaskList.value.filter(item => ['downloaded', 'failed', 'canceled'].includes(item.status)))
|
||||
|
||||
const isAutoCustomUrl = computed(() => manageStore.config.picBed[configMap.alias].isAutoCustomUrl === undefined ? true : manageStore.config.picBed[configMap.alias].isAutoCustomUrl)
|
||||
|
||||
function startRefreshUploadTask () {
|
||||
refreshUploadTaskId.value = setInterval(() => {
|
||||
ipcRenderer.invoke('getUploadTaskList').then((res: any) => {
|
||||
@@ -1096,7 +1108,8 @@ function uploadFiles () {
|
||||
filePath: item.path,
|
||||
fileSize: item.size,
|
||||
fileName: item.rawName,
|
||||
githubBranch: currentCustomUrl.value
|
||||
githubBranch: currentCustomUrl.value,
|
||||
aclForUpload: manageStore.config.picBed[configMap.alias].aclForUpload
|
||||
})
|
||||
})
|
||||
ipcRenderer.send('uploadBucketFile', configMap.alias, param)
|
||||
@@ -1193,49 +1206,97 @@ async function handelChangeCustomUrl () {
|
||||
showLoadingPage.value = true
|
||||
await resetParam(true)
|
||||
showLoadingPage.value = false
|
||||
} else if (['aliyun', 'tcyun', 'qiniu', 's3plist'].includes(currentPicBedName.value)) {
|
||||
const currentConfigs = await getConfig<any>('picBed')
|
||||
const currentConfig = currentConfigs[configMap.alias]
|
||||
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
||||
if (currentTransformedConfig[configMap.bucketName]) {
|
||||
currentTransformedConfig[configMap.bucketName].customUrl = currentCustomUrl.value
|
||||
} else {
|
||||
currentTransformedConfig[configMap.bucketName] = {
|
||||
customUrl: currentCustomUrl.value
|
||||
}
|
||||
}
|
||||
currentConfig.transformedConfig = JSON.stringify(currentTransformedConfig)
|
||||
saveConfig(`picBed.${configMap.alias}`, currentConfig)
|
||||
await manageStore.refreshConfig()
|
||||
}
|
||||
}
|
||||
|
||||
// when the current picBed is github, the customUrlList is used to store the github repo branches
|
||||
async function initCustomUrlList () {
|
||||
const param = {
|
||||
bucketName: configMap.bucketName,
|
||||
region: configMap.bucketConfig.Location
|
||||
}
|
||||
let defaultUrl = ''
|
||||
if (currentPicBedName.value === 'tcyun') {
|
||||
defaultUrl = `https://${configMap.bucketName}.cos.${configMap.bucketConfig.Location}.myqcloud.com`
|
||||
} else if (currentPicBedName.value === 'aliyun') {
|
||||
defaultUrl = `https://${configMap.bucketName}.${configMap.bucketConfig.Location}.aliyuncs.com`
|
||||
} else if (currentPicBedName.value === 'github') {
|
||||
defaultUrl = 'main'
|
||||
}
|
||||
const res = await ipcRenderer.invoke('getBucketDomain', configMap.alias, param)
|
||||
if (res.length > 0) {
|
||||
customUrlList.value.length = 0
|
||||
res.forEach((item: any) => {
|
||||
if (!item.startsWith('http://') && !item.startsWith('https://') && currentPicBedName.value !== 'github') {
|
||||
item = manageStore.config.settings.isForceCustomUrlHttps ? `https://${item}` : `http://${item}`
|
||||
}
|
||||
customUrlList.value.push({
|
||||
label: item,
|
||||
value: item
|
||||
if ((['aliyun', 'tcyun', 'qiniu'].includes(currentPicBedName.value) &&
|
||||
(manageStore.config.picBed[configMap.alias].isAutoCustomUrl === undefined || manageStore.config.picBed[configMap.alias].isAutoCustomUrl === true)) ||
|
||||
['github', 'smms', 'upyun', 'imgur'].includes(currentPicBedName.value)) {
|
||||
const param = {
|
||||
bucketName: configMap.bucketName,
|
||||
region: configMap.bucketConfig.Location
|
||||
}
|
||||
let defaultUrl = ''
|
||||
if (currentPicBedName.value === 'tcyun') {
|
||||
defaultUrl = `https://${configMap.bucketName}.cos.${configMap.bucketConfig.Location}.myqcloud.com`
|
||||
} else if (currentPicBedName.value === 'aliyun') {
|
||||
defaultUrl = `https://${configMap.bucketName}.${configMap.bucketConfig.Location}.aliyuncs.com`
|
||||
} else if (currentPicBedName.value === 'github') {
|
||||
defaultUrl = 'main'
|
||||
}
|
||||
const res = await ipcRenderer.invoke('getBucketDomain', configMap.alias, param)
|
||||
if (res.length > 0) {
|
||||
customUrlList.value.length = 0
|
||||
res.forEach((item: any) => {
|
||||
if (!/^https?:\/\//.test(item) && currentPicBedName.value !== 'github') {
|
||||
item = manageStore.config.settings.isForceCustomUrlHttps ? `https://${item}` : `http://${item}`
|
||||
}
|
||||
customUrlList.value.push({
|
||||
label: item,
|
||||
value: item
|
||||
})
|
||||
})
|
||||
})
|
||||
defaultUrl !== '' && currentPicBedName.value !== 'github' && customUrlList.value.push({
|
||||
label: defaultUrl,
|
||||
value: defaultUrl
|
||||
})
|
||||
currentCustomUrl.value = customUrlList.value[0].value
|
||||
} else {
|
||||
customUrlList.value.length = 0
|
||||
customUrlList.value = [
|
||||
{
|
||||
defaultUrl !== '' && currentPicBedName.value !== 'github' && customUrlList.value.push({
|
||||
label: defaultUrl,
|
||||
value: defaultUrl
|
||||
})
|
||||
currentCustomUrl.value = customUrlList.value[0].value
|
||||
} else {
|
||||
customUrlList.value.length = 0
|
||||
customUrlList.value = [
|
||||
{
|
||||
label: defaultUrl,
|
||||
value: defaultUrl
|
||||
}
|
||||
]
|
||||
currentCustomUrl.value = defaultUrl
|
||||
}
|
||||
} else if (['aliyun', 'tcyun', 'qiniu'].includes(currentPicBedName.value)) {
|
||||
const currentConfigs = await getConfig<any>('picBed')
|
||||
const currentConfig = currentConfigs[configMap.alias]
|
||||
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
||||
if (currentTransformedConfig[configMap.bucketName]) {
|
||||
currentCustomUrl.value = currentTransformedConfig[configMap.bucketName].customUrl ?? ''
|
||||
} else {
|
||||
currentCustomUrl.value = ''
|
||||
}
|
||||
} else if (currentPicBedName.value === 's3plist') {
|
||||
const currentConfigs = await getConfig<any>('picBed')
|
||||
const currentConfig = currentConfigs[configMap.alias]
|
||||
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
||||
if (currentTransformedConfig[configMap.bucketName]) {
|
||||
currentCustomUrl.value = currentTransformedConfig[configMap.bucketName].customUrl ?? ''
|
||||
} else {
|
||||
if (manageStore.config.picBed[configMap.alias].endpoint) {
|
||||
const endpoint = manageStore.config.picBed[configMap.alias].endpoint
|
||||
let url
|
||||
if (/^https?:\/\//.test(endpoint)) {
|
||||
url = new URL(endpoint)
|
||||
} else {
|
||||
url = new URL(manageStore.config.picBed[configMap.alias].sslEnabled ? 'https://' + endpoint : 'http://' + endpoint)
|
||||
}
|
||||
currentCustomUrl.value = `${url.protocol}//${configMap.bucketName}.${url.hostname}`
|
||||
} else {
|
||||
currentCustomUrl.value = `https://${configMap.bucketName}.s3.amazonaws.com`
|
||||
}
|
||||
]
|
||||
currentCustomUrl.value = defaultUrl
|
||||
}
|
||||
handelChangeCustomUrl()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2484,7 +2545,7 @@ const columns: Column<any>[] = [
|
||||
>
|
||||
自定义
|
||||
</ElDropdownItem>
|
||||
{['tcyun', 'aliyun', 'qiniu', 'github'].includes(currentPicBedName.value)
|
||||
{ showPresignedUrl.value
|
||||
? <ElDropdownItem
|
||||
onClick={async () => {
|
||||
const res = await getPreSignedUrl(item)
|
||||
|
||||
@@ -133,22 +133,50 @@
|
||||
v-for="option in supportedPicBedList[item.icon].options"
|
||||
:key="option"
|
||||
:prop="item.icon + '.' + option"
|
||||
:label="supportedPicBedList[item.icon].configOptions[option].description"
|
||||
>
|
||||
<template #label>
|
||||
{{ supportedPicBedList[item.icon].configOptions[option].description }}
|
||||
<el-tooltip
|
||||
v-if="!!supportedPicBedList[item.icon].configOptions[option].tooltip"
|
||||
effect="dark"
|
||||
:content="supportedPicBedList[item.icon].configOptions[option].tooltip"
|
||||
placement="right"
|
||||
>
|
||||
<el-icon
|
||||
color="#409EFF"
|
||||
>
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<el-input
|
||||
v-if="option !== 'paging' && option !== 'itemsPerPage'"
|
||||
v-if="supportedPicBedList[item.icon].configOptions[option].type === 'string'"
|
||||
v-model.trim="configResult[item.icon + '.' + option]"
|
||||
:placeholder="supportedPicBedList[item.icon].configOptions[option].placeholder"
|
||||
/>
|
||||
<el-switch
|
||||
v-else-if="option === 'paging'"
|
||||
v-else-if="supportedPicBedList[item.icon].configOptions[option].type === 'boolean'"
|
||||
v-model="configResult[item.icon + '.' + option]"
|
||||
active-color="#13ce66"
|
||||
inactive-color="#ff4949"
|
||||
/>
|
||||
<el-input
|
||||
v-else
|
||||
v-else-if="supportedPicBedList[item.icon].configOptions[option].type === 'number'"
|
||||
v-model.number="configResult[item.icon + '.' + option]"
|
||||
:placeholder="supportedPicBedList[item.icon].configOptions[option].placeholder"
|
||||
/>
|
||||
<el-select
|
||||
v-else-if="supportedPicBedList[item.icon].configOptions[option].type === 'select'"
|
||||
v-model="configResult[item.icon + '.' + option]"
|
||||
placeholder="请选择"
|
||||
>
|
||||
<el-option
|
||||
v-for="i in Object.entries(supportedPicBedList[item.icon].configOptions[option].selectOptions)"
|
||||
:key="i[0]"
|
||||
:label="i[1] as string"
|
||||
:value="i[0]"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div style="margin: 0 auto;position: relative;left: 10%;right: 50%;">
|
||||
@@ -220,7 +248,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, onBeforeMount, computed } from 'vue'
|
||||
import { supportedPicBedList } from '../utils/constants'
|
||||
import { Delete, Edit, Pointer } from '@element-plus/icons-vue'
|
||||
import { Delete, Edit, Pointer, InfoFilled } from '@element-plus/icons-vue'
|
||||
import { ElMessage, ElNotification } from 'element-plus'
|
||||
import { getConfig, saveConfig, removeConfig } from '../utils/dataSender'
|
||||
import { shell } from 'electron'
|
||||
@@ -314,7 +342,7 @@ const handleConfigChange = async (name: string) => {
|
||||
for (const key of allKeys) {
|
||||
const resultKey = name + '.' + key
|
||||
if (supportedPicBedList[name].configOptions[key].required) {
|
||||
if (key !== 'paging' && !configResult[resultKey]) {
|
||||
if (supportedPicBedList[name].configOptions[key].type !== 'boolean' && !configResult[resultKey]) {
|
||||
ElMessage.error(`请填写 ${supportedPicBedList[name].configOptions[key].description}`)
|
||||
return
|
||||
}
|
||||
@@ -329,7 +357,7 @@ const handleConfigChange = async (name: string) => {
|
||||
}
|
||||
if ((key === 'customUrl') && configResult[resultKey] !== undefined && configResult[resultKey] !== '') {
|
||||
if (name !== 'upyun') {
|
||||
if (!configResult[resultKey].startsWith('http://') && !configResult[resultKey].startsWith('https://')) {
|
||||
if (!/^https?:\/\//.test(configResult[resultKey])) {
|
||||
ElMessage.error('自定义域名必须以http://或https://开头')
|
||||
return
|
||||
}
|
||||
@@ -363,7 +391,7 @@ const handleConfigChange = async (name: string) => {
|
||||
[bucketName[i]]: {
|
||||
baseDir: baseDir && baseDir[i] ? baseDir[i] : '/',
|
||||
area: area && area[i] ? area[i] : '',
|
||||
customUrl: customUrl && customUrl[i] ? customUrl[i].startsWith('http') || customUrl[i].startsWith('https') ? customUrl[i] : 'http://' + customUrl[i] : '',
|
||||
customUrl: customUrl && customUrl[i] ? /^https?:\/\//.test(customUrl[i]) ? customUrl[i] : 'http://' + customUrl[i] : '',
|
||||
operator: operator && operator[i] ? operator[i] : '',
|
||||
password: password && password[i] ? password[i] : ''
|
||||
}
|
||||
@@ -489,10 +517,12 @@ function handleConfigImport (alias: string) {
|
||||
const selectedConfig = existingConfiguration[alias]
|
||||
if (selectedConfig) {
|
||||
supportedPicBedList[selectedConfig.picBedName].options.forEach((option: any) => {
|
||||
if (selectedConfig[option]) {
|
||||
if (selectedConfig[option] !== undefined) {
|
||||
configResult[selectedConfig.picBedName + '.' + option] = selectedConfig[option]
|
||||
}
|
||||
if (typeof selectedConfig[option] === 'boolean') {
|
||||
configResult[selectedConfig.picBedName + '.' + option] = selectedConfig[option]
|
||||
}
|
||||
configResult[selectedConfig.picBedName + '.paging'] = selectedConfig.paging
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,7 +315,8 @@ const urlMap : IStringKeyMap = {
|
||||
aliyun: 'https://oss.console.aliyun.com',
|
||||
qiniu: 'https://portal.qiniu.com',
|
||||
tcyun: 'https://console.cloud.tencent.com/cos',
|
||||
upyun: 'https://console.upyun.com'
|
||||
upyun: 'https://console.upyun.com',
|
||||
s3plist: 'https://aws.amazon.com/cn/s3/'
|
||||
}
|
||||
|
||||
const openPicBedUrl = () => shell.openExternal(urlMap[currentPagePicBedConfig.picBedName])
|
||||
@@ -438,6 +439,7 @@ const menuTitleMap:IStringKeyMap = {
|
||||
qiniu: '存储桶',
|
||||
tcyun: '存储桶',
|
||||
upyun: '存储桶',
|
||||
s3plist: '存储桶',
|
||||
smms: '相册',
|
||||
imgur: '相册',
|
||||
github: '仓库'
|
||||
|
||||
@@ -89,13 +89,10 @@ export function formatFileName (fileName: string) {
|
||||
return name.length > 20 ? `${name.slice(0, 20)}...${ext}` : fileName
|
||||
}
|
||||
|
||||
export function getExtension (fileName: string) {
|
||||
return path.extname(fileName).slice(1)
|
||||
}
|
||||
export const getExtension = (fileName: string) => path.extname(fileName).slice(1)
|
||||
|
||||
export function isImage (fileName: string) {
|
||||
return ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'ico'].includes(getExtension(fileName))
|
||||
}
|
||||
export const isImage = (fileName: string) =>
|
||||
['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'ico'].includes(getExtension(fileName))
|
||||
|
||||
export function formObjToTableData (obj: any) {
|
||||
const exclude = [undefined, null, '', 'transformedConfig']
|
||||
@@ -126,21 +123,23 @@ export interface IHTTPProxy {
|
||||
|
||||
export const formatHttpProxy = (proxy: string | undefined, type: 'object' | 'string'): IHTTPProxy | undefined | string => {
|
||||
if (proxy === undefined || proxy === '') return undefined
|
||||
if (proxy.startsWith('http://') || proxy.startsWith('https://')) {
|
||||
if (/^https?:\/\//.test(proxy)) {
|
||||
const { protocol, hostname, port } = new URL(proxy)
|
||||
if (type === 'string') return `${protocol}//${hostname}:${port}`
|
||||
return {
|
||||
host: hostname,
|
||||
port: Number(port),
|
||||
protocol: protocol.slice(0, -1)
|
||||
}
|
||||
return type === 'string'
|
||||
? `${protocol}//${hostname}:${port}`
|
||||
: {
|
||||
host: hostname,
|
||||
port: Number(port),
|
||||
protocol: protocol.slice(0, -1)
|
||||
}
|
||||
} else {
|
||||
const [host, port] = proxy.split(':')
|
||||
if (type === 'string') return `http://${host}:${port}`
|
||||
return {
|
||||
host,
|
||||
port: port ? Number(port) : 80,
|
||||
protocol: 'http'
|
||||
}
|
||||
return type === 'string'
|
||||
? `http://${host}:${port}`
|
||||
: {
|
||||
host,
|
||||
port: port ? Number(port) : 80,
|
||||
protocol: 'http'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,13 @@ const aliasRule = [
|
||||
}
|
||||
]
|
||||
|
||||
const aliasTooltip = '配置别名只能包含中文、英文、数字和下划线,且不能超过15个字符'
|
||||
const itemsPerPageTooltip = '每页显示数量必须在20-1000之间'
|
||||
const pagingTooltip = '关闭分页时,目录列表将使用数据库缓存以优化性能'
|
||||
const bucketNameTooltip = '英文逗号分隔,如:bucket1,bucket2,bucket3,和起始目录顺序一一对应'
|
||||
const baseDirTooltip = '英文逗号分隔,如:/dir1,/dir2,/dir3,和存储桶顺序一一对应'
|
||||
const isAutoCustomUrlTooltip = '开启时,将自动获取存储桶绑定的域名,关闭时可手动填写域名'
|
||||
|
||||
export const supportedPicBedList: IStringKeyMap = {
|
||||
smms: {
|
||||
name: 'SM.MS',
|
||||
@@ -62,7 +69,8 @@ export const supportedPicBedList: IStringKeyMap = {
|
||||
placeholder: '该配置的唯一标识',
|
||||
type: 'string',
|
||||
rule: aliasRule,
|
||||
default: 'smms-A'
|
||||
default: 'smms-A',
|
||||
tooltip: aliasTooltip
|
||||
},
|
||||
token: {
|
||||
required: true,
|
||||
@@ -75,7 +83,8 @@ export const supportedPicBedList: IStringKeyMap = {
|
||||
required: true,
|
||||
description: '是否分页',
|
||||
default: true,
|
||||
type: 'boolean'
|
||||
type: 'boolean',
|
||||
tooltip: pagingTooltip
|
||||
}
|
||||
},
|
||||
explain: '大陆地区请访问备用域名https://smms.app, 请勿大批量上传图片,否则API接口会被限制',
|
||||
@@ -93,7 +102,8 @@ export const supportedPicBedList: IStringKeyMap = {
|
||||
placeholder: '该配置的唯一标识',
|
||||
type: 'string',
|
||||
rule: aliasRule,
|
||||
default: 'qiniu-A'
|
||||
default: 'qiniu-A',
|
||||
tooltip: aliasTooltip
|
||||
},
|
||||
accessKey: {
|
||||
required: true,
|
||||
@@ -113,31 +123,42 @@ export const supportedPicBedList: IStringKeyMap = {
|
||||
required: false,
|
||||
description: '空间名-可选',
|
||||
placeholder: '英文逗号分隔,例如:bucket1,bucket2',
|
||||
type: 'string'
|
||||
type: 'string',
|
||||
tooltip: bucketNameTooltip
|
||||
},
|
||||
baseDir: {
|
||||
required: false,
|
||||
description: '起始目录-可选',
|
||||
placeholder: '英文逗号分隔,例如:/test1,/test2',
|
||||
default: '/',
|
||||
type: 'string'
|
||||
type: 'string',
|
||||
tooltip: baseDirTooltip
|
||||
},
|
||||
isAutoCustomUrl: {
|
||||
required: true,
|
||||
description: '是否自动获取绑定域名',
|
||||
default: true,
|
||||
type: 'boolean',
|
||||
tooltip: isAutoCustomUrlTooltip
|
||||
},
|
||||
paging: {
|
||||
required: true,
|
||||
description: '是否分页',
|
||||
default: true,
|
||||
type: 'boolean'
|
||||
type: 'boolean',
|
||||
tooltip: pagingTooltip
|
||||
},
|
||||
itemsPerPage: {
|
||||
required: true,
|
||||
description: '每页显示数量',
|
||||
default: 50,
|
||||
type: 'number',
|
||||
rule: itemsPerPageRule
|
||||
rule: itemsPerPageRule,
|
||||
tooltip: itemsPerPageTooltip
|
||||
}
|
||||
},
|
||||
explain: '空间名和起始目录配置时可通过英文逗号分隔不同存储桶的设置,顺序必须一致,逗号间留空或缺失项使用默认值',
|
||||
options: ['alias', 'accessKey', 'secretKey', 'bucketName', 'baseDir', 'paging', 'itemsPerPage'],
|
||||
options: ['alias', 'accessKey', 'secretKey', 'bucketName', 'baseDir', 'isAutoCustomUrl', 'paging', 'itemsPerPage'],
|
||||
refLink: 'https://pichoro.horosama.com/#/PicHoroDocs/configure?id=%e5%8f%82%e6%95%b0%e8%af%b4%e6%98%8e-3',
|
||||
referenceText: '配置教程请参考:'
|
||||
},
|
||||
@@ -151,14 +172,16 @@ export const supportedPicBedList: IStringKeyMap = {
|
||||
placeholder: '该配置的唯一标识',
|
||||
type: 'string',
|
||||
rule: aliasRule,
|
||||
default: 'github-A'
|
||||
default: 'github-A',
|
||||
tooltip: aliasTooltip
|
||||
},
|
||||
token: {
|
||||
required: true,
|
||||
description: 'token-必需',
|
||||
placeholder: '请输入token',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('token')
|
||||
rule: defaultBaseRule('token'),
|
||||
tooltip: '请提供具有完整repo权限的token,否则部分功能可能无法使用'
|
||||
},
|
||||
githubUsername: {
|
||||
required: true,
|
||||
@@ -171,19 +194,22 @@ export const supportedPicBedList: IStringKeyMap = {
|
||||
required: false,
|
||||
description: '代理-可选',
|
||||
placeholder: '例如:http://127.0.0.1:1080',
|
||||
type: 'string'
|
||||
type: 'string',
|
||||
tooltip: '如果您的网络环境需要使用代理才能访问GitHub,请在此处填写代理地址'
|
||||
},
|
||||
paging: {
|
||||
required: true,
|
||||
description: '是否分页',
|
||||
default: false,
|
||||
type: 'boolean'
|
||||
type: 'boolean',
|
||||
tooltip: pagingTooltip
|
||||
},
|
||||
customUrl: {
|
||||
required: false,
|
||||
description: 'CDN加速域名-可选;例如: https://cdn.staticaly.com/gh/{username}/{repo}@{branch}/{path}',
|
||||
description: 'CDN加速域名-可选',
|
||||
placeholder: '支持使用{username}、{repo}、{branch}和{path}作为替换占位符,用于适配不同仓库和分支',
|
||||
type: 'string',
|
||||
tooltip: '例如: https://cdn.staticaly.com/gh/{username}/{repo}@{branch}/{path}',
|
||||
rule: [
|
||||
{
|
||||
validator: (_rule: any, value: any, callback: any) => {
|
||||
@@ -251,7 +277,8 @@ export const supportedPicBedList: IStringKeyMap = {
|
||||
placeholder: '该配置的唯一标识',
|
||||
type: 'string',
|
||||
rule: aliasRule,
|
||||
default: 'aliyun-A'
|
||||
default: 'aliyun-A',
|
||||
tooltip: aliasTooltip
|
||||
},
|
||||
accessKeyId: {
|
||||
required: true,
|
||||
@@ -271,31 +298,42 @@ export const supportedPicBedList: IStringKeyMap = {
|
||||
required: false,
|
||||
description: '存储桶名-可选',
|
||||
placeholder: '英文逗号分隔,例如:bucket1,bucket2',
|
||||
type: 'string'
|
||||
type: 'string',
|
||||
tooltip: bucketNameTooltip
|
||||
},
|
||||
baseDir: {
|
||||
required: false,
|
||||
description: '起始目录-可选',
|
||||
placeholder: '英文逗号分隔,例如:/test1,/test2',
|
||||
type: 'string',
|
||||
default: '/'
|
||||
default: '/',
|
||||
tooltip: baseDirTooltip
|
||||
},
|
||||
isAutoCustomUrl: {
|
||||
required: true,
|
||||
description: '是否自动获取绑定域名',
|
||||
default: true,
|
||||
type: 'boolean',
|
||||
tooltip: isAutoCustomUrlTooltip
|
||||
},
|
||||
paging: {
|
||||
required: true,
|
||||
description: '是否分页',
|
||||
default: true,
|
||||
type: 'boolean'
|
||||
type: 'boolean',
|
||||
tooltip: pagingTooltip
|
||||
},
|
||||
itemsPerPage: {
|
||||
required: true,
|
||||
description: '每页显示数量',
|
||||
default: 50,
|
||||
type: 'number',
|
||||
rule: itemsPerPageRule
|
||||
rule: itemsPerPageRule,
|
||||
tooltip: itemsPerPageTooltip
|
||||
}
|
||||
},
|
||||
explain: '存储桶名和起始目录配置时可通过英文逗号分隔不同存储桶的设置,顺序必须一致,逗号间留空或缺失项使用默认值',
|
||||
options: ['alias', 'accessKeyId', 'accessKeySecret', 'bucketName', 'baseDir', 'paging', 'itemsPerPage'],
|
||||
options: ['alias', 'accessKeyId', 'accessKeySecret', 'bucketName', 'baseDir', 'isAutoCustomUrl', 'paging', 'itemsPerPage'],
|
||||
refLink: 'https://pichoro.horosama.com/#/PicHoroDocs/configure?id=%e5%8f%82%e6%95%b0%e8%af%b4%e6%98%8e-1',
|
||||
referenceText: '配置教程请参考:'
|
||||
},
|
||||
@@ -309,7 +347,8 @@ export const supportedPicBedList: IStringKeyMap = {
|
||||
placeholder: '该配置的唯一标识',
|
||||
type: 'string',
|
||||
rule: aliasRule,
|
||||
default: 'tcyun-A'
|
||||
default: 'tcyun-A',
|
||||
tooltip: aliasTooltip
|
||||
},
|
||||
secretId: {
|
||||
required: true,
|
||||
@@ -330,37 +369,49 @@ export const supportedPicBedList: IStringKeyMap = {
|
||||
description: 'appId-必需',
|
||||
placeholder: '请输入appId',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('appId')
|
||||
rule: defaultBaseRule('appId'),
|
||||
tooltip: '例如:1250000000'
|
||||
},
|
||||
bucketName: {
|
||||
required: false,
|
||||
description: '存储桶名-可选(注意包含AppId)',
|
||||
placeholder: '英文逗号分隔,例如:bucket1-1250000000,bucket2-1250000000',
|
||||
type: 'string'
|
||||
type: 'string',
|
||||
tooltip: bucketNameTooltip
|
||||
},
|
||||
baseDir: {
|
||||
required: false,
|
||||
description: '起始目录-可选',
|
||||
placeholder: '英文逗号分隔,例如:/test1,/test2',
|
||||
type: 'string',
|
||||
default: '/'
|
||||
default: '/',
|
||||
tooltip: baseDirTooltip
|
||||
},
|
||||
isAutoCustomUrl: {
|
||||
required: true,
|
||||
description: '是否自动获取绑定域名',
|
||||
default: true,
|
||||
type: 'boolean',
|
||||
tooltip: isAutoCustomUrlTooltip
|
||||
},
|
||||
paging: {
|
||||
required: true,
|
||||
description: '是否分页',
|
||||
default: true,
|
||||
type: 'boolean'
|
||||
type: 'boolean',
|
||||
tooltip: pagingTooltip
|
||||
},
|
||||
itemsPerPage: {
|
||||
required: true,
|
||||
description: '每页显示数量',
|
||||
default: 50,
|
||||
type: 'number',
|
||||
rule: itemsPerPageRule
|
||||
rule: itemsPerPageRule,
|
||||
tooltip: itemsPerPageTooltip
|
||||
}
|
||||
},
|
||||
explain: '存储桶名和起始目录配置时可通过英文逗号分隔不同存储桶的设置,顺序必须一致,逗号间留空或缺失项使用默认值',
|
||||
options: ['alias', 'secretId', 'secretKey', 'appId', 'bucketName', 'baseDir', 'paging', 'itemsPerPage'],
|
||||
options: ['alias', 'secretId', 'secretKey', 'appId', 'bucketName', 'baseDir', 'isAutoCustomUrl', 'paging', 'itemsPerPage'],
|
||||
refLink: 'https://pichoro.horosama.com/#/PicHoroDocs/configure?id=%e5%8f%82%e6%95%b0%e8%af%b4%e6%98%8e-2',
|
||||
referenceText: '配置教程请参考:'
|
||||
},
|
||||
@@ -374,7 +425,8 @@ export const supportedPicBedList: IStringKeyMap = {
|
||||
placeholder: '该配置的唯一标识',
|
||||
type: 'string',
|
||||
rule: aliasRule,
|
||||
default: 'upyun-A'
|
||||
default: 'upyun-A',
|
||||
tooltip: aliasTooltip
|
||||
},
|
||||
bucketName: {
|
||||
required: true,
|
||||
@@ -445,14 +497,16 @@ export const supportedPicBedList: IStringKeyMap = {
|
||||
required: true,
|
||||
description: '是否分页',
|
||||
default: true,
|
||||
type: 'boolean'
|
||||
type: 'boolean',
|
||||
tooltip: pagingTooltip
|
||||
},
|
||||
itemsPerPage: {
|
||||
required: true,
|
||||
description: '每页显示数量',
|
||||
default: 50,
|
||||
type: 'number',
|
||||
rule: itemsPerPageRule
|
||||
rule: itemsPerPageRule,
|
||||
tooltip: itemsPerPageTooltip
|
||||
}
|
||||
},
|
||||
explain: '又拍云图床务必填写加速域名,否则无法正常使用',
|
||||
@@ -481,21 +535,131 @@ export const supportedPicBedList: IStringKeyMap = {
|
||||
},
|
||||
accessToken: {
|
||||
required: true,
|
||||
description: 'accessToken-必需(不是clientID,请参考配置教程)',
|
||||
description: 'accessToken-必需',
|
||||
placeholder: '请输入accessToken',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('accessToken')
|
||||
rule: defaultBaseRule('accessToken'),
|
||||
tooltip: '不是clientID,请参考配置教程'
|
||||
},
|
||||
proxy: {
|
||||
required: false,
|
||||
description: '代理-可选',
|
||||
placeholder: '例如:http://127.0.0.1:1080',
|
||||
type: 'string'
|
||||
type: 'string',
|
||||
tooltip: '大陆地区请使用代理,否则无法正常使用'
|
||||
}
|
||||
},
|
||||
explain: '大陆地区请使用代理,API调用存在限制,请注意使用频率',
|
||||
options: ['alias', 'imgurUserName', 'accessToken', 'proxy'],
|
||||
refLink: 'https://pichoro.horosama.com/#/PicHoroDocs/configure?id=imgur%e5%9b%be%e5%ba%8a-1',
|
||||
referenceText: '配置教程请参考:'
|
||||
},
|
||||
s3plist: {
|
||||
name: 'S3兼容云',
|
||||
icon: 's3plist',
|
||||
configOptions: {
|
||||
alias: {
|
||||
required: true,
|
||||
description: '配置别名-必需',
|
||||
placeholder: '该配置的唯一标识',
|
||||
type: 'string',
|
||||
rule: aliasRule,
|
||||
default: 's3plist-A',
|
||||
tooltip: aliasTooltip
|
||||
},
|
||||
accessKeyId: {
|
||||
required: true,
|
||||
description: 'accessKeyId-必需',
|
||||
placeholder: '请输入accessKeyId',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('accessKeyId')
|
||||
},
|
||||
secretAccessKey: {
|
||||
required: true,
|
||||
description: 'secretAccessKey-必需',
|
||||
placeholder: '请输入secretAccessKey',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('secretAccessKey')
|
||||
},
|
||||
endpoint: {
|
||||
required: false,
|
||||
description: 'endpoint-可选',
|
||||
placeholder: '例如:s3.us-east-1.amazonaws.com',
|
||||
type: 'string',
|
||||
tooltip: '如果不填写,默认访问 AWS S3,请提供根API endpoint'
|
||||
},
|
||||
sslEnabled: {
|
||||
required: true,
|
||||
description: '使用HTTPS连接',
|
||||
default: true,
|
||||
type: 'boolean',
|
||||
tooltip: '大部分平台都支持HTTPS连接,如果您的平台不支持,请关闭该选项'
|
||||
},
|
||||
s3ForcePathStyle: {
|
||||
required: true,
|
||||
description: '启用 S3 Path style',
|
||||
default: false,
|
||||
type: 'boolean',
|
||||
tooltip: '例如使用 minio 时需要启用'
|
||||
},
|
||||
proxy: {
|
||||
required: false,
|
||||
description: '代理-可选',
|
||||
placeholder: '例如:http://127.0.0.1:1080',
|
||||
type: 'string',
|
||||
tooltip: '如果部分平台大陆地区无法访问,请使用代理'
|
||||
},
|
||||
aclForUpload: {
|
||||
required: true,
|
||||
description: '上传文件的权限',
|
||||
rule: defaultBaseRule('aclForUpload'),
|
||||
default: 'public-read',
|
||||
type: 'select',
|
||||
selectOptions: {
|
||||
private: '私有',
|
||||
'public-read': '公共读',
|
||||
'public-read-write': '公共读写',
|
||||
'authenticated-read': '授权读',
|
||||
'bucket-owner-read': '桶所有者读',
|
||||
'bucket-owner-full-control': '桶所有者完全控制',
|
||||
'aws-exec-read': 'aws执行读'
|
||||
},
|
||||
tooltip: '上传文件的权限,可选值:private、public-read、public-read-write、authenticated-read、bucket-owner-read、bucket-owner-full-control、aws-exec-read'
|
||||
},
|
||||
bucketName: {
|
||||
required: false,
|
||||
description: '存储桶名-可选',
|
||||
placeholder: '英文逗号分隔,例如:bucket1,bucket2',
|
||||
type: 'string',
|
||||
tooltip: bucketNameTooltip
|
||||
},
|
||||
baseDir: {
|
||||
required: false,
|
||||
description: '起始目录-可选',
|
||||
placeholder: '英文逗号分隔,例如:/test1,/test2',
|
||||
type: 'string',
|
||||
default: '/',
|
||||
tooltip: baseDirTooltip
|
||||
},
|
||||
paging: {
|
||||
required: true,
|
||||
description: '是否分页',
|
||||
default: true,
|
||||
type: 'boolean',
|
||||
tooltip: pagingTooltip
|
||||
},
|
||||
itemsPerPage: {
|
||||
required: true,
|
||||
description: '每页显示数量',
|
||||
default: 50,
|
||||
type: 'number',
|
||||
rule: itemsPerPageRule,
|
||||
tooltip: itemsPerPageTooltip
|
||||
}
|
||||
},
|
||||
explain: '存储桶名和起始目录配置时可通过英文逗号分隔不同存储桶的设置,顺序必须一致,逗号间留空或缺失项使用默认值',
|
||||
options: ['alias', 'accessKeyId', 'secretAccessKey', 'endpoint', 'sslEnabled', 's3ForcePathStyle', 'proxy', 'aclForUpload', 'bucketName', 'baseDir', 'paging', 'itemsPerPage'],
|
||||
refLink: 'https://github.com/wayjam/picgo-plugin-s3',
|
||||
referenceText: '配置教程请参考:'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,7 +446,6 @@ function remove (item: ImgInfo) {
|
||||
}, 0)
|
||||
}
|
||||
}
|
||||
console.log(file)
|
||||
sendToMain('removeFiles', [file])
|
||||
const obj = {
|
||||
title: $T('OPERATION_SUCCEED'),
|
||||
|
||||
Reference in New Issue
Block a user