refactor(monitor): ♻️ 优化代码
This commit is contained in:
parent
0b2c1ca83f
commit
cc30c088c4
|
|
@ -2,9 +2,9 @@
|
||||||
"permissions": {
|
"permissions": {
|
||||||
"defaultMode": "acceptEdits",
|
"defaultMode": "acceptEdits",
|
||||||
"allow": [
|
"allow": [
|
||||||
"Read(./)",
|
"Read",
|
||||||
"Edit(./)",
|
"Edit",
|
||||||
"Write(./)",
|
"Write",
|
||||||
|
|
||||||
"Bash(pnpm build *)",
|
"Bash(pnpm build *)",
|
||||||
"Bash(pnpm install:*)",
|
"Bash(pnpm install:*)",
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
"version:major": "node scripts/bump-version.mjs major",
|
"version:major": "node scripts/bump-version.mjs major",
|
||||||
"publish": "node scripts/publish.mjs",
|
"publish": "node scripts/publish.mjs",
|
||||||
"deploy": "npm run tauri-build && npm run publish",
|
"deploy": "npm run tauri-build && npm run publish",
|
||||||
|
"type-check": "vue-tsc --noEmit",
|
||||||
"lint": "eslint src",
|
"lint": "eslint src",
|
||||||
"lint:fix": "eslint src --fix",
|
"lint:fix": "eslint src --fix",
|
||||||
"commit": "git-cz",
|
"commit": "git-cz",
|
||||||
|
|
|
||||||
|
|
@ -14,17 +14,17 @@ import MonitorControl from "@/components/MonitorControl.vue";
|
||||||
import SettingsPanel from "@/components/SettingsPanel.vue";
|
import SettingsPanel from "@/components/SettingsPanel.vue";
|
||||||
import StatusHeader from "@/components/StatusHeader.vue";
|
import StatusHeader from "@/components/StatusHeader.vue";
|
||||||
import UpdateDialog from "@/components/UpdateDialog.vue";
|
import UpdateDialog from "@/components/UpdateDialog.vue";
|
||||||
import { useUpdater } from "@/composables/useUpdater";
|
|
||||||
import { useAppStore } from "@/stores/app";
|
import { useAppStore } from "@/stores/app";
|
||||||
import { useLogStore } from "@/stores/log";
|
import { useLogStore } from "@/stores/log";
|
||||||
import { useMonitorStore } from "@/stores/monitor";
|
import { useMonitorStore } from "@/stores/monitor";
|
||||||
import { useNetworkStore } from "@/stores/network";
|
import { useNetworkStore } from "@/stores/network";
|
||||||
|
import { useUpdaterStore } from "@/stores/updater";
|
||||||
|
|
||||||
const activeTab = ref("monitor");
|
const activeTab = ref("monitor");
|
||||||
const store = useMonitorStore();
|
const store = useMonitorStore();
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const logStore = useLogStore();
|
const logStore = useLogStore();
|
||||||
const updater = useUpdater();
|
const updater = useUpdaterStore();
|
||||||
const networkStore = useNetworkStore();
|
const networkStore = useNetworkStore();
|
||||||
|
|
||||||
/** 通知动作事件的取消监听函数 */
|
/** 通知动作事件的取消监听函数 */
|
||||||
|
|
@ -88,7 +88,7 @@ onMounted(async () => {
|
||||||
|
|
||||||
getVersion()
|
getVersion()
|
||||||
.then((v) => {
|
.then((v) => {
|
||||||
updater.currentVersion.value = v;
|
updater.currentVersion = v;
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@ import { CloudSyncOutlined } from "@ant-design/icons-vue";
|
||||||
import dayjs, { type Dayjs } from "dayjs";
|
import dayjs, { type Dayjs } from "dayjs";
|
||||||
import { debounce } from "lodash-es";
|
import { debounce } from "lodash-es";
|
||||||
import { computed, watch } from "vue";
|
import { computed, watch } from "vue";
|
||||||
import { useUpdater } from "@/composables/useUpdater";
|
|
||||||
import { useAppStore } from "@/stores/app";
|
import { useAppStore } from "@/stores/app";
|
||||||
|
import { useUpdaterStore } from "@/stores/updater";
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const { currentVersion, isCheckingUpdates, isUpdating, checkForUpdates } = useUpdater();
|
const { currentVersion, isCheckingUpdates, isUpdating, checkForUpdates } = useUpdaterStore();
|
||||||
|
|
||||||
// ===== 检查间隔:内部用秒,TimePicker 用 Dayjs =====
|
// ===== 检查间隔:内部用秒,TimePicker 用 Dayjs =====
|
||||||
const intervalTime = computed<Dayjs>({
|
const intervalTime = computed<Dayjs>({
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,28 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { storeToRefs } from "pinia";
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import { useUpdater } from "@/composables/useUpdater";
|
import { useUpdaterStore } from "@/stores/updater";
|
||||||
|
|
||||||
const { showUpdateDialog, updateInfo, updateProgress, isUpdating, confirmUpdate, dismissUpdate } = useUpdater();
|
const store = useUpdaterStore();
|
||||||
|
const { showUpdateDialog, updateInfo, updateProgress, isUpdating } = storeToRefs(store);
|
||||||
|
const { confirmUpdate, dismissUpdate } = store;
|
||||||
|
|
||||||
const progressPercent = computed(() => {
|
const progressPercent = computed(() => {
|
||||||
if (!updateProgress.value || !updateProgress.value.total) return 0;
|
const progress = updateProgress.value;
|
||||||
return Math.round((updateProgress.value.downloaded / updateProgress.value.total) * 100);
|
if (!progress || !progress.total) return 0;
|
||||||
|
return Math.round((progress.downloaded / progress.total) * 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
const downloadedMB = computed(() => {
|
const downloadedMB = computed(() => {
|
||||||
if (!updateProgress.value) return "0";
|
const progress = updateProgress.value;
|
||||||
return (updateProgress.value.downloaded / 1024 / 1024).toFixed(1);
|
if (!progress) return "0";
|
||||||
|
return (progress.downloaded / 1024 / 1024).toFixed(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
const totalMB = computed(() => {
|
const totalMB = computed(() => {
|
||||||
if (!updateProgress.value || !updateProgress.value.total) return "0";
|
const progress = updateProgress.value;
|
||||||
return (updateProgress.value.total / 1024 / 1024).toFixed(1);
|
if (!progress || !progress.total) return "0";
|
||||||
|
return (progress.total / 1024 / 1024).toFixed(1);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import {
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import { useAppStore } from "@/stores/app";
|
import { useAppStore } from "@/stores/app";
|
||||||
import { useLogStore } from "@/stores/log";
|
import { useLogStore } from "@/stores/log";
|
||||||
|
import { getErrorMessage } from "@/utils/common";
|
||||||
|
|
||||||
/** 通知 Composable */
|
/** 通知 Composable */
|
||||||
export function useNotification() {
|
export function useNotification() {
|
||||||
|
|
@ -44,8 +45,8 @@ export function useNotification() {
|
||||||
await invoke("send_clickable_notification", { title, body });
|
await invoke("send_clickable_notification", { title, body });
|
||||||
playNotificationSound();
|
playNotificationSound();
|
||||||
addLog("INFO", `通知: ${title} - ${body}`, "NOTIFICATION");
|
addLog("INFO", `通知: ${title} - ${body}`, "NOTIFICATION");
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
addLog("ERROR", `发送通知失败: ${e}`, "NOTIFICATION");
|
addLog("ERROR", `发送通知失败: ${getErrorMessage(e)}`, "NOTIFICATION");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import { type Ref } from "vue";
|
||||||
import { CRM_URL } from "@/constants/app";
|
import { CRM_URL } from "@/constants/app";
|
||||||
import { useLogStore } from "@/stores/log";
|
import { useLogStore } from "@/stores/log";
|
||||||
import { type TicketCounts } from "@/stores/monitor";
|
import { type TicketCounts } from "@/stores/monitor";
|
||||||
|
import { getErrorMessage } from "@/utils/common";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param isMonitoring 是否正在监测
|
* @param isMonitoring 是否正在监测
|
||||||
|
|
@ -161,8 +162,8 @@ export function useTray(
|
||||||
const icon = await Image.new(await makeTrayIconRGBA(...color), 32, 32);
|
const icon = await Image.new(await makeTrayIconRGBA(...color), 32, 32);
|
||||||
await trayIconInstance.setIcon(icon);
|
await trayIconInstance.setIcon(icon);
|
||||||
await trayIconInstance.setTooltip(tooltip);
|
await trayIconInstance.setTooltip(tooltip);
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
addLog("WARN", `更新托盘图标失败: ${e.message || e}`, "SYSTEM");
|
addLog("WARN", `更新托盘图标失败: ${getErrorMessage(e)}`, "SYSTEM");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -228,8 +229,8 @@ export function useTray(
|
||||||
try {
|
try {
|
||||||
const menu = await buildTrayMenu();
|
const menu = await buildTrayMenu();
|
||||||
await trayIconInstance.setMenu(menu);
|
await trayIconInstance.setMenu(menu);
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
addLog("WARN", `更新托盘菜单失败: ${e.message || e}`, "SYSTEM");
|
addLog("WARN", `更新托盘菜单失败: ${getErrorMessage(e)}`, "SYSTEM");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -264,8 +265,8 @@ export function useTray(
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
addLog("INFO", "系统托盘创建成功", "SYSTEM");
|
addLog("INFO", "系统托盘创建成功", "SYSTEM");
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
addLog("ERROR", `系统托盘创建失败: ${e.message || e}`, "SYSTEM");
|
addLog("ERROR", `系统托盘创建失败: ${getErrorMessage(e)}`, "SYSTEM");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import {
|
||||||
import { defineStore, acceptHMRUpdate } from "pinia";
|
import { defineStore, acceptHMRUpdate } from "pinia";
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useLogStore } from "@/stores/log";
|
import { useLogStore } from "@/stores/log";
|
||||||
|
import { getErrorMessage } from "@/utils/common";
|
||||||
|
|
||||||
export const useAppStore = defineStore("app", () => {
|
export const useAppStore = defineStore("app", () => {
|
||||||
const message = ref(""); // 界面状态提示消息
|
const message = ref(""); // 界面状态提示消息
|
||||||
|
|
@ -45,8 +46,8 @@ export const useAppStore = defineStore("app", () => {
|
||||||
config.value = { ...config.value, ...data };
|
config.value = { ...config.value, ...data };
|
||||||
addLog("INFO", "已加载保存的配置", "CONFIG");
|
addLog("INFO", "已加载保存的配置", "CONFIG");
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
addLog("ERROR", `加载配置失败: ${e.message || e}`, "CONFIG");
|
addLog("ERROR", `加载配置失败: ${getErrorMessage(e)}`, "CONFIG");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,8 +72,8 @@ export const useAppStore = defineStore("app", () => {
|
||||||
`自启动设置: ${config.value.auto_start ? "启用" : "禁用"}`,
|
`自启动设置: ${config.value.auto_start ? "启用" : "禁用"}`,
|
||||||
"CONFIG",
|
"CONFIG",
|
||||||
);
|
);
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
addLog("ERROR", `自启动设置失败: ${e.message || e}`, "CONFIG");
|
addLog("ERROR", `自启动设置失败: ${getErrorMessage(e)}`, "CONFIG");
|
||||||
}
|
}
|
||||||
saveConfigToStorage();
|
saveConfigToStorage();
|
||||||
setMessage("配置更新成功");
|
setMessage("配置更新成功");
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { useTray } from "@/composables/useTray";
|
||||||
import { LOGIN_URL, CHECK_URL, WORK_ORDER_URL } from "@/constants/api";
|
import { LOGIN_URL, CHECK_URL, WORK_ORDER_URL } from "@/constants/api";
|
||||||
import { useAppStore } from "@/stores/app";
|
import { useAppStore } from "@/stores/app";
|
||||||
import { useLogStore } from "@/stores/log";
|
import { useLogStore } from "@/stores/log";
|
||||||
import { formatTime } from "@/utils/common";
|
import { formatTime, getErrorMessage } from "@/utils/common";
|
||||||
|
|
||||||
export interface TicketCounts {
|
export interface TicketCounts {
|
||||||
pending: number;
|
pending: number;
|
||||||
|
|
@ -73,7 +73,7 @@ export const useMonitorStore = defineStore("monitor", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const setCookie = resp.headers.get("set-cookie") || "";
|
const setCookie = resp.headers.get("set-cookie") || "";
|
||||||
const match = setCookie.match(/ASP\.NET_SessionId=([^;]+)/);
|
const match = /ASP\.NET_SessionId=([^;]+)/.exec(setCookie);
|
||||||
if (match) sessionId = match[1];
|
if (match) sessionId = match[1];
|
||||||
addLog("DEBUG", `SessionId: ${sessionId || "(未提取)"}`, "LOGIN");
|
addLog("DEBUG", `SessionId: ${sessionId || "(未提取)"}`, "LOGIN");
|
||||||
|
|
||||||
|
|
@ -91,8 +91,8 @@ export const useMonitorStore = defineStore("monitor", () => {
|
||||||
addLog("ERROR", `登录失败: ${data.msg}`, "LOGIN");
|
addLog("ERROR", `登录失败: ${data.msg}`, "LOGIN");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
addLog("ERROR", `登录请求失败: ${e.message || e}`, "LOGIN");
|
addLog("ERROR", `登录请求失败: ${getErrorMessage(e)}`, "LOGIN");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -123,20 +123,18 @@ export const useMonitorStore = defineStore("monitor", () => {
|
||||||
addLog("WARN", `待审核 API 返回异常: ${result.msg}`, "SCHEDULER");
|
addLog("WARN", `待审核 API 返回异常: ${result.msg}`, "SCHEDULER");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
addLog("ERROR", `待审核 API 检查失败: ${e.message || e}`, "SCHEDULER");
|
addLog(
|
||||||
|
"ERROR",
|
||||||
|
`待审核 API 检查失败: ${getErrorMessage(e)}`,
|
||||||
|
"SCHEDULER",
|
||||||
|
);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 拉取工单状态计数,触发通知;isRetry=true 时不再递归重登 */
|
/** 发送工单状态检查请求 */
|
||||||
async function apiCheckStatus(isRetry = false): Promise<void> {
|
async function performStatusCheckRequest() {
|
||||||
if (!userGid && loginMode.value === "password") {
|
|
||||||
addLog("WARN", "会话已失效,尝试重新登录", "SCHEDULER");
|
|
||||||
if (!isRetry) await tryReLogin();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const body: Record<string, string> = {};
|
const body: Record<string, string> = {};
|
||||||
if (userGid) body.UserGID = userGid;
|
if (userGid) body.UserGID = userGid;
|
||||||
const resp = await fetch(CHECK_URL, {
|
const resp = await fetch(CHECK_URL, {
|
||||||
|
|
@ -147,41 +145,72 @@ export const useMonitorStore = defineStore("monitor", () => {
|
||||||
},
|
},
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
});
|
});
|
||||||
const result = await resp.json();
|
return await resp.json();
|
||||||
if (result.success && result.data) {
|
}
|
||||||
const d = result.data;
|
|
||||||
const pending = d.PendingCount || 0;
|
/** 处理检查到的工单数据并更新状态 */
|
||||||
const stayclose = d.StaycloseCount || 0;
|
async function updateTicketCountsAndLog(data: any) {
|
||||||
const confirm = d.ConfirmCount || 0;
|
const pending = data.PendingCount || 0;
|
||||||
|
const stayclose = data.StaycloseCount || 0;
|
||||||
|
const confirm = data.ConfirmCount || 0;
|
||||||
const workOrderCount = await apiCheckWorkOrders();
|
const workOrderCount = await apiCheckWorkOrders();
|
||||||
ticketCounts.value = {
|
|
||||||
|
const counts = {
|
||||||
pending,
|
pending,
|
||||||
stayclose,
|
stayclose,
|
||||||
confirm,
|
confirm,
|
||||||
workOrderCount,
|
workOrderCount,
|
||||||
lastCheck: formatTime(new Date()),
|
lastCheck: formatTime(new Date()),
|
||||||
};
|
};
|
||||||
|
ticketCounts.value = counts;
|
||||||
|
|
||||||
addLog(
|
addLog(
|
||||||
"INFO",
|
"INFO",
|
||||||
`检查完成 - 待处理: ${pending}, 待关闭: ${stayclose}, 待确认: ${confirm}, 待审核: ${workOrderCount}`,
|
`检查完成 - 待处理: ${pending}, 待关闭: ${stayclose}, 待确认: ${confirm}, 待审核: ${workOrderCount}`,
|
||||||
"SCHEDULER",
|
"SCHEDULER",
|
||||||
);
|
);
|
||||||
if (pending > 0 || stayclose > 0 || confirm > 0 || workOrderCount > 0) {
|
return counts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 发送工单提醒通知 */
|
||||||
|
async function sendTicketNotifications(counts: TicketCounts) {
|
||||||
const msgs: string[] = [];
|
const msgs: string[] = [];
|
||||||
if (pending > 0) msgs.push(`待处理工单: ${pending}`);
|
if (counts.pending > 0) msgs.push(`待处理工单: ${counts.pending}`);
|
||||||
if (stayclose > 0) msgs.push(`待关闭工单: ${stayclose}`);
|
if (counts.stayclose > 0) msgs.push(`待关闭工单: ${counts.stayclose}`);
|
||||||
if (confirm > 0) msgs.push(`待确认工单: ${confirm}`);
|
if (counts.confirm > 0) msgs.push(`待确认工单: ${counts.confirm}`);
|
||||||
if (workOrderCount > 0) msgs.push(`待审核: ${workOrderCount}`);
|
if (counts.workOrderCount > 0)
|
||||||
|
msgs.push(`待审核: ${counts.workOrderCount}`);
|
||||||
|
|
||||||
|
if (msgs.length > 0) {
|
||||||
await notify("工单提醒", msgs.join(","));
|
await notify("工单提醒", msgs.join(","));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 拉取工单状态计数,触发通知;isRetry=true 时不再递归重登 */
|
||||||
|
async function apiCheckStatus(isRetry = false): Promise<void> {
|
||||||
|
// 1. 预检查:如果会话失效且是密码模式,尝试重登
|
||||||
|
if (!userGid && loginMode.value === "password") {
|
||||||
|
addLog("WARN", "会话已失效,尝试重新登录", "SCHEDULER");
|
||||||
|
if (!isRetry) await tryReLogin();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await performStatusCheckRequest();
|
||||||
|
if (result.success && result.data) {
|
||||||
|
// 2. 处理成功检查
|
||||||
|
const counts = await updateTicketCountsAndLog(result.data);
|
||||||
|
await sendTicketNotifications(counts);
|
||||||
} else {
|
} else {
|
||||||
|
// 3. 处理业务失败
|
||||||
addLog("WARN", `API 返回异常: ${result.msg}`, "SCHEDULER");
|
addLog("WARN", `API 返回异常: ${result.msg}`, "SCHEDULER");
|
||||||
if (!isRetry && isSessionExpiredMsg(result.msg)) {
|
if (!isRetry && isSessionExpiredMsg(result.msg)) {
|
||||||
await tryReLogin();
|
await tryReLogin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
addLog("ERROR", `API 检查失败: ${e.message || e}`, "SCHEDULER");
|
// 4. 处理网络/系统异常
|
||||||
|
addLog("ERROR", `API 检查失败: ${getErrorMessage(e)}`, "SCHEDULER");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -242,8 +271,8 @@ export const useMonitorStore = defineStore("monitor", () => {
|
||||||
tokenSessionId.value = data.tokenSessionId || "";
|
tokenSessionId.value = data.tokenSessionId || "";
|
||||||
addLog("INFO", "已加载保存的凭据", "CONFIG");
|
addLog("INFO", "已加载保存的凭据", "CONFIG");
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
addLog("ERROR", `加载凭据失败: ${e.message || e}`, "CONFIG");
|
addLog("ERROR", `加载凭据失败: ${getErrorMessage(e)}`, "CONFIG");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -266,8 +295,8 @@ export const useMonitorStore = defineStore("monitor", () => {
|
||||||
localStorage.removeItem("crm_credentials");
|
localStorage.removeItem("crm_credentials");
|
||||||
addLog("INFO", "已清除本地凭据", "CONFIG");
|
addLog("INFO", "已清除本地凭据", "CONFIG");
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
addLog("ERROR", `保存凭据失败: ${e.message || e}`, "CONFIG");
|
addLog("ERROR", `保存凭据失败: ${getErrorMessage(e)}`, "CONFIG");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,34 @@
|
||||||
import { relaunch } from "@tauri-apps/plugin-process";
|
import { relaunch } from "@tauri-apps/plugin-process";
|
||||||
import { check, type Update } from "@tauri-apps/plugin-updater";
|
import { check, type Update } from "@tauri-apps/plugin-updater";
|
||||||
|
import { acceptHMRUpdate, defineStore } from "pinia";
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useLogStore } from "@/stores/log";
|
import { useLogStore } from "@/stores/log";
|
||||||
|
import { getErrorMessage } from "@/utils/common";
|
||||||
|
|
||||||
// ===== 模块级单例状态 =====
|
export const useUpdaterStore = defineStore("updater", () => {
|
||||||
/** 是否显示更新对话框 */
|
const { addLog } = useLogStore();
|
||||||
const showUpdateDialog = ref(false);
|
|
||||||
/** 新版本信息 */
|
/** 是否显示更新对话框 */
|
||||||
const updateInfo = ref<{
|
const showUpdateDialog = ref(false);
|
||||||
|
/** 新版本信息 */
|
||||||
|
const updateInfo = ref<{
|
||||||
version: string;
|
version: string;
|
||||||
notes: string;
|
notes: string;
|
||||||
date: string;
|
date: string;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
/** 下载进度 */
|
/** 下载进度 */
|
||||||
const updateProgress = ref<{ total: number; downloaded: number } | null>(null);
|
const updateProgress = ref<{ total: number; downloaded: number } | null>(
|
||||||
/** 是否正在更新中 */
|
null,
|
||||||
const isUpdating = ref(false);
|
);
|
||||||
/** 当前应用版本号 */
|
/** 是否正在更新中 */
|
||||||
const currentVersion = ref("");
|
const isUpdating = ref(false);
|
||||||
/** 是否正在检查更新 */
|
/** 当前应用版本号 */
|
||||||
const isCheckingUpdates = ref(false);
|
const currentVersion = ref("");
|
||||||
|
/** 是否正在检查更新 */
|
||||||
|
const isCheckingUpdates = ref(false);
|
||||||
|
|
||||||
/** 待安装的更新对象 */
|
/** 待安装的更新对象 */
|
||||||
let pendingUpdate: Update | null = null;
|
let pendingUpdate: Update | null = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* 版本更新 Composable(单例模式,模块级状态共享)
|
|
||||||
*/
|
|
||||||
export function useUpdater() {
|
|
||||||
const { addLog } = useLogStore();
|
|
||||||
|
|
||||||
/** 检查是否有可用的应用更新,发现新版本时展示更新对话框 */
|
/** 检查是否有可用的应用更新,发现新版本时展示更新对话框 */
|
||||||
async function checkForUpdates() {
|
async function checkForUpdates() {
|
||||||
|
|
@ -36,7 +36,7 @@ export function useUpdater() {
|
||||||
isCheckingUpdates.value = true;
|
isCheckingUpdates.value = true;
|
||||||
try {
|
try {
|
||||||
const update = await check();
|
const update = await check();
|
||||||
if (update?.available) {
|
if (update) {
|
||||||
pendingUpdate = update;
|
pendingUpdate = update;
|
||||||
updateInfo.value = {
|
updateInfo.value = {
|
||||||
version: update.version,
|
version: update.version,
|
||||||
|
|
@ -48,8 +48,8 @@ export function useUpdater() {
|
||||||
} else {
|
} else {
|
||||||
addLog("INFO", "当前已是最新版本", "UPDATER");
|
addLog("INFO", "当前已是最新版本", "UPDATER");
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
addLog("WARN", `检查更新失败: ${e.message || e}`, "UPDATER");
|
addLog("WARN", `检查更新失败: ${getErrorMessage(e)}`, "UPDATER");
|
||||||
} finally {
|
} finally {
|
||||||
isCheckingUpdates.value = false;
|
isCheckingUpdates.value = false;
|
||||||
}
|
}
|
||||||
|
|
@ -76,8 +76,8 @@ export function useUpdater() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await relaunch();
|
await relaunch();
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
addLog("ERROR", `更新安装失败: ${e.message || e}`, "UPDATER");
|
addLog("ERROR", `更新安装失败: ${getErrorMessage(e)}`, "UPDATER");
|
||||||
isUpdating.value = false;
|
isUpdating.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -98,4 +98,8 @@ export function useUpdater() {
|
||||||
confirmUpdate,
|
confirmUpdate,
|
||||||
dismissUpdate,
|
dismissUpdate,
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
if (import.meta.hot) {
|
||||||
|
import.meta.hot.accept(acceptHMRUpdate(useUpdaterStore, import.meta.hot));
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
/** 从 unknown 类型的 catch 错误中提取可读的错误信息 */
|
||||||
|
export function getErrorMessage(e: unknown): string {
|
||||||
|
return e instanceof Error ? e.message : String(e);
|
||||||
|
}
|
||||||
|
|
||||||
/** 将 Date 对象格式化为 'YYYY-MM-DD HH:mm:ss' 字符串 */
|
/** 将 Date 对象格式化为 'YYYY-MM-DD HH:mm:ss' 字符串 */
|
||||||
export function formatTime(date: Date): string {
|
export function formatTime(date: Date): string {
|
||||||
return dayjs(date).format("YYYY-MM-DD HH:mm:ss");
|
return dayjs(date).format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ interface ImportMeta {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module "*.vue" {
|
declare module "*.vue" {
|
||||||
import type { DefineComponent } from "vue";
|
import type { Component } from "vue";
|
||||||
|
|
||||||
const component: DefineComponent<{}, {}, any>;
|
const component: Component;
|
||||||
export default component;
|
export default component;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue