From 2fb6a0d7e9115200a565de1b2a772578335f7e81 Mon Sep 17 00:00:00 2001 From: duanshuwen Date: Sun, 21 Dec 2025 22:31:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=99=BB=E5=BD=95=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=AF=B9=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- global.d.ts | 10 +++++ src/preload.ts | 2 +- src/renderer/main.ts | 10 +++-- src/renderer/permission.ts | 2 +- src/renderer/store/counter.ts | 22 ---------- src/renderer/store/userinfo.ts | 50 +++++++++++++++++++++++ src/renderer/utils/errorHandler.ts | 5 ++- src/renderer/utils/logger.ts | 64 +++++++++++++++++++++++++++++- src/renderer/views/login/index.vue | 40 +++++++------------ 9 files changed, 148 insertions(+), 57 deletions(-) delete mode 100644 src/renderer/store/counter.ts create mode 100644 src/renderer/store/userinfo.ts diff --git a/global.d.ts b/global.d.ts index c923813..ca97b9b 100644 --- a/global.d.ts +++ b/global.d.ts @@ -88,6 +88,16 @@ declare global { type ThemeMode = 'dark' | 'light' | 'system'; + // form 表单数据类型声明 + interface LoginForm { + username: string; + password: string; + randomStr: string; + code: string; + grant_type: string; + scope: string; + } + // 弹窗类型定义 interface CreateDialogProps { winId?: string; diff --git a/src/preload.ts b/src/preload.ts index b35e351..e4d87eb 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -12,7 +12,7 @@ const api: WindowApi = { minimizeWindow: () => ipcRenderer.send(IPC_EVENTS.WINDOW_MINIMIZE), maximizeWindow: () => ipcRenderer.send(IPC_EVENTS.WINDOW_MAXIMIZE), onWindowMaximized: (callback: (isMaximized: boolean) => void) => ipcRenderer.on(IPC_EVENTS.WINDOW_MAXIMIZE + 'back', (_, isMaximized) => callback(isMaximized)), - isWindowMaximized: () => ipcRenderer.invoke(IPC_EVENTS.WINDOW_MAXIMIZE), + isWindowMaximized: () => ipcRenderer.invoke(IPC_EVENTS.IS_WINDOW_MAXIMIZED), viewIsReady: () => ipcRenderer.send(IPC_EVENTS.RENDERER_IS_READY), app: { diff --git a/src/renderer/main.ts b/src/renderer/main.ts index 39e10ba..ed0ca32 100644 --- a/src/renderer/main.ts +++ b/src/renderer/main.ts @@ -1,7 +1,8 @@ -import { createApp, type Plugin } from "vue"; -import { createPinia } from "pinia"; -import router from "./router"; -import App from "./App.vue"; +import { createApp, type Plugin } from "vue" +import { createPinia } from "pinia" +import errorHandler from "@utils/errorHandler" +import router from "./router" +import App from "./App.vue" import ElementPlus from 'element-plus' import locale from 'element-plus/es/locale/lang/zh-cn' import i18n from './i18n' @@ -30,6 +31,7 @@ app.use(router); app.use(ElementPlus, { locale }) app.use(components) app.use(i18n) +app.use(errorHandler) // 挂载应用到 DOM app.mount("#app"); diff --git a/src/renderer/permission.ts b/src/renderer/permission.ts index 055d4d4..f5b11b5 100644 --- a/src/renderer/permission.ts +++ b/src/renderer/permission.ts @@ -15,7 +15,7 @@ router.beforeEach((to: any, _from: any, next: any) => { } else if (isWhiteList(to.path)) { next() } else { - + next() } } else { // no token diff --git a/src/renderer/store/counter.ts b/src/renderer/store/counter.ts deleted file mode 100644 index 062c960..0000000 --- a/src/renderer/store/counter.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { defineStore } from 'pinia' -import { ref, computed } from 'vue' - -export const useCounterStore = defineStore('counter', () => { - const count = ref(0) - - const doubleCount = computed(() => count.value * 2) - - function increment() { - count.value++ - } - - function decrement() { - count.value-- - } - - function reset() { - count.value = 0 - } - - return { count, doubleCount, increment, decrement, reset } -}) \ No newline at end of file diff --git a/src/renderer/store/userinfo.ts b/src/renderer/store/userinfo.ts new file mode 100644 index 0000000..da830d4 --- /dev/null +++ b/src/renderer/store/userinfo.ts @@ -0,0 +1,50 @@ +import { defineStore } from 'pinia' +import { authOauth2TokenUsingPost } from "@renderer/api" +import { getToken, setToken, removeToken } from '@utils/auth' + +export const useUserStore = defineStore('userInfo', { + state: () => ({ + token: getToken(), + }), + + actions: { + /** + * 登录方法 + * @function login + * @async + * @param {Object} data - 登录数据 + * @returns {Promise} + */ + async login(data: LoginForm) { + data.grant_type = 'password'; + data.scope = 'server'; + + return new Promise((resolve, reject) => { + authOauth2TokenUsingPost({body: {...data, clientId: ''}}) + .then((res: any) => { + // 存储token 信息 + setToken(res.access_token) + resolve(res) + }) + .catch((err) => { + reject(err); + }); + }); + }, + + // 退出系统 + logOut() { + return new Promise((resolve, reject) => { + // logout(this.token).then(() => { + // this.token = '' + // this.roles = [] + // this.permissions = [] + // removeToken() + // resolve() + // }).catch(error => { + // reject(error) + // }) + }) + } + } +}) \ No newline at end of file diff --git a/src/renderer/utils/errorHandler.ts b/src/renderer/utils/errorHandler.ts index 5dd4738..1aebca0 100644 --- a/src/renderer/utils/errorHandler.ts +++ b/src/renderer/utils/errorHandler.ts @@ -1,9 +1,10 @@ import type { Plugin } from 'vue' import logger from './logger' -export const errorHandler: Plugin = (app) => { +export const errorHandler: Plugin = (app) => { app.config.errorHandler = (err, instance, info) => { - logger.error('Vue error:', err, instance, info); + // 过滤掉无法序列化的 Vue 实例对象 + logger.error('Vue error:', err, info); }; window.onerror = (message, source, lineno, colno, error) => { diff --git a/src/renderer/utils/logger.ts b/src/renderer/utils/logger.ts index e71cc26..7262313 100644 --- a/src/renderer/utils/logger.ts +++ b/src/renderer/utils/logger.ts @@ -1,5 +1,67 @@ +const safeStringify = (arg: any) => { + try { + // 处理 Error 对象 + if (arg instanceof Error) { + return { + message: arg.message, + stack: arg.stack, + name: arg.name + } + } + // 简单值直接返回 + if (typeof arg !== 'object' || arg === null) { + return arg + } + // 处理 Vue 响应式对象(Proxy) + if (arg?.__v_isRef || arg?.__v_isReactive || arg?.__v_isReadonly) { + // 尝试解包 Proxy/Ref + try { + const raw = JSON.parse(JSON.stringify(arg)) + return raw + } catch (e) { + return '[Vue Reactive Object]' + } + } + // 尝试深拷贝,如果失败则说明包含不可序列化对象 + const raw = JSON.parse(JSON.stringify(arg)) + return raw + } catch (e) { + // 序列化失败,返回字符串描述 + return String(arg) + } +} -export const logger = window.api.logger ?? console; +// 缓存原始 console 方法,防止递归调用和保持控制台输出 +const originalConsole = { + debug: console.debug.bind(console), + log: console.log.bind(console), + info: console.info.bind(console), + warn: console.warn.bind(console), + error: console.error.bind(console), +} + +const createSafeLogger = (originalLogger: any) => { + return { + debug: (message: string, ...meta: any[]) => { + originalConsole.debug(message, ...meta) + originalLogger.debug(String(message), ...meta.map(safeStringify)) + }, + info: (message: string, ...meta: any[]) => { + originalConsole.info(message, ...meta) + originalLogger.info(String(message), ...meta.map(safeStringify)) + }, + warn: (message: string, ...meta: any[]) => { + originalConsole.warn(message, ...meta) + originalLogger.warn(String(message), ...meta.map(safeStringify)) + }, + error: (message: string, ...meta: any[]) => { + originalConsole.error(message, ...meta) + originalLogger.error(String(message), ...meta.map(safeStringify)) + }, + } +} + +export const logger = window.api.logger ? createSafeLogger(window.api.logger) : console if (window.api.logger) { console.debug = logger.debug; diff --git a/src/renderer/views/login/index.vue b/src/renderer/views/login/index.vue index 3697bc6..56190c0 100644 --- a/src/renderer/views/login/index.vue +++ b/src/renderer/views/login/index.vue @@ -58,19 +58,20 @@ - -
+ @@ -81,27 +82,17 @@ -