init
22
.gitignore
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
node_modules
|
||||||
|
out/
|
||||||
|
logs/
|
||||||
|
runtime/
|
||||||
|
.idea/
|
||||||
|
package-lock.json
|
||||||
|
data/
|
||||||
|
.vscode/launch.json
|
||||||
|
public/electron/
|
||||||
|
public/dist/
|
||||||
|
pnpm-lock.yaml
|
||||||
|
.yalc/
|
||||||
|
yalc.lock
|
||||||
|
go/tmp/
|
||||||
|
build/extraResources/java-app.jar
|
||||||
|
build/extraResources/jre1.8.0_201/
|
||||||
|
python/.venv/
|
||||||
|
python/*.spec
|
||||||
|
python/build/
|
||||||
|
python/dist/
|
||||||
|
*DS_Store
|
||||||
|
yalc.lock
|
||||||
4
.npmrc
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
registry=https://registry.npmmirror.com/
|
||||||
|
disturl=https://registry.npmmirror.com/-/binary/node
|
||||||
|
electron_mirror=https://npmmirror.com/mirrors/electron/
|
||||||
|
electron-builder-binaries_mirror=https://registry.npmmirror.com/-/binary/electron-builder-binaries/
|
||||||
221
README.md
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
[](https://gitee.com/dromara/electron-egg/stargazers)
|
||||||
|
|
||||||
|
<div align=center>
|
||||||
|
<h3>🎉🎉🎉 ElectronEgg V4 已发布! 🎉🎉🎉</h3>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<div align=center>
|
||||||
|
<img src="./public/images/example/logo.png" width="150" height="150" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align=center>
|
||||||
|
<h3><strong>一个入门简单、跨平台、企业级桌面软件开发框架</strong></h3>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<!-- ## 🌏 [English](https://www.yuque.com/u34495/ee-doc) | [中文](https://www.kaka996.com/) -->
|
||||||
|
|
||||||
|
## 📋 介绍
|
||||||
|
|
||||||
|
> 框架已经广泛应用于记账、政务、企业、医疗、学校、股票交易、ERP、娱乐、视频等领域客户端,请放心使用!
|
||||||
|
|
||||||
|
## 👦 谁可以使用
|
||||||
|
|
||||||
|
项目已经有 5 个交流群,覆盖`前端`、`java`、`go`、`python`、`php` 等开发者。
|
||||||
|
|
||||||
|
无论你是前端、服务端、运维、游戏、客户端等,都可以很快入门,
|
||||||
|
|
||||||
|
## 🐶 精彩案例
|
||||||
|
|
||||||
|
- [**点击查看**](#项目案例)
|
||||||
|
|
||||||
|
## 📺 特点
|
||||||
|
- 🍩 **为什么使用?** 桌面软件(办公方向、 个人工具),仍然是未来十几年PC端需求之一,提高工作效率
|
||||||
|
- 🍉 **简单:** 只需懂 JavaScript
|
||||||
|
- 🍑 **愿景:** 所有开发者都能学会桌面软件研发
|
||||||
|
- 🍰 **gitee:** https://gitee.com/dromara/electron-egg **5100+**
|
||||||
|
- 🍨 **github:** https://github.com/dromara/electron-egg **1800+**
|
||||||
|
- 🏆 码云最有价值开源项目
|
||||||
|

|
||||||
|
|
||||||
|
## 📚 文档
|
||||||
|
- 快速体验:[教程文档](https://www.kaka996.com/)
|
||||||
|

|
||||||
|
|
||||||
|
## 📦 特性
|
||||||
|
1. 🍄 跨平台:一套代码,可以打包成windows版、Mac版、Linux版、国产UOS、Deepin、麒麟等
|
||||||
|
2. 🌹 架构:单业务进程/模块化/多任务(进程,线程,渲染进程),让开发大型项目变的简单。
|
||||||
|
3. 🌱 简单高效:只需学习 js 语言
|
||||||
|
4. 🌴 前端独立:理论上支持任何前端技术,如:vue、react、html等等
|
||||||
|
5. 🍁 工程化:可以用前端、服务端的开发思维,来编写桌面软件
|
||||||
|
6. 🌷 高性能:事件驱动、非阻塞式IO
|
||||||
|
7. 🌰 功能丰富:配置、通信、插件、数据库、升级、打包、工具... 应有尽有
|
||||||
|
8. 💐 安全:支持字节码加密、压缩混淆加密
|
||||||
|
9. 🌻 功能demo:桌面软件常见功能,框架集成或提供demo
|
||||||
|
|
||||||
|
## ✈️ 使用场景
|
||||||
|
|
||||||
|
### 1. 🚀 常规桌面软件
|
||||||
|
- 🚖 windows平台
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- 🚍 macOS平台
|
||||||
|

|
||||||
|
|
||||||
|
- 🚔 linux平台 - 国产UOS、Deepin
|
||||||
|

|
||||||
|
|
||||||
|
- 🚔 linux平台 - ubuntu
|
||||||
|

|
||||||
|
|
||||||
|
### 🚐 2. vue、react、angular、web 转换成桌面软件
|
||||||
|
- 🚙 vue-ant-design(本地)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- 🚙 禅道项目管理(web项目地址)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 🚂 3. 游戏(h5相关技术开发)
|
||||||
|
- 🚊 忍者100层
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
## 📒 开始使用
|
||||||
|
|
||||||
|
- ✒️ [安装文档](https://www.kaka996.com/pages/e64ff6/)
|
||||||
|
|
||||||
|
## 项目案例
|
||||||
|
- 🐟 框架已经应用于医疗、学校、政务、股票交易、ERP、娱乐、视频、企业等领域客户端
|
||||||
|
|
||||||
|
### 🐸 远控
|
||||||
|
|
||||||
|
- RQ Center
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
### 🐸 云盘
|
||||||
|
|
||||||
|
- FM Cloud
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
### 🐸 IM
|
||||||
|
|
||||||
|
- Cede IM
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
### 🐸 壁纸
|
||||||
|
|
||||||
|
- warpar
|
||||||
|

|
||||||
|
|
||||||
|
### 🐸 英雄联盟助手
|
||||||
|
|
||||||
|
- Serendlplty
|
||||||
|

|
||||||
|
|
||||||
|
### 🐸 更多
|
||||||
|
|
||||||
|
- [更多案例](https://www.kaka996.com/pages/eadf46/)
|
||||||
|
|
||||||
|
## 💬 交流
|
||||||
|
1. [讨论](https://www.kaka996.com/pages/c2720e/)
|
||||||
|
|
||||||
|
## 📌 关于pr
|
||||||
|
请前往[GitHub项目](https://github.com/dromara/electron-egg)提pr(避免代码同步后,pr被覆盖掉),感谢!
|
||||||
|
|
||||||
|
地址:https://github.com/dromara/electron-egg
|
||||||
|
|
||||||
|
## 📔 框架核心包 ee-core
|
||||||
|
ee-core:[https://github.com/wallace5303/ee-core](https://github.com/wallace5303/ee-core)
|
||||||
|
|
||||||
|
## 📚 Dromara 成员项目
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://gitee.com/dromara/TLog" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/tlog2.png" title="一个轻量级的分布式日志标记追踪神器,10分钟即可接入,自动对日志打标签完成微服务的链路追踪" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://gitee.com/dromara/liteFlow" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/liteflow.png" title="轻量,快速,稳定,可编排的组件式流程引擎" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://hutool.cn/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/hutool.jpg" title="小而全的Java工具类库,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://sa-token.dev33.cn/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/sa-token.png" title="一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://gitee.com/dromara/hmily" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/hmily.png" title="高性能一站式分布式事务解决方案。" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://gitee.com/dromara/Raincat" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/raincat.png" title="强一致性分布式事务解决方案。" width="15%">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://gitee.com/dromara/myth" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/myth.png" title="可靠消息分布式事务解决方案。" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://cubic.jiagoujishu.com/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/cubic.png" title="一站式问题定位平台,以agent的方式无侵入接入应用,完整集成arthas功能模块,致力于应用级监控,帮助开发人员快速定位问题" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://maxkey.top/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/maxkey.png" title="业界领先的身份管理和认证产品" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="http://forest.dtflyx.com/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/forest-logo.png" title="Forest能够帮助您使用更简单的方式编写Java的HTTP客户端" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://jpom.io/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/jpom.png" title="一款简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://su.usthe.com/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/sureness.png" title="面向 REST API 的高性能认证鉴权框架" width="15%">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://easy-es.cn/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/easy-es2.png" title="傻瓜级ElasticSearch搜索引擎ORM框架" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://gitee.com/dromara/northstar" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/northstar_logo.png" title="Northstar盈富量化交易平台" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://hertzbeat.com/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/hertzbeat_brand.jpg" title="易用友好的云监控系统" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://plugins.sheng90.wang/fast-request/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/fast-request.gif" title="Idea 版 Postman,为简化调试API而生" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://www.jeesuite.com/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/mendmix.png" title="开源分布式云原生架构一站式解决方案" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://gitee.com/dromara/koalas-rpc" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/koalas-rpc2.png" title="企业生产级百亿日PV高可用可拓展的RPC框架。" width="15%">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://async.sizegang.cn/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/gobrs-async.png" title="配置极简功能强大的异步任务动态编排框架" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://dynamictp.cn/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/dynamic-tp.png" title="基于配置中心的轻量级动态可监控线程池" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://www.x-easypdf.cn" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/x-easypdf.png" title="一个用搭积木的方式构建pdf的框架(基于pdfbox)" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="http://dromara.gitee.io/image-combiner" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/image-combiner.png" title="一个专门用于图片合成的工具,没有很复杂的功能,简单实用,却不失强大" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://www.herodotus.cn/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/dante-cloud2.png" title="Dante-Cloud 是一款企业级微服务架构和服务能力开发平台。" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://dromara.org/zh/projects/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/dromara.png" title="让每一位开源爱好者,体会到开源的快乐。" width="15%">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
221
README.zh-CN.md
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
[](https://gitee.com/dromara/electron-egg/stargazers)
|
||||||
|
|
||||||
|
<div align=center>
|
||||||
|
<h3>🎉🎉🎉 ElectronEgg V4 已发布! 🎉🎉🎉</h3>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<div align=center>
|
||||||
|
<img src="./public/images/example/logo.png" width="150" height="150" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align=center>
|
||||||
|
<h3><strong>一个入门简单、跨平台、企业级桌面软件开发框架</strong></h3>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<!-- ## 🌏 [English](https://www.yuque.com/u34495/ee-doc) | [中文](https://www.kaka996.com/) -->
|
||||||
|
|
||||||
|
## 📋 介绍
|
||||||
|
|
||||||
|
> 框架已经广泛应用于记账、政务、企业、医疗、学校、股票交易、ERP、娱乐、视频等领域客户端,请放心使用!
|
||||||
|
|
||||||
|
## 👦 谁可以使用
|
||||||
|
|
||||||
|
项目已经有 5 个交流群,覆盖`前端`、`java`、`go`、`python`、`php` 等开发者。
|
||||||
|
|
||||||
|
无论你是前端、服务端、运维、游戏、客户端等,都可以很快入门,
|
||||||
|
|
||||||
|
## 🐶 精彩案例
|
||||||
|
|
||||||
|
- [**点击查看**](#项目案例)
|
||||||
|
|
||||||
|
## 📺 特点
|
||||||
|
- 🍩 **为什么使用?** 桌面软件(办公方向、 个人工具),仍然是未来十几年PC端需求之一,提高工作效率
|
||||||
|
- 🍉 **简单:** 只需懂 JavaScript
|
||||||
|
- 🍑 **愿景:** 所有开发者都能学会桌面软件研发
|
||||||
|
- 🍰 **gitee:** https://gitee.com/dromara/electron-egg **5100+**
|
||||||
|
- 🍨 **github:** https://github.com/dromara/electron-egg **1800+**
|
||||||
|
- 🏆 码云最有价值开源项目
|
||||||
|

|
||||||
|
|
||||||
|
## 📚 文档
|
||||||
|
- 快速体验:[教程文档](https://www.kaka996.com/)
|
||||||
|

|
||||||
|
|
||||||
|
## 📦 特性
|
||||||
|
1. 🍄 跨平台:一套代码,可以打包成windows版、Mac版、Linux版、国产UOS、Deepin、麒麟等
|
||||||
|
2. 🌹 架构:单业务进程/模块化/多任务(进程,线程,渲染进程),让开发大型项目变的简单。
|
||||||
|
3. 🌱 简单高效:只需学习 js 语言
|
||||||
|
4. 🌴 前端独立:理论上支持任何前端技术,如:vue、react、html等等
|
||||||
|
5. 🍁 工程化:可以用前端、服务端的开发思维,来编写桌面软件
|
||||||
|
6. 🌷 高性能:事件驱动、非阻塞式IO
|
||||||
|
7. 🌰 功能丰富:配置、通信、插件、数据库、升级、打包、工具... 应有尽有
|
||||||
|
8. 💐 安全:支持字节码加密、压缩混淆加密
|
||||||
|
9. 🌻 功能demo:桌面软件常见功能,框架集成或提供demo
|
||||||
|
|
||||||
|
## ✈️ 使用场景
|
||||||
|
|
||||||
|
### 1. 🚀 常规桌面软件
|
||||||
|
- 🚖 windows平台
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- 🚍 macOS平台
|
||||||
|

|
||||||
|
|
||||||
|
- 🚔 linux平台 - 国产UOS、Deepin
|
||||||
|

|
||||||
|
|
||||||
|
- 🚔 linux平台 - ubuntu
|
||||||
|

|
||||||
|
|
||||||
|
### 🚐 2. vue、react、angular、web 转换成桌面软件
|
||||||
|
- 🚙 vue-ant-design(本地)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- 🚙 禅道项目管理(web项目地址)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 🚂 3. 游戏(h5相关技术开发)
|
||||||
|
- 🚊 忍者100层
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
## 📒 开始使用
|
||||||
|
|
||||||
|
- ✒️ [安装文档](https://www.kaka996.com/pages/e64ff6/)
|
||||||
|
|
||||||
|
## 项目案例
|
||||||
|
- 🐟 框架已经应用于医疗、学校、政务、股票交易、ERP、娱乐、视频、企业等领域客户端
|
||||||
|
|
||||||
|
### 🐸 远控
|
||||||
|
|
||||||
|
- RQ Center
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
### 🐸 云盘
|
||||||
|
|
||||||
|
- FM Cloud
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
### 🐸 IM
|
||||||
|
|
||||||
|
- Cede IM
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
### 🐸 壁纸
|
||||||
|
|
||||||
|
- warpar
|
||||||
|

|
||||||
|
|
||||||
|
### 🐸 英雄联盟助手
|
||||||
|
|
||||||
|
- Serendlplty
|
||||||
|

|
||||||
|
|
||||||
|
### 🐸 更多
|
||||||
|
|
||||||
|
- [更多案例](https://www.kaka996.com/pages/eadf46/)
|
||||||
|
|
||||||
|
## 💬 交流
|
||||||
|
1. [讨论](https://www.kaka996.com/pages/c2720e/)
|
||||||
|
|
||||||
|
## 📌 关于pr
|
||||||
|
请前往[GitHub项目](https://github.com/dromara/electron-egg)提pr(避免代码同步后,pr被覆盖掉),感谢!
|
||||||
|
|
||||||
|
地址:https://github.com/dromara/electron-egg
|
||||||
|
|
||||||
|
## 📔 框架核心包 ee-core
|
||||||
|
ee-core:[https://github.com/wallace5303/ee-core](https://github.com/wallace5303/ee-core)
|
||||||
|
|
||||||
|
## 📚 Dromara 成员项目
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://gitee.com/dromara/TLog" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/tlog2.png" title="一个轻量级的分布式日志标记追踪神器,10分钟即可接入,自动对日志打标签完成微服务的链路追踪" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://gitee.com/dromara/liteFlow" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/liteflow.png" title="轻量,快速,稳定,可编排的组件式流程引擎" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://hutool.cn/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/hutool.jpg" title="小而全的Java工具类库,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://sa-token.dev33.cn/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/sa-token.png" title="一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://gitee.com/dromara/hmily" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/hmily.png" title="高性能一站式分布式事务解决方案。" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://gitee.com/dromara/Raincat" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/raincat.png" title="强一致性分布式事务解决方案。" width="15%">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://gitee.com/dromara/myth" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/myth.png" title="可靠消息分布式事务解决方案。" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://cubic.jiagoujishu.com/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/cubic.png" title="一站式问题定位平台,以agent的方式无侵入接入应用,完整集成arthas功能模块,致力于应用级监控,帮助开发人员快速定位问题" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://maxkey.top/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/maxkey.png" title="业界领先的身份管理和认证产品" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="http://forest.dtflyx.com/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/forest-logo.png" title="Forest能够帮助您使用更简单的方式编写Java的HTTP客户端" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://jpom.io/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/jpom.png" title="一款简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://su.usthe.com/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/sureness.png" title="面向 REST API 的高性能认证鉴权框架" width="15%">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://easy-es.cn/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/easy-es2.png" title="傻瓜级ElasticSearch搜索引擎ORM框架" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://gitee.com/dromara/northstar" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/northstar_logo.png" title="Northstar盈富量化交易平台" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://hertzbeat.com/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/hertzbeat_brand.jpg" title="易用友好的云监控系统" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://plugins.sheng90.wang/fast-request/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/fast-request.gif" title="Idea 版 Postman,为简化调试API而生" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://www.jeesuite.com/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/mendmix.png" title="开源分布式云原生架构一站式解决方案" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://gitee.com/dromara/koalas-rpc" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/koalas-rpc2.png" title="企业生产级百亿日PV高可用可拓展的RPC框架。" width="15%">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://async.sizegang.cn/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/gobrs-async.png" title="配置极简功能强大的异步任务动态编排框架" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://dynamictp.cn/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/dynamic-tp.png" title="基于配置中心的轻量级动态可监控线程池" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://www.x-easypdf.cn" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/x-easypdf.png" title="一个用搭积木的方式构建pdf的框架(基于pdfbox)" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="http://dromara.gitee.io/image-combiner" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/image-combiner.png" title="一个专门用于图片合成的工具,没有很复杂的功能,简单实用,却不失强大" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://www.herodotus.cn/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/dante-cloud2.png" title="Dante-Cloud 是一款企业级微服务架构和服务能力开发平台。" width="15%">
|
||||||
|
</a>
|
||||||
|
<a href="https://dromara.org/zh/projects/" target="_blank">
|
||||||
|
<img src="https://oss.dev33.cn/sa-token/link/dromara.png" title="让每一位开源爱好者,体会到开源的快乐。" width="15%">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
1
build/extraResources/chromeExtension/read.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
chrome应用商店ctx文件,解压后,放置在此目录中,打包时会将资源加入安装包内。
|
||||||
1
build/extraResources/read.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
建议第三方软件放置在此目录中,打包时会将资源加入安装包内。
|
||||||
BIN
build/icons/256x256.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
build/icons/32x32.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
build/icons/512x512.png
Normal file
|
After Width: | Height: | Size: 169 KiB |
BIN
build/icons/64x64.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
build/icons/favicon.ico
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
build/icons/icon.ico
Normal file
|
After Width: | Height: | Size: 256 KiB |
0
build/script/installer.nsh
Normal file
199
cmd/bin.js
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
/**
|
||||||
|
* ee-bin 配置
|
||||||
|
* 仅适用于开发环境
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* development serve ("frontend" "electron" )
|
||||||
|
* ee-bin dev
|
||||||
|
*/
|
||||||
|
dev: {
|
||||||
|
frontend: {
|
||||||
|
directory: './frontend',
|
||||||
|
cmd: 'npm',
|
||||||
|
args: ['run', 'dev'],
|
||||||
|
port: 8080,
|
||||||
|
},
|
||||||
|
electron: {
|
||||||
|
directory: './',
|
||||||
|
cmd: 'electron',
|
||||||
|
args: ['.', '--env=local'],
|
||||||
|
watch: true,
|
||||||
|
delay: 1000,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建
|
||||||
|
* ee-bin build
|
||||||
|
*/
|
||||||
|
build: {
|
||||||
|
frontend: {
|
||||||
|
directory: './frontend',
|
||||||
|
cmd: 'npm',
|
||||||
|
args: ['run', 'build'],
|
||||||
|
},
|
||||||
|
electron: {
|
||||||
|
type: 'typescript',
|
||||||
|
},
|
||||||
|
win64: {
|
||||||
|
cmd: 'electron-builder',
|
||||||
|
directory: './',
|
||||||
|
args: ['--config=./cmd/builder.json', '-w=nsis', '--x64'],
|
||||||
|
},
|
||||||
|
win32: {
|
||||||
|
args: ['--config=./cmd/builder.json', '-w=nsis', '--ia32'],
|
||||||
|
},
|
||||||
|
win_e: {
|
||||||
|
args: ['--config=./cmd/builder.json', '-w=portable', '--x64'],
|
||||||
|
},
|
||||||
|
win_7z: {
|
||||||
|
args: ['--config=./cmd/builder.json', '-w=7z', '--x64'],
|
||||||
|
},
|
||||||
|
mac: {
|
||||||
|
args: ['--config=./cmd/builder-mac.json', '-m'],
|
||||||
|
},
|
||||||
|
mac_arm64: {
|
||||||
|
args: ['--config=./cmd/builder-mac-arm64.json', '-m', '--arm64'],
|
||||||
|
},
|
||||||
|
linux: {
|
||||||
|
args: ['--config=./cmd/builder-linux.json', '-l=deb', '--x64'],
|
||||||
|
},
|
||||||
|
linux_arm64: {
|
||||||
|
args: ['--config=./cmd/builder-linux.json', '-l=deb', '--arm64'],
|
||||||
|
},
|
||||||
|
go_w: {
|
||||||
|
directory: './go',
|
||||||
|
cmd: 'go',
|
||||||
|
args: ['build', '-o=../build/extraResources/goapp.exe'],
|
||||||
|
},
|
||||||
|
go_m: {
|
||||||
|
directory: './go',
|
||||||
|
cmd: 'go',
|
||||||
|
args: ['build', '-o=../build/extraResources/goapp'],
|
||||||
|
},
|
||||||
|
go_l: {
|
||||||
|
directory: './go',
|
||||||
|
cmd: 'go',
|
||||||
|
args: ['build', '-o=../build/extraResources/goapp'],
|
||||||
|
},
|
||||||
|
python: {
|
||||||
|
directory: './python',
|
||||||
|
cmd: 'python',
|
||||||
|
args: ['./setup.py', 'build'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移动资源
|
||||||
|
* ee-bin move
|
||||||
|
*/
|
||||||
|
move: {
|
||||||
|
frontend_dist: {
|
||||||
|
src: './frontend/dist',
|
||||||
|
dest: './public/dist'
|
||||||
|
},
|
||||||
|
go_static: {
|
||||||
|
src: './frontend/dist',
|
||||||
|
dest: './go/public/dist'
|
||||||
|
},
|
||||||
|
go_config: {
|
||||||
|
src: './go/config',
|
||||||
|
dest: './go/public/config'
|
||||||
|
},
|
||||||
|
go_package: {
|
||||||
|
src: './package.json',
|
||||||
|
dest: './go/public/package.json'
|
||||||
|
},
|
||||||
|
go_images: {
|
||||||
|
src: './public/images',
|
||||||
|
dest: './go/public/images'
|
||||||
|
},
|
||||||
|
python_dist: {
|
||||||
|
src: './python/dist',
|
||||||
|
dest: './build/extraResources/py'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预发布模式(prod)
|
||||||
|
* ee-bin start
|
||||||
|
*/
|
||||||
|
start: {
|
||||||
|
directory: './',
|
||||||
|
cmd: 'electron',
|
||||||
|
args: ['.', '--env=prod']
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密
|
||||||
|
*/
|
||||||
|
encrypt: {
|
||||||
|
frontend: {
|
||||||
|
type: 'none',
|
||||||
|
files: [
|
||||||
|
'./public/dist/**/*.(js|json)',
|
||||||
|
],
|
||||||
|
cleanFiles: ['./public/dist'],
|
||||||
|
confusionOptions: {
|
||||||
|
compact: true,
|
||||||
|
stringArray: true,
|
||||||
|
stringArrayEncoding: ['none'],
|
||||||
|
stringArrayCallsTransform: true,
|
||||||
|
numbersToExpressions: true,
|
||||||
|
target: 'browser',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
electron: {
|
||||||
|
type: 'confusion',
|
||||||
|
files: [
|
||||||
|
'./public/electron/**/*.(js|json)',
|
||||||
|
],
|
||||||
|
cleanFiles: ['./public/electron'],
|
||||||
|
specificFiles: [
|
||||||
|
'./public/electron/main.js',
|
||||||
|
'./public/electron/preload/bridge.js',
|
||||||
|
],
|
||||||
|
confusionOptions: {
|
||||||
|
compact: true,
|
||||||
|
stringArray: true,
|
||||||
|
stringArrayEncoding: ['none'],
|
||||||
|
deadCodeInjection: false,
|
||||||
|
stringArrayCallsTransform: true,
|
||||||
|
numbersToExpressions: true,
|
||||||
|
target: 'node',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行自定义命令
|
||||||
|
* ee-bin exec
|
||||||
|
*/
|
||||||
|
exec: {
|
||||||
|
// 单独调试,air 实现 go 热重载
|
||||||
|
go: {
|
||||||
|
directory: './go',
|
||||||
|
cmd: 'air',
|
||||||
|
args: ['-c=config/.air.toml' ],
|
||||||
|
},
|
||||||
|
// windows 单独调试,air 实现 go 热重载
|
||||||
|
go_w: {
|
||||||
|
directory: './go',
|
||||||
|
cmd: 'air',
|
||||||
|
args: ['-c=config/.air.windows.toml' ],
|
||||||
|
},
|
||||||
|
// 单独调试,以基础方式启动 go
|
||||||
|
go2: {
|
||||||
|
directory: './go',
|
||||||
|
cmd: 'go',
|
||||||
|
args: ['run', './main.go', '--env=dev','--basedir=../', '--port=7073'],
|
||||||
|
},
|
||||||
|
python: {
|
||||||
|
directory: './python',
|
||||||
|
cmd: 'python',
|
||||||
|
args: ['./main.py', '--port=7074'],
|
||||||
|
stdio: "inherit", // ignore
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
40
cmd/builder-linux.json
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"productName": "PQS9100工具箱",
|
||||||
|
"appId": "com.njcn.pqs9100.tool",
|
||||||
|
"copyright": "© 2025 njcn Technology Co., Ltd.",
|
||||||
|
"directories": {
|
||||||
|
"output": "out"
|
||||||
|
},
|
||||||
|
"asar": true,
|
||||||
|
"files": [
|
||||||
|
"**/*",
|
||||||
|
"!cmd/",
|
||||||
|
"!data/",
|
||||||
|
"!electron/",
|
||||||
|
"!frontend/",
|
||||||
|
"!logs/",
|
||||||
|
"!out/",
|
||||||
|
"!go/",
|
||||||
|
"!python/"
|
||||||
|
],
|
||||||
|
"extraResources": [
|
||||||
|
{
|
||||||
|
"from": "build/extraResources",
|
||||||
|
"to": "extraResources"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"publish": [
|
||||||
|
{
|
||||||
|
"provider": "generic",
|
||||||
|
"url": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"linux": {
|
||||||
|
"icon": "build/icons/icon.icns",
|
||||||
|
"artifactName": "${productName}-${os}-${version}-${arch}.${ext}",
|
||||||
|
"target": [
|
||||||
|
"deb"
|
||||||
|
],
|
||||||
|
"category": "Utility"
|
||||||
|
}
|
||||||
|
}
|
||||||
38
cmd/builder-mac-arm64.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"productName": "PQS9100工具箱",
|
||||||
|
"appId": "com.njcn.pqs9100.tool",
|
||||||
|
"copyright": "© 2025 njcn Technology Co., Ltd.",
|
||||||
|
"directories": {
|
||||||
|
"output": "out"
|
||||||
|
},
|
||||||
|
"asar": true,
|
||||||
|
"files": [
|
||||||
|
"**/*",
|
||||||
|
"!cmd/",
|
||||||
|
"!data/",
|
||||||
|
"!electron/",
|
||||||
|
"!frontend/",
|
||||||
|
"!logs/",
|
||||||
|
"!out/",
|
||||||
|
"!go/",
|
||||||
|
"!python/"
|
||||||
|
],
|
||||||
|
"extraResources": [
|
||||||
|
{
|
||||||
|
"from": "build/extraResources",
|
||||||
|
"to": "extraResources"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"publish": [
|
||||||
|
{
|
||||||
|
"provider": "generic",
|
||||||
|
"url": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mac": {
|
||||||
|
"icon": "build/icons/icon.icns",
|
||||||
|
"artifactName": "${productName}-${os}-${version}-${arch}.${ext}",
|
||||||
|
"darkModeSupport": true,
|
||||||
|
"hardenedRuntime": false
|
||||||
|
}
|
||||||
|
}
|
||||||
38
cmd/builder-mac.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"productName": "PQS9100工具箱",
|
||||||
|
"appId": "com.njcn.pqs9100.tool",
|
||||||
|
"copyright": "© 2025 njcn Technology Co., Ltd.",
|
||||||
|
"directories": {
|
||||||
|
"output": "out"
|
||||||
|
},
|
||||||
|
"asar": true,
|
||||||
|
"files": [
|
||||||
|
"**/*",
|
||||||
|
"!cmd/",
|
||||||
|
"!data/",
|
||||||
|
"!electron/",
|
||||||
|
"!frontend/",
|
||||||
|
"!logs/",
|
||||||
|
"!out/",
|
||||||
|
"!go/",
|
||||||
|
"!python/"
|
||||||
|
],
|
||||||
|
"extraResources": [
|
||||||
|
{
|
||||||
|
"from": "build/extraResources",
|
||||||
|
"to": "extraResources"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"publish": [
|
||||||
|
{
|
||||||
|
"provider": "generic",
|
||||||
|
"url": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mac": {
|
||||||
|
"icon": "build/icons/icon.icns",
|
||||||
|
"artifactName": "${productName}-${os}-${version}-${arch}.${ext}",
|
||||||
|
"darkModeSupport": true,
|
||||||
|
"hardenedRuntime": false
|
||||||
|
}
|
||||||
|
}
|
||||||
50
cmd/builder.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"productName": "PQS9100工具箱",
|
||||||
|
"appId": "com.njcn.pqs9100.tool",
|
||||||
|
"copyright": "© 2025 njcn Technology Co., Ltd.",
|
||||||
|
"directories": {
|
||||||
|
"output": "out"
|
||||||
|
},
|
||||||
|
"asar": true,
|
||||||
|
"files": [
|
||||||
|
"**/*",
|
||||||
|
"!cmd/",
|
||||||
|
"!data/",
|
||||||
|
"!electron/",
|
||||||
|
"!frontend/",
|
||||||
|
"!logs/",
|
||||||
|
"!out/",
|
||||||
|
"!go/",
|
||||||
|
"!python/"
|
||||||
|
],
|
||||||
|
"extraResources": {
|
||||||
|
"from": "build/extraResources/",
|
||||||
|
"to": "extraResources"
|
||||||
|
},
|
||||||
|
"nsis": {
|
||||||
|
"oneClick": false,
|
||||||
|
"allowElevation": true,
|
||||||
|
"allowToChangeInstallationDirectory": true,
|
||||||
|
"installerIcon": "build/icons/icon.ico",
|
||||||
|
"uninstallerIcon": "build/icons/icon.ico",
|
||||||
|
"installerHeaderIcon": "build/icons/icon.ico",
|
||||||
|
"createDesktopShortcut": true,
|
||||||
|
"createStartMenuShortcut": true,
|
||||||
|
"shortcutName": "PQS9100工具箱"
|
||||||
|
},
|
||||||
|
"publish": [
|
||||||
|
{
|
||||||
|
"provider": "generic",
|
||||||
|
"url": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"win": {
|
||||||
|
"icon": "build/icons/icon.ico",
|
||||||
|
"artifactName": "${productName}-${os}-${version}-${arch}.${ext}",
|
||||||
|
"target": [
|
||||||
|
{
|
||||||
|
"target": "nsis"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
66
electron/config/config.default.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import path from 'path';
|
||||||
|
import {getBaseDir} from 'ee-core/ps';
|
||||||
|
import {type AppConfig} from 'ee-core/config';
|
||||||
|
|
||||||
|
const config: () => AppConfig = () => {
|
||||||
|
return {
|
||||||
|
openDevTools: false,
|
||||||
|
singleLock: true,
|
||||||
|
windowsOption: {
|
||||||
|
title: 'PQS9100工具箱', // 软件标题
|
||||||
|
width: 980, // 软件窗口宽度
|
||||||
|
height: 650, // 软件窗口高度
|
||||||
|
minWidth: 800, // 软件窗口最小宽度
|
||||||
|
minHeight: 650, // 软件窗口最小高度
|
||||||
|
autoHideMenuBar: true, // 默认不显示菜单栏,
|
||||||
|
webPreferences: {
|
||||||
|
webSecurity: true,
|
||||||
|
contextIsolation: false,
|
||||||
|
nodeIntegration: true,
|
||||||
|
},
|
||||||
|
frame: true,
|
||||||
|
show: false,
|
||||||
|
icon: path.join(getBaseDir(), 'public', 'images', 'logo-32.png'),
|
||||||
|
},
|
||||||
|
logger: {
|
||||||
|
level: 'INFO',
|
||||||
|
outputJSON: false,
|
||||||
|
appLogName: 'pqs-9100_tool.log',
|
||||||
|
coreLogName: 'pqs-9100_tool-core.log',
|
||||||
|
errorLogName: 'pqs-9100_tool-error.log',
|
||||||
|
},
|
||||||
|
remote: {
|
||||||
|
enable: false,
|
||||||
|
url: '',
|
||||||
|
},
|
||||||
|
socketServer: {
|
||||||
|
enable: true,
|
||||||
|
port: 7070,
|
||||||
|
path: "/socket.io/",
|
||||||
|
connectTimeout: 45000,
|
||||||
|
pingTimeout: 30000,
|
||||||
|
pingInterval: 25000,
|
||||||
|
maxHttpBufferSize: 1e8,
|
||||||
|
transports: ["polling", "websocket"],
|
||||||
|
cors: {
|
||||||
|
origin: true,
|
||||||
|
},
|
||||||
|
channel: 'socket-channel',
|
||||||
|
},
|
||||||
|
httpServer: {
|
||||||
|
enable: true,
|
||||||
|
https: {
|
||||||
|
enable: false,
|
||||||
|
key: '/public/ssl/localhost+1.key',
|
||||||
|
cert: '/public/ssl/localhost+1.pem',
|
||||||
|
},
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: 7071,
|
||||||
|
},
|
||||||
|
mainServer: {
|
||||||
|
indexPath: '/public/dist/index.html',
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
14
electron/config/config.local.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { type AppConfig } from 'ee-core/config';
|
||||||
|
|
||||||
|
const config: () => AppConfig = () => {
|
||||||
|
return {
|
||||||
|
openDevTools: {
|
||||||
|
mode: 'bottom'
|
||||||
|
},
|
||||||
|
jobs: {
|
||||||
|
messageLog: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
9
electron/config/config.prod.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { type AppConfig } from 'ee-core/config';
|
||||||
|
|
||||||
|
const config: () => AppConfig = () => {
|
||||||
|
return {
|
||||||
|
openDevTools: false,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
63
electron/controller/cross.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import { crossService } from '../service/cross';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cross
|
||||||
|
* @class
|
||||||
|
*/
|
||||||
|
class CrossController {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View process service information
|
||||||
|
*/
|
||||||
|
info() {
|
||||||
|
crossService.info();
|
||||||
|
return 'hello electron-egg';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get service url
|
||||||
|
*/
|
||||||
|
async getUrl(args: { name: string }): Promise<string> {
|
||||||
|
const { name } = args;
|
||||||
|
const serverUrl = crossService.getUrl(name);
|
||||||
|
return serverUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* kill service
|
||||||
|
* By default (modifiable), killing the process will exit the electron application.
|
||||||
|
*/
|
||||||
|
async killServer(args: { type: string; name: string }): Promise<void> {
|
||||||
|
const { type, name } = args;
|
||||||
|
crossService.killServer(type, name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create service
|
||||||
|
*/
|
||||||
|
async createServer(args: { program: string }): Promise<void> {
|
||||||
|
const { program } = args;
|
||||||
|
if (program == 'go') {
|
||||||
|
crossService.createGoServer();
|
||||||
|
} else if (program == 'java') {
|
||||||
|
crossService.createJavaServer();
|
||||||
|
} else if (program == 'python') {
|
||||||
|
crossService.createPythonServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access the api for the cross service
|
||||||
|
*/
|
||||||
|
async requestApi(args: { name: string; urlPath: string; params: any }): Promise<any> {
|
||||||
|
const { name, urlPath, params} = args;
|
||||||
|
const data = await crossService.requestApi(name, urlPath, params);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CrossController.toString = () => '[class CrossController]';
|
||||||
|
|
||||||
|
export default CrossController;
|
||||||
63
electron/controller/effect.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import { dialog } from 'electron';
|
||||||
|
import { getMainWindow } from 'ee-core/electron';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* effect - demo
|
||||||
|
* @class
|
||||||
|
*/
|
||||||
|
class EffectController {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* select file
|
||||||
|
*/
|
||||||
|
selectFile(): string | null {
|
||||||
|
const filePaths = dialog.showOpenDialogSync({
|
||||||
|
properties: ['openFile']
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!filePaths) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return filePaths[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* login window
|
||||||
|
*/
|
||||||
|
loginWindow(args: { width?: number; height?: number }): void {
|
||||||
|
const { width, height } = args;
|
||||||
|
const win = getMainWindow();
|
||||||
|
|
||||||
|
const size = {
|
||||||
|
width: width || 400,
|
||||||
|
height: height || 300
|
||||||
|
}
|
||||||
|
win.setSize(size.width, size.height);
|
||||||
|
win.setResizable(true);
|
||||||
|
win.center();
|
||||||
|
win.show();
|
||||||
|
win.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* restore window
|
||||||
|
*/
|
||||||
|
restoreWindow(args: { width?: number; height?: number }): void {
|
||||||
|
const { width, height } = args;
|
||||||
|
const win = getMainWindow();
|
||||||
|
|
||||||
|
const size = {
|
||||||
|
width: width || 980,
|
||||||
|
height: height || 650
|
||||||
|
}
|
||||||
|
win.setSize(size.width, size.height);
|
||||||
|
win.setResizable(true);
|
||||||
|
win.center();
|
||||||
|
win.show();
|
||||||
|
win.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EffectController.toString = () => '[class EffectController]';
|
||||||
|
|
||||||
|
export default EffectController;
|
||||||
16
electron/controller/example.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* example
|
||||||
|
* @class
|
||||||
|
*/
|
||||||
|
class ExampleController {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test
|
||||||
|
*/
|
||||||
|
async test(): Promise<string> {
|
||||||
|
return 'hello electron-egg';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExampleController.toString = () => '[class ExampleController]';
|
||||||
|
|
||||||
|
export default ExampleController;
|
||||||
167
electron/controller/os.ts
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { app as electronApp, dialog, shell } from 'electron';
|
||||||
|
import { windowService } from '../service/os/window';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* example
|
||||||
|
* @class
|
||||||
|
*/
|
||||||
|
class OsController {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All methods receive two parameters
|
||||||
|
* @param args Parameters transmitted by the frontend
|
||||||
|
* @param event - Event are only available during IPC communication. For details, please refer to the controller documentation
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message prompt dialog box
|
||||||
|
*/
|
||||||
|
messageShow(): string {
|
||||||
|
dialog.showMessageBoxSync({
|
||||||
|
type: 'info', // "none", "info", "error", "question" 或者 "warning"
|
||||||
|
title: 'Custom Title',
|
||||||
|
message: 'Customize message content',
|
||||||
|
detail: 'Other additional information'
|
||||||
|
})
|
||||||
|
|
||||||
|
return 'Opened the message box';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message prompt and confirmation dialog box
|
||||||
|
*/
|
||||||
|
messageShowConfirm(): string {
|
||||||
|
const res = dialog.showMessageBoxSync({
|
||||||
|
type: 'info',
|
||||||
|
title: 'Custom Title',
|
||||||
|
message: 'Customize message content',
|
||||||
|
detail: 'Other additional information',
|
||||||
|
cancelId: 1, // Index of buttons used to cancel dialog boxes
|
||||||
|
defaultId: 0, // Set default selected button
|
||||||
|
buttons: ['confirm', 'cancel'],
|
||||||
|
})
|
||||||
|
let data = (res === 0) ? 'click the confirm button' : 'click the cancel button';
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select Directory
|
||||||
|
*/
|
||||||
|
selectFolder() {
|
||||||
|
const filePaths = dialog.showOpenDialogSync({
|
||||||
|
properties: ['openDirectory', 'createDirectory']
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!filePaths) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return filePaths[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* open directory
|
||||||
|
*/
|
||||||
|
openDirectory(args: { id: any }): boolean {
|
||||||
|
const { id } = args;
|
||||||
|
if (!id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let dir = '';
|
||||||
|
if (path.isAbsolute(id)) {
|
||||||
|
dir = id;
|
||||||
|
} else {
|
||||||
|
dir = electronApp.getPath(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
shell.openPath(dir);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select Picture
|
||||||
|
*/
|
||||||
|
selectPic(): string | null {
|
||||||
|
const filePaths = dialog.showOpenDialogSync({
|
||||||
|
title: 'select pic',
|
||||||
|
properties: ['openFile'],
|
||||||
|
filters: [
|
||||||
|
{ name: 'Images', extensions: ['jpg', 'png', 'gif'] },
|
||||||
|
]
|
||||||
|
});
|
||||||
|
if (!filePaths) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = fs.readFileSync(filePaths[0]);
|
||||||
|
const pic = 'data:image/jpeg;base64,' + data.toString('base64');
|
||||||
|
return pic;
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a new window
|
||||||
|
*/
|
||||||
|
createWindow(args: any): any {
|
||||||
|
const wcid = windowService.createWindow(args);
|
||||||
|
return wcid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Window contents id
|
||||||
|
*/
|
||||||
|
getWCid(args: any): any {
|
||||||
|
const wcid = windowService.getWCid(args);
|
||||||
|
return wcid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Realize communication between two windows through the transfer of the main process
|
||||||
|
*/
|
||||||
|
window1ToWindow2(args: any): void {
|
||||||
|
windowService.communicate(args);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Realize communication between two windows through the transfer of the main process
|
||||||
|
*/
|
||||||
|
window2ToWindow1(args: any): void {
|
||||||
|
windowService.communicate(args);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create system notifications
|
||||||
|
*/
|
||||||
|
sendNotification(args: { title?: string; subtitle?: string; body?: string; silent?: boolean }, event: any): boolean {
|
||||||
|
const { title, subtitle, body, silent} = args;
|
||||||
|
|
||||||
|
const options: any = {};
|
||||||
|
if (title) {
|
||||||
|
options.title = title;
|
||||||
|
}
|
||||||
|
if (subtitle) {
|
||||||
|
options.subtitle = subtitle;
|
||||||
|
}
|
||||||
|
if (body) {
|
||||||
|
options.body = body;
|
||||||
|
}
|
||||||
|
if (silent !== undefined) {
|
||||||
|
options.silent = silent;
|
||||||
|
}
|
||||||
|
windowService.createNotification(options, event);
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OsController.toString = () => '[class OsController]';
|
||||||
|
|
||||||
|
export default OsController;
|
||||||
10
electron/jobs/example/hello.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { logger } from 'ee-core/log';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Welcome function
|
||||||
|
*/
|
||||||
|
function welcome(): void {
|
||||||
|
logger.info('[child-process] [jobs/example/hello] welcome !');
|
||||||
|
}
|
||||||
|
|
||||||
|
export { welcome };
|
||||||
98
electron/jobs/example/timer.ts
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
import { logger } from 'ee-core/log';
|
||||||
|
import { isChildJob, exit } from 'ee-core/ps';
|
||||||
|
import { childMessage } from 'ee-core/message';
|
||||||
|
import { welcome } from './hello';
|
||||||
|
import { UserService } from '../../service/job/user';
|
||||||
|
import { sqlitedbService } from '../../service/database/sqlitedb';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* example - TimerJob
|
||||||
|
* @class
|
||||||
|
*/
|
||||||
|
class TimerJob {
|
||||||
|
timer: NodeJS.Timeout | undefined;
|
||||||
|
timeoutTimer: NodeJS.Timeout | undefined;
|
||||||
|
number: number;
|
||||||
|
countdown: number;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.timer = undefined;
|
||||||
|
this.timeoutTimer = undefined;
|
||||||
|
this.number = 0;
|
||||||
|
this.countdown = 10; // 倒计时
|
||||||
|
sqlitedbService.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handle() method is necessary and will be automatically called
|
||||||
|
* params transferred parameters
|
||||||
|
*/
|
||||||
|
async handle(params: any): Promise<void> {
|
||||||
|
logger.info("[child-process] TimerJob params: ", params);
|
||||||
|
const { jobId } = params;
|
||||||
|
|
||||||
|
// Use service in child process
|
||||||
|
// 1. Ensure that the service does not have Electron's API or dependencies, as Electron does not support them
|
||||||
|
const userService = new UserService();
|
||||||
|
userService.hello('job');
|
||||||
|
|
||||||
|
// Execute the task
|
||||||
|
this.number = 0;
|
||||||
|
this.countdown = 10;
|
||||||
|
this.doTimer(jobId);
|
||||||
|
|
||||||
|
// sqlite
|
||||||
|
const userList = await sqlitedbService.getAllTestDataSqlite();
|
||||||
|
logger.info('[child-process] Sqlite userList:', userList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pause the job
|
||||||
|
*/
|
||||||
|
async pause(jobId: string): Promise<void> {
|
||||||
|
logger.info("[child-process] Pause timerJob, jobId: ", jobId);
|
||||||
|
clearInterval(this.timer);
|
||||||
|
clearInterval(this.timeoutTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resume the job
|
||||||
|
*/
|
||||||
|
async resume(jobId: string, pid: number): Promise<void> {
|
||||||
|
logger.info("[child-process] Resume timerJob, jobId: ", jobId, ", pid: ", pid);
|
||||||
|
this.doTimer(jobId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the task
|
||||||
|
*/
|
||||||
|
async doTimer(jobId) {
|
||||||
|
// Timer to simulate the task
|
||||||
|
const eventName = 'job-timer-progress-' + jobId;
|
||||||
|
this.timer = setInterval(() => {
|
||||||
|
welcome();
|
||||||
|
|
||||||
|
childMessage.send(eventName, {jobId, number: this.number, end: false});
|
||||||
|
this.number++;
|
||||||
|
this.countdown--;
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
// Use setTimeout to simulate the task duration
|
||||||
|
this.timeoutTimer = setTimeout(() => {
|
||||||
|
// Stop the timer to simulate the task
|
||||||
|
clearInterval(this.timer);
|
||||||
|
|
||||||
|
// Task completed, reset the front-end display
|
||||||
|
childMessage.send(eventName, {jobId, number:0, pid:0, end: true});
|
||||||
|
|
||||||
|
// If it is a childJob task, call exit() to exit the process, otherwise it will stay in memory
|
||||||
|
// If it is a childPoolJob task, stay in memory and wait for the next business
|
||||||
|
if (isChildJob()) {
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
}, this.countdown * 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TimerJob.toString = () => '[class TimerJob]';
|
||||||
|
|
||||||
|
export default TimerJob;
|
||||||
19
electron/main.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { ElectronEgg } from 'ee-core';
|
||||||
|
import { Lifecycle } from './preload/lifecycle';
|
||||||
|
import { preload } from './preload';
|
||||||
|
|
||||||
|
// New app
|
||||||
|
const app = new ElectronEgg();
|
||||||
|
|
||||||
|
// Register lifecycle
|
||||||
|
const life = new Lifecycle();
|
||||||
|
app.register("ready", life.ready);
|
||||||
|
app.register("electron-app-ready", life.electronAppReady);
|
||||||
|
app.register("window-ready", life.windowReady);
|
||||||
|
app.register("before-close", life.beforeClose);
|
||||||
|
|
||||||
|
// Register preload
|
||||||
|
app.register("preload", preload);
|
||||||
|
|
||||||
|
// Run
|
||||||
|
app.run();
|
||||||
16
electron/preload/bridge.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* 如果启用了上下文隔离,渲染进程无法使用electron的api,
|
||||||
|
* 可通过contextBridge 导出api给渲染进程使用
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { type IpcRenderer, contextBridge, ipcRenderer } from 'electron';
|
||||||
|
|
||||||
|
// 确保contextBridge.exposeInMainWorld的参数类型正确,这里进行简单的类型定义示例
|
||||||
|
type ElectronApi = {
|
||||||
|
ipcRenderer: IpcRenderer;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ele: ElectronApi = {
|
||||||
|
ipcRenderer,
|
||||||
|
};
|
||||||
|
contextBridge.exposeInMainWorld('electron', ele);
|
||||||
21
electron/preload/index.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* Preload module, this file will be loaded when the program starts.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {logger} from 'ee-core/log';
|
||||||
|
import {trayService} from '../service/os/tray';
|
||||||
|
import {securityService} from '../service/os/security';
|
||||||
|
import {autoUpdaterService} from '../service/os/auto_updater';
|
||||||
|
|
||||||
|
function preload(): void {
|
||||||
|
// Example feature module, optional to use and modify
|
||||||
|
logger.info('[preload] load 5');
|
||||||
|
trayService.create();
|
||||||
|
securityService.create();
|
||||||
|
autoUpdaterService.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry point of the preload module
|
||||||
|
*/
|
||||||
|
export { preload };
|
||||||
70
electron/preload/lifecycle.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import { app as electronApp, screen } from 'electron';
|
||||||
|
import { logger } from 'ee-core/log';
|
||||||
|
import { getConfig } from 'ee-core/config';
|
||||||
|
import { getMainWindow } from 'ee-core/electron';
|
||||||
|
|
||||||
|
class Lifecycle {
|
||||||
|
/**
|
||||||
|
* Core app has been loaded
|
||||||
|
*/
|
||||||
|
async ready(): Promise<void> {
|
||||||
|
logger.info('[lifecycle] ready');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Electron app is ready
|
||||||
|
*/
|
||||||
|
async electronAppReady(): Promise<void> {
|
||||||
|
logger.info('[lifecycle] electron-app-ready');
|
||||||
|
|
||||||
|
// When double clicking the icon, display the opened window
|
||||||
|
electronApp.on('second-instance', () => {
|
||||||
|
const win = getMainWindow();
|
||||||
|
if (win.isMinimized()) {
|
||||||
|
win.restore();
|
||||||
|
}
|
||||||
|
win.show();
|
||||||
|
win.focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main window has been loaded
|
||||||
|
*/
|
||||||
|
async windowReady(): Promise<void> {
|
||||||
|
logger.info('[lifecycle] window-ready');
|
||||||
|
|
||||||
|
const win = getMainWindow();
|
||||||
|
|
||||||
|
// The window is centered and scaled proportionally
|
||||||
|
// Obtain the size information of the main screen, calculate the width and height of the window as a percentage of the screen,
|
||||||
|
// and calculate the coordinates of the upper left corner when the window is centered
|
||||||
|
const mainScreen = screen.getPrimaryDisplay();
|
||||||
|
const { width, height } = mainScreen.workAreaSize;
|
||||||
|
const windowWidth = Math.floor(width * 0.6);
|
||||||
|
const windowHeight = Math.floor(height * 0.8);
|
||||||
|
const x = Math.floor((width - windowWidth) / 2);
|
||||||
|
const y = Math.floor((height - windowHeight) / 2);
|
||||||
|
win.setBounds({ x, y, width: windowWidth, height: windowHeight });
|
||||||
|
|
||||||
|
// Delay loading, no white screen
|
||||||
|
const config = getConfig();
|
||||||
|
const { windowsOption } = config;
|
||||||
|
if (windowsOption?.show == false) {
|
||||||
|
win.once('ready-to-show', () => {
|
||||||
|
win.show();
|
||||||
|
win.focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Before app close
|
||||||
|
*/
|
||||||
|
async beforeClose(): Promise<void> {
|
||||||
|
logger.info('[lifecycle] before-close');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Lifecycle.toString = () => '[class Lifecycle]';
|
||||||
|
|
||||||
|
export { Lifecycle };
|
||||||
144
electron/service/cross.ts
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
import { logger } from 'ee-core/log';
|
||||||
|
import { getExtraResourcesDir, getLogDir } from 'ee-core/ps';
|
||||||
|
import path from 'path';
|
||||||
|
import axios from 'axios';
|
||||||
|
import { is } from 'ee-core/utils';
|
||||||
|
import { cross } from 'ee-core/cross';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cross
|
||||||
|
* @class
|
||||||
|
*/
|
||||||
|
class CrossService {
|
||||||
|
|
||||||
|
info(): string {
|
||||||
|
const pids = cross.getPids();
|
||||||
|
logger.info('cross pids:', pids);
|
||||||
|
|
||||||
|
let num = 1;
|
||||||
|
pids.forEach(pid => {
|
||||||
|
let entity = cross.getProc(pid);
|
||||||
|
logger.info(`server-${num} name:${entity.name}`);
|
||||||
|
logger.info(`server-${num} config:`, entity.config);
|
||||||
|
num++;
|
||||||
|
})
|
||||||
|
|
||||||
|
return 'hello electron-egg';
|
||||||
|
}
|
||||||
|
|
||||||
|
getUrl(name: string): string {
|
||||||
|
const serverUrl = cross.getUrl(name);
|
||||||
|
return serverUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
killServer(type: string, name: string): void {
|
||||||
|
if (type == 'all') {
|
||||||
|
cross.killAll();
|
||||||
|
} else {
|
||||||
|
cross.killByName(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create go service
|
||||||
|
* In the default configuration, services can be started with applications.
|
||||||
|
* Developers can turn off the configuration and create it manually.
|
||||||
|
*/
|
||||||
|
async createGoServer(): Promise<void> {
|
||||||
|
// method 1: Use the default Settings
|
||||||
|
//const entity = await cross.run(serviceName);
|
||||||
|
|
||||||
|
// method 2: Use custom configuration
|
||||||
|
const serviceName = "go";
|
||||||
|
const opt = {
|
||||||
|
name: 'goapp',
|
||||||
|
cmd: path.join(getExtraResourcesDir(), 'goapp'),
|
||||||
|
directory: getExtraResourcesDir(),
|
||||||
|
args: ['--port=7073'],
|
||||||
|
appExit: true,
|
||||||
|
}
|
||||||
|
const entity = await cross.run(serviceName, opt);
|
||||||
|
logger.info('server name:', entity.name);
|
||||||
|
logger.info('server config:', entity.config);
|
||||||
|
logger.info('server url:', entity.getUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create java server
|
||||||
|
*/
|
||||||
|
async createJavaServer(): Promise<void> {
|
||||||
|
const serviceName = "java";
|
||||||
|
const jarPath = path.join(getExtraResourcesDir(), 'java-app.jar');
|
||||||
|
const opt = {
|
||||||
|
name: 'javaapp',
|
||||||
|
cmd: path.join(getExtraResourcesDir(), 'jre1.8.0_201/bin/javaw.exe'),
|
||||||
|
directory: getExtraResourcesDir(),
|
||||||
|
args: ['-jar', '-server', '-Xms512M', '-Xmx512M', '-Xss512k', '-Dspring.profiles.active=prod', `-Dserver.port=18080`, `-Dlogging.file.path=${getLogDir()}`, `${jarPath}`],
|
||||||
|
appExit: false,
|
||||||
|
}
|
||||||
|
if (is.macOS()) {
|
||||||
|
// Setup Java program
|
||||||
|
opt.cmd = path.join(getExtraResourcesDir(), 'jre1.8.0_201.jre/Contents/Home/bin/java');
|
||||||
|
}
|
||||||
|
if (is.linux()) {
|
||||||
|
// Setup Java program
|
||||||
|
}
|
||||||
|
|
||||||
|
const entity = await cross.run(serviceName, opt);
|
||||||
|
logger.info('server name:', entity.name);
|
||||||
|
logger.info('server config:', entity.config);
|
||||||
|
logger.info('server url:', cross.getUrl(entity.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create python service
|
||||||
|
* In the default configuration, services can be started with applications.
|
||||||
|
* Developers can turn off the configuration and create it manually.
|
||||||
|
*/
|
||||||
|
async createPythonServer(): Promise<void> {
|
||||||
|
// method 1: Use the default Settings
|
||||||
|
//const entity = await cross.run(serviceName);
|
||||||
|
|
||||||
|
// method 2: Use custom configuration
|
||||||
|
const serviceName = "python";
|
||||||
|
const opt = {
|
||||||
|
name: 'pyapp',
|
||||||
|
cmd: path.join(getExtraResourcesDir(), 'py', 'pyapp'),
|
||||||
|
directory: path.join(getExtraResourcesDir(), 'py'),
|
||||||
|
args: ['--port=7074'],
|
||||||
|
windowsExtname: true,
|
||||||
|
appExit: true,
|
||||||
|
}
|
||||||
|
const entity = await cross.run(serviceName, opt);
|
||||||
|
logger.info('server name:', entity.name);
|
||||||
|
logger.info('server config:', entity.config);
|
||||||
|
logger.info('server url:', entity.getUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
async requestApi(name: string, urlPath: string, params: any): Promise<any> {
|
||||||
|
const serverUrl = cross.getUrl(name);
|
||||||
|
const apiHello = serverUrl + urlPath;
|
||||||
|
console.log('Server Url:', serverUrl);
|
||||||
|
|
||||||
|
const response = await axios({
|
||||||
|
method: 'get',
|
||||||
|
url: apiHello,
|
||||||
|
timeout: 1000,
|
||||||
|
params,
|
||||||
|
proxy: false,
|
||||||
|
});
|
||||||
|
if (response.status == 200) {
|
||||||
|
const { data } = response;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CrossService.toString = () => '[class CrossService]';
|
||||||
|
const crossService = new CrossService();
|
||||||
|
|
||||||
|
export {
|
||||||
|
CrossService,
|
||||||
|
crossService
|
||||||
|
};
|
||||||
23
electron/service/effect.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { logger } from 'ee-core/log';
|
||||||
|
|
||||||
|
// effect service
|
||||||
|
class EffectService {
|
||||||
|
|
||||||
|
// hello
|
||||||
|
async hello(args: any): Promise<{ status: string; params: any }> {
|
||||||
|
let obj = {
|
||||||
|
status:'ok',
|
||||||
|
params: args
|
||||||
|
}
|
||||||
|
logger.info('EffectService obj:', obj);
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EffectService.toString = () => '[class EffectService]';
|
||||||
|
const effectService = new EffectService();
|
||||||
|
|
||||||
|
export {
|
||||||
|
EffectService,
|
||||||
|
effectService
|
||||||
|
}
|
||||||
21
electron/service/example.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { logger } from 'ee-core/log';
|
||||||
|
|
||||||
|
// example service
|
||||||
|
class ExampleService {
|
||||||
|
|
||||||
|
async test(args: any): Promise<{ status: string; params: any }> {
|
||||||
|
let obj = {
|
||||||
|
status:'ok',
|
||||||
|
params: args
|
||||||
|
}
|
||||||
|
logger.info('ExampleService obj:', obj);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExampleService.toString = () => '[class ExampleService]';
|
||||||
|
const exampleService = new ExampleService();
|
||||||
|
|
||||||
|
export {
|
||||||
|
ExampleService,
|
||||||
|
exampleService
|
||||||
|
};
|
||||||
19
electron/service/job/user.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { logger } from 'ee-core/log';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserService class
|
||||||
|
*/
|
||||||
|
class UserService {
|
||||||
|
|
||||||
|
async hello(args: any): Promise<{ status: string; params: any }> {
|
||||||
|
const obj = {
|
||||||
|
status: 'ok',
|
||||||
|
params: args,
|
||||||
|
};
|
||||||
|
logger.info('UserService obj:', obj);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UserService.toString = () => '[class UserService]';
|
||||||
|
|
||||||
|
export { UserService };
|
||||||
177
electron/service/os/auto_updater.ts
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
import { app as electronApp } from 'electron';
|
||||||
|
import { autoUpdater } from 'electron-updater';
|
||||||
|
import { is } from 'ee-core/utils';
|
||||||
|
import { logger } from 'ee-core/log';
|
||||||
|
import { getMainWindow, setCloseAndQuit } from 'ee-core/electron';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AutoUpdaterService class for automatic updates
|
||||||
|
*/
|
||||||
|
class AutoUpdaterService {
|
||||||
|
private config: {
|
||||||
|
windows: boolean;
|
||||||
|
macOS: boolean;
|
||||||
|
linux: boolean;
|
||||||
|
options: any;
|
||||||
|
};
|
||||||
|
constructor() {
|
||||||
|
this.config = {
|
||||||
|
windows: false,
|
||||||
|
macOS: false,
|
||||||
|
linux: false,
|
||||||
|
options: {
|
||||||
|
provider: 'generic',
|
||||||
|
url: 'http://kodo.qiniu.com/'
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and configure the auto updater
|
||||||
|
*/
|
||||||
|
create(): void {
|
||||||
|
logger.info('[autoUpdater] load');
|
||||||
|
const cfg = this.config;
|
||||||
|
if ((is.windows() && cfg.windows) ||
|
||||||
|
(is.macOS() && cfg.macOS) ||
|
||||||
|
(is.linux() && cfg.linux)) {
|
||||||
|
// continue
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const status = {
|
||||||
|
error: -1,
|
||||||
|
available: 1,
|
||||||
|
noAvailable: 2,
|
||||||
|
downloading: 3,
|
||||||
|
downloaded: 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
const version = electronApp.getVersion();
|
||||||
|
logger.info('[autoUpdater] current version: ', version);
|
||||||
|
|
||||||
|
// Set the download server address
|
||||||
|
let server = cfg.options.url;
|
||||||
|
const lastChar = server.substring(server.length - 1);
|
||||||
|
server = lastChar === '/' ? server : server + "/";
|
||||||
|
cfg.options.url = server;
|
||||||
|
|
||||||
|
try {
|
||||||
|
autoUpdater.setFeedURL(cfg.options);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('[autoUpdater] setFeedURL error : ', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
autoUpdater.on('checking-for-update', () => {
|
||||||
|
// sendStatusToWindow('正在检查更新...');
|
||||||
|
});
|
||||||
|
autoUpdater.on('update-available', () => {
|
||||||
|
const data = {
|
||||||
|
status: status.available,
|
||||||
|
desc: '有可用更新',
|
||||||
|
};
|
||||||
|
this.sendStatusToWindow(data);
|
||||||
|
});
|
||||||
|
autoUpdater.on('update-not-available', () => {
|
||||||
|
const data = {
|
||||||
|
status: status.noAvailable,
|
||||||
|
desc: '没有可用更新',
|
||||||
|
};
|
||||||
|
this.sendStatusToWindow(data);
|
||||||
|
});
|
||||||
|
autoUpdater.on('error', (err) => {
|
||||||
|
const data = {
|
||||||
|
status: status.error,
|
||||||
|
desc: err,
|
||||||
|
};
|
||||||
|
this.sendStatusToWindow(data);
|
||||||
|
});
|
||||||
|
autoUpdater.on('download-progress', (progressObj) => {
|
||||||
|
const percentNumber = progressObj.percent;
|
||||||
|
const totalSize = this.bytesChange(progressObj.total);
|
||||||
|
const transferredSize = this.bytesChange(progressObj.transferred);
|
||||||
|
let text = '已下载 ' + percentNumber + '%';
|
||||||
|
text = text + ' (' + transferredSize + "/" + totalSize + ')';
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
status: status.downloading,
|
||||||
|
desc: text,
|
||||||
|
percentNumber,
|
||||||
|
totalSize,
|
||||||
|
transferredSize,
|
||||||
|
};
|
||||||
|
logger.info('[addon:autoUpdater] progress: ', text);
|
||||||
|
this.sendStatusToWindow(data);
|
||||||
|
});
|
||||||
|
autoUpdater.on('update-downloaded', () => {
|
||||||
|
const data = {
|
||||||
|
status: status.downloaded,
|
||||||
|
desc: '下载完成',
|
||||||
|
};
|
||||||
|
this.sendStatusToWindow(data);
|
||||||
|
|
||||||
|
// Allow the window to close
|
||||||
|
setCloseAndQuit(true);
|
||||||
|
|
||||||
|
// Install updates and exit the application
|
||||||
|
autoUpdater.quitAndInstall();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for updates
|
||||||
|
*/
|
||||||
|
checkUpdate(): void {
|
||||||
|
autoUpdater.checkForUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download updates
|
||||||
|
*/
|
||||||
|
download(): void {
|
||||||
|
autoUpdater.downloadUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send status to the frontend
|
||||||
|
*/
|
||||||
|
sendStatusToWindow(content: any = {}): void {
|
||||||
|
const textJson = JSON.stringify(content);
|
||||||
|
const channel = 'custom/app/updater';
|
||||||
|
const win = getMainWindow();
|
||||||
|
win.webContents.send(channel, textJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert bytes to a more readable format
|
||||||
|
*/
|
||||||
|
bytesChange(limit: number): string {
|
||||||
|
let size = "";
|
||||||
|
if (limit < 0.1 * 1024) {
|
||||||
|
size = limit.toFixed(2) + "B";
|
||||||
|
} else if (limit < 0.1 * 1024 * 1024) {
|
||||||
|
size = (limit / 1024).toFixed(2) + "KB";
|
||||||
|
} else if (limit < 0.1 * 1024 * 1024 * 1024) {
|
||||||
|
size = (limit / (1024 * 1024)).toFixed(2) + "MB";
|
||||||
|
} else {
|
||||||
|
size = (limit / (1024 * 1024 * 1024)).toFixed(2) + "GB";
|
||||||
|
}
|
||||||
|
|
||||||
|
let sizeStr = size + "";
|
||||||
|
let index = sizeStr.indexOf(".");
|
||||||
|
let dou = sizeStr.substring(index + 1, index + 3);
|
||||||
|
if (dou === "00") {
|
||||||
|
return sizeStr.substring(0, index) + sizeStr.substring(index + 3, index + 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AutoUpdaterService.toString = () => '[class AutoUpdaterService]';
|
||||||
|
const autoUpdaterService = new AutoUpdaterService();
|
||||||
|
|
||||||
|
export {
|
||||||
|
AutoUpdaterService,
|
||||||
|
autoUpdaterService
|
||||||
|
};
|
||||||
15
electron/service/os/icon.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
const {getMainWindow} = require("ee-core/electron");
|
||||||
|
|
||||||
|
|
||||||
|
class IconService {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
update(iconPath) {
|
||||||
|
const win = getMainWindow();
|
||||||
|
win.setIcon(iconPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = {
|
||||||
|
iconService: new IconService()
|
||||||
|
};
|
||||||
31
electron/service/os/security.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { logger } from 'ee-core/log';
|
||||||
|
import { app as electronApp } from 'electron';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SecurityService class for handling security-related operations
|
||||||
|
*/
|
||||||
|
class SecurityService {
|
||||||
|
/**
|
||||||
|
* Create and configure the security service
|
||||||
|
*/
|
||||||
|
create(): void {
|
||||||
|
logger.info('[security] load');
|
||||||
|
const runWithDebug = process.argv.find((e) => {
|
||||||
|
const isHasDebug = e.includes('--inspect') || e.includes('--inspect-brk') || e.includes('--remote-debugging-port');
|
||||||
|
return isHasDebug;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Do not allow remote debugging
|
||||||
|
if (runWithDebug) {
|
||||||
|
logger.error('[error] Remote debugging is not allowed, runWithDebug:', runWithDebug);
|
||||||
|
electronApp.quit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SecurityService.toString = () => '[class SecurityService]';
|
||||||
|
const securityService = new SecurityService();
|
||||||
|
|
||||||
|
export {
|
||||||
|
SecurityService,
|
||||||
|
securityService
|
||||||
|
};
|
||||||
81
electron/service/os/tray.ts
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import { Tray, Menu } from 'electron';
|
||||||
|
import path from 'path';
|
||||||
|
import { isDev, getBaseDir } from 'ee-core/ps';
|
||||||
|
import { logger } from 'ee-core/log';
|
||||||
|
import { app as electronApp } from 'electron';
|
||||||
|
import { getMainWindow, getCloseAndQuit, setCloseAndQuit } from 'ee-core/electron';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 托盘
|
||||||
|
* @class
|
||||||
|
*/
|
||||||
|
class TrayService {
|
||||||
|
tray: Tray | null;
|
||||||
|
config: {
|
||||||
|
title: string;
|
||||||
|
icon: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.tray = null;
|
||||||
|
this.config = {
|
||||||
|
title: 'electron-egg',
|
||||||
|
icon: '/public/images/tray.png',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the tray icon
|
||||||
|
*/
|
||||||
|
create () {
|
||||||
|
logger.info('[tray] load');
|
||||||
|
|
||||||
|
const cfg = this.config;
|
||||||
|
const mainWindow = getMainWindow();
|
||||||
|
|
||||||
|
// tray icon
|
||||||
|
const iconPath = path.join(getBaseDir(), cfg.icon);
|
||||||
|
|
||||||
|
// Tray menu items
|
||||||
|
const trayMenuTemplate = [
|
||||||
|
{
|
||||||
|
label: '显示',
|
||||||
|
click: function () {
|
||||||
|
mainWindow.show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '退出',
|
||||||
|
click: function () {
|
||||||
|
electronApp.quit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// Set a flag to minimize to tray instead of closing
|
||||||
|
setCloseAndQuit(false);
|
||||||
|
mainWindow.on('close', (event: any) => {
|
||||||
|
if (getCloseAndQuit()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mainWindow.hide();
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize the tray
|
||||||
|
this.tray = new Tray(iconPath);
|
||||||
|
this.tray.setToolTip(cfg.title);
|
||||||
|
const contextMenu = Menu.buildFromTemplate(trayMenuTemplate);
|
||||||
|
this.tray.setContextMenu(contextMenu);
|
||||||
|
// Show the main window when the tray icon is clicked
|
||||||
|
this.tray.on('click', () => {
|
||||||
|
mainWindow.show()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TrayService.toString = () => '[class TrayService]';
|
||||||
|
const trayService = new TrayService();
|
||||||
|
|
||||||
|
export {
|
||||||
|
trayService
|
||||||
|
}
|
||||||
131
electron/service/os/window.ts
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
import path from 'path';
|
||||||
|
import { BrowserWindow, Notification } from 'electron';
|
||||||
|
import { getMainWindow } from 'ee-core/electron';
|
||||||
|
import { isProd, getBaseDir } from 'ee-core/ps';
|
||||||
|
import { getConfig } from 'ee-core/config';
|
||||||
|
import { isFileProtocol } from 'ee-core/utils';
|
||||||
|
import { logger } from 'ee-core/log';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Window
|
||||||
|
* @class
|
||||||
|
*/
|
||||||
|
class WindowService {
|
||||||
|
myNotification: Notification | null;
|
||||||
|
windows: { [key: string]: BrowserWindow };
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.myNotification = null;
|
||||||
|
this.windows = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new window
|
||||||
|
*/
|
||||||
|
createWindow(args: { type: string; content: string; windowName: string; windowTitle: string }): number {
|
||||||
|
const { type, content, windowName, windowTitle } = args;
|
||||||
|
let contentUrl: string = '';
|
||||||
|
if (type == 'html') {
|
||||||
|
contentUrl = path.join('file://', getBaseDir(), content)
|
||||||
|
} else if (type == 'web') {
|
||||||
|
contentUrl = content;
|
||||||
|
} else if (type == 'vue') {
|
||||||
|
let addr = 'http://localhost:8080'
|
||||||
|
if (isProd()) {
|
||||||
|
const { mainServer } = getConfig();
|
||||||
|
if (mainServer && mainServer.protocol && isFileProtocol(mainServer.protocol)) {
|
||||||
|
addr = mainServer.protocol + path.join(getBaseDir(), mainServer.indexPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contentUrl = addr + content;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info('[createWindow] url: ', contentUrl);
|
||||||
|
const opt = {
|
||||||
|
title: windowTitle,
|
||||||
|
x: 10,
|
||||||
|
y: 10,
|
||||||
|
width: 980,
|
||||||
|
height: 650,
|
||||||
|
webPreferences: {
|
||||||
|
contextIsolation: false,
|
||||||
|
nodeIntegration: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const win = new BrowserWindow(opt);
|
||||||
|
const winContentsId = win.webContents.id;
|
||||||
|
win.loadURL(contentUrl);
|
||||||
|
win.webContents.openDevTools();
|
||||||
|
this.windows[windowName] = win;
|
||||||
|
|
||||||
|
return winContentsId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get window contents id
|
||||||
|
*/
|
||||||
|
getWCid(args: { windowName: string }): number {
|
||||||
|
const { windowName } = args;
|
||||||
|
let win: BrowserWindow;
|
||||||
|
if (windowName == 'main') {
|
||||||
|
win = getMainWindow();
|
||||||
|
} else {
|
||||||
|
win = this.windows[windowName];
|
||||||
|
}
|
||||||
|
|
||||||
|
return win.webContents.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Realize communication between two windows through the transfer of the main process
|
||||||
|
*/
|
||||||
|
communicate(args: { receiver: string; content: any }): void {
|
||||||
|
const { receiver, content } = args;
|
||||||
|
if (receiver == 'main') {
|
||||||
|
const win = getMainWindow();
|
||||||
|
win.webContents.send('controller/os/window2ToWindow1', content);
|
||||||
|
} else if (receiver == 'window2') {
|
||||||
|
const win = this.windows[receiver];
|
||||||
|
win.webContents.send('controller/os/window1ToWindow2', content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* createNotification
|
||||||
|
*/
|
||||||
|
createNotification(options: any, event: any): void {
|
||||||
|
const channel = 'controller/os/sendNotification';
|
||||||
|
this.myNotification = new Notification(options);
|
||||||
|
|
||||||
|
if (options.clickEvent) {
|
||||||
|
this.myNotification.on('click', () => {
|
||||||
|
let data = {
|
||||||
|
type: 'click',
|
||||||
|
msg: '您点击了通知消息'
|
||||||
|
}
|
||||||
|
event.reply(`${channel}`, data)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.closeEvent) {
|
||||||
|
this.myNotification.on('close', () => {
|
||||||
|
let data = {
|
||||||
|
type: 'close',
|
||||||
|
msg: '您关闭了通知消息'
|
||||||
|
}
|
||||||
|
event.reply(`${channel}`, data)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.myNotification.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
WindowService.toString = () => '[class WindowService]';
|
||||||
|
const windowService = new WindowService();
|
||||||
|
|
||||||
|
export {
|
||||||
|
WindowService,
|
||||||
|
windowService
|
||||||
|
}
|
||||||
14
frontend/.editorconfig
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# https://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
insert_final_newline = false
|
||||||
|
trim_trailing_whitespace = false
|
||||||
4
frontend/.env.development
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
VITE_TITLE="NPQS9100-自动检测平台工具箱"
|
||||||
|
|
||||||
|
VITE_RSA_PUBLIC_KEY="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnFMmIVanMxsW5S/qP8Wcxf/J3/i4631BP3UtWkRzO7jAw9HIAgK4Y7X53hXj6zMbfme1vMjQc0mq7m/KrH4WlTYpFexLO6Gnk8oH40F04tp+ABZIq93zNOydPEaVoZeTPH/LlkwrrxVGAMNNIKuebcqapp25JiWtlSFMv4kH/nDAj+2m8+P4zYVM1Ed6gO01eKDEYE3SBA1Ket2BfHTgviR/F8WKwlXh11enywsJnrHTM5dJQdlUxCjHy214TpheYOz/cv9elQnDfFAbmZW8mH5/hgMSTkm3h4uR7ITin6Erg+yc/t1kGaTWrzloyBRMSiFN/Pwr5yQjj+1wQqqUkwIDAQAB"
|
||||||
|
VITE_RSA_PRIVATE_KEY="MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCcUyYhVqczGxblL+o/xZzF/8nf+LjrfUE/dS1aRHM7uMDD0cgCArhjtfneFePrMxt+Z7W8yNBzSarub8qsfhaVNikV7Es7oaeTygfjQXTi2n4AFkir3fM07J08RpWhl5M8f8uWTCuvFUYAw00gq55typqmnbkmJa2VIUy/iQf+cMCP7abz4/jNhUzUR3qA7TV4oMRgTdIEDUp63YF8dOC+JH8XxYrCVeHXV6fLCwmesdMzl0lB2VTEKMfLbXhOmF5g7P9y/16VCcN8UBuZlbyYfn+GAxJOSbeHi5HshOKfoSuD7Jz+3WQZpNavOWjIFExKIU38/CvnJCOP7XBCqpSTAgMBAAECggEAYeWokWRE3TpvwiOZnUpR/aVMdVi75a3ROL5XIpqPV61B+t/bU3cEpl0GF9C5pUeiRi0IoStZb3mI9D1KPW/REKyUWkhabQO1gFYbTnRlkNOn6MILzKX4cwJjDaZeeo4EBPU7N+qHyOOXrU6hdH5FfxhMdV983ajm5eeuupxER1C2kAcIklTeVpTX6EKOgZb5LBp5ssOVm2P42pOauvcRozRcvZmqnErXmukv0H4l3EVNt4rHpTn9riHUC63e8JfiYzVaF6zuNUxv6nHEft0/SRMw11XSTnNfDzcKqgjz6ksFBS/6eQQYKESk+ONC53HUuYHFAknkwsPupDCT2W8FIQKBgQDLHT/xCU3nxGr4vFKBDNaO2D5oK20ECbBO4oDvLWWmQG7f+6TsMy8PgVdMnoL4RfqGlwFAKEpS6KVFHnBVqnNEhcdy9uCI7x7Xx8UnyUtxj1EDTm76uta9Ki9OrlqB6tImDM9+Ya3vGktW37ht4WOx2OsJRhG1dbf6RLwFlH7DWwKBgQDFBxvi5I1BR6hg6Tj7xd2SqOT2Y+BED3xuSYENhWbmMhLJDResaB7mjztbxlYaY2mOE0holWm2uDmVFFhMh4jYXik4hYH8nmDzq9mDpZCZ9pyjYqnAP8THoAa8EbgrUWB8A6BPH4iL3KbMnBfBKY0pIr2xrvnjQjNBAgta7KDRKQKBgCe6oe4wxrdF2TKsC2tIqpMoQxS3Icy/ZGgZr+SYuaBKTCWtoDW/UT40K3JGMxIDBhzbXphBCUCsVt9tM8Xd4EwP6tJW7dZ7B0pnve2pVwNwaAVAiz6p2yUHIle+jN+Koe5lZRSwYIg7WW81tWpwwsJfzqFyvjYDP6hJV4mz4ROvAoGAaRcdnKvjXApomShMqJ4lTPChD3q+SA8qg3jZSOj6tZXHx00gb2kp8jg7pPvpOTIFPy6x1Ha9aCRjMk0ju84fA6lVuzwa1S907wOehUVuF3Eeo1cgy9Y3k3KbpPyeixxgpkUY4JslLdSHc2NemD0dee951qhJyRmqVOZOQDUuoeECgYEAqBw2cAFk3vM97WY06TSldGA8ajVHx3BYRjj+zl62NTQthy8fw3tqxb3c5e8toOmZWKjZvDhg2TRLhsDDQWEYg3LZG87REqVIjgEPcpjNLidjygGX8n3JF2o0O5I/EMvl0s/+LVQONfduOBvhwDqr8QNisbLsyneiAq7umewMolo="
|
||||||
3
frontend/.env.production
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
VITE_TITLE="NPQS9100-自动检测平台工具箱"
|
||||||
|
VITE_RSA_PUBLIC_KEY="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnFMmIVanMxsW5S/qP8Wcxf/J3/i4631BP3UtWkRzO7jAw9HIAgK4Y7X53hXj6zMbfme1vMjQc0mq7m/KrH4WlTYpFexLO6Gnk8oH40F04tp+ABZIq93zNOydPEaVoZeTPH/LlkwrrxVGAMNNIKuebcqapp25JiWtlSFMv4kH/nDAj+2m8+P4zYVM1Ed6gO01eKDEYE3SBA1Ket2BfHTgviR/F8WKwlXh11enywsJnrHTM5dJQdlUxCjHy214TpheYOz/cv9elQnDfFAbmZW8mH5/hgMSTkm3h4uR7ITin6Erg+yc/t1kGaTWrzloyBRMSiFN/Pwr5yQjj+1wQqqUkwIDAQAB"
|
||||||
|
VITE_RSA_PRIVATE_KEY="MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCcUyYhVqczGxblL+o/xZzF/8nf+LjrfUE/dS1aRHM7uMDD0cgCArhjtfneFePrMxt+Z7W8yNBzSarub8qsfhaVNikV7Es7oaeTygfjQXTi2n4AFkir3fM07J08RpWhl5M8f8uWTCuvFUYAw00gq55typqmnbkmJa2VIUy/iQf+cMCP7abz4/jNhUzUR3qA7TV4oMRgTdIEDUp63YF8dOC+JH8XxYrCVeHXV6fLCwmesdMzl0lB2VTEKMfLbXhOmF5g7P9y/16VCcN8UBuZlbyYfn+GAxJOSbeHi5HshOKfoSuD7Jz+3WQZpNavOWjIFExKIU38/CvnJCOP7XBCqpSTAgMBAAECggEAYeWokWRE3TpvwiOZnUpR/aVMdVi75a3ROL5XIpqPV61B+t/bU3cEpl0GF9C5pUeiRi0IoStZb3mI9D1KPW/REKyUWkhabQO1gFYbTnRlkNOn6MILzKX4cwJjDaZeeo4EBPU7N+qHyOOXrU6hdH5FfxhMdV983ajm5eeuupxER1C2kAcIklTeVpTX6EKOgZb5LBp5ssOVm2P42pOauvcRozRcvZmqnErXmukv0H4l3EVNt4rHpTn9riHUC63e8JfiYzVaF6zuNUxv6nHEft0/SRMw11XSTnNfDzcKqgjz6ksFBS/6eQQYKESk+ONC53HUuYHFAknkwsPupDCT2W8FIQKBgQDLHT/xCU3nxGr4vFKBDNaO2D5oK20ECbBO4oDvLWWmQG7f+6TsMy8PgVdMnoL4RfqGlwFAKEpS6KVFHnBVqnNEhcdy9uCI7x7Xx8UnyUtxj1EDTm76uta9Ki9OrlqB6tImDM9+Ya3vGktW37ht4WOx2OsJRhG1dbf6RLwFlH7DWwKBgQDFBxvi5I1BR6hg6Tj7xd2SqOT2Y+BED3xuSYENhWbmMhLJDResaB7mjztbxlYaY2mOE0holWm2uDmVFFhMh4jYXik4hYH8nmDzq9mDpZCZ9pyjYqnAP8THoAa8EbgrUWB8A6BPH4iL3KbMnBfBKY0pIr2xrvnjQjNBAgta7KDRKQKBgCe6oe4wxrdF2TKsC2tIqpMoQxS3Icy/ZGgZr+SYuaBKTCWtoDW/UT40K3JGMxIDBhzbXphBCUCsVt9tM8Xd4EwP6tJW7dZ7B0pnve2pVwNwaAVAiz6p2yUHIle+jN+Koe5lZRSwYIg7WW81tWpwwsJfzqFyvjYDP6hJV4mz4ROvAoGAaRcdnKvjXApomShMqJ4lTPChD3q+SA8qg3jZSOj6tZXHx00gb2kp8jg7pPvpOTIFPy6x1Ha9aCRjMk0ju84fA6lVuzwa1S907wOehUVuF3Eeo1cgy9Y3k3KbpPyeixxgpkUY4JslLdSHc2NemD0dee951qhJyRmqVOZOQDUuoeECgYEAqBw2cAFk3vM97WY06TSldGA8ajVHx3BYRjj+zl62NTQthy8fw3tqxb3c5e8toOmZWKjZvDhg2TRLhsDDQWEYg3LZG87REqVIjgEPcpjNLidjygGX8n3JF2o0O5I/EMvl0s/+LVQONfduOBvhwDqr8QNisbLsyneiAq7umewMolo="
|
||||||
6
frontend/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
node_modules
|
||||||
|
.DS_Store
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
package-lock.json
|
||||||
105
frontend/index.html
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1.0, minimum-scale=1.0" />
|
||||||
|
<title></title>
|
||||||
|
<!-- 优化:vue渲染未完成之前,先加一个css动画 -->
|
||||||
|
<style>
|
||||||
|
#loadingPage {
|
||||||
|
background-color: #dedede;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.base {
|
||||||
|
height: 9em;
|
||||||
|
left: 50%;
|
||||||
|
margin: -7.5em;
|
||||||
|
padding: 3em;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
width: 9em;
|
||||||
|
transform: rotateX(45deg) rotateZ(45deg);
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
}
|
||||||
|
.cube,
|
||||||
|
.cube:after,
|
||||||
|
.cube:before {
|
||||||
|
content: '';
|
||||||
|
float: left;
|
||||||
|
height: 3em;
|
||||||
|
position: absolute;
|
||||||
|
width: 3em;
|
||||||
|
}
|
||||||
|
/* Top */
|
||||||
|
.cube {
|
||||||
|
background-color: #06cf68;
|
||||||
|
position: relative;
|
||||||
|
transform: translateZ(3em);
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
transition: .25s;
|
||||||
|
box-shadow: 13em 13em 1.5em rgba(0, 0, 0, 0.1);
|
||||||
|
animation: anim 1s infinite;
|
||||||
|
}
|
||||||
|
.cube:after {
|
||||||
|
background-color: #05a151;
|
||||||
|
transform: rotateX(-90deg) translateY(3em);
|
||||||
|
transform-origin: 100% 100%;
|
||||||
|
}
|
||||||
|
.cube:before {
|
||||||
|
background-color: #026934;
|
||||||
|
transform: rotateY(90deg) translateX(3em);
|
||||||
|
transform-origin: 100% 0;
|
||||||
|
}
|
||||||
|
.cube:nth-child(1) {
|
||||||
|
animation-delay: 0.05s;
|
||||||
|
}
|
||||||
|
.cube:nth-child(2) {
|
||||||
|
animation-delay: 0.1s;
|
||||||
|
}
|
||||||
|
.cube:nth-child(3) {
|
||||||
|
animation-delay: 0.15s;
|
||||||
|
}
|
||||||
|
.cube:nth-child(4) {
|
||||||
|
animation-delay: 0.2s;
|
||||||
|
}
|
||||||
|
.cube:nth-child(5) {
|
||||||
|
animation-delay: 0.25s;
|
||||||
|
}
|
||||||
|
.cube:nth-child(6) {
|
||||||
|
animation-delay: 0.3s;
|
||||||
|
}
|
||||||
|
.cube:nth-child(7) {
|
||||||
|
animation-delay: 0.35s;
|
||||||
|
}
|
||||||
|
.cube:nth-child(8) {
|
||||||
|
animation-delay: 0.4s;
|
||||||
|
}
|
||||||
|
.cube:nth-child(9) {
|
||||||
|
animation-delay: 0.45s;
|
||||||
|
}
|
||||||
|
@keyframes anim {
|
||||||
|
50% {
|
||||||
|
transform: translateZ(0.5em);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="loadingPage">
|
||||||
|
<div class='base'>
|
||||||
|
<div class='cube'></div>
|
||||||
|
<div class='cube'></div>
|
||||||
|
<div class='cube'></div>
|
||||||
|
<div class='cube'></div>
|
||||||
|
<div class='cube'></div>
|
||||||
|
<div class='cube'></div>
|
||||||
|
<div class='cube'></div>
|
||||||
|
<div class='cube'></div>
|
||||||
|
<div class='cube'></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
38
frontend/package.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"name": "ee",
|
||||||
|
"version": "4.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite --host --port 8080",
|
||||||
|
"serve": "vite --host --port 8080",
|
||||||
|
"build-staging": "vite build --mode staging",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ant-design/icons-vue": "^6.1.0",
|
||||||
|
"ant-design-vue": "^3.2.20",
|
||||||
|
"axios": "^1.12.2",
|
||||||
|
"jsencrypt": "^3.5.4",
|
||||||
|
"node-forge": "^1.3.1",
|
||||||
|
"pinia": "^3.0.3",
|
||||||
|
"socket.io-client": "^4.8.1",
|
||||||
|
"store2": "^2.14.4",
|
||||||
|
"vue": "^3.5.22",
|
||||||
|
"vue-router": "^4.6.2",
|
||||||
|
"vuex": "^4.1.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^20.16.0",
|
||||||
|
"@types/node-forge": "^1.3.14",
|
||||||
|
"@vitejs/plugin-vue": "^6.0.1",
|
||||||
|
"@vue/compiler-sfc": "^3.5.22",
|
||||||
|
"less": "^4.4.2",
|
||||||
|
"less-loader": "^12.3.0",
|
||||||
|
"postcss": "^8.5.6",
|
||||||
|
"postcss-pxtorem": "^6.1.0",
|
||||||
|
"terser": "^5.44.0",
|
||||||
|
"typescript": "^5.9.3",
|
||||||
|
"vite": "^6.4.0",
|
||||||
|
"vite-plugin-compression": "^0.5.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
15
frontend/src/App.vue
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<template>
|
||||||
|
<router-view/>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {onMounted} from 'vue';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const loadingElement = document.getElementById('loadingPage');
|
||||||
|
if (loadingElement) {
|
||||||
|
(loadingElement as HTMLElement).remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="less"></style>
|
||||||
84
frontend/src/api/index.ts
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* Definition of communication channel between main process and rendering process
|
||||||
|
* format:controller/filename/method
|
||||||
|
* Definition of communication channels between main process and rendering process
|
||||||
|
*/
|
||||||
|
const ipcApiRoute = {
|
||||||
|
example: {
|
||||||
|
test: 'controller/example/test',
|
||||||
|
},
|
||||||
|
framework: {
|
||||||
|
checkForUpdater: 'controller/framework/checkForUpdater',
|
||||||
|
downloadApp: 'controller/framework/downloadApp',
|
||||||
|
jsondbOperation: 'controller/framework/jsondbOperation',
|
||||||
|
sqlitedbOperation: 'controller/framework/sqlitedbOperation',
|
||||||
|
uploadFile: 'controller/framework/uploadFile',
|
||||||
|
checkHttpServer: 'controller/framework/checkHttpServer',
|
||||||
|
doHttpRequest: 'controller/framework/doHttpRequest',
|
||||||
|
doSocketRequest: 'controller/framework/doSocketRequest',
|
||||||
|
ipcInvokeMsg: 'controller/framework/ipcInvokeMsg',
|
||||||
|
ipcSendSyncMsg: 'controller/framework/ipcSendSyncMsg',
|
||||||
|
ipcSendMsg: 'controller/framework/ipcSendMsg',
|
||||||
|
startJavaServer: 'controller/framework/startJavaServer',
|
||||||
|
closeJavaServer: 'controller/framework/closeJavaServer',
|
||||||
|
someJob: 'controller/framework/someJob',
|
||||||
|
timerJobProgress: 'controller/framework/timerJobProgress',
|
||||||
|
createPool: 'controller/framework/createPool',
|
||||||
|
createPoolNotice: 'controller/framework/createPoolNotice',
|
||||||
|
someJobByPool: 'controller/framework/someJobByPool',
|
||||||
|
hello: 'controller/framework/hello',
|
||||||
|
openSoftware: 'controller/framework/openSoftware',
|
||||||
|
},
|
||||||
|
|
||||||
|
// os
|
||||||
|
os: {
|
||||||
|
messageShow: 'controller/os/messageShow',
|
||||||
|
messageShowConfirm: 'controller/os/messageShowConfirm',
|
||||||
|
selectFolder: 'controller/os/selectFolder',
|
||||||
|
selectPic: 'controller/os/selectPic',
|
||||||
|
openDirectory: 'controller/os/openDirectory',
|
||||||
|
loadViewContent: 'controller/os/loadViewContent',
|
||||||
|
removeViewContent: 'controller/os/removeViewContent',
|
||||||
|
createWindow: 'controller/os/createWindow',
|
||||||
|
getWCid: 'controller/os/getWCid',
|
||||||
|
sendNotification: 'controller/os/sendNotification',
|
||||||
|
initPowerMonitor: 'controller/os/initPowerMonitor',
|
||||||
|
getScreen: 'controller/os/getScreen',
|
||||||
|
autoLaunch: 'controller/os/autoLaunch',
|
||||||
|
setTheme: 'controller/os/setTheme',
|
||||||
|
getTheme: 'controller/os/getTheme',
|
||||||
|
window1ToWindow2: 'controller/os/window1ToWindow2',
|
||||||
|
window2ToWindow1: 'controller/os/window2ToWindow1',
|
||||||
|
},
|
||||||
|
|
||||||
|
// effect
|
||||||
|
effect: {
|
||||||
|
selectFile: 'controller/effect/selectFile',
|
||||||
|
loginWindow: 'controller/effect/loginWindow',
|
||||||
|
restoreWindow: 'controller/effect/restoreWindow',
|
||||||
|
},
|
||||||
|
|
||||||
|
// cross
|
||||||
|
cross: {
|
||||||
|
crossInfo: 'controller/cross/info',
|
||||||
|
getCrossUrl: 'controller/cross/getUrl',
|
||||||
|
killCrossServer: 'controller/cross/killServer',
|
||||||
|
createCrossServer: 'controller/cross/createServer',
|
||||||
|
requestApi: 'controller/cross/requestApi',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customize Channel
|
||||||
|
* Format: Custom (recommended to add a prefix)
|
||||||
|
*/
|
||||||
|
const specialIpcRoute = {
|
||||||
|
appUpdater: 'custom/app/updater', // updater channel
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
ipcApiRoute,
|
||||||
|
specialIpcRoute
|
||||||
|
}
|
||||||
|
|
||||||
15
frontend/src/assets/global.less
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#app {
|
||||||
|
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
text-align: center;
|
||||||
|
color: #2c3e50;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 滚动条 */
|
||||||
|
::-webkit-scrollbar{width:8px;height:4px}
|
||||||
|
::-webkit-scrollbar-button{width:10px;height:0}
|
||||||
|
::-webkit-scrollbar-track{background:0 0}
|
||||||
|
::-webkit-scrollbar-thumb{background: #ecf3fb; border-radius: 4px;-webkit-transition:.3s;transition:.3s}
|
||||||
|
::-webkit-scrollbar-thumb:hover{background-color:#1890ff}
|
||||||
|
::-webkit-scrollbar-thumb:active{background-color:#1890ff}
|
||||||
BIN
frontend/src/assets/login.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
frontend/src/assets/logo.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
17
frontend/src/assets/theme.less
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
@import 'ant-design-vue/dist/antd.less';
|
||||||
|
|
||||||
|
// 可自定义主题颜色
|
||||||
|
//@primary-color: #07C160; // 全局主色
|
||||||
|
@link-color: #1890ff; // 链接色
|
||||||
|
@success-color: #52c41a; // 成功色
|
||||||
|
@warning-color: #faad14; // 警告色
|
||||||
|
@error-color: #f5222d; // 错误色
|
||||||
|
@font-size-base: 14px; // 主字号
|
||||||
|
@heading-color: rgba(0, 0, 0, 0.85); // 标题色
|
||||||
|
@text-color: rgba(0, 0, 0, 0.65); // 主文本色
|
||||||
|
@text-color-secondary: rgba(0, 0, 0, 0.45); // 次文本色
|
||||||
|
@disabled-color: rgba(0, 0, 0, 0.25); // 失效色
|
||||||
|
@border-radius-base: 4px; // 组件/浮层圆角
|
||||||
|
@border-color-base: #dce3e8; // 边框色
|
||||||
|
@box-shadow-base: 0 2px 8px rgba(0, 0, 0, 0.15); // 浮层阴影
|
||||||
|
|
||||||
22
frontend/src/components/global/iconFont.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { createFromIconfontCN } from '@ant-design/icons-vue'
|
||||||
|
import { h, VNode } from 'vue'
|
||||||
|
|
||||||
|
const IconFont = createFromIconfontCN({
|
||||||
|
scriptUrl: 'https://at.alicdn.com/t/font_2456157_4ovzopz659q.js',
|
||||||
|
extraCommonProps: {
|
||||||
|
type: 'icon-fengche',
|
||||||
|
style: {
|
||||||
|
fontSize: '18px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
type?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DynamicIconFont = (props: Props): VNode => {
|
||||||
|
return h(IconFont, { type: props.type || 'icon-fengche' })
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DynamicIconFont
|
||||||
19
frontend/src/components/global/index.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import iconFont from './iconFont';
|
||||||
|
|
||||||
|
// Use import.meta.globEager to dynamically import all .vue files in the directory
|
||||||
|
const modules: { [key: string]: { default: any } } = import.meta.glob('./*.vue', { eager: true });
|
||||||
|
|
||||||
|
// Create a map of component names to their default exports
|
||||||
|
const map: { [key: string]: any } = {};
|
||||||
|
Object.keys(modules).forEach(file => {
|
||||||
|
const moduleName = file.replace('./', '').replace('.vue', '');
|
||||||
|
map[moduleName] = modules[file].default;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Combine the dynamically imported components with the iconFont component
|
||||||
|
const globalComponents = {
|
||||||
|
...map,
|
||||||
|
iconFont,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default globalComponents;
|
||||||
112
frontend/src/layouts/AppSider.vue
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<template>
|
||||||
|
<a-layout has-sider id="app-layout-sider">
|
||||||
|
<a-layout-sider
|
||||||
|
v-model:collapsed="collapsed" collapsible
|
||||||
|
theme="light"
|
||||||
|
class="layout-sider"
|
||||||
|
>
|
||||||
|
<div class="logo">
|
||||||
|
<img src="@/assets/logo.png" class="pic-logo" />
|
||||||
|
<h4>PQS9100工具箱</h4>
|
||||||
|
</div>
|
||||||
|
<a-menu
|
||||||
|
theme="light"
|
||||||
|
mode="inline"
|
||||||
|
:selectedKeys="[current]"
|
||||||
|
@click="menuHandle"
|
||||||
|
>
|
||||||
|
<a-menu-item v-for="(menuInfo, index) in menu" :key="index">
|
||||||
|
<component :is="menuInfo.icon"></component>
|
||||||
|
<span>{{ menuInfo.title }}</span>
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
</a-layout-sider>
|
||||||
|
<a-layout :style="{ marginLeft: '200px' }">
|
||||||
|
<a-layout-content class="layout-content">
|
||||||
|
<router-view />
|
||||||
|
</a-layout-content>
|
||||||
|
</a-layout>
|
||||||
|
</a-layout>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {onMounted, ref} from 'vue';
|
||||||
|
import {useRouter} from 'vue-router';
|
||||||
|
import {FileProtectOutlined} from "@ant-design/icons-vue"; // 定义菜单项的类型
|
||||||
|
|
||||||
|
// 定义菜单项的类型
|
||||||
|
interface MenuItem {
|
||||||
|
icon: any;
|
||||||
|
title: string;
|
||||||
|
pageName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义菜单的类型
|
||||||
|
interface Menu {
|
||||||
|
[key: string]: MenuItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const collapsed = ref<boolean>(false);
|
||||||
|
const current = ref<string>('menu_1');
|
||||||
|
const menu = ref<Menu>({
|
||||||
|
'menu_1': {
|
||||||
|
icon: FileProtectOutlined,
|
||||||
|
title: '设备激活',
|
||||||
|
pageName: 'Activate'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
menuHandle(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
const menuHandle = (e: any): void => {
|
||||||
|
console.log('sider menu e:', e);
|
||||||
|
if (e) {
|
||||||
|
current.value = e.key;
|
||||||
|
}
|
||||||
|
console.log('sider menu current:', current.value);
|
||||||
|
|
||||||
|
const linkInfo = menu.value[current.value];
|
||||||
|
console.log('[home] load linkInfo:', linkInfo);
|
||||||
|
router.push({ name: linkInfo.pageName});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
// 嵌套
|
||||||
|
#app-layout-sider {
|
||||||
|
height: 100%;
|
||||||
|
.logo {
|
||||||
|
border-bottom: 1px solid #e8e8e8;
|
||||||
|
padding:10px;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.pic-logo {
|
||||||
|
height: 32px;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
.layout-sider {
|
||||||
|
border-top: 1px solid #e8e8e8;
|
||||||
|
border-right: 1px solid #e8e8e8;
|
||||||
|
overflow: auto;
|
||||||
|
height: 100vh;
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.menu-item {
|
||||||
|
.ant-menu-item {
|
||||||
|
background-color: #fff;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.layout-content {
|
||||||
|
width: 96%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
5
frontend/src/layouts/index.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import AppSider from '@/layouts/AppSider.vue'
|
||||||
|
|
||||||
|
export {
|
||||||
|
AppSider
|
||||||
|
}
|
||||||
30
frontend/src/main.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import * as AntIcon from '@ant-design/icons-vue';
|
||||||
|
import Antd from 'ant-design-vue';
|
||||||
|
import { createApp } from 'vue';
|
||||||
|
import App from './App.vue';
|
||||||
|
import './assets/global.less';
|
||||||
|
import './assets/theme.less';
|
||||||
|
import components from './components/global';
|
||||||
|
import Router from './router/index';
|
||||||
|
|
||||||
|
const app = createApp(App)
|
||||||
|
|
||||||
|
// components
|
||||||
|
type ComponentsType = typeof components;
|
||||||
|
for (const componentName in components) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(components, componentName)) {
|
||||||
|
const component = components[componentName as keyof ComponentsType];
|
||||||
|
app.component(componentName, component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// icon
|
||||||
|
const whiteList = ['createFromIconfontCN', 'getTwoToneColor', 'setTwoToneColor', 'default']
|
||||||
|
const iconKeys = Object.keys(AntIcon) as Array<keyof typeof AntIcon>;
|
||||||
|
iconKeys.forEach(key => {
|
||||||
|
if (!whiteList.includes(key as typeof whiteList[number])) {
|
||||||
|
app.component(key.toString(), AntIcon[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(Antd).use(Router).mount('#app')
|
||||||
9
frontend/src/router/index.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
|
||||||
|
import routerMap from './routerMap'
|
||||||
|
|
||||||
|
const Router = createRouter({
|
||||||
|
history: createWebHashHistory(),
|
||||||
|
routes: routerMap as RouteRecordRaw[],
|
||||||
|
})
|
||||||
|
|
||||||
|
export default Router
|
||||||
21
frontend/src/router/routerMap.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* 基础路由
|
||||||
|
* @type { *[] }
|
||||||
|
*/
|
||||||
|
|
||||||
|
const constantRouterMap = [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
component: () => import('@/layouts/AppSider.vue'),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/activate',
|
||||||
|
name: 'Activate',
|
||||||
|
component: () => import('@/views/activate/index.vue'),
|
||||||
|
props: { id: 'activate' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export default constantRouterMap
|
||||||
12
frontend/src/types/env.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
|
declare module '*.vue' {
|
||||||
|
import type { DefineComponent } from 'vue';
|
||||||
|
const component: DefineComponent<{}, {}, any>;
|
||||||
|
export default component;
|
||||||
|
}
|
||||||
|
|
||||||
|
// declare global {
|
||||||
|
// interface Window {
|
||||||
|
// electron?: any;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
0
frontend/src/types/pinia.d.ts
vendored
Normal file
0
frontend/src/types/shim.d.ts
vendored
Normal file
7
frontend/src/types/source.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// 声明一个模块,防止引入文件时报错
|
||||||
|
declare module '*.json';
|
||||||
|
declare module '*.png';
|
||||||
|
declare module '*.jpg';
|
||||||
|
declare module '*.scss';
|
||||||
|
declare module '*.ts';
|
||||||
|
declare module '*.js';
|
||||||
27
frontend/src/utils/iconList.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
export default [
|
||||||
|
{ name: '对话框', type: 'icon-duihuakuang' },
|
||||||
|
{ name: '闹钟', type: 'icon-naozhong' },
|
||||||
|
{ name: '笑脸', type: 'icon-xiaolian' },
|
||||||
|
{ name: 'ok', type: 'icon-ok' },
|
||||||
|
{ name: '风车', type: 'icon-fengche' },
|
||||||
|
{ name: '汗颜', type: 'icon-hanyan' },
|
||||||
|
{ name: '相机', type: 'icon-xiangji' },
|
||||||
|
{ name: '礼物', type: 'icon-liwu' },
|
||||||
|
{ name: '礼花', type: 'icon-lihua' },
|
||||||
|
{ name: '扭蛋', type: 'icon-niudan' },
|
||||||
|
{ name: '流星', type: 'icon-liuxing' },
|
||||||
|
{ name: '风筝', type: 'icon-fengzheng' },
|
||||||
|
{ name: '蛋糕', type: 'icon-dangao' },
|
||||||
|
{ name: '泡泡', type: 'icon-paopao' },
|
||||||
|
{ name: '购物', type: 'icon-gouwu' },
|
||||||
|
{ name: '饮料', type: 'icon-yinliao' },
|
||||||
|
{ name: '云彩', type: 'icon-yuncai' },
|
||||||
|
{ name: '彩铅', type: 'icon-caiqian' },
|
||||||
|
{ name: '纸飞机', type: 'icon-zhifeiji' },
|
||||||
|
{ name: '点赞', type: 'icon-dianzan' },
|
||||||
|
{ name: '煎蛋', type: 'icon-jiandan' },
|
||||||
|
{ name: '小熊', type: 'icon-xiaoxiong' },
|
||||||
|
{ name: '花', type: 'icon-hua' },
|
||||||
|
{ name: '眼睛', type: 'icon-yanjing' },
|
||||||
|
]
|
||||||
|
|
||||||
39
frontend/src/utils/ipcRenderer.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
electron?: any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Renderer = (window.require && window.require('electron')) || window.electron || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ipc
|
||||||
|
* 官方api说明:https://www.electronjs.org/zh/docs/latest/api/ipc-renderer
|
||||||
|
*
|
||||||
|
* 属性/方法
|
||||||
|
* ipc.invoke(channel, param) - 发送异步消息(invoke/handle 模型)
|
||||||
|
* ipc.sendSync(channel, param) - 发送同步消息(send/on 模型)
|
||||||
|
* ipc.on(channel, listener) - 监听 channel, 当新消息到达,调用 listener
|
||||||
|
* ipc.once(channel, listener) - 添加一次性 listener 函数
|
||||||
|
* ipc.removeListener(channel, listener) - 为特定的 channel 从监听队列中删除特定的 listener 监听者
|
||||||
|
* ipc.removeAllListeners(channel) - 移除所有的监听器,当指定 channel 时只移除与其相关的所有监听器
|
||||||
|
* ipc.send(channel, ...args) - 通过channel向主进程发送异步消息
|
||||||
|
* ipc.postMessage(channel, message, [transfer]) - 发送消息到主进程
|
||||||
|
* ipc.sendTo(webContentsId, channel, ...args) - 通过 channel 发送消息到带有 webContentsId 的窗口
|
||||||
|
* ipc.sendToHost(channel, ...args) - 消息会被发送到 host 页面上的 <webview> 元素
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ipc
|
||||||
|
*/
|
||||||
|
const ipc = Renderer.ipcRenderer || undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为EE环境
|
||||||
|
*/
|
||||||
|
const isEE = ipc ? true : false;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Renderer, ipc, isEE
|
||||||
|
};
|
||||||
|
|
||||||
47
frontend/src/utils/rsa.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import JSEncrypt from 'jsencrypt'
|
||||||
|
|
||||||
|
// 获取 RSA 公钥
|
||||||
|
const publicKey = import.meta.env.VITE_RSA_PUBLIC_KEY
|
||||||
|
|
||||||
|
// 获取 RSA 私钥
|
||||||
|
const privateKey = import.meta.env.VITE_RSA_PRIVATE_KEY
|
||||||
|
|
||||||
|
// RSA加密
|
||||||
|
const encrypt = (data: string): string => {
|
||||||
|
try {
|
||||||
|
const encrypt = new JSEncrypt()
|
||||||
|
encrypt.setPublicKey(publicKey)
|
||||||
|
const encrypted = encrypt.encrypt(data)
|
||||||
|
if (encrypted) {
|
||||||
|
return encrypted
|
||||||
|
} else {
|
||||||
|
throw new Error('加密失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加密失败:', error)
|
||||||
|
throw new Error('RSA加密失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RSA解密
|
||||||
|
const decrypt = (encryptedData: string): string => {
|
||||||
|
try {
|
||||||
|
const decrypt = new JSEncrypt()
|
||||||
|
decrypt.setPrivateKey(privateKey)
|
||||||
|
const decrypted = decrypt.decrypt(encryptedData)
|
||||||
|
if (decrypted) {
|
||||||
|
return decrypted as string
|
||||||
|
} else {
|
||||||
|
throw new Error('解密失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('解密失败:', error)
|
||||||
|
throw new Error('RSA解密失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default {
|
||||||
|
encrypt,
|
||||||
|
decrypt,
|
||||||
|
publicKey,
|
||||||
|
privateKey
|
||||||
|
}
|
||||||
56
frontend/src/views/activate/index.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
export namespace Activate {
|
||||||
|
|
||||||
|
export interface ApplicationModule {
|
||||||
|
/**
|
||||||
|
* 是否申请 1是 0否
|
||||||
|
*/
|
||||||
|
apply: number;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ActivateModule extends ApplicationModule {
|
||||||
|
/**
|
||||||
|
* 是否永久 1是 0否
|
||||||
|
*/
|
||||||
|
permanently: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApplicationCodePlaintext {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模拟式模块
|
||||||
|
*/
|
||||||
|
simulate: ApplicationModule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数字式模块
|
||||||
|
*/
|
||||||
|
digital: ApplicationModule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 比对式模块
|
||||||
|
*/
|
||||||
|
contrast: ApplicationModule;
|
||||||
|
}
|
||||||
|
export interface ActivationCodePlaintext {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模拟式模块
|
||||||
|
*/
|
||||||
|
simulate: ActivateModule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数字式模块
|
||||||
|
*/
|
||||||
|
digital: ActivateModule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 比对式模块
|
||||||
|
*/
|
||||||
|
contrast: ActivateModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
205
frontend/src/views/activate/index.vue
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
<template>
|
||||||
|
<div class="activation-page">
|
||||||
|
<a-card title="RSA密钥配置" style="margin-bottom: 20px;">
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :span="24">
|
||||||
|
<a-alert
|
||||||
|
message="注意:请妥善保管私钥,不要泄露给他人"
|
||||||
|
type="warning"
|
||||||
|
show-icon
|
||||||
|
style="margin-bottom: 16px;"
|
||||||
|
/>
|
||||||
|
</a-col>
|
||||||
|
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item label="RSA公钥">
|
||||||
|
<a-textarea
|
||||||
|
v-model:value="rsaKeys.publicKey"
|
||||||
|
:rows="5"
|
||||||
|
readonly
|
||||||
|
placeholder="RSA公钥内容"
|
||||||
|
/>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
ghost
|
||||||
|
size="small"
|
||||||
|
@click="copyToClipboard(rsaKeys.publicKey)"
|
||||||
|
:disabled="!rsaKeys.publicKey"
|
||||||
|
style="margin-top: 8px;"
|
||||||
|
>
|
||||||
|
复制公钥
|
||||||
|
</a-button>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item label="RSA私钥">
|
||||||
|
<a-textarea
|
||||||
|
v-model:value="rsaKeys.privateKey"
|
||||||
|
:rows="5"
|
||||||
|
readonly
|
||||||
|
placeholder="RSA私钥内容"
|
||||||
|
/>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
ghost
|
||||||
|
size="small"
|
||||||
|
@click="copyToClipboard(rsaKeys.privateKey)"
|
||||||
|
:disabled="!rsaKeys.privateKey"
|
||||||
|
style="margin-top: 8px;"
|
||||||
|
>
|
||||||
|
复制私钥
|
||||||
|
</a-button>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-card>
|
||||||
|
|
||||||
|
<a-card title="设备激活">
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :span="24">
|
||||||
|
<a-divider orientation="left" orientation-margin="0px">设备申请码</a-divider>
|
||||||
|
<a-form-item>
|
||||||
|
<a-textarea
|
||||||
|
v-model:value="activationForm.requestCode"
|
||||||
|
:rows="3"
|
||||||
|
placeholder="请输入设备申请码"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
|
||||||
|
<a-col :span="24">
|
||||||
|
<a-divider orientation="left" orientation-margin="0px">设备申请码</a-divider>
|
||||||
|
<a-form-item>
|
||||||
|
<a-textarea
|
||||||
|
v-model:value="activationForm.activationCode"
|
||||||
|
:rows="3"
|
||||||
|
placeholder="生成的激活码将显示在这里"
|
||||||
|
readonly
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
|
||||||
|
<a-col :span="24">
|
||||||
|
<a-space>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
@click="generateActivationCode"
|
||||||
|
:loading="generating"
|
||||||
|
:disabled="!activationForm.requestCode.trim()"
|
||||||
|
>
|
||||||
|
生成激活码
|
||||||
|
</a-button>
|
||||||
|
|
||||||
|
<a-button
|
||||||
|
@click="copyToClipboard(activationForm.activationCode)"
|
||||||
|
:disabled="!activationForm.activationCode"
|
||||||
|
>
|
||||||
|
复制激活码
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {ref} from 'vue'
|
||||||
|
import {message} from 'ant-design-vue'
|
||||||
|
import rsa from '@/utils/rsa'
|
||||||
|
import {Activate} from "@/views/activate/index";
|
||||||
|
|
||||||
|
const rsaKeys = ref({
|
||||||
|
publicKey: rsa.publicKey,
|
||||||
|
privateKey: rsa.privateKey
|
||||||
|
})
|
||||||
|
|
||||||
|
const activationForm = ref({
|
||||||
|
requestCode: '',
|
||||||
|
activationCode: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const generating = ref(false)
|
||||||
|
|
||||||
|
|
||||||
|
// 生成激活码
|
||||||
|
const generateActivationCode = () => {
|
||||||
|
if (!activationForm.value.requestCode.trim()) {
|
||||||
|
message.error('请输入设备申请码')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
generating.value = true
|
||||||
|
let activationCodePlaintext
|
||||||
|
try {
|
||||||
|
const plaintext = rsa.decrypt(activationForm.value.requestCode)
|
||||||
|
activationCodePlaintext = JSON.parse(plaintext) as Activate.ActivationCodePlaintext
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
if (!activationCodePlaintext) {
|
||||||
|
generating.value = false
|
||||||
|
message.error('无效的设备申请码')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const contrast = activationCodePlaintext.contrast
|
||||||
|
const digital = activationCodePlaintext.digital
|
||||||
|
const simulate = activationCodePlaintext.simulate
|
||||||
|
if (!contrast && !digital && !simulate) {
|
||||||
|
generating.value = false
|
||||||
|
message.error('无效的设备申请码')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (contrast.apply === 1) {
|
||||||
|
activationCodePlaintext.contrast.permanently = 1
|
||||||
|
}
|
||||||
|
if (digital.apply === 1) {
|
||||||
|
activationCodePlaintext.digital.permanently = 1
|
||||||
|
}
|
||||||
|
if (simulate.apply === 1) {
|
||||||
|
activationCodePlaintext.simulate.permanently = 1
|
||||||
|
}
|
||||||
|
const data = JSON.stringify(activationCodePlaintext)
|
||||||
|
try {
|
||||||
|
setTimeout(() => {
|
||||||
|
activationForm.value.activationCode = rsa.encrypt(data)
|
||||||
|
generating.value = false
|
||||||
|
}, 1000)
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
generating.value = false
|
||||||
|
message.error('生成激活码失败')
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复制到剪贴板
|
||||||
|
const copyToClipboard = (text: string) => {
|
||||||
|
if (!text) {
|
||||||
|
message.warning('没有内容可复制')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
navigator.clipboard.writeText(text).then(() => {
|
||||||
|
message.success('复制成功')
|
||||||
|
}).catch(() => {
|
||||||
|
message.error('复制失败')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
.activation-page {
|
||||||
|
:deep(textarea) {
|
||||||
|
font-family: consolas, monospace;
|
||||||
|
resize: none;
|
||||||
|
}
|
||||||
|
:deep(.ant-form-item-label) {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-card) {
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
35
frontend/tsconfig.json
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "esnext",
|
||||||
|
"module": "esnext",
|
||||||
|
"lib": ["esnext", "dom", "dom.iterable", "scripthost"],
|
||||||
|
"jsx": "preserve",
|
||||||
|
|
||||||
|
"strict": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"importHelpers": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
|
||||||
|
// 定义一个变量就必须给它一个初始值
|
||||||
|
"strictPropertyInitialization": false,
|
||||||
|
// 允许使用obj[key]访问对象属性
|
||||||
|
//"suppressImplicitAnyIndexErrors": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"baseUrl": "./",
|
||||||
|
"paths": {
|
||||||
|
"@/*": [
|
||||||
|
"src/*"
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include":["src/**/*.ts", "src/**/*.vue", "src/**/*.tsx", "src/**/*.d.ts", "*.d.ts"],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"dist"
|
||||||
|
]
|
||||||
|
}
|
||||||
54
frontend/vite.config.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import vue from '@vitejs/plugin-vue';
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import viteCompression from 'vite-plugin-compression';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
export default defineConfig((mode) => {
|
||||||
|
return {
|
||||||
|
// Project plugins
|
||||||
|
plugins: [
|
||||||
|
vue(),
|
||||||
|
viteCompression({
|
||||||
|
verbose: true,
|
||||||
|
disable: false,
|
||||||
|
threshold: 1025,
|
||||||
|
algorithm: 'gzip',
|
||||||
|
ext: '.gz',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
// Base configuration
|
||||||
|
base: './',
|
||||||
|
publicDir: 'public',
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': path.resolve(__dirname, 'src'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
css: {
|
||||||
|
preprocessorOptions: {
|
||||||
|
less: {
|
||||||
|
modifyVars: {
|
||||||
|
'@border-color-base': '#dce3e8',
|
||||||
|
},
|
||||||
|
javascriptEnabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
outDir: 'dist',
|
||||||
|
assetsDir: 'assets',
|
||||||
|
assetsInlineLimit: 4096,
|
||||||
|
cssCodeSplit: true,
|
||||||
|
brotliSize: false,
|
||||||
|
sourcemap: false,
|
||||||
|
minify: 'terser',
|
||||||
|
terserOptions: {
|
||||||
|
compress: {
|
||||||
|
// Remove console and debugger in production
|
||||||
|
drop_console: false,
|
||||||
|
drop_debugger: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
50
package.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"name": "pqs9100_tool",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "pqs-9100 tool client",
|
||||||
|
"main": "./public/electron/main.js",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "ee-bin dev",
|
||||||
|
"build": "npm run build-frontend && npm run build-electron && ee-bin encrypt",
|
||||||
|
"start": "ee-bin start",
|
||||||
|
"dev-frontend": "ee-bin dev --serve=frontend",
|
||||||
|
"dev-electron": "ee-bin dev --serve=electron",
|
||||||
|
"build-frontend": "ee-bin build --cmds=frontend && ee-bin move --flag=frontend_dist",
|
||||||
|
"build-electron": "ee-bin build --cmds=electron",
|
||||||
|
"encrypt": "ee-bin encrypt",
|
||||||
|
"icon": "ee-bin icon",
|
||||||
|
"build-w": "ee-bin build --cmds=win64",
|
||||||
|
"build-we": "ee-bin build --cmds=win_e",
|
||||||
|
"build-m": "ee-bin build --cmds=mac",
|
||||||
|
"build-m-arm64": "ee-bin build --cmds=mac_arm64",
|
||||||
|
"build-l": "ee-bin build --cmds=linux",
|
||||||
|
"debug-dev": "cross-env DEBUG=ee-* ee-bin dev",
|
||||||
|
"debug-encrypt": "ee-bin encrypt",
|
||||||
|
"debug-electron": "cross-env DEBUG=ee-* ee-bin dev --serve=electron",
|
||||||
|
"debug-move": "ee-bin move --flag=frontend_dist"
|
||||||
|
},
|
||||||
|
"repository": "https://github.com/dromara/electron-egg.git",
|
||||||
|
"keywords": [
|
||||||
|
"Electron",
|
||||||
|
"electron-egg",
|
||||||
|
"ElectronEgg"
|
||||||
|
],
|
||||||
|
"author": "njcn",
|
||||||
|
"devDependencies": {
|
||||||
|
"@electron/rebuild": "^3.7.1",
|
||||||
|
"@types/node": "^20.16.0",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
|
"debug": "^4.4.0",
|
||||||
|
"ee-bin": "^4.1.10",
|
||||||
|
"electron": "^31.7.6",
|
||||||
|
"electron-builder": "^25.1.8",
|
||||||
|
"icon-gen": "^5.0.0",
|
||||||
|
"typescript": "^5.4.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.7.9",
|
||||||
|
"dayjs": "^1.11.13",
|
||||||
|
"ee-core": "^4.1.5",
|
||||||
|
"electron-updater": "^6.3.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
94
public/html/loading.html
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1.0, minimum-scale=1.0" />
|
||||||
|
<style>
|
||||||
|
#loadingPage {
|
||||||
|
background-color: #dedede;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.base {
|
||||||
|
left: 50%;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
.desc {
|
||||||
|
margin: 0, 0, 20px, 0;
|
||||||
|
}
|
||||||
|
.loading,
|
||||||
|
.loading > div {
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.loading {
|
||||||
|
display: block;
|
||||||
|
font-size: 0;
|
||||||
|
color: #06b359;
|
||||||
|
}
|
||||||
|
.loading.la-dark {
|
||||||
|
color: #07C160;
|
||||||
|
}
|
||||||
|
.loading > div {
|
||||||
|
display: inline-block;
|
||||||
|
float: none;
|
||||||
|
background-color: currentColor;
|
||||||
|
border: 0 solid currentColor;
|
||||||
|
}
|
||||||
|
.loading {
|
||||||
|
width: 92px;
|
||||||
|
height: 92px;
|
||||||
|
}
|
||||||
|
.loading > div {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
background: transparent;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 2px;
|
||||||
|
border-radius: 100%;
|
||||||
|
animation: ball-clip-rotate-multiple-rotate 1s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
.loading > div:first-child {
|
||||||
|
position: absolute;
|
||||||
|
width: 92px;
|
||||||
|
height: 92px;
|
||||||
|
border-right-color: transparent;
|
||||||
|
border-left-color: transparent;
|
||||||
|
}
|
||||||
|
.loading > div:last-child {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border-top-color: transparent;
|
||||||
|
border-bottom-color: transparent;
|
||||||
|
animation-duration: 0.5s;
|
||||||
|
animation-direction: reverse;
|
||||||
|
}
|
||||||
|
@keyframes ball-clip-rotate-multiple-rotate {
|
||||||
|
0% {
|
||||||
|
transform: translate(-50%, -50%) rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: translate(-50%, -50%) rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translate(-50%, -50%) rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="boot">
|
||||||
|
<div class='base'>
|
||||||
|
<div class="loading">
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
22
public/html/view_example.html
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<style type="text/css">
|
||||||
|
body{
|
||||||
|
margin:0px auto;
|
||||||
|
}
|
||||||
|
#content {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 35%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<title></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="content">
|
||||||
|
这是一个html页面
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
public/images/logo-32.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
public/images/logo.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
public/images/tray.png
Normal file
|
After Width: | Height: | Size: 943 B |
28
public/ssl/localhost+1.key
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDpWYqPkljVtDNp
|
||||||
|
JVwlcOxNVihQPf4T3Q/tuIt5znV5ImBmlWg+OyuG47Y5e+qPMjFCSX4ebTAtBMbY
|
||||||
|
m6AJihkKy0iKj1mVS9TPCzqcHFnUliCIqJMKFsJTWygNGgogjXhlxFaJgCZO6Gw6
|
||||||
|
ocWp6nw1gMhrMIxqT2MQIQX16SD1IH/F4JMoaYuifnR+OOgbS3yUKHDTFApkZAWn
|
||||||
|
dS4GpbT39rW9cmbJrGHCvl8bsm8MXMdXars10A++wjjmHbtZu8beFv+zKbDw4iAu
|
||||||
|
ls8p/lAoIvQy8MkLLM5b392CLMaK0517+qM3VdEZ0ph+32m9IEoj5QV8xgaPdnyP
|
||||||
|
8/8a2bU/AgMBAAECggEBAIzFZ8GVF+JUA2+7CgvMQ8Gj6E4AF/cDtUhDvGCPHG8n
|
||||||
|
PeCk4W4pY+jMFnI3PxmDvhOvIlZYqGeAKjUiLTmUBedtGyX7tJ9MT+VXcNQchlSo
|
||||||
|
/Jd0mr/LWw/OPispOlLJBYjfGRV6KaIQtLnqPcRzoNrmBgIkF5FKswhX47CmIyu8
|
||||||
|
eEXmDsqXzWmYwdOHLNDshLOrCgFgRnqK7HjxvNqb9k4qv3V9WxlJYITK7L4eJNcZ
|
||||||
|
XYvGl+QV1+n153phyYnHcbohzvE44Hv8e4hiY9uYNdWckNBNFLpk9vEmUjewCRT1
|
||||||
|
kL30woifUhZCalXBIfKEHNZg23teOMHNZTqcS+ER64ECgYEA7BAWVWS/8b9h1AmP
|
||||||
|
SYhJgudb+ck1ItuvEDjonKuUCTBYm0iQI7cgAimasIBybRO8zwKstvWGDnUJJEkB
|
||||||
|
Oh7AXF6CbKuP7navTBAaF3AXsNfDgQuEwtEg78iqiQzTyp6FOvvOT2aOtzi86Ju1
|
||||||
|
zwKu+DLV3ETeokHWrQmV1uZnbZMCgYEA/Q7LdEEvZxz8OqOjtj8iKLWAv0WvnHTO
|
||||||
|
Zjqn/BbXi2PyI8d5ntIUPEgm/MRpvXTa465Uu8Orujfq51Z/oFbyvhhEOWT/sVn/
|
||||||
|
fzzbH4xXb3bLJ3D+LILQzsm4d8yrV66Re1ehFVxRPIy5RTpssED7bOns9ds4lsHT
|
||||||
|
W9p7ibYRBSUCgYAMpJftnuXA1tUwfAqWj5wQTL/aUvJrmYR4w/OBYJcfHt3AA1Tk
|
||||||
|
9MvcEcpdJaP7P5FfLO9/JQs2/wGsVdSg/kCjMdSeaVneFbExy7L6CmDacdPgt3M2
|
||||||
|
0+iFryOjD3LQaUkNbasRCZcfLQTBGIXWPniMhnx5vZ6G5ivPPLIvvktPzQKBgQCd
|
||||||
|
s/yi5ISwE+Y0fQpnZwzYpdQoXztDm5+NIfzSI0IMgirClWt7yJwHvUdeuuDSyuIm
|
||||||
|
hdwUb6qzkGl55fP/bnA0e1b5FbIrSlTpbHl6PbG3qyaL2+TqxFNwq1Gkhw44xHex
|
||||||
|
kDi44SFXRLOpKvHVHYoSo+2igg3QFdasJYpblfUhaQKBgF0l9PpMbDLdPlI33IQz
|
||||||
|
bEzw0ig8R8nHocJzOkK/BdLI8WiItYGgq4mcZGDWsztNg17QQGTEFrH7H9B8DKAJ
|
||||||
|
p75jz5O83arjMECqAiXlSGOWtq6NhbgyJcQJxvvvN8wObVFoVkLoEbqE1TkDqZfI
|
||||||
|
CqiusA5zgG89vzP9xFhW2ia2
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
26
public/ssl/localhost+1.pem
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEXzCCAsegAwIBAgIRAOLUY4uS9d2yXx0vd6qql30wDQYJKoZIhvcNAQELBQAw
|
||||||
|
gZExHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTEzMDEGA1UECwwqQklM
|
||||||
|
SUJJTElcZ2Fvc2h1YWl4aW5nQENOMjEwMTAyMjc0ICjljaHor7opMTowOAYDVQQD
|
||||||
|
DDFta2NlcnQgQklMSUJJTElcZ2Fvc2h1YWl4aW5nQENOMjEwMTAyMjc0ICjljaHo
|
||||||
|
r7opMB4XDTIyMDcyNzA4NDcyOFoXDTI0MTAyNzA4NDcyOFowXjEnMCUGA1UEChMe
|
||||||
|
bWtjZXJ0IGRldmVsb3BtZW50IGNlcnRpZmljYXRlMTMwMQYDVQQLDCpCSUxJQklM
|
||||||
|
SVxnYW9zaHVhaXhpbmdAQ04yMTAxMDIyNzQgKOWNoeivuikwggEiMA0GCSqGSIb3
|
||||||
|
DQEBAQUAA4IBDwAwggEKAoIBAQDpWYqPkljVtDNpJVwlcOxNVihQPf4T3Q/tuIt5
|
||||||
|
znV5ImBmlWg+OyuG47Y5e+qPMjFCSX4ebTAtBMbYm6AJihkKy0iKj1mVS9TPCzqc
|
||||||
|
HFnUliCIqJMKFsJTWygNGgogjXhlxFaJgCZO6Gw6ocWp6nw1gMhrMIxqT2MQIQX1
|
||||||
|
6SD1IH/F4JMoaYuifnR+OOgbS3yUKHDTFApkZAWndS4GpbT39rW9cmbJrGHCvl8b
|
||||||
|
sm8MXMdXars10A++wjjmHbtZu8beFv+zKbDw4iAuls8p/lAoIvQy8MkLLM5b392C
|
||||||
|
LMaK0517+qM3VdEZ0ph+32m9IEoj5QV8xgaPdnyP8/8a2bU/AgMBAAGjZDBiMA4G
|
||||||
|
A1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAfBgNVHSMEGDAWgBQn
|
||||||
|
B1E5Js/cFhxBwpZL59aoK/skLjAaBgNVHREEEzARgglsb2NhbGhvc3SHBH8AAAEw
|
||||||
|
DQYJKoZIhvcNAQELBQADggGBAIaUncQj2XN2rNn6sE0MuaWboFqwpkydyei6FvtN
|
||||||
|
c/TY9RWW3QRYICcO721l/2jBiWplQt/ZYaJ+IWN+C+3JSAz9IYsM/nMgxHL2azLQ
|
||||||
|
zHKnASEjxptW9+mlsgVk2LTrBfbc197ikLu80M/0jQYaIBeoEOaMlhBjno139nTO
|
||||||
|
evNheyFKvAhggOseD00I9VBZkKDBxvqr6PHnGjyAU43C1/HkNjglIbQjAZdBmXlX
|
||||||
|
HuelQ97glfhzyApvmczPrc8IAqPhtYn2nJ5P6Ea35LEc3D7uVExywcjDFcSwMJCb
|
||||||
|
TXqouzM/U8pO+DGeuvgwkYrBGlA7iEE+ZQgxCBatOXwG95THtFlfW+H0ILHB2tcX
|
||||||
|
P+Kztwd+4ipPciJz+1NK7z7erwfxHO5hmXJskH9YWi6YJsIw5g1iYs0pJJ/4p7Bd
|
||||||
|
8qSGEhri/+iijcC76q+1N0xhJxQrDDlC0pKp6oAYFDGKirzwmlAf/eJBy0ORWjCj
|
||||||
|
yk+d9T622yzcXa5fw3HBZh1o6A==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
28
tsconfig.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es6",
|
||||||
|
"module": "commonjs",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"types": ["node"],
|
||||||
|
"esModuleInterop": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "node", // node
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./electron/**/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||