feat: 添加 ESLint 配置并优化代码风格,移除未使用的功能

This commit is contained in:
Elysia
2026-02-12 18:31:09 +08:00
parent b43c6117ec
commit e11740ad4c
14 changed files with 65 additions and 114 deletions

View File

@@ -9,5 +9,10 @@
], ],
"url": "https://json.schemastore.org/electron-builder" "url": "https://json.schemastore.org/electron-builder"
} }
],
"eslint.validate": [
"javascript",
"javascriptreact",
"vue"
] ]
} }

View File

@@ -1,2 +1,2 @@
import { ref } from 'vue'; import { ref } from 'vue';
export let isLoaded = ref(false); export const isLoaded = ref(false);

View File

@@ -1,6 +1,5 @@
import { ipcMain, WebContents } from 'electron'; import { ipcMain, WebContents } from 'electron';
import { spawn, ChildProcess, exec } from 'node:child_process'; import { spawn, ChildProcess, exec } from 'node:child_process';
import readline from 'node:readline';
import { promisify } from 'node:util'; import { promisify } from 'node:util';
import pino from 'pino'; import pino from 'pino';
@@ -122,7 +121,7 @@ const parseUpgradableList = (output: string) => {
// Listen for download requests from renderer process // Listen for download requests from renderer process
ipcMain.on('queue-install', async (event, download_json) => { ipcMain.on('queue-install', async (event, download_json) => {
const download = JSON.parse(download_json); const download = JSON.parse(download_json);
const { id, pkgname, upgradeOnly } = download || {}; const { id, pkgname } = download || {};
if (!id || !pkgname) { if (!id || !pkgname) {
logger.warn('passed arguments missing id or pkgname'); logger.warn('passed arguments missing id or pkgname');
@@ -151,9 +150,9 @@ ipcMain.on('queue-install', async (event, download_json) => {
const webContents = event.sender; const webContents = event.sender;
// 开始组装安装命令 // 开始组装安装命令
let superUserCmd = await checkSuperUserCommand(); const superUserCmd = await checkSuperUserCommand();
let execCommand = ''; let execCommand = '';
let execParams = []; const execParams = [];
if (superUserCmd.length > 0) { if (superUserCmd.length > 0) {
execCommand = superUserCmd; execCommand = superUserCmd;
execParams.push(SHELL_CALLER_PATH); execParams.push(SHELL_CALLER_PATH);
@@ -258,7 +257,7 @@ ipcMain.handle('check-installed', async (_event, pkgname: string) => {
logger.info(`检查应用是否已安装: ${pkgname}`); logger.info(`检查应用是否已安装: ${pkgname}`);
let child = spawn(SHELL_CALLER_PATH, ['apm', 'list', '--installed', pkgname], { const child = spawn(SHELL_CALLER_PATH, ['apm', 'list', '--installed', pkgname], {
shell: true, shell: true,
env: process.env env: process.env
}); });
@@ -291,16 +290,16 @@ ipcMain.on('remove-installed', async (_event, pkgname: string) => {
} }
logger.info(`卸载已安装应用: ${pkgname}`); logger.info(`卸载已安装应用: ${pkgname}`);
let superUserCmd = await checkSuperUserCommand(); const superUserCmd = await checkSuperUserCommand();
let execCommand = ''; let execCommand = '';
let execParams = []; const execParams = [];
if (superUserCmd.length > 0) { if (superUserCmd.length > 0) {
execCommand = superUserCmd; execCommand = superUserCmd;
execParams.push(SHELL_CALLER_PATH); execParams.push(SHELL_CALLER_PATH);
} else { } else {
execCommand = SHELL_CALLER_PATH; execCommand = SHELL_CALLER_PATH;
} }
let child = spawn(execCommand, [...execParams, 'apm', 'remove', '-y', pkgname], { const child = spawn(execCommand, [...execParams, 'apm', 'remove', '-y', pkgname], {
shell: true, shell: true,
env: process.env env: process.env
}); });

View File

@@ -7,7 +7,7 @@ import pino from "pino";
const logger = pino({ 'name': 'deeplink.ts' }); const logger = pino({ 'name': 'deeplink.ts' });
type Query = Record<string, string>; type Query = Record<string, string>;
export type Listener = (query: Query) => any; export type Listener = (query: Query) => void;
class ListenersMap { class ListenersMap {
private map: Map<string, Set<Listener>> = new Map(); private map: Map<string, Set<Listener>> = new Map();

View File

@@ -1,5 +1,4 @@
import { app, BrowserWindow, ipcMain, Menu, shell, Tray } from 'electron' import { app, BrowserWindow, ipcMain, Menu, shell, Tray } from 'electron'
import { createRequire } from 'node:module'
import { fileURLToPath } from 'node:url' import { fileURLToPath } from 'node:url'
import path from 'node:path' import path from 'node:path'
import os from 'node:os' import os from 'node:os'
@@ -19,7 +18,6 @@ import './backend/install-manager.js'
import './handle-url-scheme.js' import './handle-url-scheme.js'
const logger = pino({ 'name': 'index.ts' }); const logger = pino({ 'name': 'index.ts' });
const require = createRequire(import.meta.url)
const __dirname = path.dirname(fileURLToPath(import.meta.url)) const __dirname = path.dirname(fileURLToPath(import.meta.url))
// The built directory structure // The built directory structure
@@ -187,8 +185,13 @@ app.whenReady().then(() => {
// 双击触发 // 双击触发
tray.on('click', () => { tray.on('click', () => {
// 双击通知区图标实现应用的显示或隐藏 // 双击通知区图标实现应用的显示或隐藏
win.isVisible() ? win.hide() : win.show() if (win.isVisible()) {
win.isVisible() ? win.setSkipTaskbar(false) : win.setSkipTaskbar(true); win.hide();
win.setSkipTaskbar(true);
} else {
win.show();
win.setSkipTaskbar(false);
}
}); });
}) })

View File

@@ -123,7 +123,8 @@ const { appendLoading, removeLoading } = useLoading()
domReady().then(appendLoading) domReady().then(appendLoading)
window.onmessage = (ev) => { window.onmessage = (ev) => {
ev.data.payload === 'removeLoading' && removeLoading() if (ev.data.payload === 'removeLoading')
removeLoading()
} }
setTimeout(removeLoading, 4999) setTimeout(removeLoading, 4999)

17
eslint.config.ts Normal file
View File

@@ -0,0 +1,17 @@
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import pluginVue from "eslint-plugin-vue";
import { defineConfig, globalIgnores } from "eslint/config";
import eslintConfigPrettier from "eslint-config-prettier/flat";
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
export default defineConfig([
globalIgnores(["**/3rdparty/**", "**/node_modules/**", "**/dist/**", "**/dist-electron/**"]),
{ files: ["**/*.{js,mjs,cjs,ts,mts,cts,vue}"], plugins: { js }, extends: ["js/recommended"], languageOptions: { globals: { ...globals.browser, ...globals.node } } },
tseslint.configs.recommended,
pluginVue.configs["flat/essential"],
{ files: ["**/*.vue"], languageOptions: { parserOptions: { parser: tseslint.parser } } },
eslintConfigPrettier,
eslintPluginPrettierRecommended,
]);

View File

@@ -26,15 +26,26 @@
"build:vite": "vue-tsc --noEmit && vite build --mode production", "build:vite": "vue-tsc --noEmit && vite build --mode production",
"build:rpm": "vue-tsc --noEmit && vite build --mode production && electron-builder --config electron-builder.yml --linux rpm", "build:rpm": "vue-tsc --noEmit && vite build --mode production && electron-builder --config electron-builder.yml --linux rpm",
"build:deb": "vue-tsc --noEmit && vite build --mode production && electron-builder --config electron-builder.yml --linux deb", "build:deb": "vue-tsc --noEmit && vite build --mode production && electron-builder --config electron-builder.yml --linux deb",
"preview": "vite preview --mode debug" "preview": "vite preview --mode debug",
"lint": "eslint --ext .ts,.vue src electron"
}, },
"devDependencies": { "devDependencies": {
"@dotenvx/dotenvx": "^1.51.4", "@dotenvx/dotenvx": "^1.51.4",
"@eslint/create-config": "^1.11.0",
"@eslint/js": "^9.39.2",
"@loongdotjs/electron-builder": "^26.0.12-1", "@loongdotjs/electron-builder": "^26.0.12-1",
"@vitejs/plugin-vue": "^6.0.3", "@vitejs/plugin-vue": "^6.0.3",
"electron": "^40.0.0", "electron": "^40.0.0",
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.5",
"eslint-plugin-vue": "^10.7.0",
"globals": "^17.3.0",
"jiti": "^2.6.1",
"pino-pretty": "^13.1.3", "pino-pretty": "^13.1.3",
"prettier": "3.8.1",
"typescript": "^5.4.2", "typescript": "^5.4.2",
"typescript-eslint": "^8.55.0",
"vite": "^6.4.1", "vite": "^6.4.1",
"vite-plugin-electron": "^0.29.0", "vite-plugin-electron": "^0.29.0",
"vite-plugin-electron-renderer": "^0.14.5", "vite-plugin-electron-renderer": "^0.14.5",

View File

@@ -59,8 +59,9 @@ import UninstallConfirmModal from './components/UninstallConfirmModal.vue';
import { APM_STORE_BASE_URL, currentApp, currentAppIsInstalled } from './global/storeConfig'; import { APM_STORE_BASE_URL, currentApp, currentAppIsInstalled } from './global/storeConfig';
import { downloads, removeDownloadItem, watchDownloadsChange } from './global/downloadStatus'; import { downloads, removeDownloadItem, watchDownloadsChange } from './global/downloadStatus';
import { handleInstall, handleRetry, handleUpgrade } from './modeuls/processInstall'; import { handleInstall, handleRetry, handleUpgrade } from './modeuls/processInstall';
import type { App, AppJson, DownloadItem, UpdateAppItem, InstalledAppInfo, ChannelPayload } from './global/typedefinition'; import type { App, AppJson, DownloadItem, UpdateAppItem, ChannelPayload } from './global/typedefinition';
import type { Ref } from 'vue'; import type { Ref } from 'vue';
import type { IpcRendererEvent } from 'electron';
const logger = pino(); const logger = pino();
// Axios 全局配置 // Axios 全局配置
@@ -250,9 +251,9 @@ const refreshUpgradableApps = async () => {
selected: false, selected: false,
upgrading: false upgrading: false
})); }));
} catch (error: any) { } catch (error: unknown) {
upgradableApps.value = []; upgradableApps.value = [];
updateError.value = error?.message || '检查更新失败'; updateError.value = (error as Error)?.message || '检查更新失败';
} finally { } finally {
updateLoading.value = false; updateLoading.value = false;
} }
@@ -322,7 +323,7 @@ const refreshInstalledApps = async () => {
installedError.value = result?.message || '读取已安装应用失败'; installedError.value = result?.message || '读取已安装应用失败';
return; return;
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any
installedApps.value = [] installedApps.value = []
for (const app of result.apps) { for (const app of result.apps) {
let appInfo = apps.value.find(a => a.pkgname === app.pkgname); let appInfo = apps.value.find(a => a.pkgname === app.pkgname);
@@ -355,9 +356,9 @@ const refreshInstalledApps = async () => {
} }
installedApps.value.push(appInfo); installedApps.value.push(appInfo);
} }
} catch (error: any) { } catch (error: unknown) {
installedApps.value = []; installedApps.value = [];
installedError.value = error?.message || '读取已安装应用失败'; installedError.value = (error as Error)?.message || '读取已安装应用失败';
} finally { } finally {
installedLoading.value = false; installedLoading.value = false;
} }
@@ -409,70 +410,6 @@ const uninstallInstalledApp = (app: App) => {
requestUninstall(app); requestUninstall(app);
}; };
const openApmStoreUrl = (url: string, { fallbackText }: { fallbackText: string }) => {
try {
window.location.href = url;
} catch (e) {
showProtocolFallback(fallbackText);
}
};
const showProtocolFallback = (cmd: string) => {
const existing = document.getElementById('protocolFallbackBox');
if (existing) existing.remove();
const box = document.createElement('div');
box.id = 'protocolFallbackBox';
box.style.position = 'fixed';
box.style.right = '18px';
box.style.bottom = '18px';
box.style.zIndex = '2000';
box.style.boxShadow = 'var(--shadow)';
box.style.background = 'var(--card)';
box.style.borderRadius = '12px';
box.style.padding = '12px';
box.style.maxWidth = '420px';
box.style.fontSize = '13px';
box.innerHTML = `
<div style="font-weight:600;margin-bottom:6px;">无法直接启动本地应用?</div>
<div style="color:var(--muted);margin-bottom:8px;">请在终端执行下列命令,或检查系统是否已将 <code>apmstore://</code> 协议关联到 APM 处理程序。</div>
<div style="display:flex;gap:8px;align-items:center;">
<code style="padding:6px 8px;border-radius:8px;background:var(--glass);flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">${escapeHtml(cmd)}</code>
<button id="copyApmCmd" class="action-btn secondary" title="复制命令">复制</button>
<button id="dismissApmCmd" class="action-btn" title="关闭">关闭</button>
</div>
`;
document.body.appendChild(box);
document.getElementById('copyApmCmd')?.addEventListener('click', () => {
navigator.clipboard?.writeText(cmd).then(() => {
alert('命令已复制到剪贴板');
}).catch(() => {
prompt('请手动复制命令:', cmd);
});
});
document.getElementById('dismissApmCmd')?.addEventListener('click', () => {
box.remove();
});
// 自动消失
setTimeout(() => {
try { box.remove(); } catch (e) { }
}, 30000);
};
const escapeHtml = (s: string) => {
if (!s) return '';
return s.replace(/[&<>"']/g, (c) => ({
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;'
})[c as '&' | '<' | '>' | '"' | "'"]);
};
// 目前 APM 商店不能暂停下载(因为 APM 本身不支持),但保留这些方法以备将来使用 // 目前 APM 商店不能暂停下载(因为 APM 本身不支持),但保留这些方法以备将来使用
const pauseDownload = (id: DownloadItem) => { const pauseDownload = (id: DownloadItem) => {
const download = downloads.value.find(d => d.id === id.id); const download = downloads.value.find(d => d.id === id.id);
@@ -660,7 +597,7 @@ onMounted(async () => {
} }
}); });
window.ipcRenderer.on('deep-link-install', (_event: Electron.IpcRendererEvent, pkgname: string) => { window.ipcRenderer.on('deep-link-install', (_event: IpcRendererEvent, pkgname: string) => {
const tryOpen = () => { const tryOpen = () => {
const target = apps.value.find(a => a.pkgname === pkgname); const target = apps.value.find(a => a.pkgname === pkgname);
if (target) { if (target) {
@@ -682,7 +619,7 @@ onMounted(async () => {
} }
}); });
window.ipcRenderer.on('remove-complete', (_event: Electron.IpcRendererEvent, payload: ChannelPayload) => { window.ipcRenderer.on('remove-complete', (_event: IpcRendererEvent, payload: ChannelPayload) => {
const pkgname = currentApp.value?.pkgname const pkgname = currentApp.value?.pkgname
if(payload.success && pkgname){ if(payload.success && pkgname){
removeDownloadItem(pkgname); removeDownloadItem(pkgname);

View File

@@ -146,18 +146,6 @@ const handleOverlayClick = () => {
close(); close();
}; };
const pause = () => {
// emit('pause', props.download.id);
};
const resume = () => {
// emit('resume', props.download.id);
};
const cancel = () => {
//emit('cancel', props.download.id);
};
const retry = () => { const retry = () => {
if (props.download) { if (props.download) {
emit('retry', props.download); emit('retry', props.download);

View File

@@ -100,18 +100,6 @@ const toggleExpand = () => {
isExpanded.value = !isExpanded.value; isExpanded.value = !isExpanded.value;
}; };
const pauseDownload = (id: string) => {
// emit('pause', id);
};
const resumeDownload = (id: string) => {
// emit('resume', id);
};
const cancelDownload = (id: string) => {
// emit('cancel', id);
};
const retryDownload = (download: DownloadItem) => { const retryDownload = (download: DownloadItem) => {
emit('retry', download); emit('retry', download);
}; };

View File

@@ -90,6 +90,7 @@ defineProps<{
hasSelected: boolean; hasSelected: boolean;
}>(); }>();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'close'): void; (e: 'close'): void;
(e: 'refresh'): void; (e: 'refresh'): void;

View File

@@ -7,7 +7,7 @@ import { currentApp, currentAppIsInstalled } from "../global/storeConfig";
import { APM_STORE_BASE_URL } from "../global/storeConfig"; import { APM_STORE_BASE_URL } from "../global/storeConfig";
import { downloads } from "../global/downloadStatus"; import { downloads } from "../global/downloadStatus";
import { InstallLog, DownloadItem, DownloadResult, App } from '../global/typedefinition'; import { InstallLog, DownloadItem, DownloadResult, App, DownloadItemStatus } from '../global/typedefinition';
let downloadIdCounter = 0; let downloadIdCounter = 0;
const logger = pino({ name: 'processInstall.ts' }); const logger = pino({ name: 'processInstall.ts' });
@@ -110,7 +110,7 @@ window.ipcRenderer.on('remove-complete', (_event, log: DownloadResult) => {
window.ipcRenderer.on('install-status', (_event, log: InstallLog) => { window.ipcRenderer.on('install-status', (_event, log: InstallLog) => {
const downloadObj = downloads.value.find(d => d.id === log.id); const downloadObj = downloads.value.find(d => d.id === log.id);
if(downloadObj) downloadObj.status = log.message as any; if(downloadObj) downloadObj.status = log.message as DownloadItemStatus;
}); });
window.ipcRenderer.on('install-log', (_event, log: InstallLog) => { window.ipcRenderer.on('install-log', (_event, log: InstallLog) => {
const downloadObj = downloads.value.find(d => d.id === log.id); const downloadObj = downloads.value.find(d => d.id === log.id);

1
src/vite-env.d.ts vendored
View File

@@ -1,3 +1,4 @@
/* eslint-disable */
/// <reference types="vite/client" /> /// <reference types="vite/client" />
declare module '*.vue' { declare module '*.vue' {