🐛 Fix(custom): fix titlebar in macos

This commit is contained in:
Kuingsmile
2025-08-14 14:25:20 +08:00
parent 3ebbeb4dc7
commit 9d4e280b3d
9 changed files with 316 additions and 317 deletions

View File

@@ -1,90 +1,89 @@
import { dbPathChecker } from '@core/datastore/dbChecker' import { dbPathChecker } from '@core/datastore/dbChecker'
import axios, { AxiosRequestConfig } from 'axios' import axios, { AxiosRequestConfig } from 'axios'
import fs from 'fs-extra' import fs from 'fs-extra'
import { IConfig } from 'piclist' import { IConfig } from 'piclist'
import tunnel from 'tunnel' import tunnel from 'tunnel'
import type { IToolboxCheckerMap } from '#/types/rpc' import type { IToolboxCheckerMap } from '#/types/rpc'
import { sendToolboxResWithType } from '~/events/rpc/routes/toolbox/utils' import { sendToolboxResWithType } from '~/events/rpc/routes/toolbox/utils'
import { T as $t } from '~/i18n' import { T as $t } from '~/i18n'
import { IToolboxItemCheckStatus, IToolboxItemType } from '~/utils/enum' import { IToolboxItemCheckStatus, IToolboxItemType } from '~/utils/enum'
function getProxy (proxyStr: string): AxiosRequestConfig['proxy'] | null { function getProxy (proxyStr: string): AxiosRequestConfig['proxy'] | null {
if (proxyStr) { if (proxyStr) {
try { try {
const proxyOptions = new URL(proxyStr) const proxyOptions = new URL(proxyStr)
return { return {
host: proxyOptions.hostname, host: proxyOptions.hostname,
port: parseInt(proxyOptions.port || '0', 10), port: parseInt(proxyOptions.port || '0', 10),
protocol: proxyOptions.protocol protocol: proxyOptions.protocol
} }
} catch (e) {} } catch (e) {}
} }
return null return null
} }
const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.HAS_PROBLEM_WITH_PROXY) const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.HAS_PROBLEM_WITH_PROXY)
export const checkProxyMap: IToolboxCheckerMap<string> = { export const checkProxyMap: IToolboxCheckerMap<string> = {
[IToolboxItemType.HAS_PROBLEM_WITH_PROXY]: async event => { [IToolboxItemType.HAS_PROBLEM_WITH_PROXY]: async event => {
sendToolboxRes(event, { sendToolboxRes(event, {
status: IToolboxItemCheckStatus.LOADING status: IToolboxItemCheckStatus.LOADING
}) })
const configFilePath = dbPathChecker() const configFilePath = dbPathChecker()
if (fs.existsSync(configFilePath)) { if (fs.existsSync(configFilePath)) {
let config: IConfig | undefined let config: IConfig | undefined
try { try {
config = (await fs.readJSON(configFilePath)) as IConfig config = (await fs.readJSON(configFilePath)) as IConfig
} catch (e) {} } catch (e) {}
if (!config) { if (!config) {
return sendToolboxRes(event, { return sendToolboxRes(event, {
status: IToolboxItemCheckStatus.SUCCESS, status: IToolboxItemCheckStatus.SUCCESS,
msg: $t('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS') msg: $t('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS')
}) })
} }
const proxy = config.picBed?.proxy const proxy = config.picBed?.proxy
if (!proxy) { if (!proxy) {
return sendToolboxRes(event, { return sendToolboxRes(event, {
status: IToolboxItemCheckStatus.SUCCESS, status: IToolboxItemCheckStatus.SUCCESS,
msg: $t('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS') msg: $t('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS')
}) })
} else { } else {
const proxyOptions = getProxy(proxy) const proxyOptions = getProxy(proxy)
if (!proxyOptions) { if (!proxyOptions) {
return sendToolboxRes(event, { return sendToolboxRes(event, {
status: IToolboxItemCheckStatus.ERROR, status: IToolboxItemCheckStatus.ERROR,
msg: $t('TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_CORRECT') msg: $t('TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_CORRECT')
}) })
} else { } else {
const httpsAgent = tunnel.httpsOverHttp({ const httpsAgent = tunnel.httpsOverHttp({
proxy: { proxy: {
host: proxyOptions.host, host: proxyOptions.host,
port: proxyOptions.port port: proxyOptions.port
} }
}) })
try { try {
await axios.get('https://www.google.com', { await axios.get('https://www.google.com', {
httpsAgent httpsAgent
}) })
return sendToolboxRes(event, { return sendToolboxRes(event, {
status: IToolboxItemCheckStatus.SUCCESS, status: IToolboxItemCheckStatus.SUCCESS,
msg: $t('TOOLBOX_CHECK_PROXY_SUCCESS_TIPS') msg: $t('TOOLBOX_CHECK_PROXY_SUCCESS_TIPS')
}) })
} catch (e) { } catch (e) {
console.log(e) return sendToolboxRes(event, {
return sendToolboxRes(event, { status: IToolboxItemCheckStatus.ERROR,
status: IToolboxItemCheckStatus.ERROR, msg: $t('TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_WORKING')
msg: $t('TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_WORKING') })
}) }
} }
} }
} }
}
sendToolboxRes(event, {
sendToolboxRes(event, { status: IToolboxItemCheckStatus.SUCCESS,
status: IToolboxItemCheckStatus.SUCCESS, msg: $t('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS')
msg: $t('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS') })
}) }
} }
}

View File

@@ -151,7 +151,7 @@ updater.autoUpdater.on('update-downloaded', () => {
}) })
updater.autoUpdater.on('error', err => { updater.autoUpdater.on('error', err => {
console.log(err) logger.error(err)
}) })
class LifeCycle { class LifeCycle {
@@ -175,7 +175,7 @@ class LifeCycle {
const readyFunction = async () => { const readyFunction = async () => {
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
installExtension(VUEJS_DEVTOOLS).catch(err => { installExtension(VUEJS_DEVTOOLS).catch(err => {
console.log('An error occurred: ', err) logger.error('An error occurred: ', err)
}) })
} }
windowManager.create(IWindowList.TRAY_WINDOW) windowManager.create(IWindowList.TRAY_WINDOW)

View File

@@ -6,6 +6,7 @@ import querystring from 'node:querystring'
import type { S3ClientConfig } from '@aws-sdk/client-s3' import type { S3ClientConfig } from '@aws-sdk/client-s3'
import { DeleteObjectCommand, S3Client } from '@aws-sdk/client-s3' import { DeleteObjectCommand, S3Client } from '@aws-sdk/client-s3'
import logger from '@core/picgo/logger'
import { NodeHttpHandler } from '@smithy/node-http-handler' import { NodeHttpHandler } from '@smithy/node-http-handler'
import axios from 'axios' import axios from 'axios'
import type { ISftpPlistConfig } from 'piclist' import type { ISftpPlistConfig } from 'piclist'
@@ -82,7 +83,7 @@ async function getDogeToken (accessKey: string, secretKey: string): Promise<IObj
) )
return data return data
} catch (err: any) { } catch (err: any) {
console.log(err) logger.error(err)
return {} return {}
} }
} }
@@ -179,7 +180,7 @@ export async function removeFileFromS3InMain (configMap: IStringKeyMap, dogeMode
} }
return result.$metadata.httpStatusCode === 204 return result.$metadata.httpStatusCode === 204
} catch (err: any) { } catch (err: any) {
console.log(err) logger.error(err)
return false return false
} }
} }
@@ -203,7 +204,7 @@ export async function removeFileFromDogeInMain (configMap: IStringKeyMap) {
} }
return await removeFileFromS3InMain(newConfigMap, true) return await removeFileFromS3InMain(newConfigMap, true)
} catch (err: any) { } catch (err: any) {
console.log(err) logger.error(err)
return false return false
} }
} }
@@ -241,8 +242,8 @@ export async function removeFileFromHuaweiInMain (configMap: IStringKeyMap) {
} }
}) })
return res.status === 204 return res.status === 204
} catch (error) { } catch (error: any) {
console.log(error) logger.error(error)
return false return false
} }
} }
@@ -257,7 +258,7 @@ export async function removeFileFromSFTPInMain (config: ISftpPlistConfig, fileNa
client.close() client.close()
return deleteResult return deleteResult
} catch (err: any) { } catch (err: any) {
console.log(err) logger.error(err)
return false return false
} }
} }

View File

@@ -1,193 +1,194 @@
import path from 'node:path' import path from 'node:path'
import fs from 'fs-extra' import logger from '@core/picgo/logger'
import { Config, NodeSSH, SSHExecCommandResponse } from 'node-ssh-no-cpu-features' import fs from 'fs-extra'
import { ISftpPlistConfig } from 'piclist/dist/types' import { Config, NodeSSH, SSHExecCommandResponse } from 'node-ssh-no-cpu-features'
import { Client } from 'ssh2-no-cpu-features' import { ISftpPlistConfig } from 'piclist/dist/types'
import { Client } from 'ssh2-no-cpu-features'
class SSHClient {
private static _instance: SSHClient class SSHClient {
private static _client: NodeSSH private static _instance: SSHClient
private _isConnected = false private static _client: NodeSSH
private _isConnected = false
static get instance (): SSHClient {
return this._instance || (this._instance = new this()) static get instance (): SSHClient {
} return this._instance || (this._instance = new this())
}
static get client (): NodeSSH {
return this._client || (this._client = new NodeSSH()) static get client (): NodeSSH {
} return this._client || (this._client = new NodeSSH())
}
private changeWinStylePathToUnix (path: string): string {
return path.replace(/\\/g, '/') private changeWinStylePathToUnix (path: string): string {
} return path.replace(/\\/g, '/')
}
async connect (config: ISftpPlistConfig): Promise<boolean> {
const { username, password, privateKey, passphrase } = config async connect (config: ISftpPlistConfig): Promise<boolean> {
const loginInfo: Config = privateKey const { username, password, privateKey, passphrase } = config
? { const loginInfo: Config = privateKey
username, ? {
privateKeyPath: privateKey, username,
passphrase: passphrase || undefined privateKeyPath: privateKey,
} passphrase: passphrase || undefined
: { username, password } }
try { : { username, password }
await SSHClient.client.connect({ try {
host: config.host, await SSHClient.client.connect({
port: Number(config.port) || 22, host: config.host,
...loginInfo port: Number(config.port) || 22,
}) ...loginInfo
this._isConnected = true })
return true this._isConnected = true
} catch (err: any) { return true
throw new Error(err) } catch (err: any) {
} throw new Error(err)
} }
}
async deleteFileSFTP (config: ISftpPlistConfig, remote: string): Promise<boolean> {
try { async deleteFileSFTP (config: ISftpPlistConfig, remote: string): Promise<boolean> {
const client = new Client() try {
const { username, password, privateKey, passphrase } = config const client = new Client()
const loginInfo: Config = privateKey const { username, password, privateKey, passphrase } = config
? { const loginInfo: Config = privateKey
username, ? {
privateKey: fs.readFileSync(privateKey), username,
passphrase: passphrase || undefined privateKey: fs.readFileSync(privateKey),
} passphrase: passphrase || undefined
: { username, password } }
remote = this.changeWinStylePathToUnix(remote) : { username, password }
if (remote === '/' || remote.includes('*')) return false remote = this.changeWinStylePathToUnix(remote)
const promise = new Promise((resolve, reject) => { if (remote === '/' || remote.includes('*')) return false
client const promise = new Promise((resolve, reject) => {
.on('ready', () => { client
client.sftp( .on('ready', () => {
( client.sftp(
err: any, (
sftp: { err: any,
unlink: (arg0: string, arg1: (err: any) => void) => void sftp: {
} unlink: (arg0: string, arg1: (err: any) => void) => void
) => { }
// eslint-disable-next-line prefer-promise-reject-errors ) => {
if (err) reject(false) // eslint-disable-next-line prefer-promise-reject-errors
sftp.unlink(remote, (err: any) => { if (err) reject(false)
// eslint-disable-next-line prefer-promise-reject-errors sftp.unlink(remote, (err: any) => {
if (err) reject(false) // eslint-disable-next-line prefer-promise-reject-errors
client.end() if (err) reject(false)
resolve(true) client.end()
}) resolve(true)
} })
) }
}) )
.connect({ })
host: config.host, .connect({
port: Number(config.port) || 22, host: config.host,
...loginInfo port: Number(config.port) || 22,
}) ...loginInfo
}) })
return (await promise) as boolean })
} catch (err: any) { return (await promise) as boolean
console.log(err) } catch (err: any) {
return false logger.error(err)
} return false
} }
}
private async exec (script: string): Promise<boolean> {
const execResult = await SSHClient.client.execCommand(script) private async exec (script: string): Promise<boolean> {
return execResult.code === 0 const execResult = await SSHClient.client.execCommand(script)
} return execResult.code === 0
}
async execCommand (script: string): Promise<SSHExecCommandResponse> {
const execResult = await SSHClient.client.execCommand(script) async execCommand (script: string): Promise<SSHExecCommandResponse> {
return execResult || { code: 1, stdout: '', stderr: '' } const execResult = await SSHClient.client.execCommand(script)
} return execResult || { code: 1, stdout: '', stderr: '' }
}
async getFile (local: string, remote: string): Promise<boolean> {
if (!this._isConnected) { async getFile (local: string, remote: string): Promise<boolean> {
throw new Error('SSH 未连接') if (!this._isConnected) {
} throw new Error('SSH 未连接')
try { }
remote = this.changeWinStylePathToUnix(remote) try {
local = this.changeWinStylePathToUnix(local) remote = this.changeWinStylePathToUnix(remote)
await SSHClient.client.getFile(local, remote, undefined, { local = this.changeWinStylePathToUnix(local)
concurrency: 1 await SSHClient.client.getFile(local, remote, undefined, {
}) concurrency: 1
return true })
} catch (err: any) { return true
console.log(err) } catch (err: any) {
return false logger.error(err)
} return false
} }
}
async putFile (
local: string, async putFile (
remote: string, local: string,
config: { remote: string,
fileMode?: string config: {
dirMode?: string fileMode?: string
} = {} dirMode?: string
): Promise<boolean> { } = {}
if (!this._isConnected) { ): Promise<boolean> {
throw new Error('SSH 未连接') if (!this._isConnected) {
} throw new Error('SSH 未连接')
try { }
remote = this.changeWinStylePathToUnix(remote) try {
await this.mkdir(path.dirname(remote).replace(/^\/+|\/+$/g, ''), config) remote = this.changeWinStylePathToUnix(remote)
await SSHClient.client.putFile(local, remote) await this.mkdir(path.dirname(remote).replace(/^\/+|\/+$/g, ''), config)
const fileMode = config.fileMode || '0644' await SSHClient.client.putFile(local, remote)
if (fileMode !== '0644') { const fileMode = config.fileMode || '0644'
const script = `chmod ${fileMode} "${remote}"` if (fileMode !== '0644') {
return await this.exec(script) const script = `chmod ${fileMode} "${remote}"`
} return await this.exec(script)
return true }
} catch (err: any) { return true
console.log(err) } catch (err: any) {
return false logger.error(err)
} return false
} }
}
async mkdir (
dirPath: string, async mkdir (
config: { dirPath: string,
dirMode?: string config: {
} = {} dirMode?: string
): Promise<boolean> { } = {}
if (!this._isConnected) { ): Promise<boolean> {
throw new Error('SSH 未连接') if (!this._isConnected) {
} throw new Error('SSH 未连接')
try { }
const directoryMode = config.dirMode || '0755' try {
if (directoryMode === '0755') { const directoryMode = config.dirMode || '0755'
const script = `mkdir -p "${dirPath}"` if (directoryMode === '0755') {
return await this.exec(script) const script = `mkdir -p "${dirPath}"`
} else { return await this.exec(script)
const dirs = dirPath.split('/') } else {
let currentPath = '' const dirs = dirPath.split('/')
for (const dir of dirs) { let currentPath = ''
if (dir) { for (const dir of dirs) {
currentPath += `/${dir}` if (dir) {
const script = `mkdir "${currentPath}" && chmod ${directoryMode} "${currentPath}"` currentPath += `/${dir}`
const result = await this.exec(script) const script = `mkdir "${currentPath}" && chmod ${directoryMode} "${currentPath}"`
if (!result) { const result = await this.exec(script)
return false if (!result) {
} return false
} }
} }
return true }
} return true
} catch (err: any) { }
console.log(err) } catch (err: any) {
return false logger.error(err)
} return false
} }
}
get isConnected (): boolean {
return SSHClient.client.isConnected() get isConnected (): boolean {
} return SSHClient.client.isConnected()
}
close (): void {
SSHClient.client.dispose() close (): void {
this._isConnected = false SSHClient.client.dispose()
} this._isConnected = false
} }
}
export default SSHClient
export default SSHClient

View File

@@ -4,7 +4,10 @@
data-drag-region data-drag-region
> >
<div class="title-bar-content"> <div class="title-bar-content">
<div class="title-left"> <div
v-if="osGlobal !== 'darwin'"
class="title-left"
>
<div class="app-icon"> <div class="app-icon">
<img <img
:src="defaultLogo" :src="defaultLogo"
@@ -78,6 +81,7 @@ import { MinusIcon, PinIcon, ShrinkIcon, XIcon } from 'lucide-vue-next'
import { computed, onBeforeMount, onBeforeUnmount, ref } from 'vue' import { computed, onBeforeMount, onBeforeUnmount, ref } from 'vue'
import { IRPCActionType } from '@/utils/enum' import { IRPCActionType } from '@/utils/enum'
import { osGlobal } from '@/utils/global'
const isShowprogress = ref(false) const isShowprogress = ref(false)
const progress = ref(0) const progress = ref(0)

View File

@@ -2367,7 +2367,6 @@ async function resetParam (force: boolean = false) {
fileSortSizeReverse.value = false fileSortSizeReverse.value = false
fileSortTimeReverse.value = false fileSortTimeReverse.value = false
if (!isAutoRefresh.value && !force && !paging.value) { if (!isAutoRefresh.value && !force && !paging.value) {
console.log('use cache')
const cachedData = await searchExistFileList() const cachedData = await searchExistFileList()
if (cachedData.length > 0) { if (cachedData.length > 0) {
currentPageFilesInfo.push(...cachedData[0].value.fullList) currentPageFilesInfo.push(...cachedData[0].value.fullList)

View File

@@ -585,8 +585,6 @@ async function handleConfigChange (name: string) {
for (const key of allKeys) { for (const key of allKeys) {
const resultKey = name + '.' + key const resultKey = name + '.' + key
console.log('Config change detected for:', resultKey)
if (key === 'customUrl' && configResult[resultKey] !== undefined && configResult[resultKey] !== '') { if (key === 'customUrl' && configResult[resultKey] !== undefined && configResult[resultKey] !== '') {
if (name !== 'upyun') { if (name !== 'upyun') {
configResult[resultKey] = formatEndpoint(configResult[resultKey], false) configResult[resultKey] = formatEndpoint(configResult[resultKey], false)

View File

@@ -371,7 +371,6 @@ const picBedSwitchDialogVisible = ref(false)
watch(route, async (newRoute) => { watch(route, async (newRoute) => {
if (newRoute.fullPath.split('?')[0] === '/main-page/manage-main-page') { if (newRoute.fullPath.split('?')[0] === '/main-page/manage-main-page') {
console.log('route changed')
currentAlias.value = newRoute.query.alias as string currentAlias.value = newRoute.query.alias as string
currentPicBedName.value = newRoute.query.picBedName as string currentPicBedName.value = newRoute.query.picBedName as string
allPicBedConfigure = JSON.parse(newRoute.query.allPicBedConfigure as string) allPicBedConfigure = JSON.parse(newRoute.query.allPicBedConfigure as string)
@@ -553,7 +552,6 @@ function changePicBed () {
} }
function openBucketPageSetting () { function openBucketPageSetting () {
console.log('Open Bucket Page Setting')
router.push({ router.push({
path: '/main-page/manage-main-page/manage-setting-page', path: '/main-page/manage-main-page/manage-setting-page',
query: { query: {

View File

@@ -1,20 +1,19 @@
import { ref } from 'vue' import { ref } from 'vue'
import { IRPCActionType } from '@/utils/enum' import { IRPCActionType } from '@/utils/enum'
import type { IPicBedType } from '#/types/types' import type { IPicBedType } from '#/types/types'
console.log('global.ts loaded', window.electron.platform) const osGlobal = ref<string>(window.electron.platform)
const osGlobal = ref<string>(window.electron.platform)
const picBedGlobal = ref<IPicBedType[]>([])
const picBedGlobal = ref<IPicBedType[]>([]) const pageReloadCount = ref(0)
const pageReloadCount = ref(0)
async function updatePicBedGlobal () {
async function updatePicBedGlobal () { picBedGlobal.value = (await window.electron.triggerRPC<IPicBedType[]>(IRPCActionType.MAIN_GET_PICBED))!
picBedGlobal.value = (await window.electron.triggerRPC<IPicBedType[]>(IRPCActionType.MAIN_GET_PICBED))! }
}
async function updatePageReloadCount () {
async function updatePageReloadCount () { pageReloadCount.value++
pageReloadCount.value++ }
}
export { osGlobal, pageReloadCount, picBedGlobal, updatePageReloadCount, updatePicBedGlobal }
export { osGlobal, pageReloadCount, picBedGlobal, updatePageReloadCount, updatePicBedGlobal }