🚧 WIP(custom): v3.0.0 migrate to vite and esm
@@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<div id="app" :key="pageReloadCount">
|
||||
<div
|
||||
id="app"
|
||||
:key="pageReloadCount"
|
||||
>
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
@@ -8,8 +11,8 @@
|
||||
import type { IConfig } from 'piclist'
|
||||
import { onBeforeMount } from 'vue'
|
||||
|
||||
import { useStore } from '@/hooks/useStore'
|
||||
import { useATagClick } from '@/hooks/useATagClick'
|
||||
import { useStore } from '@/hooks/useStore'
|
||||
import { getConfig } from '@/utils/dataSender'
|
||||
import { pageReloadCount } from '@/utils/global'
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import path from 'path'
|
||||
|
||||
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
|
||||
|
||||
@@ -14,7 +13,7 @@ interface IConfigMap {
|
||||
}
|
||||
|
||||
export default class AlistApi {
|
||||
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
||||
const { fileName, config } = configMap
|
||||
try {
|
||||
const { version, url, uploadPath, token } = config
|
||||
@@ -30,8 +29,8 @@ export default class AlistApi {
|
||||
Authorization: token
|
||||
},
|
||||
data: {
|
||||
dir: path.join('/', uploadPath, path.dirname(fileName)),
|
||||
names: [path.basename(fileName)]
|
||||
dir: window.node.path.join('/', uploadPath, window.node.path.dirname(fileName)),
|
||||
names: [window.node.path.basename(fileName)]
|
||||
}
|
||||
})
|
||||
if (result.data.code === 200) {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import path from 'path'
|
||||
|
||||
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
|
||||
|
||||
@@ -25,7 +24,7 @@ const getAListToken = async (url: string, username: string, password: string) =>
|
||||
}
|
||||
|
||||
export default class AListplistApi {
|
||||
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
||||
const { fileName, config } = configMap
|
||||
try {
|
||||
const { url, username, password, uploadPath } = config
|
||||
@@ -45,8 +44,8 @@ export default class AListplistApi {
|
||||
Authorization: token
|
||||
},
|
||||
data: {
|
||||
dir: path.join('/', uploadPath, path.dirname(fileName)),
|
||||
names: [path.basename(fileName)]
|
||||
dir: window.node.path.join('/', uploadPath, window.node.path.dirname(fileName)),
|
||||
names: [window.node.path.basename(fileName)]
|
||||
}
|
||||
})
|
||||
if (result.data.code === 200) {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import OSS from 'ali-oss'
|
||||
|
||||
import { IAliYunConfig, PartialKeys } from '#/types/types'
|
||||
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
|
||||
|
||||
interface IConfigMap {
|
||||
@@ -8,14 +7,14 @@ interface IConfigMap {
|
||||
}
|
||||
|
||||
export default class AliyunApi {
|
||||
static #getKey(fileName: string, path?: string): string {
|
||||
static #getKey (fileName: string, path?: string): string {
|
||||
return path && path !== '/' ? `${path.replace(/^\/+|\/+$/, '')}/${fileName}` : fileName
|
||||
}
|
||||
|
||||
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
||||
const { fileName, config } = configMap
|
||||
try {
|
||||
const client = new OSS({ ...config, region: config.area })
|
||||
const client = new window.node.OSS({ ...config, region: config.area })
|
||||
const key = AliyunApi.#getKey(fileName, config.path)
|
||||
const result = await client.delete(key)
|
||||
if (result.res.status === 204) {
|
||||
|
||||
@@ -15,6 +15,7 @@ import SmmsApi from '@/apis/smms'
|
||||
import TcyunApi from '@/apis/tcyun'
|
||||
import UpyunApi from '@/apis/upyun'
|
||||
import WebdavApi from '@/apis/webdav'
|
||||
import { IStringKeyMap } from '#/types/types'
|
||||
|
||||
const apiMap: IStringKeyMap = {
|
||||
alist: AlistApi,
|
||||
@@ -38,7 +39,7 @@ const apiMap: IStringKeyMap = {
|
||||
}
|
||||
|
||||
export default class ALLApi {
|
||||
static async delete(configMap: IStringKeyMap): Promise<boolean> {
|
||||
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
||||
const api = apiMap[configMap.type]
|
||||
return api ? await api.delete(configMap) : false
|
||||
}
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
import { ipcRenderer } from 'electron'
|
||||
|
||||
import { getRawData, triggerRPC } from '@/utils/common'
|
||||
import { removeFileFromS3InMain } from '~/utils/deleteFunc'
|
||||
import { deleteFailedLog } from '#/utils/deleteLog'
|
||||
import { getRawData } from '@/utils/common'
|
||||
import { IRPCActionType } from '#/types/enum'
|
||||
import { IStringKeyMap } from '#/types/types'
|
||||
import { deleteFailedLog } from '#/utils/deleteLog'
|
||||
|
||||
export default class AwsS3Api {
|
||||
static async delete(configMap: IStringKeyMap): Promise<boolean> {
|
||||
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
||||
try {
|
||||
return ipcRenderer
|
||||
? (await triggerRPC(IRPCActionType.GALLERY_DELETE_AWS_S3_FILE, getRawData(configMap))) || false
|
||||
: await removeFileFromS3InMain(getRawData(configMap))
|
||||
return (await window.electron.triggerRPC(IRPCActionType.GALLERY_DELETE_AWS_S3_FILE, getRawData(configMap))) || false
|
||||
} catch (error: any) {
|
||||
deleteFailedLog(configMap.fileName, 'AWS S3', error)
|
||||
return false
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
import { ipcRenderer } from 'electron'
|
||||
|
||||
import { removeFileFromDogeInMain } from '~/utils/deleteFunc'
|
||||
|
||||
import { getRawData, triggerRPC } from '@/utils/common'
|
||||
import { deleteFailedLog } from '#/utils/deleteLog'
|
||||
import { getRawData } from '@/utils/common'
|
||||
import { IRPCActionType } from '#/types/enum'
|
||||
import { IStringKeyMap } from '#/types/types'
|
||||
import { deleteFailedLog } from '#/utils/deleteLog'
|
||||
|
||||
export default class AwsS3Api {
|
||||
static async delete(configMap: IStringKeyMap): Promise<boolean> {
|
||||
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
||||
try {
|
||||
return ipcRenderer
|
||||
? (await triggerRPC(IRPCActionType.GALLERY_DELETE_DOGE_FILE, getRawData(configMap))) || false
|
||||
: await removeFileFromDogeInMain(getRawData(configMap))
|
||||
return (await window.electron.triggerRPC(IRPCActionType.GALLERY_DELETE_DOGE_FILE, getRawData(configMap))) || false
|
||||
} catch (error: any) {
|
||||
deleteFailedLog(configMap.fileName, 'DogeCloud', error)
|
||||
return false
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Octokit } from '@octokit/rest'
|
||||
|
||||
import { IGitHubConfig, PartialKeys } from '#/types/types'
|
||||
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
|
||||
|
||||
interface IConfigMap {
|
||||
@@ -9,18 +8,18 @@ interface IConfigMap {
|
||||
}
|
||||
|
||||
export default class GithubApi {
|
||||
static #createOctokit(token: string) {
|
||||
return new Octokit({
|
||||
static #createOctokit (token: string) {
|
||||
return new window.node.Octokit({
|
||||
auth: token
|
||||
})
|
||||
}
|
||||
|
||||
static #createKey(path: string | undefined, fileName: string): string {
|
||||
static #createKey (path: string | undefined, fileName: string): string {
|
||||
const formatedFileName = fileName.replace(/%2F/g, '/')
|
||||
return path && path !== '/' ? `${path.replace(/^\/+|\/+$/, '')}/${formatedFileName}` : formatedFileName
|
||||
}
|
||||
|
||||
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
||||
const {
|
||||
fileName,
|
||||
hash,
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
import { ipcRenderer } from 'electron'
|
||||
|
||||
import { removeFileFromHuaweiInMain } from '~/utils/deleteFunc'
|
||||
|
||||
import { getRawData, triggerRPC } from '@/utils/common'
|
||||
import { deleteFailedLog } from '#/utils/deleteLog'
|
||||
import { getRawData } from '@/utils/common'
|
||||
import { IRPCActionType } from '#/types/enum'
|
||||
import { IStringKeyMap } from '#/types/types'
|
||||
import { deleteFailedLog } from '#/utils/deleteLog'
|
||||
|
||||
export default class HuaweicloudApi {
|
||||
static async delete(configMap: IStringKeyMap): Promise<boolean> {
|
||||
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
||||
try {
|
||||
return ipcRenderer
|
||||
? (await triggerRPC(IRPCActionType.GALLERY_DELETE_HUAWEI_OSS_FILE, getRawData(configMap))) || false
|
||||
: await removeFileFromHuaweiInMain(getRawData(configMap))
|
||||
return (await window.electron.triggerRPC(IRPCActionType.GALLERY_DELETE_HUAWEI_OSS_FILE, getRawData(configMap))) || false
|
||||
} catch (error: any) {
|
||||
deleteFailedLog(configMap.fileName, 'HuaweiCloud', error)
|
||||
return false
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import axios, { AxiosResponse } from 'axios'
|
||||
|
||||
import { IImgurConfig } from '#/types/types'
|
||||
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
|
||||
|
||||
interface IConfigMap {
|
||||
@@ -10,7 +11,7 @@ interface IConfigMap {
|
||||
export default class ImgurApi {
|
||||
static #baseUrl = 'https://api.imgur.com/3'
|
||||
|
||||
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
||||
const { config: { clientId = '', username = '', accessToken = '' } = {}, hash = '' } = configMap
|
||||
let Authorization: string, apiUrl: string
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import fs from 'fs-extra'
|
||||
|
||||
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
|
||||
|
||||
interface IConfigMap {
|
||||
@@ -7,7 +5,7 @@ interface IConfigMap {
|
||||
}
|
||||
|
||||
export default class LocalApi {
|
||||
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
||||
const { hash } = configMap
|
||||
if (!hash) {
|
||||
deleteLog(hash, 'Local', false, 'Local.delete: invalid params')
|
||||
@@ -15,7 +13,7 @@ export default class LocalApi {
|
||||
}
|
||||
|
||||
try {
|
||||
await fs.remove(hash)
|
||||
await window.node.fs.remove(hash)
|
||||
deleteLog(hash, 'Local')
|
||||
return true
|
||||
} catch (error: any) {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import axios, { AxiosResponse } from 'axios'
|
||||
import https from 'https'
|
||||
|
||||
import { IStringKeyMap } from '#/types/types'
|
||||
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
|
||||
|
||||
export default class LskyplistApi {
|
||||
static async delete(configMap: IStringKeyMap): Promise<boolean> {
|
||||
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
||||
const { hash, config } = configMap
|
||||
if (!hash || !config || !config.token) {
|
||||
deleteLog(hash, 'Lskyplist', false, 'LskyplistApi.delete: invalid params')
|
||||
@@ -22,11 +20,11 @@ export default class LskyplistApi {
|
||||
Authorization: token || undefined
|
||||
}
|
||||
|
||||
const requestAgent = new https.Agent({
|
||||
const requestAgent = new window.node.https.Agent({
|
||||
rejectUnauthorized: false
|
||||
})
|
||||
try {
|
||||
const response: AxiosResponse = await axios.delete(`${host}/api/v1/images/${hash}`, {
|
||||
const response: any = await window.node.axios.delete(`${host}/api/v1/images/${hash}`, {
|
||||
headers: v2Headers,
|
||||
timeout: 30000,
|
||||
httpsAgent: requestAgent
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import axios, { AxiosResponse } from 'axios'
|
||||
|
||||
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
|
||||
import { IStringKeyMap } from '#/types/types'
|
||||
import { deleteFailedLog, deleteLog } from '~/utils/deleteLog'
|
||||
|
||||
export default class PiclistApi {
|
||||
static async delete(configMap: IStringKeyMap): Promise<boolean> {
|
||||
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
||||
const { config, fullResult } = configMap
|
||||
const { host, port } = config
|
||||
if (!fullResult) return true
|
||||
@@ -16,7 +15,7 @@ export default class PiclistApi {
|
||||
const url = `http://${host || '127.0.0.1'}:${port || 36677}/delete`
|
||||
|
||||
try {
|
||||
const response: AxiosResponse = await axios.post(url, {
|
||||
const response: any = await window.node.axios.post(url, {
|
||||
list: [fullResult]
|
||||
})
|
||||
if (response.status === 200 && response.data?.success) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import Qiniu from 'qiniu'
|
||||
|
||||
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
|
||||
import { IQiniuConfig, PartialKeys } from '#/types/types'
|
||||
import { deleteFailedLog, deleteLog } from '~/utils/deleteLog'
|
||||
|
||||
interface IConfigMap {
|
||||
fileName: string
|
||||
@@ -8,15 +7,15 @@ interface IConfigMap {
|
||||
}
|
||||
|
||||
export default class QiniuApi {
|
||||
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
||||
const {
|
||||
fileName,
|
||||
config: { accessKey, secretKey, bucket, path }
|
||||
} = configMap
|
||||
const mac = new Qiniu.auth.digest.Mac(accessKey, secretKey)
|
||||
const qiniuConfig = new Qiniu.conf.Config()
|
||||
const mac = new window.node.qiniu.auth.digest.Mac(accessKey, secretKey)
|
||||
const qiniuConfig = new window.node.qiniu.conf.Config()
|
||||
try {
|
||||
const bucketManager = new Qiniu.rs.BucketManager(mac, qiniuConfig)
|
||||
const bucketManager = new window.node.qiniu.rs.BucketManager(mac, qiniuConfig)
|
||||
const formattedPath = path?.replace(/^\/+|\/+$/, '') || ''
|
||||
const key = path === '/' || !path ? fileName : `${formattedPath}/${fileName}`
|
||||
const res = (await new Promise((resolve, reject) => {
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
import { ipcRenderer } from 'electron'
|
||||
|
||||
import { removeFileFromSFTPInMain } from '~/utils/deleteFunc'
|
||||
|
||||
import { getRawData, triggerRPC } from '@/utils/common'
|
||||
import { deleteFailedLog } from '#/utils/deleteLog'
|
||||
import { getRawData } from '@/utils/common'
|
||||
import { IRPCActionType } from '#/types/enum'
|
||||
import { IStringKeyMap } from '#/types/types'
|
||||
import { deleteFailedLog } from '#/utils/deleteLog'
|
||||
|
||||
export default class SftpPlistApi {
|
||||
static async delete(configMap: IStringKeyMap): Promise<boolean> {
|
||||
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
||||
const { fileName, config } = configMap
|
||||
try {
|
||||
return ipcRenderer
|
||||
? (await triggerRPC(IRPCActionType.GALLERY_DELETE_SFTP_FILE, getRawData(config), fileName)) || false
|
||||
: await removeFileFromSFTPInMain(getRawData(config), fileName)
|
||||
return (await window.electron.triggerRPC(IRPCActionType.GALLERY_DELETE_SFTP_FILE, getRawData(config), fileName)) || false
|
||||
} catch (error: any) {
|
||||
deleteFailedLog(fileName, 'SFTP', error)
|
||||
return false
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import axios, { AxiosResponse } from 'axios'
|
||||
|
||||
import { ISMMSConfig } from '#/types/types'
|
||||
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
|
||||
|
||||
interface IConfigMap {
|
||||
@@ -10,7 +9,7 @@ interface IConfigMap {
|
||||
export default class SmmsApi {
|
||||
static readonly #baseUrl = 'https://smms.app/api/v2'
|
||||
|
||||
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
||||
const { hash, config } = configMap
|
||||
if (!hash || !config || !config.token) {
|
||||
deleteLog(hash, 'Smms', false, 'SmmsApi.delete: invalid params')
|
||||
@@ -20,7 +19,7 @@ export default class SmmsApi {
|
||||
const { token } = config
|
||||
|
||||
try {
|
||||
const response: AxiosResponse = await axios.get(`${SmmsApi.#baseUrl}/delete/${hash}`, {
|
||||
const response: any = await window.node.axios.get(`${SmmsApi.#baseUrl}/delete/${hash}`, {
|
||||
headers: {
|
||||
Authorization: token
|
||||
},
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
import COS from 'cos-nodejs-sdk-v5'
|
||||
|
||||
import { ITcYunConfig, PartialKeys } from '#/types/types'
|
||||
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
|
||||
|
||||
interface IConfigMap {
|
||||
fileName: string
|
||||
config: PartialKeys<ITcYunConfig, 'path'>
|
||||
}
|
||||
|
||||
export default class TcyunApi {
|
||||
static #createCOS(SecretId: string, SecretKey: string): COS {
|
||||
return new COS({
|
||||
static #createCOS (SecretId: string, SecretKey: string): any {
|
||||
return new window.node.COS({
|
||||
SecretId,
|
||||
SecretKey
|
||||
})
|
||||
}
|
||||
|
||||
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
||||
const {
|
||||
fileName,
|
||||
config: { secretId, secretKey, bucket, area, path }
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import Upyun from 'upyun'
|
||||
|
||||
import { IUpYunConfig, PartialKeys } from '#/types/types'
|
||||
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
|
||||
|
||||
interface IConfigMap {
|
||||
@@ -8,14 +7,14 @@ interface IConfigMap {
|
||||
}
|
||||
|
||||
export default class UpyunApi {
|
||||
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
||||
const {
|
||||
fileName,
|
||||
config: { bucket, operator, password, path }
|
||||
} = configMap
|
||||
try {
|
||||
const service = new Upyun.Service(bucket, operator, password)
|
||||
const client = new Upyun.Client(service)
|
||||
const service = new window.node.Upyun.Service(bucket, operator, password)
|
||||
const client = new window.node.Upyun.Client(service)
|
||||
let key
|
||||
if (path === '/' || !path) {
|
||||
key = fileName
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { AuthType, WebDAVClientOptions, createClient } from 'webdav'
|
||||
|
||||
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
|
||||
import { IWebdavPlistConfig, PartialKeys } from '#/types/types'
|
||||
import { formatEndpoint } from '#/utils/common'
|
||||
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
|
||||
|
||||
interface IConfigMap {
|
||||
fileName: string
|
||||
@@ -9,20 +8,20 @@ interface IConfigMap {
|
||||
}
|
||||
|
||||
export default class WebdavApi {
|
||||
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
||||
const {
|
||||
fileName,
|
||||
config: { host, username, password, path, sslEnabled, authType }
|
||||
} = configMap
|
||||
const endpoint = formatEndpoint(host, sslEnabled)
|
||||
const options: WebDAVClientOptions = {
|
||||
const options: any = {
|
||||
username,
|
||||
password
|
||||
}
|
||||
if (authType === 'digest') {
|
||||
options.authType = AuthType.Digest
|
||||
options.authType = window.node.webdav.AuthType.Digest
|
||||
}
|
||||
const ctx = createClient(endpoint, options)
|
||||
const ctx = window.node.webdav.createClient(endpoint, options)
|
||||
let key
|
||||
if (path === '/' || !path) {
|
||||
key = fileName
|
||||
|
||||
@@ -1,8 +1,26 @@
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<template>
|
||||
<div id="config-form" :class="props.colorMode === 'white' ? 'white' : ''">
|
||||
<el-form ref="$form" label-position="left" label-width="50%" :model="ruleForm" size="small">
|
||||
<el-form-item :label="$T('UPLOADER_CONFIG_NAME')" required prop="_configName">
|
||||
<el-input v-model="ruleForm._configName" type="input" :placeholder="$T('UPLOADER_CONFIG_PLACEHOLDER')" />
|
||||
<div
|
||||
id="config-form"
|
||||
:class="props.colorMode === 'white' ? 'white' : ''"
|
||||
>
|
||||
<el-form
|
||||
ref="$form"
|
||||
label-position="left"
|
||||
label-width="50%"
|
||||
:model="ruleForm"
|
||||
size="small"
|
||||
>
|
||||
<el-form-item
|
||||
:label="$T('UPLOADER_CONFIG_NAME')"
|
||||
required
|
||||
prop="_configName"
|
||||
>
|
||||
<el-input
|
||||
v-model="ruleForm._configName"
|
||||
type="input"
|
||||
:placeholder="$T('UPLOADER_CONFIG_PLACEHOLDER')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<!-- dynamic config -->
|
||||
<el-form-item
|
||||
@@ -15,9 +33,18 @@
|
||||
<el-row align="middle">
|
||||
{{ item.alias || item.name }}
|
||||
<template v-if="item.tips">
|
||||
<el-tooltip class="item" effect="dark" placement="right" :persistent="false" teleported>
|
||||
<el-tooltip
|
||||
class="item"
|
||||
effect="dark"
|
||||
placement="right"
|
||||
:persistent="false"
|
||||
teleported
|
||||
>
|
||||
<template #content>
|
||||
<span class="config-form-common-tips" v-html="transformMarkdownToHTML(item.tips)" />
|
||||
<span
|
||||
class="config-form-common-tips"
|
||||
v-html="transformMarkdownToHTML(item.tips)"
|
||||
/>
|
||||
</template>
|
||||
<el-icon class="ml-[4px] cursor-pointer hover:text-blue">
|
||||
<InfoFilled />
|
||||
@@ -75,14 +102,16 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { cloneDeep, union } from 'lodash'
|
||||
import { marked } from 'marked'
|
||||
import { reactive, ref, watch, toRefs } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { InfoFilled } from '@element-plus/icons-vue'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { cloneDeep, union } from 'lodash-es'
|
||||
import { marked } from 'marked'
|
||||
import { reactive, ref, toRefs, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
import { T as $T } from '@/i18n/index'
|
||||
import { getConfig } from '@/utils/dataSender'
|
||||
import { IPicGoPluginConfig, IStringKeyMap } from '#/types/types'
|
||||
|
||||
interface IProps {
|
||||
config: any[]
|
||||
@@ -109,11 +138,11 @@ watch(
|
||||
}
|
||||
)
|
||||
|
||||
function handleConfigChange(val: any) {
|
||||
function handleConfigChange (val: any) {
|
||||
handleConfig(val)
|
||||
}
|
||||
|
||||
async function validate(): Promise<IStringKeyMap | false> {
|
||||
async function validate (): Promise<IStringKeyMap | false> {
|
||||
return new Promise(resolve => {
|
||||
$form.value?.validate((valid: boolean) => {
|
||||
if (valid) {
|
||||
@@ -125,7 +154,7 @@ async function validate(): Promise<IStringKeyMap | false> {
|
||||
})
|
||||
}
|
||||
|
||||
function transformMarkdownToHTML(markdown: string) {
|
||||
function transformMarkdownToHTML (markdown: string) {
|
||||
try {
|
||||
return marked.parse(markdown)
|
||||
} catch (e) {
|
||||
@@ -133,7 +162,7 @@ function transformMarkdownToHTML(markdown: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function getConfigType() {
|
||||
function getConfigType () {
|
||||
switch (props.type) {
|
||||
case 'plugin': {
|
||||
return props.id
|
||||
@@ -149,7 +178,7 @@ function getConfigType() {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleConfig(val: IPicGoPluginConfig[]) {
|
||||
async function handleConfig (val: IPicGoPluginConfig[]) {
|
||||
const config = await getCurConfigFormData()
|
||||
const configId = $route.params.configId
|
||||
Object.assign(ruleForm, config)
|
||||
@@ -175,13 +204,13 @@ async function handleConfig(val: IPicGoPluginConfig[]) {
|
||||
}
|
||||
}
|
||||
|
||||
async function getCurConfigFormData() {
|
||||
async function getCurConfigFormData () {
|
||||
const configId = $route.params.configId
|
||||
const curTypeConfigList = (await getConfig<IStringKeyMap[]>(`uploader.${props.id}.configList`)) || []
|
||||
return curTypeConfigList.find(i => i._id === configId) || {}
|
||||
}
|
||||
|
||||
function updateRuleForm(key: string, value: any) {
|
||||
function updateRuleForm (key: string, value: any) {
|
||||
try {
|
||||
ruleForm[key] = value
|
||||
} catch (e) {
|
||||
|
||||
@@ -1,8 +1,25 @@
|
||||
<template>
|
||||
<div id="config-form" :class="props.colorMode === 'white' ? 'white' : ''">
|
||||
<el-form ref="$form" label-position="left" label-width="50%" :model="ruleForm" size="small">
|
||||
<el-form-item :label="$T('UPLOADER_CONFIG_NAME')" required prop="_configName">
|
||||
<el-input v-model="ruleForm._configName" type="input" :placeholder="$T('UPLOADER_CONFIG_PLACEHOLDER')" />
|
||||
<div
|
||||
id="config-form"
|
||||
:class="props.colorMode === 'white' ? 'white' : ''"
|
||||
>
|
||||
<el-form
|
||||
ref="$form"
|
||||
label-position="left"
|
||||
label-width="50%"
|
||||
:model="ruleForm"
|
||||
size="small"
|
||||
>
|
||||
<el-form-item
|
||||
:label="$T('UPLOADER_CONFIG_NAME')"
|
||||
required
|
||||
prop="_configName"
|
||||
>
|
||||
<el-input
|
||||
v-model="ruleForm._configName"
|
||||
type="input"
|
||||
:placeholder="$T('UPLOADER_CONFIG_PLACEHOLDER')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<!-- dynamic config -->
|
||||
<el-form-item
|
||||
@@ -62,11 +79,12 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { cloneDeep, union } from 'lodash'
|
||||
import { cloneDeep, union } from 'lodash-es'
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
|
||||
import { getConfig } from '@/utils/dataSender'
|
||||
import { T as $T } from '@/i18n'
|
||||
import { getConfig } from '@/utils/dataSender'
|
||||
import { IPicGoPluginConfig, IStringKeyMap } from '#/types/types'
|
||||
|
||||
interface IProps {
|
||||
config: any[]
|
||||
@@ -92,11 +110,11 @@ watch(
|
||||
}
|
||||
)
|
||||
|
||||
function handleConfigChange(val: any) {
|
||||
function handleConfigChange (val: any) {
|
||||
handleConfig(val)
|
||||
}
|
||||
|
||||
async function validate(): Promise<IStringKeyMap | false> {
|
||||
async function validate (): Promise<IStringKeyMap | false> {
|
||||
return new Promise(resolve => {
|
||||
$form.value?.validate((valid: boolean) => {
|
||||
if (valid) {
|
||||
@@ -108,7 +126,7 @@ async function validate(): Promise<IStringKeyMap | false> {
|
||||
})
|
||||
}
|
||||
|
||||
function getConfigType() {
|
||||
function getConfigType () {
|
||||
switch (props.type) {
|
||||
case 'plugin': {
|
||||
return props.id
|
||||
@@ -124,7 +142,7 @@ function getConfigType() {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleConfig(val: IPicGoPluginConfig[]) {
|
||||
async function handleConfig (val: IPicGoPluginConfig[]) {
|
||||
const config = await getCurConfigFormData()
|
||||
Object.assign(ruleForm, config)
|
||||
if (val.length > 0) {
|
||||
@@ -148,11 +166,11 @@ async function handleConfig(val: IPicGoPluginConfig[]) {
|
||||
}
|
||||
}
|
||||
|
||||
async function getCurConfigFormData() {
|
||||
async function getCurConfigFormData () {
|
||||
return (await getConfig<IStringKeyMap>(`${props.id}`)) || {}
|
||||
}
|
||||
|
||||
function updateRuleForm(key: string, value: any) {
|
||||
function updateRuleForm (key: string, value: any) {
|
||||
try {
|
||||
ruleForm[key] = value
|
||||
} catch (e) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
:src="
|
||||
isShowThumbnail && item.isImage
|
||||
? base64Image
|
||||
: require(`../manage/pages/assets/icons/${getFileIconPath(item.fileName ?? '')}`)
|
||||
: `/assets/icons/${getFileIconPath(item.fileName ?? '')}`
|
||||
"
|
||||
fit="contain"
|
||||
style="height: 100px; width: 100%; margin: 0 auto"
|
||||
@@ -15,7 +15,7 @@
|
||||
</template>
|
||||
<template #error>
|
||||
<el-image
|
||||
:src="require(`../manage/pages/assets/icons/${getFileIconPath(item.fileName ?? '')}`)"
|
||||
:src="`/assets/icons/${getFileIconPath(item.fileName ?? '')}`"
|
||||
fit="contain"
|
||||
style="height: 100px; width: 100%; margin: 0 auto"
|
||||
/>
|
||||
@@ -24,11 +24,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import fs from 'fs-extra'
|
||||
import mime from 'mime-types'
|
||||
import path from 'path'
|
||||
import { ref, onBeforeMount } from 'vue'
|
||||
|
||||
import { Loading } from '@element-plus/icons-vue'
|
||||
import { onBeforeMount, ref } from 'vue'
|
||||
|
||||
import { getFileIconPath } from '@/manage/utils/common'
|
||||
|
||||
@@ -43,9 +41,9 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const createBase64Image = async () => {
|
||||
const filePath = path.normalize(props.localPath)
|
||||
const base64 = await fs.readFile(filePath, 'base64')
|
||||
base64Image.value = `data:${mime.lookup(filePath) || 'image/png'};base64,${base64}`
|
||||
const filePath = window.node.path.normalize(props.localPath)
|
||||
const base64 = await window.node.fs.readFile(filePath, 'base64')
|
||||
base64Image.value = `data:${window.node.mime.lookup(filePath) || 'image/png'};base64,${base64}`
|
||||
}
|
||||
|
||||
onBeforeMount(async () => {
|
||||
|
||||
@@ -1,23 +1,30 @@
|
||||
<template>
|
||||
<el-image :src="imageSource" fit="contain" style="height: 100px; width: 100%; margin: 0 auto">
|
||||
<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" />
|
||||
<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 { computed, onMounted, ref, watch } from 'vue'
|
||||
|
||||
import { getFileIconPath } from '@/manage/utils/common'
|
||||
import { IRPCActionType } from '#/types/enum'
|
||||
import { triggerRPC } from '@/utils/common'
|
||||
|
||||
const preSignedUrl = ref('')
|
||||
|
||||
@@ -36,13 +43,13 @@ const props = defineProps<{
|
||||
const imageSource = computed(() => {
|
||||
return props.isShowThumbnail && props.item.isImage
|
||||
? preSignedUrl.value
|
||||
: require(`../manage/pages/assets/icons/${getFileIconPath(props.item.fileName ?? '')}`)
|
||||
: `/assets/icons/${getFileIconPath(props.item.fileName ?? '')}`
|
||||
})
|
||||
|
||||
const iconPath = computed(() => require(`../manage/pages/assets/icons/${getFileIconPath(props.item.fileName ?? '')}`))
|
||||
const iconPath = computed(() => `/assets/icons/${getFileIconPath(props.item.fileName ?? '')}`)
|
||||
|
||||
async function getUrl() {
|
||||
preSignedUrl.value = await triggerRPC<any>(IRPCActionType.MANAGE_GET_PRE_SIGNED_URL, props.alias, props.config)
|
||||
async function getUrl () {
|
||||
preSignedUrl.value = await window.electron.triggerRPC<any>(IRPCActionType.MANAGE_GET_PRE_SIGNED_URL, props.alias, props.config)
|
||||
}
|
||||
|
||||
watch(() => [props.url, props.item], getUrl, { deep: true })
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { ElImage, ElIcon } from 'element-plus'
|
||||
import { defineComponent, ref, onMounted, watch, computed } from 'vue'
|
||||
import { Loading } from '@element-plus/icons-vue'
|
||||
import { ElIcon, ElImage } from 'element-plus'
|
||||
import { computed, defineComponent, onMounted, ref, watch } from 'vue'
|
||||
|
||||
import { getFileIconPath } from '@/manage/utils/common'
|
||||
import { IRPCActionType } from '#/types/enum'
|
||||
import { triggerRPC } from '@/utils/common'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@@ -30,20 +29,20 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
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 ?? '')}`)
|
||||
: `/assets/icons/${getFileIconPath(props.item.fileName ?? '')}`
|
||||
})
|
||||
const iconPath = computed(() =>
|
||||
require(`../manage/pages/assets/icons/${getFileIconPath(props.item.fileName ?? '')}`)
|
||||
`/assets/icons/${getFileIconPath(props.item.fileName ?? '')}`
|
||||
)
|
||||
|
||||
async function getUrl() {
|
||||
preSignedUrl.value = await triggerRPC<any>(IRPCActionType.MANAGE_GET_PRE_SIGNED_URL, props.alias, props.config)
|
||||
async function getUrl () {
|
||||
preSignedUrl.value = await window.electron.triggerRPC<any>(IRPCActionType.MANAGE_GET_PRE_SIGNED_URL, props.alias, props.config)
|
||||
}
|
||||
|
||||
watch(() => [props.url, props.item], getUrl, { deep: true })
|
||||
|
||||
@@ -7,15 +7,25 @@
|
||||
:model="waterMarkForm"
|
||||
>
|
||||
<el-form-item :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_SKIP_PROCESS_EXT_LIST')">
|
||||
<el-input v-model="skipProcessForm.skipProcessExtList" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }" />
|
||||
<el-input
|
||||
v-model="skipProcessForm.skipProcessExtList"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 2, maxRows: 4 }"
|
||||
/>
|
||||
<div class="text-xs text-gray-500">
|
||||
{{ $T('UPLOAD_PAGE_IMAGE_PROCESS_SKIP_PROCESS_EXT_LIST_TIPS') }}
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_ISADDWM')">
|
||||
<el-switch v-model="waterMarkForm.isAddWatermark" :style="switchStyle" />
|
||||
<el-switch
|
||||
v-model="waterMarkForm.isAddWatermark"
|
||||
:style="switchStyle"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item v-show="waterMarkForm.isAddWatermark" :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_WMTYPE')">
|
||||
<el-form-item
|
||||
v-show="waterMarkForm.isAddWatermark"
|
||||
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_WMTYPE')"
|
||||
>
|
||||
<el-radio-group v-model="waterMarkForm.watermarkType">
|
||||
<el-radio value="text">
|
||||
{{ $T('UPLOAD_PAGE_IMAGE_PROCESS_WMTYPE_TEXT') }}
|
||||
@@ -25,11 +35,23 @@
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-show="waterMarkForm.isAddWatermark" :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_ISFULLSCREEN_WM')">
|
||||
<el-switch v-model="waterMarkForm.isFullScreenWatermark" :style="switchStyle" />
|
||||
<el-form-item
|
||||
v-show="waterMarkForm.isAddWatermark"
|
||||
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_ISFULLSCREEN_WM')"
|
||||
>
|
||||
<el-switch
|
||||
v-model="waterMarkForm.isFullScreenWatermark"
|
||||
:style="switchStyle"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item v-show="waterMarkForm.isAddWatermark" :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_WMDEGREE')">
|
||||
<el-input-number v-model="waterMarkForm.watermarkDegree" :step="1" />
|
||||
<el-form-item
|
||||
v-show="waterMarkForm.isAddWatermark"
|
||||
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_WMDEGREE')"
|
||||
>
|
||||
<el-input-number
|
||||
v-model="waterMarkForm.watermarkDegree"
|
||||
:step="1"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-show="waterMarkForm.isAddWatermark && waterMarkForm.watermarkType === 'text'"
|
||||
@@ -43,14 +65,25 @@
|
||||
>
|
||||
<el-input v-model="waterMarkForm.watermarkFontPath" />
|
||||
</el-form-item>
|
||||
<el-form-item v-show="waterMarkForm.isAddWatermark" :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_WMRATIO')">
|
||||
<el-input-number v-model="waterMarkForm.watermarkScaleRatio" :min="0" :max="1" :step="0.01" />
|
||||
<el-form-item
|
||||
v-show="waterMarkForm.isAddWatermark"
|
||||
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_WMRATIO')"
|
||||
>
|
||||
<el-input-number
|
||||
v-model="waterMarkForm.watermarkScaleRatio"
|
||||
:min="0"
|
||||
:max="1"
|
||||
:step="0.01"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-show="waterMarkForm.isAddWatermark && waterMarkForm.watermarkType === 'text'"
|
||||
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_WMCOLOR')"
|
||||
>
|
||||
<el-color-picker v-model="waterMarkForm.watermarkColor" show-alpha />
|
||||
<el-color-picker
|
||||
v-model="waterMarkForm.watermarkColor"
|
||||
show-alpha
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-show="waterMarkForm.isAddWatermark && waterMarkForm.watermarkType === 'image'"
|
||||
@@ -58,76 +91,157 @@
|
||||
>
|
||||
<el-input v-model="waterMarkForm.watermarkImagePath" />
|
||||
</el-form-item>
|
||||
<el-form-item v-show="waterMarkForm.isAddWatermark" :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_WMPOSITION')">
|
||||
<el-form-item
|
||||
v-show="waterMarkForm.isAddWatermark"
|
||||
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_WMPOSITION')"
|
||||
>
|
||||
<el-radio-group v-model="waterMarkForm.watermarkPosition">
|
||||
<el-radio v-for="item in waterMarkPositionMap" :key="item[0]" :value="item[0]">
|
||||
<el-radio
|
||||
v-for="item in waterMarkPositionMap"
|
||||
:key="item[0]"
|
||||
:value="item[0]"
|
||||
>
|
||||
{{ item[1] }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_ISREMOVEEXIF')">
|
||||
<el-switch v-model="compressForm.isRemoveExif" :style="switchStyle" />
|
||||
<el-switch
|
||||
v-model="compressForm.isRemoveExif"
|
||||
:style="switchStyle"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_QUALITY')">
|
||||
<el-input-number v-model="compressForm.quality" :min="1" :max="100" :step="1" />
|
||||
<el-input-number
|
||||
v-model="compressForm.quality"
|
||||
:min="1"
|
||||
:max="100"
|
||||
:step="1"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_ISCONVERT')">
|
||||
<el-switch v-model="compressForm.isConvert" :style="switchStyle" />
|
||||
<el-switch
|
||||
v-model="compressForm.isConvert"
|
||||
:style="switchStyle"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item v-show="compressForm.isConvert" :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_CONVERTFORMAT')">
|
||||
<el-select v-model="compressForm.convertFormat" :persistent="false" teleported>
|
||||
<el-option v-for="item in availableFormat" :key="item" :label="item" :value="item" />
|
||||
<el-form-item
|
||||
v-show="compressForm.isConvert"
|
||||
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_CONVERTFORMAT')"
|
||||
>
|
||||
<el-select
|
||||
v-model="compressForm.convertFormat"
|
||||
:persistent="false"
|
||||
teleported
|
||||
>
|
||||
<el-option
|
||||
v-for="item in availableFormat"
|
||||
:key="item"
|
||||
:label="item"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-show="compressForm.isConvert" :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_CONVERTFORMAT_SPECIFIC')">
|
||||
<el-form-item
|
||||
v-show="compressForm.isConvert"
|
||||
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_CONVERTFORMAT_SPECIFIC')"
|
||||
>
|
||||
<el-input
|
||||
v-model="formatConvertObj"
|
||||
placeholder='{"jpg": "png", "png": "jpg"}'
|
||||
placeholder="{"jpg": "png", "png": "jpg"}"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 2, maxRows: 4 }"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_ISFLIP')">
|
||||
<el-switch v-model="compressForm.isFlip" :style="switchStyle" />
|
||||
<el-switch
|
||||
v-model="compressForm.isFlip"
|
||||
:style="switchStyle"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_ISFLOP')">
|
||||
<el-switch v-model="compressForm.isFlop" :style="switchStyle" />
|
||||
<el-switch
|
||||
v-model="compressForm.isFlop"
|
||||
:style="switchStyle"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_ISRESIZE')">
|
||||
<el-switch v-model="compressForm.isReSize" :style="switchStyle" />
|
||||
<el-switch
|
||||
v-model="compressForm.isReSize"
|
||||
:style="switchStyle"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item v-show="compressForm.isReSize" :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_RESIZEWIDTH')">
|
||||
<el-input-number v-model="compressForm.reSizeWidth" :min="0" />
|
||||
<el-form-item
|
||||
v-show="compressForm.isReSize"
|
||||
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_RESIZEWIDTH')"
|
||||
>
|
||||
<el-input-number
|
||||
v-model="compressForm.reSizeWidth"
|
||||
:min="0"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item v-show="compressForm.isReSize" :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_RESIZEHEIGHT')">
|
||||
<el-input-number v-model="compressForm.reSizeHeight" :min="0" />
|
||||
<el-form-item
|
||||
v-show="compressForm.isReSize"
|
||||
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_RESIZEHEIGHT')"
|
||||
>
|
||||
<el-input-number
|
||||
v-model="compressForm.reSizeHeight"
|
||||
:min="0"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-show="compressForm.isReSize && compressForm.reSizeHeight! > 0 && compressForm.reSizeWidth === 0"
|
||||
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_SKIPRESIZEOfSMALLIMG_HEIGHT')"
|
||||
>
|
||||
<el-switch v-model="compressForm.skipReSizeOfSmallImg" :style="switchStyle" />
|
||||
<el-switch
|
||||
v-model="compressForm.skipReSizeOfSmallImg"
|
||||
:style="switchStyle"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-show="compressForm.isReSize && compressForm.reSizeWidth! > 0 && compressForm.reSizeHeight === 0"
|
||||
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_SKIPRESIZEOfSMALLIMG_WIDTH')"
|
||||
>
|
||||
<el-switch v-model="compressForm.skipReSizeOfSmallImg" :style="switchStyle" />
|
||||
<el-switch
|
||||
v-model="compressForm.skipReSizeOfSmallImg"
|
||||
:style="switchStyle"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_ISRESIZEBYPERCENT')">
|
||||
<el-switch v-model="compressForm.isReSizeByPercent" :style="switchStyle" />
|
||||
<el-switch
|
||||
v-model="compressForm.isReSizeByPercent"
|
||||
:style="switchStyle"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item v-show="compressForm.isReSizeByPercent" :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_RESIZEPERCENT')">
|
||||
<el-input-number v-model="compressForm.reSizePercent" :min="0" />
|
||||
<el-form-item
|
||||
v-show="compressForm.isReSizeByPercent"
|
||||
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_RESIZEPERCENT')"
|
||||
>
|
||||
<el-input-number
|
||||
v-model="compressForm.reSizePercent"
|
||||
:min="0"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_ISROTATE')">
|
||||
<el-switch v-model="compressForm.isRotate" :style="switchStyle" />
|
||||
<el-switch
|
||||
v-model="compressForm.isRotate"
|
||||
:style="switchStyle"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item v-show="compressForm.isRotate" :label="$T('UPLOAD_PAGE_IMAGE_PROCESS_ROTATEDEGREE')">
|
||||
<el-input-number v-model="compressForm.rotateDegree" :step="1" />
|
||||
<el-form-item
|
||||
v-show="compressForm.isRotate"
|
||||
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_ROTATEDEGREE')"
|
||||
>
|
||||
<el-input-number
|
||||
v-model="compressForm.rotateDegree"
|
||||
:step="1"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSaveConfig">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleSaveConfig"
|
||||
>
|
||||
{{ $T('UPLOAD_PAGE_IMAGE_PROCESS_CONFIRM') }}
|
||||
</el-button>
|
||||
<el-button @click="closeDialog">
|
||||
@@ -138,7 +252,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { IBuildInCompressOptions, IBuildInWaterMarkOptions } from 'piclist'
|
||||
import type { IBuildInCompressOptions, IBuildInWaterMarkOptions } from 'piclist'
|
||||
import { onBeforeMount, reactive, ref, toRaw } from 'vue'
|
||||
|
||||
import { T as $T } from '@/i18n/index'
|
||||
@@ -224,7 +338,7 @@ const skipProcessFormKeys = Object.keys(skipProcessForm) as (keyof typeof skipPr
|
||||
|
||||
const switchStyle = '--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949;'
|
||||
|
||||
function handleSaveConfig() {
|
||||
function handleSaveConfig () {
|
||||
let iformatConvertObj = {}
|
||||
try {
|
||||
iformatConvertObj = JSON.parse(formatConvertObj.value)
|
||||
@@ -242,7 +356,7 @@ function handleSaveConfig() {
|
||||
closeDialog()
|
||||
}
|
||||
|
||||
async function initData() {
|
||||
async function initData () {
|
||||
const compress = await getConfig<any>(configPaths.buildIn.compress)
|
||||
const watermark = await getConfig<any>(configPaths.buildIn.watermark)
|
||||
const skipProcess = await getConfig<any>(configPaths.buildIn.skipProcess)
|
||||
@@ -273,7 +387,7 @@ async function initData() {
|
||||
}
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
function closeDialog () {
|
||||
imageProcessDialogVisible.value = false
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,30 @@
|
||||
<template>
|
||||
<el-image :src="imageSource" fit="contain" style="height: 100px; width: 100%; margin: 0 auto">
|
||||
<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" />
|
||||
<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 { computed, onMounted, ref, watch } from 'vue'
|
||||
|
||||
import { getAuthHeader } from '@/manage/utils/digestAuth'
|
||||
import { getFileIconPath } from '@/manage/utils/common'
|
||||
|
||||
import { getAuthHeader } from '@/manage/utils/digestAuth'
|
||||
import { formatEndpoint } from '#/utils/common'
|
||||
|
||||
const base64Url = ref('')
|
||||
@@ -37,12 +44,12 @@ const props = defineProps<{
|
||||
const imageSource = computed(() => {
|
||||
return props.isShowThumbnail && props.item.isImage && success.value
|
||||
? base64Url.value
|
||||
: require(`../manage/pages/assets/icons/${getFileIconPath(props.item.fileName ?? '')}`)
|
||||
: `/assets/icons/${getFileIconPath(props.item.fileName ?? '')}`
|
||||
})
|
||||
|
||||
const iconPath = computed(() => require(`../manage/pages/assets/icons/${getFileIconPath(props.item.fileName ?? '')}`))
|
||||
const iconPath = computed(() => `/assets/icons/${getFileIconPath(props.item.fileName ?? '')}`)
|
||||
|
||||
async function getWebdavHeader(key: string) {
|
||||
async function getWebdavHeader (key: string) {
|
||||
let headers = {} as any
|
||||
if (props.config.authType === 'digest') {
|
||||
const authHeader = await getAuthHeader(
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { ElImage, ElIcon } from 'element-plus'
|
||||
import { defineComponent, ref, onMounted, watch, computed } from 'vue'
|
||||
import { Loading } from '@element-plus/icons-vue'
|
||||
import { ElIcon, ElImage } from 'element-plus'
|
||||
import { computed, defineComponent, onMounted, ref, watch } from 'vue'
|
||||
|
||||
import { getFileIconPath } from '@/manage/utils/common'
|
||||
import { getAuthHeader } from '@/manage/utils/digestAuth'
|
||||
|
||||
import { formatEndpoint } from '#/utils/common'
|
||||
|
||||
export default defineComponent({
|
||||
@@ -27,20 +26,20 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
setup (props) {
|
||||
const base64Url = ref('')
|
||||
const success = ref(false)
|
||||
|
||||
const imageSource = computed(() => {
|
||||
return props.isShowThumbnail && props.item.isImage && success.value
|
||||
? base64Url.value
|
||||
: require(`../manage/pages/assets/icons/${getFileIconPath(props.item.fileName ?? '')}`)
|
||||
: `/assets/icons/${getFileIconPath(props.item.fileName ?? '')}`
|
||||
})
|
||||
const iconPath = computed(() =>
|
||||
require(`../manage/pages/assets/icons/${getFileIconPath(props.item.fileName ?? '')}`)
|
||||
`/assets/icons/${getFileIconPath(props.item.fileName ?? '')}`
|
||||
)
|
||||
|
||||
async function getWebdavHeader(key: string) {
|
||||
async function getWebdavHeader (key: string) {
|
||||
let headers = {} as any
|
||||
if (props.config.authType === 'digest') {
|
||||
const authHeader = await getAuthHeader(
|
||||
|
||||
@@ -5,12 +5,22 @@
|
||||
:modal-append-to-body="false"
|
||||
append-to-body
|
||||
>
|
||||
<el-input v-model="inputBoxValue" :placeholder="inputBoxOptions.placeholder" />
|
||||
<el-input
|
||||
v-model="inputBoxValue"
|
||||
:placeholder="inputBoxOptions.placeholder"
|
||||
/>
|
||||
<template #footer>
|
||||
<el-button round @click="handleInputBoxCancel">
|
||||
<el-button
|
||||
round
|
||||
@click="handleInputBoxCancel"
|
||||
>
|
||||
{{ $T('CANCEL') }}
|
||||
</el-button>
|
||||
<el-button type="primary" round @click="handleInputBoxConfirm">
|
||||
<el-button
|
||||
type="primary"
|
||||
round
|
||||
@click="handleInputBoxConfirm"
|
||||
>
|
||||
{{ $T('CONFIRM') }}
|
||||
</el-button>
|
||||
</template>
|
||||
@@ -18,14 +28,13 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ipcRenderer, IpcRendererEvent } from 'electron'
|
||||
import { ref, reactive, onBeforeUnmount, onBeforeMount } from 'vue'
|
||||
import type { IpcRendererEvent } from 'electron'
|
||||
import { onBeforeMount, onBeforeUnmount, reactive, ref } from 'vue'
|
||||
|
||||
import { T as $T } from '@/i18n/index'
|
||||
import $bus from '@/utils/bus'
|
||||
import { sendToMain } from '@/utils/common'
|
||||
|
||||
import { SHOW_INPUT_BOX, SHOW_INPUT_BOX_RESPONSE } from '#/events/constants'
|
||||
import { IShowInputBoxOption } from '#/types/types'
|
||||
|
||||
const inputBoxValue = ref('')
|
||||
const showInputBoxVisible = ref(false)
|
||||
@@ -35,36 +44,36 @@ const inputBoxOptions = reactive({
|
||||
})
|
||||
|
||||
onBeforeMount(() => {
|
||||
ipcRenderer.on(SHOW_INPUT_BOX, ipcEventHandler)
|
||||
window.electron.ipcRendererOn(SHOW_INPUT_BOX, ipcEventHandler)
|
||||
$bus.on(SHOW_INPUT_BOX, initInputBoxValue)
|
||||
})
|
||||
|
||||
function ipcEventHandler(_: IpcRendererEvent, options: IShowInputBoxOption) {
|
||||
function ipcEventHandler (_: IpcRendererEvent, options: IShowInputBoxOption) {
|
||||
initInputBoxValue(options)
|
||||
}
|
||||
|
||||
function initInputBoxValue(options: IShowInputBoxOption) {
|
||||
function initInputBoxValue (options: IShowInputBoxOption) {
|
||||
inputBoxValue.value = options.value || ''
|
||||
inputBoxOptions.title = options.title || ''
|
||||
inputBoxOptions.placeholder = options.placeholder || ''
|
||||
showInputBoxVisible.value = true
|
||||
}
|
||||
|
||||
function handleInputBoxCancel() {
|
||||
function handleInputBoxCancel () {
|
||||
// TODO: RPCServer
|
||||
showInputBoxVisible.value = false
|
||||
sendToMain(SHOW_INPUT_BOX, '')
|
||||
window.electron.sendToMain(SHOW_INPUT_BOX, '')
|
||||
$bus.emit(SHOW_INPUT_BOX_RESPONSE, '')
|
||||
}
|
||||
|
||||
function handleInputBoxConfirm() {
|
||||
function handleInputBoxConfirm () {
|
||||
showInputBoxVisible.value = false
|
||||
sendToMain(SHOW_INPUT_BOX, inputBoxValue.value)
|
||||
window.electron.sendToMain(SHOW_INPUT_BOX, inputBoxValue.value)
|
||||
$bus.emit(SHOW_INPUT_BOX_RESPONSE, inputBoxValue.value)
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
ipcRenderer.removeListener(SHOW_INPUT_BOX, ipcEventHandler)
|
||||
window.electron.ipcRendererRemoveListener(SHOW_INPUT_BOX, ipcEventHandler)
|
||||
$bus.off(SHOW_INPUT_BOX)
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div class="toolbox-handler">
|
||||
<ElButton type="primary" :link="true" @click="() => props.handler(value)">
|
||||
<ElButton
|
||||
type="primary"
|
||||
:link="true"
|
||||
@click="() => props.handler(value)"
|
||||
>
|
||||
{{ props.handlerText }}
|
||||
</ElButton>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<el-icon :color="color" class="toolbox-status-icon">
|
||||
<el-icon
|
||||
:color="color"
|
||||
class="toolbox-status-icon"
|
||||
>
|
||||
<template v-if="props.status === IToolboxItemCheckStatus.SUCCESS">
|
||||
<SuccessFilled />
|
||||
</template>
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { IRPCActionType } from 'root/src/universal/types/enum'
|
||||
import { onMounted, onUnmounted } from 'vue'
|
||||
|
||||
import { sendRPC } from '@/utils/common'
|
||||
import { IRPCActionType } from 'root/src/universal/types/enum'
|
||||
|
||||
export function useATagClick() {
|
||||
export function useATagClick () {
|
||||
const handleATagClick = (e: MouseEvent) => {
|
||||
if (e.target instanceof HTMLAnchorElement) {
|
||||
if (e.target.href) {
|
||||
e.preventDefault()
|
||||
sendRPC(IRPCActionType.OPEN_URL, e.target.href)
|
||||
window.electron.sendRPC(IRPCActionType.OPEN_URL, e.target.href)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import { ipcRenderer } from 'electron'
|
||||
import { onUnmounted } from 'vue'
|
||||
|
||||
import { IRPCActionType } from '#/types/enum'
|
||||
|
||||
export const useIPCOn = (channel: string, listener: IpcRendererListener) => {
|
||||
ipcRenderer.on(channel, listener)
|
||||
|
||||
onUnmounted(() => {
|
||||
ipcRenderer.removeListener(channel, listener)
|
||||
})
|
||||
}
|
||||
|
||||
export const useIPCOnce = (channel: string, listener: IpcRendererListener) => {
|
||||
ipcRenderer.once(channel, listener)
|
||||
|
||||
onUnmounted(() => {
|
||||
ipcRenderer.removeListener(channel, listener)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* will auto removeListener when component unmounted
|
||||
*/
|
||||
export const useIPC = () => {
|
||||
return {
|
||||
on: (channel: IRPCActionType, listener: IpcRendererListener) => useIPCOn(channel, listener),
|
||||
once: (channel: IRPCActionType, listener: IpcRendererListener) => useIPCOnce(channel, listener)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { inject } from 'vue'
|
||||
|
||||
import { storeKey } from '@/store'
|
||||
|
||||
export const useStore = () => {
|
||||
|
||||
@@ -1,54 +1,45 @@
|
||||
import { ipcRenderer } from 'electron'
|
||||
import { ObjectAdapter, I18n } from '@picgo/i18n'
|
||||
|
||||
import { sendRPC, sendRpcSync } from '@/utils/common'
|
||||
import { ILocales, ILocalesKey } from 'root/src/universal/types/i18n'
|
||||
|
||||
import { updatePageReloadCount } from '@/utils/global'
|
||||
import { SET_CURRENT_LANGUAGE } from '#/events/constants'
|
||||
import { builtinI18nList } from '#/i18n'
|
||||
import { IRPCActionType } from '#/types/enum'
|
||||
import { updatePageReloadCount } from '@/utils/global'
|
||||
import { II18nItem, IStringKeyMap } from '#/types/types'
|
||||
|
||||
export class I18nManager {
|
||||
#i18n: I18n | null = null
|
||||
#i18nFileList: II18nItem[] = builtinI18nList
|
||||
|
||||
constructor() {
|
||||
constructor () {
|
||||
this.#getCurrentLanguage()
|
||||
this.#getLanguageList()
|
||||
ipcRenderer.on(SET_CURRENT_LANGUAGE, (_, lang: string, locales: ILocales) => {
|
||||
window.electron.ipcRendererOn(SET_CURRENT_LANGUAGE, (_, lang: string, locales: ILocales) => {
|
||||
this.#setLocales(lang, locales)
|
||||
updatePageReloadCount()
|
||||
})
|
||||
}
|
||||
|
||||
#getLanguageList() {
|
||||
this.#i18nFileList = sendRpcSync(IRPCActionType.GET_LANGUAGE_LIST)
|
||||
#getLanguageList () {
|
||||
this.#i18nFileList = window.electron.sendRpcSync(IRPCActionType.GET_LANGUAGE_LIST)
|
||||
}
|
||||
|
||||
#getCurrentLanguage() {
|
||||
const [lang, locales] = sendRpcSync(IRPCActionType.GET_CURRENT_LANGUAGE)
|
||||
#getCurrentLanguage () {
|
||||
const [lang, locales] = window.electron.sendRpcSync(IRPCActionType.GET_CURRENT_LANGUAGE)
|
||||
this.#setLocales(lang, locales)
|
||||
}
|
||||
|
||||
#setLocales(lang: string, locales: ILocales) {
|
||||
const objectAdapter = new ObjectAdapter({
|
||||
[lang]: locales
|
||||
})
|
||||
this.#i18n = new I18n({
|
||||
adapter: objectAdapter,
|
||||
defaultLanguage: lang
|
||||
})
|
||||
#setLocales (lang: string, locales: ILocales) {
|
||||
window.i18n.setLocales(lang, locales)
|
||||
}
|
||||
|
||||
T(key: ILocalesKey, args: IStringKeyMap = {}): string {
|
||||
return this.#i18n?.translate(key, args) || key
|
||||
T (key: ILocalesKey, args: IStringKeyMap = {}): string {
|
||||
return window.i18n?.translate(key, args) || key
|
||||
}
|
||||
|
||||
setCurrentLanguage(lang: string) {
|
||||
sendRPC(IRPCActionType.SET_CURRENT_LANGUAGE, lang)
|
||||
setCurrentLanguage (lang: string) {
|
||||
window.electron.sendRPC(IRPCActionType.SET_CURRENT_LANGUAGE, lang)
|
||||
}
|
||||
|
||||
get languageList() {
|
||||
get languageList () {
|
||||
return this.#i18nFileList
|
||||
}
|
||||
}
|
||||
|
||||
12
src/renderer/index.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>PicList</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="./main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,8 +1,13 @@
|
||||
<template>
|
||||
<div id="main-page">
|
||||
<div class="fake-title-bar">
|
||||
<div class="fake-title-bar__title">PicList - {{ version }}</div>
|
||||
<div v-if="osGlobal !== 'darwin'" class="handle-bar">
|
||||
<div class="fake-title-bar__title">
|
||||
PicList - {{ version }}
|
||||
</div>
|
||||
<div
|
||||
v-if="osGlobal !== 'darwin'"
|
||||
class="handle-bar"
|
||||
>
|
||||
<el-icon
|
||||
class="minus"
|
||||
:color="isAlwaysOnTop ? '#409EFF' : '#fff'"
|
||||
@@ -12,13 +17,30 @@
|
||||
>
|
||||
<ArrowUpBold />
|
||||
</el-icon>
|
||||
<el-icon class="minus" color="#fff" size="20" style="margin-right: 10px" @click="minimizeWindow">
|
||||
<el-icon
|
||||
class="minus"
|
||||
color="#fff"
|
||||
size="20"
|
||||
style="margin-right: 10px"
|
||||
@click="minimizeWindow"
|
||||
>
|
||||
<SemiSelect />
|
||||
</el-icon>
|
||||
<el-icon class="plus" color="orange" size="20" style="margin-right: 10px" @click="openMiniWindow">
|
||||
<el-icon
|
||||
class="plus"
|
||||
color="orange"
|
||||
size="20"
|
||||
style="margin-right: 10px"
|
||||
@click="openMiniWindow"
|
||||
>
|
||||
<ArrowDownBold />
|
||||
</el-icon>
|
||||
<el-icon class="close" color="#fff" size="20" @click="closeWindow">
|
||||
<el-icon
|
||||
class="close"
|
||||
color="#fff"
|
||||
size="20"
|
||||
@click="closeWindow"
|
||||
>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
@@ -32,9 +54,17 @@
|
||||
status="success"
|
||||
class="progress-bar"
|
||||
/>
|
||||
<el-row style="padding-top: 22px" class="main-content">
|
||||
<el-row
|
||||
style="padding-top: 22px"
|
||||
class="main-content"
|
||||
>
|
||||
<el-col class="side-bar-menu">
|
||||
<el-menu class="picgo-sidebar" :default-active="defaultActive" :unique-opened="true" @select="handleSelect">
|
||||
<el-menu
|
||||
class="picgo-sidebar"
|
||||
:default-active="defaultActive"
|
||||
:unique-opened="true"
|
||||
@select="handleSelect"
|
||||
>
|
||||
<el-menu-item :index="routerConfig.UPLOAD_PAGE">
|
||||
<el-icon>
|
||||
<UploadFilled />
|
||||
@@ -53,7 +83,12 @@
|
||||
</el-icon>
|
||||
<span>{{ $T('GALLERY') }}</span>
|
||||
</el-menu-item>
|
||||
<el-sub-menu index="sub-menu" :show-timeout="0" :hide-timeout="0" :popper-offset="0">
|
||||
<el-sub-menu
|
||||
index="sub-menu"
|
||||
:show-timeout="0"
|
||||
:hide-timeout="0"
|
||||
:popper-offset="0"
|
||||
>
|
||||
<template #title>
|
||||
<el-icon>
|
||||
<Menu />
|
||||
@@ -89,13 +124,24 @@
|
||||
<span>{{ $T('MANUAL') }}</span>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
<el-icon class="info-window" @click="openMenu">
|
||||
<el-icon
|
||||
class="info-window"
|
||||
@click="openMenu"
|
||||
>
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</el-col>
|
||||
<el-col :span="21" :offset="3" style="height: 100%" class="main-wrapper">
|
||||
<el-col
|
||||
:span="21"
|
||||
:offset="3"
|
||||
style="height: 100%"
|
||||
class="main-wrapper"
|
||||
>
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition name="picgo-fade" mode="out-in">
|
||||
<transition
|
||||
name="picgo-fade"
|
||||
mode="out-in"
|
||||
>
|
||||
<keep-alive :include="keepAlivePages">
|
||||
<component :is="Component" />
|
||||
</keep-alive>
|
||||
@@ -113,10 +159,25 @@
|
||||
lock-scroll
|
||||
append-to-body
|
||||
>
|
||||
<el-form label-position="left" label-width="70px" size="small">
|
||||
<el-form
|
||||
label-position="left"
|
||||
label-width="70px"
|
||||
size="small"
|
||||
>
|
||||
<el-form-item :label="$T('CHOOSE_PICBED')">
|
||||
<el-select v-model="choosedPicBedForQRCode" multiple collapse-tags :persistent="false" teleported>
|
||||
<el-option v-for="item in picBedGlobal" :key="item.type" :label="item.name" :value="item.type" />
|
||||
<el-select
|
||||
v-model="choosedPicBedForQRCode"
|
||||
multiple
|
||||
collapse-tags
|
||||
:persistent="false"
|
||||
teleported
|
||||
>
|
||||
<el-option
|
||||
v-for="item in picBedGlobal"
|
||||
:key="item.type"
|
||||
:label="item.name"
|
||||
:value="item.type"
|
||||
/>
|
||||
</el-select>
|
||||
<el-button
|
||||
v-show="choosedPicBedForQRCode.length > 0"
|
||||
@@ -130,7 +191,11 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="qrcode-container">
|
||||
<qrcode-vue v-show="choosedPicBedForQRCode.length > 0" :size="280" :value="picBedConfigString" />
|
||||
<qrcode-vue
|
||||
v-show="choosedPicBedForQRCode.length > 0"
|
||||
:size="280"
|
||||
:value="picBedConfigString"
|
||||
/>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<input-box-dialog />
|
||||
@@ -139,40 +204,37 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Tools,
|
||||
UploadFilled,
|
||||
PictureFilled,
|
||||
Menu,
|
||||
Share,
|
||||
InfoFilled,
|
||||
SemiSelect,
|
||||
ArrowDownBold,
|
||||
ArrowUpBold,
|
||||
CloseBold,
|
||||
PieChart,
|
||||
InfoFilled,
|
||||
Link,
|
||||
ArrowUpBold
|
||||
Menu,
|
||||
PictureFilled,
|
||||
PieChart,
|
||||
SemiSelect,
|
||||
Share,
|
||||
Tools,
|
||||
UploadFilled
|
||||
} from '@element-plus/icons-vue'
|
||||
import { ipcRenderer, IpcRendererEvent, clipboard } from 'electron'
|
||||
import type { IpcRendererEvent } from 'electron'
|
||||
import { ElMessage as $message, ElMessageBox } from 'element-plus'
|
||||
import pick from 'lodash/pick'
|
||||
import { pick } from 'lodash-es'
|
||||
import QrcodeVue from 'qrcode.vue'
|
||||
import { ref, onBeforeUnmount, Ref, onBeforeMount, watch, nextTick, reactive } from 'vue'
|
||||
import pkg from 'root/package.json'
|
||||
import { nextTick, onBeforeMount, onBeforeUnmount, reactive, Ref, ref, watch } from 'vue'
|
||||
import { onBeforeRouteUpdate, useRouter } from 'vue-router'
|
||||
|
||||
import InputBoxDialog from '@/components/InputBoxDialog.vue'
|
||||
import { T as $T } from '@/i18n/index'
|
||||
import * as config from '@/router/config'
|
||||
import { getConfig, saveConfig } from '@/utils/dataSender'
|
||||
import { sendRPC } from '@/utils/common'
|
||||
import { osGlobal, picBedGlobal, updatePicBedGlobal } from '@/utils/global'
|
||||
|
||||
import { SHOW_MAIN_PAGE_QRCODE } from '#/events/constants'
|
||||
import { configPaths, manualPageOpenType } from '#/utils/configPaths'
|
||||
import { II18nLanguage, IRPCActionType } from '#/types/enum'
|
||||
import { configPaths, manualPageOpenType } from '#/utils/configPaths'
|
||||
|
||||
import pkg from 'root/package.json'
|
||||
|
||||
const version = ref(process.env.NODE_ENV === 'production' ? pkg.version : 'Dev')
|
||||
const version = ref(pkg.version)
|
||||
const routerConfig = reactive(config)
|
||||
const defaultActive = ref(routerConfig.UPLOAD_PAGE)
|
||||
const $router = useRouter()
|
||||
@@ -188,15 +250,18 @@ const keepAlivePages = $router
|
||||
const isShowprogress = ref(false)
|
||||
const progress = ref(0)
|
||||
|
||||
const qrCodeHandler = () => {
|
||||
qrcodeVisible.value = true
|
||||
}
|
||||
|
||||
const uploadProcessHandler = (_event: IpcRendererEvent, data: { progress: number }) => {
|
||||
isShowprogress.value = data.progress !== 100 && data.progress !== 0
|
||||
progress.value = data.progress
|
||||
}
|
||||
onBeforeMount(() => {
|
||||
updatePicBedGlobal()
|
||||
ipcRenderer.on(SHOW_MAIN_PAGE_QRCODE, () => {
|
||||
qrcodeVisible.value = true
|
||||
})
|
||||
ipcRenderer.on('updateProgress', (_event: IpcRendererEvent, data: { progress: number }) => {
|
||||
isShowprogress.value = data.progress !== 100 && data.progress !== 0
|
||||
progress.value = data.progress
|
||||
})
|
||||
window.electron.ipcRendererOn(SHOW_MAIN_PAGE_QRCODE, qrCodeHandler)
|
||||
window.electron.ipcRendererOn('updateProgress', uploadProcessHandler)
|
||||
})
|
||||
|
||||
watch(
|
||||
@@ -218,9 +283,9 @@ const handleSelect = async (index: string) => {
|
||||
if (index === routerConfig.DocumentPage) {
|
||||
const manualPageOpenSetting = await getConfig<manualPageOpenType>(configPaths.settings.manualPageOpen)
|
||||
const lang = (await getConfig(configPaths.settings.language)) || II18nLanguage.ZH_CN
|
||||
const openManual = () => sendRPC(IRPCActionType.OPEN_MANUAL_WINDOW)
|
||||
const openManual = () => window.electron.sendRPC(IRPCActionType.OPEN_MANUAL_WINDOW)
|
||||
const openExternal = () =>
|
||||
sendRPC(
|
||||
window.electron.sendRPC(
|
||||
IRPCActionType.OPEN_URL,
|
||||
lang === II18nLanguage.ZH_CN ? 'https://piclist.cn/app.html' : 'https://piclist.cn/en/app.html'
|
||||
)
|
||||
@@ -261,30 +326,30 @@ const handleSelect = async (index: string) => {
|
||||
}
|
||||
}
|
||||
|
||||
function minimizeWindow() {
|
||||
sendRPC(IRPCActionType.MINIMIZE_WINDOW)
|
||||
function minimizeWindow () {
|
||||
window.electron.sendRPC(IRPCActionType.MINIMIZE_WINDOW)
|
||||
}
|
||||
|
||||
function closeWindow() {
|
||||
sendRPC(IRPCActionType.CLOSE_WINDOW)
|
||||
function closeWindow () {
|
||||
window.electron.sendRPC(IRPCActionType.CLOSE_WINDOW)
|
||||
}
|
||||
|
||||
function openMenu() {
|
||||
sendRPC(IRPCActionType.SHOW_MAIN_PAGE_MENU)
|
||||
function openMenu () {
|
||||
window.electron.sendRPC(IRPCActionType.SHOW_MAIN_PAGE_MENU)
|
||||
}
|
||||
|
||||
function openMiniWindow() {
|
||||
sendRPC(IRPCActionType.OPEN_MINI_WINDOW)
|
||||
function openMiniWindow () {
|
||||
window.electron.sendRPC(IRPCActionType.OPEN_MINI_WINDOW)
|
||||
}
|
||||
|
||||
function handleCopyPicBedConfig() {
|
||||
clipboard.writeText(picBedConfigString.value)
|
||||
function handleCopyPicBedConfig () {
|
||||
window.electron.clipboard.writeText(picBedConfigString.value)
|
||||
$message.success($T('COPY_PICBED_CONFIG_SUCCEED'))
|
||||
}
|
||||
|
||||
function setAlwaysOnTop() {
|
||||
function setAlwaysOnTop () {
|
||||
isAlwaysOnTop.value = !isAlwaysOnTop.value
|
||||
sendRPC(IRPCActionType.MAIN_WINDOW_ON_TOP)
|
||||
window.electron.sendRPC(IRPCActionType.MAIN_WINDOW_ON_TOP)
|
||||
}
|
||||
|
||||
onBeforeRouteUpdate(async to => {
|
||||
@@ -296,8 +361,8 @@ onBeforeRouteUpdate(async to => {
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
ipcRenderer.removeAllListeners(SHOW_MAIN_PAGE_QRCODE)
|
||||
ipcRenderer.removeAllListeners('updateProgress')
|
||||
window.electron.ipcRendererRemoveListener(SHOW_MAIN_PAGE_QRCODE, qrCodeHandler)
|
||||
window.electron.ipcRendererRemoveListener('updateProgress', uploadProcessHandler)
|
||||
})
|
||||
</script>
|
||||
<script lang="ts">
|
||||
|
||||
49
src/renderer/main.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import 'element-plus/dist/index.css'
|
||||
import 'vue3-photo-preview/dist/index.css'
|
||||
import 'video.js/dist/video-js.css'
|
||||
import 'highlight.js/styles/stackoverflow-light.css'
|
||||
import 'highlight.js/lib/common'
|
||||
|
||||
import hljsVuePlugin from '@highlightjs/vue-plugin'
|
||||
import VueVideoPlayer from '@videojs-player/vue'
|
||||
import ElementUI from 'element-plus'
|
||||
import { createPinia } from 'pinia'
|
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
||||
import { createApp } from 'vue'
|
||||
import VueLazyLoad from 'vue3-lazyload'
|
||||
import vue3PhotoPreview from 'vue3-photo-preview'
|
||||
|
||||
import App from '@/App.vue'
|
||||
import { T } from '@/i18n/index'
|
||||
import router from '@/router'
|
||||
import { store } from '@/store'
|
||||
import { initTalkingData } from '@/utils/analytic'
|
||||
import db from '@/utils/db'
|
||||
|
||||
window.electron.setVisualZoomLevelLimits(1, 1)
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.config.globalProperties.$$db = db
|
||||
app.config.globalProperties.$T = T
|
||||
app.config.globalProperties.triggerRPC = window.electron.triggerRPC
|
||||
app.config.globalProperties.sendRPC = window.electron.sendRPC
|
||||
app.config.globalProperties.sendToMain = window.electron.sendToMain
|
||||
|
||||
const pinia = createPinia()
|
||||
pinia.use(piniaPluginPersistedstate)
|
||||
app.use(VueLazyLoad, {
|
||||
loading: 'file://loading.jpg',
|
||||
error: 'file://unknown-file-type.svg',
|
||||
delay: 500
|
||||
})
|
||||
app.use(ElementUI)
|
||||
app.use(router)
|
||||
app.use(store)
|
||||
app.use(vue3PhotoPreview)
|
||||
app.use(pinia)
|
||||
app.use(hljsVuePlugin)
|
||||
app.use(VueVideoPlayer)
|
||||
app.mount('#app')
|
||||
|
||||
initTalkingData()
|
||||
@@ -2,10 +2,21 @@
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span style="position: absolute; left: 0">
|
||||
<span v-for="(segment, index) in segments" :key="index" :style="segment.style">
|
||||
<span
|
||||
v-for="(segment, index) in segments"
|
||||
:key="index"
|
||||
:style="segment.style"
|
||||
>
|
||||
{{ segment.text }}
|
||||
</span>
|
||||
<el-tooltip v-if="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>
|
||||
|
||||
@@ -16,9 +16,27 @@
|
||||
lazy
|
||||
>
|
||||
<el-row>
|
||||
<el-col v-for="item in sortedAllConfigAliasMap" :key="item" :xs="24" :sm="12" :md="8" :lg="6" :xl="4">
|
||||
<el-card class="box-card" style="margin: 10px 0" shadow="hover">
|
||||
<el-popover placement="top" :width="300" trigger="click" :persistent="false" teleported>
|
||||
<el-col
|
||||
v-for="item in sortedAllConfigAliasMap"
|
||||
:key="item"
|
||||
:xs="24"
|
||||
:sm="12"
|
||||
:md="8"
|
||||
:lg="6"
|
||||
:xl="4"
|
||||
>
|
||||
<el-card
|
||||
class="box-card"
|
||||
style="margin: 10px 0"
|
||||
shadow="hover"
|
||||
>
|
||||
<el-popover
|
||||
placement="top"
|
||||
:width="300"
|
||||
trigger="click"
|
||||
:persistent="false"
|
||||
teleported
|
||||
>
|
||||
<el-table
|
||||
:data="formObjToTableData(item.config)"
|
||||
style="width: 100%"
|
||||
@@ -26,8 +44,15 @@
|
||||
:header-cell-style="{ 'text-align': 'center' }"
|
||||
:cell-style="{ 'text-align': 'center' }"
|
||||
>
|
||||
<el-table-column prop="key" :label="$T('MANAGE_LOGIN_PAGE_PANE_KEY_NAME')" width="100" />
|
||||
<el-table-column prop="value" :label="$T('MANAGE_LOGIN_PAGE_PANE_KEY_VALUE')" />
|
||||
<el-table-column
|
||||
prop="key"
|
||||
:label="$T('MANAGE_LOGIN_PAGE_PANE_KEY_NAME')"
|
||||
width="100"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="value"
|
||||
:label="$T('MANAGE_LOGIN_PAGE_PANE_KEY_VALUE')"
|
||||
/>
|
||||
</el-table>
|
||||
<template #reference>
|
||||
<el-button
|
||||
@@ -40,7 +65,10 @@
|
||||
"
|
||||
>
|
||||
<template #icon>
|
||||
<img :src="require(`./assets/${item.picBedName}.webp`)" style="width: 25px; height: 25px" />
|
||||
<img
|
||||
:src="`/assets/${item.picBedName}.webp`"
|
||||
style="width: 25px; height: 25px"
|
||||
>
|
||||
</template>
|
||||
<el-tooltip
|
||||
effect="light"
|
||||
@@ -55,13 +83,23 @@
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popover>
|
||||
<br />
|
||||
<br />
|
||||
<br>
|
||||
<br>
|
||||
<el-button-group>
|
||||
<el-button type="primary" :icon="Pointer" plain @click="handleConfigClick(item)">
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Pointer"
|
||||
plain
|
||||
@click="handleConfigClick(item)"
|
||||
>
|
||||
{{ $T('MANAGE_LOGIN_PAGE_PANE_ENTER') }}
|
||||
</el-button>
|
||||
<el-button type="warning" :icon="Delete" plain @click="handleConfigRemove(item.alias)">
|
||||
<el-button
|
||||
type="warning"
|
||||
:icon="Delete"
|
||||
plain
|
||||
@click="handleConfigRemove(item.alias)"
|
||||
>
|
||||
{{ $T('MANAGE_LOGIN_PAGE_PANE_DELETE') }}
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
@@ -78,11 +116,23 @@
|
||||
lazy
|
||||
style="width: 100%; overflow-y: scroll; height: calc(100vh - 50px)"
|
||||
>
|
||||
<el-alert :title="item.explain" type="info" show-icon center :closable="false" />
|
||||
<el-alert center :closable="false">
|
||||
<el-alert
|
||||
:title="item.explain"
|
||||
type="info"
|
||||
show-icon
|
||||
center
|
||||
:closable="false"
|
||||
/>
|
||||
<el-alert
|
||||
center
|
||||
:closable="false"
|
||||
>
|
||||
<div>
|
||||
{{ item.referenceText }}
|
||||
<a style="color: blue; cursor: pointer" @click="handleReferenceClick(item.refLink)">{{ item.refLink }}</a>
|
||||
<a
|
||||
style="color: blue; cursor: pointer"
|
||||
@click="handleReferenceClick(item.refLink)"
|
||||
>{{ item.refLink }}</a>
|
||||
</div>
|
||||
</el-alert>
|
||||
<el-form
|
||||
@@ -156,20 +206,41 @@
|
||||
>
|
||||
{{ $T('MANAGE_LOGIN_PAGE_PANE_IMPORT') }}
|
||||
<template #dropdown>
|
||||
<el-dropdown-item v-for="i in currentAliasList" :key="i" @click="handleConfigImport(i)">
|
||||
<el-dropdown-item
|
||||
v-for="i in currentAliasList"
|
||||
:key="i"
|
||||
@click="handleConfigImport(i)"
|
||||
>
|
||||
{{ i }}
|
||||
</el-dropdown-item>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<el-button type="primary" style="margin-left: 10vw" :icon="Edit" plain @click="handleConfigChange(item.icon)">
|
||||
<el-button
|
||||
type="primary"
|
||||
style="margin-left: 10vw"
|
||||
:icon="Edit"
|
||||
plain
|
||||
@click="handleConfigChange(item.icon)"
|
||||
>
|
||||
{{ $T('MANAGE_LOGIN_PAGE_PANE_SAVE') }}
|
||||
</el-button>
|
||||
<el-button type="danger" style="margin-left: 10vw" :icon="Delete" plain @click="handleConfigReset(item.icon)">
|
||||
<el-button
|
||||
type="danger"
|
||||
style="margin-left: 10vw"
|
||||
:icon="Delete"
|
||||
plain
|
||||
@click="handleConfigReset(item.icon)"
|
||||
>
|
||||
{{ $T('MANAGE_LOGIN_PAGE_PANE_RESET') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<br />
|
||||
<el-alert :title="$T('MANAGE_LOGIN_PAGE_PANE_TABLE_TITLE')" type="success" center :closable="false" />
|
||||
<br>
|
||||
<el-alert
|
||||
:title="$T('MANAGE_LOGIN_PAGE_PANE_TABLE_TITLE')"
|
||||
type="success"
|
||||
center
|
||||
:closable="false"
|
||||
/>
|
||||
<el-table
|
||||
:data="dataForTable"
|
||||
style="width: 100%; margin-top: 10px"
|
||||
@@ -192,20 +263,19 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { shell } from 'electron'
|
||||
import { Delete, Edit, InfoFilled, Pointer } from '@element-plus/icons-vue'
|
||||
import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
|
||||
import { Delete, Edit, Pointer, InfoFilled } from '@element-plus/icons-vue'
|
||||
import { reactive, ref, onMounted, computed } from 'vue'
|
||||
import { computed, onMounted, reactive, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import { useManageStore } from '@/manage/store/manageStore'
|
||||
import { supportedPicBedList } from '@/manage/utils/constants'
|
||||
import { getConfig, saveConfig, removeConfig } from '@/manage/utils/dataSender'
|
||||
import { formObjToTableData } from '@/manage/utils/common'
|
||||
|
||||
import { getConfig as getPicBedsConfig } from '@/utils/dataSender'
|
||||
import { T as $T } from '@/i18n'
|
||||
|
||||
import { useManageStore } from '@/manage/store/manageStore'
|
||||
import { formObjToTableData } from '@/manage/utils/common'
|
||||
import { supportedPicBedList } from '@/manage/utils/constants'
|
||||
import { getConfig, removeConfig, saveConfig } from '@/manage/utils/dataSender'
|
||||
import { getConfig as getPicBedsConfig } from '@/utils/dataSender'
|
||||
import { IRPCActionType } from '#/types/enum'
|
||||
import { IStringKeyMap, IUploaderConfigListItem } from '#/types/types'
|
||||
import { formatEndpoint, isNeedToShorten, safeSliceF } from '#/utils/common'
|
||||
|
||||
const manageStore = useManageStore()
|
||||
@@ -228,7 +298,7 @@ const sortedAllConfigAliasMap = computed(() => {
|
||||
|
||||
const importedNewConfig: IStringKeyMap = {}
|
||||
|
||||
function ruleMap(options: IStringKeyMap) {
|
||||
function ruleMap (options: IStringKeyMap) {
|
||||
const rule: any = {}
|
||||
Object.keys(options).forEach(key => {
|
||||
const item = options[key].options
|
||||
@@ -246,13 +316,13 @@ function ruleMap(options: IStringKeyMap) {
|
||||
return rule
|
||||
}
|
||||
|
||||
function getDataForTable() {
|
||||
function getDataForTable () {
|
||||
for (const key in existingConfiguration) {
|
||||
dataForTable.push({ ...(existingConfiguration[key] as IStringKeyMap) })
|
||||
}
|
||||
}
|
||||
|
||||
async function getExistingConfig(name: string) {
|
||||
async function getExistingConfig (name: string) {
|
||||
if (name === 'login') {
|
||||
getAllConfigAliasArray()
|
||||
return
|
||||
@@ -278,11 +348,11 @@ async function getExistingConfig(name: string) {
|
||||
handleConfigImport(currentAliasList[0])
|
||||
}
|
||||
|
||||
function getAliasList() {
|
||||
function getAliasList () {
|
||||
return Object.values(existingConfiguration).map(item => item.alias)
|
||||
}
|
||||
|
||||
async function handleConfigChange(name: string) {
|
||||
async function handleConfigChange (name: string) {
|
||||
const aliasList = getAliasList()
|
||||
const allKeys = Object.keys(supportedPicBedList[name].configOptions)
|
||||
const resultMap: IStringKeyMap = {}
|
||||
@@ -456,7 +526,7 @@ const handleCellClick = (row: any, column: any) => {
|
||||
ElMessage.success(`${$T('MANAGE_LOGIN_PAGE_PANE_CONFIG_CHANGE_COPY_SUCCESS')}${row[column.property]}`)
|
||||
}
|
||||
|
||||
const handleReferenceClick = (url: string) => shell.openExternal(url)
|
||||
const handleReferenceClick = (url: string) => window.electron.sendRPC(IRPCActionType.OPEN_URL, url)
|
||||
|
||||
const handleConfigClick = async (item: any) => {
|
||||
const alias = item.alias
|
||||
@@ -474,7 +544,7 @@ const handleConfigClick = async (item: any) => {
|
||||
})
|
||||
}
|
||||
|
||||
function handleConfigImport(alias: string) {
|
||||
function handleConfigImport (alias: string) {
|
||||
const selectedConfig = existingConfiguration[alias]
|
||||
if (!selectedConfig) return
|
||||
|
||||
@@ -485,7 +555,7 @@ function handleConfigImport(alias: string) {
|
||||
})
|
||||
}
|
||||
|
||||
async function getCurrentConfigList() {
|
||||
async function getCurrentConfigList () {
|
||||
await manageStore.refreshConfig()
|
||||
const configList = (await getPicBedsConfig<any>('uploader')) ?? {}
|
||||
const pbList = [
|
||||
@@ -526,18 +596,18 @@ async function getCurrentConfigList() {
|
||||
await getAllConfigAliasArray()
|
||||
}
|
||||
|
||||
function isImported(alias: string) {
|
||||
function isImported (alias: string) {
|
||||
return Object.values(allConfigAliasMap).some(item => item.alias === alias)
|
||||
}
|
||||
|
||||
function initArray(arrayT: string | string[], defaultValue: string[]) {
|
||||
function initArray (arrayT: string | string[], defaultValue: string[]) {
|
||||
if (!Array.isArray(arrayT)) {
|
||||
arrayT = arrayT ? [arrayT] : defaultValue
|
||||
}
|
||||
return arrayT
|
||||
}
|
||||
|
||||
async function transUpToManage(config: IUploaderConfigListItem, picBedName: string, autoImportPicBed: string[]) {
|
||||
async function transUpToManage (config: IUploaderConfigListItem, picBedName: string, autoImportPicBed: string[]) {
|
||||
const alias = `${
|
||||
picBedName === 'webdavplist'
|
||||
? 'webdav'
|
||||
|
||||
@@ -2,15 +2,22 @@
|
||||
<div class="layout">
|
||||
<div class="layout__menu">
|
||||
<div class="layout__menu__button">
|
||||
<span class="layout__menu__button__item" @click="openPicBedUrl">
|
||||
<span
|
||||
class="layout__menu__button__item"
|
||||
@click="openPicBedUrl"
|
||||
>
|
||||
<img
|
||||
:src="require(`./assets/${currentPagePicBedConfig.picBedName}.webp`)"
|
||||
:src="`/assets/${currentPagePicBedConfig.picBedName}.webp`"
|
||||
class="layout__menu__button__item__icon"
|
||||
/>
|
||||
>
|
||||
{{ supportedPicBedList[currentPagePicBedConfig.picBedName].name }}
|
||||
</span>
|
||||
</div>
|
||||
<el-divider content-position="left" class="layout__menu__button__divider" border-style="none">
|
||||
<el-divider
|
||||
content-position="left"
|
||||
class="layout__menu__button__divider"
|
||||
border-style="none"
|
||||
>
|
||||
<span style="font-size: 14px; color: #909399">
|
||||
{{ menuTitleMap[currentPicBedName] }}
|
||||
<el-tooltip
|
||||
@@ -42,7 +49,11 @@
|
||||
active-text-color="#409EFF"
|
||||
@select="handleSelectMenu"
|
||||
>
|
||||
<el-menu-item v-for="item of bucketNameList" :key="item" :index="item">
|
||||
<el-menu-item
|
||||
v-for="item of bucketNameList"
|
||||
:key="item"
|
||||
:index="item"
|
||||
>
|
||||
<span
|
||||
class="layout__menu__list__item"
|
||||
:style="{
|
||||
@@ -77,8 +88,15 @@
|
||||
</span>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
<el-menu class="layout__menu__setting" style="width: 120px">
|
||||
<el-menu-item index="changePicBed" style="height: 40px" @click="switchPicBed('main')">
|
||||
<el-menu
|
||||
class="layout__menu__setting"
|
||||
style="width: 120px"
|
||||
>
|
||||
<el-menu-item
|
||||
index="changePicBed"
|
||||
style="height: 40px"
|
||||
@click="switchPicBed('main')"
|
||||
>
|
||||
<span class="layout__menu__setting__item">
|
||||
<el-icon class="layout__menu__setting__item__icon">
|
||||
<HomeFilled />
|
||||
@@ -86,7 +104,11 @@
|
||||
{{ $T('MANAGE_MAIN_PAGE_BACK_TO_HOME') }}
|
||||
</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="changePicBed" style="height: 40px" @click="changePicBed">
|
||||
<el-menu-item
|
||||
index="changePicBed"
|
||||
style="height: 40px"
|
||||
@click="changePicBed"
|
||||
>
|
||||
<span class="layout__menu__setting__item">
|
||||
<el-icon class="layout__menu__setting__item__icon">
|
||||
<Switch />
|
||||
@@ -94,7 +116,11 @@
|
||||
{{ $T('MANAGE_MAIN_PAGE_SWITCH_PICBED') }}
|
||||
</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="bucketPageSetting" style="height: 40px" @click="openBucketPageSetting">
|
||||
<el-menu-item
|
||||
index="bucketPageSetting"
|
||||
style="height: 40px"
|
||||
@click="openBucketPageSetting"
|
||||
>
|
||||
<span class="layout__menu__setting__item">
|
||||
<el-icon class="layout__menu__setting__item__icon">
|
||||
<Tools />
|
||||
@@ -104,17 +130,31 @@
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
</div>
|
||||
<div class="layout__content" style="height: 100%; background-color: transparent; flex: 1; width: 0">
|
||||
<div
|
||||
class="layout__content"
|
||||
style="height: 100%; background-color: transparent; flex: 1; width: 0"
|
||||
>
|
||||
<router-view />
|
||||
</div>
|
||||
<el-dialog v-model="picBedSwitchDialogVisible" top="30vh" append-to-body>
|
||||
<el-dialog
|
||||
v-model="picBedSwitchDialogVisible"
|
||||
top="30vh"
|
||||
append-to-body
|
||||
>
|
||||
<div
|
||||
class="choice-cos"
|
||||
style="display: flex; flex-direction: row; flex-wrap: wrap; justify-content: space-around"
|
||||
>
|
||||
<el-card shadow="hover">
|
||||
<div style="text-align: center; display: flex; flex-direction: column" @click="switchPicBed('main')">
|
||||
<el-icon color="red" size="25px" style="margin: 0 auto">
|
||||
<div
|
||||
style="text-align: center; display: flex; flex-direction: column"
|
||||
@click="switchPicBed('main')"
|
||||
>
|
||||
<el-icon
|
||||
color="red"
|
||||
size="25px"
|
||||
style="margin: 0 auto"
|
||||
>
|
||||
<ChromeFilled />
|
||||
</el-icon>
|
||||
<span style="font-size: 13px; margin-top: 5px; color: red">
|
||||
@@ -122,10 +162,17 @@
|
||||
</span>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card v-for="item in allPicBedConfigure" :key="item" shadow="hover">
|
||||
<div style="text-align: center; display: flex; flex-direction: column" @click="switchPicBed(item.alias)">
|
||||
<el-card
|
||||
v-for="item in allPicBedConfigure"
|
||||
:key="item"
|
||||
shadow="hover"
|
||||
>
|
||||
<div
|
||||
style="text-align: center; display: flex; flex-direction: column"
|
||||
@click="switchPicBed(item.alias)"
|
||||
>
|
||||
<el-image
|
||||
:src="require(`./assets/${item.picBedName}.webp`)"
|
||||
:src="`/assets/${item.picBedName}.webp`"
|
||||
class="layout__addNewBucket__icon"
|
||||
style="width: 25px; height: 25px; margin: 0 auto"
|
||||
/>
|
||||
@@ -136,7 +183,11 @@
|
||||
</el-card>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-drawer v-model="nweBucketDrawerVisible" class="layout__addNewBucket" append-to-body>
|
||||
<el-drawer
|
||||
v-model="nweBucketDrawerVisible"
|
||||
class="layout__addNewBucket"
|
||||
append-to-body
|
||||
>
|
||||
<el-form
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
@@ -147,7 +198,7 @@
|
||||
>
|
||||
<div style="position: relative; height: 10vh; width: 100%">
|
||||
<el-image
|
||||
:src="require(`./assets/${currentPicBedName}.webp`)"
|
||||
:src="`/assets/${currentPicBedName}.webp`"
|
||||
class="layout__addNewBucket__icon"
|
||||
style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%)"
|
||||
/>
|
||||
@@ -162,7 +213,7 @@
|
||||
<el-input
|
||||
v-if="
|
||||
newBucketConfig[currentPicBedName].configOptions[option].component === 'input' &&
|
||||
currentPicBedName !== 'tcyun'
|
||||
currentPicBedName !== 'tcyun'
|
||||
"
|
||||
v-model.trim="newBucketConfigResult[currentPicBedName + '.' + option]"
|
||||
:placeholder="newBucketConfig[currentPicBedName].configOptions[option].placeholder"
|
||||
@@ -170,7 +221,7 @@
|
||||
<el-input
|
||||
v-if="
|
||||
currentPicBedName === 'tcyun' &&
|
||||
newBucketConfig[currentPicBedName].configOptions[option].component === 'input'
|
||||
newBucketConfig[currentPicBedName].configOptions[option].component === 'input'
|
||||
"
|
||||
v-model.trim="newBucketConfigResult[currentPicBedName + '.' + option]"
|
||||
:placeholder="newBucketConfig[currentPicBedName].configOptions[option].placeholder"
|
||||
@@ -216,29 +267,27 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { shell } from 'electron'
|
||||
import { ElNotification } from 'element-plus'
|
||||
import {
|
||||
CirclePlus,
|
||||
SuccessFilled,
|
||||
Folder,
|
||||
Switch,
|
||||
Tools,
|
||||
ChromeFilled,
|
||||
HomeFilled,
|
||||
FolderOpened
|
||||
} from '@element-plus/icons-vue'
|
||||
import path from 'path'
|
||||
import { ref, reactive, computed, onBeforeMount, watch } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
|
||||
import { supportedPicBedList } from '@/manage/utils/constants'
|
||||
import { useManageStore } from '@/manage/store/manageStore'
|
||||
import { newBucketConfig } from '@/manage/utils/newBucketConfig'
|
||||
import {
|
||||
ChromeFilled,
|
||||
CirclePlus,
|
||||
Folder,
|
||||
FolderOpened,
|
||||
HomeFilled,
|
||||
SuccessFilled,
|
||||
Switch,
|
||||
Tools
|
||||
} from '@element-plus/icons-vue'
|
||||
import { ElNotification } from 'element-plus'
|
||||
import { IRPCActionType } from 'root/src/universal/types/enum'
|
||||
import { computed, onBeforeMount, reactive, ref, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
import { T as $T } from '@/i18n'
|
||||
import { triggerRPC } from '@/utils/common'
|
||||
import { IRPCActionType } from 'root/src/universal/types/enum'
|
||||
import { useManageStore } from '@/manage/store/manageStore'
|
||||
import { supportedPicBedList } from '@/manage/utils/constants'
|
||||
import { newBucketConfig } from '@/manage/utils/newBucketConfig'
|
||||
import { IStringKeyMap } from '#/types/types'
|
||||
|
||||
const manageStore = useManageStore() as any
|
||||
const route = useRoute()
|
||||
@@ -307,9 +356,9 @@ const menuTitleMap: IStringKeyMap = {
|
||||
|
||||
const rules = ruleMap(newBucketConfig)
|
||||
|
||||
const openPicBedUrl = () => shell.openExternal(urlMap[currentPagePicBedConfig.picBedName])
|
||||
const openPicBedUrl = () => window.electron.sendRPC(IRPCActionType.OPEN_URL, urlMap[currentPagePicBedConfig.picBedName])
|
||||
|
||||
function ruleMap(options: IStringKeyMap) {
|
||||
function ruleMap (options: IStringKeyMap) {
|
||||
return Object.keys(options).reduce((result, key) => {
|
||||
options[key].options.forEach((option: string) => {
|
||||
const keyName = `${key}.${option}`
|
||||
@@ -325,11 +374,11 @@ function ruleMap(options: IStringKeyMap) {
|
||||
}, {} as IStringKeyMap)
|
||||
}
|
||||
|
||||
function openNewBucketDrawer() {
|
||||
function openNewBucketDrawer () {
|
||||
nweBucketDrawerVisible.value = true
|
||||
}
|
||||
|
||||
function createNewBucket(picBedName: string) {
|
||||
function createNewBucket (picBedName: string) {
|
||||
const configOptions = newBucketConfig[picBedName].configOptions
|
||||
const resultMap: IStringKeyMap = Object.keys(configOptions).reduce((result, key) => {
|
||||
const resultKey = `${picBedName}.${key}`
|
||||
@@ -349,7 +398,7 @@ function createNewBucket(picBedName: string) {
|
||||
resultMap.BucketName = `${resultMap.BucketName}-${currentPagePicBedConfig.appId}`
|
||||
}
|
||||
resultMap.endpoint = currentPagePicBedConfig.endpoint
|
||||
triggerRPC(IRPCActionType.MANAGE_CREATE_BUCKET, currentAlias, resultMap).then((result: any) => {
|
||||
window.electron.triggerRPC(IRPCActionType.MANAGE_CREATE_BUCKET, currentAlias, resultMap).then((result: any) => {
|
||||
if (result) {
|
||||
ElNotification({
|
||||
title: $T('MANAGE_MAIN_PAGE_TIPS'),
|
||||
@@ -370,12 +419,12 @@ function createNewBucket(picBedName: string) {
|
||||
})
|
||||
}
|
||||
|
||||
async function getBucketList() {
|
||||
async function getBucketList () {
|
||||
bucketList.value = {}
|
||||
bucketNameList.value = []
|
||||
isLoadingBucketList.value = true
|
||||
|
||||
const result = await triggerRPC<any>(IRPCActionType.MANAGE_GET_BUCKET_LIST, currentAlias.value)
|
||||
const result = await window.electron.triggerRPC<any>(IRPCActionType.MANAGE_GET_BUCKET_LIST, currentAlias.value)
|
||||
isLoadingBucketList.value = false
|
||||
|
||||
if (result.length > 0) {
|
||||
@@ -386,17 +435,17 @@ async function getBucketList() {
|
||||
}
|
||||
}
|
||||
|
||||
function transPathToUnix(filePath: string | undefined) {
|
||||
function transPathToUnix (filePath: string | undefined) {
|
||||
if (!filePath) return ''
|
||||
return process.platform === 'win32'
|
||||
return window.electron.sendRpcSync(IRPCActionType.GET_PLATFORM) === 'win32'
|
||||
? filePath
|
||||
.split(path.sep)
|
||||
.join(path.posix.sep)
|
||||
.split(window.node.path.sep)
|
||||
.join(window.node.path.posix.sep)
|
||||
.replace(/^\/+|\/+$/g, '')
|
||||
: filePath.replace(/^\/+|\/+$/g, '')
|
||||
}
|
||||
|
||||
function handleSelectMenu(bucketName: string) {
|
||||
function handleSelectMenu (bucketName: string) {
|
||||
const currentPicBedConfig = manageStore.config.picBed[currentAlias.value]
|
||||
const transformedConfig = JSON.parse(currentPicBedConfig.transformedConfig ?? '{}')
|
||||
|
||||
@@ -429,7 +478,7 @@ function handleSelectMenu(bucketName: string) {
|
||||
})
|
||||
}
|
||||
|
||||
function switchPicBed(picBedAlias: string) {
|
||||
function switchPicBed (picBedAlias: string) {
|
||||
if (picBedAlias === 'main') {
|
||||
router.push({
|
||||
path: '/main-page/manage-login-page'
|
||||
@@ -460,11 +509,11 @@ function switchPicBed(picBedAlias: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function changePicBed() {
|
||||
function changePicBed () {
|
||||
picBedSwitchDialogVisible.value = true
|
||||
}
|
||||
|
||||
function openBucketPageSetting() {
|
||||
function openBucketPageSetting () {
|
||||
router.push({
|
||||
path: '/main-page/manage-main-page/manage-setting-page'
|
||||
})
|
||||
|
||||
@@ -1,12 +1,25 @@
|
||||
<template>
|
||||
<div id="manage-setting">
|
||||
<el-row class="view-title" align="middle" justify="center" style="font-size: 20px; color: black">
|
||||
<el-row
|
||||
class="view-title"
|
||||
align="middle"
|
||||
justify="center"
|
||||
style="font-size: 20px; color: black"
|
||||
>
|
||||
{{ $T('MANAGE_SETTING_TITLE') }}
|
||||
</el-row>
|
||||
<el-row class="setting-list">
|
||||
<el-col :span="20" :offset="2">
|
||||
<el-col
|
||||
:span="20"
|
||||
:offset="2"
|
||||
>
|
||||
<el-row style="width: 100%">
|
||||
<el-form label-position="left" label-width="50%" size="default" style="position: relative; width: 100%">
|
||||
<el-form
|
||||
label-position="left"
|
||||
label-width="50%"
|
||||
size="default"
|
||||
style="position: relative; width: 100%"
|
||||
>
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span style="position: absolute; left: 0">
|
||||
@@ -37,7 +50,11 @@
|
||||
@confirm="handleClearDb"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button type="primary" plain style="position: absolute; right: 0">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
style="position: absolute; right: 0"
|
||||
>
|
||||
{{ $T('MANAGE_SETTING_CLEAR_CACHE_BUTTON') }}
|
||||
</el-button>
|
||||
</template>
|
||||
@@ -82,7 +99,7 @@
|
||||
width="150"
|
||||
/>
|
||||
</el-table>
|
||||
<br v-if="form.customRename" />
|
||||
<br v-if="form.customRename">
|
||||
<DynamicSwitch
|
||||
v-for="item in switchFieldsSpecialList"
|
||||
:key="item.configName"
|
||||
@@ -142,12 +159,19 @@
|
||||
:step="1"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-link style="margin-top: 10px; margin-bottom: 10px; color: #409eff" :underline="false">
|
||||
<el-link
|
||||
style="margin-top: 10px; margin-bottom: 10px; color: #409eff"
|
||||
:underline="false"
|
||||
>
|
||||
{{ $T('MANAGE_SETTING_CHOOSE_COPY_FORMAT_TITLE') }}
|
||||
</el-link>
|
||||
<br />
|
||||
<br>
|
||||
<el-radio-group v-model="form.pasteFormat">
|
||||
<el-radio v-for="item in pasteFormatList" :key="item" :value="item">
|
||||
<el-radio
|
||||
v-for="item in pasteFormatList"
|
||||
:key="item"
|
||||
:value="item"
|
||||
>
|
||||
{{ $T(`MANAGE_SETTING_CHOOSE_COPY_FORMAT_${item.toUpperCase().replace(/-/g, '_')}` as any) }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
@@ -165,7 +189,10 @@
|
||||
style="width: 100%"
|
||||
/>
|
||||
<div>
|
||||
<el-link style="margin-top: 10px; margin-bottom: 10px; color: #409eff" :underline="false">
|
||||
<el-link
|
||||
style="margin-top: 10px; margin-bottom: 10px; color: #409eff"
|
||||
:underline="false"
|
||||
>
|
||||
{{ $T('MANAGE_SETTING_CHOOSE_DOWNLOAD_FOLDER_TITLE') }}
|
||||
</el-link>
|
||||
</div>
|
||||
@@ -176,7 +203,10 @@
|
||||
style="width: 100%; margin-top: 10px"
|
||||
>
|
||||
<template #append>
|
||||
<el-button type="primary" @click="handleDownloadDirClick">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleDownloadDirClick"
|
||||
>
|
||||
<el-icon>
|
||||
<Folder />
|
||||
</el-icon>
|
||||
@@ -193,19 +223,17 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Folder, InfoFilled } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { InfoFilled, Folder } from '@element-plus/icons-vue'
|
||||
import { ref, onBeforeMount, watch } from 'vue'
|
||||
|
||||
import DynamicSwitch from '@/manage/components/DynamicSwitch.vue'
|
||||
import { fileCacheDbInstance } from '@/manage/store/bucketFileDb'
|
||||
import { formatFileSize, customRenameFormatTable } from '@/manage/utils/common'
|
||||
import { getConfig, saveConfig } from '@/manage/utils/dataSender'
|
||||
import { IRPCActionType } from 'root/src/universal/types/enum'
|
||||
import { onBeforeMount, ref, watch } from 'vue'
|
||||
|
||||
import { T as $T } from '@/i18n'
|
||||
|
||||
import { triggerRPC } from '@/utils/common'
|
||||
import { IRPCActionType } from 'root/src/universal/types/enum'
|
||||
import DynamicSwitch from '@/manage/components/DynamicSwitch.vue'
|
||||
import { fileCacheDbInstance } from '@/manage/store/bucketFileDb'
|
||||
import { customRenameFormatTable, formatFileSize } from '@/manage/utils/common'
|
||||
import { getConfig, saveConfig } from '@/manage/utils/dataSender'
|
||||
import { IStringKeyMap } from '#/types/types'
|
||||
|
||||
const form = ref<IStringKeyMap>({
|
||||
timestampRename: false,
|
||||
@@ -315,15 +343,15 @@ const switchFieldsSpecialList = [
|
||||
}
|
||||
]
|
||||
|
||||
async function initData() {
|
||||
async function initData () {
|
||||
const config = (await getConfig()) as IStringKeyMap
|
||||
settingsKeys.forEach(key => {
|
||||
form.value[key] = config.settings[key] ?? form.value[key]
|
||||
})
|
||||
}
|
||||
|
||||
async function handleDownloadDirClick() {
|
||||
const result = await triggerRPC<any>(IRPCActionType.MANAGE_SELECT_DOWNLOAD_FOLDER)
|
||||
async function handleDownloadDirClick () {
|
||||
const result = await window.electron.triggerRPC<any>(IRPCActionType.MANAGE_SELECT_DOWNLOAD_FOLDER)
|
||||
if (result) {
|
||||
form.value.downloadDir = result
|
||||
}
|
||||
@@ -334,7 +362,7 @@ const handleCellClick = (row: any, column: any) => {
|
||||
ElMessage.success(`${$T('MANAGE_SETTING_COPY_MESSAGE')}${row[column.property]}`)
|
||||
}
|
||||
|
||||
function handleClearDb() {
|
||||
function handleClearDb () {
|
||||
fileCacheDbInstance
|
||||
.delete()
|
||||
.then(() => {
|
||||
@@ -346,7 +374,7 @@ function handleClearDb() {
|
||||
})
|
||||
}
|
||||
|
||||
async function getIndexDbSize() {
|
||||
async function getIndexDbSize () {
|
||||
const size = (await navigator.storage.estimate()).usage ?? 0
|
||||
const quota = (await navigator.storage.estimate()).quota ?? 0
|
||||
dbSize.value = size
|
||||
|
||||
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 7.5 KiB |