🚧 WIP: add local path picbed for manage page

This commit is contained in:
萌萌哒赫萝
2023-08-12 01:00:40 -07:00
parent f585bb4d7d
commit e56bd78096
14 changed files with 457 additions and 102 deletions

View File

@@ -154,42 +154,21 @@ export const deleteChoosedFiles = async (list: ImgInfo[]): Promise<boolean[]> =>
const file = await dbStore.removeById(item.id)
if (await picgo.getConfig('settings.deleteCloudFile')) {
if (item.type !== undefined && picBedsCanbeDeleted.includes(item.type)) {
const noteFunc = (value: boolean) => {
const notification = new Notification({
title: T('MANAGE_BUCKET_BATCH_DELETE_ERROR_MSG_MSG2'),
body: T(value ? 'GALLERY_SYNC_DELETE_NOTICE_SUCCEED' : 'GALLERY_SYNC_DELETE_NOTICE_FAILED')
})
notification.show()
}
if (item.type === 'webdavplist') {
const { fileName, config } = item
setTimeout(() => {
deleteWebdavFile(getRawData(config), fileName || '').then((value: boolean) => {
if (value) {
const notification = new Notification({
title: T('MANAGE_BUCKET_BATCH_DELETE_ERROR_MSG_MSG2'),
body: T('GALLERY_SYNC_DELETE_NOTICE_SUCCEED')
})
notification.show()
} else {
const notification = new Notification({
title: T('MANAGE_BUCKET_BATCH_DELETE_ERROR_MSG_MSG2'),
body: T('GALLERY_SYNC_DELETE_NOTICE_FAILED')
})
notification.show()
}
})
deleteWebdavFile(getRawData(config), fileName || '').then(noteFunc)
}, 0)
} else {
setTimeout(() => {
ALLApi.delete(item).then((value: boolean) => {
if (value) {
const notification = new Notification({
title: T('MANAGE_BUCKET_BATCH_DELETE_ERROR_MSG_MSG2'),
body: T('GALLERY_SYNC_DELETE_NOTICE_SUCCEED')
})
notification.show()
} else {
const notification = new Notification({
title: T('MANAGE_BUCKET_BATCH_DELETE_ERROR_MSG_MSG2'),
body: T('GALLERY_SYNC_DELETE_NOTICE_FAILED')
})
notification.show()
}
})
ALLApi.delete(item).then(noteFunc)
}, 0)
}
}

View File

@@ -1,6 +1,7 @@
import AliyunApi from './aliyun'
import GithubApi from './github'
import ImgurApi from './imgur'
import LocalApi from './local'
import QiniuApi from './qiniu'
import S3plistApi from './s3plist'
import SmmsApi from './smms'
@@ -12,6 +13,7 @@ export default {
AliyunApi,
GithubApi,
ImgurApi,
LocalApi,
QiniuApi,
S3plistApi,
SmmsApi,

View File

@@ -0,0 +1,319 @@
// 日志记录器
import ManageLogger from '../utils/logger'
// 错误格式化函数、端点地址格式化函数、获取内部代理、新的下载器、并发异步任务池
import { formatError } from '../utils/common'
// HTTP 代理格式化函数、是否为图片的判断函数
import { isImage } from '@/manage/utils/common'
// 窗口管理器
import windowManager from 'apis/app/window/windowManager'
// 枚举类型声明
import { IWindowList } from '#/types/enum'
// Electron 相关
import { ipcMain, IpcMainEvent } from 'electron'
// 上传下载任务队列
import UpDownTaskQueue, { uploadTaskSpecialStatus, commonTaskStatus, downloadTaskSpecialStatus } from '../datastore/upDownTaskQueue'
// 文件系统库
import fs from 'fs-extra'
// 路径处理库
import path from 'path'
import * as fsWalk from '@nodelib/fs.walk'
// 取消下载任务的加载文件列表、刷新下载文件传输列表
import { cancelDownloadLoadingFileList, refreshDownloadFileTransferList } from '@/manage/utils/static'
class LocalApi {
logger: ManageLogger
isWindows: boolean
constructor (logger: ManageLogger) {
this.logger = logger
this.isWindows = process.platform === 'win32'
}
logParam = (error:any, method: string) =>
this.logger.error(formatError(error, { class: 'LocalApi', method }))
// windows 系统下将路径转换为 unix 风格
transPathToUnix (filePath: string | undefined) {
if (!filePath) return ''
return this.isWindows ? filePath.split(path.sep).join(path.posix.sep) : filePath.replace(/^\/+/, '')
}
transBack (filePath: string | undefined) {
if (!filePath) return ''
return this.isWindows
? filePath.split(path.posix.sep).join(path.sep).replace(/^\\+/, '')
: `/${filePath.replace(/^\/+/, '')}`
}
formatFolder (item: fs.Stats, urlPrefix: string, fileName: string, filePath: string) {
const key = this.transPathToUnix(filePath)
return {
...item,
key,
fileName,
fileSize: 0,
Key: key,
formatedTime: '',
isDir: true,
checked: false,
isImage: false,
match: false,
url: urlPrefix
}
}
formatFile (item: fs.Stats, urlPrefix: string, fileName: string, filePath: string) {
const key = this.transPathToUnix(filePath)
return {
...item,
key,
fileName,
fileSize: item.size,
Key: key,
formatedTime: new Date(item.mtime).toLocaleString(),
isDir: false,
checked: false,
match: false,
isImage: isImage(fileName),
url: urlPrefix
}
}
async getBucketListRecursively (configMap: IStringKeyMap): Promise<any> {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
const { prefix, customUrl = '', cancelToken } = configMap
const urlPrefix = customUrl.replace(/\/+$/, '')
const cancelTask = [false]
ipcMain.on(cancelDownloadLoadingFileList, (_evt: IpcMainEvent, token: string) => {
if (token === cancelToken) {
cancelTask[0] = true
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
}
})
let res = {} as any
const result = {
fullList: <any>[],
success: false,
finished: false
}
try {
res = fsWalk.walkSync(prefix, {
followSymbolicLinks: true,
fs,
stats: true,
throwErrorOnBrokenSymbolicLink: false
})
if (res.length) {
result.fullList.push(
...res.data
.filter((item: fsWalk.Entry) => item.stats?.isFile())
.map((item: any) => this.formatFile(item, urlPrefix, item.name, item.path))
)
result.success = true
}
} catch (error) {
this.logParam(error, 'getBucketListRecursively')
}
result.finished = true
window.webContents.send(refreshDownloadFileTransferList, result)
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
}
async getBucketListBackstage (configMap: IStringKeyMap): Promise<any> {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
const { customUrl = '', cancelToken, baseDir } = configMap
let prefix = configMap.prefix
prefix = this.transBack(prefix)
let urlPrefix = customUrl.replace(/\/+$/, '')
let webPath = configMap.webPath || ''
if (webPath && customUrl && webPath !== '/') {
webPath = webPath.replace(/^\/+|\/+$/, '')
}
const cancelTask = [false]
ipcMain.on('cancelLoadingFileList', (_evt: IpcMainEvent, token: string) => {
if (token === cancelToken) {
cancelTask[0] = true
ipcMain.removeAllListeners('cancelLoadingFileList')
}
})
const result = {
fullList: <any>[],
success: false,
finished: false
}
try {
const res = await fs.readdir(prefix, {
withFileTypes: true
})
if (res.length) {
res.forEach((item: fs.Dirent) => {
const pathOfFile = path.join(prefix, item.name)
const relativePath = path.relative(baseDir, pathOfFile)
const relative = webPath && urlPrefix + `/${path.join(webPath, relativePath)}`.replace(/\\/g, '/').replace(/\/+/g, '/')
if (webPath && customUrl) {
urlPrefix = relative
} else {
urlPrefix = pathOfFile
}
const stats = fs.statSync(pathOfFile)
if (item.isDirectory()) {
result.fullList.push(this.formatFolder(stats, urlPrefix, item.name, relativePath))
} else {
result.fullList.push(this.formatFile(stats, urlPrefix, item.name, relativePath))
}
})
result.success = true
}
} catch (error) {
this.logParam(error, 'getBucketListBackstage')
}
result.finished = true
window.webContents.send('refreshFileTransferList', result)
ipcMain.removeAllListeners('cancelLoadingFileList')
}
async renameBucketFile (configMap: IStringKeyMap): Promise<boolean> {
const { oldKey, newKey } = configMap
let result = false
try {
await fs.rename(this.transBack(oldKey), this.transBack(newKey))
result = true
} catch (error) {
this.logParam(error, 'renameBucketFile')
}
return result
}
async deleteBucketFile (configMap: IStringKeyMap): Promise<boolean> {
const { key } = configMap
let result = false
try {
await fs.remove(this.transBack(key))
result = true
} catch (error) {
this.logParam(error, 'deleteBucketFile')
}
return result
}
async deleteBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
const { key } = configMap
let result = false
try {
await fs.rmdir(this.transBack(key), {
recursive: true
})
result = true
} catch (error) {
this.logParam(error, 'deleteBucketFolder')
}
return result
}
async uploadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
const { fileArray } = configMap
const instance = UpDownTaskQueue.getInstance()
for (const item of fileArray) {
const { alias, bucketName, key, filePath, fileName } = item
const id = `${alias}-${bucketName}-${key}-${filePath}`
if (instance.getUploadTask(id)) {
continue
}
instance.addUploadTask({
id,
progress: 0,
status: commonTaskStatus.queuing,
sourceFileName: fileName,
sourceFilePath: filePath,
targetFilePath: key,
targetFileBucket: bucketName,
targetFileRegion: '',
noProgress: true
})
try {
fs.ensureFileSync(filePath)
await fs.copyFile(filePath, this.transBack(key))
instance.updateUploadTask({
id,
progress: 100,
status: uploadTaskSpecialStatus.uploaded,
finishTime: new Date().toLocaleString()
})
} catch (error) {
this.logParam(error, 'uploadBucketFile')
instance.updateUploadTask({
id,
progress: 0,
status: commonTaskStatus.failed,
finishTime: new Date().toLocaleString()
})
}
}
return true
}
async createBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
const { key } = configMap
let result = false
try {
await fs.mkdir(this.transBack(key), {
recursive: true
})
result = true
} catch (error) {
this.logParam(error, 'createBucketFolder')
}
return result
}
async downloadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
const { downloadPath, fileArray } = configMap
const instance = UpDownTaskQueue.getInstance()
for (const item of fileArray) {
const { alias, bucketName, key, fileName } = item
const savedFilePath = path.join(downloadPath, fileName)
const id = `${alias}-${bucketName}-local-${key}`
if (instance.getDownloadTask(id)) {
continue
}
instance.addDownloadTask({
id,
progress: 0,
status: commonTaskStatus.queuing,
sourceFileName: fileName,
targetFilePath: savedFilePath
})
try {
fs.ensureFileSync(savedFilePath)
await fs.copyFile(this.transBack(key), savedFilePath)
instance.updateDownloadTask({
id,
progress: 100,
status: downloadTaskSpecialStatus.downloaded,
finishTime: new Date().toLocaleString()
})
} catch (error) {
this.logParam(error, 'downloadBucketFile')
instance.updateDownloadTask({
id,
progress: 0,
status: commonTaskStatus.failed,
finishTime: new Date().toLocaleString()
})
}
}
return true
}
}
export default LocalApi

View File

@@ -137,20 +137,11 @@ class WebdavplistApi {
}
})
}
} else {
result.finished = true
window.webContents.send(refreshDownloadFileTransferList, result)
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
return
result.success = true
}
} catch (error) {
this.logParam(error, 'getBucketListRecursively')
result.finished = true
window.webContents.send(refreshDownloadFileTransferList, result)
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
return
}
result.success = true
result.finished = true
window.webContents.send(refreshDownloadFileTransferList, result)
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)

View File

@@ -54,22 +54,24 @@ export class ManageApi extends EventEmitter implements ManageApiType {
createClient () {
const name = this.currentPicBedConfig.picBedName
switch (name) {
case 'tcyun':
return new API.TcyunApi(this.currentPicBedConfig.secretId, this.currentPicBedConfig.secretKey, this.logger)
case 'aliyun':
return new API.AliyunApi(this.currentPicBedConfig.accessKeyId, this.currentPicBedConfig.accessKeySecret, this.logger)
case 'qiniu':
return new API.QiniuApi(this.currentPicBedConfig.accessKey, this.currentPicBedConfig.secretKey, this.logger)
case 'upyun':
return new API.UpyunApi(this.currentPicBedConfig.bucketName, this.currentPicBedConfig.operator, this.currentPicBedConfig.password, this.logger)
case 'smms':
return new API.SmmsApi(this.currentPicBedConfig.token, this.logger)
case 'github':
return new API.GithubApi(this.currentPicBedConfig.token, this.currentPicBedConfig.githubUsername, this.currentPicBedConfig.proxy, this.logger)
case 'imgur':
return new API.ImgurApi(this.currentPicBedConfig.imgurUserName, this.currentPicBedConfig.accessToken, this.currentPicBedConfig.proxy, this.logger)
case 'local':
return new API.LocalApi(this.logger)
case 'qiniu':
return new API.QiniuApi(this.currentPicBedConfig.accessKey, this.currentPicBedConfig.secretKey, this.logger)
case 'smms':
return new API.SmmsApi(this.currentPicBedConfig.token, this.logger)
case 's3plist':
return new API.S3plistApi(this.currentPicBedConfig.accessKeyId, this.currentPicBedConfig.secretAccessKey, this.currentPicBedConfig.endpoint, this.currentPicBedConfig.sslEnabled, this.currentPicBedConfig.s3ForcePathStyle, this.currentPicBedConfig.proxy, this.logger)
case 'tcyun':
return new API.TcyunApi(this.currentPicBedConfig.secretId, this.currentPicBedConfig.secretKey, this.logger)
case 'upyun':
return new API.UpyunApi(this.currentPicBedConfig.bucketName, this.currentPicBedConfig.operator, this.currentPicBedConfig.password, this.logger)
case 'webdavplist':
return new API.WebdavplistApi(this.currentPicBedConfig.endpoint, this.currentPicBedConfig.username, this.currentPicBedConfig.password, this.currentPicBedConfig.sslEnabled, this.currentPicBedConfig.proxy, this.logger)
default:
@@ -148,6 +150,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
param?: IStringKeyMap | undefined
): Promise<any> {
let client
const name = this.currentPicBedConfig.picBedName.replace('plist', '')
switch (this.currentPicBedConfig.picBedName) {
case 'tcyun':
case 'aliyun':
@@ -169,15 +172,11 @@ export class ManageApi extends EventEmitter implements ManageApiType {
CreationDate: new Date().toISOString()
}]
case 'smms':
return [{
Name: 'smms',
Location: 'smms',
CreationDate: new Date().toISOString()
}]
case 'webdavplist':
case 'local':
return [{
Name: 'webdav',
Location: 'webdav',
Name: name,
Location: name,
CreationDate: new Date().toISOString()
}]
default:
@@ -313,6 +312,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
case 'imgur':
case 's3plist':
case 'webdavplist':
case 'local':
try {
client = this.createClient() as any
return await client.getBucketListRecursively(param!)
@@ -356,6 +356,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
case 'imgur':
case 's3plist':
case 'webdavplist':
case 'local':
try {
client = this.createClient() as any
return await client.getBucketListBackstage(param!)
@@ -426,6 +427,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
case 'imgur':
case 's3plist':
case 'webdavplist':
case 'local':
try {
client = this.createClient() as any
const res = await client.deleteBucketFile(param!)
@@ -451,6 +453,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
case 'github':
case 's3plist':
case 'webdavplist':
case 'local':
try {
client = this.createClient() as any
return await client.deleteBucketFolder(param!)
@@ -474,6 +477,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
case 'upyun':
case 's3plist':
case 'webdavplist':
case 'local':
try {
client = this.createClient() as any
return await client.renameBucketFile(param!)
@@ -500,6 +504,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
case 'imgur':
case 's3plist':
case 'webdavplist':
case 'local':
try {
client = this.createClient() as any
const res = await client.downloadBucketFile(param!)
@@ -532,6 +537,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
case 'github':
case 's3plist':
case 'webdavplist':
case 'local':
try {
client = this.createClient() as any
return await client.createBucketFolder(param!)
@@ -558,6 +564,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
case 'imgur':
case 's3plist':
case 'webdavplist':
case 'local':
try {
client = this.createClient() as any
return await client.uploadBucketFile(param!)

View File

@@ -21,14 +21,11 @@ function beforeOpen () {
*/
function resolveMacWorkFlow () {
const dest = `${os.homedir()}/Library/Services/Upload pictures with PicList.workflow`
if (fs.existsSync(dest)) {
return true
} else {
try {
fs.copySync(path.join(__static, 'Upload pictures with PicList.workflow'), dest)
} catch (e) {
console.log(e)
}
if (fs.existsSync(dest)) return true
try {
fs.copySync(path.join(__static, 'Upload pictures with PicList.workflow'), dest)
} catch (e) {
console.log(e)
}
}

View File

@@ -33,7 +33,7 @@ export default class AliyunApi {
try {
const client = AliyunApi.createClient(config)
const key = AliyunApi.getKey(fileName, config.path)
const result = await client.delete(key) as any
const result = await client.delete(key)
return result.res.status === 204
} catch (error) {
console.error(error)

View File

@@ -1570,6 +1570,7 @@ const urlToUpload = ref('')
// 图片预览相关
const previewedImage = ref('')
const ImagePreviewList = computed(() => currentPageFilesInfo.filter(item => item.isImage).map(item => item.url))
const getCurrentPreviewIndex = computed(() => ImagePreviewList.value.indexOf(previewedImage.value))
// 快捷键相关
const isShiftKeyPress = ref<boolean>(false)
const lastChoosed = ref<number>(-1)
@@ -1577,7 +1578,7 @@ const lastChoosed = ref<number>(-1)
const customDomainList = ref([] as any[])
const currentCustomDomain = ref('')
const isShowCustomDomainSelectList = computed(() => ['tcyun', 'aliyun', 'qiniu', 'github'].includes(currentPicBedName.value))
const isShowCustomDomainInput = computed(() => ['aliyun', 'qiniu', 'tcyun', 's3plist', 'webdavplist'].includes(currentPicBedName.value))
const isShowCustomDomainInput = computed(() => ['aliyun', 'qiniu', 'tcyun', 's3plist', 'webdavplist', 'local'].includes(currentPicBedName.value))
const isAutoCustomDomain = computed(() => manageStore.config.picBed[configMap.alias].isAutoCustomUrl === undefined ? true : manageStore.config.picBed[configMap.alias].isAutoCustomUrl)
// 文件预览相关
const isShowMarkDownDialog = ref(false)
@@ -1588,17 +1589,27 @@ const isShowVideoFileDialog = ref(false)
const videoFileUrl = ref('')
const videoPlayerHeaders = ref({})
// 重命名相关
const isShowRenameFileIcon = computed(() => ['tcyun', 'aliyun', 'qiniu', 'upyun', 's3plist', 'webdavplist'].includes(currentPicBedName.value))
const isShowRenameFileIcon = computed(() => ['tcyun', 'aliyun', 'qiniu', 'upyun', 's3plist', 'webdavplist', 'local'].includes(currentPicBedName.value))
const isShowBatchRenameDialog = ref(false)
const batchRenameMatch = ref('')
const batchRenameReplace = ref('')
const isRenameIncludeExt = ref(false)
const isSingleRename = ref(false)
const itemToBeRenamed = ref({} as any)
// 新建文件夹相关
const isShowCreateNewFolder = computed(() => ['tcyun', 'aliyun', 'qiniu', 'upyun', 'github', 's3plist', 'webdavplist'].includes(currentPicBedName.value))
const isShowPresignedUrl = computed(() => ['tcyun', 'aliyun', 'qiniu', 'github', 's3plist', 'webdavplist'].includes(currentPicBedName.value))
// 当前页面信息相关
const currentPicBedName = computed<string>(() => manageStore.config.picBed[configMap.alias].picBedName)
const paging = computed(() => manageStore.config.picBed[configMap.alias].paging)
const itemsPerPage = computed(() => manageStore.config.picBed[configMap.alias].itemsPerPage)
const calculateAllFileSize = computed(() => formatFileSize(currentPageFilesInfo.reduce((total: any, item: { fileSize: any }) => total + item.fileSize, 0)) || '0')
const isShowThumbnail = computed(() => manageStore.config.settings.isShowThumbnail ?? false)
const isAutoRefresh = computed(() => manageStore.config.settings.isAutoRefresh ?? false)
const isIgnoreCase = computed(() => manageStore.config.settings.isIgnoreCase ?? false)
// 新建文件夹相关
const isShowCreateNewFolder = computed(() => ['aliyun', 'github', 'local', 'qiniu', 'tcyun', 's3plist', 'upyun', 'webdavplist'].includes(currentPicBedName.value))
const isShowPresignedUrl = computed(() => ['aliyun', 'github', 'qiniu', 's3plist', 'tcyun', 'webdavplist'].includes(currentPicBedName.value))
// 上传相关函数
@@ -1655,7 +1666,7 @@ function getBase64ofWebdav () {
return headers
}
const getCurrentPreviewIndex = computed(() => ImagePreviewList.value.indexOf(previewedImage.value))
// 上传文件选择相关
function openFileSelectDialog () {
ipcRenderer.invoke('openFileSelectDialog').then((res: any) => {
@@ -1866,11 +1877,6 @@ function handleCopyUploadingTaskInfo () {
ElMessage.success($T('MANAGE_BUCKET_COPY_SUCCESS'))
}
function handleCopyDownloadingTaskInfo () {
clipboard.writeText(JSON.stringify(downloadTaskList.value, null, 2))
ElMessage.success($T('MANAGE_BUCKET_COPY_SUCCESS'))
}
function handleDeleteUploadedTask () {
ipcRenderer.send('deleteUploadedTask')
ElMessage.success($T('MANAGE_BUCKET_DELETE_SUCCESS'))
@@ -1881,6 +1887,13 @@ function handleDeleteAllUploadedTask () {
ElMessage.success($T('MANAGE_BUCKET_DELETE_SUCCESS'))
}
// 下载任务相关
function handleCopyDownloadingTaskInfo () {
clipboard.writeText(JSON.stringify(downloadTaskList.value, null, 2))
ElMessage.success($T('MANAGE_BUCKET_COPY_SUCCESS'))
}
function handleDeleteDownloadedTask () {
ipcRenderer.send('deleteDownloadedTask')
ElMessage.success($T('MANAGE_BUCKET_DELETE_SUCCESS'))
@@ -1891,7 +1904,11 @@ function handleDeleteAllDownloadedTask () {
ElMessage.success($T('MANAGE_BUCKET_DELETE_SUCCESS'))
}
const handleOpenDownloadedFolder = () => ipcRenderer.send('OpenDownloadedFolder', manageStore.config.settings.downloadDir)
function handleOpenDownloadedFolder () {
ipcRenderer.send('OpenDownloadedFolder', manageStore.config.settings.downloadDir)
}
// 文件列表相关
function handleShowFileInfo (item: any) {
isShowFileInfo.value = true
@@ -1967,17 +1984,7 @@ async function handleClickFile (item: any) {
}
}
const currentPicBedName = computed<string>(() => manageStore.config.picBed[configMap.alias].picBedName)
const paging = computed(() => manageStore.config.picBed[configMap.alias].paging)
const itemsPerPage = computed(() => manageStore.config.picBed[configMap.alias].itemsPerPage)
const calculateAllFileSize = computed(() => formatFileSize(currentPageFilesInfo.reduce((total: any, item: { fileSize: any }) => total + item.fileSize, 0)) || '0')
const isShowThumbnail = computed(() => manageStore.config.settings.isShowThumbnail ?? false)
const isAutoRefresh = computed(() => manageStore.config.settings.isAutoRefresh ?? false)
const isIgnoreCase = computed(() => manageStore.config.settings.isIgnoreCase ?? false)
// 自定义域名相关
async function handleChangeCustomUrl () {
if (currentPicBedName.value === 'github') {
@@ -2101,6 +2108,8 @@ async function initCustomDomainList () {
}
}
// 重置
async function resetParam (force: boolean = false) {
if (isLoadingData.value) {
isLoadingData.value = false
@@ -2596,7 +2605,7 @@ function handleCreateFolder () {
ElMessageBox.prompt($T('MANAGE_BUCKET_CREATE_FOLDER_BOX_TITLE'), $T('MANAGE_BUCKET_CREATE_FOLDER_BOX_TIP'), {
confirmButtonText: $T('MANAGE_BUCKET_CREATE_FOLDER_BOX_CONFIRM'),
cancelButtonText: $T('MANAGE_BUCKET_CREATE_FOLDER_BOX_CANCEL'),
inputPattern: /^[\u4e00-\u9fa5_a-zA-Z0-9/]+$/,
inputPattern: /^[\u4e00-\u9fff_a-zA-Z0-9/]+$/,
inputErrorMessage: $T('MANAGE_BUCKET_CREATE_FOLDER_ERROR_MSG')
}).then(async ({ value }) => {
let formatedPath = value
@@ -2617,7 +2626,7 @@ function handleCreateFolder () {
}).catch(() => {})
}
const showUrlDialog = () => {
function showUrlDialog () {
dialogVisible.value = true
}
@@ -2857,10 +2866,12 @@ async function getBucketFileListBackStage () {
isLoadingData.value = true
const fileTransferStore = useFileTransferStore()
fileTransferStore.resetFileTransferList()
if (currentPicBedName.value === 'webdavplist') {
if (currentPicBedName.value === 'webdavplist' ||
currentPicBedName.value === 'local') {
param.baseDir = configMap.baseDir
param.webPath = configMap.webPath
}
console.log(param)
ipcRenderer.send('getBucketListBackstage', configMap.alias, param)
ipcRenderer.on('refreshFileTransferList', (evt: IpcRendererEvent, data) => {
fileTransferStore.refreshFileTransferList(data)
@@ -3433,7 +3444,9 @@ const upLoadTaskColumns: Column<any>[] = [
}
]
const rowClass = ({ rowData }: Parameters<RowClassNameGetter<any>>[0]) => rowData.checked ? 'file-list-row-checked' : ''
function rowClass ({ rowData }: Parameters<RowClassNameGetter<any>>[0]) {
return rowData.checked ? 'file-list-row-checked' : ''
}
const columns: Column<any>[] = [
{

View File

@@ -555,7 +555,7 @@ function handleConfigImport (alias: string) {
const selectedConfig = existingConfiguration[alias]
if (!selectedConfig) return
supportedPicBedList[selectedConfig.picBedName].forEach((option: any) => {
supportedPicBedList[selectedConfig.picBedName].options.forEach((option: any) => {
if (selectedConfig[option] !== undefined) {
configResult[selectedConfig.picBedName + '.' + option] = selectedConfig[option]
}

View File

@@ -302,6 +302,7 @@ import { useManageStore } from '../store/manageStore'
// 国际化函数
import { T as $T } from '@/i18n'
import path from 'path'
const manageStore = useManageStore() as any
const route = useRoute()
@@ -443,13 +444,22 @@ async function getBucketList () {
}
}
function transPathToUnix (filePath: string | undefined) {
if (!filePath) return ''
return process.platform === 'win32' ? filePath.split(path.sep).join(path.posix.sep).replace(/^\/+|\/+$/g, '') : filePath.replace(/^\/+|\/+$/g, '')
}
function handleSelectMenu (bucketName: string) {
const currentPicBedConfig = manageStore.config.picBed[currentAlias.value]
const transformedConfig = JSON.parse(currentPicBedConfig.transformedConfig ?? '{}')
let prefix = transformedConfig[bucketName]?.baseDir || '/'
prefix = prefix.startsWith('/') ? prefix : `/${prefix}`
prefix = prefix.endsWith('/') ? prefix : `${prefix}/`
if (currentPicBedConfig.picBedName ?? currentPicBedName.value === 'local') {
prefix = `/${transPathToUnix(prefix)}/`
} else {
prefix = prefix.startsWith('/') ? prefix : `/${prefix}`
prefix = prefix.endsWith('/') ? prefix : `${prefix}/`
}
const configMap = {
prefix,
@@ -463,7 +473,7 @@ function handleSelectMenu (bucketName: string) {
webPath: currentPicBedConfig.webPath || ''
}
currentSelectedBucket.value = bucketName
console.log(configMap)
router.push({
path: '/main-page/manage-main-page/manage-bucket-page',
query: {
@@ -477,6 +487,7 @@ function switchPicBed (picBedAlias:string) {
router.push({
path: '/main-page/manage-login-page'
})
return
}
if (route.fullPath.startsWith('/main-page/manage-main-page/manage-bucket-page') || route.fullPath.startsWith('/main-page/manage-main-page/manage-setting-page')
) {

View File

@@ -41,7 +41,7 @@ const aliasRule = [
},
{
validator: (rule: any, value: any, callback: any) => {
const reg = /^[\u4e00-\u9fa5_a-zA-Z0-9-]+$/
const reg = /^[\u4e00-\u9fff_a-zA-Z0-9-]+$/
if (!reg.test(value)) {
callback(new Error($T('MANAGE_CONSTANT_ALIAS_RULE_MESSAGE_B')))
} else {
@@ -838,7 +838,7 @@ export const supportedPicBedList: IStringKeyMap = {
}
},
explain: $T('MANAGE_CONSTANT_LOCAL_EXPLAIN'),
options: ['alias', 'baseDir', 'customUrl', 'webPath'],
options: ['alias', 'baseDir', 'customUrl', 'bucketName', 'webPath'],
refLink: 'https://piclist.cn',
referenceText: $T('MANAGE_CONSTANT_LOCAL_REFER_TEXT')
}

View File

@@ -1,11 +1,18 @@
class LS {
get (name: string) {
const item = localStorage.getItem(name) as string
return item ? JSON.parse(item) : {}
const item = localStorage.getItem(name)
if (item) {
try {
return JSON.parse(item)
} catch (e) {
console.error('Failed to parse JSON:', e)
}
}
return {}
}
set (name: string, value: any) {
return localStorage.setItem(name, JSON.stringify(value))
set (name: string, value: any): void {
localStorage.setItem(name, JSON.stringify(value))
}
}