115 lines
5.7 KiB
JavaScript
115 lines
5.7 KiB
JavaScript
|
|
//#region \0rolldown/runtime.js
|
|||
|
|
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|||
|
|
//#endregion
|
|||
|
|
//#region src/preload/index.ts
|
|||
|
|
var import_electron = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|||
|
|
var { spawnSync } = require("child_process");
|
|||
|
|
var fs = require("fs");
|
|||
|
|
var path = require("path");
|
|||
|
|
var pathFile = path.join(__dirname, "path.txt");
|
|||
|
|
function downloadElectron() {
|
|||
|
|
console.log("Downloading Electron binary...");
|
|||
|
|
if (spawnSync(process.execPath, [path.join(__dirname, "install.js")], { stdio: "inherit" }).status !== 0) throw new Error("Electron failed to install correctly. Please delete `node_modules/electron` and run \"npx install-electron --no\" manually.");
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Fetches the path to the Electron executable to use in development mode.
|
|||
|
|
* If the executable is missing, attempt to download it first.
|
|||
|
|
*
|
|||
|
|
* @returns the path to the Electron executable to run
|
|||
|
|
*/
|
|||
|
|
function getElectronPath() {
|
|||
|
|
let executablePath;
|
|||
|
|
if (fs.existsSync(pathFile)) executablePath = fs.readFileSync(pathFile, "utf-8");
|
|||
|
|
if (process.env.ELECTRON_OVERRIDE_DIST_PATH) return path.join(process.env.ELECTRON_OVERRIDE_DIST_PATH, executablePath || "electron");
|
|||
|
|
if (executablePath) {
|
|||
|
|
const fullPath = path.join(__dirname, "dist", executablePath);
|
|||
|
|
if (!fs.existsSync(fullPath)) downloadElectron();
|
|||
|
|
return fullPath;
|
|||
|
|
} else {
|
|||
|
|
try {
|
|||
|
|
downloadElectron();
|
|||
|
|
} catch {
|
|||
|
|
throw new Error("Electron failed to install correctly. Please delete `node_modules/electron` and run \"npx install-electron --no\" manually.");
|
|||
|
|
}
|
|||
|
|
executablePath = fs.readFileSync(pathFile, "utf-8");
|
|||
|
|
return path.join(__dirname, "dist", executablePath);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
module.exports = getElectronPath();
|
|||
|
|
})))();
|
|||
|
|
/**
|
|||
|
|
* 用 canvas 绘制 Windows 任务栏角标覆盖图(红底白字数字),返回 dataURL
|
|||
|
|
* 为什么在 preload 画:主进程没有 DOM canvas,nativeImage 也不能绘制文字;
|
|||
|
|
* preload 跑在渲染进程里有完整 DOM 能力,画完把 dataURL 交给主进程 setOverlayIcon
|
|||
|
|
*/
|
|||
|
|
function drawBadgeDataURL(count) {
|
|||
|
|
const size = 32;
|
|||
|
|
const canvas = document.createElement("canvas");
|
|||
|
|
canvas.width = size;
|
|||
|
|
canvas.height = size;
|
|||
|
|
const ctx = canvas.getContext("2d");
|
|||
|
|
if (!ctx) return "";
|
|||
|
|
const text = count > 99 ? "99+" : String(count);
|
|||
|
|
ctx.beginPath();
|
|||
|
|
ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2);
|
|||
|
|
ctx.fillStyle = "#f5222d";
|
|||
|
|
ctx.fill();
|
|||
|
|
ctx.fillStyle = "#ffffff";
|
|||
|
|
ctx.font = `bold ${text.length > 2 ? 13 : 18}px sans-serif`;
|
|||
|
|
ctx.textAlign = "center";
|
|||
|
|
ctx.textBaseline = "middle";
|
|||
|
|
ctx.fillText(text, size / 2, 17);
|
|||
|
|
return canvas.toDataURL("image/png");
|
|||
|
|
}
|
|||
|
|
/** 订阅主进程推送事件的通用封装,返回取消订阅函数(组件卸载时记得调用防止泄漏) */
|
|||
|
|
function subscribe(channel, callback) {
|
|||
|
|
const listener = (_event, payload) => callback(payload);
|
|||
|
|
import_electron.ipcRenderer.on(channel, listener);
|
|||
|
|
return () => import_electron.ipcRenderer.removeListener(channel, listener);
|
|||
|
|
}
|
|||
|
|
var desktopAPI = {
|
|||
|
|
/** 恒为 true,web 侧用它判断是否运行在 Electron 壳内 */
|
|||
|
|
isElectron: true,
|
|||
|
|
/** 当前平台:win32 / darwin / linux(渲染层做平台差异 UI 时用) */
|
|||
|
|
platform: process.platform,
|
|||
|
|
/** 应用版本号(package.json version,用于「关于」展示) */
|
|||
|
|
getVersion: () => import_electron.ipcRenderer.invoke("desktop:get-version"),
|
|||
|
|
/**
|
|||
|
|
* 发系统通知;route 传入站内路由(如 /notice/list)时点击通知会唤起窗口并跳转
|
|||
|
|
* flash 默认 true:窗口未聚焦时同时闪烁任务栏(mac 表现为 Dock 弹跳)
|
|||
|
|
*/
|
|||
|
|
notify: (options) => import_electron.ipcRenderer.invoke("desktop:notify", options),
|
|||
|
|
/** 设置未读角标数,0 清除;mac 用 Dock 原生数字,Windows 用 canvas 画的覆盖图 */
|
|||
|
|
setBadge: (count) => {
|
|||
|
|
const dataUrl = count > 0 && process.platform === "win32" ? drawBadgeDataURL(count) : "";
|
|||
|
|
return import_electron.ipcRenderer.invoke("desktop:set-badge", count, dataUrl);
|
|||
|
|
},
|
|||
|
|
/** 手动控制任务栏闪烁(一般用不到,notify 已内置) */
|
|||
|
|
flashFrame: (flag = true) => import_electron.ipcRenderer.invoke("desktop:flash-frame", flag),
|
|||
|
|
/** 读取开机自启状态 */
|
|||
|
|
getAutoLaunch: () => import_electron.ipcRenderer.invoke("desktop:get-auto-launch"),
|
|||
|
|
/** 设置开机自启(--hidden 静默启动进托盘) */
|
|||
|
|
setAutoLaunch: (enabled) => import_electron.ipcRenderer.invoke("desktop:set-auto-launch", enabled),
|
|||
|
|
/** 枚举系统打印机列表 */
|
|||
|
|
getPrinters: () => import_electron.ipcRenderer.invoke("desktop:get-printers"),
|
|||
|
|
/**
|
|||
|
|
* 打印一段完整 HTML:不传 deviceName 时读持久化的默认打印机;
|
|||
|
|
* silent=true 静默打印,false 弹系统打印对话框
|
|||
|
|
*/
|
|||
|
|
printHTML: (options) => import_electron.ipcRenderer.invoke("desktop:print-html", options),
|
|||
|
|
/** 读桌面端本地设置(如默认打印机) */
|
|||
|
|
getSetting: (key) => import_electron.ipcRenderer.invoke("desktop:get-setting", key),
|
|||
|
|
/** 写桌面端本地设置 */
|
|||
|
|
setSetting: (key, value) => import_electron.ipcRenderer.invoke("desktop:set-setting", key, value),
|
|||
|
|
/** 手动检查更新(托盘菜单也有同款入口) */
|
|||
|
|
checkUpdate: () => import_electron.ipcRenderer.invoke("desktop:check-update"),
|
|||
|
|
/** 更新下载完成后立即重启安装 */
|
|||
|
|
quitAndInstall: () => import_electron.ipcRenderer.invoke("desktop:quit-and-install"),
|
|||
|
|
/** 订阅「点击通知要求跳转路由」事件,web 侧收到后自行 router.push */
|
|||
|
|
onNavigate: (callback) => subscribe("desktop:navigate", callback),
|
|||
|
|
/** 订阅更新流程事件(checking / available / progress / downloaded 等),用于展示进度 */
|
|||
|
|
onUpdateEvent: (callback) => subscribe("desktop:update-event", callback)
|
|||
|
|
};
|
|||
|
|
import_electron.contextBridge.exposeInMainWorld("desktopAPI", desktopAPI);
|
|||
|
|
//#endregion
|