app · e4d6054

Dev index Recent changes / versions Changelog About TODO

fix(monitor): Raw Socket 記住使用者與圖片偏好

e4d6054 · 2026-11-11 01:13 · app
Docs/ChangeHistory.mdTest/monitor_audience_ui.cjsassets/app.css.build.jsonassets/monitor.js
commit e4d6054f8818d02319768d810a173e7af63a8238Author: Nuclear0709 <agp05432@gmail.com>Date:   Wed Nov 11 01:13:16 2026 +0800     fix(monitor): Raw Socket 記住使用者與圖片偏好        - raw prefs 保存 user/image/gift,重新整理後恢復並預覽    - MediaCache/emoji 選擇立即寫入偏好    - 清除測試設定同步清除 raw prefs    - UI 測試補圖片持久化 diff --git a/Docs/ChangeHistory.md b/Docs/ChangeHistory.mdindex 3d9e438..41eabd6 100644--- a/Docs/ChangeHistory.md+++ b/Docs/ChangeHistory.md@@ -11,7 +11,10 @@ - 選 emoji 使用目前 `/api/emoji/preview` 的 URL。 - AdOverlay 模式下同一選擇會同步填入 iconURL。 - Raw 圖片欄新增 HTTP(S)/data URI 預覽,選單選擇後立即更新。-- UI 測試補 Raw 圖片選單與預覽。+- Raw Socket 的使用者名稱與圖片/禮物欄位會存到 `ttw-monitor-raw-prefs`,重新整理後自動帶回;流程測試沿用原本的 `ttw-monitor-test-prefs`。+- MediaCache/emoji 選單選到的頭貼也會一併記憶。+- 「清除測試設定」會同時清除兩份使用者偏好。+- UI 測試補 Raw 圖片選單、預覽與使用者名稱持久化。  ### 驗證 diff --git a/Test/monitor_audience_ui.cjs b/Test/monitor_audience_ui.cjsindex 682c450..62cee3d 100644--- a/Test/monitor_audience_ui.cjs+++ b/Test/monitor_audience_ui.cjs@@ -180,6 +180,9 @@ async function main() {             const image = document.querySelector('#monRawImagePreview');             return image && !image.hidden && image.src.endsWith('/emoji.png');         });+        await page.evaluate(() => { document.querySelector('#monRawPanel').open = true; });+        await page.type('#monRawUser', 'Raw User');+        assert.equal(await page.$eval('#monRawUser', node => node.value), 'Raw User');         await page.waitForFunction(() => {             const image = document.querySelector('#monTestAvatarPreview');             return image && !image.hidden && image.src.endsWith('/emoji.png');@@ -244,6 +247,8 @@ async function main() {         assert.notEqual(posts[1].data.testId, posts[0].data.testId);         assert.match(await page.$eval('#monTestStatus', node => node.textContent), /去重保護/); +        const rawPrefsBeforeReload = await page.evaluate(() => localStorage.getItem('ttw-monitor-raw-prefs'));+        assert.match(rawPrefsBeforeReload || '', /Raw User/);         await page.reload({ waitUntil: 'load' });         await page.waitForFunction(() => document.querySelectorAll('#monTestCategory option').length >= 2);         await page.evaluate(() => { document.querySelector('#monTestPanel').open = true; });@@ -251,6 +256,12 @@ async function main() {             const image = document.querySelector('#monTestAvatarPreview');             return image && !image.hidden && image.src.endsWith('/avatar.png');         });+        assert.equal(await page.$eval('#monRawUser', node => node.value), 'Raw User');+        assert.equal(await page.$eval('#monRawImage', node => node.value), rawEmoji);+        await page.waitForFunction(() => {+            const image = document.querySelector('#monRawImagePreview');+            return image && !image.hidden && image.src.endsWith('/emoji.png');+        });         const restored = await page.evaluate(() => ({             user: document.querySelector('#monTestUser').value,             avatar: document.querySelector('#monTestAvatar').value,diff --git a/assets/app.css.build.json b/assets/app.css.build.jsonindex 0feb633..17f3217 100644--- a/assets/app.css.build.json+++ b/assets/app.css.build.json@@ -1,5 +1,5 @@ {   "schema": 2,-  "inputHash": "2fb160324cbdeec2df88a8bb855e3bb50e01fb4d01f6ef3b9362c1269597add5",+  "inputHash": "d5695138279146aa1fca53e5fda83ba8441f95737fedabfa82f6ffba142846f4",   "outputHash": "5e8e8ac9b7a490acf78fc06ee9e9c0e63e69a0a32e695f93025dce6a24930dce" }diff --git a/assets/monitor.js b/assets/monitor.jsindex cc4b1c9..6a25580 100644--- a/assets/monitor.js+++ b/assets/monitor.js@@ -93,6 +93,7 @@     const rawSend = document.getElementById('monRawSend');     const rawStatus = document.getElementById('monRawStatus');     const TEST_PREFS_KEY = 'ttw-monitor-test-prefs';+    const RAW_PREFS_KEY = 'ttw-monitor-raw-prefs';      let emojiMap = null;     let emojiPattern = null;@@ -388,6 +389,31 @@         } catch { /* 無痕模式或儲存額度不足時不影響測試 */ }     } +    function loadRawPrefs() {+        try {+            const data = JSON.parse(localStorage.getItem(RAW_PREFS_KEY) || 'null');+            return data && typeof data === 'object' ? data : null;+        } catch { return null; }+    }++    function saveRawPrefs() {+        try {+            localStorage.setItem(RAW_PREFS_KEY, JSON.stringify({+                user: rawUser.value,+                image: rawImage.value,+                gift: rawGift.value+            }));+        } catch { /* ignore */ }+    }++    function restoreRawPrefs() {+        const saved = loadRawPrefs();+        if (!saved) return;+        if (typeof saved.user === 'string') rawUser.value = saved.user;+        if (typeof saved.image === 'string') rawImage.value = saved.image;+        if (typeof saved.gift === 'string') rawGift.value = saved.gift;+    }+     function restoreTestPrefs() {         if (!savedTestPrefs) return;         if (typeof savedTestPrefs.user === 'string') testUser.value = savedTestPrefs.user;@@ -478,7 +504,12 @@         clearTestPending();         clearTestCooldown();         try { localStorage.removeItem(TEST_PREFS_KEY); } catch { /* ignore */ }+        try { localStorage.removeItem(RAW_PREFS_KEY); } catch { /* ignore */ }         savedTestPrefs = null;+        rawUser.value = '';+        rawImage.value = '';+        rawGift.value = '';+        rawImagePick.value = '';         testUser.value = '';         testAvatar.value = '';         testAvatarPick.value = '';@@ -489,6 +520,7 @@         testSocket.checked = true;         testNotify.checked = false;         updateAvatarPreview();+        updateRawImagePreview();         setTestStatus(t('monitor.test.cleared', {}, '已清除測試設定。'));     } @@ -1192,15 +1224,21 @@         if (!rawImagePick.value) return;         rawImage.value = rawImagePick.value;         if (rawType.value === 'AdOverlay') rawGift.value = rawImagePick.value;+        saveRawPrefs();+        updateRawImagePreview();+    });+    rawImage.addEventListener('input', () => {+        saveRawPrefs();         updateRawImagePreview();     });-    rawImage.addEventListener('input', updateRawImagePreview);+    rawGift.addEventListener('input', saveRawPrefs);     rawSend.addEventListener('click', sendRawSocketTest);      testAdd.addEventListener('click', addTestMessage);     testSend.addEventListener('click', sendSocketTest);     testClear.addEventListener('click', clearTestPrefs);     testUser.addEventListener('input', saveTestPrefs);+    rawUser.addEventListener('input', saveRawPrefs);     testAvatar.addEventListener('input', () => { saveTestPrefs(); updateAvatarPreview(); });     testPlatform.addEventListener('change', saveTestPrefs);     testCategory.addEventListener('change', saveTestPrefs);@@ -1237,6 +1275,7 @@     applyTestI18n();     buildTestCategories();     restoreTestPrefs();+    restoreRawPrefs();     restoreTestCategory();     updateAvatarPreview();     updateCount();