mirror of
https://github.com/Kuingsmile/PicList.git
synced 2026-05-31 09:59:43 +08:00
✨ Feature: add remote file delete , picBed management
First version of PicList. In album, you can delete remote file now. Add picBed management function.
This commit is contained in:
146
src/renderer/manage/utils/common.ts
Normal file
146
src/renderer/manage/utils/common.ts
Normal file
@@ -0,0 +1,146 @@
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import path from 'path'
|
||||
import crypto from 'crypto'
|
||||
import { availableIconList } from './icon'
|
||||
|
||||
export function randomStringGenerator (length: number): string {
|
||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
||||
return Array.from({ length }).map(() => chars.charAt(Math.floor(Math.random() * chars.length))).join('')
|
||||
}
|
||||
|
||||
export function renameFileNameWithTimestamp (oldName: string): string {
|
||||
return `${Math.floor(Date.now() / 1000)}${randomStringGenerator(5)}${path.extname(oldName)}`
|
||||
}
|
||||
|
||||
export function renameFileNameWithRandomString (oldName: string, length: number = 5): string {
|
||||
return `${randomStringGenerator(length)}${path.extname(oldName)}`
|
||||
}
|
||||
|
||||
export function renameFileNameWithCustomString (oldName: string, customFormat: string): string {
|
||||
const conversionMap : {[key: string]: () => string} = {
|
||||
'{Y}': () => new Date().getFullYear().toString(),
|
||||
'{y}': () => new Date().getFullYear().toString().slice(2),
|
||||
'{m}': () => (new Date().getMonth() + 1).toString().length === 1 ? `0${new Date().getMonth() + 1}` : (new Date().getMonth() + 1).toString(),
|
||||
'{d}': () => new Date().getDate().toString().length === 1 ? `0${new Date().getDate()}` : new Date().getDate().toString(),
|
||||
'{md5}': () => crypto.createHash('md5').update(path.basename(oldName, path.extname(oldName))).digest('hex'),
|
||||
'{md5-16}': () => crypto.createHash('md5').update(path.basename(oldName, path.extname(oldName))).digest('hex').slice(0, 16),
|
||||
'{str-10}': () => randomStringGenerator(10),
|
||||
'{str-20}': () => randomStringGenerator(20),
|
||||
'{filename}': () => path.basename(oldName, path.extname(oldName)),
|
||||
'{uuid}': () => uuidv4().replace(/-/g, ''),
|
||||
'{timestamp}': () => Math.floor(Date.now() / 1000).toString()
|
||||
}
|
||||
if (customFormat === undefined || !Object.keys(conversionMap).some(item => customFormat.includes(item))) {
|
||||
return oldName
|
||||
}
|
||||
const ext = path.extname(oldName)
|
||||
return Object.keys(conversionMap).reduce((acc, cur) => {
|
||||
return acc.replace(cur, conversionMap[cur]())
|
||||
}, customFormat) + ext
|
||||
}
|
||||
|
||||
export function renameFile (typeMap : IStringKeyMap, oldName: string): string {
|
||||
if (typeMap.timestampRename) {
|
||||
return renameFileNameWithTimestamp(oldName)
|
||||
} else if (typeMap.randomStringRename) {
|
||||
return renameFileNameWithRandomString(oldName, 20)
|
||||
} else {
|
||||
return renameFileNameWithCustomString(oldName, typeMap.customRenameFormat)
|
||||
}
|
||||
}
|
||||
|
||||
export function formatLink (url: string, fileName: string, type: string, format?: string) : string {
|
||||
switch (type) {
|
||||
case 'markdown':
|
||||
return ``
|
||||
case 'html':
|
||||
return `<img src="${url}" alt="${fileName}"/>`
|
||||
case 'bbcode':
|
||||
return `[img]${url}[/img]`
|
||||
case 'url':
|
||||
return url
|
||||
case 'markdown-with-link':
|
||||
return `[](${url})`
|
||||
case 'custom':
|
||||
if (format && (format.includes('$url') || format.includes('$fileName'))) {
|
||||
return format.replace(/\$url/g, url).replace(/\$fileName/g, fileName)
|
||||
}
|
||||
return url
|
||||
default:
|
||||
return url
|
||||
}
|
||||
}
|
||||
|
||||
export function getFileIconPath (fileName: string) {
|
||||
const ext = path.extname(fileName).slice(1)
|
||||
return availableIconList.includes(ext) ? `${ext}.png` : 'unknown.png'
|
||||
}
|
||||
|
||||
export function formatFileSize (size: number) {
|
||||
if (size === 0) return ''
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
|
||||
const index = Math.floor(Math.log2(size) / 10)
|
||||
return `${(size / Math.pow(2, index * 10)).toFixed(2)} ${units[index]}`
|
||||
}
|
||||
|
||||
export function formatFileName (fileName: string) {
|
||||
const ext = path.extname(fileName)
|
||||
const name = path.basename(fileName, ext)
|
||||
return name.length > 20 ? `${name.slice(0, 20)}...${ext}` : fileName
|
||||
}
|
||||
|
||||
export function getExtension (fileName: string) {
|
||||
return path.extname(fileName).slice(1)
|
||||
}
|
||||
|
||||
export function isImage (fileName: string) {
|
||||
return ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'ico'].includes(getExtension(fileName))
|
||||
}
|
||||
|
||||
export function formObjToTableData (obj: any) {
|
||||
const exclude = [undefined, null, '', 'transformedConfig']
|
||||
return Object.keys(obj).filter(key => !exclude.includes(obj[key])).map(key => ({
|
||||
key,
|
||||
value: typeof obj[key] === 'object' ? JSON.stringify(obj[key]) : obj[key]
|
||||
})).sort((a, b) => a.key.localeCompare(b.key))
|
||||
}
|
||||
|
||||
export function isValidUrl (str: string) {
|
||||
const pattern = new RegExp(
|
||||
'^([a-zA-Z]+:\\/\\/)?' +
|
||||
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' +
|
||||
'((\\d{1,3}\\.){3}\\d{1,3}))' +
|
||||
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' +
|
||||
'(\\?[;&a-z\\d%_.~+=-]*)?' +
|
||||
'(\\#[-a-z\\d_]*)?$',
|
||||
'i'
|
||||
)
|
||||
return pattern.test(str)
|
||||
}
|
||||
|
||||
export interface IHTTPProxy {
|
||||
host: string
|
||||
port: number
|
||||
protocol: string
|
||||
}
|
||||
|
||||
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://')) {
|
||||
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)
|
||||
}
|
||||
} else {
|
||||
const [host, port] = proxy.split(':')
|
||||
if (type === 'string') return `http://${host}:${port}`
|
||||
return {
|
||||
host,
|
||||
port: port ? Number(port) : 80,
|
||||
protocol: 'http'
|
||||
}
|
||||
}
|
||||
}
|
||||
501
src/renderer/manage/utils/constants.ts
Normal file
501
src/renderer/manage/utils/constants.ts
Normal file
@@ -0,0 +1,501 @@
|
||||
|
||||
const defaultBaseRule = (name: string) => {
|
||||
return [
|
||||
{
|
||||
required: true,
|
||||
message: `请输入${name}`,
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const itemsPerPageRule = [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入每页显示数量',
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
message: '每页显示数量必须为数字',
|
||||
trigger: 'change'
|
||||
},
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (value < 20 || value > 1000) {
|
||||
callback(new Error('每页显示数量必须在20-1000之间'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
|
||||
const aliasRule = [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入配置别名, 该配置的唯一标识',
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
const reg = /^[\u4e00-\u9fa5_a-zA-Z0-9-]{1,15}$/
|
||||
if (!reg.test(value)) {
|
||||
callback(new Error('配置别名只能包含中文、英文、数字和下划线,且不能超过15个字符'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
|
||||
export const supportedPicBedList: IStringKeyMap = {
|
||||
smms: {
|
||||
name: 'SM.MS',
|
||||
icon: 'smms',
|
||||
configOptions: {
|
||||
alias: {
|
||||
required: true,
|
||||
description: '配置别名-必需',
|
||||
placeholder: '该配置的唯一标识',
|
||||
type: 'string',
|
||||
rule: aliasRule,
|
||||
default: 'smms-A'
|
||||
},
|
||||
token: {
|
||||
required: true,
|
||||
description: 'token-必需',
|
||||
placeholder: '请输入token',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('token')
|
||||
},
|
||||
paging: {
|
||||
required: true,
|
||||
description: '是否分页',
|
||||
default: true,
|
||||
type: 'boolean'
|
||||
}
|
||||
},
|
||||
explain: '大陆地区请访问备用域名https://smms.app, 请勿大批量上传图片,否则API接口会被限制',
|
||||
options: ['alias', 'token', 'paging'],
|
||||
refLink: 'https://pichoro.horosama.com/#/PicHoroDocs/configure?id=%e5%8f%82%e6%95%b0%e8%af%b4%e6%98%8e-6',
|
||||
referenceText: '配置教程请参考:'
|
||||
},
|
||||
qiniu: {
|
||||
name: '七牛云',
|
||||
icon: 'qiniu',
|
||||
configOptions: {
|
||||
alias: {
|
||||
required: true,
|
||||
description: '配置别名-必需',
|
||||
placeholder: '该配置的唯一标识',
|
||||
type: 'string',
|
||||
rule: aliasRule,
|
||||
default: 'qiniu-A'
|
||||
},
|
||||
accessKey: {
|
||||
required: true,
|
||||
description: 'accessKey-必需',
|
||||
placeholder: '请输入accessKey',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('accessKey')
|
||||
},
|
||||
secretKey: {
|
||||
required: true,
|
||||
description: 'secretKey-必需',
|
||||
placeholder: '请输入secretKey',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('secretKey')
|
||||
},
|
||||
bucketName: {
|
||||
required: false,
|
||||
description: '空间名-可选',
|
||||
placeholder: '英文逗号分隔,例如:bucket1,bucket2',
|
||||
type: 'string'
|
||||
},
|
||||
baseDir: {
|
||||
required: false,
|
||||
description: '起始目录-可选',
|
||||
placeholder: '英文逗号分隔,例如:/test1,/test2',
|
||||
default: '/',
|
||||
type: 'string'
|
||||
},
|
||||
paging: {
|
||||
required: true,
|
||||
description: '是否分页',
|
||||
default: true,
|
||||
type: 'boolean'
|
||||
},
|
||||
itemsPerPage: {
|
||||
required: true,
|
||||
description: '每页显示数量',
|
||||
default: 50,
|
||||
type: 'number',
|
||||
rule: itemsPerPageRule
|
||||
}
|
||||
},
|
||||
explain: '空间名和起始目录配置时可通过英文逗号分隔不同存储桶的设置,顺序必须一致,逗号间留空或缺失项使用默认值',
|
||||
options: ['alias', 'accessKey', 'secretKey', 'bucketName', 'baseDir', 'paging', 'itemsPerPage'],
|
||||
refLink: 'https://pichoro.horosama.com/#/PicHoroDocs/configure?id=%e5%8f%82%e6%95%b0%e8%af%b4%e6%98%8e-3',
|
||||
referenceText: '配置教程请参考:'
|
||||
},
|
||||
github: {
|
||||
name: 'GitHub',
|
||||
icon: 'github',
|
||||
configOptions: {
|
||||
alias: {
|
||||
required: true,
|
||||
description: '配置别名-必需',
|
||||
placeholder: '该配置的唯一标识',
|
||||
type: 'string',
|
||||
rule: aliasRule,
|
||||
default: 'github-A'
|
||||
},
|
||||
token: {
|
||||
required: true,
|
||||
description: 'token-必需',
|
||||
placeholder: '请输入token',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('token')
|
||||
},
|
||||
githubUsername: {
|
||||
required: true,
|
||||
description: '用户名-必需',
|
||||
placeholder: '请输入用户名',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('用户名')
|
||||
},
|
||||
proxy: {
|
||||
required: false,
|
||||
description: '代理-可选',
|
||||
placeholder: '例如:http://127.0.0.1:1080',
|
||||
type: 'string'
|
||||
},
|
||||
paging: {
|
||||
required: true,
|
||||
description: '是否分页',
|
||||
default: false,
|
||||
type: 'boolean'
|
||||
},
|
||||
customUrl: {
|
||||
required: false,
|
||||
description: 'CDN加速域名-可选;例如: https://cdn.staticaly.com/gh/{username}/{repo}@{branch}/{path}',
|
||||
placeholder: '支持使用{username}、{repo}、{branch}和{path}作为替换占位符,用于适配不同仓库和分支',
|
||||
type: 'string',
|
||||
rule: [
|
||||
{
|
||||
validator: (_rule: any, value: any, callback: any) => {
|
||||
if (value) {
|
||||
const customUrlList = value.split(',')
|
||||
const customUrlValid = customUrlList.every((customUrl: string) => {
|
||||
const reg = /^((https|http)?:\/\/)/
|
||||
if (customUrl === '') {
|
||||
return true
|
||||
} else if (!reg.test(customUrl)) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
const isBracketsValid = customUrlList.every((customUrl: string) => {
|
||||
const bracketPaired = (str: string) => {
|
||||
const stack = []
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
if (str[i] === '{') {
|
||||
stack.push(str[i])
|
||||
} else if (str[i] === '}') {
|
||||
if (stack.length === 0) {
|
||||
return false
|
||||
}
|
||||
stack.pop()
|
||||
}
|
||||
}
|
||||
return stack.length === 0
|
||||
}
|
||||
if (customUrl === '') {
|
||||
return true
|
||||
} else if (!bracketPaired(customUrl)) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
if (!customUrlValid) {
|
||||
callback(new Error('加速域名请以http://或https://开头'))
|
||||
} else if (!isBracketsValid) {
|
||||
callback(new Error('加速域名中的大括号必须成对出现'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
explain: 'API调用有每小时上限,此外不支持上传超过100M的文件',
|
||||
options: ['alias', 'token', 'githubUsername', 'proxy', 'customUrl'],
|
||||
refLink: 'https://pichoro.horosama.com/#/PicHoroDocs/configure?id=%e5%8f%82%e6%95%b0%e8%af%b4%e6%98%8e-9',
|
||||
referenceText: '配置教程请参考:'
|
||||
},
|
||||
aliyun: {
|
||||
name: '阿里云',
|
||||
icon: 'aliyun',
|
||||
configOptions: {
|
||||
alias: {
|
||||
required: true,
|
||||
description: '配置别名-必需',
|
||||
placeholder: '该配置的唯一标识',
|
||||
type: 'string',
|
||||
rule: aliasRule,
|
||||
default: 'aliyun-A'
|
||||
},
|
||||
accessKeyId: {
|
||||
required: true,
|
||||
description: 'accessKeyId-必需',
|
||||
placeholder: '请输入accessKeyId',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('accessKeyId')
|
||||
},
|
||||
accessKeySecret: {
|
||||
required: true,
|
||||
description: 'accessKeySecret-必需',
|
||||
placeholder: '请输入accessKeySecret',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('accessKeySecret')
|
||||
},
|
||||
bucketName: {
|
||||
required: false,
|
||||
description: '存储桶名-可选',
|
||||
placeholder: '英文逗号分隔,例如:bucket1,bucket2',
|
||||
type: 'string'
|
||||
},
|
||||
baseDir: {
|
||||
required: false,
|
||||
description: '起始目录-可选',
|
||||
placeholder: '英文逗号分隔,例如:/test1,/test2',
|
||||
type: 'string',
|
||||
default: '/'
|
||||
},
|
||||
paging: {
|
||||
required: true,
|
||||
description: '是否分页',
|
||||
default: true,
|
||||
type: 'boolean'
|
||||
},
|
||||
itemsPerPage: {
|
||||
required: true,
|
||||
description: '每页显示数量',
|
||||
default: 50,
|
||||
type: 'number',
|
||||
rule: itemsPerPageRule
|
||||
}
|
||||
},
|
||||
explain: '存储桶名和起始目录配置时可通过英文逗号分隔不同存储桶的设置,顺序必须一致,逗号间留空或缺失项使用默认值',
|
||||
options: ['alias', 'accessKeyId', 'accessKeySecret', 'bucketName', 'baseDir', 'paging', 'itemsPerPage'],
|
||||
refLink: 'https://pichoro.horosama.com/#/PicHoroDocs/configure?id=%e5%8f%82%e6%95%b0%e8%af%b4%e6%98%8e-1',
|
||||
referenceText: '配置教程请参考:'
|
||||
},
|
||||
tcyun: {
|
||||
name: '腾讯云',
|
||||
icon: 'tcyun',
|
||||
configOptions: {
|
||||
alias: {
|
||||
required: true,
|
||||
description: '配置别名-必需',
|
||||
placeholder: '该配置的唯一标识',
|
||||
type: 'string',
|
||||
rule: aliasRule,
|
||||
default: 'tcyun-A'
|
||||
},
|
||||
secretId: {
|
||||
required: true,
|
||||
description: 'secretId-必需',
|
||||
placeholder: '请输入secretId',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('secretId')
|
||||
},
|
||||
secretKey: {
|
||||
required: true,
|
||||
description: 'secretKey-必需',
|
||||
placeholder: '请输入secretKey',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('secretKey')
|
||||
},
|
||||
appId: {
|
||||
required: true,
|
||||
description: 'appId-必需',
|
||||
placeholder: '请输入appId',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('appId')
|
||||
},
|
||||
bucketName: {
|
||||
required: false,
|
||||
description: '存储桶名-可选(注意包含AppId)',
|
||||
placeholder: '英文逗号分隔,例如:bucket1-1250000000,bucket2-1250000000',
|
||||
type: 'string'
|
||||
},
|
||||
baseDir: {
|
||||
required: false,
|
||||
description: '起始目录-可选',
|
||||
placeholder: '英文逗号分隔,例如:/test1,/test2',
|
||||
type: 'string',
|
||||
default: '/'
|
||||
},
|
||||
paging: {
|
||||
required: true,
|
||||
description: '是否分页',
|
||||
default: true,
|
||||
type: 'boolean'
|
||||
},
|
||||
itemsPerPage: {
|
||||
required: true,
|
||||
description: '每页显示数量',
|
||||
default: 50,
|
||||
type: 'number',
|
||||
rule: itemsPerPageRule
|
||||
}
|
||||
},
|
||||
explain: '存储桶名和起始目录配置时可通过英文逗号分隔不同存储桶的设置,顺序必须一致,逗号间留空或缺失项使用默认值',
|
||||
options: ['alias', 'secretId', 'secretKey', 'appId', 'bucketName', 'baseDir', 'paging', 'itemsPerPage'],
|
||||
refLink: 'https://pichoro.horosama.com/#/PicHoroDocs/configure?id=%e5%8f%82%e6%95%b0%e8%af%b4%e6%98%8e-2',
|
||||
referenceText: '配置教程请参考:'
|
||||
},
|
||||
upyun: {
|
||||
name: '又拍云',
|
||||
icon: 'upyun',
|
||||
configOptions: {
|
||||
alias: {
|
||||
required: true,
|
||||
description: '配置别名-必需',
|
||||
placeholder: '该配置的唯一标识',
|
||||
type: 'string',
|
||||
rule: aliasRule,
|
||||
default: 'upyun-A'
|
||||
},
|
||||
bucketName: {
|
||||
required: true,
|
||||
description: '服务名-必需',
|
||||
placeholder: '对应其它对象存储的存储桶名',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('bucketName')
|
||||
},
|
||||
operator: {
|
||||
required: true,
|
||||
description: '操作员-必需',
|
||||
placeholder: '推荐使用具有读取、写入和删除完整权限的操作员',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('操作员')
|
||||
},
|
||||
password: {
|
||||
required: true,
|
||||
description: '操作员密码-必需',
|
||||
placeholder: '请输入密码',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('操作员密码')
|
||||
},
|
||||
baseDir: {
|
||||
required: false,
|
||||
description: '起始目录-可选',
|
||||
placeholder: '读取文件时的初始目录',
|
||||
type: 'string',
|
||||
default: '/'
|
||||
},
|
||||
customUrl: {
|
||||
required: true,
|
||||
description: '加速域名-必需',
|
||||
placeholder: '请以http://或https://开头',
|
||||
type: 'string',
|
||||
rule: [
|
||||
{
|
||||
required: true,
|
||||
message: '加速域名不能为空',
|
||||
trigger: 'change'
|
||||
},
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (value) {
|
||||
const customUrlList = value.split(',')
|
||||
const customUrlValid = customUrlList.every((customUrl: string) => {
|
||||
const reg = /^((https|http)?:\/\/)/
|
||||
if (customUrl === '') {
|
||||
return true
|
||||
} else if (!reg.test(customUrl)) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
if (!customUrlValid) {
|
||||
callback(new Error('自定义域名请以http://或https://开头'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
},
|
||||
paging: {
|
||||
required: true,
|
||||
description: '是否分页',
|
||||
default: true,
|
||||
type: 'boolean'
|
||||
},
|
||||
itemsPerPage: {
|
||||
required: true,
|
||||
description: '每页显示数量',
|
||||
default: 50,
|
||||
type: 'number',
|
||||
rule: itemsPerPageRule
|
||||
}
|
||||
},
|
||||
explain: '又拍云图床务必填写加速域名,否则无法正常使用',
|
||||
options: ['alias', 'bucketName', 'operator', 'password', 'baseDir', 'customUrl', 'paging', 'itemsPerPage'],
|
||||
refLink: 'https://pichoro.horosama.com/#/PicHoroDocs/configure?id=%e5%8f%82%e6%95%b0%e8%af%b4%e6%98%8e-4',
|
||||
referenceText: '配置教程请参考:'
|
||||
},
|
||||
imgur: {
|
||||
name: 'Imgur',
|
||||
icon: 'imgur',
|
||||
configOptions: {
|
||||
alias: {
|
||||
required: true,
|
||||
description: '配置别名-必需',
|
||||
placeholder: '该配置的唯一标识',
|
||||
type: 'string',
|
||||
rule: aliasRule,
|
||||
default: 'imgur-A'
|
||||
},
|
||||
imgurUserName: {
|
||||
required: true,
|
||||
description: 'imgur用户名-必需',
|
||||
placeholder: '请输入imgur用户名',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('imgurUserName')
|
||||
},
|
||||
accessToken: {
|
||||
required: true,
|
||||
description: 'accessToken-必需(不是clientID,请参考配置教程)',
|
||||
placeholder: '请输入accessToken',
|
||||
type: 'string',
|
||||
rule: defaultBaseRule('accessToken')
|
||||
},
|
||||
proxy: {
|
||||
required: false,
|
||||
description: '代理-可选',
|
||||
placeholder: '例如:http://127.0.0.1:1080',
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
explain: '大陆地区请使用代理,API调用存在限制,请注意使用频率',
|
||||
options: ['alias', 'imgurUserName', 'accessToken', 'proxy'],
|
||||
refLink: 'https://pichoro.horosama.com/#/PicHoroDocs/configure?id=imgur%e5%9b%be%e5%ba%8a-1',
|
||||
referenceText: '配置教程请参考:'
|
||||
}
|
||||
}
|
||||
44
src/renderer/manage/utils/dataSender.ts
Normal file
44
src/renderer/manage/utils/dataSender.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { ipcRenderer, IpcRendererEvent } from 'electron'
|
||||
import { PICLIST_MANAGE_GET_CONFIG, PICLIST_MANAGE_SAVE_CONFIG, PICLIST_MANAGE_REMOVE_CONFIG } from '~/main/manage/events/constants'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
import { getRawData } from '~/renderer/utils/common'
|
||||
|
||||
export function getConfig<T> (key?: string): Promise<T | undefined> {
|
||||
return new Promise((resolve) => {
|
||||
const callbackId = uuid()
|
||||
const callback = (event: IpcRendererEvent, config: T | undefined, returnCallbackId: string) => {
|
||||
if (returnCallbackId === callbackId) {
|
||||
resolve(config)
|
||||
ipcRenderer.removeListener(PICLIST_MANAGE_GET_CONFIG, callback)
|
||||
}
|
||||
}
|
||||
ipcRenderer.on(PICLIST_MANAGE_GET_CONFIG, callback)
|
||||
ipcRenderer.send(PICLIST_MANAGE_GET_CONFIG, key, callbackId)
|
||||
})
|
||||
}
|
||||
|
||||
export function saveConfig (_config: IObj | string, value?: any) {
|
||||
let config
|
||||
if (typeof _config === 'string') {
|
||||
config = {
|
||||
[_config]: value
|
||||
}
|
||||
} else {
|
||||
config = getRawData(_config)
|
||||
}
|
||||
ipcRenderer.send(PICLIST_MANAGE_SAVE_CONFIG, config)
|
||||
}
|
||||
|
||||
export function removeConfig (key: string, propName: string) {
|
||||
ipcRenderer.send(PICLIST_MANAGE_REMOVE_CONFIG, key, propName)
|
||||
}
|
||||
|
||||
export function sendToMain (channel: string, ...args: any[]) {
|
||||
const data = getRawData(args)
|
||||
ipcRenderer.send(channel, ...data)
|
||||
}
|
||||
|
||||
export function invokeToMain (channel: string, ...args: any[]) {
|
||||
const data = getRawData(args)
|
||||
return ipcRenderer.invoke(channel, ...data)
|
||||
}
|
||||
224
src/renderer/manage/utils/icon.ts
Normal file
224
src/renderer/manage/utils/icon.ts
Normal file
@@ -0,0 +1,224 @@
|
||||
export const availableIconList = [
|
||||
'_blank',
|
||||
'_page',
|
||||
'3g2',
|
||||
'3gp',
|
||||
'7z',
|
||||
'aac',
|
||||
'accdb',
|
||||
'adt',
|
||||
'ai',
|
||||
'aiff',
|
||||
'aly',
|
||||
'amiga',
|
||||
'amr',
|
||||
'ape',
|
||||
'apk',
|
||||
'arj',
|
||||
'asf',
|
||||
'asm',
|
||||
'asx',
|
||||
'au',
|
||||
'avc',
|
||||
'avi',
|
||||
'avs',
|
||||
'bak',
|
||||
'bas',
|
||||
'bat',
|
||||
'bmp',
|
||||
'bom',
|
||||
'c',
|
||||
'cda',
|
||||
'cdr',
|
||||
'chm',
|
||||
'class',
|
||||
'cmd',
|
||||
'com',
|
||||
'cpp',
|
||||
'css',
|
||||
'csv',
|
||||
'dart',
|
||||
'dat',
|
||||
'ddb',
|
||||
'dif',
|
||||
'divx',
|
||||
'dll',
|
||||
'dmg',
|
||||
'doc',
|
||||
'docm',
|
||||
'docx',
|
||||
'dot',
|
||||
'dotm',
|
||||
'dotx',
|
||||
'dsl',
|
||||
'dv',
|
||||
'dvd',
|
||||
'dvdaudio',
|
||||
'dwg',
|
||||
'dxf',
|
||||
'emf',
|
||||
'env',
|
||||
'eot',
|
||||
'eps',
|
||||
'exe',
|
||||
'exif',
|
||||
'fakesmms',
|
||||
'flc',
|
||||
'fli',
|
||||
'flv',
|
||||
'folder',
|
||||
'fon',
|
||||
'font',
|
||||
'for',
|
||||
'fpx',
|
||||
'fv',
|
||||
'gif',
|
||||
'gitingore',
|
||||
'gitkeep',
|
||||
'gz',
|
||||
'h',
|
||||
'hdri',
|
||||
'hlp',
|
||||
'hpp',
|
||||
'htm',
|
||||
'html',
|
||||
'ico',
|
||||
'ics',
|
||||
'int',
|
||||
'ipynb',
|
||||
'iso',
|
||||
'java',
|
||||
'jpeg',
|
||||
'jpg',
|
||||
'js',
|
||||
'json',
|
||||
'key',
|
||||
'ksp',
|
||||
'less',
|
||||
'lib',
|
||||
'lic',
|
||||
'license',
|
||||
'log',
|
||||
'lst',
|
||||
'lua',
|
||||
'mac',
|
||||
'map',
|
||||
'markdown',
|
||||
'md',
|
||||
'mdf',
|
||||
'mht',
|
||||
'mhtml',
|
||||
'mid',
|
||||
'midi',
|
||||
'mkv',
|
||||
'mmf',
|
||||
'mod',
|
||||
'mov',
|
||||
'mp2',
|
||||
'mp3',
|
||||
'mp4',
|
||||
'mpa',
|
||||
'mpe',
|
||||
'mpeg',
|
||||
'mpeg1',
|
||||
'mpeg2',
|
||||
'mpg',
|
||||
'mppro',
|
||||
'msg',
|
||||
'mts',
|
||||
'mux',
|
||||
'mv',
|
||||
'navi',
|
||||
'obj',
|
||||
'odf',
|
||||
'ods',
|
||||
'odt',
|
||||
'ogg',
|
||||
'one',
|
||||
'otf',
|
||||
'otp',
|
||||
'ots',
|
||||
'ott',
|
||||
'pas',
|
||||
'pcd',
|
||||
'pcx',
|
||||
'pdf',
|
||||
'php',
|
||||
'pic',
|
||||
'png',
|
||||
'ppt',
|
||||
'pptx',
|
||||
'proe',
|
||||
'prt',
|
||||
'psd',
|
||||
'py',
|
||||
'pyc',
|
||||
'qsv',
|
||||
'qt',
|
||||
'quicktime',
|
||||
'ra',
|
||||
'ram',
|
||||
'rar',
|
||||
'raw',
|
||||
'rb',
|
||||
'realaudio',
|
||||
'rm',
|
||||
'rmvb',
|
||||
'rp',
|
||||
'rtf',
|
||||
's48',
|
||||
'sacd',
|
||||
'sass',
|
||||
'sch',
|
||||
'scss',
|
||||
'sh',
|
||||
'sql',
|
||||
'stp',
|
||||
'svcd',
|
||||
'svg',
|
||||
'swf',
|
||||
'sys',
|
||||
'tga',
|
||||
'tgz',
|
||||
'tiff',
|
||||
'tmp',
|
||||
'ts',
|
||||
'ttc',
|
||||
'ttf',
|
||||
'txt',
|
||||
'ufo',
|
||||
'unknown',
|
||||
'vcd',
|
||||
'vob',
|
||||
'voc',
|
||||
'vqf',
|
||||
'vue',
|
||||
'wav',
|
||||
'wdl',
|
||||
'webm',
|
||||
'webp',
|
||||
'wki',
|
||||
'wma',
|
||||
'wmf',
|
||||
'wmv',
|
||||
'wmvhd',
|
||||
'woff',
|
||||
'woff2',
|
||||
'wps',
|
||||
'wpt',
|
||||
'x_t',
|
||||
'xls',
|
||||
'xlsm',
|
||||
'xlsx',
|
||||
'xlt',
|
||||
'xltm',
|
||||
'xltx',
|
||||
'xmind',
|
||||
'xml',
|
||||
'xv',
|
||||
'xvid',
|
||||
'yaml',
|
||||
'yml',
|
||||
'z',
|
||||
'zip'
|
||||
]
|
||||
227
src/renderer/manage/utils/newBucketConfig.ts
Normal file
227
src/renderer/manage/utils/newBucketConfig.ts
Normal file
@@ -0,0 +1,227 @@
|
||||
import { AliyunAreaCodeName, QiniuAreaCodeName, TencentAreaCodeName } from '~/main/manage/utils/constants'
|
||||
|
||||
export const newBucketConfig:IStringKeyMap = {
|
||||
tcyun: {
|
||||
name: '腾讯云',
|
||||
icon: 'tcyun',
|
||||
configOptions: {
|
||||
BucketName: {
|
||||
required: true,
|
||||
description: 'Bucket名称',
|
||||
placeholder: '请输入Bucket名称',
|
||||
paraType: 'string',
|
||||
component: 'input',
|
||||
default: 'piclist',
|
||||
rule: [
|
||||
{
|
||||
required: true,
|
||||
message: 'Bucket名称不能为空',
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
const reg = /^[a-z0-9][a-z0-9-]{1,21}[a-z0-9]$/
|
||||
if (value.length > 23) {
|
||||
callback(new Error('Bucket名称长度不能超过23个字符'))
|
||||
} else if (!reg.test(value)) {
|
||||
callback(new Error('Bucket名称只能包含小写字母、数字和中划线,且不能以中划线开头和结尾'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
},
|
||||
region: {
|
||||
required: true,
|
||||
description: '地域',
|
||||
paraType: 'string',
|
||||
component: 'select',
|
||||
default: 'ap-nanjing',
|
||||
options: TencentAreaCodeName
|
||||
},
|
||||
acl: {
|
||||
required: true,
|
||||
description: '访问权限',
|
||||
paraType: 'string',
|
||||
component: 'select',
|
||||
default: 'private',
|
||||
options: {
|
||||
private: '私有',
|
||||
publicRead: '公共读',
|
||||
publicReadWrite: '公共读写'
|
||||
}
|
||||
}
|
||||
},
|
||||
options: ['BucketName', 'region', 'acl']
|
||||
},
|
||||
aliyun: {
|
||||
name: '阿里云',
|
||||
icon: 'aliyun',
|
||||
configOptions: {
|
||||
BucketName: {
|
||||
required: true,
|
||||
description: 'Bucket名称',
|
||||
placeholder: '请输入Bucket名称',
|
||||
paraType: 'string',
|
||||
component: 'input',
|
||||
default: 'piclist',
|
||||
rule: [
|
||||
{
|
||||
required: true,
|
||||
message: 'Bucket名称不能为空',
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
const reg = /^[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$/
|
||||
if (value.length > 63) {
|
||||
callback(new Error('Bucket名称长度不能超过63个字符'))
|
||||
} else if (!reg.test(value)) {
|
||||
callback(new Error('Bucket名称只能包含小写字母、数字和中划线,且不能以中划线开头和结尾'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
},
|
||||
region: {
|
||||
required: true,
|
||||
description: '地域',
|
||||
paraType: 'string',
|
||||
component: 'select',
|
||||
default: 'oss-cn-hangzhou',
|
||||
options: AliyunAreaCodeName
|
||||
},
|
||||
acl: {
|
||||
required: true,
|
||||
description: '访问权限',
|
||||
paraType: 'string',
|
||||
component: 'select',
|
||||
default: 'private',
|
||||
options: {
|
||||
private: '私有',
|
||||
publicRead: '公共读',
|
||||
publicReadWrite: '公共读写'
|
||||
}
|
||||
}
|
||||
},
|
||||
options: ['BucketName', 'region', 'acl']
|
||||
},
|
||||
qiniu: {
|
||||
name: '七牛云',
|
||||
icon: 'qiniu',
|
||||
configOptions: {
|
||||
BucketName: {
|
||||
required: true,
|
||||
description: 'Bucket名称',
|
||||
placeholder: '请输入Bucket名称',
|
||||
paraType: 'string',
|
||||
component: 'input',
|
||||
default: 'piclist',
|
||||
rule: [
|
||||
{
|
||||
required: true,
|
||||
message: 'Bucket名称不能为空',
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
const reg = /^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/
|
||||
if (value.length > 63) {
|
||||
callback(new Error('Bucket名称长度不能超过63个字符'))
|
||||
} else if (!reg.test(value)) {
|
||||
callback(new Error('Bucket名称只能包含小写字母、数字和中划线,且不能以中划线开头和结尾'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
},
|
||||
region: {
|
||||
required: true,
|
||||
description: '地域',
|
||||
paraType: 'string',
|
||||
component: 'select',
|
||||
default: 'z0',
|
||||
options: QiniuAreaCodeName
|
||||
},
|
||||
acl: {
|
||||
required: true,
|
||||
description: '公开访问',
|
||||
paraType: 'boolean',
|
||||
component: 'switch',
|
||||
default: false
|
||||
}
|
||||
},
|
||||
options: ['BucketName', 'region', 'acl']
|
||||
},
|
||||
upyun: {
|
||||
name: '又拍云',
|
||||
icon: 'upyun',
|
||||
configOptions: {
|
||||
BucketName: {
|
||||
required: true,
|
||||
description: 'Bucket名称',
|
||||
placeholder: '请输入Bucket名称',
|
||||
paraType: 'string',
|
||||
component: 'input',
|
||||
default: 'piclist',
|
||||
rule: [
|
||||
{
|
||||
required: true,
|
||||
message: 'Bucket名称不能为空',
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
const reg = /^[a-z][a-z0-9-]{4,19}$/
|
||||
if (value.length > 23 || value.length < 5) {
|
||||
callback(new Error('Bucket名称长度为5-20个字符'))
|
||||
} else if (!reg.test(value)) {
|
||||
callback(new Error('Bucket名称只能包含小写字母、数字和中划线,且不能以中划线开头和结尾'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
},
|
||||
operator: {
|
||||
required: true,
|
||||
description: '操作员',
|
||||
placeholder: '请输入操作员',
|
||||
paraType: 'string',
|
||||
component: 'input',
|
||||
rule: [
|
||||
{
|
||||
required: true,
|
||||
message: '操作员不能为空',
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
},
|
||||
password: {
|
||||
required: true,
|
||||
description: '密码',
|
||||
placeholder: '请输入密码',
|
||||
paraType: 'string',
|
||||
component: 'input',
|
||||
rule: [
|
||||
{
|
||||
required: true,
|
||||
message: '密码不能为空',
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
options: ['BucketName', 'operator', 'password']
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user