mirror of
https://github.com/kuaifan/dootask.git
synced 2026-01-21 16:48:13 +00:00
refactor: 优化 webTab 管理和状态同步
- 封装 safeCloseWebTab 方法,复用标签关闭时的未保存数据检查逻辑 - 添加 recreatePreloadPool,支持主题切换后重建预加载池 - broadcastCommand 扩展到 webTab views,确保子窗口收到同步消息 - 修复 synchTheme 和 saveDialogDraft 的跨窗口参数传递 - IDBDel 返回 Promise 并正确 await
This commit is contained in:
parent
9c7ec58bb6
commit
a34b0c88d5
9
electron/electron.js
vendored
9
electron/electron.js
vendored
@ -789,11 +789,20 @@ ipcMain.on('windowMax', (event) => {
|
|||||||
ipcMain.on('broadcastCommand', (event, args) => {
|
ipcMain.on('broadcastCommand', (event, args) => {
|
||||||
const channel = args.channel || args.command
|
const channel = args.channel || args.command
|
||||||
const payload = args.payload || args.data
|
const payload = args.payload || args.data
|
||||||
|
// 广播给所有 BrowserWindow
|
||||||
BrowserWindow.getAllWindows().forEach(window => {
|
BrowserWindow.getAllWindows().forEach(window => {
|
||||||
if (window.webContents.id !== event.sender.id) {
|
if (window.webContents.id !== event.sender.id) {
|
||||||
window.webContents.send(channel, payload)
|
window.webContents.send(channel, payload)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
// 广播给 webTabManager 中的所有 view
|
||||||
|
for (const [, windowData] of webTabManager.getWebTabWindows()) {
|
||||||
|
windowData.views?.forEach(({ view }) => {
|
||||||
|
if (view && !view.webContents.isDestroyed() && view.webContents.id !== event.sender.id) {
|
||||||
|
view.webContents.send(channel, payload)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
event.returnValue = "ok"
|
event.returnValue = "ok"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
117
electron/lib/web-tab-manager.js
vendored
117
electron/lib/web-tab-manager.js
vendored
@ -220,6 +220,38 @@ function clearPreloadPool() {
|
|||||||
preloadViewPool = []
|
preloadViewPool = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重建预加载池(清理后重新创建)
|
||||||
|
*/
|
||||||
|
function recreatePreloadPool() {
|
||||||
|
clearPreloadPool()
|
||||||
|
while (preloadViewPool.length < PRELOAD_CONFIG.poolSize) {
|
||||||
|
const view = createPreloadView()
|
||||||
|
if (view) {
|
||||||
|
preloadViewPool.push(view)
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内置浏览器 - 延迟发送导航状态
|
||||||
|
*/
|
||||||
|
function notifyNavigationState(item) {
|
||||||
|
setTimeout(() => {
|
||||||
|
const wd = webTabWindows.get(item.view.webTabWindowId)
|
||||||
|
if (wd && wd.window) {
|
||||||
|
utils.onDispatchEvent(wd.window.webContents, {
|
||||||
|
event: 'navigation-state',
|
||||||
|
id: item.id,
|
||||||
|
canGoBack: item.view.webContents.navigationHistory.canGoBack(),
|
||||||
|
canGoForward: item.view.webContents.navigationHistory.canGoForward()
|
||||||
|
}).then(_ => { })
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// 核心函数
|
// 核心函数
|
||||||
// ============================================================
|
// ============================================================
|
||||||
@ -527,7 +559,7 @@ function createWebTabWindowInstance(windowId, position, mode = 'tab') {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 点击窗口关闭按钮:依次检查并关闭每个标签页
|
// 点击窗口关闭按钮:依次检查并关闭每个标签页
|
||||||
const checkAndCloseTabs = async () => {
|
const checkAndCloseTabs = async () => {
|
||||||
// 复制标签列表,因为关闭时会修改原数组
|
// 复制标签列表,因为关闭时会修改原数组
|
||||||
@ -1080,6 +1112,32 @@ function closeWebTabInWindow(windowId, id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全关闭标签(检查未保存数据后关闭)
|
||||||
|
* @param windowId 窗口ID
|
||||||
|
* @param tabId 标签ID
|
||||||
|
*/
|
||||||
|
function safeCloseWebTab(windowId, tabId) {
|
||||||
|
const windowData = webTabWindows.get(windowId)
|
||||||
|
if (!windowData) {
|
||||||
|
closeWebTabInWindow(windowId, tabId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const tab = windowData.views.find(v => v.id === tabId)
|
||||||
|
if (!tab) {
|
||||||
|
closeWebTabInWindow(windowId, tabId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const proxyWindow = Object.create(windowData.window, {
|
||||||
|
webContents: { get: () => tab.view.webContents }
|
||||||
|
})
|
||||||
|
utils.onBeforeUnload({ preventDefault: () => {} }, proxyWindow).then(() => {
|
||||||
|
closeWebTabInWindow(windowId, tabId)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分离标签到新窗口
|
* 分离标签到新窗口
|
||||||
* @param windowId 源窗口ID
|
* @param windowId 源窗口ID
|
||||||
@ -1432,6 +1490,14 @@ function destroyAllWindowMode() {
|
|||||||
function registerIPC() {
|
function registerIPC() {
|
||||||
const electronMenu = getElectronMenu()
|
const electronMenu = getElectronMenu()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重建预加载池
|
||||||
|
*/
|
||||||
|
ipcMain.on('recreatePreloadPool', (event) => {
|
||||||
|
recreatePreloadPool()
|
||||||
|
event.returnValue = "ok"
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取路由窗口信息(从 webTabWindows 中查找 mode='window' 的窗口)
|
* 获取路由窗口信息(从 webTabWindows 中查找 mode='window' 的窗口)
|
||||||
*/
|
*/
|
||||||
@ -1598,21 +1664,7 @@ function registerIPC() {
|
|||||||
windowId = findWindowIdByTabId(tabId)
|
windowId = findWindowIdByTabId(tabId)
|
||||||
}
|
}
|
||||||
if (windowId) {
|
if (windowId) {
|
||||||
const windowData = webTabWindows.get(windowId)
|
safeCloseWebTab(windowId, tabId)
|
||||||
if (windowData) {
|
|
||||||
const tab = windowData.views.find(v => v.id === tabId)
|
|
||||||
if (tab) {
|
|
||||||
const proxyWindow = Object.create(windowData.window, {
|
|
||||||
webContents: { get: () => tab.view.webContents }
|
|
||||||
})
|
|
||||||
utils.onBeforeUnload({ preventDefault: () => {} }, proxyWindow).then(() => {
|
|
||||||
closeWebTabInWindow(windowId, tabId)
|
|
||||||
})
|
|
||||||
event.returnValue = "ok"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closeWebTabInWindow(windowId, tabId)
|
|
||||||
}
|
}
|
||||||
event.returnValue = "ok"
|
event.returnValue = "ok"
|
||||||
})
|
})
|
||||||
@ -1726,23 +1778,6 @@ function registerIPC() {
|
|||||||
event.returnValue = "ok"
|
event.returnValue = "ok"
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
|
||||||
* 内置浏览器 - 延迟发送导航状态
|
|
||||||
*/
|
|
||||||
function notifyNavigationState(item) {
|
|
||||||
setTimeout(() => {
|
|
||||||
const wd = webTabWindows.get(item.view.webTabWindowId)
|
|
||||||
if (wd && wd.window) {
|
|
||||||
utils.onDispatchEvent(wd.window.webContents, {
|
|
||||||
event: 'navigation-state',
|
|
||||||
id: item.id,
|
|
||||||
canGoBack: item.view.webContents.navigationHistory.canGoBack(),
|
|
||||||
canGoForward: item.view.webContents.navigationHistory.canGoForward()
|
|
||||||
}).then(_ => { })
|
|
||||||
}
|
|
||||||
}, 100)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 内置浏览器 - 后退
|
* 内置浏览器 - 后退
|
||||||
*/
|
*/
|
||||||
@ -1864,21 +1899,7 @@ function registerIPC() {
|
|||||||
const tabId = event.sender.id
|
const tabId = event.sender.id
|
||||||
const windowId = findWindowIdByTabId(tabId)
|
const windowId = findWindowIdByTabId(tabId)
|
||||||
if (windowId !== null) {
|
if (windowId !== null) {
|
||||||
const windowData = webTabWindows.get(windowId)
|
safeCloseWebTab(windowId, tabId)
|
||||||
if (windowData) {
|
|
||||||
const tab = windowData.views.find(v => v.id === tabId)
|
|
||||||
if (tab) {
|
|
||||||
const proxyWindow = Object.create(windowData.window, {
|
|
||||||
webContents: { get: () => tab.view.webContents }
|
|
||||||
})
|
|
||||||
utils.onBeforeUnload({ preventDefault: () => {} }, proxyWindow).then(() => {
|
|
||||||
closeWebTabInWindow(windowId, tabId)
|
|
||||||
})
|
|
||||||
event.returnValue = "ok"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closeWebTabInWindow(windowId, tabId)
|
|
||||||
} else {
|
} else {
|
||||||
const win = BrowserWindow.fromWebContents(event.sender)
|
const win = BrowserWindow.fromWebContents(event.sender)
|
||||||
win?.close()
|
win?.close()
|
||||||
|
|||||||
10
resources/assets/js/functions/common.js
vendored
10
resources/assets/js/functions/common.js
vendored
@ -889,10 +889,10 @@ const timezone = require("dayjs/plugin/timezone");
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 输入框数字限制
|
* 输入框数字限制
|
||||||
* @param object
|
* @param object
|
||||||
* @param min
|
* @param min
|
||||||
* @param max
|
* @param max
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
inputNumberLimit(object, min = null, max = null) {
|
inputNumberLimit(object, min = null, max = null) {
|
||||||
if (object === null || typeof object !== "object") return;
|
if (object === null || typeof object !== "object") return;
|
||||||
@ -1674,7 +1674,7 @@ const timezone = require("dayjs/plugin/timezone");
|
|||||||
},
|
},
|
||||||
|
|
||||||
IDBDel(key) {
|
IDBDel(key) {
|
||||||
localforage.removeItem(key).then(_ => {})
|
return localforage.removeItem(key)
|
||||||
},
|
},
|
||||||
|
|
||||||
IDBSet(key, value) {
|
IDBSet(key, value) {
|
||||||
|
|||||||
2
resources/assets/js/language/index.js
vendored
2
resources/assets/js/language/index.js
vendored
@ -95,7 +95,7 @@ function setLanguage(language, silence = false) {
|
|||||||
if (silence) {
|
if (silence) {
|
||||||
utils.saveLanguage(language);
|
utils.saveLanguage(language);
|
||||||
(async () => {
|
(async () => {
|
||||||
$A.IDBDel("callAt")
|
await $A.IDBDel("callAt")
|
||||||
$A.reloadUrl()
|
$A.reloadUrl()
|
||||||
})()
|
})()
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -56,6 +56,7 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
$A.messageSuccess('保存成功');
|
$A.messageSuccess('保存成功');
|
||||||
|
$A.Electron?.sendMessage('recreatePreloadPool');
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
12
resources/assets/js/store/actions.js
vendored
12
resources/assets/js/store/actions.js
vendored
@ -556,7 +556,7 @@ export default {
|
|||||||
resolve(false)
|
resolve(false)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatch("synchTheme", mode)
|
dispatch("synchTheme", {mode})
|
||||||
resolve(true)
|
resolve(true)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -566,8 +566,11 @@ export default {
|
|||||||
* @param state
|
* @param state
|
||||||
* @param dispatch
|
* @param dispatch
|
||||||
* @param mode
|
* @param mode
|
||||||
|
* @param args
|
||||||
*/
|
*/
|
||||||
synchTheme({state, dispatch}, mode = undefined) {
|
synchTheme({state, dispatch}, {mode, ...args} = {}) {
|
||||||
|
$A.syncDispatch("synchTheme", {...args, mode})
|
||||||
|
//
|
||||||
if (typeof mode === "undefined") {
|
if (typeof mode === "undefined") {
|
||||||
mode = state.themeConf
|
mode = state.themeConf
|
||||||
} else {
|
} else {
|
||||||
@ -3814,13 +3817,14 @@ export default {
|
|||||||
* @param id
|
* @param id
|
||||||
* @param content
|
* @param content
|
||||||
* @param immediate
|
* @param immediate
|
||||||
|
* @param args
|
||||||
*/
|
*/
|
||||||
saveDialogDraft({commit}, {id, content, immediate = false}) {
|
saveDialogDraft({commit}, {id, content, immediate = false, ...args}) {
|
||||||
if ($A.isSubElectron) {
|
if ($A.isSubElectron) {
|
||||||
dialogDraftState.subTemp = {id, content, immediate: true}
|
dialogDraftState.subTemp = {id, content, immediate: true}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
$A.syncDispatch("saveDialogDraft", {id, content, immediate})
|
$A.syncDispatch("saveDialogDraft", {...args, id, content, immediate})
|
||||||
|
|
||||||
// 清除已有的计时器
|
// 清除已有的计时器
|
||||||
if (dialogDraftState.timer[id]) {
|
if (dialogDraftState.timer[id]) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user