Browse Source
- 新增 `electron.vite.config.1749712333417.mjs` 配置文件,配置Vite构建相关插件和参数 - 创建 `packages/utils/index.ts` 工具类文件,添加通用工具函数 `isPromise` 和 `slash` - 扩展 `packages/utils/main/index.ts` 工具类,新增 `getFileUrl` 和 `getPreloadUrl` 方法 - 新增 `packages/utils/main/session/cookies.ts` 实现Electron会话cookie管理功能 - 新增 `packages/utils/main/session/index.ts` 实现Electron多会话隔离功能 - 重构多处代码引用路径,将原 `main/utils` 迁移至 `packages/utils` 统一管理 - 新增设置模块相关代码:`src/common/event/Setting/*` 实现配置同步保存功能 - 新增设置页面 `src/renderer/src/pages/setting/index.vue` 提供UI交互 - 优化导航栏菜单逻辑,移除模块切换功能,整合为统一菜单main
26 changed files with 532 additions and 273 deletions
@ -0,0 +1,133 @@ |
|||||
|
// electron.vite.config.ts
|
||||
|
import { resolve } from "path"; |
||||
|
import { defineConfig, externalizeDepsPlugin } from "electron-vite"; |
||||
|
import vue from "@vitejs/plugin-vue"; |
||||
|
import vueJsx from "@vitejs/plugin-vue-jsx"; |
||||
|
import UnoCSS from "unocss/vite"; |
||||
|
import AutoImport from "unplugin-auto-import/vite"; |
||||
|
import Components from "unplugin-vue-components/vite"; |
||||
|
import VueMacros from "unplugin-vue-macros/vite"; |
||||
|
import { VueRouterAutoImports } from "unplugin-vue-router"; |
||||
|
import VueRouter from "unplugin-vue-router/vite"; |
||||
|
import Layouts from "vite-plugin-vue-layouts"; |
||||
|
import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite"; |
||||
|
import monacoEditorPlugin from "vite-plugin-monaco-editor"; |
||||
|
import IconsResolver from "unplugin-icons/resolver"; |
||||
|
import Icons from "unplugin-icons/vite"; |
||||
|
var __electron_vite_injected_dirname = "D:\\@code\\xyx\\electron-app"; |
||||
|
var electron_vite_config_default = defineConfig({ |
||||
|
main: { |
||||
|
resolve: { |
||||
|
alias: { |
||||
|
config: resolve("config"), |
||||
|
main: resolve("src/main"), |
||||
|
common: resolve("src/common"), |
||||
|
"@res": resolve("resources") |
||||
|
} |
||||
|
}, |
||||
|
plugins: [externalizeDepsPlugin()] |
||||
|
}, |
||||
|
preload: { |
||||
|
build: { |
||||
|
lib: { |
||||
|
entry: { |
||||
|
index: resolve(__electron_vite_injected_dirname, "./src/preload/index.ts"), |
||||
|
plugin: resolve(__electron_vite_injected_dirname, "./src/preload/plugin.ts") |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
plugins: [externalizeDepsPlugin()] |
||||
|
}, |
||||
|
renderer: { |
||||
|
root: resolve(__electron_vite_injected_dirname, "./src/renderer"), |
||||
|
resolve: { |
||||
|
alias: { |
||||
|
config: resolve("config"), |
||||
|
common: resolve("src/common"), |
||||
|
"@": resolve("src/renderer/src"), |
||||
|
"@res": resolve("resources") |
||||
|
} |
||||
|
}, |
||||
|
css: { |
||||
|
preprocessorOptions: { |
||||
|
scss: { |
||||
|
additionalData: `@use "@/assets/style/global" as *;
|
||||
|
`,
|
||||
|
api: "modern-compiler" |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
build: { |
||||
|
rollupOptions: { |
||||
|
input: { |
||||
|
main: resolve(__electron_vite_injected_dirname, "./src/renderer/index.html"), |
||||
|
about: resolve(__electron_vite_injected_dirname, "./src/renderer/about.html") |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
plugins: [ |
||||
|
UnoCSS(), |
||||
|
VueMacros({ |
||||
|
plugins: { |
||||
|
vue: vue(), |
||||
|
vueJsx: vueJsx(), |
||||
|
vueRouter: VueRouter({ |
||||
|
root: resolve(__electron_vite_injected_dirname, "src/renderer"), |
||||
|
// https://github.com/posva/unplugin-vue-router
|
||||
|
extensions: [".vue", ".setup.tsx"], |
||||
|
exclude: ["**/_ui"] |
||||
|
}) |
||||
|
} |
||||
|
}), |
||||
|
VueI18nPlugin({ |
||||
|
compositionOnly: false, |
||||
|
include: resolve(__electron_vite_injected_dirname, "packages/locales/languages/**") |
||||
|
}), |
||||
|
Layouts({ |
||||
|
layoutsDirs: "src/layouts", |
||||
|
pagesDirs: "src/pages", |
||||
|
defaultLayout: "default", |
||||
|
extensions: ["vue", "setup.tsx"], |
||||
|
exclude: ["**/_ui"] |
||||
|
}), |
||||
|
// https://github.com/antfu/unplugin-auto-import
|
||||
|
AutoImport({ |
||||
|
imports: [ |
||||
|
"vue", |
||||
|
"@vueuse/core", |
||||
|
VueRouterAutoImports, |
||||
|
{ |
||||
|
// add any other imports you were relying on
|
||||
|
"vue-router/auto": ["useLink"] |
||||
|
}, |
||||
|
"vue-i18n" |
||||
|
], |
||||
|
dts: true, |
||||
|
dirs: ["src/composables"], |
||||
|
vueTemplate: true |
||||
|
}), |
||||
|
// https://github.com/antfu/vite-plugin-components
|
||||
|
Components({ |
||||
|
dts: true, |
||||
|
dirs: ["src/components", "src/ui"], |
||||
|
resolvers: [ |
||||
|
IconsResolver({ |
||||
|
prefix: "icon" |
||||
|
}) |
||||
|
] |
||||
|
}), |
||||
|
Icons(), |
||||
|
// https://wf0.github.io/example/plugins/Formatter.html
|
||||
|
// @ts-ignore ...
|
||||
|
monacoEditorPlugin.default({ |
||||
|
publicPath: "monacoeditorwork", |
||||
|
customDistPath() { |
||||
|
return resolve(__electron_vite_injected_dirname, "out/renderer/monacoeditorwork"); |
||||
|
} |
||||
|
}) |
||||
|
] |
||||
|
} |
||||
|
}); |
||||
|
export { |
||||
|
electron_vite_config_default as default |
||||
|
}; |
@ -0,0 +1,11 @@ |
|||||
|
export function isPromise(value: () => any) { |
||||
|
return value && Object.prototype.toString.call(value) === "[object Promise]" |
||||
|
} |
||||
|
|
||||
|
export function slash(path: string) { |
||||
|
const isExtendedLengthPath = path.startsWith("\\\\?\\") |
||||
|
if (isExtendedLengthPath) { |
||||
|
return path |
||||
|
} |
||||
|
return path.replace(/\\/g, "/") |
||||
|
} |
@ -1,5 +1,22 @@ |
|||||
|
import { is } from "@electron-toolkit/utils" |
||||
import { webContents } from "electron" |
import { webContents } from "electron" |
||||
|
import { join } from "node:path" |
||||
|
import { slash } from "utils" |
||||
|
|
||||
export const broadcast = <T extends Record<string, (...argu: any[]) => void>>(event: keyof T, ...args: Parameters<T[keyof T]>) => { |
export const broadcast = <T extends Record<string, (...argu: any[]) => void>>(event: keyof T, ...args: Parameters<T[keyof T]>) => { |
||||
webContents.getAllWebContents().forEach(browser => browser.send(event as any, ...args)) |
webContents.getAllWebContents().forEach(browser => browser.send(event as any, ...args)) |
||||
} |
} |
||||
|
|
||||
|
export function getFileUrl(app: string) { |
||||
|
let winURL = "" |
||||
|
if (is.dev && process.env["ELECTRON_RENDERER_URL"]) { |
||||
|
winURL = process.env["ELECTRON_RENDERER_URL"] + `/${app}#/` |
||||
|
} else { |
||||
|
winURL = join(__dirname, `../renderer/${app}#/`) |
||||
|
} |
||||
|
return slash(winURL) |
||||
|
} |
||||
|
|
||||
|
export function getPreloadUrl(file) { |
||||
|
return join(__dirname, `../preload/${file}.mjs`) |
||||
|
} |
||||
|
@ -0,0 +1,63 @@ |
|||||
|
import { defineStore } from "pinia" |
||||
|
import { Setting } from "." |
||||
|
import type { IConfig } from "config" |
||||
|
|
||||
|
let rawConfig: IConfig = Setting.getInstance().sync() as unknown as IConfig |
||||
|
|
||||
|
export const useSettingStore = defineStore( |
||||
|
"Setting", |
||||
|
() => { |
||||
|
const config = ref(JSON.parse(JSON.stringify(rawConfig))) |
||||
|
const diffKeys = ref<(keyof IConfig)[]>([]) |
||||
|
const isSame = computed(() => { |
||||
|
return diffKeys.value.length === 0 |
||||
|
}) |
||||
|
watch( |
||||
|
() => config.value, |
||||
|
() => { |
||||
|
diffKeys.value = [] |
||||
|
;(Object.keys(config.value) as (keyof IConfig)[]).forEach((key: keyof IConfig) => { |
||||
|
if (config.value[key] !== rawConfig[key]) { |
||||
|
diffKeys.value.push(key) |
||||
|
} |
||||
|
}) |
||||
|
}, |
||||
|
{ |
||||
|
deep: true, |
||||
|
immediate: true, |
||||
|
}, |
||||
|
) |
||||
|
const reset = () => { |
||||
|
const tempConfig = JSON.parse(JSON.stringify(rawConfig)) |
||||
|
config.value = tempConfig |
||||
|
} |
||||
|
const isSaving = ref(false) |
||||
|
const save = async () => { |
||||
|
if (isSaving.value) { |
||||
|
return |
||||
|
} |
||||
|
isSaving.value = true |
||||
|
try { |
||||
|
const tempConfig = JSON.parse(JSON.stringify(unref(config))) |
||||
|
await Setting.getInstance().save(tempConfig) |
||||
|
isSaving.value = false |
||||
|
rawConfig = JSON.parse(JSON.stringify(tempConfig)) |
||||
|
config.value = tempConfig |
||||
|
} catch (error) { |
||||
|
isSaving.value = false |
||||
|
throw error |
||||
|
} |
||||
|
} |
||||
|
return { |
||||
|
config, |
||||
|
isSame, |
||||
|
isSaving, |
||||
|
diffKeys, |
||||
|
reset, |
||||
|
save, |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
persist: false, |
||||
|
}, |
||||
|
) |
@ -0,0 +1,23 @@ |
|||||
|
import { ApiFactory } from "common/lib/abstract" |
||||
|
import { BaseSingleton } from "base" |
||||
|
import { IConfig } from "config" |
||||
|
|
||||
|
class Setting extends BaseSingleton { |
||||
|
constructor() { |
||||
|
super() |
||||
|
} |
||||
|
|
||||
|
private get api() { |
||||
|
return ApiFactory.getApiClient() |
||||
|
} |
||||
|
|
||||
|
sync() { |
||||
|
return this.api.callSync("SettingCommand.sync") |
||||
|
} |
||||
|
|
||||
|
save(config: IConfig) { |
||||
|
return this.api.call("SettingCommand.save", config) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export { Setting } |
@ -0,0 +1,13 @@ |
|||||
|
import Setting, { IConfig } from "setting/main" |
||||
|
|
||||
|
export default class SettingCommand { |
||||
|
static init() { |
||||
|
console.log("SettingCommand init") |
||||
|
} |
||||
|
sync() { |
||||
|
return Setting.config() |
||||
|
} |
||||
|
save(config: IConfig) { |
||||
|
return Setting.set(config) |
||||
|
} |
||||
|
} |
@ -0,0 +1,16 @@ |
|||||
|
import { EventMaps } from "helper/updater/common" |
||||
|
import { defineStore } from "pinia" |
||||
|
|
||||
|
export const useSettingStore = defineStore( |
||||
|
"Updater", |
||||
|
() => { |
||||
|
getApi<EventMaps>().on("update-progress", (_, data) => { |
||||
|
console.log(data) |
||||
|
}) |
||||
|
|
||||
|
return {} |
||||
|
}, |
||||
|
{ |
||||
|
persist: false, |
||||
|
}, |
||||
|
) |
@ -1,15 +1,13 @@ |
|||||
import { EventMaps } from "helper/updater/common" |
import { BaseEvent } from "common/lib/abstract" |
||||
|
|
||||
const curProgress = ref(0) |
class Updater extends BaseEvent { |
||||
|
constructor() { |
||||
getApi<EventMaps>().on("update-progress", (_, data) => { |
super() |
||||
console.log(data) |
} |
||||
}) |
|
||||
|
|
||||
function useUpdate() { |
test() { |
||||
return { |
this.api |
||||
curProgress, |
|
||||
} |
} |
||||
} |
} |
||||
|
|
||||
export { useUpdate } |
export { Updater } |
||||
|
@ -1,28 +0,0 @@ |
|||||
import { is } from "@electron-toolkit/utils" |
|
||||
import { join } from "node:path" |
|
||||
|
|
||||
export function getFileUrl(app: string) { |
|
||||
let winURL = "" |
|
||||
if (is.dev && process.env["ELECTRON_RENDERER_URL"]) { |
|
||||
winURL = process.env["ELECTRON_RENDERER_URL"] + `/${app}#/` |
|
||||
} else { |
|
||||
winURL = join(__dirname, `../renderer/${app}#/`) |
|
||||
} |
|
||||
return slash(winURL) |
|
||||
} |
|
||||
|
|
||||
export function getPreloadUrl(file) { |
|
||||
return join(__dirname, `../preload/${file}.mjs`) |
|
||||
} |
|
||||
|
|
||||
export function isPromise(value: () => any) { |
|
||||
return value && Object.prototype.toString.call(value) === "[object Promise]" |
|
||||
} |
|
||||
|
|
||||
export function slash(path: string) { |
|
||||
const isExtendedLengthPath = path.startsWith("\\\\?\\") |
|
||||
if (isExtendedLengthPath) { |
|
||||
return path |
|
||||
} |
|
||||
return path.replace(/\\/g, "/") |
|
||||
} |
|
@ -1,9 +1,7 @@ |
|||||
<script setup lang="ts"></script> |
<script setup lang="ts"></script> |
||||
|
|
||||
<template> |
<template> |
||||
<div h-full flex flex-col> |
<div h-full flex flex-col>sad</div> |
||||
<div v-for="i in 200" :key="i">{{ i }}</div> |
|
||||
</div> |
|
||||
</template> |
</template> |
||||
|
|
||||
<style lang="scss" scoped></style> |
<style lang="scss" scoped></style> |
||||
|
@ -0,0 +1,18 @@ |
|||||
|
<template> |
||||
|
<div h-full flex> |
||||
|
<div w="200px" border-r="#E5E5E5 solid 1px">左侧菜单</div> |
||||
|
<div flex="1" w="0"> |
||||
|
{{ settingStore.isSame }}--{{ settingStore.diffKeys }} |
||||
|
<input v-model="settingStore.config['update.repo']" type="text" /> |
||||
|
{{ settingStore.config["update.repo"] }} |
||||
|
<button v-if="!settingStore.isSame" :disabled="settingStore.isSaving" @click="settingStore.save()">保存</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { useSettingStore } from "common/event/Setting/hook" |
||||
|
|
||||
|
const settingStore = useSettingStore() |
||||
|
console.log(settingStore.config) |
||||
|
</script> |
@ -1,11 +1,8 @@ |
|||||
|
import { createPinia } from "pinia" |
||||
import { createPinia } from 'pinia' |
import piniaPluginPersistedstate from "pinia-plugin-persistedstate" |
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' |
|
||||
|
|
||||
const pinia = createPinia() |
const pinia = createPinia() |
||||
pinia.use(piniaPluginPersistedstate) |
pinia.use(piniaPluginPersistedstate) |
||||
|
|
||||
export default pinia |
export default pinia |
||||
export { |
export { pinia } |
||||
pinia |
|
||||
} |
|
||||
|
@ -1,30 +0,0 @@ |
|||||
import { defineStore } from "pinia" |
|
||||
|
|
||||
export enum ModuleType { |
|
||||
CommonPanel = 0, |
|
||||
CodeMgr = 1, |
|
||||
LinkBox = 2, |
|
||||
} |
|
||||
export const useModuleStore = defineStore("module", () => { |
|
||||
const curModuleId = ref<ModuleType>(ModuleType.CommonPanel) |
|
||||
|
|
||||
const modules: Record<"id" | "label", string | ModuleType>[] = [ |
|
||||
{ id: ModuleType.CommonPanel, label: "全能面板" }, |
|
||||
{ id: ModuleType.CodeMgr, label: "代码管家" }, |
|
||||
{ id: ModuleType.LinkBox, label: "超链鉴宝" }, |
|
||||
] |
|
||||
|
|
||||
const setModule = (type: ModuleType) => { |
|
||||
console.log(type); |
|
||||
curModuleId.value = type |
|
||||
} |
|
||||
const curModule = computed(() => { |
|
||||
return modules.find(m => m.id === curModuleId.value) |
|
||||
}) |
|
||||
return { |
|
||||
ModuleType, |
|
||||
setModule, |
|
||||
modules, |
|
||||
curModule, |
|
||||
} |
|
||||
}) |
|
Loading…
Reference in new issue