提交 e3e4a1f1 作者: test

feat: 优化 ipc 通信以及部分前端内容优化

上级 aaf9c031
......@@ -26,4 +26,4 @@ nsis:
deleteAppDataOnUninstall: false
publish:
provider: generic
url: https://example.com/auto-updates
url: https://client.yiring.com/auto-updates
export const app = {
// 应用名称
name: 'basic-electron-client',
// 密钥
key: 'yiring.com',
// 调试模式
debug: false,
}
......@@ -5,39 +5,37 @@ import type { SettingStore } from '/#/store'
export async function useHandler(win: BrowserWindow, store: ElectronStore<SettingStore>) {
// ==================== ipc handle ===================
ipcMain.handle('window:action', (_, action: string) => {
switch (action) {
// 关闭程序
ipcMain.handle('close', () => {
case 'close':
win.close()
app.quit()
})
break
// 重新加载
ipcMain.handle('reload', () => {
case 'reload':
win.reload()
})
break
// 打开 F12
ipcMain.handle('debug', () => {
win.webContents.toggleDevTools()
})
// 最大化
ipcMain.handle('max', () => {
if (win.isMaximized()) {
win.restore()
} else {
win.maximize()
}
})
case 'debug':
win.webContents?.toggleDevTools()
break
// 最大化/还原
case 'max':
win.isMaximized() ? win.restore() : win.maximize()
break
// 最小化
ipcMain.handle('min', () => {
case 'min':
win.minimize()
})
// 置顶
ipcMain.handle('top', (_, value: boolean) => {
win.setAlwaysOnTop(value)
break
// 置顶/取消置顶
case 'top':
win.setAlwaysOnTop(!win.isAlwaysOnTop())
break
default:
console.warn('[window:action] unknow', action)
break
}
})
// 设置窗口是否总在最前
......
......@@ -17,28 +17,31 @@ process.env.PUBLIC = app.isPackaged ? __dirname : path.join(process.env.DIST_ELE
async function createWindow(): Promise<BrowserWindow> {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 900,
height: 685,
show: false,
autoHideMenuBar: true,
// icon: path.join(__dirname, '../../build/electron/icon.ico'),
webPreferences: {
preload: path.join(__dirname, '../preload/index.js'),
sandbox: false,
// Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
// Consider using contextBridge.exposeInMainWorld
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
nodeIntegration: true,
contextIsolation: false,
sandbox: false,
},
// 窗口大小
width: 900,
height: 685,
// icon
...(process.platform === 'linux' ? { icon: path.join(__dirname, '../../build/electron/icon.ico') } : {}),
// 隐藏菜单栏
autoHideMenuBar: true,
// 默认不显示
show: false,
// 无边框
frame: false,
// 自定义 titleBar
// titleBarStyle: 'hidden',
// titleBarOverlay: {
// height: 32,
// },
})
mainWindow.on('ready-to-show', () => {
......
import os from 'node:os'
import log from 'electron-log'
import { app } from './config'
log.transports.file.maxSize = 1002430
log.transports.file.format = '[{y}-{m}-{d} {h}:{i}:{s}.{ms}] [{level}]{scope} {text}'
// 需要保存的路径
log.transports.file.resolvePath = () => `${os.homedir()}\\Documents\\multi-screen-control-client.log`
// 需要保存的路径
log.transports.file.resolvePath = () => `${os.homedir()}\\Documents\\${app.name}.log`
// 全局的 console.info 写进日志文件
console.info = log.info
......
import type { BrowserWindow } from 'electron'
import type { SettingStore } from '/#/store'
import Store from 'electron-store'
import { machineIdSync } from 'node-machine-id'
import type { BrowserWindow } from 'electron'
import { ipcMain } from 'electron'
import { autoUpdater } from 'electron-updater'
import { machineIdSync } from 'node-machine-id'
import { app } from './config'
export async function useStore(_win: BrowserWindow) {
// 初始化配置
const store = new Store<SettingStore>({
name: 'basic-electron-client-config',
name: app.name,
encryptionKey: app.key,
clearInvalidConfig: true,
encryptionKey: 'yiring.com',
defaults: {
system: {
// 机器码
machineId: machineIdSync().toUpperCase(),
// 调试模式
debug: false,
debug: app.debug,
// 是否总在最前
alwaysOnTop: false,
// 检查更新地址
......@@ -26,13 +29,11 @@ export async function useStore(_win: BrowserWindow) {
// ==================== ipc handle ===================
// 获取配置
ipcMain.handle('store-get', (_, key) => {
ipcMain.handle('store:get', (_, key) => {
return store.get(key)
})
// 设置配置
ipcMain.handle('store-set', (_, key, value) => {
console.log('store-set', key, value)
ipcMain.handle('store:set', (_, key, value) => {
if (key === 'system') {
const oldValue = store.get(key)
if (oldValue?.feedURL !== value.feedURL) {
......@@ -47,9 +48,10 @@ export async function useStore(_win: BrowserWindow) {
}
store.set(key, value)
console.log('store:set', key, value)
})
// 重置配置
ipcMain.handle('store-reset', (_, keys) => {
ipcMain.handle('store:reset', (_, keys) => {
store.reset(keys)
})
......
......@@ -23,7 +23,7 @@ export async function useUpdater(win: BrowserWindow, store: ElectronStore<Settin
function sendUpdateMessageToWindow(body: { type: MessageType; text: string }) {
log.info(`${body.type}: ${body.text}`)
win.webContents.send('updater-message', body)
win.webContents.send('updater:message', body)
}
autoUpdater.on('checking-for-update', () => {
......@@ -55,7 +55,7 @@ export async function useUpdater(win: BrowserWindow, store: ElectronStore<Settin
})
// 监听界面发送的检查更新事件
ipcMain.on('checkForUpdate', () => {
ipcMain.on('updater:check', () => {
checkForUpdate()
})
......@@ -73,7 +73,7 @@ export async function useUpdater(win: BrowserWindow, store: ElectronStore<Settin
}
} catch (error: any) {
log.info(`[检查更新] 出现异常: ${error}`)
win.webContents.send('app-notify', {
win.webContents.send('app:notify', {
type: 'error',
message: error.message,
})
......
......@@ -14,7 +14,7 @@ export const useClientStore = defineStore('app-client', () => {
}
async function getSystem() {
system.value = await ipc.invokeAsync<ISystem>('store-get', 'system')
system.value = await ipc.invokeAsync<ISystem>('store:get', 'system')
return system.value
}
......@@ -23,21 +23,21 @@ export const useClientStore = defineStore('app-client', () => {
const machineId = system.value.machineId
system.value = value
system.value.machineId = machineId
ipc.invoke('store-set', 'system', toRaw(system.value))
ipc.invoke('store:set', 'system', toRaw(system.value))
}
function setDebug(debug: boolean): void {
system.value.debug = debug
ipc.invoke('store-set', 'system', toRaw(system.value))
ipc.invoke('store:set', 'system', toRaw(system.value))
}
function setAlwaysOnTop(alwaysOnTop: boolean): void {
system.value.alwaysOnTop = alwaysOnTop
ipc.invoke('store-set', 'system', toRaw(system.value))
ipc.invoke('store:set', 'system', toRaw(system.value))
}
async function reset(...keys: ['system']) {
ipc.invoke('store-reset', keys)
ipc.invoke('store:reset', keys)
await init()
}
......
......@@ -24,8 +24,8 @@
// 监听检查更新事件
let hide = null
ipc.on('updater-message', (_e, body: { type: MessageType; text: string }) => {
console.log('updater-message', body)
ipc.on('updater:message', (_e, body: { type: MessageType; text: string }) => {
console.log('updater:message', body)
const { type, text } = body
if (type === 'checking-for-update' || type === 'download-progress') {
......
<script setup lang="tsx">
import dayjs from 'dayjs'
import { BasicModal } from '/@/components/Modal'
import { Icon } from '/@/components/Icon'
import { app } from '../config'
import { useElectron } from '@/hooks/electron/useElectron'
import { useMessage } from '@/hooks/web/useMessage'
import { getEnvText } from '/@/utils/env'
......@@ -19,17 +19,15 @@
const { ipcRenderer: ipc } = useElectron()
const { createMessage } = useMessage()
const startYear = 2023
const currentYear = dayjs().year()
const yearText = ref<string>(currentYear === startYear ? `${currentYear}` : `${startYear} - ${currentYear}`)
const loading = ref<boolean>(false)
const versions = reactive({ ...window.electron.process.versions })
const isDebug = computed(() => clientStore.system?.debug)
const versions = reactive({ ...window.electron.process.versions })
// 监听检查更新事件
let hide = null
ipc.on('updater-message', (_e, body: { type: MessageType; text: string }) => {
console.log('updater-message', body)
onMounted(() => {
ipc.on('updater:message', (_e, body: { type: MessageType; text: string }) => {
console.log('updater:message', body)
const { type, text } = body
if (type === 'checking-for-update' || type === 'download-progress') {
......@@ -54,6 +52,12 @@
hide?.()
}
})
})
// 发送检查更新
function checkUpdate() {
ipc.send('updater:check')
}
</script>
<template>
......@@ -72,7 +76,6 @@
<div class="app-icon relative">
<img src="/logo.png" />
</div>
<!-- <div class="app-name">{{ $app.name }}</div> -->
<div class="app-description">{{ $app.description }}</div>
<div class="app-version">
<a-tooltip>
......@@ -89,7 +92,7 @@
</div>
<!-- 检查版本更新按钮 -->
<div class="app-check-update-action">
<a-button type="dashed" :loading="loading" @click="ipc.send('checkForUpdate')">
<a-button type="dashed" :loading="loading" @click="checkUpdate">
<Icon icon="ant-design:bulb-outlined" v-show="!loading" />
检查更新
</a-button>
......@@ -97,11 +100,11 @@
</div>
<!-- 版本信息 -->
<div class="about-footer">
<div class="company">长沙壹润信息科技发展有限公司</div>
<div class="company">{{ app.copyright.company }}</div>
<div class="copyright">
<span>Copyright © {{ yearText }}</span>
<span>Copyright © {{ app.copyright.year }}</span>
<span class="link">
<a target="_blank" href="https://yiring.com">YiRing.com</a>
<a target="_blank" :href="app.copyright.link">{{ app.copyright.text }}</a>
</span>
</div>
</div>
......
<script setup lang="ts">
import dayjs from 'dayjs'
import { LinkOutlined } from '@ant-design/icons-vue'
const year = ref(dayjs().year())
const company = ref<string>('长沙壹润信息科技发展有限公司')
const copyright = reactive({
link: 'https://yiring.com',
text: 'YiRing.com',
})
import { app } from '../config'
</script>
<template>
<div class="footer">
<div class="company">{{ company }}</div>
<div class="company">{{ app.copyright.company }}</div>
<div class="copyright">
<span>Copyright © {{ year }}</span>
<span>Copyright © {{ app.copyright.year }}</span>
<span class="link">
<LinkOutlined />
<a target="_blank" :href="copyright.link">{{ copyright.text }}</a>
<a target="_blank" :href="app.copyright.link">{{ app.copyright.text }}</a>
</span>
</div>
</div>
......
......@@ -17,13 +17,13 @@
const [aboutRegister, { openModal: openAboutModal }] = useModal()
const [settingRegister, { openModal: openSettingModal }] = useModal()
function handle(action: 'reload' | 'debug' | 'min' | 'max' | 'close' | 'top') {
function handleAction(action: 'reload' | 'debug' | 'min' | 'max' | 'close' | 'top') {
if (action === 'close') {
createConfirm({
iconType: 'warning',
content: '确认关闭应用吗?',
onOk() {
ipc.invoke(action)
ipc.invoke('window:action', action)
},
})
return
......@@ -32,11 +32,10 @@
if (action === 'top') {
clientStore.setAlwaysOnTop(!isAlwaysOnTop.value)
createMessage.success(`应用${isAlwaysOnTop.value ? '' : '取消'}置顶`)
ipc.invoke(action, isAlwaysOnTop.value)
return
}
ipc.invoke(action)
ipc.invoke('window:action', action)
}
function about() {
......@@ -48,8 +47,8 @@
}
// 监听全局通知
ipc.on('app-notify', (_, body) => {
console.log('app-notify', body)
ipc.on('app:notify', (_, body) => {
console.log('app:notify', body)
if (body?.message.startsWith('net::')) {
createMessage.warn('更新源访问失败,请检查网络或者更新源配置')
......@@ -70,12 +69,12 @@
</a-space>
<a-space class="btns">
<a-tooltip title="重新加载" v-if="isDebug">
<a-button type="text" primary @click="handle('reload')">
<a-button type="text" primary @click="handleAction('reload')">
<Icon icon="ant-design:reload-outlined" :size="22" />
</a-button>
</a-tooltip>
<a-tooltip title="调试" v-if="isDebug">
<a-button type="text" primary @click="handle('debug')">
<a-button type="text" primary @click="handleAction('debug')">
<Icon icon="ant-design:bug-outlined" :size="22" />
</a-button>
</a-tooltip>
......@@ -90,22 +89,26 @@
</a-button>
</a-tooltip>
<a-tooltip :title="isAlwaysOnTop ? '取消置顶' : '置顶'">
<a-button type="text" primary @click="handle('top')" :class="{ actived: isAlwaysOnTop }">
<Icon icon="ph:push-pin-duotone" :size="22" :color="isAlwaysOnTop ? 'green' : '#000'" />
<a-button type="text" primary @click="handleAction('top')" :class="{ actived: isAlwaysOnTop }">
<Icon
:icon="isAlwaysOnTop ? 'ph:push-pin-fill' : 'ph:push-pin'"
:size="22"
:color="isAlwaysOnTop ? 'green' : '#000'"
/>
</a-button>
</a-tooltip>
<a-tooltip title="最小化">
<a-button type="text" primary @click="handle('min')">
<a-button type="text" primary @click="handleAction('min')">
<Icon icon="ant-design:minus-outlined" :size="22" />
</a-button>
</a-tooltip>
<a-tooltip title="缩放">
<a-button type="text" primary @click="handle('max')">
<a-button type="text" primary @click="handleAction('max')">
<Icon icon="uil:window-maximize" :size="22" />
</a-button>
</a-tooltip>
<a-tooltip title="关闭应用">
<a-button type="text" primary @click="handle('close')" class="close">
<a-button type="text" primary @click="handleAction('close')" class="close">
<Icon icon="ant-design:close-outlined" :size="22" />
</a-button>
</a-tooltip>
......
const startYear = 2023
const endYear = new Date().getFullYear()
export const app = {
copyright: {
text: 'YiRing',
link: 'https://yiring.com',
company: '长沙壹润信息科技发展有限公司',
year: startYear === endYear ? `${startYear}` : `${startYear} - ${endYear}`,
},
}
......@@ -4,7 +4,7 @@
import Footer from './components/Footer.vue'
onMounted(() => {
postMessage({ payload: 'loaded' }, '*')
nextTick(() => postMessage({ payload: 'loaded' }, '*'))
})
</script>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论