(function attachSidepanelLuckmailManager(globalScope) { function createLuckmailManager(context = {}) { const { dom, helpers, runtime, constants = {}, } = context; const copyIcon = constants.copyIcon || ''; let renderedPurchases = []; let selectedPurchaseIds = new Set(); let searchTerm = ''; let filterMode = 'all'; let refreshQueued = false; function normalizeLuckmailSearchText(value) { return String(value || '').trim().toLowerCase(); } function getFilteredLuckmailPurchases(purchases = renderedPurchases) { const normalizedSearchTerm = normalizeLuckmailSearchText(searchTerm); return (Array.isArray(purchases) ? purchases : []).filter((purchase) => { const matchesFilter = (() => { switch (filterMode) { case 'reusable': return Boolean(purchase.reusable); case 'used': return Boolean(purchase.used); case 'unused': return !purchase.used; case 'preserved': return Boolean(purchase.preserved); case 'disabled': return Boolean(purchase.disabled); default: return true; } })(); if (!matchesFilter) return false; if (!normalizedSearchTerm) return true; const haystack = [ purchase.email_address, purchase.project_name, purchase.tag_name, purchase.used ? '已用 used' : '未用 unused', purchase.preserved ? '保留 preserved' : '', purchase.disabled ? '已禁用 disabled' : '', purchase.reusable ? '可复用 reusable' : '', ].join(' ').toLowerCase(); return haystack.includes(normalizedSearchTerm); }); } function pruneLuckmailSelection(purchases = renderedPurchases) { const existingIds = new Set((Array.isArray(purchases) ? purchases : []).map((purchase) => String(purchase.id))); selectedPurchaseIds = new Set([...selectedPurchaseIds].filter((id) => existingIds.has(id))); } function updateLuckmailBulkUI(visiblePurchases = getFilteredLuckmailPurchases()) { if (!dom.checkboxLuckmailSelectAll || !dom.luckmailSelectionSummary) { return; } const visibleIds = visiblePurchases.map((purchase) => String(purchase.id)); const selectedVisibleCount = visibleIds.filter((id) => selectedPurchaseIds.has(id)).length; const hasVisible = visibleIds.length > 0; const hasSelection = selectedPurchaseIds.size > 0; dom.checkboxLuckmailSelectAll.checked = hasVisible && selectedVisibleCount === visibleIds.length; dom.checkboxLuckmailSelectAll.indeterminate = selectedVisibleCount > 0 && selectedVisibleCount < visibleIds.length; dom.checkboxLuckmailSelectAll.disabled = !hasVisible; dom.luckmailSelectionSummary.textContent = `已选 ${selectedPurchaseIds.size} 个(当前显示 ${visibleIds.length} 个)`; if (dom.btnLuckmailBulkUsed) dom.btnLuckmailBulkUsed.disabled = !hasSelection; if (dom.btnLuckmailBulkUnused) dom.btnLuckmailBulkUnused.disabled = !hasSelection; if (dom.btnLuckmailBulkPreserve) dom.btnLuckmailBulkPreserve.disabled = !hasSelection; if (dom.btnLuckmailBulkUnpreserve) dom.btnLuckmailBulkUnpreserve.disabled = !hasSelection; if (dom.btnLuckmailBulkDisable) dom.btnLuckmailBulkDisable.disabled = !hasSelection; if (dom.btnLuckmailBulkEnable) dom.btnLuckmailBulkEnable.disabled = !hasSelection; } function setLuckmailLoadingState(loading, summary = '') { if (dom.btnLuckmailRefresh) dom.btnLuckmailRefresh.disabled = loading; if (dom.btnLuckmailDisableUsed) dom.btnLuckmailDisableUsed.disabled = loading; if (dom.inputLuckmailSearch) dom.inputLuckmailSearch.disabled = loading; if (dom.selectLuckmailFilter) dom.selectLuckmailFilter.disabled = loading; if (dom.checkboxLuckmailSelectAll) dom.checkboxLuckmailSelectAll.disabled = loading || getFilteredLuckmailPurchases().length === 0; if (dom.btnLuckmailBulkUsed) dom.btnLuckmailBulkUsed.disabled = loading || selectedPurchaseIds.size === 0; if (dom.btnLuckmailBulkUnused) dom.btnLuckmailBulkUnused.disabled = loading || selectedPurchaseIds.size === 0; if (dom.btnLuckmailBulkPreserve) dom.btnLuckmailBulkPreserve.disabled = loading || selectedPurchaseIds.size === 0; if (dom.btnLuckmailBulkUnpreserve) dom.btnLuckmailBulkUnpreserve.disabled = loading || selectedPurchaseIds.size === 0; if (dom.btnLuckmailBulkDisable) dom.btnLuckmailBulkDisable.disabled = loading || selectedPurchaseIds.size === 0; if (dom.btnLuckmailBulkEnable) dom.btnLuckmailBulkEnable.disabled = loading || selectedPurchaseIds.size === 0; if (summary && dom.luckmailSummary) { dom.luckmailSummary.textContent = summary; } } function renderLuckmailPurchases(purchases = renderedPurchases) { if (!dom.luckmailList || !dom.luckmailSummary) return; renderedPurchases = Array.isArray(purchases) ? purchases : []; pruneLuckmailSelection(renderedPurchases); dom.luckmailList.innerHTML = ''; if (!renderedPurchases.length) { selectedPurchaseIds.clear(); dom.luckmailList.innerHTML = '
未找到 openai 项目的 LuckMail 邮箱。
'; dom.luckmailSummary.textContent = '加载已购邮箱后可在这里管理 openai 项目的 LuckMail 邮箱。'; if (dom.btnLuckmailDisableUsed) dom.btnLuckmailDisableUsed.disabled = true; updateLuckmailBulkUI([]); return; } const usedCount = renderedPurchases.filter((purchase) => purchase.used).length; const reusableCount = renderedPurchases.filter((purchase) => purchase.reusable).length; const disableUsedCount = renderedPurchases.filter((purchase) => purchase.used && !purchase.preserved && !purchase.disabled).length; dom.luckmailSummary.textContent = `已加载 ${renderedPurchases.length} 个 openai 邮箱,其中 ${reusableCount} 个可复用,${usedCount} 个已本地标记为已用。`; if (dom.btnLuckmailDisableUsed) { dom.btnLuckmailDisableUsed.textContent = `禁用已用${disableUsedCount > 0 ? `(${disableUsedCount})` : ''}`; dom.btnLuckmailDisableUsed.disabled = disableUsedCount === 0; } const visiblePurchases = getFilteredLuckmailPurchases(renderedPurchases); if (!visiblePurchases.length) { dom.luckmailList.innerHTML = '
没有匹配当前筛选条件的 LuckMail 邮箱。
'; updateLuckmailBulkUI([]); return; } for (const purchase of visiblePurchases) { const purchaseId = String(purchase.id); const item = document.createElement('div'); item.className = `luckmail-item${purchase.current ? ' is-current' : ''}`; item.innerHTML = `
${helpers.escapeHtml(helpers.normalizeLuckmailProjectName(purchase.project_name) || 'openai')} ${purchase.reusable ? '可复用' : ''} ${purchase.current ? '当前' : ''} ${purchase.used ? '已用' : ''} ${purchase.preserved ? '保留' : ''} ${purchase.disabled ? '已禁用' : ''} ${purchase.tag_name && normalizeLuckmailSearchText(purchase.tag_name) !== normalizeLuckmailSearchText(helpers.getLuckmailPreserveTagName()) ? `${helpers.escapeHtml(purchase.tag_name)}` : ''}
ID:${helpers.escapeHtml(String(purchase.id || ''))} 保修至:${helpers.escapeHtml(helpers.formatLuckmailDateTime(purchase.warranty_until))}
`; item.querySelector('[data-action="select"]').addEventListener('change', (event) => { if (event.target.checked) { selectedPurchaseIds.add(purchaseId); } else { selectedPurchaseIds.delete(purchaseId); } updateLuckmailBulkUI(visiblePurchases); }); item.querySelector('[data-action="copy-email"]').addEventListener('click', async () => { await helpers.copyTextToClipboard(purchase.email_address || ''); helpers.showToast('邮箱已复制', 'success', 1600); }); item.querySelector('[data-action="use"]').addEventListener('click', async () => { await selectSingleLuckmailPurchase(purchase); }); item.querySelector('[data-action="toggle-used"]').addEventListener('click', async () => { await setSingleLuckmailPurchaseUsedState(purchase, !purchase.used); }); item.querySelector('[data-action="toggle-preserved"]').addEventListener('click', async () => { await setSingleLuckmailPurchasePreservedState(purchase, !purchase.preserved); }); item.querySelector('[data-action="toggle-disabled"]').addEventListener('click', async () => { await setSingleLuckmailPurchaseDisabledState(purchase, !purchase.disabled); }); dom.luckmailList.appendChild(item); } updateLuckmailBulkUI(visiblePurchases); } async function refreshLuckmailPurchases(options = {}) { const { silent = false } = options; if (!dom.luckmailSection || dom.luckmailSection.style.display === 'none') { return; } if (!silent) setLuckmailLoadingState(true, '正在加载 LuckMail openai 邮箱...'); try { const response = await runtime.sendMessage({ type: 'LIST_LUCKMAIL_PURCHASES', source: 'sidepanel', payload: {}, }); if (response?.error) throw new Error(response.error); renderLuckmailPurchases(response?.purchases || []); } catch (err) { selectedPurchaseIds.clear(); if (dom.luckmailList) { dom.luckmailList.innerHTML = '
无法加载 LuckMail 邮箱列表。
'; } if (dom.luckmailSummary) { dom.luckmailSummary.textContent = err.message; } updateLuckmailBulkUI([]); if (!silent) { helpers.showToast(`LuckMail 邮箱列表加载失败:${err.message}`, 'error'); } } finally { setLuckmailLoadingState(false); } } function queueLuckmailPurchaseRefresh() { if (refreshQueued) return; refreshQueued = true; setTimeout(async () => { refreshQueued = false; await refreshLuckmailPurchases({ silent: true }); }, 150); } async function selectSingleLuckmailPurchase(purchase) { setLuckmailLoadingState(true, `正在切换到 ${purchase.email_address} ...`); try { const response = await runtime.sendMessage({ type: 'SELECT_LUCKMAIL_PURCHASE', source: 'sidepanel', payload: { purchaseId: purchase.id }, }); if (response?.error) throw new Error(response.error); dom.inputEmail.value = response?.purchase?.email_address || purchase.email_address || ''; helpers.showToast(`已切换当前 LuckMail 邮箱为 ${purchase.email_address}`, 'success', 2200); await refreshLuckmailPurchases({ silent: true }); } catch (err) { if (dom.luckmailSummary) dom.luckmailSummary.textContent = err.message; helpers.showToast(`切换 LuckMail 邮箱失败:${err.message}`, 'error'); } finally { setLuckmailLoadingState(false); } } async function setSingleLuckmailPurchaseUsedState(purchase, used) { setLuckmailLoadingState(true, `正在更新 ${purchase.email_address} 的已用状态...`); try { const response = await runtime.sendMessage({ type: 'SET_LUCKMAIL_PURCHASE_USED_STATE', source: 'sidepanel', payload: { purchaseId: purchase.id, used }, }); if (response?.error) throw new Error(response.error); helpers.showToast(`${purchase.email_address} 已${used ? '标记为已用' : '恢复为未用'}`, 'success', 2200); await refreshLuckmailPurchases({ silent: true }); } catch (err) { if (dom.luckmailSummary) dom.luckmailSummary.textContent = err.message; helpers.showToast(`更新 LuckMail 已用状态失败:${err.message}`, 'error'); } finally { setLuckmailLoadingState(false); } } async function setSingleLuckmailPurchasePreservedState(purchase, preserved) { setLuckmailLoadingState(true, `正在更新 ${purchase.email_address} 的保留状态...`); try { const response = await runtime.sendMessage({ type: 'SET_LUCKMAIL_PURCHASE_PRESERVED_STATE', source: 'sidepanel', payload: { purchaseId: purchase.id, preserved }, }); if (response?.error) throw new Error(response.error); helpers.showToast(`${purchase.email_address} 已${preserved ? '设为保留' : '取消保留'}`, 'success', 2200); await refreshLuckmailPurchases({ silent: true }); } catch (err) { if (dom.luckmailSummary) dom.luckmailSummary.textContent = err.message; helpers.showToast(`更新 LuckMail 保留状态失败:${err.message}`, 'error'); } finally { setLuckmailLoadingState(false); } } async function setSingleLuckmailPurchaseDisabledState(purchase, disabled) { setLuckmailLoadingState(true, `正在${disabled ? '禁用' : '启用'} ${purchase.email_address} ...`); try { const response = await runtime.sendMessage({ type: 'SET_LUCKMAIL_PURCHASE_DISABLED_STATE', source: 'sidepanel', payload: { purchaseId: purchase.id, disabled }, }); if (response?.error) throw new Error(response.error); helpers.showToast(`${purchase.email_address} 已${disabled ? '禁用' : '启用'}`, 'success', 2200); await refreshLuckmailPurchases({ silent: true }); } catch (err) { if (dom.luckmailSummary) dom.luckmailSummary.textContent = err.message; helpers.showToast(`更新 LuckMail 禁用状态失败:${err.message}`, 'error'); } finally { setLuckmailLoadingState(false); } } async function runBulkLuckmailAction(action) { const selectedIds = renderedPurchases .filter((purchase) => selectedPurchaseIds.has(String(purchase.id))) .map((purchase) => purchase.id); if (!selectedIds.length) { updateLuckmailBulkUI(); return; } const actionLabelMap = { used: '标记已用', unused: '标记未用', preserve: '保留', unpreserve: '取消保留', disable: '禁用', enable: '启用', }; setLuckmailLoadingState(true, `正在批量${actionLabelMap[action] || '处理'} LuckMail 邮箱...`); try { const response = await runtime.sendMessage({ type: 'BATCH_UPDATE_LUCKMAIL_PURCHASES', source: 'sidepanel', payload: { action, ids: selectedIds }, }); if (response?.error) throw new Error(response.error); helpers.showToast(`已批量${actionLabelMap[action] || '处理'} ${selectedIds.length} 个 LuckMail 邮箱`, 'success', 2400); await refreshLuckmailPurchases({ silent: true }); } catch (err) { if (dom.luckmailSummary) dom.luckmailSummary.textContent = err.message; helpers.showToast(`批量处理 LuckMail 邮箱失败:${err.message}`, 'error'); } finally { setLuckmailLoadingState(false); updateLuckmailBulkUI(); } } async function disableUsedLuckmailPurchases() { const confirmed = await helpers.openConfirmModal({ title: '禁用已用 LuckMail 邮箱', message: '确认禁用所有本地已用且未保留的 openai LuckMail 邮箱吗?', confirmLabel: '确认禁用', confirmVariant: 'btn-danger', }); if (!confirmed) { return; } setLuckmailLoadingState(true, '正在禁用已用 LuckMail 邮箱...'); try { const response = await runtime.sendMessage({ type: 'DISABLE_USED_LUCKMAIL_PURCHASES', source: 'sidepanel', payload: {}, }); if (response?.error) throw new Error(response.error); const disabledCount = Array.isArray(response?.disabledIds) ? response.disabledIds.length : 0; helpers.showToast(`已禁用 ${disabledCount} 个 LuckMail 邮箱`, disabledCount > 0 ? 'success' : 'info', 2400); await refreshLuckmailPurchases({ silent: true }); } catch (err) { if (dom.luckmailSummary) dom.luckmailSummary.textContent = err.message; helpers.showToast(`禁用已用 LuckMail 邮箱失败:${err.message}`, 'error'); } finally { setLuckmailLoadingState(false); } } function reset() { renderedPurchases = []; selectedPurchaseIds.clear(); searchTerm = ''; filterMode = 'all'; refreshQueued = false; if (dom.inputLuckmailSearch) dom.inputLuckmailSearch.value = ''; if (dom.selectLuckmailFilter) dom.selectLuckmailFilter.value = 'all'; if (dom.luckmailList) dom.luckmailList.innerHTML = ''; if (dom.luckmailSummary) dom.luckmailSummary.textContent = '加载已购邮箱后可在这里管理 openai 项目的 LuckMail 邮箱。'; if (dom.btnLuckmailDisableUsed) dom.btnLuckmailDisableUsed.disabled = true; updateLuckmailBulkUI([]); } function bindLuckmailEvents() { dom.inputLuckmailSearch?.addEventListener('input', (event) => { searchTerm = event.target.value || ''; renderLuckmailPurchases(renderedPurchases); }); dom.selectLuckmailFilter?.addEventListener('change', (event) => { filterMode = String(event.target.value || 'all').trim() || 'all'; renderLuckmailPurchases(renderedPurchases); }); dom.checkboxLuckmailSelectAll?.addEventListener('change', () => { const visiblePurchases = getFilteredLuckmailPurchases(); if (dom.checkboxLuckmailSelectAll.checked) { visiblePurchases.forEach((purchase) => selectedPurchaseIds.add(String(purchase.id))); } else { visiblePurchases.forEach((purchase) => selectedPurchaseIds.delete(String(purchase.id))); } renderLuckmailPurchases(renderedPurchases); }); dom.btnLuckmailRefresh?.addEventListener('click', async () => { await refreshLuckmailPurchases(); }); dom.btnLuckmailDisableUsed?.addEventListener('click', async () => { await disableUsedLuckmailPurchases(); }); dom.btnLuckmailBulkUsed?.addEventListener('click', async () => { await runBulkLuckmailAction('used'); }); dom.btnLuckmailBulkUnused?.addEventListener('click', async () => { await runBulkLuckmailAction('unused'); }); dom.btnLuckmailBulkPreserve?.addEventListener('click', async () => { await runBulkLuckmailAction('preserve'); }); dom.btnLuckmailBulkUnpreserve?.addEventListener('click', async () => { await runBulkLuckmailAction('unpreserve'); }); dom.btnLuckmailBulkDisable?.addEventListener('click', async () => { await runBulkLuckmailAction('disable'); }); dom.btnLuckmailBulkEnable?.addEventListener('click', async () => { await runBulkLuckmailAction('enable'); }); } return { bindLuckmailEvents, disableUsedLuckmailPurchases, queueLuckmailPurchaseRefresh, refreshLuckmailPurchases, renderLuckmailPurchases, reset, }; } globalScope.SidepanelLuckmailManager = { createLuckmailManager, }; })(window);