diff --git a/src/aura/init/rendererHook/injection.js b/src/aura/init/rendererHook/injection.js index 1ecf92d..5a55778 100755 --- a/src/aura/init/rendererHook/injection.js +++ b/src/aura/init/rendererHook/injection.js @@ -24,40 +24,6 @@ }); }; - const createStore = () => { - const store = { - router: "/", - }; - const internal = { - get: (key) => store[key], - set: (key, value) => { - store[key] = value; - return true; - }, - }; - - window.$store = { - get: (key) => { - const stack = new Error().stack; - if (stack.includes("aura/ui/pages/")) { - return internal.get(key); - } - return undefined; - }, - set: (key, value) => { - const stack = new Error().stack; - if (stack.includes("aura/ui/pages/")) { - return internal.set(key, value); - } - return false; - }, - }; - - return internal; - }; - - const store = createStore(); - const createUILoader = () => { const modules = "__TEMPLATE_TARGETS__"; const containers = new Map(); @@ -65,6 +31,63 @@ const moduleResources = new Map(); const globalScripts = new Set(); + const flattenTargets = (targets, parentKey = "") => { + const flattened = {}; + + for (const [key, config] of Object.entries(targets)) { + const fullKey = parentKey ? `${parentKey}.${key}` : key; + flattened[fullKey] = { ...config }; + + if ( + config.childs && + typeof config.childs === "object" && + !Array.isArray(config.childs) + ) { + const childTargets = flattenTargets(config.childs, fullKey); + Object.assign(flattened, childTargets); + delete flattened[fullKey].childs; + } + } + + return flattened; + }; + + const flatModules = flattenTargets(modules); + + const createAccessProxy = (originalModules, flatModules) => { + const createNestedProxy = (target, path = []) => { + return new Proxy(target, { + get(target, prop) { + const currentPath = [...path, prop].join("."); + + if (flatModules[currentPath]) { + return flatModules[currentPath]; + } + + const value = Reflect.get(target, prop); + if (typeof value === "object" && value !== null) { + return createNestedProxy(value, [...path, prop]); + } + + return value; + }, + set(target, prop, value) { + const currentPath = [...path, prop].join("."); + + if (flatModules[currentPath]) { + flatModules[currentPath] = value; + } + + return Reflect.set(target, prop, value); + }, + }); + }; + + return createNestedProxy(originalModules); + }; + + const accessibleModules = createAccessProxy(modules, flatModules); + const insertElement = (target, element, mode = "appendChild") => { const elementId = element.id; if (document.getElementById(elementId)) { @@ -120,12 +143,12 @@ const observer = new MutationObserver((_mutations) => { if (!document.getElementById(elementId)) { let targetElement = document.querySelector( - modules[moduleKey].pageSelector + flatModules[moduleKey].pageSelector ); if ( targetElement && - modules[moduleKey].active && - modules[moduleKey].revive + flatModules[moduleKey].active && + flatModules[moduleKey].revive ) { if (!document.getElementById(elementId)) { console.log( @@ -145,12 +168,53 @@ observers.set(moduleKey, observer); }; + const loadResources = async (resources, type, moduleKey, isRevive) => { + if (!resources || isRevive) return []; + + const resourceArray = Array.isArray(resources) ? resources : [resources]; + const loadedResources = []; + + for (const resource of resourceArray) { + try { + let element; + if (type === "css") { + element = document.createElement("link"); + element.rel = "stylesheet"; + element.href = `../../aura/${resource}`; + document.head.appendChild(element); + } else if (type === "js") { + element = document.createElement("script"); + element.src = `../../aura/${resource}`; + document.body.appendChild(element); + await new Promise((resolve, reject) => { + element.onload = resolve; + element.onerror = reject; + }); + } + + if (element) { + loadedResources.push(element); + console.log( + `[HugoAura / UI / ${moduleKey}] Loaded ${type}: ${resource}` + ); + } + } catch (err) { + console.error( + `[HugoAura / UI / Error] Failed to load ${type} ${resource} for ${moduleKey}:`, + err + ); + } + } + + return loadedResources; + }; + const loader = { async loadModule(moduleKey, isRevive = false) { - if (!modules[moduleKey]?.active) return; + if (!flatModules[moduleKey]?.active) return; try { - const config = modules[moduleKey]; + const config = flatModules[moduleKey]; const target = await waitForElement(config.pageSelector); const elementId = `aura-container-${moduleKey.replace(/\./g, "-")}`; @@ -168,12 +232,14 @@ const resources = new Set(); moduleResources.set(moduleKey, resources); - if (config.pageCSS && !isRevive) { - const link = document.createElement("link"); - link.rel = "stylesheet"; - link.href = `../../aura/${config.pageCSS}`; - document.head.appendChild(link); - resources.add(link); + if (config.pageCSS) { + const cssResources = await loadResources( + config.pageCSS, + "css", + moduleKey, + isRevive + ); + cssResources.forEach((resource) => resources.add(resource)); } const html = await fetch(`../../aura/${config.pageURI}`).then((r) => @@ -184,18 +250,21 @@ insertElement(target, container, config.selectorMode); monitorParent(moduleKey, target, container, config.selectorMode); - if (config.pageScript && !isRevive) { - const script = document.createElement("script"); - script.src = `../../aura/${config.pageScript}`; - document.body.appendChild(script); - resources.add(script); + if (config.pageScript) { + const jsResources = await loadResources( + config.pageScript, + "js", + moduleKey, + isRevive + ); + jsResources.forEach((resource) => resources.add(resource)); } const observer = new MutationObserver(() => { if ( !document.contains(container) && - modules[moduleKey].active && - modules[moduleKey].revive + flatModules[moduleKey].active && + flatModules[moduleKey].revive ) { this.loadModule(moduleKey, true); } @@ -238,13 +307,13 @@ handleModuleChange(moduleKey, path = []) { const fullPath = [...path, moduleKey].join("."); - if (path.length === 0 && modules[moduleKey].active) { + if (path.length === 0 && flatModules[moduleKey].active) { this.loadModule(moduleKey); } else if (path.length === 0) { this.unloadModule(moduleKey); } else { if (moduleKey === "active") { - if (modules[path[0]].active) { + if (flatModules[path[0]].active) { this.loadModule(path[0]); } else { this.unloadModule(path[0]); @@ -297,7 +366,7 @@ try { await loadGlobalJS(); - for (const [key, config] of Object.entries(modules)) { + for (const [key, config] of Object.entries(flatModules)) { if (config.active) { await loader.loadModule(key); } @@ -309,7 +378,7 @@ initialLoad(); - return createDeepProxy(modules, (path, prop, value) => { + return createDeepProxy(accessibleModules, (path, prop, value) => { loader.handleModuleChange(prop, path); }); }; diff --git a/src/aura/init/rendererHook/uiHooksManager.js b/src/aura/init/rendererHook/uiHooksManager.js index 463bf31..b91ff87 100755 --- a/src/aura/init/rendererHook/uiHooksManager.js +++ b/src/aura/init/rendererHook/uiHooksManager.js @@ -14,7 +14,7 @@ class RendererHooksManager { const hooksPath = path.join(__dirname, "../../../aura/ui/hookDefinitions"); - /** @type {import("../../types/main/core").HooksMap} */ + /** @type {import("../../types/main/core").UIHooksMap} */ const hooks = new Map(); try { @@ -65,6 +65,7 @@ class RendererHooksManager { webContents.removeListener("destroyed", destroyedListener); } + // @ts-expect-error global.__HUGO_AURA__.hookedWindows.delete(windowKey); } @@ -80,6 +81,7 @@ class RendererHooksManager { /** @type {import("../../types/main/core").WindowName} */ const windowKey = `${hookConfig.windowName || windowName}`; + // @ts-expect-error if (global.__HUGO_AURA__.hookedWindows.has(windowKey)) { console.log( `[HugoAura / Init / RDH] Duplicate ui hook for ${windowKey}, ignoring...` @@ -137,6 +139,7 @@ class RendererHooksManager { const destroyedListener = () => { this.cleanupWindow( windowKey, + // @ts-expect-error global.__HUGO_AURA__.hookedWindows.get(windowKey) ); }; @@ -144,6 +147,7 @@ class RendererHooksManager { webContents.on("dom-ready", domReadyListener); webContents.on("destroyed", destroyedListener); + // @ts-expect-error global.__HUGO_AURA__.hookedWindows.set(windowKey, { webContents, domReadyListener, diff --git a/src/aura/types/render/uiHook.d.ts b/src/aura/types/render/uiHook.d.ts index 97635ce..9615d91 100755 --- a/src/aura/types/render/uiHook.d.ts +++ b/src/aura/types/render/uiHook.d.ts @@ -1,12 +1,13 @@ import { WindowName } from "../main/core"; interface UIHookTarget { - active: boolean; - pageURI: string; - pageScript: string; - pageSelector: string; - selectorMode: "insertAfter" | "insertBefore" | "appendChild"; - pageCSS: string; + active?: boolean; + pageURI?: string; + pageScript?: string; + pageSelector?: string; + selectorMode?: "insertAfter" | "insertBefore" | "appendChild"; + pageCSS?: string; + childs?: Record; revive?: boolean; } diff --git a/src/aura/ui/composables/plsConfigManager.js b/src/aura/ui/composables/plsConfigManager.js index 6555300..694a863 100755 --- a/src/aura/ui/composables/plsConfigManager.js +++ b/src/aura/ui/composables/plsConfigManager.js @@ -37,16 +37,6 @@ const { genRandomHex } = require("../../utils/crypto"); */ const updatePlsConfigToRemote = async (configKey, configValue) => { const configLevels = configKey.split("."); - /** @type {Record} */ - // @ts-expect-error - let localUpdateTarget = - configLevels[0] === "ruleSettings" - ? global.__HUGO_AURA__.plsRules - : global.__HUGO_AURA__.plsSettings; - for (const level of configLevels.slice(0, -1)) { - localUpdateTarget = localUpdateTarget[level]; - } - localUpdateTarget[configLevels.slice(-1)[0]] = configValue; const plsConfigUpdateEvent = new CustomEvent("onPLSConfigUpdate", { detail: { @@ -55,6 +45,14 @@ const updatePlsConfigToRemote = async (configKey, configValue) => { }, }); document.dispatchEvent(plsConfigUpdateEvent); + const settingsEntries = document.getElementsByClassName( + "aura-settings-entry" + ); + if (settingsEntries.length > 0) { + Array.from(settingsEntries).forEach((entry) => { + entry.dispatchEvent(plsConfigUpdateEvent); + }); + } /** * @type {ClientPLSRequest} diff --git a/src/aura/ui/composables/settingsRenderer.js b/src/aura/ui/composables/settingsRenderer.js index 9144170..2df7904 100755 --- a/src/aura/ui/composables/settingsRenderer.js +++ b/src/aura/ui/composables/settingsRenderer.js @@ -51,6 +51,9 @@ const insertOrRemoveEl = (parent, child, isInsert = true) => { } }; +const createOnLeaveEvtListener = + global.__HUGO_AURA_GLOBAL__.utils.createOnLeaveEvtListener; + const renderInputArea = (entry, operationArea, descriptionArea) => { switch (entry.type) { case "switch": { @@ -131,7 +134,7 @@ const renderInputArea = (entry, operationArea, descriptionArea) => { } }; -const renderChild = (entry, formEl) => { +const renderNormalSettingsItem = (entry, formEl) => { const entryContainerEl = document.createElement("div"); entryContainerEl.classList.add("aura-settings-entry"); entryContainerEl.id = `${entry.id}Container`; @@ -216,7 +219,7 @@ const renderChild = (entry, formEl) => { const entryDescription = document.createElement("p"); entryDescription.classList.add("aura-settings-entry-desc"); - entryDescription.textContent = entry.description; + entryDescription.innerHTML = entry.description; entryInfoContainerEl.appendChild(entryTitle); entryInfoContainerEl.appendChild(entryDescription); @@ -229,20 +232,18 @@ const renderChild = (entry, formEl) => { insertOrRemoveEl(entryOperationArea, targetEl, true); if (entry.reactive) { - document.addEventListener( - entry.PLSRequired ? "onPLSConfigUpdate" : "onHugoAuraConfigUpdate", - (event) => { - if (entry.reactiveVal.includes(event.detail.path.join("."))) { - insertOrRemoveEl(entryOperationArea, targetEl, false); - targetEl = renderInputArea( - entry, - entryOperationArea, - entryDescription - ); - insertOrRemoveEl(entryOperationArea, targetEl, true); - } + const evtListener = (event) => { + if (entry.reactiveVal.includes(event.detail.path.join("."))) { + insertOrRemoveEl(entryOperationArea, targetEl, false); + targetEl = renderInputArea(entry, entryOperationArea, entryDescription); + insertOrRemoveEl(entryOperationArea, targetEl, true); } - ); + }; + const channel = entry.PLSRequired + ? "onPLSConfigUpdate" + : "onHugoAuraConfigUpdate"; + entryContainerEl.addEventListener(channel, evtListener); + // createOnLeaveEvtListener(channel, evtListener); } const setDisableStatus = (el, isDisable, hint = null) => { @@ -266,35 +267,95 @@ const renderChild = (entry, formEl) => { setDisableStatus(entryOperationArea, true, "连接至 PLS 以继续"); } - document.addEventListener("onPLSStatsUpdate", (event) => { + const evtListener = (event) => { if (event.detail.connected) { setDisableStatus(entryOperationArea, false); } else { setDisableStatus(entryOperationArea, true, "连接至 PLS 以继续"); } - }); + }; + entryContainerEl.addEventListener("onPLSStatsUpdate", evtListener); + // createOnLeaveEvtListener("onPLSStatsUpdate", evtListener); } entryContainerEl.appendChild(entryOperationArea); const isShow = entry.auraIf(); if (!isShow) entryContainerEl.classList.add("aura-settings-entry-hidden"); if (entry.associateVal) { - document.addEventListener( - entry.PLSRequired ? "onPLSConfigUpdate" : "onHugoAuraConfigUpdate", - (event) => { - if (!entry.associateVal.includes(event.detail.path.join("."))) return; - const cls = entryContainerEl.classList; - const isShow = entry.auraIf(); - isShow - ? cls.remove("aura-settings-entry-hidden") - : cls.add("aura-settings-entry-hidden"); - } - ); + const evtListener = (event) => { + if (!entry.associateVal.includes(event.detail.path.join("."))) return; + const cls = entryContainerEl.classList; + const isShow = entry.auraIf(); + isShow + ? cls.remove("aura-settings-entry-hidden") + : cls.add("aura-settings-entry-hidden"); + }; + const channel = entry.PLSRequired + ? "onPLSConfigUpdate" + : "onHugoAuraConfigUpdate"; + entryContainerEl.addEventListener(channel, evtListener); + // createOnLeaveEvtListener(channel, evtListener); } formEl.appendChild(entryContainerEl); }; +const renderPreviewItem = (entry, formEl) => { + const elementId = entry.customId ? entry.customId : `${entry.id}Container`; + const eventChannel = entry.listenerType; + + const separateHrContainer = document.createElement("div"); + separateHrContainer.classList.add("aura-settings-preview-area-hr-container"); + + const hrTitle = document.createElement("p"); + hrTitle.textContent = "预览"; + + const hrElement = document.createElement("hr"); + hrElement.classList.add("aura-settings-preview-hr"); + + separateHrContainer.appendChild(hrElement); + separateHrContainer.appendChild(hrTitle); + separateHrContainer.appendChild(hrElement.cloneNode()); + + formEl.appendChild(separateHrContainer); + + const previewContainerEl = document.createElement("div"); + previewContainerEl.classList.add("aura-settings-preview-area-container"); + previewContainerEl.id = elementId; + + const eventListener = (event) => { + const childs = previewContainerEl.querySelectorAll("*"); + Array.from(childs).forEach((el) => { + el.dispatchEvent( + new CustomEvent("onAssociateValueUpdated", { detail: event.detail }) + ); + }); + }; + + document.addEventListener( + eventChannel === "pls" ? "onPLSConfigUpdate" : "onHugoAuraConfigUpdate", + eventListener + ); + createOnLeaveEvtListener(eventListener); // Clean up + + formEl.appendChild(previewContainerEl); + + setTimeout(() => { + global.__HUGO_AURA_LOADER__[entry.loaderTarget].active = true; + }, 50); +}; + +const renderChild = (entry, formEl) => { + switch (entry.type) { + case "preview": + renderPreviewItem(entry, formEl); + break; + default: + renderNormalSettingsItem(entry, formEl); + break; + } +}; + const settingsRenderer = (pendingEl, settingsObj) => { const formEl = document.createElement("form"); formEl.classList.add("aura-settings-form"); diff --git a/src/aura/ui/css/form.css b/src/aura/ui/css/form.css index d5e234d..08f67f3 100755 --- a/src/aura/ui/css/form.css +++ b/src/aura/ui/css/form.css @@ -65,6 +65,33 @@ border-bottom: 0.75px solid rgba(0, 0, 0, 0.25); } +.aura-settings-preview-area-hr-container { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; +} + +.aura-settings-preview-hr { + margin-top: 1.5rem; + margin-bottom: 1.5rem; + border-bottom: 0.75px solid rgba(0, 0, 0, 0.25); + width: -webkit-fill-available; +} + +.aura-settings-preview-area-hr-container p { + margin-left: 0.5rem; + margin-right: 0.5rem; + min-width: 2rem; + opacity: 0.75; + text-align: center; +} + +.aura-settings-preview-area-container { + width: 100%; + padding-bottom: 0.5rem; +} + .aura-settings-entry-property-icon { margin-left: 0.5rem; font-size: 15px; diff --git a/src/aura/ui/hookDefinitions/assistant.js b/src/aura/ui/hookDefinitions/assistant.js index 7030b26..4ae580d 100755 --- a/src/aura/ui/hookDefinitions/assistant.js +++ b/src/aura/ui/hookDefinitions/assistant.js @@ -21,41 +21,60 @@ const def = { pageSelector: "#root", selectorMode: "appendChild", pageCSS: "ui/pages/config/config.css", - }, - "Aura.UI.Assistant.Config.DisableLimitations": { - active: false, - pageURI: - "ui/pages/configSubPages/disableLimitations/disableLimitations.html", - pageScript: - "ui/pages/configSubPages/disableLimitations/disableLimitations.js", - pageSelector: ".aura-config-page-subpage-container", - selectorMode: "appendChild", - pageCSS: - "ui/pages/configSubPages/disableLimitations/disableLimitations.css", - }, - "Aura.UI.Assistant.Config.BehaviourCtrl": { - active: false, - pageURI: "ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.html", - pageScript: "ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.js", - pageSelector: ".aura-config-page-subpage-container", - selectorMode: "appendChild", - pageCSS: "ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.css", - }, - "Aura.UI.Assistant.Config.BehaviourCtrl.PlsStatus": { - active: false, - pageURI: "ui/pages/configSubPages/behaviourCtrl/plsStatus.html", - pageScript: "ui/pages/configSubPages/behaviourCtrl/plsStatus.js", - pageSelector: "#status-subpage", - selectorMode: "appendChild", - pageCSS: "ui/pages/configSubPages/behaviourCtrl/plsStatus.css", - }, - "Aura.UI.Assistant.Config.Preferences": { - active: false, - pageURI: "ui/pages/configSubPages/preferences/preferences.html", - pageScript: "ui/pages/configSubPages/preferences/preferences.js", - pageSelector: ".aura-config-page-subpage-container", - selectorMode: "appendChild", - pageCSS: "ui/pages/configSubPages/preferences/preferences.css", + childs: { + DisableLimitations: { + active: false, + pageURI: + "ui/pages/configSubPages/disableLimitations/disableLimitations.html", + pageScript: + "ui/pages/configSubPages/disableLimitations/disableLimitations.js", + pageSelector: ".aura-config-page-subpage-container", + selectorMode: "appendChild", + pageCSS: + "ui/pages/configSubPages/disableLimitations/disableLimitations.css", + }, + BehaviourCtrl: { + active: false, + pageURI: "ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.html", + pageScript: "ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.js", + pageSelector: ".aura-config-page-subpage-container", + selectorMode: "appendChild", + pageCSS: "ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.css", + childs: { + PlsStatus: { + active: false, + pageURI: "ui/pages/configSubPages/behaviourCtrl/plsStatus.html", + pageScript: "ui/pages/configSubPages/behaviourCtrl/plsStatus.js", + pageSelector: "#status-subpage", + selectorMode: "appendChild", + pageCSS: "ui/pages/configSubPages/behaviourCtrl/plsStatus.css", + }, + DeviceSecurity: { + childs: { + FreezeOverridePreview: { + active: false, + pageURI: + "ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.html", + pageScript: + "ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.js", + pageSelector: "#freezeInfoReportOverridePreviewContainer", + selectorMode: "appendChild", + pageCSS: + "ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.css", + }, + }, + }, + }, + }, + Preferences: { + active: false, + pageURI: "ui/pages/configSubPages/preferences/preferences.html", + pageScript: "ui/pages/configSubPages/preferences/preferences.js", + pageSelector: ".aura-config-page-subpage-container", + selectorMode: "appendChild", + pageCSS: "ui/pages/configSubPages/preferences/preferences.css", + }, + }, }, }, globalStyles: [ @@ -65,7 +84,11 @@ const def = { "ui/layui/css/layui.css", "ui/bootstrap/bootstrap.min.css", ], - globalJS: ["ui/js/global.js", "ui/js/plsListener.js", "ui/bootstrap/bootstrap.bundle.min.js"], + globalJS: [ + "ui/js/global.js", + "ui/js/plsListener.js", + "ui/bootstrap/bootstrap.bundle.min.js", + ], onLoaded: ` console.log('[HugoAura / UI / Hooks / Assistant] Page loaded.'); `, diff --git a/src/aura/ui/js/global.js b/src/aura/ui/js/global.js index bb02a08..efd4656 100755 --- a/src/aura/ui/js/global.js +++ b/src/aura/ui/js/global.js @@ -20,10 +20,24 @@ ); }; + const createOnLeaveEvtListener = ( + channel, + pendingRmEvtListener, + leaveEvt = "onCurConfigPageLeave" + ) => { + const rmEvtListener = (event) => { + document.removeEventListener(channel, pendingRmEvtListener); + document.removeEventListener(leaveEvt, rmEvtListener); + }; + document.addEventListener(leaveEvt, rmEvtListener); + return rmEvtListener; + }; + if (!window.__HUGO_AURA_GLOBAL__) window.__HUGO_AURA_GLOBAL__ = {}; window.__HUGO_AURA_GLOBAL__.utils = { sleep, refreshBsTooltip, + createOnLeaveEvtListener, }; })(); diff --git a/src/aura/ui/js/plsListener.js b/src/aura/ui/js/plsListener.js index 83cfb9e..9cf5ad5 100755 --- a/src/aura/ui/js/plsListener.js +++ b/src/aura/ui/js/plsListener.js @@ -14,13 +14,23 @@ `${IPC_METHOD_BASE}.post.onPlsStatsUpdate`, (_event, arg) => { global.__HUGO_AURA__.plsStats = arg; - document.dispatchEvent( - new CustomEvent("onPLSStatsUpdate", { - detail: { - connected: arg.connected, - }, - }) + + const event = new CustomEvent("onPLSStatsUpdate", { + detail: { + connected: arg.connected, + }, + }); + + document.dispatchEvent(event); + + const settingsEntries = document.getElementsByClassName( + "aura-settings-entry" ); + if (settingsEntries.length > 0) { + Array.from(settingsEntries).forEach((entry) => { + entry.dispatchEvent(event); + }); + } } ); @@ -28,14 +38,24 @@ `${IPC_METHOD_BASE}.post.onPlsSettingsUpdate`, (_event, arg) => { global.__HUGO_AURA__.plsSettings = arg; - document.dispatchEvent( - new CustomEvent("onPLSConfigUpdate", { - detail: { - path: ["root", "settings"], - value: arg, - }, - }) + + const event = new CustomEvent("onPLSConfigUpdate", { + detail: { + path: ["root", "settings"], + value: arg, + }, + }); + + document.dispatchEvent(event); + + const settingsEntries = document.getElementsByClassName( + "aura-settings-entry" ); + if (settingsEntries.length > 0) { + Array.from(settingsEntries).forEach((entry) => { + entry.dispatchEvent(event); + }); + } } ); @@ -43,27 +63,38 @@ `${IPC_METHOD_BASE}.post.onPlsRulesUpdate`, (_event, arg) => { global.__HUGO_AURA__.plsRules = arg; - document.dispatchEvent( - new CustomEvent("onPLSConfigUpdate", { - detail: { - path: ["root", "ruleSettings"], - value: arg, - }, - }) + + const event = new CustomEvent("onPLSConfigUpdate", { + detail: { + path: ["root", "ruleSettings"], + value: arg, + }, + }); + + document.dispatchEvent(event); + + const settingsEntries = document.getElementsByClassName( + "aura-settings-entry" ); + if (settingsEntries.length > 0) { + Array.from(settingsEntries).forEach((entry) => { + entry.dispatchEvent(event); + }); + } } ); ipcRenderer.on( `${IPC_METHOD_BASE}.post.updateRetryStatus`, (_event, arg) => { - document.dispatchEvent( - new CustomEvent("onPLSStatsUpdate", { - detail: { - connected: arg.success, - }, - }) - ); + const event = new CustomEvent("onPLSStatsUpdate", { + detail: { + connected: arg.success, + }, + }); + + document.dispatchEvent(event); + if ( global.__HUGO_AURA_LOADER__["Aura.UI.Assistant.Config.BehaviourCtrl"] .active diff --git a/src/aura/ui/pages/config/config.js b/src/aura/ui/pages/config/config.js index 8c156d5..441f4ed 100755 --- a/src/aura/ui/pages/config/config.js +++ b/src/aura/ui/pages/config/config.js @@ -23,6 +23,8 @@ global.__HUGO_AURA_UI_FUNCTIONS__.config = { global.__HUGO_AURA_UI_REACTIVES__.config.currentActiveSubPage, false ); + const onLeaveEvent = new CustomEvent("onCurConfigPageLeave"); + document.dispatchEvent(onLeaveEvent); } else { global.__HUGO_AURA_UI_FUNCTIONS__.config.hideConfigPage(); } diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.js b/src/aura/ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.js index 5eee61a..ba3cf5f 100755 --- a/src/aura/ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.js +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.js @@ -7,6 +7,7 @@ } = require(`${REQUIRE_BASE}/../../../../composables/settingsRenderer`); const { basicSettings } = require(`${REQUIRE_BASE}/basic`); + const { deviceSecuritySettings } = require(`${REQUIRE_BASE}/deviceSecurity`); const { updatePlsSettingsFromLocal, @@ -24,19 +25,27 @@ settingsRenderer(basicSubPageEl, basicSettings); }; + const initDeviceSecuritySettingsPage = () => { + const deviceSecuritySubPageEl = document.getElementById( + "security-config-subpage" + ); + settingsRenderer(deviceSecuritySubPageEl, deviceSecuritySettings); + }; + const renderSubPages = async () => { await updatePlsSettingsFromLocal(); await updatePlsRulesFromLocal(); initBasicSettingsPage(); + initDeviceSecuritySettingsPage(); }; const onMounted = () => { const rootEl = document.getElementById("acs-behaviour-control-el"); initStatusPage(); - renderSubPages(); setTimeout(() => { rootEl.classList.remove("acs-behaviour-control-hidden"); + renderSubPages(); // 如果立即渲染子页面, 此时 plsRules 还未初始化, 会导致子页面 auraIf 失效 }, 500); }; diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.js b/src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.js index 4720b94..5a1e977 100755 --- a/src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.js +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.js @@ -655,9 +655,15 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) initBsTooltip(); GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", false); GLOBAL_FUNCTIONS.refreshPlsStatus(true); - document.addEventListener("onPLSStatsUpdate", () => { + + const eventListener = () => { GLOBAL_FUNCTIONS.updateStatusContent(); - }); + }; + document.addEventListener("onPLSStatsUpdate", eventListener); + global.__HUGO_AURA_GLOBAL__.utils.createOnLeaveEvtListener( + "onPLSStatsUpdate", + eventListener + ); }; onMounted(); diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/deviceSecurity.js b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/deviceSecurity.js new file mode 100644 index 0000000..76b3adf --- /dev/null +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/deviceSecurity.js @@ -0,0 +1,93 @@ +const REQUIRE_BASE = "."; + +const { + updatePlsConfigToRemote, +} = require(`${REQUIRE_BASE}/../../../../composables/plsConfigManager`); + +const composables = {}; + +const deviceSecuritySettings = [ + { + id: 0, + categoryName: "冰点管理", + child: [ + { + index: 0, + id: "enableFreezeInfoReportOverride", + type: "switch", + name: "启用冰冻状态篡改", + description: "篡改上报的冰冻数据, 可自定义集控端显示的状态", + reactive: true, + reactiveVal: ["root.ruleSettings"], + restart: false, + reload: false, + PLSRequired: true, + restartPLS: false, + associateVal: null, + auraIf: () => true, + defaultValue: false, + valueGetter: () => { + if (!global.__HUGO_AURA__.plsRules) return ""; + return global.__HUGO_AURA__.plsRules.client.security.uploadFreezeInfo + .enable; + }, + callbackFn: (newVal) => { + if (typeof newVal !== "boolean") return; + + global.__HUGO_AURA__.plsRules.client.security.uploadFreezeInfo.enable = + newVal; + updatePlsConfigToRemote( + "ruleSettings.client.security.uploadFreezeInfo.enable", + newVal + ); + return true; + }, + }, + { + index: 1, + id: "freezeInfoReportOverrideType", + type: "radio", + name: "篡改模式", + description: "选择一种篡改模式, 选中的磁盘范围会被上报为冻结 (不是实际行为)", + restart: false, + reload: false, + PLSRequired: true, + restartPLS: false, + reactive: true, + reactiveVal: ["root.ruleSettings"], + associateVal: ["ruleSettings.client.security.uploadFreezeInfo.enable"], + auraIf: () => { + return global.__HUGO_AURA__.plsRules.client.security.uploadFreezeInfo + .enable; + }, + defaultValue: "allFreeze", + templates: ["allFreeze", "systemOnly", "exceptSecondDisk"], + templateLabels: ["全部冻结", "仅系统盘", "仅第二磁盘"], + valueGetter: () => { + return global.__HUGO_AURA__.plsRules.client.security.uploadFreezeInfo + .rewriteMode; + }, + callbackFn: (newVal) => { + global.__HUGO_AURA__.plsRules.client.security.uploadFreezeInfo.rewriteMode = + newVal; + updatePlsConfigToRemote( + "ruleSettings.client.security.uploadFreezeInfo.rewriteMode", + newVal + ); + return true; + }, + }, + { + index: 2, + id: "freezeInfoReportOverridePreview", + type: "preview", + loaderTarget: + "Aura.UI.Assistant.Config.BehaviourCtrl.DeviceSecurity.FreezeOverridePreview", + associateVal: ["ruleSettings.client.security.uploadFreezeInfo"], + listenerType: "pls" + }, + ], + }, +]; + +module.exports = { deviceSecuritySettings }; diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.css b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.css new file mode 100644 index 0000000..96f4bb9 --- /dev/null +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.css @@ -0,0 +1,100 @@ +.acs-bc-dsc-fop-container { + display: flex; +} + +.acs-bc-dsc-fop-please-wait, +.acs-bc-dsc-fop-on-req-error, +.acs-bc-dsc-fop-on-not-bind { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + + width: 100%; + height: 100%; + opacity: 0.6; +} + +.acs-bc-dsc-fop-please-wait svg, +.acs-bc-dsc-fop-on-req-error svg, +.acs-bc-dsc-fop-on-not-bind svg { + width: 18px; + height: 18px; +} + +.acs-bc-dsc-fop-please-wait p, +.acs-bc-dsc-fop-on-req-error p, +.acs-bc-dsc-fop-on-not-bind p { + margin-left: 0.5rem; + margin-top: -1px; +} + +.acs-bc-dsc-fop-please-wait[auraIf="false"], +.acs-bc-dsc-fop-on-req-error[auraIf="false"], +.acs-bc-dsc-fop-on-not-bind[auraIf="false"], +.acs-bc-dsc-fop-main[auraIf="false"] { + display: none; +} + +.acs-bc-dsc-fop-main { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100%; +} + +.acs-bc-dsc-fop-main .disks-container { + display: flex; + flex-direction: row; +} + +.acs-bc-dsc-fop-disk-el { + padding: 5px 10px; + border-radius: 3px; + border: 0.5px solid rgba(0, 0, 0, 0.25); + margin-left: 0.375rem; + margin-right: 0.375rem; + + /* transition: all 0.5s; */ + /* 没有用, 因为元素全被重新创建了 */ +} + +.acs-bc-dsc-fop-disk-el.active { + background-color: #1d70f2; + color: white; + border: 0.5px solid rgba(0, 0, 0, 0.125); +} + +.acs-bc-dsc-fop-main-hint-area { + display: flex; + flex-direction: row; + margin-top: 1rem; + margin-bottom: -0.25rem; +} + +.acs-bc-dsc-fop-main-hint-area svg { + width: 18px; + height: 18px; +} + +.acs-bc-dsc-fop-main-hint-area div { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; +} + +.acs-bc-dsc-fop-main-hint-area p { + margin-top: -1px; + margin-left: 0.25rem; +} + +.acs-bc-dsc-fop-main-hint-area .acs-bc-dsc-fop-main-hint-freeze { + margin-right: 0.5rem; + color: #1d70f2; +} + +.acs-bc-dsc-fop-main-hint-area .acs-bc-dsc-fop-main-hint-unfreeze { + margin-left: 0.5rem; +} diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.html b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.html new file mode 100644 index 0000000..cc829aa --- /dev/null +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.html @@ -0,0 +1,91 @@ +
+
+ + + + + +

请稍候...

+
+ +
+ + + + + +

获取磁盘信息失败:

+
+ +
+ + + + + + + +

当前设备暂未绑定学校, 无法查询冰点信息

+
+ +
+
+

C 盘

+
+ +
+
+ + + +

已冻结

+
+
+ + + +

未冻结

+
+
+
+
diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.js b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.js new file mode 100644 index 0000000..5322db5 --- /dev/null +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.js @@ -0,0 +1,156 @@ +// @ts-check + +(() => { + const REQUIRE_BASE = "../.."; + const { genRandomHex } = require(`${REQUIRE_BASE}/aura/utils/crypto`); + + const composables = { + getAndUpdateDiskInfo: async (curConfig) => { + const progressingEl = document.getElementsByClassName( + "acs-bc-dsc-fop-please-wait" + )[0]; + const onErrorEl = document.getElementsByClassName( + "acs-bc-dsc-fop-on-req-error" + )[0]; + const onNotBindEl = document.getElementsByClassName( + "acs-bc-dsc-fop-on-not-bind" + )[0]; + const mainEl = document.getElementsByClassName("acs-bc-dsc-fop-main")[0]; + const diskContainerEl = + document.getElementsByClassName("disks-container")[0]; + + const seewoProxyPort = window._ACCEPT_DATA.data.ports.SeewoProxyHTTP; + + const reqPromise = new Promise((resolve) => { + fetch( + `https://127.0.0.1:${seewoProxyPort}/forward/freeze/api/v1/get_disk_data`, + { + headers: { + accept: "application/json, text/plain, */*", + "X-Auth-Traceid": genRandomHex(), + }, + } + ) + .then(async (response) => { + const parsedData = await response.json(); + + resolve({ + success: true, + data: parsedData, + status: response.status, + }); + }) + .catch((e) => { + resolve({ success: false, data: null, errorObj: e }); + }); + }); + + const responseInfo = await reqPromise; + + progressingEl.setAttribute("auraIf", "false"); + + if (!responseInfo.success) { + onNotBindEl.setAttribute("auraIf", "false"); + mainEl.setAttribute("auraIf", "false"); + onErrorEl.setAttribute("auraIf", "true"); + const detailEl = document.getElementById("acsBcDscFopOnReqErrorDetail"); + // @ts-expect-error + detailEl.textContent = responseInfo.errorObj; + + return; + } + + if (responseInfo.status !== 200) { + onErrorEl.setAttribute("auraIf", "false"); + mainEl.setAttribute("auraIf", "false"); + onNotBindEl.setAttribute("auraIf", "true"); + return; + } + + diskContainerEl.innerHTML = ``; + + const curDisks = []; + for (const disk of responseInfo.data.data[0].disksData) { + curDisks.push({ name: disk.diskName, status: disk.protectedStatus }); + } + + const diskElTemplate = document.createElement("p"); + diskElTemplate.classList.add("acs-bc-dsc-fop-disk-el"); + if (!curConfig.enable) { + for (const disk of curDisks) { + const curDiskEl = diskElTemplate.cloneNode(); + if (disk.status !== 0) { + // @ts-expect-error + curDiskEl.classList.add("active"); + } + curDiskEl.textContent = `${disk.name.toUpperCase()} 盘`; + diskContainerEl.appendChild(curDiskEl); + } + } else { + switch (curConfig.rewriteMode) { + case "allFreeze": + { + for (const disk of curDisks) { + const curDiskEl = diskElTemplate.cloneNode(); + // @ts-expect-error + curDiskEl.classList.add("active"); + curDiskEl.textContent = `${disk.name.toUpperCase()} 盘`; + diskContainerEl.appendChild(curDiskEl); + } + } + break; + case "systemOnly": + { + let idx = 0; + for (const disk of curDisks) { + const curDiskEl = diskElTemplate.cloneNode(); + // @ts-expect-error + if (idx === 0) curDiskEl.classList.add("active"); + curDiskEl.textContent = `${disk.name.toUpperCase()} 盘`; + diskContainerEl.appendChild(curDiskEl); + idx += 1; + } + } + break; + case "exceptSecondDisk": + { + let idx = 0; + for (const disk of curDisks) { + const curDiskEl = diskElTemplate.cloneNode(); + // @ts-expect-error + if (idx === 0) curDiskEl.classList.add("active"); + curDiskEl.textContent = `${disk.name.toUpperCase()} 盘`; + diskContainerEl.appendChild(curDiskEl); + idx += 1; + } + } + break; + } + } + + onErrorEl.setAttribute("auraIf", "false"); + onNotBindEl.setAttribute("auraIf", "false"); + mainEl.setAttribute("auraIf", "true"); + }, + }; + + const onMounted = () => { + const rootEl = document.getElementsByClassName( + "acs-bc-dsc-fop-container" + )[0]; + + const eventListener = (_event) => { + if (!global.__HUGO_AURA__.plsRules) return; + composables.getAndUpdateDiskInfo( + global.__HUGO_AURA__.plsRules.client.security.uploadFreezeInfo + ); + }; + rootEl.addEventListener("onAssociateValueUpdated", eventListener); + + setTimeout(() => { + eventListener(); + }, 100); + }; + + onMounted(); +})(); diff --git a/src/core/preload.js b/src/core/preload.js index 3b1766a..a82e2f3 100755 --- a/src/core/preload.js +++ b/src/core/preload.js @@ -63,6 +63,15 @@ const __AURA_VERSION__ = "0.1.1-pre-IV"; }); const pathName = [...path, prop].join("."); document.dispatchEvent(configUpdateEvent); + + const settingsEntries = document.getElementsByClassName( + "aura-settings-entry" + ); + if (settingsEntries.length > 0) { + Array.from(settingsEntries).forEach((entry) => { + entry.dispatchEvent(configUpdateEvent); + }); + } console.log( `[HugoAura / Config] Config changed at path: ${[...path, prop].join( "."