| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
- (function attachBackgroundAccountRunHistory(root, factory) {
- root.MultiPageBackgroundAccountRunHistory = factory();
- })(typeof self !== 'undefined' ? self : globalThis, function createBackgroundAccountRunHistoryModule() {
- function createAccountRunHistoryHelpers(deps = {}) {
- const {
- ACCOUNT_RUN_HISTORY_STORAGE_KEY = 'accountRunHistory',
- addLog,
- buildLocalHelperEndpoint,
- chrome,
- getErrorMessage,
- getState,
- normalizeAccountRunHistoryHelperBaseUrl,
- } = deps;
- function normalizeTimestamp(value) {
- const timestamp = Date.parse(String(value || ''));
- return Number.isFinite(timestamp) ? timestamp : 0;
- }
- function normalizeRetryCount(value) {
- const count = Math.floor(Number(value) || 0);
- return count > 0 ? count : 0;
- }
- function normalizeFinalStatus(status = '') {
- const normalized = String(status || '').trim().toLowerCase();
- if (!normalized) {
- return '';
- }
- if (normalized === 'success') {
- return 'success';
- }
- if (normalized === 'failed' || /_failed$/.test(normalized)) {
- return 'failed';
- }
- if (normalized === 'stopped' || /_stopped$/.test(normalized)) {
- return 'stopped';
- }
- return '';
- }
- function extractFailedStep(status = '', detail = '') {
- const normalizedStatus = String(status || '').trim().toLowerCase();
- const statusMatch = normalizedStatus.match(/^step(\d+)_failed$/);
- if (statusMatch) {
- const step = Number(statusMatch[1]);
- return Number.isInteger(step) && step > 0 ? step : null;
- }
- const text = String(detail || '').trim();
- const detailMatch = text.match(/(?:Step\s+(\d+)|步骤\s*(\d+))/i);
- if (!detailMatch) {
- return null;
- }
- const step = Number(detailMatch[1] || detailMatch[2]);
- return Number.isInteger(step) && step > 0 ? step : null;
- }
- function isPhoneVerificationFailure(detail = '') {
- const text = String(detail || '').trim();
- if (!text) {
- return false;
- }
- return /add[_\s-]?phone/i.test(text)
- || /手机号(?:验证|页面|页)|手机(?:号)?页面|出现手机号验证/.test(text)
- || /进入了手机号页面/.test(text);
- }
- function buildFailureLabel(finalStatus, failedStep, failureDetail = '') {
- if (finalStatus === 'success') {
- return '流程完成';
- }
- if (finalStatus === 'stopped') {
- return '流程已停止';
- }
- if (finalStatus !== 'failed') {
- return '无';
- }
- if (isPhoneVerificationFailure(failureDetail)) {
- return '出现手机号验证';
- }
- if (Number.isInteger(failedStep) && failedStep > 0) {
- return `步骤 ${failedStep} 失败`;
- }
- return '流程失败';
- }
- function buildRecordId(email = '') {
- return String(email || '').trim().toLowerCase();
- }
- function normalizeSource(value = '') {
- return String(value || '').trim().toLowerCase() === 'auto' ? 'auto' : 'manual';
- }
- function normalizeAutoRunContext(context) {
- if (!context || typeof context !== 'object') {
- return null;
- }
- const currentRun = Math.max(0, Math.floor(Number(context.currentRun) || 0));
- const totalRuns = Math.max(0, Math.floor(Number(context.totalRuns) || 0));
- const attemptRun = Math.max(0, Math.floor(Number(context.attemptRun) || 0));
- if (!currentRun && !totalRuns && !attemptRun) {
- return null;
- }
- return {
- currentRun,
- totalRuns,
- attemptRun,
- };
- }
- function buildAutoRunContextFromState(state = {}) {
- return normalizeAutoRunContext({
- currentRun: state.autoRunCurrentRun,
- totalRuns: state.autoRunTotalRuns,
- attemptRun: state.autoRunAttemptRun,
- });
- }
- function getRetryCountFromState(state = {}) {
- if (!Boolean(state.autoRunning)) {
- return 0;
- }
- const attemptRun = Math.max(0, Math.floor(Number(state.autoRunAttemptRun) || 0));
- return attemptRun > 1 ? attemptRun - 1 : 0;
- }
- function normalizeAccountRunHistoryRecord(record) {
- if (!record || typeof record !== 'object') {
- return null;
- }
- const email = String(record.email || '').trim();
- const password = String(record.password || '').trim();
- const finalStatus = normalizeFinalStatus(record.finalStatus || record.status || '');
- if (!email || !password || !finalStatus) {
- return null;
- }
- const finishedAt = String(record.finishedAt || record.recordedAt || '').trim();
- const failureDetail = finalStatus === 'failed' || finalStatus === 'stopped'
- ? String(record.failureDetail || record.reason || '').trim()
- : '';
- const failedStepCandidate = Number(record.failedStep);
- const failedStep = Number.isInteger(failedStepCandidate) && failedStepCandidate > 0
- ? failedStepCandidate
- : extractFailedStep(record.finalStatus || record.status || '', failureDetail);
- const autoRunContext = normalizeAutoRunContext(record.autoRunContext);
- const retryCount = normalizeRetryCount(
- record.retryCount !== undefined
- ? record.retryCount
- : ((autoRunContext?.attemptRun || 0) > 1 ? autoRunContext.attemptRun - 1 : 0)
- );
- const source = normalizeSource(record.source || (autoRunContext ? 'auto' : 'manual'));
- return {
- recordId: String(record.recordId || '').trim() || buildRecordId(email),
- email,
- password,
- finalStatus,
- finishedAt,
- retryCount,
- failureLabel: String(record.failureLabel || '').trim() || buildFailureLabel(finalStatus, failedStep, failureDetail),
- failureDetail,
- failedStep: Number.isInteger(failedStep) && failedStep > 0 ? failedStep : null,
- source,
- autoRunContext: source === 'auto' ? autoRunContext : null,
- };
- }
- function normalizeAccountRunHistory(records) {
- if (!Array.isArray(records)) {
- return [];
- }
- return records
- .map((item) => normalizeAccountRunHistoryRecord(item))
- .filter(Boolean)
- .sort((left, right) => normalizeTimestamp(right.finishedAt) - normalizeTimestamp(left.finishedAt));
- }
- async function getPersistedAccountRunHistory() {
- try {
- const stored = await chrome.storage.local.get(ACCOUNT_RUN_HISTORY_STORAGE_KEY);
- return normalizeAccountRunHistory(stored[ACCOUNT_RUN_HISTORY_STORAGE_KEY]);
- } catch (err) {
- console.warn('[MultiPage:account-run-history] Failed to read account run history:', err?.message || err);
- return [];
- }
- }
- async function setPersistedAccountRunHistory(records) {
- const normalizedHistory = normalizeAccountRunHistory(records);
- await chrome.storage.local.set({
- [ACCOUNT_RUN_HISTORY_STORAGE_KEY]: normalizedHistory,
- });
- return normalizedHistory;
- }
- function buildAccountRunHistoryRecord(state = {}, status = '', reason = '') {
- const email = String(state.email || '').trim();
- const password = String(state.password || state.customPassword || '').trim() || '无';
- const finalStatus = normalizeFinalStatus(status);
- if (!email || !finalStatus) {
- return null;
- }
- const failureDetail = finalStatus === 'failed' || finalStatus === 'stopped' ? String(reason || '').trim() : '';
- const failedStep = finalStatus === 'failed' ? extractFailedStep(status, failureDetail) : null;
- const source = Boolean(state.autoRunning) ? 'auto' : 'manual';
- const autoRunContext = source === 'auto' ? buildAutoRunContextFromState(state) : null;
- const retryCount = source === 'auto' ? getRetryCountFromState(state) : 0;
- const finishedAt = new Date().toISOString();
- return {
- recordId: buildRecordId(email),
- email,
- password,
- finalStatus,
- finishedAt,
- retryCount,
- failureLabel: buildFailureLabel(finalStatus, failedStep, failureDetail),
- failureDetail,
- failedStep: Number.isInteger(failedStep) && failedStep > 0 ? failedStep : null,
- source,
- autoRunContext,
- };
- }
- function upsertAccountRunHistoryRecord(history, record) {
- const normalizedHistory = normalizeAccountRunHistory(history);
- if (!record) {
- return normalizedHistory;
- }
- const recordId = String(record.recordId || '').trim();
- const emailKey = String(record.email || '').trim().toLowerCase();
- const nextHistory = normalizedHistory.filter((item) => {
- const itemRecordId = String(item.recordId || '').trim();
- const itemEmailKey = String(item.email || '').trim().toLowerCase();
- return itemRecordId !== recordId && itemEmailKey !== emailKey;
- });
- nextHistory.unshift(record);
- return normalizeAccountRunHistory(nextHistory);
- }
- async function appendAccountRunHistoryRecord(status, stateOverride = null, reason = '') {
- const state = stateOverride || await getState();
- const record = buildAccountRunHistoryRecord(state, status, reason);
- if (!record) {
- return null;
- }
- const history = await getPersistedAccountRunHistory();
- const nextHistory = upsertAccountRunHistoryRecord(history, record);
- await setPersistedAccountRunHistory(nextHistory);
- return record;
- }
- function summarizeAccountRunHistory(records = []) {
- return normalizeAccountRunHistory(records).reduce((summary, record) => {
- summary.total += 1;
- if (record.finalStatus === 'success') {
- summary.success += 1;
- } else if (record.finalStatus === 'failed') {
- summary.failed += 1;
- } else if (record.finalStatus === 'stopped') {
- summary.stopped += 1;
- }
- summary.retryTotal += normalizeRetryCount(record.retryCount);
- return summary;
- }, {
- total: 0,
- success: 0,
- failed: 0,
- stopped: 0,
- retryTotal: 0,
- });
- }
- function buildAccountRunHistorySnapshotPayload(records = []) {
- const normalizedHistory = normalizeAccountRunHistory(records);
- return {
- generatedAt: new Date().toISOString(),
- summary: summarizeAccountRunHistory(normalizedHistory),
- records: normalizedHistory,
- };
- }
- function shouldSyncAccountRunHistorySnapshot(state = {}) {
- if (!Boolean(state.accountRunHistoryTextEnabled)) {
- return false;
- }
- const helperBaseUrl = normalizeAccountRunHistoryHelperBaseUrl(state.accountRunHistoryHelperBaseUrl);
- return Boolean(helperBaseUrl);
- }
- function shouldAppendAccountRunTextFile(state = {}) {
- return shouldSyncAccountRunHistorySnapshot(state);
- }
- async function syncAccountRunHistorySnapshot(records, stateOverride = null) {
- const state = stateOverride || await getState();
- if (!shouldSyncAccountRunHistorySnapshot(state)) {
- return '';
- }
- const helperBaseUrl = normalizeAccountRunHistoryHelperBaseUrl(state.accountRunHistoryHelperBaseUrl);
- let response;
- try {
- response = await fetch(buildLocalHelperEndpoint(helperBaseUrl, '/sync-account-run-records'), {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- Accept: 'application/json',
- },
- body: JSON.stringify(buildAccountRunHistorySnapshotPayload(records)),
- });
- } catch (err) {
- throw new Error(`账号记录快照同步失败:无法连接本地 helper(${getErrorMessage(err)})`);
- }
- let payload = null;
- try {
- payload = await response.json();
- } catch (err) {
- throw new Error(`账号记录快照同步失败:本地 helper 返回了无法解析的响应(${getErrorMessage(err)})`);
- }
- if (!response.ok || payload?.ok === false) {
- throw new Error(`账号记录快照同步失败:${payload?.error || `HTTP ${response.status}`}`);
- }
- return payload?.filePath || '';
- }
- async function appendAccountRunRecord(status, stateOverride = null, reason = '') {
- const state = stateOverride || await getState();
- const record = await appendAccountRunHistoryRecord(status, state, reason);
- if (!record) {
- return null;
- }
- try {
- const history = await getPersistedAccountRunHistory();
- const filePath = await syncAccountRunHistorySnapshot(history, state);
- if (filePath) {
- await addLog(`账号记录快照已同步到本地:${filePath}`, 'info');
- }
- } catch (err) {
- await addLog(getErrorMessage(err), 'warn');
- }
- return record;
- }
- async function clearAccountRunHistory(stateOverride = null) {
- const state = stateOverride || await getState();
- const history = await getPersistedAccountRunHistory();
- await setPersistedAccountRunHistory([]);
- try {
- const filePath = await syncAccountRunHistorySnapshot([], state);
- if (filePath) {
- await addLog(`账号记录快照已同步到本地:${filePath}`, 'info');
- }
- } catch (err) {
- await addLog(getErrorMessage(err), 'warn');
- }
- return {
- clearedCount: history.length,
- };
- }
- return {
- appendAccountRunRecord,
- appendAccountRunHistoryRecord,
- buildAccountRunHistoryRecord,
- buildAccountRunHistorySnapshotPayload,
- clearAccountRunHistory,
- getPersistedAccountRunHistory,
- normalizeAccountRunHistory,
- normalizeAccountRunHistoryRecord,
- normalizeFinalStatus,
- setPersistedAccountRunHistory,
- shouldAppendAccountRunTextFile,
- shouldSyncAccountRunHistorySnapshot,
- summarizeAccountRunHistory,
- syncAccountRunHistorySnapshot,
- };
- }
- return {
- createAccountRunHistoryHelpers,
- };
- });
|