From 564c48861db7f69ced5299aa0774c35f1adb18f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BB=BB=E5=B8=85?= <1064425721@qq.com> Date: Mon, 27 Feb 2023 10:36:40 +0800 Subject: [PATCH 1/3] feat : add electron auto update template feat : add some components url : https://github.com/RSS1101/electron-vite-react --- electron-builder.json5 | 5 ++ electron/main/index.ts | 5 +- electron/preload/update.ts | 113 ++++++++++++++++++++++++ package.json | 3 + src/App.scss | 4 + src/App.tsx | 43 +++++++++- src/components/RsModal/index.scss | 50 +++++++++++ src/components/RsModal/index.tsx | 60 +++++++++++++ src/components/RsModal/type.d.ts | 18 ++++ src/components/RsProgress/index.scss | 16 ++++ src/components/RsProgress/index.tsx | 22 +++++ src/components/RsProgress/type.d.ts | 5 ++ src/pages/update/index.scss | 13 +++ src/pages/update/index.tsx | 123 +++++++++++++++++++++++++++ 14 files changed, 478 insertions(+), 2 deletions(-) create mode 100644 electron/preload/update.ts create mode 100644 src/components/RsModal/index.scss create mode 100644 src/components/RsModal/index.tsx create mode 100644 src/components/RsModal/type.d.ts create mode 100644 src/components/RsProgress/index.scss create mode 100644 src/components/RsProgress/index.tsx create mode 100644 src/components/RsProgress/type.d.ts create mode 100644 src/pages/update/index.scss create mode 100644 src/pages/update/index.tsx diff --git a/electron-builder.json5 b/electron-builder.json5 index 05ad4f3..02c29d7 100644 --- a/electron-builder.json5 +++ b/electron-builder.json5 @@ -33,5 +33,10 @@ "perMachine": false, "allowToChangeInstallationDirectory": true, "deleteAppDataOnUninstall": false + }, + publish:{ + provider: 'generic', + channel: 'latest', + url: 'https://github.com/RSS1101/electron-vite-react/releases/download/v9.9.9/', } } \ No newline at end of file diff --git a/electron/main/index.ts b/electron/main/index.ts index d99e0cf..a4540b7 100644 --- a/electron/main/index.ts +++ b/electron/main/index.ts @@ -1,6 +1,7 @@ import { app, BrowserWindow, shell, ipcMain } from 'electron' import { release } from 'node:os' import { join } from 'node:path' +import { update } from '../preload/update' // The built directory structure // @@ -72,6 +73,7 @@ async function createWindow() { if (url.startsWith('https:')) shell.openExternal(url) return { action: 'deny' } }) + update(win) } app.whenReady().then(createWindow) @@ -113,4 +115,5 @@ ipcMain.handle('open-win', (_, arg) => { } else { childWindow.loadFile(indexHtml, { hash: arg }) } -}) \ No newline at end of file +}) + diff --git a/electron/preload/update.ts b/electron/preload/update.ts new file mode 100644 index 0000000..4f8b355 --- /dev/null +++ b/electron/preload/update.ts @@ -0,0 +1,113 @@ +import { autoUpdater } from "electron-updater" +import { app, ipcMain } from "electron"; +export const update = (win: Electron.CrossProcessExports.BrowserWindow) => { + // 设置日志打印 + + // 是否自动下载更新,设置为 false 时将通过 API 触发更新下载 + autoUpdater.autoDownload = false; + + autoUpdater.disableWebInstaller = false + + // 是否允许版本降级,也就是服务器版本低于本地版本时,依旧以服务器版本为主 + autoUpdater.allowDowngrade = false; + + // 设置服务器版本最新版本查询接口配置 + autoUpdater.setFeedURL({ + provider: 'generic', + channel: 'latest', + url: 'https://github.com/RSS1101/electron-vite-react/releases/download/v9.9.9/', + }); + + // 保存是否需要安装更新的版本状态,因为需要提供用户在下载完成更新之后立即更新和稍后更新的操作 + let NEED_INSTALL = false; + + Object.defineProperty(app, 'isPackaged', { + get() { + return true; + } + }); + + // 调用 API 检查是否用更新 + ipcMain.on('check-update',()=>{ + autoUpdater.checkForUpdatesAndNotify() + .then((res) => { + win.webContents.send('check-update-type',{ checkUpdate: true}) + }).catch(err => { + // 网络错误 network error + win.webContents.send('check-update-type', { checkUpdate: false}) + }); + }) + + // 检测开始 + autoUpdater.on('checking-for-update', function () { + console.log('checking-for-update') + }) + // 更新可用 + autoUpdater.on('update-available', (arg) => { + console.log('update-available') + win.webContents.send('is-update-available', { isUpdate: true, oldVersion: app.getVersion(), newVersion: arg?.version }) + }) + // 更新不可用 + autoUpdater.on('update-not-available', (arg) => { + console.log('update-not-available') + win.webContents.send('is-update-available', { isUpdate: false, oldVersion: app.getVersion(), newVersion: arg?.version }) + }) + // API 触发更新下载 + const startDownload = (callback: any, successCallback: any) => { + // 监听下载进度并推送到更新窗口 + autoUpdater.on('download-progress', (data) => { + console.log("progress", data) + win.webContents.send('download-progress-data', data) + callback && callback instanceof Function && callback(null, data); + }); + // 监听下载错误并推送到更新窗口 + autoUpdater.on('error', (err) => { + console.log("error") + callback && callback instanceof Function && callback(err); + }); + // 监听下载完成并推送到更新窗口 + autoUpdater.on('update-downloaded', () => { + console.log("update-downloaded") + NEED_INSTALL = true; + successCallback && successCallback instanceof Function && successCallback(); + }); + // 下载更新 + autoUpdater.downloadUpdate(); + }; + + // 监听应用层发送来的进程消息,开始下载更新 + ipcMain.on('start-download', (event) => { + console.log("start") + startDownload( + (err: any, progressInfo: { percent: any; }) => { + if (err) { + //回推下载错误消息 + console.log("update-error") + event.sender.send('update-error', { updateError:true}); + } else { + //回推下载进度消息 + console.log("pdate-progress-percent") + event.sender.send('update-progress', { progressInfo: progressInfo.percent }); + } + }, + () => { + //回推下载完成消息 + console.log("update-downed") + event.sender.send('update-downed'); + } + ); + }); + + ipcMain.on('quit-and-install', () => { + autoUpdater.quitAndInstall(false, true); + }) + + // 用户点击稍后安装后程序退出时执行立即安装更新 + app.on('will-quit', () => { + console.log("NEED_INSTALL=true") + if (NEED_INSTALL) { + autoUpdater.quitAndInstall(true, false); + } + }); + +} \ No newline at end of file diff --git a/package.json b/package.json index 08962a4..a373bcc 100644 --- a/package.json +++ b/package.json @@ -36,5 +36,8 @@ }, "engines": { "node": "^14.18.0 || >=16.0.0" + }, + "dependencies": { + "electron-updater": "^5.3.0" } } diff --git a/src/App.scss b/src/App.scss index 78b1263..45b0b01 100644 --- a/src/App.scss +++ b/src/App.scss @@ -32,6 +32,10 @@ .card { padding: 2em; + button{ + margin: 0 20px; + background-color: #646cffaa; + } } .read-the-docs { diff --git a/src/App.tsx b/src/App.tsx index a5cb431..9dcbf08 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,11 +1,48 @@ import nodeLogo from "./assets/node.svg" -import { useState } from 'react' +import { useEffect, useRef, useState } from 'react' import './App.scss' +import Update from "./pages/update" +import { ipcRenderer } from "electron" console.log('[App.tsx]', `Hello world from Electron ${process.versions.electron}!`) +interface checkUpdateType { + checkUpdate: boolean +} + function App() { const [count, setCount] = useState(0) + const ref =useRef(null) + const [checkBtnText, setCheckBtnText] = useState('check update') + const [checkLoading, setCheckLoading] = useState(false) + const [checkType, setCheckType] = useState(false) + const [openModalType, setopenModalType] = useState(false) + /** + * @description 检查是否有新的更新 Listen for new updates + */ + const checkUpdate = () => { + setCheckLoading(true) + setCheckBtnText('checking Update ...') + ipcRenderer.send('check-update') + } + /** + * @description 获取到检查结果 Get the check results + */ + ipcRenderer.on('check-update-type', (_event, ...args: checkUpdateType[]) => { + setCheckLoading(false) + setCheckBtnText('check update') + setCheckType(args[0].checkUpdate) + setopenModalType(true) + }) + /** + * @description 在通信监听的过程中获取不到ref. + */ + useEffect(()=>{ + if (openModalType){ + ref.current!.openModal() + setopenModalType(false) + } + }, [openModalType]) return (
@@ -19,6 +56,9 @@ function App() { +

Edit src/App.tsx and save to test HMR

@@ -29,6 +69,7 @@ function App() {
Place static files into the/public folder Node logo
+
) } diff --git a/src/components/RsModal/index.scss b/src/components/RsModal/index.scss new file mode 100644 index 0000000..8488a39 --- /dev/null +++ b/src/components/RsModal/index.scss @@ -0,0 +1,50 @@ +.rs-modal-bg{ + width: 100vw; + height: 100vh; + position: fixed; + left: 0; + top: 0; + z-index: 9999; + background: rgba(0, 0, 0, 0.3); +} +.rs-modal { + position: absolute; + top: 20vh; + left: 30vw; + z-index: 10000; + .rs-modal-panel { + border: 1px solid #000000; + border-radius: 5px; + .rs-modal-header { + $titleheight: 38px; + width: 530px; + height: $titleheight; + line-height: $titleheight; + background-color: rgb(99, 153, 255); + display: flex; + .rs-modal-header-text { + text-align: center; + width: 480px; + } + } + .rs-modal-body{ + background-color: #ffffff; + } + .rs-modal-footer { + background-color: #ffffff; + display: flex; + justify-content: end; + button{ + margin: 10px; + } + } + } + .icon { + padding: 0 15px; + width: 20px; + fill: currentColor; + &:hover { + color: rgba(0, 0, 0, 0.4); + } + } +} diff --git a/src/components/RsModal/index.tsx b/src/components/RsModal/index.tsx new file mode 100644 index 0000000..9e50878 --- /dev/null +++ b/src/components/RsModal/index.tsx @@ -0,0 +1,60 @@ +import { createPortal } from 'react-dom'; +import { ModalChildType, ModalPropsType } from './type'; +import './index.scss'; +const ModalTemplate = (child: ModalChildType) => { + return ( + <> +
+
+
+ {child.isHeaderShow ? ( +
+
{child.titleText}
+ + + +
+ ) : null} + +
{child.body}
+ {child.isFooterShow ? ( +
+ + +
+ ) : null} +
+
+ + ); +}; + +const RsModal = (props: ModalPropsType) => { + return createPortal( + props.isOpenModal? + ModalTemplate({ + titleText: props.titleText, + isHeaderShow: props.isHeaderShow ?? true, + isFooterShow: props.isFooterShow ?? true, + body: props.children, + submitText: props.submitText, + canCelText: props.canCelText, + onCanCel: props.onCanCel, + onSubmit: props.onSubmit, + }):
, + document.body, + ); +}; +export default RsModal; diff --git a/src/components/RsModal/type.d.ts b/src/components/RsModal/type.d.ts new file mode 100644 index 0000000..90b83fe --- /dev/null +++ b/src/components/RsModal/type.d.ts @@ -0,0 +1,18 @@ +import { ReactNode } from 'react'; +interface childrens { + titleText?: string; + isHeaderShow?: boolean; + isFooterShow?: boolean; + canCelText?: string; + submitText?: string; + onSubmit?: () => void; + onCanCel?: () => void; +} +export interface ModalChildType extends childrens { + body: ReactNode | null; +} + +export interface ModalPropsType extends childrens { + isOpenModal: boolean; + children: ReactNode | null; +} diff --git a/src/components/RsProgress/index.scss b/src/components/RsProgress/index.scss new file mode 100644 index 0000000..0ba7768 --- /dev/null +++ b/src/components/RsProgress/index.scss @@ -0,0 +1,16 @@ +.rs-progress{ + display: flex; + align-items: center; + .rs-progress-pr{ + border: 1px solid #000000; + border-radius: 3px; + height: 6px; + } + .rs-progress-rate{ + height: 6px; + border-radius: 3px; + } + .rs-progress-num{ + margin: 0 10px; + } +} diff --git a/src/components/RsProgress/index.tsx b/src/components/RsProgress/index.tsx new file mode 100644 index 0000000..22e8639 --- /dev/null +++ b/src/components/RsProgress/index.tsx @@ -0,0 +1,22 @@ +import { RsProgressType } from './type'; +import './index.scss'; + +const RsProgress = (props: RsProgressType) => { + + return ( +
+
+
+
+ {props.percent > 100 ? 100 :(props.percent.toString().substring(0,2) ?? 0) }% +
+ ); +}; + +export default RsProgress; diff --git a/src/components/RsProgress/type.d.ts b/src/components/RsProgress/type.d.ts new file mode 100644 index 0000000..1012a9a --- /dev/null +++ b/src/components/RsProgress/type.d.ts @@ -0,0 +1,5 @@ +export interface RsProgressType { + rateColor?: string; + rateWidth?: number; + percent: number; +} diff --git a/src/pages/update/index.scss b/src/pages/update/index.scss new file mode 100644 index 0000000..9b56d90 --- /dev/null +++ b/src/pages/update/index.scss @@ -0,0 +1,13 @@ +.modal-body{ + display: flex; + align-items: center; + justify-content: center; + height: 100px; + .progress-title{ + width: 150px; + } + + .update-progress{ + display: flex; + } +} \ No newline at end of file diff --git a/src/pages/update/index.tsx b/src/pages/update/index.tsx new file mode 100644 index 0000000..0982932 --- /dev/null +++ b/src/pages/update/index.tsx @@ -0,0 +1,123 @@ +import RsModal from "@/components/RsModal" +import RsProgress from "@/components/RsProgress" +import { ipcRenderer } from "electron" +import { forwardRef, useEffect, useImperativeHandle, useState } from "react" +import "./index.scss" + +interface VersionInfo { + oldVersion: string, + newVersion: string +} + +interface isUpdateAvailable extends VersionInfo { + isUpdate: boolean, + +} +interface ModalBtnText { + canCelText: string, + submitText: string +} + +let onModalSubmit = () => { } +let onModalCanCel = () => { } + +const Update = forwardRef((props: { checkType: boolean }, ref) => { + const [isOpenModal, setIsOpenModal] = useState(false) + const [percentNum, setPercentNum] = useState(0) + const [isNeedUpdate, setIsNeedUpdate] = useState(false) + const [updateError, setUpdateError] = useState(false) + const [versionInfo, setVersionInfo] = useState({ + oldVersion: '', + newVersion: '' + }) + const [modalBtnText, setModalBtnText] = useState({ + canCelText: '', + submitText: '' + }) + + useImperativeHandle(ref, () => ({ + openModal: () => setIsOpenModal(true) + })); + + useEffect(() => { + onModalCanCel = () => setIsOpenModal(false) + }, []) + + /** + * @description 获取版本信息和是否需要更新 Get version information and whether to update + */ + ipcRenderer.on('is-update-available', (_event, ...args: isUpdateAvailable[]) => { + setVersionInfo({ + oldVersion: args[0].oldVersion, + newVersion: args[0].newVersion, + }) + setIsNeedUpdate(args[0].isUpdate) + if (args[0].isUpdate) { + setModalBtnText({ + canCelText: 'cancel', + submitText: 'update' + }) + onModalSubmit = () => ipcRenderer.send('start-download') + onModalCanCel = () => setIsOpenModal(false) + } + }) + /** + * @description 如果更新失败了抛出更新失败信息 Throw the update failure message if the update fails + */ + ipcRenderer.on('update-error', (_event, ...args: { updateError: boolean }[]) => { + setUpdateError(args[0].updateError) + }) + /** + * @description 监听更新进度 update progress + */ + ipcRenderer.on('update-progress', (_event, ...args: { progressInfo: number }[]) => { + setPercentNum(args[0].progressInfo) + }) + /** + * @description 监听是否更新完成 is update been completed + */ + ipcRenderer.on('update-downed', (_event, ...args) => { + setPercentNum(100) + setModalBtnText({ + canCelText: 'install later', + submitText: 'install now' + }) + onModalSubmit = () => ipcRenderer.send('quit-and-install') + onModalCanCel = () => { + ipcRenderer.send('will-quit') + setIsOpenModal(false) + } + }) + + return ( + <> + +
+ {updateError ? +
Error downloading the latest version, please contact the developer
: + props.checkType ? ( + isNeedUpdate ? ( +
+
+ oldVersion : v.{versionInfo.oldVersion} + newVersion : v.{versionInfo.newVersion} +
+
+ update progress : + +
+
) + : This is last version : v.{versionInfo.oldVersion} ! + ) : Check update is Error,Please check your network! + } + +
+
+ + + ) +}) + +export default Update \ No newline at end of file From 9432cd793f5631f205777833ab94bf773c2308bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BB=BB=E5=B8=85?= <1064425721@qq.com> Date: Tue, 28 Feb 2023 17:09:20 +0800 Subject: [PATCH 2/3] feat : Add electron auto update function --- electron-builder.json5 | 2 +- electron/preload/update.ts | 56 ++++------- src/App.scss | 4 - src/App.tsx | 61 +++--------- src/components/RsModal/type.d.ts | 18 ---- src/components/RsProgress/index.tsx | 22 ----- src/components/RsProgress/type.d.ts | 5 - .../{RsModal => update/Modal}/index.scss | 14 +-- .../{RsModal => update/Modal}/index.tsx | 24 ++--- src/components/update/Modal/type.d.ts | 20 ++++ .../Progress}/index.scss | 8 +- src/components/update/Progress/index.tsx | 22 +++++ src/components/update/Progress/type.d.ts | 5 + src/{pages => components}/update/index.scss | 2 +- src/{pages => components}/update/index.tsx | 98 +++++++++---------- src/components/update/type.d.ts | 18 ++++ 16 files changed, 170 insertions(+), 209 deletions(-) delete mode 100644 src/components/RsModal/type.d.ts delete mode 100644 src/components/RsProgress/index.tsx delete mode 100644 src/components/RsProgress/type.d.ts rename src/components/{RsModal => update/Modal}/index.scss (84%) rename src/components/{RsModal => update/Modal}/index.tsx (66%) create mode 100644 src/components/update/Modal/type.d.ts rename src/components/{RsProgress => update/Progress}/index.scss (72%) create mode 100644 src/components/update/Progress/index.tsx create mode 100644 src/components/update/Progress/type.d.ts rename src/{pages => components}/update/index.scss (90%) rename src/{pages => components}/update/index.tsx (58%) create mode 100644 src/components/update/type.d.ts diff --git a/electron-builder.json5 b/electron-builder.json5 index 02c29d7..fd9886a 100644 --- a/electron-builder.json5 +++ b/electron-builder.json5 @@ -37,6 +37,6 @@ publish:{ provider: 'generic', channel: 'latest', - url: 'https://github.com/RSS1101/electron-vite-react/releases/download/v9.9.9/', + url: 'https://github.com/electron-vite/electron-vite-react/releases/download/v0.9.9/', } } \ No newline at end of file diff --git a/electron/preload/update.ts b/electron/preload/update.ts index 4f8b355..76b0a05 100644 --- a/electron/preload/update.ts +++ b/electron/preload/update.ts @@ -1,108 +1,90 @@ import { autoUpdater } from "electron-updater" import { app, ipcMain } from "electron"; export const update = (win: Electron.CrossProcessExports.BrowserWindow) => { - // 设置日志打印 - // 是否自动下载更新,设置为 false 时将通过 API 触发更新下载 + // When set to false, the update download will be triggered through the API autoUpdater.autoDownload = false; autoUpdater.disableWebInstaller = false - // 是否允许版本降级,也就是服务器版本低于本地版本时,依旧以服务器版本为主 autoUpdater.allowDowngrade = false; - // 设置服务器版本最新版本查询接口配置 - autoUpdater.setFeedURL({ - provider: 'generic', - channel: 'latest', - url: 'https://github.com/RSS1101/electron-vite-react/releases/download/v9.9.9/', - }); - - // 保存是否需要安装更新的版本状态,因为需要提供用户在下载完成更新之后立即更新和稍后更新的操作 + // Save the version status of whether the update needs to be installed, + // Because the user needs to update immediately and later after the update is downloaded let NEED_INSTALL = false; - Object.defineProperty(app, 'isPackaged', { - get() { - return true; - } - }); - - // 调用 API 检查是否用更新 + // Check whether update is used ipcMain.on('check-update',()=>{ autoUpdater.checkForUpdatesAndNotify() .then((res) => { win.webContents.send('check-update-type',{ checkUpdate: true}) }).catch(err => { - // 网络错误 network error + // network error win.webContents.send('check-update-type', { checkUpdate: false}) }); }) - // 检测开始 + // start check autoUpdater.on('checking-for-update', function () { console.log('checking-for-update') }) - // 更新可用 + // update available autoUpdater.on('update-available', (arg) => { console.log('update-available') win.webContents.send('is-update-available', { isUpdate: true, oldVersion: app.getVersion(), newVersion: arg?.version }) }) - // 更新不可用 + // update not available autoUpdater.on('update-not-available', (arg) => { console.log('update-not-available') win.webContents.send('is-update-available', { isUpdate: false, oldVersion: app.getVersion(), newVersion: arg?.version }) }) - // API 触发更新下载 + const startDownload = (callback: any, successCallback: any) => { - // 监听下载进度并推送到更新窗口 + // Monitor the download progress and push it to the update window autoUpdater.on('download-progress', (data) => { console.log("progress", data) win.webContents.send('download-progress-data', data) callback && callback instanceof Function && callback(null, data); }); - // 监听下载错误并推送到更新窗口 + // Listen for download errors and push to the update window autoUpdater.on('error', (err) => { - console.log("error") callback && callback instanceof Function && callback(err); }); - // 监听下载完成并推送到更新窗口 + // Listen to the download completion and push it to the update window autoUpdater.on('update-downloaded', () => { - console.log("update-downloaded") NEED_INSTALL = true; successCallback && successCallback instanceof Function && successCallback(); }); - // 下载更新 + autoUpdater.downloadUpdate(); }; - // 监听应用层发送来的进程消息,开始下载更新 + // Listen to the process message sent by the application layer and start downloading updates ipcMain.on('start-download', (event) => { console.log("start") startDownload( (err: any, progressInfo: { percent: any; }) => { if (err) { - //回推下载错误消息 - console.log("update-error") + // callback download error message event.sender.send('update-error', { updateError:true}); } else { - //回推下载进度消息 - console.log("pdate-progress-percent") + // callback update progress message event.sender.send('update-progress', { progressInfo: progressInfo.percent }); } }, () => { - //回推下载完成消息 - console.log("update-downed") + // callback update downed message event.sender.send('update-downed'); } ); }); + // install now ipcMain.on('quit-and-install', () => { autoUpdater.quitAndInstall(false, true); }) - // 用户点击稍后安装后程序退出时执行立即安装更新 + // install later app.on('will-quit', () => { console.log("NEED_INSTALL=true") if (NEED_INSTALL) { diff --git a/src/App.scss b/src/App.scss index 45b0b01..78b1263 100644 --- a/src/App.scss +++ b/src/App.scss @@ -32,10 +32,6 @@ .card { padding: 2em; - button{ - margin: 0 20px; - background-color: #646cffaa; - } } .read-the-docs { diff --git a/src/App.tsx b/src/App.tsx index 9dcbf08..c4c091d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,75 +1,36 @@ -import nodeLogo from "./assets/node.svg" -import { useEffect, useRef, useState } from 'react' +import nodeLogo from './assets/node.svg' +import { useState } from 'react' import './App.scss' -import Update from "./pages/update" -import { ipcRenderer } from "electron" +import Update from '@/components/update' console.log('[App.tsx]', `Hello world from Electron ${process.versions.electron}!`) -interface checkUpdateType { - checkUpdate: boolean -} function App() { const [count, setCount] = useState(0) - const ref =useRef(null) - const [checkBtnText, setCheckBtnText] = useState('check update') - const [checkLoading, setCheckLoading] = useState(false) - const [checkType, setCheckType] = useState(false) - const [openModalType, setopenModalType] = useState(false) - /** - * @description 检查是否有新的更新 Listen for new updates - */ - const checkUpdate = () => { - setCheckLoading(true) - setCheckBtnText('checking Update ...') - ipcRenderer.send('check-update') - } - /** - * @description 获取到检查结果 Get the check results - */ - ipcRenderer.on('check-update-type', (_event, ...args: checkUpdateType[]) => { - setCheckLoading(false) - setCheckBtnText('check update') - setCheckType(args[0].checkUpdate) - setopenModalType(true) - }) - /** - * @description 在通信监听的过程中获取不到ref. - */ - useEffect(()=>{ - if (openModalType){ - ref.current!.openModal() - setopenModalType(false) - } - }, [openModalType]) - return ( -
+

Electron + Vite + React

-
+
-

Edit src/App.tsx and save to test HMR

-

+

Click on the Electron + Vite logo to learn more

-
- Place static files into the/public folder Node logo +
+ Place static files into the/public folder Node logo
- +
) } diff --git a/src/components/RsModal/type.d.ts b/src/components/RsModal/type.d.ts deleted file mode 100644 index 90b83fe..0000000 --- a/src/components/RsModal/type.d.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ReactNode } from 'react'; -interface childrens { - titleText?: string; - isHeaderShow?: boolean; - isFooterShow?: boolean; - canCelText?: string; - submitText?: string; - onSubmit?: () => void; - onCanCel?: () => void; -} -export interface ModalChildType extends childrens { - body: ReactNode | null; -} - -export interface ModalPropsType extends childrens { - isOpenModal: boolean; - children: ReactNode | null; -} diff --git a/src/components/RsProgress/index.tsx b/src/components/RsProgress/index.tsx deleted file mode 100644 index 22e8639..0000000 --- a/src/components/RsProgress/index.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { RsProgressType } from './type'; -import './index.scss'; - -const RsProgress = (props: RsProgressType) => { - - return ( -
-
-
-
- {props.percent > 100 ? 100 :(props.percent.toString().substring(0,2) ?? 0) }% -
- ); -}; - -export default RsProgress; diff --git a/src/components/RsProgress/type.d.ts b/src/components/RsProgress/type.d.ts deleted file mode 100644 index 1012a9a..0000000 --- a/src/components/RsProgress/type.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface RsProgressType { - rateColor?: string; - rateWidth?: number; - percent: number; -} diff --git a/src/components/RsModal/index.scss b/src/components/update/Modal/index.scss similarity index 84% rename from src/components/RsModal/index.scss rename to src/components/update/Modal/index.scss index 8488a39..eeef6c1 100644 --- a/src/components/RsModal/index.scss +++ b/src/components/update/Modal/index.scss @@ -1,4 +1,4 @@ -.rs-modal-bg{ +.up-modal-bg{ width: 100vw; height: 100vh; position: fixed; @@ -7,30 +7,30 @@ z-index: 9999; background: rgba(0, 0, 0, 0.3); } -.rs-modal { +.up-modal { position: absolute; top: 20vh; left: 30vw; z-index: 10000; - .rs-modal-panel { + .up-modal-panel { border: 1px solid #000000; border-radius: 5px; - .rs-modal-header { + .up-modal-header { $titleheight: 38px; width: 530px; height: $titleheight; line-height: $titleheight; background-color: rgb(99, 153, 255); display: flex; - .rs-modal-header-text { + .up-modal-header-text { text-align: center; width: 480px; } } - .rs-modal-body{ + .up-modal-body{ background-color: #ffffff; } - .rs-modal-footer { + .up-modal-footer { background-color: #ffffff; display: flex; justify-content: end; diff --git a/src/components/RsModal/index.tsx b/src/components/update/Modal/index.tsx similarity index 66% rename from src/components/RsModal/index.tsx rename to src/components/update/Modal/index.tsx index 9e50878..02bf723 100644 --- a/src/components/RsModal/index.tsx +++ b/src/components/update/Modal/index.tsx @@ -4,12 +4,12 @@ import './index.scss'; const ModalTemplate = (child: ModalChildType) => { return ( <> -
-
-
+
+
+
{child.isHeaderShow ? ( -
-
{child.titleText}
+
+
{child.titleText}
{
) : null} -
{child.body}
+
{child.body}
{child.isFooterShow ? ( -
- - +
+ {(child.isSubmitShow ?? true) ? : null} + {(child.isCanCelShow ?? true) ? : null}
) : null}
@@ -41,13 +41,15 @@ const ModalTemplate = (child: ModalChildType) => { ); }; -const RsModal = (props: ModalPropsType) => { +const Modal = (props: ModalPropsType) => { return createPortal( props.isOpenModal? ModalTemplate({ titleText: props.titleText, isHeaderShow: props.isHeaderShow ?? true, isFooterShow: props.isFooterShow ?? true, + isCanCelShow: props.isCanCelShow ?? true, + isSubmitShow: props.isSubmitShow ?? true, body: props.children, submitText: props.submitText, canCelText: props.canCelText, @@ -57,4 +59,4 @@ const RsModal = (props: ModalPropsType) => { document.body, ); }; -export default RsModal; +export default Modal; diff --git a/src/components/update/Modal/type.d.ts b/src/components/update/Modal/type.d.ts new file mode 100644 index 0000000..2ba43c3 --- /dev/null +++ b/src/components/update/Modal/type.d.ts @@ -0,0 +1,20 @@ +import { ReactNode } from 'react' +interface childrens { + titleText?: string + isHeaderShow?: boolean + isFooterShow?: boolean + isCanCelShow?: boolean + isSubmitShow?: boolean + canCelText?: string + submitText?: string + onSubmit?: () => void + onCanCel?: () => void +} +export interface ModalChildType extends childrens { + body: ReactNode | null +} + +export interface ModalPropsType extends childrens { + isOpenModal: boolean + children: ReactNode | null +} diff --git a/src/components/RsProgress/index.scss b/src/components/update/Progress/index.scss similarity index 72% rename from src/components/RsProgress/index.scss rename to src/components/update/Progress/index.scss index 0ba7768..51ee222 100644 --- a/src/components/RsProgress/index.scss +++ b/src/components/update/Progress/index.scss @@ -1,16 +1,16 @@ -.rs-progress{ +.up-progress{ display: flex; align-items: center; - .rs-progress-pr{ + .up-progress-pr{ border: 1px solid #000000; border-radius: 3px; height: 6px; } - .rs-progress-rate{ + .up-progress-rate{ height: 6px; border-radius: 3px; } - .rs-progress-num{ + .up-progress-num{ margin: 0 10px; } } diff --git a/src/components/update/Progress/index.tsx b/src/components/update/Progress/index.tsx new file mode 100644 index 0000000..de02693 --- /dev/null +++ b/src/components/update/Progress/index.tsx @@ -0,0 +1,22 @@ +import { RsProgressType } from './type' +import './index.scss' + +const Progress = (props: RsProgressType) => { + + return ( +
+
+
+
+ {props.percent > 100 ? 100 :(props.percent.toString().substring(0,4) ?? 0) }% +
+ ); +}; + +export default Progress; diff --git a/src/components/update/Progress/type.d.ts b/src/components/update/Progress/type.d.ts new file mode 100644 index 0000000..24a0970 --- /dev/null +++ b/src/components/update/Progress/type.d.ts @@ -0,0 +1,5 @@ +export interface RsProgressType { + rateColor?: string + rateWidth?: number + percent: number +} diff --git a/src/pages/update/index.scss b/src/components/update/index.scss similarity index 90% rename from src/pages/update/index.scss rename to src/components/update/index.scss index 9b56d90..39961b2 100644 --- a/src/pages/update/index.scss +++ b/src/components/update/index.scss @@ -1,4 +1,4 @@ -.modal-body{ +.up-modal-body{ display: flex; align-items: center; justify-content: center; diff --git a/src/pages/update/index.tsx b/src/components/update/index.tsx similarity index 58% rename from src/pages/update/index.tsx rename to src/components/update/index.tsx index 0982932..61ed92b 100644 --- a/src/pages/update/index.tsx +++ b/src/components/update/index.tsx @@ -1,27 +1,18 @@ -import RsModal from "@/components/RsModal" -import RsProgress from "@/components/RsProgress" -import { ipcRenderer } from "electron" -import { forwardRef, useEffect, useImperativeHandle, useState } from "react" -import "./index.scss" +import Modal from '@/components/update/Modal' +import Progress from '@/components/update/Progress' +import { ipcRenderer } from 'electron' +import { useEffect, useState } from 'react' +import './index.scss' +import { checkUpdateType, isUpdateAvailable, ModalBtnText, VersionInfo } from './type' -interface VersionInfo { - oldVersion: string, - newVersion: string -} - -interface isUpdateAvailable extends VersionInfo { - isUpdate: boolean, - -} -interface ModalBtnText { - canCelText: string, - submitText: string -} let onModalSubmit = () => { } let onModalCanCel = () => { } -const Update = forwardRef((props: { checkType: boolean }, ref) => { +const Update = () => { + const [checkBtnText, setCheckBtnText] = useState('check update') + const [checkType, setCheckType] = useState(false) + const [checkLoading, setCheckLoading] = useState(false) const [isOpenModal, setIsOpenModal] = useState(false) const [percentNum, setPercentNum] = useState(0) const [isNeedUpdate, setIsNeedUpdate] = useState(false) @@ -35,23 +26,33 @@ const Update = forwardRef((props: { checkType: boolean }, ref) => { submitText: '' }) - useImperativeHandle(ref, () => ({ - openModal: () => setIsOpenModal(true) - })); - useEffect(() => { onModalCanCel = () => setIsOpenModal(false) }, []) - /** - * @description 获取版本信息和是否需要更新 Get version information and whether to update - */ + // Check for updates + const checkUpdate = () => { + setCheckLoading(true) + setCheckBtnText('checking Update ...') + ipcRenderer.send('check-update') + } + + // Listen to get the check result + ipcRenderer.on('check-update-type', (_event, ...args: checkUpdateType[]) => { + setCheckLoading(false) + setCheckBtnText('check update') + setCheckType(args[0].checkUpdate) + setIsOpenModal(true) + }) + + // Get version information and whether to update ipcRenderer.on('is-update-available', (_event, ...args: isUpdateAvailable[]) => { setVersionInfo({ oldVersion: args[0].oldVersion, newVersion: args[0].newVersion, }) setIsNeedUpdate(args[0].isUpdate) + // Update required if (args[0].isUpdate) { setModalBtnText({ canCelText: 'cancel', @@ -61,21 +62,19 @@ const Update = forwardRef((props: { checkType: boolean }, ref) => { onModalCanCel = () => setIsOpenModal(false) } }) - /** - * @description 如果更新失败了抛出更新失败信息 Throw the update failure message if the update fails - */ + + // Throw the update failure message when the update fails ipcRenderer.on('update-error', (_event, ...args: { updateError: boolean }[]) => { setUpdateError(args[0].updateError) + setCheckType(false) }) - /** - * @description 监听更新进度 update progress - */ + + // Get update progress ipcRenderer.on('update-progress', (_event, ...args: { progressInfo: number }[]) => { setPercentNum(args[0].progressInfo) }) - /** - * @description 监听是否更新完成 is update been completed - */ + + // is update been completed ipcRenderer.on('update-downed', (_event, ...args) => { setPercentNum(100) setModalBtnText({ @@ -90,34 +89,35 @@ const Update = forwardRef((props: { checkType: boolean }, ref) => { }) return ( - <> - + -
+ isFooterShow={checkType && isNeedUpdate}> +
{updateError ? -
Error downloading the latest version, please contact the developer
: - props.checkType ? ( +
Error downloading the latest version, please contact the developer
: + checkType ? ( isNeedUpdate ? (
oldVersion : v.{versionInfo.oldVersion} newVersion : v.{versionInfo.newVersion}
-
- update progress : - +
+ update progress : +
) : This is last version : v.{versionInfo.oldVersion} ! ) : Check update is Error,Please check your network! } -
- - - + + +
) -}) +} export default Update \ No newline at end of file diff --git a/src/components/update/type.d.ts b/src/components/update/type.d.ts new file mode 100644 index 0000000..de30813 --- /dev/null +++ b/src/components/update/type.d.ts @@ -0,0 +1,18 @@ + +export interface checkUpdateType { + checkUpdate: boolean +} + +export interface VersionInfo { + oldVersion: string + newVersion: string +} + +export interface isUpdateAvailable extends VersionInfo { + isUpdate: boolean + +} +export interface ModalBtnText { + canCelText: string + submitText: string +} From 1f8b17810a7cc596abd79b8c676f5381befa67a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BB=BB=E5=B8=85?= <1064425721@qq.com> Date: Wed, 1 Mar 2023 11:39:06 +0800 Subject: [PATCH 3/3] chore : use css module conduct style isolation --- src/components/update/Modal/index.scss | 50 --------------- src/components/update/Modal/index.tsx | 32 +++++----- src/components/update/Modal/modal.module.scss | 63 +++++++++++++++++++ src/components/update/Progress/index.scss | 16 ----- src/components/update/Progress/index.tsx | 10 +-- .../update/Progress/progress.module.scss | 21 +++++++ src/components/update/index.scss | 13 ---- src/components/update/index.tsx | 8 +-- src/components/update/update.module.scss | 19 ++++++ 9 files changed, 128 insertions(+), 104 deletions(-) delete mode 100644 src/components/update/Modal/index.scss create mode 100644 src/components/update/Modal/modal.module.scss delete mode 100644 src/components/update/Progress/index.scss create mode 100644 src/components/update/Progress/progress.module.scss delete mode 100644 src/components/update/index.scss create mode 100644 src/components/update/update.module.scss diff --git a/src/components/update/Modal/index.scss b/src/components/update/Modal/index.scss deleted file mode 100644 index eeef6c1..0000000 --- a/src/components/update/Modal/index.scss +++ /dev/null @@ -1,50 +0,0 @@ -.up-modal-bg{ - width: 100vw; - height: 100vh; - position: fixed; - left: 0; - top: 0; - z-index: 9999; - background: rgba(0, 0, 0, 0.3); -} -.up-modal { - position: absolute; - top: 20vh; - left: 30vw; - z-index: 10000; - .up-modal-panel { - border: 1px solid #000000; - border-radius: 5px; - .up-modal-header { - $titleheight: 38px; - width: 530px; - height: $titleheight; - line-height: $titleheight; - background-color: rgb(99, 153, 255); - display: flex; - .up-modal-header-text { - text-align: center; - width: 480px; - } - } - .up-modal-body{ - background-color: #ffffff; - } - .up-modal-footer { - background-color: #ffffff; - display: flex; - justify-content: end; - button{ - margin: 10px; - } - } - } - .icon { - padding: 0 15px; - width: 20px; - fill: currentColor; - &:hover { - color: rgba(0, 0, 0, 0.4); - } - } -} diff --git a/src/components/update/Modal/index.tsx b/src/components/update/Modal/index.tsx index 02bf723..7ecce0b 100644 --- a/src/components/update/Modal/index.tsx +++ b/src/components/update/Modal/index.tsx @@ -1,43 +1,43 @@ import { createPortal } from 'react-dom'; import { ModalChildType, ModalPropsType } from './type'; -import './index.scss'; +import modalScss from './modal.module.scss' const ModalTemplate = (child: ModalChildType) => { return ( - <> -
-
-
+
+
+
+
{child.isHeaderShow ? ( -
-
{child.titleText}
+
+
{child.titleText}
) : null} -
{child.body}
+
{child.body}
{child.isFooterShow ? ( -
+
{(child.isSubmitShow ?? true) ? : null} {(child.isCanCelShow ?? true) ? : null}
) : null}
- +
); }; diff --git a/src/components/update/Modal/modal.module.scss b/src/components/update/Modal/modal.module.scss new file mode 100644 index 0000000..a9536de --- /dev/null +++ b/src/components/update/Modal/modal.module.scss @@ -0,0 +1,63 @@ +.modal{ + :global{ + .modal-bg { + width: 100vw; + height: 100vh; + position: fixed; + left: 0; + top: 0; + z-index: 9999; + background: rgba(0, 0, 0, 0.3); + } + + .modal-outboard { + position: absolute; + top: 20vh; + left: 30vw; + z-index: 10000; + } + + .modal-panel { + border: 1px solid #000000; + border-radius: 5px; + + .modal-header { + $titleheight: 38px; + width: 530px; + height: $titleheight; + line-height: $titleheight; + background-color: rgb(99, 153, 255); + display: flex; + + .modal-header-text { + text-align: center; + width: 480px; + } + } + + .modal-body { + background-color: #ffffff; + } + + .modal-footer { + background-color: #ffffff; + display: flex; + justify-content: end; + + button { + margin: 10px; + } + } + } + + .icon { + padding: 0 15px; + width: 20px; + fill: currentColor; + + &:hover { + color: rgba(0, 0, 0, 0.4); + } + } + } +} \ No newline at end of file diff --git a/src/components/update/Progress/index.scss b/src/components/update/Progress/index.scss deleted file mode 100644 index 51ee222..0000000 --- a/src/components/update/Progress/index.scss +++ /dev/null @@ -1,16 +0,0 @@ -.up-progress{ - display: flex; - align-items: center; - .up-progress-pr{ - border: 1px solid #000000; - border-radius: 3px; - height: 6px; - } - .up-progress-rate{ - height: 6px; - border-radius: 3px; - } - .up-progress-num{ - margin: 0 10px; - } -} diff --git a/src/components/update/Progress/index.tsx b/src/components/update/Progress/index.tsx index de02693..bb82162 100644 --- a/src/components/update/Progress/index.tsx +++ b/src/components/update/Progress/index.tsx @@ -1,20 +1,20 @@ import { RsProgressType } from './type' -import './index.scss' +import progressScss from './progress.module.scss' const Progress = (props: RsProgressType) => { return ( -
-
+
+
- {props.percent > 100 ? 100 :(props.percent.toString().substring(0,4) ?? 0) }% + {props.percent > 100 ? 100 :(props.percent.toString().substring(0,4) ?? 0) }%
); }; diff --git a/src/components/update/Progress/progress.module.scss b/src/components/update/Progress/progress.module.scss new file mode 100644 index 0000000..ff84486 --- /dev/null +++ b/src/components/update/Progress/progress.module.scss @@ -0,0 +1,21 @@ +.progress { + display: flex; + align-items: center; + + :global { + .progress-pr { + border: 1px solid #000000; + border-radius: 3px; + height: 6px; + } + + .progress-rate { + height: 6px; + border-radius: 3px; + } + + .progress-num { + margin: 0 10px; + } + } +} \ No newline at end of file diff --git a/src/components/update/index.scss b/src/components/update/index.scss deleted file mode 100644 index 39961b2..0000000 --- a/src/components/update/index.scss +++ /dev/null @@ -1,13 +0,0 @@ -.up-modal-body{ - display: flex; - align-items: center; - justify-content: center; - height: 100px; - .progress-title{ - width: 150px; - } - - .update-progress{ - display: flex; - } -} \ No newline at end of file diff --git a/src/components/update/index.tsx b/src/components/update/index.tsx index 61ed92b..3eb4fd0 100644 --- a/src/components/update/index.tsx +++ b/src/components/update/index.tsx @@ -2,7 +2,7 @@ import Modal from '@/components/update/Modal' import Progress from '@/components/update/Progress' import { ipcRenderer } from 'electron' import { useEffect, useState } from 'react' -import './index.scss' +import updateScss from './update.module.scss' import { checkUpdateType, isUpdateAvailable, ModalBtnText, VersionInfo } from './type' @@ -89,11 +89,11 @@ const Update = () => { }) return ( -
+ <> -
+
{updateError ?
Error downloading the latest version, please contact the developer
: checkType ? ( @@ -116,7 +116,7 @@ const Update = () => { -
+ ) } diff --git a/src/components/update/update.module.scss b/src/components/update/update.module.scss new file mode 100644 index 0000000..926bb44 --- /dev/null +++ b/src/components/update/update.module.scss @@ -0,0 +1,19 @@ +.modalslot{ + display: flex; + align-items: center; + justify-content: center; + height: 100px; + + :global { + .progress-title { + width: 150px; + } + + .update-progress { + display: flex; + } + } +} +.a{ + color: red; +} \ No newline at end of file