feat: 插件沙箱 with(fakeGlobal) 修复 Z_SYNC_FLUSH 未定义 + 播放列表抽屉 + 日志系统 + 侧边栏日志入口
This commit is contained in:
124
src/stores/log.ts
Normal file
124
src/stores/log.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
export type LogLevel = 'info' | 'warn' | 'error' | 'debug';
|
||||
|
||||
export interface LogEntry {
|
||||
id: number;
|
||||
time: string;
|
||||
level: LogLevel;
|
||||
module: string;
|
||||
message: string;
|
||||
detail?: any;
|
||||
}
|
||||
|
||||
const MAX_LOGS = 500;
|
||||
const STORAGE_KEY = 'qz-app-logs';
|
||||
const LEVEL_ORDER: Record<LogLevel, number> = { debug: 0, info: 1, warn: 2, error: 3 };
|
||||
|
||||
function loadFromStorage(): LogEntry[] {
|
||||
try {
|
||||
const raw = localStorage.getItem(STORAGE_KEY);
|
||||
if (raw) {
|
||||
const parsed = JSON.parse(raw);
|
||||
if (Array.isArray(parsed)) return parsed as LogEntry[];
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
export const useLogStore = defineStore('log', () => {
|
||||
const logs = ref<LogEntry[]>(loadFromStorage());
|
||||
let nextId = logs.value.length > 0 ? Math.max(...logs.value.map((l) => l.id)) + 1 : 1;
|
||||
|
||||
watch(
|
||||
logs,
|
||||
(newLogs) => {
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(newLogs));
|
||||
} catch {
|
||||
// ignore quota issues
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
const add = (level: LogLevel, module: string, message: string, detail?: any) => {
|
||||
const now = new Date();
|
||||
const hh = now.getHours().toString().padStart(2, '0');
|
||||
const mm = now.getMinutes().toString().padStart(2, '0');
|
||||
const ss = now.getSeconds().toString().padStart(2, '0');
|
||||
const ms = now.getMilliseconds().toString().padStart(3, '0');
|
||||
|
||||
const entry: LogEntry = {
|
||||
id: nextId++,
|
||||
time: `${hh}:${mm}:${ss}.${ms}`,
|
||||
level,
|
||||
module,
|
||||
message,
|
||||
detail,
|
||||
};
|
||||
|
||||
logs.value.push(entry);
|
||||
if (logs.value.length > MAX_LOGS) {
|
||||
logs.value = logs.value.slice(-MAX_LOGS);
|
||||
}
|
||||
|
||||
// 同步到浏览器控制台,方便调试
|
||||
const consoleArgs = [`[${entry.time}] [${level.toUpperCase()}] [${module}]`, message];
|
||||
if (detail !== undefined) consoleArgs.push(detail);
|
||||
try {
|
||||
if (level === 'error') console.error(...consoleArgs);
|
||||
else if (level === 'warn') console.warn(...consoleArgs);
|
||||
else if (level === 'debug') console.debug(...consoleArgs);
|
||||
else console.log(...consoleArgs);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
};
|
||||
|
||||
const info = (module: string, message: string, detail?: any) => add('info', module, message, detail);
|
||||
const warn = (module: string, message: string, detail?: any) => add('warn', module, message, detail);
|
||||
const error = (module: string, message: string, detail?: any) => add('error', module, message, detail);
|
||||
const debug = (module: string, message: string, detail?: any) => add('debug', module, message, detail);
|
||||
|
||||
const clear = () => {
|
||||
logs.value = [];
|
||||
nextId = 1;
|
||||
};
|
||||
|
||||
const filter = (module?: string, level?: LogLevel) => {
|
||||
return logs.value.filter((l) => {
|
||||
if (module && l.module !== module) return false;
|
||||
if (level && LEVEL_ORDER[l.level] < LEVEL_ORDER[level]) return false;
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
const moduleList = () => {
|
||||
const set = new Set<string>();
|
||||
for (const l of logs.value) set.add(l.module);
|
||||
return Array.from(set).sort();
|
||||
};
|
||||
|
||||
const countByLevel = () => {
|
||||
const c = { info: 0, warn: 0, error: 0, debug: 0 };
|
||||
for (const l of logs.value) c[l.level]++;
|
||||
return c;
|
||||
};
|
||||
|
||||
return {
|
||||
logs,
|
||||
info,
|
||||
warn,
|
||||
error,
|
||||
debug,
|
||||
add,
|
||||
clear,
|
||||
filter,
|
||||
moduleList,
|
||||
countByLevel,
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user