diff --git a/.tauri/signing-key b/.tauri/signing-key
new file mode 100644
index 0000000..0cfba4e
--- /dev/null
+++ b/.tauri/signing-key
@@ -0,0 +1 @@
+dW50cnVzdGVkIGNvbW1lbnQ6IHJzaWduIGVuY3J5cHRlZCBzZWNyZXQga2V5ClJXUlRZMEl5eVJXUG1sdWpVNnBJUHpXSjFZWnczeVpPVjNZMEVvOGFkQlB5UFZDSFNEc0FBQkFBQUFBQUFBQUFBQUlBQUFBQVVmWE1BVXlmNXNqRFRmSEhSU3ltY3hqT1h4aE1hRVNEenJ2RUhkZ0JZaFJWc1owb1hpY3UwaEdqeTNQelRYaVd4M3E4WWR2MTloYWJSZFVTQm5scUhaTjRKOXlqeVlPRVpybWZTY2p2cUQzNkpDZGZGRzBtTEgvdFVBajNzdnBPTXVROFZXQXFUTGc9Cg==
\ No newline at end of file
diff --git a/.tauri/signing-key.pub b/.tauri/signing-key.pub
new file mode 100644
index 0000000..e3e6dd4
--- /dev/null
+++ b/.tauri/signing-key.pub
@@ -0,0 +1 @@
+dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDY0Q0YxMzNBM0Q5OEU4NEMKUldSTTZKZzlPaFBQWkVXRVdBVHdTdlNvVnZSL2FFQkZtbFpRTzdjNGxHbjJsZ1R5MFRLdkpmYzMK
\ No newline at end of file
diff --git a/CLAUDE.md b/CLAUDE.md
index d507e16..97d4022 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -8,7 +8,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## 常用命令
-项目使用 **npm** 作为包管理器(存在 package-lock.json)。
+项目使用 **pnpm** 作为包管理器(存在 package-lock.json)。
```bash
# 启动开发模式(前端 + Tauri)
@@ -18,7 +18,7 @@ pnpm run tauri dev
pnpm run dev
# 构建生产版本
-npm run tauri build
+pnpm run tauri build
# 前端类型检查 + 构建
pnpm run build
@@ -60,7 +60,7 @@ cd src-tauri && cargo clippy
- `src-tauri/capabilities/default.json` - Tauri 权限配置(HTTP 白名单、插件权限)
- `src-tauri/tauri.conf.json` - 应用配置(窗口、图标、bundle)
-- 用户配置文件路径:`%APPDATA%/tauri-app/config.json`(Windows)
+- 用户配置文件路径:`%APPDATA%/work-order-monitor/config.json`(Windows)
## 依赖的 Tauri 插件
diff --git a/README_APP.md b/README_APP.md
index 31b17d5..024db1c 100644
--- a/README_APP.md
+++ b/README_APP.md
@@ -1,137 +1,127 @@
-# 系统监测应用程序
+# 工单系统监测
-这是一个基于 Tauri + Vue 开发的系统监测应用程序,具有以下功能:
+基于 **Tauri 2.x + Vue 3** 的工单监测桌面应用,用于监测 CRM 系统的待处理工单并发送系统通知。
-## 功能特性
+## 环境要求
-1. **用户设置界面** - 配置用户名和密码
-2. **系统托盘集成** - 应用启动后自动最小化到系统托盘
-3. **自动登录** - 保存用户凭据并支持自动登录
-4. **定时API调用** - 登录后每1分钟调用一次接口
-5. **系统通知** - 根据API返回值弹出系统消息
-6. **模块化架构** - 代码按功能模块组织,便于维护
+- Node.js >= 18
+- Rust (stable)
+- Visual Studio Build Tools(Windows,含 C++ 工具链)
+
+## 开发
+
+```bash
+# 安装依赖
+pnpm install
+
+# 启动开发模式(前端 + Tauri)
+pnpm tauri dev
+
+# 仅启动前端
+pnpm dev
+```
+
+## 构建
+
+签名密钥已包含在项目中(`.tauri/` 目录),构建脚本会自动加载,直接运行:
+
+```bash
+pnpm run tauri-build
+```
+
+构建产物位于 `src-tauri/target/release/bundle/nsis/`。
+
+## 版本号管理
+
+使用自定义脚本统一更新 `package.json`、`tauri.conf.json`、`Cargo.toml` 三个文件的版本号:
+
+```bash
+node scripts/bump-version.mjs # 默认 patch: 0.2.0 → 0.2.1
+node scripts/bump-version.mjs minor # minor: 0.2.0 → 0.3.0
+node scripts/bump-version.mjs major # major: 0.2.0 → 1.0.0
+node scripts/bump-version.mjs 1.2.3 # 指定版本
+```
+
+## 发布
+
+构建完成后,运行发布脚本将安装包和更新元数据上传到远程服务器:
+
+```bash
+node scripts/publish.mjs --notes "更新说明"
+```
+
+脚本会自动:
+1. 从构建产物中读取 `.nsis.zip` 和 `.nsis.zip.sig`
+2. 生成 `update.json`(供应用内自动更新使用)
+3. 通过 SCP 上传到服务器 `192.168.2.127:/var/www/html/work-order-monitor/`
+
+更新地址:`http://web.nps.yunvip123.cn/work-order-monitor/update.json`
+
+## 完整发版流程
+
+```bash
+# 1. 更新版本号
+node scripts/bump-version.mjs minor
+
+# 2. 构建
+pnpm run tauri-build
+
+# 3. 发布到服务器
+node scripts/publish.mjs --notes "v0.3.0 新功能说明"
+```
+
+## 签名密钥
+
+项目已内置 updater 签名密钥(`.tauri/signing-key` 和 `.tauri/signing-key.pub`),无密码保护,任何人克隆项目后即可直接构建。
+
+如需重新生成密钥:
+
+```bash
+pnpm tauri signer generate -w .tauri/signing-key -p "" --ci -f
+```
+
+生成后需将 `.tauri/signing-key.pub` 的内容更新到 `src-tauri/tauri.conf.json` 的 `plugins.updater.pubkey` 字段。
## 项目结构
```
-src-tauri/src/
-├── lib.rs # 主模块,应用程序入口和命令处理
-├── config.rs # 配置管理模块
-├── api.rs # API调用模块
-├── tray.rs # 系统托盘模块
-└── scheduler.rs # 定时任务模块
+src/ # 前端(Vue 3)
+├── App.vue # 主界面
+├── stores/monitor.ts # Pinia 状态管理(核心业务逻辑)
+├── components/
+│ ├── MonitorControl.vue # 监测面板(工单数据卡片)
+│ ├── LoginForm.vue # 登录表单
+│ ├── SettingsPanel.vue # 配置面板
+│ ├── StatusHeader.vue # 顶部状态栏
+│ ├── LogViewer.vue # 日志查看器
+│ ├── CloseDialog.vue # 关闭确认弹窗
+│ └── UpdateDialog.vue # 更新确认弹窗
-src/
-└── App.vue # Vue设置界面
+src-tauri/ # Rust 后端
+├── src/lib.rs # 应用初始化、插件注册
+├── src/notification.rs # Windows Toast 通知
+├── tauri.conf.json # Tauri 配置
+├── capabilities/default.json # 权限配置
+
+scripts/
+├── build.mjs # 构建(自动加载签名密钥)
+├── bump-version.mjs # 版本号管理
+└── publish.mjs # 构建发布
```
-## 使用说明
+## 监测的 API
-### 1. 启动应用程序
-```bash
-# 开发模式
-pnpm tauri dev
+| 接口 | 说明 | 触发通知条件 |
+| --- | --- | --- |
+| `SystemUser/Login` | 登录获取 Session | - |
+| `DemandManage/QueryIndexCount` | 工单统计 | PendingCount / StaycloseCount / ConfirmCount > 0 |
+| `DemandManage/GetWorkOrderListPage` | 待审核工单列表 | DataCount > 0 |
-# 构建生产版本
-pnpm tauri build
-```
+## Tauri 插件
-### 2. 配置设置
-- 应用启动后会自动最小化到系统托盘
-- 右键点击托盘图标选择"显示设置"打开设置界面
-- 输入用户名和密码,点击"保存设置"
-
-### 3. 登录和监测
-- 保存设置后点击"登录"按钮
-- 登录成功后会自动启动定时任务(每1分钟执行一次)
-- 系统会根据API返回值显示通知消息
-
-### 4. 托盘操作
-- **左键点击托盘图标** - 显示设置界面
-- **右键点击托盘图标** - 显示菜单(显示设置/退出)
-- **关闭窗口** - 应用会隐藏到托盘而不是退出
-
-## 配置说明
-
-### API接口
-应用程序已配置为使用以下API接口:
-
-- **登录接口**: `https://crm.yunvip123.com/api/SystemUser/Login`
-- **检查接口**: `https://crm.yunvip123.com/api/DemandManage/QueryIndexCount`
-
-### 认证机制
-- 登录时获取 `ASP.NET_SessionId` Cookie
-- 所有后续请求都需要携带此Cookie进行认证
-
-### API响应格式
-
-**登录响应 (LoginResponse):**
-```json
-{
- "success": true,
- "code": null,
- "msg": "执行成功",
- "data": {
- "GID": "512860ad-aa4a-4268-a5d9-6c7d2e28680b",
- "SU_UserName": "A田森林"
- }
-}
-```
-
-**检查响应 (CheckResponse):**
-```json
-{
- "success": true,
- "code": null,
- "msg": "执行成功",
- "data": {
- "PendingCount": 0,
- "StaycloseCount": 0,
- "ConfirmCount": 0
- }
-}
-```
-
-### 通知逻辑
-- 当 `PendingCount`、`StaycloseCount`、`ConfirmCount` 三个值都为0时,不发送通知
-- 当任意一个值大于0时,发送系统通知,显示具体的工单数量
-
-## 开发说明
-
-### 添加新功能
-1. **新的API端点** - 在 `api.rs` 中添加新的方法
-2. **新的配置项** - 在 `config.rs` 中添加到 `AppConfig` 结构体
-3. **新的UI组件** - 在 `App.vue` 中添加新的界面元素
-4. **新的命令** - 在 `lib.rs` 中添加新的 Tauri 命令
-
-### 错误处理
-- 所有模块都使用 `anyhow::Result` 进行错误处理
-- 错误信息会显示在UI的消息卡片中
-- 日志记录使用 `log` crate,可通过环境变量 `RUST_LOG` 控制级别
-
-### 数据持久化
-- 用户配置保存在系统配置目录:`%APPDATA%/tauri-app/config.json` (Windows)
-- 配置文件使用JSON格式,包含用户名、密码等信息
-
-## 注意事项
-
-1. **安全性** - 密码以明文形式存储在配置文件中,生产环境建议加密
-2. **网络请求** - API调用失败时会显示错误通知
-3. **系统权限** - 需要通知权限来显示系统消息
-4. **托盘图标** - 使用应用程序默认图标,可根据登录状态切换不同图标
-
-## TODO 项目
-
-- [x] 配置实际的API地址和端点
-- [x] 实现Cookie认证机制
-- [x] 适配实际API响应格式
-- [x] 添加更多的配置选项(检查间隔等)
-- [x] 添加日志系统和日志显示
-- [x] 实现自动启动功能
-- [x] 添加网络连接状态检测
-- [x] 添加测试按钮(手动检查、停止/开始、最小化等)
-- [ ] 实现密码加密存储
-- [ ] 支持不同登录状态的托盘图标(图标文件)
-- [ ] 添加日志文件输出
-- [ ] 实现会话过期自动重新登录
-- [ ] 解决Windows编译环境问题(需要Visual Studio Build Tools)
+- `tauri-plugin-http` — HTTP 请求
+- `tauri-plugin-notification` — 系统通知
+- `tauri-plugin-autostart` — 开机自启动
+- `tauri-plugin-opener` — 打开外部链接
+- `tauri-plugin-updater` — 应用内自动更新
+- `tauri-plugin-process` — 进程管理(重启)
diff --git a/data/deploy.js b/data/deploy.js
new file mode 100644
index 0000000..7ca33f6
--- /dev/null
+++ b/data/deploy.js
@@ -0,0 +1,39 @@
+const { NodeSSH } = require("node-ssh");
+const os = require("node:os");
+
+const config = {
+ host: "192.168.2.250",
+ username: "admin",
+ privateKeyPath: `${os.homedir()}\\.ssh\\id_rsa_2048`,
+ localDirectory: "dist",
+ remoteDirectory: "/D:/nginx/nginx-1.27.1/erp",
+};
+
+async function main() {
+ const ssh = new NodeSSH();
+
+ await ssh.connect({
+ host: config.host,
+ username: config.username,
+ privateKeyPath: config.privateKeyPath,
+ });
+
+ const res = await ssh.putDirectory(
+ config.localDirectory,
+ config.remoteDirectory,
+ {
+ recursive: true,
+ }
+ );
+ if (res) {
+ console.log("传输完成", res);
+ } else {
+ console.error(res);
+ }
+
+ const connection = ssh.getConnection();
+ connection.destroy();
+ // await ssh.dispose();
+}
+
+main();
diff --git a/package-lock.json b/package-lock.json
index 7ac1b95..afc99c1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
- "name": "tauri-app",
- "version": "0.1.3",
+ "name": "work-order-monitor",
+ "version": "0.2.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "tauri-app",
- "version": "0.1.3",
+ "name": "work-order-monitor",
+ "version": "0.2.1",
"dependencies": {
"@ant-design/icons-vue": "^7.0.1",
"@tauri-apps/api": "^2.10.1",
@@ -14,13 +14,15 @@
"@tauri-apps/plugin-http": "^2.5.7",
"@tauri-apps/plugin-notification": "^2.3.3",
"@tauri-apps/plugin-opener": "^2.5.3",
+ "@tauri-apps/plugin-process": "^2.3.1",
+ "@tauri-apps/plugin-updater": "^2.10.0",
"ant-design-vue": "^4.2.6",
"dayjs": "^1.11.19",
"pinia": "^3.0.4",
"vue": "^3.5.29"
},
"devDependencies": {
- "@tauri-apps/cli": "^2",
+ "@tauri-apps/cli": "^2.10.1",
"@vitejs/plugin-vue": "^6.0.4",
"typescript": "~5.9.3",
"vite": "^7.3.1",
@@ -957,9 +959,9 @@
}
},
"node_modules/@tauri-apps/cli": {
- "version": "2.10.0",
- "resolved": "https://registry.npmmirror.com/@tauri-apps/cli/-/cli-2.10.0.tgz",
- "integrity": "sha512-ZwT0T+7bw4+DPCSWzmviwq5XbXlM0cNoleDKOYPFYqcZqeKY31KlpoMW/MOON/tOFBPgi31a2v3w9gliqwL2+Q==",
+ "version": "2.10.1",
+ "resolved": "https://registry.npmmirror.com/@tauri-apps/cli/-/cli-2.10.1.tgz",
+ "integrity": "sha512-jQNGF/5quwORdZSSLtTluyKQ+o6SMa/AUICfhf4egCGFdMHqWssApVgYSbg+jmrZoc8e1DscNvjTnXtlHLS11g==",
"dev": true,
"license": "Apache-2.0 OR MIT",
"bin": {
@@ -973,23 +975,23 @@
"url": "https://opencollective.com/tauri"
},
"optionalDependencies": {
- "@tauri-apps/cli-darwin-arm64": "2.10.0",
- "@tauri-apps/cli-darwin-x64": "2.10.0",
- "@tauri-apps/cli-linux-arm-gnueabihf": "2.10.0",
- "@tauri-apps/cli-linux-arm64-gnu": "2.10.0",
- "@tauri-apps/cli-linux-arm64-musl": "2.10.0",
- "@tauri-apps/cli-linux-riscv64-gnu": "2.10.0",
- "@tauri-apps/cli-linux-x64-gnu": "2.10.0",
- "@tauri-apps/cli-linux-x64-musl": "2.10.0",
- "@tauri-apps/cli-win32-arm64-msvc": "2.10.0",
- "@tauri-apps/cli-win32-ia32-msvc": "2.10.0",
- "@tauri-apps/cli-win32-x64-msvc": "2.10.0"
+ "@tauri-apps/cli-darwin-arm64": "2.10.1",
+ "@tauri-apps/cli-darwin-x64": "2.10.1",
+ "@tauri-apps/cli-linux-arm-gnueabihf": "2.10.1",
+ "@tauri-apps/cli-linux-arm64-gnu": "2.10.1",
+ "@tauri-apps/cli-linux-arm64-musl": "2.10.1",
+ "@tauri-apps/cli-linux-riscv64-gnu": "2.10.1",
+ "@tauri-apps/cli-linux-x64-gnu": "2.10.1",
+ "@tauri-apps/cli-linux-x64-musl": "2.10.1",
+ "@tauri-apps/cli-win32-arm64-msvc": "2.10.1",
+ "@tauri-apps/cli-win32-ia32-msvc": "2.10.1",
+ "@tauri-apps/cli-win32-x64-msvc": "2.10.1"
}
},
"node_modules/@tauri-apps/cli-darwin-arm64": {
- "version": "2.10.0",
- "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.10.0.tgz",
- "integrity": "sha512-avqHD4HRjrMamE/7R/kzJPcAJnZs0IIS+1nkDP5b+TNBn3py7N2aIo9LIpy+VQq0AkN8G5dDpZtOOBkmWt/zjA==",
+ "version": "2.10.1",
+ "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.10.1.tgz",
+ "integrity": "sha512-Z2OjCXiZ+fbYZy7PmP3WRnOpM9+Fy+oonKDEmUE6MwN4IGaYqgceTjwHucc/kEEYZos5GICve35f7ZiizgqEnQ==",
"cpu": [
"arm64"
],
@@ -1004,9 +1006,9 @@
}
},
"node_modules/@tauri-apps/cli-darwin-x64": {
- "version": "2.10.0",
- "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.10.0.tgz",
- "integrity": "sha512-keDmlvJRStzVFjZTd0xYkBONLtgBC9eMTpmXnBXzsHuawV2q9PvDo2x6D5mhuoMVrJ9QWjgaPKBBCFks4dK71Q==",
+ "version": "2.10.1",
+ "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.10.1.tgz",
+ "integrity": "sha512-V/irQVvjPMGOTQqNj55PnQPVuH4VJP8vZCN7ajnj+ZS8Kom1tEM2hR3qbbIRoS3dBKs5mbG8yg1WC+97dq17Pw==",
"cpu": [
"x64"
],
@@ -1021,9 +1023,9 @@
}
},
"node_modules/@tauri-apps/cli-linux-arm-gnueabihf": {
- "version": "2.10.0",
- "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.10.0.tgz",
- "integrity": "sha512-e5u0VfLZsMAC9iHaOEANumgl6lfnJx0Dtjkd8IJpysZ8jp0tJ6wrIkto2OzQgzcYyRCKgX72aKE0PFgZputA8g==",
+ "version": "2.10.1",
+ "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.10.1.tgz",
+ "integrity": "sha512-Hyzwsb4VnCWKGfTw+wSt15Z2pLw2f0JdFBfq2vHBOBhvg7oi6uhKiF87hmbXOBXUZaGkyRDkCHsdzJcIfoJC2w==",
"cpu": [
"arm"
],
@@ -1038,9 +1040,9 @@
}
},
"node_modules/@tauri-apps/cli-linux-arm64-gnu": {
- "version": "2.10.0",
- "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.10.0.tgz",
- "integrity": "sha512-YrYYk2dfmBs5m+OIMCrb+JH/oo+4FtlpcrTCgiFYc7vcs6m3QDd1TTyWu0u01ewsCtK2kOdluhr/zKku+KP7HA==",
+ "version": "2.10.1",
+ "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.10.1.tgz",
+ "integrity": "sha512-OyOYs2t5GkBIvyWjA1+h4CZxTcdz1OZPCWAPz5DYEfB0cnWHERTnQ/SLayQzncrT0kwRoSfSz9KxenkyJoTelA==",
"cpu": [
"arm64"
],
@@ -1055,9 +1057,9 @@
}
},
"node_modules/@tauri-apps/cli-linux-arm64-musl": {
- "version": "2.10.0",
- "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.10.0.tgz",
- "integrity": "sha512-GUoPdVJmrJRIXFfW3Rkt+eGK9ygOdyISACZfC/bCSfOnGt8kNdQIQr5WRH9QUaTVFIwxMlQyV3m+yXYP+xhSVA==",
+ "version": "2.10.1",
+ "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.10.1.tgz",
+ "integrity": "sha512-MIj78PDDGjkg3NqGptDOGgfXks7SYJwhiMh8SBoZS+vfdz7yP5jN18bNaLnDhsVIPARcAhE1TlsZe/8Yxo2zqg==",
"cpu": [
"arm64"
],
@@ -1072,9 +1074,9 @@
}
},
"node_modules/@tauri-apps/cli-linux-riscv64-gnu": {
- "version": "2.10.0",
- "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.10.0.tgz",
- "integrity": "sha512-JO7s3TlSxshwsoKNCDkyvsx5gw2QAs/Y2GbR5UE2d5kkU138ATKoPOtxn8G1fFT1aDW4LH0rYAAfBpGkDyJJnw==",
+ "version": "2.10.1",
+ "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.10.1.tgz",
+ "integrity": "sha512-X0lvOVUg8PCVaoEtEAnpxmnkwlE1gcMDTqfhbefICKDnOTJ5Est3qL0SrWxizDackIOKBcvtpejrSiVpuJI1kw==",
"cpu": [
"riscv64"
],
@@ -1089,9 +1091,9 @@
}
},
"node_modules/@tauri-apps/cli-linux-x64-gnu": {
- "version": "2.10.0",
- "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.10.0.tgz",
- "integrity": "sha512-Uvh4SUUp4A6DVRSMWjelww0GnZI3PlVy7VS+DRF5napKuIehVjGl9XD0uKoCoxwAQBLctvipyEK+pDXpJeoHng==",
+ "version": "2.10.1",
+ "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.10.1.tgz",
+ "integrity": "sha512-2/12bEzsJS9fAKybxgicCDFxYD1WEI9kO+tlDwX5znWG2GwMBaiWcmhGlZ8fi+DMe9CXlcVarMTYc0L3REIRxw==",
"cpu": [
"x64"
],
@@ -1106,9 +1108,9 @@
}
},
"node_modules/@tauri-apps/cli-linux-x64-musl": {
- "version": "2.10.0",
- "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.10.0.tgz",
- "integrity": "sha512-AP0KRK6bJuTpQ8kMNWvhIpKUkQJfcPFeba7QshOQZjJ8wOS6emwTN4K5g/d3AbCMo0RRdnZWwu67MlmtJyxC1Q==",
+ "version": "2.10.1",
+ "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.10.1.tgz",
+ "integrity": "sha512-Y8J0ZzswPz50UcGOFuXGEMrxbjwKSPgXftx5qnkuMs2rmwQB5ssvLb6tn54wDSYxe7S6vlLob9vt0VKuNOaCIQ==",
"cpu": [
"x64"
],
@@ -1123,9 +1125,9 @@
}
},
"node_modules/@tauri-apps/cli-win32-arm64-msvc": {
- "version": "2.10.0",
- "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.10.0.tgz",
- "integrity": "sha512-97DXVU3dJystrq7W41IX+82JEorLNY+3+ECYxvXWqkq7DBN6FsA08x/EFGE8N/b0LTOui9X2dvpGGoeZKKV08g==",
+ "version": "2.10.1",
+ "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.10.1.tgz",
+ "integrity": "sha512-iSt5B86jHYAPJa/IlYw++SXtFPGnWtFJriHn7X0NFBVunF6zu9+/zOn8OgqIWSl8RgzhLGXQEEtGBdR4wzpVgg==",
"cpu": [
"arm64"
],
@@ -1140,9 +1142,9 @@
}
},
"node_modules/@tauri-apps/cli-win32-ia32-msvc": {
- "version": "2.10.0",
- "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.10.0.tgz",
- "integrity": "sha512-EHyQ1iwrWy1CwMalEm9z2a6L5isQ121pe7FcA2xe4VWMJp+GHSDDGvbTv/OPdkt2Lyr7DAZBpZHM6nvlHXEc4A==",
+ "version": "2.10.1",
+ "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.10.1.tgz",
+ "integrity": "sha512-gXyxgEzsFegmnWywYU5pEBURkcFN/Oo45EAwvZrHMh+zUSEAvO5E8TXsgPADYm31d1u7OQU3O3HsYfVBf2moHw==",
"cpu": [
"ia32"
],
@@ -1157,9 +1159,9 @@
}
},
"node_modules/@tauri-apps/cli-win32-x64-msvc": {
- "version": "2.10.0",
- "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.10.0.tgz",
- "integrity": "sha512-NTpyQxkpzGmU6ceWBTY2xRIEaS0ZLbVx1HE1zTA3TY/pV3+cPoPPOs+7YScr4IMzXMtOw7tLw5LEXo5oIG3qaQ==",
+ "version": "2.10.1",
+ "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.10.1.tgz",
+ "integrity": "sha512-6Cn7YpPFwzChy0ERz6djKEmUehWrYlM+xTaNzGPgZocw3BD7OfwfWHKVWxXzdjEW2KfKkHddfdxK1XXTYqBRLg==",
"cpu": [
"x64"
],
@@ -1209,6 +1211,24 @@
"@tauri-apps/api": "^2.8.0"
}
},
+ "node_modules/@tauri-apps/plugin-process": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmmirror.com/@tauri-apps/plugin-process/-/plugin-process-2.3.1.tgz",
+ "integrity": "sha512-nCa4fGVaDL/B9ai03VyPOjfAHRHSBz5v6F/ObsB73r/dA3MHHhZtldaDMIc0V/pnUw9ehzr2iEG+XkSEyC0JJA==",
+ "license": "MIT OR Apache-2.0",
+ "dependencies": {
+ "@tauri-apps/api": "^2.8.0"
+ }
+ },
+ "node_modules/@tauri-apps/plugin-updater": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmmirror.com/@tauri-apps/plugin-updater/-/plugin-updater-2.10.0.tgz",
+ "integrity": "sha512-ljN8jPlnT0aSn8ecYhuBib84alxfMx6Hc8vJSKMJyzGbTPFZAC44T2I1QNFZssgWKrAlofvJqCC6Rr472JWfkQ==",
+ "license": "MIT OR Apache-2.0",
+ "dependencies": {
+ "@tauri-apps/api": "^2.10.1"
+ }
+ },
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz",
diff --git a/package.json b/package.json
index e85e038..1120446 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
- "name": "tauri-app",
+ "name": "work-order-monitor",
"private": true,
- "version": "0.1.3",
+ "version": "0.2.2",
"type": "module",
"scripts": {
"dev": "vite",
@@ -9,7 +9,7 @@
"preview": "vite preview",
"tauri": "tauri",
"tauri-dev": "tauri dev",
- "tauri-build": "tauri build"
+ "tauri-build": "node scripts/build.mjs"
},
"dependencies": {
"@ant-design/icons-vue": "^7.0.1",
@@ -18,13 +18,15 @@
"@tauri-apps/plugin-http": "^2.5.7",
"@tauri-apps/plugin-notification": "^2.3.3",
"@tauri-apps/plugin-opener": "^2.5.3",
+ "@tauri-apps/plugin-process": "^2.3.1",
+ "@tauri-apps/plugin-updater": "^2.10.0",
"ant-design-vue": "^4.2.6",
"dayjs": "^1.11.19",
"pinia": "^3.0.4",
"vue": "^3.5.29"
},
"devDependencies": {
- "@tauri-apps/cli": "^2",
+ "@tauri-apps/cli": "^2.10.1",
"@vitejs/plugin-vue": "^6.0.4",
"typescript": "~5.9.3",
"vite": "^7.3.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1507a80..9c4a66d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -26,6 +26,12 @@ importers:
'@tauri-apps/plugin-opener':
specifier: ^2.5.3
version: 2.5.3
+ '@tauri-apps/plugin-process':
+ specifier: ^2.3.1
+ version: 2.3.1
+ '@tauri-apps/plugin-updater':
+ specifier: ^2.10.0
+ version: 2.10.0
ant-design-vue:
specifier: ^4.2.6
version: 4.2.6(vue@3.5.29(typescript@5.9.3))
@@ -40,8 +46,8 @@ importers:
version: 3.5.29(typescript@5.9.3)
devDependencies:
'@tauri-apps/cli':
- specifier: ^2
- version: 2.8.4
+ specifier: ^2.10.1
+ version: 2.10.1
'@vitejs/plugin-vue':
specifier: ^6.0.4
version: 6.0.4(vite@7.3.1)(vue@3.5.29(typescript@5.9.3))
@@ -388,79 +394,79 @@ packages:
'@tauri-apps/api@2.10.1':
resolution: {integrity: sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==}
- '@tauri-apps/cli-darwin-arm64@2.8.4':
- resolution: {integrity: sha512-BKu8HRkYV01SMTa7r4fLx+wjgtRK8Vep7lmBdHDioP6b8XH3q2KgsAyPWfEZaZIkZ2LY4SqqGARaE9oilNe0oA==}
+ '@tauri-apps/cli-darwin-arm64@2.10.1':
+ resolution: {integrity: sha512-Z2OjCXiZ+fbYZy7PmP3WRnOpM9+Fy+oonKDEmUE6MwN4IGaYqgceTjwHucc/kEEYZos5GICve35f7ZiizgqEnQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
- '@tauri-apps/cli-darwin-x64@2.8.4':
- resolution: {integrity: sha512-imb9PfSd/7G6VAO7v1bQ2A3ZH4NOCbhGJFLchxzepGcXf9NKkfun157JH9mko29K6sqAwuJ88qtzbKCbWJTH9g==}
+ '@tauri-apps/cli-darwin-x64@2.10.1':
+ resolution: {integrity: sha512-V/irQVvjPMGOTQqNj55PnQPVuH4VJP8vZCN7ajnj+ZS8Kom1tEM2hR3qbbIRoS3dBKs5mbG8yg1WC+97dq17Pw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
- '@tauri-apps/cli-linux-arm-gnueabihf@2.8.4':
- resolution: {integrity: sha512-Ml215UnDdl7/fpOrF1CNovym/KjtUbCuPgrcZ4IhqUCnhZdXuphud/JT3E8X97Y03TZ40Sjz8raXYI2ET0exzw==}
+ '@tauri-apps/cli-linux-arm-gnueabihf@2.10.1':
+ resolution: {integrity: sha512-Hyzwsb4VnCWKGfTw+wSt15Z2pLw2f0JdFBfq2vHBOBhvg7oi6uhKiF87hmbXOBXUZaGkyRDkCHsdzJcIfoJC2w==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
- '@tauri-apps/cli-linux-arm64-gnu@2.8.4':
- resolution: {integrity: sha512-pbcgBpMyI90C83CxE5REZ9ODyIlmmAPkkJXtV398X3SgZEIYy5TACYqlyyv2z5yKgD8F8WH4/2fek7+jH+ZXAw==}
+ '@tauri-apps/cli-linux-arm64-gnu@2.10.1':
+ resolution: {integrity: sha512-OyOYs2t5GkBIvyWjA1+h4CZxTcdz1OZPCWAPz5DYEfB0cnWHERTnQ/SLayQzncrT0kwRoSfSz9KxenkyJoTelA==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [glibc]
- '@tauri-apps/cli-linux-arm64-musl@2.8.4':
- resolution: {integrity: sha512-zumFeaU1Ws5Ay872FTyIm7z8kfzEHu8NcIn8M6TxbJs0a7GRV21KBdpW1zNj2qy7HynnpQCqjAYXTUUmm9JAOw==}
+ '@tauri-apps/cli-linux-arm64-musl@2.10.1':
+ resolution: {integrity: sha512-MIj78PDDGjkg3NqGptDOGgfXks7SYJwhiMh8SBoZS+vfdz7yP5jN18bNaLnDhsVIPARcAhE1TlsZe/8Yxo2zqg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [musl]
- '@tauri-apps/cli-linux-riscv64-gnu@2.8.4':
- resolution: {integrity: sha512-qiqbB3Zz6IyO201f+1ojxLj65WYj8mixL5cOMo63nlg8CIzsP23cPYUrx1YaDPsCLszKZo7tVs14pc7BWf+/aQ==}
+ '@tauri-apps/cli-linux-riscv64-gnu@2.10.1':
+ resolution: {integrity: sha512-X0lvOVUg8PCVaoEtEAnpxmnkwlE1gcMDTqfhbefICKDnOTJ5Est3qL0SrWxizDackIOKBcvtpejrSiVpuJI1kw==}
engines: {node: '>= 10'}
cpu: [riscv64]
os: [linux]
libc: [glibc]
- '@tauri-apps/cli-linux-x64-gnu@2.8.4':
- resolution: {integrity: sha512-TaqaDd9Oy6k45Hotx3pOf+pkbsxLaApv4rGd9mLuRM1k6YS/aw81YrsMryYPThrxrScEIUcmNIHaHsLiU4GMkw==}
+ '@tauri-apps/cli-linux-x64-gnu@2.10.1':
+ resolution: {integrity: sha512-2/12bEzsJS9fAKybxgicCDFxYD1WEI9kO+tlDwX5znWG2GwMBaiWcmhGlZ8fi+DMe9CXlcVarMTYc0L3REIRxw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [glibc]
- '@tauri-apps/cli-linux-x64-musl@2.8.4':
- resolution: {integrity: sha512-ot9STAwyezN8w+bBHZ+bqSQIJ0qPZFlz/AyscpGqB/JnJQVDFQcRDmUPFEaAtt2UUHSWzN3GoTJ5ypqLBp2WQA==}
+ '@tauri-apps/cli-linux-x64-musl@2.10.1':
+ resolution: {integrity: sha512-Y8J0ZzswPz50UcGOFuXGEMrxbjwKSPgXftx5qnkuMs2rmwQB5ssvLb6tn54wDSYxe7S6vlLob9vt0VKuNOaCIQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [musl]
- '@tauri-apps/cli-win32-arm64-msvc@2.8.4':
- resolution: {integrity: sha512-+2aJ/g90dhLiOLFSD1PbElXX3SoMdpO7HFPAZB+xot3CWlAZD1tReUFy7xe0L5GAR16ZmrxpIDM9v9gn5xRy/w==}
+ '@tauri-apps/cli-win32-arm64-msvc@2.10.1':
+ resolution: {integrity: sha512-iSt5B86jHYAPJa/IlYw++SXtFPGnWtFJriHn7X0NFBVunF6zu9+/zOn8OgqIWSl8RgzhLGXQEEtGBdR4wzpVgg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
- '@tauri-apps/cli-win32-ia32-msvc@2.8.4':
- resolution: {integrity: sha512-yj7WDxkL1t9Uzr2gufQ1Hl7hrHuFKTNEOyascbc109EoiAqCp0tgZ2IykQqOZmZOHU884UAWI1pVMqBhS/BfhA==}
+ '@tauri-apps/cli-win32-ia32-msvc@2.10.1':
+ resolution: {integrity: sha512-gXyxgEzsFegmnWywYU5pEBURkcFN/Oo45EAwvZrHMh+zUSEAvO5E8TXsgPADYm31d1u7OQU3O3HsYfVBf2moHw==}
engines: {node: '>= 10'}
cpu: [ia32]
os: [win32]
- '@tauri-apps/cli-win32-x64-msvc@2.8.4':
- resolution: {integrity: sha512-XuvGB4ehBdd7QhMZ9qbj/8icGEatDuBNxyYHbLKsTYh90ggUlPa/AtaqcC1Fo69lGkTmq9BOKrs1aWSi7xDonA==}
+ '@tauri-apps/cli-win32-x64-msvc@2.10.1':
+ resolution: {integrity: sha512-6Cn7YpPFwzChy0ERz6djKEmUehWrYlM+xTaNzGPgZocw3BD7OfwfWHKVWxXzdjEW2KfKkHddfdxK1XXTYqBRLg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
- '@tauri-apps/cli@2.8.4':
- resolution: {integrity: sha512-ejUZBzuQRcjFV+v/gdj/DcbyX/6T4unZQjMSBZwLzP/CymEjKcc2+Fc8xTORThebHDUvqoXMdsCZt8r+hyN15g==}
+ '@tauri-apps/cli@2.10.1':
+ resolution: {integrity: sha512-jQNGF/5quwORdZSSLtTluyKQ+o6SMa/AUICfhf4egCGFdMHqWssApVgYSbg+jmrZoc8e1DscNvjTnXtlHLS11g==}
engines: {node: '>= 10'}
hasBin: true
@@ -476,6 +482,12 @@ packages:
'@tauri-apps/plugin-opener@2.5.3':
resolution: {integrity: sha512-CCcUltXMOfUEArbf3db3kCE7Ggy1ExBEBl51Ko2ODJ6GDYHRp1nSNlQm5uNCFY5k7/ufaK5Ib3Du/Zir19IYQQ==}
+ '@tauri-apps/plugin-process@2.3.1':
+ resolution: {integrity: sha512-nCa4fGVaDL/B9ai03VyPOjfAHRHSBz5v6F/ObsB73r/dA3MHHhZtldaDMIc0V/pnUw9ehzr2iEG+XkSEyC0JJA==}
+
+ '@tauri-apps/plugin-updater@2.10.0':
+ resolution: {integrity: sha512-ljN8jPlnT0aSn8ecYhuBib84alxfMx6Hc8vJSKMJyzGbTPFZAC44T2I1QNFZssgWKrAlofvJqCC6Rr472JWfkQ==}
+
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
@@ -970,52 +982,52 @@ snapshots:
'@tauri-apps/api@2.10.1': {}
- '@tauri-apps/cli-darwin-arm64@2.8.4':
+ '@tauri-apps/cli-darwin-arm64@2.10.1':
optional: true
- '@tauri-apps/cli-darwin-x64@2.8.4':
+ '@tauri-apps/cli-darwin-x64@2.10.1':
optional: true
- '@tauri-apps/cli-linux-arm-gnueabihf@2.8.4':
+ '@tauri-apps/cli-linux-arm-gnueabihf@2.10.1':
optional: true
- '@tauri-apps/cli-linux-arm64-gnu@2.8.4':
+ '@tauri-apps/cli-linux-arm64-gnu@2.10.1':
optional: true
- '@tauri-apps/cli-linux-arm64-musl@2.8.4':
+ '@tauri-apps/cli-linux-arm64-musl@2.10.1':
optional: true
- '@tauri-apps/cli-linux-riscv64-gnu@2.8.4':
+ '@tauri-apps/cli-linux-riscv64-gnu@2.10.1':
optional: true
- '@tauri-apps/cli-linux-x64-gnu@2.8.4':
+ '@tauri-apps/cli-linux-x64-gnu@2.10.1':
optional: true
- '@tauri-apps/cli-linux-x64-musl@2.8.4':
+ '@tauri-apps/cli-linux-x64-musl@2.10.1':
optional: true
- '@tauri-apps/cli-win32-arm64-msvc@2.8.4':
+ '@tauri-apps/cli-win32-arm64-msvc@2.10.1':
optional: true
- '@tauri-apps/cli-win32-ia32-msvc@2.8.4':
+ '@tauri-apps/cli-win32-ia32-msvc@2.10.1':
optional: true
- '@tauri-apps/cli-win32-x64-msvc@2.8.4':
+ '@tauri-apps/cli-win32-x64-msvc@2.10.1':
optional: true
- '@tauri-apps/cli@2.8.4':
+ '@tauri-apps/cli@2.10.1':
optionalDependencies:
- '@tauri-apps/cli-darwin-arm64': 2.8.4
- '@tauri-apps/cli-darwin-x64': 2.8.4
- '@tauri-apps/cli-linux-arm-gnueabihf': 2.8.4
- '@tauri-apps/cli-linux-arm64-gnu': 2.8.4
- '@tauri-apps/cli-linux-arm64-musl': 2.8.4
- '@tauri-apps/cli-linux-riscv64-gnu': 2.8.4
- '@tauri-apps/cli-linux-x64-gnu': 2.8.4
- '@tauri-apps/cli-linux-x64-musl': 2.8.4
- '@tauri-apps/cli-win32-arm64-msvc': 2.8.4
- '@tauri-apps/cli-win32-ia32-msvc': 2.8.4
- '@tauri-apps/cli-win32-x64-msvc': 2.8.4
+ '@tauri-apps/cli-darwin-arm64': 2.10.1
+ '@tauri-apps/cli-darwin-x64': 2.10.1
+ '@tauri-apps/cli-linux-arm-gnueabihf': 2.10.1
+ '@tauri-apps/cli-linux-arm64-gnu': 2.10.1
+ '@tauri-apps/cli-linux-arm64-musl': 2.10.1
+ '@tauri-apps/cli-linux-riscv64-gnu': 2.10.1
+ '@tauri-apps/cli-linux-x64-gnu': 2.10.1
+ '@tauri-apps/cli-linux-x64-musl': 2.10.1
+ '@tauri-apps/cli-win32-arm64-msvc': 2.10.1
+ '@tauri-apps/cli-win32-ia32-msvc': 2.10.1
+ '@tauri-apps/cli-win32-x64-msvc': 2.10.1
'@tauri-apps/plugin-autostart@2.5.1':
dependencies:
@@ -1033,6 +1045,14 @@ snapshots:
dependencies:
'@tauri-apps/api': 2.10.1
+ '@tauri-apps/plugin-process@2.3.1':
+ dependencies:
+ '@tauri-apps/api': 2.10.1
+
+ '@tauri-apps/plugin-updater@2.10.0':
+ dependencies:
+ '@tauri-apps/api': 2.10.1
+
'@types/estree@1.0.8': {}
'@vitejs/plugin-vue@6.0.4(vite@7.3.1)(vue@3.5.29(typescript@5.9.3))':
diff --git a/scripts/build.mjs b/scripts/build.mjs
new file mode 100644
index 0000000..b22c860
--- /dev/null
+++ b/scripts/build.mjs
@@ -0,0 +1,24 @@
+#!/usr/bin/env node
+/**
+ * 构建脚本 - 自动加载项目内置签名密钥后执行 tauri build
+ */
+
+import { readFileSync } from "node:fs";
+import { resolve, dirname } from "node:path";
+import { execSync } from "node:child_process";
+import { fileURLToPath } from "node:url";
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+const root = resolve(__dirname, "..");
+const keyPath = resolve(root, ".tauri/signing-key");
+
+try {
+ process.env.TAURI_SIGNING_PRIVATE_KEY = readFileSync(keyPath, "utf-8").trim();
+ process.env.TAURI_SIGNING_PRIVATE_KEY_PASSWORD = "";
+} catch {
+ console.error(`错误: 未找到签名密钥 ${keyPath}`);
+ console.error("请运行: pnpm tauri signer generate -w .tauri/signing-key -p \"\" --ci");
+ process.exit(1);
+}
+
+execSync("pnpm tauri build", { stdio: "inherit", cwd: root });
diff --git a/scripts/bump-version.mjs b/scripts/bump-version.mjs
new file mode 100644
index 0000000..80b75ad
--- /dev/null
+++ b/scripts/bump-version.mjs
@@ -0,0 +1,103 @@
+/*
+ * @file /scripts/bump-version.mjs
+ * @description 统一更新 Tauri 项目版本号
+ * @author tsl (randy1924@163.com)
+ * @date 2026-03-23 10:23:42
+ * @lastModified 2026-03-23 10:25:08
+ * @lastModifiedBy tsl (randy1924@163.com)
+ * @example node scripts/bump-version.mjs [patch|minor|major|x.y.z]
+ * @default patch
+ */
+
+import { readFileSync, writeFileSync } from "node:fs";
+import { resolve, dirname } from "node:path";
+import { fileURLToPath } from "node:url";
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+const root = resolve(__dirname, "..");
+
+// 读取当前版本
+function getCurrentVersion() {
+ const pkg = JSON.parse(readFileSync(resolve(root, "package.json"), "utf-8"));
+ return pkg.version;
+}
+
+// 根据 bump 类型计算新版本
+function bumpVersion(current, type) {
+ const parts = current.replace(/-.*$/, "").split(".").map(Number);
+ switch (type) {
+ case "major":
+ return `${parts[0] + 1}.0.0`;
+ case "minor":
+ return `${parts[0]}.${parts[1] + 1}.0`;
+ case "patch":
+ return `${parts[0]}.${parts[1]}.${parts[2] + 1}`;
+ default:
+ return null;
+ }
+}
+
+const arg = process.argv[2] || "patch";
+const BUMP_TYPES = ["patch", "minor", "major"];
+const current = getCurrentVersion();
+let version;
+
+if (BUMP_TYPES.includes(arg)) {
+ version = bumpVersion(current, arg);
+} else if (/^\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?$/.test(arg)) {
+ version = arg;
+} else {
+ console.error(`错误: 无效参数 "${arg}",应为 patch / minor / major 或 x.y.z 格式`);
+ process.exit(1);
+}
+
+const files = [
+ {
+ path: "package.json",
+ update(content) {
+ const json = JSON.parse(content);
+ const old = json.version;
+ json.version = version;
+ return { result: JSON.stringify(json, null, 2) + "\n", old };
+ },
+ },
+ {
+ path: "src-tauri/tauri.conf.json",
+ update(content) {
+ const json = JSON.parse(content);
+ const old = json.version;
+ json.version = version;
+ return { result: JSON.stringify(json, null, 2) + "\n", old };
+ },
+ },
+ {
+ path: "src-tauri/Cargo.toml",
+ update(content) {
+ let old = "";
+ let replaced = false;
+ const result = content.replace(
+ /^version\s*=\s*"([^"]*)"/m,
+ (match, v) => {
+ if (replaced) return match;
+ replaced = true;
+ old = v;
+ return `version = "${version}"`;
+ }
+ );
+ return { result, old };
+ },
+ },
+];
+
+console.log(`\n${current} → ${version} (${BUMP_TYPES.includes(arg) ? arg : "指定版本"})\n`);
+
+for (const file of files) {
+ const filePath = resolve(root, file.path);
+ const content = readFileSync(filePath, "utf-8");
+ const { result, old } = file.update(content);
+ writeFileSync(filePath, result, "utf-8");
+ console.log(` ✔ ${file.path} ${old} → ${version}`);
+}
+
+console.log("\n全部更新完成!");
+console.log("提示: package-lock.json 和 Cargo.lock 会在下次 install/build 时自动同步\n");
diff --git a/scripts/publish.mjs b/scripts/publish.mjs
new file mode 100644
index 0000000..b3e203a
--- /dev/null
+++ b/scripts/publish.mjs
@@ -0,0 +1,120 @@
+#!/usr/bin/env node
+/**
+ * @file /scripts/publish.mjs
+ * @description 构建后生成 update.json 并上传到远程服务器
+ * @usage node scripts/publish.mjs [--notes "更新说明"]
+ *
+ * 前置条件:
+ * 1. 已运行 `pnpm run tauri-build` 生成构建产物
+ * 2. 远程服务器 SSH 可达(192.168.2.127:22)
+ */
+
+import { readFileSync, writeFileSync, readdirSync, existsSync } from "node:fs";
+import { resolve, dirname, basename } from "node:path";
+import { fileURLToPath } from "node:url";
+import { execSync } from "node:child_process";
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+const root = resolve(__dirname, "..");
+
+// ===== 配置 =====
+const REMOTE_USER = "root_test";
+const REMOTE_HOST = "192.168.2.127";
+const REMOTE_PORT = 22;
+const REMOTE_DIR = "/var/www/html/work-order-monitor";
+const BASE_URL = "http://web.nps.yunvip123.cn/work-order-monitor";
+
+// ===== 解析参数 =====
+const args = process.argv.slice(2);
+let notes = "";
+const notesIdx = args.indexOf("--notes");
+if (notesIdx !== -1 && args[notesIdx + 1]) {
+ notes = args[notesIdx + 1];
+}
+
+// ===== 读取版本号 =====
+const pkg = JSON.parse(readFileSync(resolve(root, "package.json"), "utf-8"));
+const version = pkg.version;
+
+// ===== 查找构建产物 =====
+const bundleDir = resolve(root, "src-tauri/target/release/bundle/nsis");
+
+if (!existsSync(bundleDir)) {
+ console.error(`错误: 未找到构建目录 ${bundleDir}`);
+ console.error("请先运行: pnpm run tauri-build");
+ process.exit(1);
+}
+
+const files = readdirSync(bundleDir);
+const setupFile = files.find((f) => f.includes(version) && f.endsWith("-setup.exe"));
+const sigFile = files.find((f) => f.includes(version) && f.endsWith("-setup.exe.sig"));
+
+if (!setupFile || !sigFile) {
+ console.error(`错误: 未找到版本 ${version} 的 -setup.exe 或 -setup.exe.sig 文件`);
+ console.error(`目录内容: ${files.join(", ")}`);
+ process.exit(1);
+}
+
+const setupPath = resolve(bundleDir, setupFile);
+const sigPath = resolve(bundleDir, sigFile);
+const signature = readFileSync(sigPath, "utf-8").trim();
+
+console.log(`\n版本: ${version}`);
+console.log(`安装包: ${setupFile}`);
+console.log(`签名文件: ${sigFile}`);
+console.log(`签名: ${signature.substring(0, 40)}...`);
+
+// ===== 生成 update.json =====
+const encodedFileName = encodeURIComponent(setupFile);
+const updateJson = {
+ version,
+ notes: notes || `v${version} 更新`,
+ pub_date: new Date().toISOString(),
+ platforms: {
+ "windows-x86_64": {
+ url: `${BASE_URL}/${encodedFileName}`,
+ signature,
+ },
+ },
+};
+
+const updateJsonPath = resolve(bundleDir, "update.json");
+writeFileSync(updateJsonPath, JSON.stringify(updateJson, null, 2), "utf-8");
+console.log(`\nupdate.json 已生成`);
+console.log(JSON.stringify(updateJson, null, 2));
+
+// ===== 上传到远程服务器 =====
+console.log(`\n正在上传到 ${REMOTE_HOST}:${REMOTE_DIR} ...`);
+
+try {
+ // 确保远程目录存在
+ execSync(
+ `ssh -p ${REMOTE_PORT} ${REMOTE_USER}@${REMOTE_HOST} "mkdir -p ${REMOTE_DIR}"`,
+ { stdio: "inherit" }
+ );
+
+ // 上传安装包
+ console.log(` 上传 ${setupFile} ...`);
+ execSync(
+ `scp -P ${REMOTE_PORT} "${setupPath}" ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DIR}/`,
+ { stdio: "inherit" }
+ );
+
+ // 上传 update.json
+ console.log(` 上传 update.json ...`);
+ execSync(
+ `scp -P ${REMOTE_PORT} "${updateJsonPath}" ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DIR}/`,
+ { stdio: "inherit" }
+ );
+
+ console.log("\n全部上传完成!");
+ console.log(`更新地址: ${BASE_URL}/update.json`);
+ console.log(`下载地址: ${BASE_URL}/${encodedFileName}\n`);
+} catch (e) {
+ console.error("\n上传失败:", e.message);
+ console.error("请检查 SSH 连接是否正常,或手动上传以下文件:");
+ console.error(` 1. ${setupPath}`);
+ console.error(` 2. ${updateJsonPath}`);
+ console.error(` → 目标: ${REMOTE_HOST}:${REMOTE_DIR}/`);
+ process.exit(1);
+}
diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock
index b98eb2c..3b2b9b5 100644
--- a/src-tauri/Cargo.lock
+++ b/src-tauri/Cargo.lock
@@ -47,6 +47,15 @@ version = "1.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
+[[package]]
+name = "arbitrary"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
+dependencies = [
+ "derive_arbitrary",
+]
+
[[package]]
name = "async-broadcast"
version = "0.7.2"
@@ -717,6 +726,17 @@ dependencies = [
"serde_core",
]
+[[package]]
+name = "derive_arbitrary"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
[[package]]
name = "derive_more"
version = "0.99.20"
@@ -1018,6 +1038,17 @@ dependencies = [
"rustc_version",
]
+[[package]]
+name = "filetime"
+version = "0.2.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "libredox",
+]
+
[[package]]
name = "find-msvc-tools"
version = "0.1.9"
@@ -2114,6 +2145,7 @@ checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
dependencies = [
"bitflags 2.11.0",
"libc",
+ "redox_syscall 0.7.3",
]
[[package]]
@@ -2225,6 +2257,12 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+[[package]]
+name = "minisign-verify"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22f9645cb765ea72b8111f36c522475d2daa0d22c957a9826437e97534bc4e9e"
+
[[package]]
name = "miniz_oxide"
version = "0.8.9"
@@ -2286,10 +2324,10 @@ dependencies = [
"libc",
"log",
"openssl",
- "openssl-probe",
+ "openssl-probe 0.1.6",
"openssl-sys",
"schannel",
- "security-framework",
+ "security-framework 2.11.1",
"security-framework-sys",
"tempfile",
]
@@ -2548,6 +2586,18 @@ dependencies = [
"objc2-core-foundation",
]
+[[package]]
+name = "objc2-osa-kit"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f112d1746737b0da274ef79a23aac283376f335f4095a083a267a082f21db0c0"
+dependencies = [
+ "bitflags 2.11.0",
+ "objc2",
+ "objc2-app-kit",
+ "objc2-foundation",
+]
+
[[package]]
name = "objc2-quartz-core"
version = "0.3.2"
@@ -2649,6 +2699,12 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
+[[package]]
+name = "openssl-probe"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
+
[[package]]
name = "openssl-sys"
version = "0.9.110"
@@ -2677,6 +2733,20 @@ dependencies = [
"pin-project-lite",
]
+[[package]]
+name = "osakit"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b"
+dependencies = [
+ "objc2",
+ "objc2-foundation",
+ "objc2-osa-kit",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.18",
+]
+
[[package]]
name = "pango"
version = "0.18.3"
@@ -2726,7 +2796,7 @@ checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
- "redox_syscall",
+ "redox_syscall 0.5.18",
"smallvec",
"windows-link 0.2.1",
]
@@ -3305,6 +3375,15 @@ dependencies = [
"bitflags 2.11.0",
]
+[[package]]
+name = "redox_syscall"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16"
+dependencies = [
+ "bitflags 2.11.0",
+]
+
[[package]]
name = "redox_users"
version = "0.4.6"
@@ -3436,15 +3515,20 @@ dependencies = [
"http-body",
"http-body-util",
"hyper",
+ "hyper-rustls",
"hyper-util",
"js-sys",
"log",
"percent-encoding",
"pin-project-lite",
+ "rustls",
+ "rustls-pki-types",
+ "rustls-platform-verifier",
"serde",
"serde_json",
"sync_wrapper",
"tokio",
+ "tokio-rustls",
"tokio-util",
"tower",
"tower-http",
@@ -3512,6 +3596,18 @@ dependencies = [
"zeroize",
]
+[[package]]
+name = "rustls-native-certs"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63"
+dependencies = [
+ "openssl-probe 0.2.1",
+ "rustls-pki-types",
+ "schannel",
+ "security-framework 3.5.1",
+]
+
[[package]]
name = "rustls-pki-types"
version = "1.14.0"
@@ -3522,6 +3618,33 @@ dependencies = [
"zeroize",
]
+[[package]]
+name = "rustls-platform-verifier"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784"
+dependencies = [
+ "core-foundation 0.10.1",
+ "core-foundation-sys",
+ "jni",
+ "log",
+ "once_cell",
+ "rustls",
+ "rustls-native-certs",
+ "rustls-platform-verifier-android",
+ "rustls-webpki",
+ "security-framework 3.5.1",
+ "security-framework-sys",
+ "webpki-root-certs",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "rustls-platform-verifier-android"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
+
[[package]]
name = "rustls-webpki"
version = "0.103.9"
@@ -3633,6 +3756,19 @@ dependencies = [
"security-framework-sys",
]
+[[package]]
+name = "security-framework"
+version = "3.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef"
+dependencies = [
+ "bitflags 2.11.0",
+ "core-foundation 0.10.1",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
[[package]]
name = "security-framework-sys"
version = "2.15.0"
@@ -3923,7 +4059,7 @@ dependencies = [
"objc2-foundation",
"objc2-quartz-core",
"raw-window-handle",
- "redox_syscall",
+ "redox_syscall 0.5.18",
"tracing",
"wasm-bindgen",
"web-sys",
@@ -4137,6 +4273,17 @@ dependencies = [
"syn 2.0.117",
]
+[[package]]
+name = "tar"
+version = "0.4.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973"
+dependencies = [
+ "filetime",
+ "libc",
+ "xattr",
+]
+
[[package]]
name = "target-lexicon"
version = "0.12.16"
@@ -4195,24 +4342,6 @@ dependencies = [
"windows 0.61.3",
]
-[[package]]
-name = "tauri-app"
-version = "0.1.2"
-dependencies = [
- "env_logger",
- "log",
- "serde",
- "serde_json",
- "tauri",
- "tauri-build",
- "tauri-plugin-autostart",
- "tauri-plugin-http",
- "tauri-plugin-notification",
- "tauri-plugin-opener",
- "tauri-plugin-store",
- "windows 0.58.0",
-]
-
[[package]]
name = "tauri-build"
version = "2.5.5"
@@ -4394,6 +4523,16 @@ dependencies = [
"zbus",
]
+[[package]]
+name = "tauri-plugin-process"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d55511a7bf6cd70c8767b02c97bf8134fa434daf3926cfc1be0a0f94132d165a"
+dependencies = [
+ "tauri",
+ "tauri-plugin",
+]
+
[[package]]
name = "tauri-plugin-store"
version = "2.4.2"
@@ -4410,6 +4549,39 @@ dependencies = [
"tracing",
]
+[[package]]
+name = "tauri-plugin-updater"
+version = "2.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fe8e9bebd88fc222938ffdfbdcfa0307081423bd01e3252fc337d8bde81fc61"
+dependencies = [
+ "base64 0.22.1",
+ "dirs 6.0.0",
+ "flate2",
+ "futures-util",
+ "http",
+ "infer",
+ "log",
+ "minisign-verify",
+ "osakit",
+ "percent-encoding",
+ "reqwest 0.13.2",
+ "rustls",
+ "semver",
+ "serde",
+ "serde_json",
+ "tar",
+ "tauri",
+ "tauri-plugin",
+ "tempfile",
+ "thiserror 2.0.18",
+ "time",
+ "tokio",
+ "url",
+ "windows-sys 0.60.2",
+ "zip",
+]
+
[[package]]
name = "tauri-runtime"
version = "2.10.0"
@@ -5305,6 +5477,15 @@ dependencies = [
"system-deps",
]
+[[package]]
+name = "webpki-root-certs"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca"
+dependencies = [
+ "rustls-pki-types",
+]
+
[[package]]
name = "webpki-roots"
version = "1.0.6"
@@ -5984,6 +6165,26 @@ dependencies = [
"wasmparser",
]
+[[package]]
+name = "work-order-monitor"
+version = "0.2.2"
+dependencies = [
+ "env_logger",
+ "log",
+ "serde",
+ "serde_json",
+ "tauri",
+ "tauri-build",
+ "tauri-plugin-autostart",
+ "tauri-plugin-http",
+ "tauri-plugin-notification",
+ "tauri-plugin-opener",
+ "tauri-plugin-process",
+ "tauri-plugin-store",
+ "tauri-plugin-updater",
+ "windows 0.58.0",
+]
+
[[package]]
name = "writeable"
version = "0.6.2"
@@ -6056,6 +6257,16 @@ dependencies = [
"pkg-config",
]
+[[package]]
+name = "xattr"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156"
+dependencies = [
+ "libc",
+ "rustix",
+]
+
[[package]]
name = "yoke"
version = "0.8.1"
@@ -6220,6 +6431,18 @@ dependencies = [
"syn 2.0.117",
]
+[[package]]
+name = "zip"
+version = "4.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1"
+dependencies = [
+ "arbitrary",
+ "crc32fast",
+ "indexmap 2.13.0",
+ "memchr",
+]
+
[[package]]
name = "zmij"
version = "1.0.21"
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index dabcc07..c9c15cd 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -1,6 +1,6 @@
[package]
-name = "tauri-app"
-version = "0.1.2"
+name = "work-order-monitor"
+version = "0.2.2"
description = "A Tauri App"
authors = ["you"]
edition = "2021"
@@ -11,7 +11,7 @@ edition = "2021"
# The `_lib` suffix may seem redundant but it is necessary
# to make the lib name unique and wouldn't conflict with the bin name.
# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
-name = "tauri_app_lib"
+name = "work_order_monitor_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
@@ -28,6 +28,8 @@ serde = { version = "1", features = ["derive"] }
serde_json = "1"
log = "0.4"
env_logger = "0.10"
+tauri-plugin-updater = "2.10.0"
+tauri-plugin-process = "2.3.1"
[target.'cfg(windows)'.dependencies]
windows = { version = "0.58", features = [
diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json
index f2f6d0a..badb8da 100644
--- a/src-tauri/capabilities/default.json
+++ b/src-tauri/capabilities/default.json
@@ -41,6 +41,8 @@
"core:window:allow-set-title",
"core:window:allow-unminimize",
"core:image:default",
- "core:image:allow-from-path"
+ "core:image:allow-from-path",
+ "updater:default",
+ "process:allow-restart"
]
}
diff --git a/src-tauri/gen/android/app/build.gradle.kts b/src-tauri/gen/android/app/build.gradle.kts
index 5a7b5af..ea0fad6 100644
--- a/src-tauri/gen/android/app/build.gradle.kts
+++ b/src-tauri/gen/android/app/build.gradle.kts
@@ -15,10 +15,10 @@ val tauriProperties = Properties().apply {
android {
compileSdk = 36
- namespace = "com.administrator.tauri_app"
+ namespace = "com.yunpu.workordermonitor"
defaultConfig {
manifestPlaceholders["usesCleartextTraffic"] = "false"
- applicationId = "com.administrator.tauri_app"
+ applicationId = "com.yunpu.workordermonitor"
minSdk = 24
targetSdk = 36
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
diff --git a/src-tauri/gen/android/app/src/main/java/com/administrator/tauri_app/MainActivity.kt b/src-tauri/gen/android/app/src/main/java/com/yunpu/workordermonitor/MainActivity.kt
similarity index 83%
rename from src-tauri/gen/android/app/src/main/java/com/administrator/tauri_app/MainActivity.kt
rename to src-tauri/gen/android/app/src/main/java/com/yunpu/workordermonitor/MainActivity.kt
index d0288d2..da256db 100644
--- a/src-tauri/gen/android/app/src/main/java/com/administrator/tauri_app/MainActivity.kt
+++ b/src-tauri/gen/android/app/src/main/java/com/yunpu/workordermonitor/MainActivity.kt
@@ -1,4 +1,4 @@
-package com.administrator.tauri_app
+package com.yunpu.workordermonitor
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
diff --git a/src-tauri/gen/android/app/src/main/res/values/strings.xml b/src-tauri/gen/android/app/src/main/res/values/strings.xml
index b0037cb..29e5978 100644
--- a/src-tauri/gen/android/app/src/main/res/values/strings.xml
+++ b/src-tauri/gen/android/app/src/main/res/values/strings.xml
@@ -1,4 +1,4 @@
- tauri-app
- tauri-app
+ work-order-monitor
+ work-order-monitor
\ No newline at end of file
diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs
index 5e87bd6..7df0fe2 100644
--- a/src-tauri/src/lib.rs
+++ b/src-tauri/src/lib.rs
@@ -91,6 +91,8 @@ pub fn run() {
MacosLauncher::LaunchAgent,
Some(vec![]),
))
+ .plugin(tauri_plugin_updater::Builder::new().build())
+ .plugin(tauri_plugin_process::init())
.setup(|app| {
start_notification_callback_server(app.handle().clone());
Ok(())
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
index 4a9b77a..b7d9dd2 100644
--- a/src-tauri/src/main.rs
+++ b/src-tauri/src/main.rs
@@ -2,5 +2,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
- tauri_app_lib::run()
+ work_order_monitor_lib::run()
}
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index 2b1608f..43ca691 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -1,8 +1,8 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "工单系统监测",
- "version": "0.1.3",
- "identifier": "com.administrator.tauri-app",
+ "version": "0.2.2",
+ "identifier": "com.yunpu.workordermonitor",
"build": {
"beforeDevCommand": "pnpm dev",
"devUrl": "http://localhost:1420",
@@ -23,7 +23,10 @@
},
"bundle": {
"active": true,
- "targets": ["nsis"],
+ "targets": [
+ "nsis"
+ ],
+ "createUpdaterArtifacts": true,
"icon": [
"icons/32x32.png",
"icons/128x128.png",
@@ -35,5 +38,17 @@
"icons/32x32.png",
"icons/icon.ico"
]
+ },
+ "plugins": {
+ "updater": {
+ "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDY0Q0YxMzNBM0Q5OEU4NEMKUldSTTZKZzlPaFBQWkVXRVdBVHdTdlNvVnZSL2FFQkZtbFpRTzdjNGxHbjJsZ1R5MFRLdkpmYzMK",
+ "endpoints": [
+ "http://web.nps.yunvip123.cn/work-order-monitor/update.json"
+ ],
+ "dangerousInsecureTransportProtocol": true,
+ "windows": {
+ "installMode": "passive"
+ }
+ }
}
}
diff --git a/src/App.vue b/src/App.vue
index e7e3cc9..e466a9a 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -15,6 +15,7 @@ import SettingsPanel from "./components/SettingsPanel.vue";
import LogViewer from "./components/LogViewer.vue";
import AppStatusBar, { type StatusBarItem } from "./components/AppStatusBar.vue";
import CloseDialog from "./components/CloseDialog.vue";
+import UpdateDialog from "./components/UpdateDialog.vue";
import { useMonitorStore } from "./stores/monitor";
const activeTab = ref("monitor");
@@ -81,6 +82,7 @@ onUnmounted(() => store.cleanup());
+
diff --git a/src/stores/monitor.ts b/src/stores/monitor.ts
index 3ece053..7bee5dd 100644
--- a/src/stores/monitor.ts
+++ b/src/stores/monitor.ts
@@ -18,6 +18,8 @@ import {
import { invoke } from "@tauri-apps/api/core";
import { listen, type UnlistenFn } from "@tauri-apps/api/event";
import { openUrl } from "@tauri-apps/plugin-opener";
+import { check, type Update } from "@tauri-apps/plugin-updater";
+import { relaunch } from "@tauri-apps/plugin-process";
export const APP_NAME = "工单系统监测";
const API_BASE = "https://crm.yunvip123.com/api";
@@ -76,6 +78,10 @@ export const useMonitorStore = defineStore("monitor", () => {
});
const showCloseDialog = ref(false);
const postponeResumeTime = ref(null);
+ const showUpdateDialog = ref(false);
+ const updateInfo = ref<{ version: string; notes: string; date: string } | null>(null);
+ const updateProgress = ref<{ total: number; downloaded: number } | null>(null);
+ const isUpdating = ref(false);
// ===== 内部状态 =====
let sessionId = "";
@@ -85,7 +91,9 @@ export const useMonitorStore = defineStore("monitor", () => {
let postponeTimer: ReturnType | null = null;
let unlistenNotification: UnlistenFn | null = null;
let unlistenClose: UnlistenFn | null = null;
+ let pendingUpdate: Update | null = null;
let trayIconInstance: TrayIcon | null = null;
+ let cachedSvgImg: HTMLImageElement | null = null;
// ===== 工具函数 =====
function formatTime(date: Date): string {
@@ -541,6 +549,60 @@ export const useMonitorStore = defineStore("monitor", () => {
}
// ===== 配置更新 =====
+
+ async function checkForUpdates() {
+ try {
+ addLog("INFO", "正在检查应用更新...", "UPDATER");
+ const update = await check();
+ if (update) {
+ pendingUpdate = update;
+ updateInfo.value = {
+ version: update.version,
+ notes: update.body || "",
+ date: update.date || "",
+ };
+ showUpdateDialog.value = true;
+ addLog("INFO", `发现新版本: ${update.version}`, "UPDATER");
+ } else {
+ addLog("INFO", "当前已是最新版本", "UPDATER");
+ }
+ } catch (e: any) {
+ addLog("WARN", `检查更新失败: ${e.message || e}`, "UPDATER");
+ }
+ }
+
+ async function confirmUpdate() {
+ if (!pendingUpdate) return;
+ isUpdating.value = true;
+ updateProgress.value = { total: 0, downloaded: 0 };
+ try {
+ addLog("INFO", "开始下载更新...", "UPDATER");
+ await pendingUpdate.downloadAndInstall((event) => {
+ if (event.event === "Started" && event.data.contentLength) {
+ updateProgress.value = { total: event.data.contentLength, downloaded: 0 };
+ } else if (event.event === "Progress") {
+ if (updateProgress.value) {
+ updateProgress.value.downloaded += event.data.chunkLength;
+ }
+ } else if (event.event === "Finished") {
+ addLog("INFO", "更新下载完成,即将重启...", "UPDATER");
+ }
+ });
+ await relaunch();
+ } catch (e: any) {
+ addLog("ERROR", `更新安装失败: ${e.message || e}`, "UPDATER");
+ message.value = "更新安装失败";
+ isUpdating.value = false;
+ updateProgress.value = null;
+ }
+ }
+
+ function dismissUpdate() {
+ showUpdateDialog.value = false;
+ pendingUpdate = null;
+ updateInfo.value = null;
+ }
+
async function updateConfig() {
isLoading.value = true;
try {
@@ -563,29 +625,59 @@ export const useMonitorStore = defineStore("monitor", () => {
// ===== 系统托盘 =====
- /** 用 Canvas 渲染彩色圆形背景 + 白色"工"字,返回 RGBA 像素数据 */
- function makeTrayIconRGBA(r: number, g: number, b: number, size = 32): Uint8Array {
+ /** 加载 SVG 图片(带缓存) */
+ async function loadSvgImage(): Promise {
+ if (cachedSvgImg) return cachedSvgImg;
+ return new Promise((resolve, reject) => {
+ const img = new window.Image();
+ img.onload = () => { cachedSvgImg = img; resolve(img); };
+ img.onerror = reject;
+ img.src = "/gong.svg";
+ });
+ }
+
+ /** 加载 SVG → Canvas 渲染 → 像素替色 → 返回 RGBA 数据 */
+ async function makeTrayIconRGBA(r: number, g: number, b: number, size = 32): Promise {
const canvas = document.createElement("canvas");
canvas.width = size;
canvas.height = size;
const ctx = canvas.getContext("2d")!;
- // 圆形背景
- ctx.clearRect(0, 0, size, size);
- ctx.beginPath();
- ctx.arc(size / 2, size / 2, size / 2 - 1, 0, Math.PI * 2);
- ctx.fillStyle = `rgb(${r},${g},${b})`;
- ctx.fill();
+ try {
+ const svgImg = await loadSvgImage();
- // 白色"工"字
- ctx.fillStyle = "#ffffff";
- ctx.font = `bold ${Math.round(size * 0.62)}px "Microsoft YaHei","SimHei",sans-serif`;
- ctx.textAlign = "center";
- ctx.textBaseline = "middle";
- ctx.fillText("工", size / 2, size / 2 + 1);
+ ctx.drawImage(svgImg, 0, 0, size, size);
+ const imageData = ctx.getImageData(0, 0, size, size);
+ const data = imageData.data;
- const imageData = ctx.getImageData(0, 0, size, size);
- return new Uint8Array(imageData.data.buffer);
+ for (let i = 0; i < data.length; i += 4) {
+ // 根据亮度判断:暗像素(文字) → 白色,亮像素(背景) → 状态色
+ const brightness = (data[i] * 0.299 + data[i + 1] * 0.587 + data[i + 2] * 0.114);
+ if (brightness < 128) {
+ data[i] = data[i + 1] = data[i + 2] = 255;
+ } else {
+ data[i] = r;
+ data[i + 1] = g;
+ data[i + 2] = b;
+ }
+ data[i + 3] = 255;
+ }
+
+ ctx.putImageData(imageData, 0, 0);
+ } catch {
+ // SVG 加载失败,回退到纯 Canvas 绘制
+ addLog("WARN", "SVG 图标加载失败,使用回退方案", "SYSTEM");
+ ctx.fillStyle = `rgb(${r},${g},${b})`;
+ ctx.fillRect(0, 0, size, size);
+ ctx.fillStyle = "#ffffff";
+ ctx.font = `bold ${Math.round(size * 0.62)}px "Microsoft YaHei","SimHei",sans-serif`;
+ ctx.textAlign = "center";
+ ctx.textBaseline = "middle";
+ ctx.fillText("工", size / 2, size / 2 + 1);
+ }
+
+ const finalData = ctx.getImageData(0, 0, size, size);
+ return new Uint8Array(finalData.data.buffer);
}
/** 根据当前应用状态更新托盘图标和提示文字 */
@@ -620,7 +712,7 @@ export const useMonitorStore = defineStore("monitor", () => {
tooltip = `${APP_NAME} - 监测中`;
}
- const icon = await Image.new(makeTrayIconRGBA(...color), 32, 32);
+ const icon = await Image.new(await makeTrayIconRGBA(...color), 32, 32);
await trayIconInstance.setIcon(icon);
await trayIconInstance.setTooltip(tooltip);
} catch (e: any) {
@@ -686,7 +778,7 @@ export const useMonitorStore = defineStore("monitor", () => {
const menu = await buildTrayMenu();
// 初始状态:灰色(未开始)
- const icon = await Image.new(makeTrayIconRGBA(158, 158, 158), 32, 32);
+ const icon = await Image.new(await makeTrayIconRGBA(158, 158, 158), 32, 32);
trayIconInstance = await TrayIcon.new({
icon,
@@ -763,6 +855,7 @@ export const useMonitorStore = defineStore("monitor", () => {
}
checkNetworkStatus();
+ checkForUpdates();
if (config.value.auto_monitor && rememberPassword.value) {
const canAutoStart = loginMode.value === "token"
@@ -795,12 +888,14 @@ export const useMonitorStore = defineStore("monitor", () => {
isLoggedIn, isMonitoring, isPostponed, postponeResumeTime, autoStartEnabled,
logs, networkStatus, config, ticketCounts,
showCloseDialog,
+ showUpdateDialog, updateInfo, updateProgress, isUpdating,
// 方法
initialize, cleanup,
addLog, clearLogs, clearMessage, saveSettings, exportLogs,
startMonitoring, stopMonitoring, resumeMonitoring, manualCheck,
testNotification, checkNetworkStatus, updateConfig,
minimizeToTray, handleCloseAction,
+ checkForUpdates, confirmUpdate, dismissUpdate,
};
});