feat: add support for running status in account run history and UI

- Enhanced account run history to include 'running' status with appropriate translations and summaries.
- Updated logging status to handle new error message format.
- Introduced new properties for task progress in create-plus-checkout step.
- Modified fill-plus-checkout step to handle additional error details.
- Updated account records manager to display running status and summary correctly.
- Added CSS styles for running status in account records.
- Implemented logic to refresh account run history based on auto-run state changes.
- Added tests for running status and idle log restart functionality in auto-run steps.
- Improved account records manager tests to validate running state display and failure details.
This commit is contained in:
QLHazyCoder
2026-05-10 18:36:34 +08:00
parent 6bd00dbd5b
commit 48d3d5fc12
14 changed files with 727 additions and 35 deletions
+99 -12
View File
@@ -21,19 +21,25 @@
success: {
label: '成',
className: 'is-success',
matches: (record) => record.finalStatus === 'success',
matches: (record) => getRecordDisplayStatus(record) === 'success',
metaLabel: '成功',
},
running: {
label: '运行',
className: 'is-running',
matches: (record) => getRecordDisplayStatus(record) === 'running',
metaLabel: '运行中',
},
failed: {
label: '失',
className: 'is-failed',
matches: (record) => record.finalStatus === 'failed',
matches: (record) => getRecordDisplayStatus(record) === 'failed',
metaLabel: '失败',
},
stopped: {
label: '停',
className: 'is-stopped',
matches: (record) => record.finalStatus === 'stopped',
matches: (record) => getRecordDisplayStatus(record) === 'stopped',
metaLabel: '停止',
},
retry: {
@@ -96,6 +102,58 @@
: identifier.toLowerCase();
}
function getRecordDisplayStatus(record = {}) {
return String(record.displayStatus || record.finalStatus || '').trim().toLowerCase();
}
function isAutoRunRecordDisplayRunning(currentState = {}) {
const phase = String(currentState.autoRunPhase || '').trim().toLowerCase();
return Boolean(currentState.autoRunning)
&& ['running', 'waiting_step', 'waiting_email', 'retrying'].includes(phase);
}
function buildCurrentAccountRecordId(currentState = {}) {
const accountIdentifierType = String(currentState.accountIdentifierType || '').trim().toLowerCase();
const email = String(currentState.email || '').trim();
const phoneNumber = String(
currentState.signupPhoneNumber
|| currentState.phoneNumber
|| currentState.phone
|| ''
).trim();
const accountIdentifier = String(
currentState.accountIdentifier
|| (accountIdentifierType === 'phone' ? phoneNumber : email)
|| ''
).trim();
return buildRecordId({
accountIdentifierType,
accountIdentifier,
email,
phoneNumber,
});
}
function applyRunningDisplayState(record = {}, currentState = {}) {
if (!isAutoRunRecordDisplayRunning(currentState)) {
return record;
}
if (getRecordDisplayStatus(record) === 'success') {
return record;
}
const currentRecordId = buildCurrentAccountRecordId(currentState);
if (!currentRecordId || buildRecordId(record) !== currentRecordId) {
return record;
}
return {
...record,
displayStatus: 'running',
displaySummary: '正在运行',
};
}
function getRecordIdentifierType(record = {}) {
const rawType = String(record.accountIdentifierType || '').trim().toLowerCase();
if (rawType === 'phone') {
@@ -167,18 +225,22 @@
return (Array.isArray(currentState?.accountRunHistory) ? currentState.accountRunHistory : [])
.filter((item) => item && typeof item === 'object')
.slice()
.sort((left, right) => normalizeTimestamp(right.finishedAt) - normalizeTimestamp(left.finishedAt));
.sort((left, right) => normalizeTimestamp(right.finishedAt) - normalizeTimestamp(left.finishedAt))
.map((record) => applyRunningDisplayState(record, currentState));
}
function summarizeAccountRunHistory(records = []) {
return records.reduce((summary, record) => {
const retryCount = normalizeRetryCount(record.retryCount);
const status = getRecordDisplayStatus(record);
summary.total += 1;
if (record.finalStatus === 'success') {
if (status === 'success') {
summary.success += 1;
} else if (record.finalStatus === 'failed') {
} else if (status === 'running') {
summary.running += 1;
} else if (status === 'failed') {
summary.failed += 1;
} else if (record.finalStatus === 'stopped') {
} else if (status === 'stopped') {
summary.stopped += 1;
}
if (retryCount > 0) {
@@ -189,6 +251,7 @@
}, {
total: 0,
success: 0,
running: 0,
failed: 0,
stopped: 0,
retryRecordCount: 0,
@@ -227,21 +290,44 @@
}
function getStatusMeta(record = {}) {
if (record.finalStatus === 'success') {
const status = getRecordDisplayStatus(record);
if (status === 'success') {
return { kind: 'success', label: '成功' };
}
if (record.finalStatus === 'stopped') {
if (status === 'running') {
return { kind: 'running', label: '正在运行' };
}
if (status === 'stopped') {
return { kind: 'stopped', label: '停止' };
}
return { kind: 'failed', label: '失败' };
}
function getRecordSummaryText(record = {}) {
if (record.finalStatus === 'success') {
const status = getRecordDisplayStatus(record);
if (record.displaySummary) {
return String(record.displaySummary || '').trim();
}
if (status === 'success') {
return '流程完成';
}
if (status === 'running') {
return '正在运行';
}
return String(record.failureLabel || '').trim() || '流程失败';
return String(record.failureDetail || record.reason || '').trim()
|| String(record.failureLabel || '').trim()
|| '流程失败';
}
function getRecordTooltipText(record = {}, summaryText = '') {
const recordTitle = getRecordTitle(record);
const status = getRecordDisplayStatus(record);
const detail = String(record.displaySummary || record.failureDetail || record.reason || '').trim();
if (status === 'success' || status === 'running' || !detail || detail === recordTitle) {
return recordTitle;
}
return `${recordTitle}\n${detail}`;
}
function getFilterConfig(filterKey = activeFilter) {
@@ -378,6 +464,7 @@
const summary = summarizeAccountRunHistory(allRecords);
dom.accountRecordsStats.innerHTML = [
createStatChip('all', summary.total),
createStatChip('running', summary.running),
createStatChip('success', summary.success),
createStatChip('failed', summary.failed),
createStatChip('stopped', summary.stopped),
@@ -449,9 +536,9 @@
const recordId = buildRecordId(record);
const primaryIdentifier = getRecordPrimaryIdentifier(record) || '(空账号)';
const secondaryIdentifier = getRecordSecondaryIdentifier(record);
const recordTitle = getRecordTitle(record);
const statusMeta = getStatusMeta(record);
const summaryText = getRecordSummaryText(record);
const recordTitle = getRecordTooltipText(record, summaryText);
const retryCount = normalizeRetryCount(record.retryCount);
const isSelected = selectedRecordIds.has(recordId);
const itemClassNames = [
+20 -2
View File
@@ -2985,6 +2985,12 @@ header {
border-color: color-mix(in srgb, var(--green) 16%, var(--border));
}
.account-records-stat.is-running {
color: var(--blue);
background: var(--blue-soft);
border-color: color-mix(in srgb, var(--blue) 16%, var(--border));
}
.account-records-stat.is-failed {
color: var(--red);
background: var(--red-soft);
@@ -3158,8 +3164,11 @@ header {
min-width: 0;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow-wrap: anywhere;
white-space: normal;
color: var(--text-secondary);
font-size: 11px;
line-height: 1.4;
@@ -3186,6 +3195,15 @@ header {
color: var(--green);
}
.account-record-item.is-running {
border-color: color-mix(in srgb, var(--blue) 14%, var(--border-subtle));
}
.account-record-item.is-running .account-record-item-status {
background: var(--blue-soft);
color: var(--blue);
}
.account-record-item.is-failed {
border-color: color-mix(in srgb, var(--red) 14%, var(--border-subtle));
}
+21
View File
@@ -2065,6 +2065,23 @@ function syncLatestState(nextState) {
renderAccountRecords(latestState);
}
let accountRunHistoryRefreshTimer = null;
function scheduleAccountRunHistoryRefresh(delayMs = 150) {
if (accountRunHistoryRefreshTimer) {
clearTimeout(accountRunHistoryRefreshTimer);
}
accountRunHistoryRefreshTimer = setTimeout(() => {
accountRunHistoryRefreshTimer = null;
chrome.runtime.sendMessage({ type: 'GET_STATE', source: 'sidepanel' }).then(state => {
syncLatestState(state);
syncAutoRunState(state);
updateStatusDisplay(latestState);
updateButtonStates();
}).catch(() => { });
}, Math.max(0, Number(delayMs) || 0));
}
function normalizeOperationDelayEnabled(value) {
return typeof value === 'boolean' ? value : true;
}
@@ -13380,6 +13397,7 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
appendLog(message.payload);
if (message.payload.level === 'error') {
showToast(message.payload.message, 'error');
scheduleAccountRunHistoryRefresh();
}
break;
@@ -14135,6 +14153,9 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
applyAutoRunStatus(message.payload);
updateStatusDisplay(latestState);
updateButtonStates();
if (!['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(message.payload.phase)) {
scheduleAccountRunHistoryRefresh();
}
break;
}
}