| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467 |
- (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 = '<div class="luckmail-empty">未找到 openai 项目的 LuckMail 邮箱。</div>';
- 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 = '<div class="luckmail-empty">没有匹配当前筛选条件的 LuckMail 邮箱。</div>';
- 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 = `
- <input class="luckmail-item-check" type="checkbox" data-action="select" ${selectedPurchaseIds.has(purchaseId) ? 'checked' : ''} />
- <div class="luckmail-item-main">
- <div class="luckmail-item-email-row">
- <div class="luckmail-item-email">${helpers.escapeHtml(purchase.email_address || '(未知邮箱)')}</div>
- <button
- class="hotmail-copy-btn"
- type="button"
- data-action="copy-email"
- title="复制邮箱"
- aria-label="复制邮箱 ${helpers.escapeHtml(purchase.email_address || '')}"
- >${copyIcon}</button>
- </div>
- <div class="luckmail-item-meta">
- <span class="luckmail-tag">${helpers.escapeHtml(helpers.normalizeLuckmailProjectName(purchase.project_name) || 'openai')}</span>
- ${purchase.reusable ? '<span class="luckmail-tag active">可复用</span>' : ''}
- ${purchase.current ? '<span class="luckmail-tag current">当前</span>' : ''}
- ${purchase.used ? '<span class="luckmail-tag used">已用</span>' : ''}
- ${purchase.preserved ? '<span class="luckmail-tag">保留</span>' : ''}
- ${purchase.disabled ? '<span class="luckmail-tag disabled">已禁用</span>' : ''}
- ${purchase.tag_name && normalizeLuckmailSearchText(purchase.tag_name) !== normalizeLuckmailSearchText(helpers.getLuckmailPreserveTagName())
- ? `<span class="luckmail-tag">${helpers.escapeHtml(purchase.tag_name)}</span>`
- : ''}
- </div>
- <div class="luckmail-item-details">
- <span>ID:${helpers.escapeHtml(String(purchase.id || ''))}</span>
- <span>保修至:${helpers.escapeHtml(helpers.formatLuckmailDateTime(purchase.warranty_until))}</span>
- </div>
- </div>
- <div class="luckmail-item-actions">
- <button class="btn btn-outline btn-xs" type="button" data-action="use">使用此邮箱</button>
- <button class="btn btn-outline btn-xs" type="button" data-action="toggle-used">${helpers.escapeHtml(purchase.used ? '标记未用' : '标记已用')}</button>
- <button class="btn btn-outline btn-xs" type="button" data-action="toggle-preserved">${helpers.escapeHtml(purchase.preserved ? '取消保留' : '保留')}</button>
- <button class="btn btn-outline btn-xs" type="button" data-action="toggle-disabled">${helpers.escapeHtml(purchase.disabled ? '启用' : '禁用')}</button>
- </div>
- `;
- 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 = '<div class="luckmail-empty">无法加载 LuckMail 邮箱列表。</div>';
- }
- 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);
|