2925邮箱增加账号池功能
This commit is contained in:
@@ -0,0 +1,463 @@
|
||||
(function attachSidepanelMail2925Manager(globalScope) {
|
||||
function createMail2925Manager(context = {}) {
|
||||
const {
|
||||
state,
|
||||
dom,
|
||||
helpers,
|
||||
runtime,
|
||||
constants = {},
|
||||
mail2925Utils = {},
|
||||
} = context;
|
||||
|
||||
const expandedStorageKey = constants.expandedStorageKey || 'multipage-mail2925-list-expanded';
|
||||
const displayTimeZone = constants.displayTimeZone || 'Asia/Shanghai';
|
||||
const copyIcon = constants.copyIcon || '';
|
||||
|
||||
let actionInFlight = false;
|
||||
let listExpanded = false;
|
||||
|
||||
function getMail2925Accounts(currentState = state.getLatestState()) {
|
||||
return helpers.getMail2925Accounts(currentState);
|
||||
}
|
||||
|
||||
function getCurrentMail2925AccountId(currentState = state.getLatestState()) {
|
||||
return String(currentState?.currentMail2925AccountId || '');
|
||||
}
|
||||
|
||||
function updateMail2925ListViewport() {
|
||||
const count = getMail2925Accounts().length;
|
||||
if (dom.btnDeleteAllMail2925Accounts) {
|
||||
dom.btnDeleteAllMail2925Accounts.textContent = `全部删除${count > 0 ? `(${count})` : ''}`;
|
||||
dom.btnDeleteAllMail2925Accounts.disabled = count === 0;
|
||||
}
|
||||
if (dom.btnToggleMail2925List) {
|
||||
const label = typeof mail2925Utils.getMail2925ListToggleLabel === 'function'
|
||||
? mail2925Utils.getMail2925ListToggleLabel(listExpanded, count)
|
||||
: `${listExpanded ? '收起列表' : '展开列表'}${count > 0 ? `(${count})` : ''}`;
|
||||
dom.btnToggleMail2925List.textContent = label;
|
||||
dom.btnToggleMail2925List.setAttribute('aria-expanded', String(listExpanded));
|
||||
dom.btnToggleMail2925List.disabled = count === 0;
|
||||
}
|
||||
if (dom.mail2925ListShell) {
|
||||
dom.mail2925ListShell.classList.toggle('is-expanded', listExpanded);
|
||||
dom.mail2925ListShell.classList.toggle('is-collapsed', !listExpanded);
|
||||
}
|
||||
}
|
||||
|
||||
function setMail2925ListExpanded(expanded, options = {}) {
|
||||
const { persist = true } = options;
|
||||
listExpanded = Boolean(expanded);
|
||||
updateMail2925ListViewport();
|
||||
if (persist) {
|
||||
localStorage.setItem(expandedStorageKey, listExpanded ? '1' : '0');
|
||||
}
|
||||
}
|
||||
|
||||
function initMail2925ListExpandedState() {
|
||||
const saved = localStorage.getItem(expandedStorageKey);
|
||||
setMail2925ListExpanded(saved === '1', { persist: false });
|
||||
}
|
||||
|
||||
function formatDateTime(timestamp) {
|
||||
const value = Number(timestamp);
|
||||
if (!Number.isFinite(value) || value <= 0) {
|
||||
return '未记录';
|
||||
}
|
||||
return new Date(value).toLocaleString('zh-CN', {
|
||||
hour12: false,
|
||||
timeZone: displayTimeZone,
|
||||
});
|
||||
}
|
||||
|
||||
function getStatusSnapshot(account) {
|
||||
const status = typeof mail2925Utils.getMail2925AccountStatus === 'function'
|
||||
? mail2925Utils.getMail2925AccountStatus(account, Date.now())
|
||||
: 'ready';
|
||||
switch (status) {
|
||||
case 'cooldown':
|
||||
return { label: '冷却中', className: 'status-used' };
|
||||
case 'disabled':
|
||||
return { label: '已禁用', className: 'status-disabled' };
|
||||
case 'error':
|
||||
return { label: '异常', className: 'status-error' };
|
||||
case 'pending':
|
||||
return { label: '待完善', className: 'status-pending' };
|
||||
default:
|
||||
return { label: '可用', className: 'status-authorized' };
|
||||
}
|
||||
}
|
||||
|
||||
function refreshManagedAliasBaseEmail() {
|
||||
if (typeof helpers.refreshManagedAliasBaseEmail === 'function') {
|
||||
helpers.refreshManagedAliasBaseEmail();
|
||||
}
|
||||
}
|
||||
|
||||
function applyMail2925AccountMutation(account, options = {}) {
|
||||
if (!account?.id) return;
|
||||
const latestState = state.getLatestState();
|
||||
const currentId = getCurrentMail2925AccountId(latestState);
|
||||
const nextAccounts = typeof mail2925Utils.upsertMail2925AccountInList === 'function'
|
||||
? mail2925Utils.upsertMail2925AccountInList(getMail2925Accounts(latestState), account)
|
||||
: getMail2925Accounts(latestState).map((item) => (item.id === account.id ? account : item));
|
||||
|
||||
const nextState = {
|
||||
mail2925Accounts: nextAccounts,
|
||||
};
|
||||
if (currentId === account.id && account.enabled === false) {
|
||||
nextState.currentMail2925AccountId = null;
|
||||
}
|
||||
state.syncLatestState(nextState);
|
||||
refreshManagedAliasBaseEmail();
|
||||
renderMail2925Accounts();
|
||||
}
|
||||
|
||||
function clearMail2925Form() {
|
||||
if (dom.inputMail2925Email) dom.inputMail2925Email.value = '';
|
||||
if (dom.inputMail2925Password) dom.inputMail2925Password.value = '';
|
||||
}
|
||||
|
||||
function renderMail2925Accounts() {
|
||||
if (!dom.mail2925AccountsList) return;
|
||||
|
||||
const latestState = state.getLatestState();
|
||||
const accounts = getMail2925Accounts(latestState);
|
||||
const currentId = getCurrentMail2925AccountId(latestState);
|
||||
|
||||
if (!accounts.length) {
|
||||
dom.mail2925AccountsList.innerHTML = '<div class="hotmail-empty">还没有 2925 账号,先添加一条再使用。</div>';
|
||||
updateMail2925ListViewport();
|
||||
return;
|
||||
}
|
||||
|
||||
dom.mail2925AccountsList.innerHTML = accounts.map((account) => {
|
||||
const status = getStatusSnapshot(account);
|
||||
const coolingDown = status.label === '冷却中';
|
||||
return `
|
||||
<div class="hotmail-account-item${account.id === currentId ? ' is-current' : ''}">
|
||||
<div class="hotmail-account-top">
|
||||
<div class="hotmail-account-title-row">
|
||||
<div class="hotmail-account-email">${helpers.escapeHtml(account.email || '(未命名账号)')}</div>
|
||||
<button
|
||||
class="hotmail-copy-btn"
|
||||
type="button"
|
||||
data-account-action="copy-email"
|
||||
data-account-id="${helpers.escapeHtml(account.id)}"
|
||||
title="复制邮箱"
|
||||
aria-label="复制邮箱 ${helpers.escapeHtml(account.email || '')}"
|
||||
>${copyIcon}</button>
|
||||
</div>
|
||||
<span class="hotmail-status-chip ${helpers.escapeHtml(status.className)}">${helpers.escapeHtml(status.label)}</span>
|
||||
</div>
|
||||
<div class="hotmail-account-meta">
|
||||
<span>密码:${account.password ? '已保存' : '未保存'}</span>
|
||||
<span>上次登录:${helpers.escapeHtml(formatDateTime(account.lastLoginAt))}</span>
|
||||
<span>上次使用:${helpers.escapeHtml(formatDateTime(account.lastUsedAt))}</span>
|
||||
<span>上限记录:${helpers.escapeHtml(formatDateTime(account.lastLimitAt))}</span>
|
||||
<span>恢复时间:${helpers.escapeHtml(formatDateTime(account.disabledUntil))}</span>
|
||||
</div>
|
||||
${account.lastError ? `<div class="hotmail-account-error">${helpers.escapeHtml(account.lastError)}</div>` : ''}
|
||||
<div class="hotmail-account-actions">
|
||||
<button class="btn btn-outline btn-sm" type="button" data-account-action="select" data-account-id="${helpers.escapeHtml(account.id)}">使用此账号</button>
|
||||
<button class="btn btn-primary btn-sm" type="button" data-account-action="login" data-account-id="${helpers.escapeHtml(account.id)}">登录</button>
|
||||
<button class="btn btn-outline btn-sm" type="button" data-account-action="toggle-enabled" data-account-id="${helpers.escapeHtml(account.id)}">${account.enabled === false ? '启用' : '禁用'}</button>
|
||||
${coolingDown ? `<button class="btn btn-outline btn-sm" type="button" data-account-action="clear-cooldown" data-account-id="${helpers.escapeHtml(account.id)}">清冷却</button>` : ''}
|
||||
<button class="btn btn-ghost btn-sm" type="button" data-account-action="delete" data-account-id="${helpers.escapeHtml(account.id)}">删除</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
updateMail2925ListViewport();
|
||||
}
|
||||
|
||||
async function handleAddMail2925Account() {
|
||||
if (actionInFlight) return;
|
||||
|
||||
const email = String(dom.inputMail2925Email?.value || '').trim();
|
||||
const password = String(dom.inputMail2925Password?.value || '');
|
||||
if (!email) {
|
||||
helpers.showToast('请先填写 2925 邮箱。', 'warn');
|
||||
return;
|
||||
}
|
||||
if (!password) {
|
||||
helpers.showToast('请先填写 2925 密码。', 'warn');
|
||||
return;
|
||||
}
|
||||
|
||||
actionInFlight = true;
|
||||
if (dom.btnAddMail2925Account) {
|
||||
dom.btnAddMail2925Account.disabled = true;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await runtime.sendMessage({
|
||||
type: 'UPSERT_MAIL2925_ACCOUNT',
|
||||
source: 'sidepanel',
|
||||
payload: {
|
||||
email,
|
||||
password,
|
||||
},
|
||||
});
|
||||
if (response?.error) {
|
||||
throw new Error(response.error);
|
||||
}
|
||||
|
||||
applyMail2925AccountMutation(response.account);
|
||||
clearMail2925Form();
|
||||
helpers.showToast(`已保存 2925 账号 ${email}`, 'success', 1800);
|
||||
} catch (err) {
|
||||
helpers.showToast(`保存 2925 账号失败:${err.message}`, 'error');
|
||||
} finally {
|
||||
actionInFlight = false;
|
||||
if (dom.btnAddMail2925Account) {
|
||||
dom.btnAddMail2925Account.disabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleImportMail2925Accounts() {
|
||||
if (actionInFlight) return;
|
||||
if (typeof mail2925Utils.parseMail2925ImportText !== 'function') {
|
||||
helpers.showToast('2925 导入解析器未加载,请刷新扩展后重试。', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const rawText = String(dom.inputMail2925Import?.value || '').trim();
|
||||
if (!rawText) {
|
||||
helpers.showToast('请先粘贴 2925 账号导入内容。', 'warn');
|
||||
return;
|
||||
}
|
||||
|
||||
const parsedAccounts = mail2925Utils.parseMail2925ImportText(rawText);
|
||||
if (!parsedAccounts.length) {
|
||||
helpers.showToast('没有解析到有效账号,请检查格式是否为 邮箱----密码。', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
actionInFlight = true;
|
||||
if (dom.btnImportMail2925Accounts) {
|
||||
dom.btnImportMail2925Accounts.disabled = true;
|
||||
}
|
||||
|
||||
try {
|
||||
for (const account of parsedAccounts) {
|
||||
const response = await runtime.sendMessage({
|
||||
type: 'UPSERT_MAIL2925_ACCOUNT',
|
||||
source: 'sidepanel',
|
||||
payload: account,
|
||||
});
|
||||
if (response?.error) {
|
||||
throw new Error(response.error);
|
||||
}
|
||||
}
|
||||
|
||||
if (dom.inputMail2925Import) {
|
||||
dom.inputMail2925Import.value = '';
|
||||
}
|
||||
helpers.showToast(`已导入 ${parsedAccounts.length} 条 2925 账号`, 'success', 2200);
|
||||
} catch (err) {
|
||||
helpers.showToast(`批量导入 2925 账号失败:${err.message}`, 'error');
|
||||
} finally {
|
||||
actionInFlight = false;
|
||||
if (dom.btnImportMail2925Accounts) {
|
||||
dom.btnImportMail2925Accounts.disabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteAllMail2925Accounts() {
|
||||
const accounts = getMail2925Accounts();
|
||||
if (!accounts.length) {
|
||||
helpers.showToast('没有可删除的 2925 账号。', 'warn');
|
||||
return;
|
||||
}
|
||||
|
||||
const confirmed = await helpers.openConfirmModal({
|
||||
title: '全部删除 2925 账号',
|
||||
message: `确认删除当前全部 ${accounts.length} 个 2925 账号吗?`,
|
||||
confirmLabel: '确认全部删除',
|
||||
confirmVariant: 'btn-danger',
|
||||
});
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await runtime.sendMessage({
|
||||
type: 'DELETE_MAIL2925_ACCOUNTS',
|
||||
source: 'sidepanel',
|
||||
payload: { mode: 'all' },
|
||||
});
|
||||
if (response?.error) {
|
||||
throw new Error(response.error);
|
||||
}
|
||||
|
||||
state.syncLatestState({
|
||||
mail2925Accounts: [],
|
||||
currentMail2925AccountId: null,
|
||||
});
|
||||
refreshManagedAliasBaseEmail();
|
||||
renderMail2925Accounts();
|
||||
helpers.showToast(`已删除全部 ${response.deletedCount || 0} 个 2925 账号`, 'success', 2200);
|
||||
}
|
||||
|
||||
async function handleAccountListClick(event) {
|
||||
const actionButton = event.target.closest('[data-account-action]');
|
||||
if (!actionButton || actionInFlight) {
|
||||
return;
|
||||
}
|
||||
|
||||
const accountId = String(actionButton.dataset.accountId || '');
|
||||
const action = String(actionButton.dataset.accountAction || '');
|
||||
if (!accountId || !action) {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetAccount = getMail2925Accounts().find((account) => account.id === accountId) || null;
|
||||
actionInFlight = true;
|
||||
actionButton.disabled = true;
|
||||
|
||||
try {
|
||||
if (action === 'copy-email') {
|
||||
if (!targetAccount?.email) throw new Error('未找到可复制的 2925 邮箱。');
|
||||
await helpers.copyTextToClipboard(targetAccount.email);
|
||||
helpers.showToast(`已复制 ${targetAccount.email}`, 'success', 1800);
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === 'select') {
|
||||
const response = await runtime.sendMessage({
|
||||
type: 'SELECT_MAIL2925_ACCOUNT',
|
||||
source: 'sidepanel',
|
||||
payload: { accountId },
|
||||
});
|
||||
if (response?.error) throw new Error(response.error);
|
||||
state.syncLatestState({ currentMail2925AccountId: response.account.id });
|
||||
refreshManagedAliasBaseEmail();
|
||||
renderMail2925Accounts();
|
||||
helpers.showToast(`已切换当前 2925 账号为 ${response.account.email}`, 'success', 2000);
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === 'login') {
|
||||
const response = await runtime.sendMessage({
|
||||
type: 'LOGIN_MAIL2925_ACCOUNT',
|
||||
source: 'sidepanel',
|
||||
payload: {
|
||||
accountId,
|
||||
forceRelogin: true,
|
||||
},
|
||||
});
|
||||
if (response?.error) throw new Error(response.error);
|
||||
state.syncLatestState({ currentMail2925AccountId: response.account.id });
|
||||
refreshManagedAliasBaseEmail();
|
||||
renderMail2925Accounts();
|
||||
helpers.showToast(`已使用 ${response.account.email} 登录 2925 邮箱`, 'success', 2200);
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === 'toggle-enabled') {
|
||||
if (!targetAccount) throw new Error('未找到目标 2925 账号。');
|
||||
const response = await runtime.sendMessage({
|
||||
type: 'PATCH_MAIL2925_ACCOUNT',
|
||||
source: 'sidepanel',
|
||||
payload: {
|
||||
accountId,
|
||||
updates: {
|
||||
enabled: targetAccount.enabled === false,
|
||||
},
|
||||
},
|
||||
});
|
||||
if (response?.error) throw new Error(response.error);
|
||||
applyMail2925AccountMutation(response.account);
|
||||
helpers.showToast(`2925 账号 ${response.account.email} 已${response.account.enabled === false ? '禁用' : '启用'}`, 'success', 2200);
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === 'clear-cooldown') {
|
||||
const response = await runtime.sendMessage({
|
||||
type: 'PATCH_MAIL2925_ACCOUNT',
|
||||
source: 'sidepanel',
|
||||
payload: {
|
||||
accountId,
|
||||
updates: {
|
||||
disabledUntil: 0,
|
||||
lastError: '',
|
||||
},
|
||||
},
|
||||
});
|
||||
if (response?.error) throw new Error(response.error);
|
||||
applyMail2925AccountMutation(response.account);
|
||||
helpers.showToast(`2925 账号 ${response.account.email} 已清除冷却`, 'success', 2200);
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === 'delete') {
|
||||
const confirmed = await helpers.openConfirmModal({
|
||||
title: '删除 2925 账号',
|
||||
message: '确认删除这个 2925 账号吗?',
|
||||
confirmLabel: '确认删除',
|
||||
confirmVariant: 'btn-danger',
|
||||
});
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
const response = await runtime.sendMessage({
|
||||
type: 'DELETE_MAIL2925_ACCOUNT',
|
||||
source: 'sidepanel',
|
||||
payload: { accountId },
|
||||
});
|
||||
if (response?.error) throw new Error(response.error);
|
||||
|
||||
const nextAccounts = getMail2925Accounts().filter((account) => account.id !== accountId);
|
||||
const nextState = { mail2925Accounts: nextAccounts };
|
||||
if (getCurrentMail2925AccountId() === accountId) {
|
||||
nextState.currentMail2925AccountId = null;
|
||||
}
|
||||
state.syncLatestState(nextState);
|
||||
refreshManagedAliasBaseEmail();
|
||||
renderMail2925Accounts();
|
||||
helpers.showToast('2925 账号已删除', 'success', 1800);
|
||||
}
|
||||
} catch (err) {
|
||||
helpers.showToast(err.message, 'error');
|
||||
} finally {
|
||||
actionInFlight = false;
|
||||
actionButton.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
function bindMail2925Events() {
|
||||
dom.btnToggleMail2925List?.addEventListener('click', () => {
|
||||
setMail2925ListExpanded(!listExpanded);
|
||||
});
|
||||
|
||||
dom.btnDeleteAllMail2925Accounts?.addEventListener('click', async () => {
|
||||
if (actionInFlight) return;
|
||||
actionInFlight = true;
|
||||
try {
|
||||
await deleteAllMail2925Accounts();
|
||||
} catch (err) {
|
||||
helpers.showToast(err.message, 'error');
|
||||
} finally {
|
||||
actionInFlight = false;
|
||||
updateMail2925ListViewport();
|
||||
}
|
||||
});
|
||||
|
||||
dom.btnAddMail2925Account?.addEventListener('click', handleAddMail2925Account);
|
||||
dom.btnImportMail2925Accounts?.addEventListener('click', handleImportMail2925Accounts);
|
||||
dom.mail2925AccountsList?.addEventListener('click', handleAccountListClick);
|
||||
}
|
||||
|
||||
return {
|
||||
bindMail2925Events,
|
||||
initMail2925ListExpandedState,
|
||||
renderMail2925Accounts,
|
||||
};
|
||||
}
|
||||
|
||||
globalScope.SidepanelMail2925Manager = {
|
||||
createMail2925Manager,
|
||||
};
|
||||
})(window);
|
||||
Reference in New Issue
Block a user