From 5d2b60af56a68a083b7773a23f09cfb511098624 Mon Sep 17 00:00:00 2001 From: QLHazyCoder <2825305047@qq.com> Date: Tue, 21 Apr 2026 02:16:45 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E5=92=8C=E5=8F=96=E6=B6=88=E7=BC=96=E8=BE=91=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E5=88=B02925=E9=82=AE=E7=AE=B1=E7=AE=A1=E7=90=86=E5=99=A8?= =?UTF-8?q?=EF=BC=8C=E6=9B=B4=E6=96=B0=E7=9B=B8=E5=85=B3UI=E5=92=8C?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sidepanel/mail-2925-manager.js | 57 ++++++++++++++- sidepanel/sidepanel.html | 7 +- sidepanel/sidepanel.js | 2 + tests/sidepanel-contribution-button.test.js | 1 + tests/sidepanel-mail2925-edit.test.js | 81 +++++++++++++++++++++ tests/sidepanel-mail2925-manager.test.js | 1 + 6 files changed, 144 insertions(+), 5 deletions(-) create mode 100644 tests/sidepanel-mail2925-edit.test.js diff --git a/sidepanel/mail-2925-manager.js b/sidepanel/mail-2925-manager.js index fcb6918..e7793b8 100644 --- a/sidepanel/mail-2925-manager.js +++ b/sidepanel/mail-2925-manager.js @@ -15,6 +15,7 @@ let actionInFlight = false; let listExpanded = false; + let editingAccountId = ''; function getMail2925Accounts(currentState = state.getLatestState()) { return helpers.getMail2925Accounts(currentState); @@ -93,7 +94,7 @@ } } - function applyMail2925AccountMutation(account, options = {}) { + function applyMail2925AccountMutation(account) { if (!account?.id) return; const latestState = state.getLatestState(); const currentId = getCurrentMail2925AccountId(latestState); @@ -117,6 +118,32 @@ if (dom.inputMail2925Password) dom.inputMail2925Password.value = ''; } + function syncEditUi() { + if (dom.btnAddMail2925Account) { + dom.btnAddMail2925Account.textContent = editingAccountId ? '保存修改' : '添加账号'; + } + if (dom.btnCancelMail2925Edit) { + dom.btnCancelMail2925Edit.style.display = editingAccountId ? '' : 'none'; + } + } + + function startEditingAccount(account) { + if (!account?.id) return; + editingAccountId = account.id; + if (dom.inputMail2925Email) dom.inputMail2925Email.value = String(account.email || '').trim(); + if (dom.inputMail2925Password) dom.inputMail2925Password.value = String(account.password || ''); + syncEditUi(); + } + + function stopEditingAccount(options = {}) { + const { clearForm = true } = options; + editingAccountId = ''; + if (clearForm) { + clearMail2925Form(); + } + syncEditUi(); + } + function renderMail2925Accounts() { if (!dom.mail2925AccountsList) return; @@ -160,6 +187,7 @@
+ ${coolingDown ? `` : ''} @@ -185,6 +213,7 @@ return; } + const updatingExisting = Boolean(editingAccountId); actionInFlight = true; if (dom.btnAddMail2925Account) { dom.btnAddMail2925Account.disabled = true; @@ -195,6 +224,7 @@ type: 'UPSERT_MAIL2925_ACCOUNT', source: 'sidepanel', payload: { + ...(editingAccountId ? { id: editingAccountId } : {}), email, password, }, @@ -204,8 +234,14 @@ } applyMail2925AccountMutation(response.account); - clearMail2925Form(); - helpers.showToast(`已保存 2925 账号 ${email}`, 'success', 1800); + stopEditingAccount(); + helpers.showToast( + updatingExisting + ? `已更新 2925 账号 ${email}` + : `已保存 2925 账号 ${email}`, + 'success', + 1800 + ); } catch (err) { helpers.showToast(`保存 2925 账号失败:${err.message}`, 'error'); } finally { @@ -296,6 +332,7 @@ mail2925Accounts: [], currentMail2925AccountId: null, }); + stopEditingAccount(); refreshManagedAliasBaseEmail(); renderMail2925Accounts(); helpers.showToast(`已删除全部 ${response.deletedCount || 0} 个 2925 账号`, 'success', 2200); @@ -356,6 +393,13 @@ return; } + if (action === 'edit') { + if (!targetAccount) throw new Error('未找到目标 2925 账号。'); + startEditingAccount(targetAccount); + helpers.showToast(`已载入 ${targetAccount.email},修改后点“保存修改”即可`, 'info', 1800); + return; + } + if (action === 'toggle-enabled') { if (!targetAccount) throw new Error('未找到目标 2925 账号。'); const response = await runtime.sendMessage({ @@ -415,6 +459,9 @@ nextState.currentMail2925AccountId = null; } state.syncLatestState(nextState); + if (editingAccountId === accountId) { + stopEditingAccount(); + } refreshManagedAliasBaseEmail(); renderMail2925Accounts(); helpers.showToast('2925 账号已删除', 'success', 1800); @@ -446,8 +493,12 @@ }); dom.btnAddMail2925Account?.addEventListener('click', handleAddMail2925Account); + dom.btnCancelMail2925Edit?.addEventListener('click', () => { + stopEditingAccount(); + }); dom.btnImportMail2925Accounts?.addEventListener('click', handleImportMail2925Accounts); dom.mail2925AccountsList?.addEventListener('click', handleAccountListClick); + syncEditUi(); } return { diff --git a/sidepanel/sidepanel.html b/sidepanel/sidepanel.html index 1127659..2fcd6ee 100644 --- a/sidepanel/sidepanel.html +++ b/sidepanel/sidepanel.html @@ -35,7 +35,7 @@
+ aria-pressed="false" title="进入贡献模式">贡献/使用
- +
+ + +
批量导入 diff --git a/sidepanel/sidepanel.js b/sidepanel/sidepanel.js index e9d8e84..cbf201c 100644 --- a/sidepanel/sidepanel.js +++ b/sidepanel/sidepanel.js @@ -155,6 +155,7 @@ const inputMail2925Email = document.getElementById('input-mail2925-email'); const inputMail2925Password = document.getElementById('input-mail2925-password'); const inputMail2925Import = document.getElementById('input-mail2925-import'); const btnAddMail2925Account = document.getElementById('btn-add-mail2925-account'); +const btnCancelMail2925Edit = document.getElementById('btn-cancel-mail2925-edit'); const btnImportMail2925Accounts = document.getElementById('btn-import-mail2925-accounts'); const btnDeleteAllMail2925Accounts = document.getElementById('btn-delete-all-mail2925-accounts'); const btnToggleMail2925List = document.getElementById('btn-toggle-mail2925-list'); @@ -3040,6 +3041,7 @@ const mail2925Manager = window.SidepanelMail2925Manager?.createMail2925Manager({ }, dom: { btnAddMail2925Account, + btnCancelMail2925Edit, btnDeleteAllMail2925Accounts, btnImportMail2925Accounts, btnToggleMail2925List, diff --git a/tests/sidepanel-contribution-button.test.js b/tests/sidepanel-contribution-button.test.js index 54152ac..d9976d3 100644 --- a/tests/sidepanel-contribution-button.test.js +++ b/tests/sidepanel-contribution-button.test.js @@ -8,6 +8,7 @@ test('sidepanel html keeps a single contribution mode button in header', () => { assert.equal(matches.length, 1); assert.match(html, /id="btn-contribution-mode"[^>]*title="进入贡献模式"/); + assert.match(html, />贡献\/使用<\/button>/); }); test('sidepanel source no longer keeps the legacy upload-page handler on the header contribution button', () => { diff --git a/tests/sidepanel-mail2925-edit.test.js b/tests/sidepanel-mail2925-edit.test.js new file mode 100644 index 0000000..99221f8 --- /dev/null +++ b/tests/sidepanel-mail2925-edit.test.js @@ -0,0 +1,81 @@ +const test = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('node:fs'); + +test('sidepanel html contains cancel edit button for mail2925 form', () => { + const html = fs.readFileSync('sidepanel/sidepanel.html', 'utf8'); + assert.match(html, /id="btn-cancel-mail2925-edit"/); +}); + +test('mail2925 manager renders edit action for existing accounts', () => { + const source = fs.readFileSync('sidepanel/mail-2925-manager.js', 'utf8'); + const windowObject = {}; + const localStorageMock = { + getItem() { + return null; + }, + setItem() {}, + }; + + const api = new Function('window', 'localStorage', `${source}; return window.SidepanelMail2925Manager;`)( + windowObject, + localStorageMock + ); + + const mail2925AccountsList = { innerHTML: '', addEventListener() {} }; + const manager = api.createMail2925Manager({ + state: { + getLatestState: () => ({ + currentMail2925AccountId: 'acc-1', + mail2925Accounts: [{ + id: 'acc-1', + email: 'demo@2925.com', + password: 'secret', + enabled: true, + lastLoginAt: 0, + lastUsedAt: 0, + lastLimitAt: 0, + disabledUntil: 0, + lastError: '', + }], + }), + syncLatestState() {}, + }, + dom: { + btnAddMail2925Account: { textContent: '', disabled: false, addEventListener() {} }, + btnCancelMail2925Edit: { style: { display: 'none' }, addEventListener() {} }, + btnDeleteAllMail2925Accounts: { textContent: '', disabled: false, addEventListener() {} }, + btnImportMail2925Accounts: { disabled: false, addEventListener() {} }, + btnToggleMail2925List: { textContent: '', disabled: false, setAttribute() {}, addEventListener() {} }, + inputMail2925Email: { value: '' }, + inputMail2925Import: { value: '' }, + inputMail2925Password: { value: '' }, + mail2925AccountsList, + mail2925ListShell: { classList: { toggle() {} } }, + }, + helpers: { + getMail2925Accounts: (state) => state.mail2925Accounts || [], + escapeHtml: (value) => String(value || ''), + showToast() {}, + openConfirmModal: async () => true, + copyTextToClipboard: async () => {}, + refreshManagedAliasBaseEmail() {}, + }, + runtime: { + sendMessage: async () => ({}), + }, + constants: { + copyIcon: '', + displayTimeZone: 'Asia/Shanghai', + expandedStorageKey: 'multipage-mail2925-list-expanded', + }, + mail2925Utils: { + getMail2925AccountStatus: () => 'ready', + getMail2925ListToggleLabel: () => '展开列表(1)', + upsertMail2925AccountInList: (_accounts, nextAccount) => [nextAccount], + }, + }); + + manager.renderMail2925Accounts(); + assert.match(mail2925AccountsList.innerHTML, /data-account-action="edit"/); +}); diff --git a/tests/sidepanel-mail2925-manager.test.js b/tests/sidepanel-mail2925-manager.test.js index 10e3108..40d2efa 100644 --- a/tests/sidepanel-mail2925-manager.test.js +++ b/tests/sidepanel-mail2925-manager.test.js @@ -17,6 +17,7 @@ test('sidepanel html contains mail2925 pool toggle and selector controls', () => assert.match(html, /id="input-mail2925-use-account-pool"/); assert.match(html, /id="select-mail2925-pool-account"/); + assert.match(html, /id="btn-cancel-mail2925-edit"/); }); test('mail2925 manager exposes a factory and renders empty state', () => {