style(frontend): 全站背景图 webp 化(bg.jpg 4MB→251KB 压缩 + bg.webp)+品牌工具页默认策略调优(品牌检测默认改精确匹配 Simple、Terms 后置)+任务面板/登录页/亚马逊控制台观感微调
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
<div class="section-title">店铺输入</div>
|
||||
<div class="input-zone">
|
||||
<div class="hint">
|
||||
左侧负责录入店铺并加入备选区,点击“匹配店铺”只会生成匹配结果;确认后需手动点击“启动任务”才会创建并执行任务。任务只会跑下方勾选的国家。
|
||||
左侧负责录入店铺并加入备选区,点击“匹配店铺”得到匹配结果;确认后点“启动任务”开始执行。任务只处理下方勾选的国家。
|
||||
</div>
|
||||
<div class="input-row">
|
||||
<el-input
|
||||
@@ -84,7 +84,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="!deleteConditions.length" class="empty-conditions">
|
||||
暂无删除条件,保存后可在推送任务时多选携带。
|
||||
暂无删除条件,保存后可在启动任务时多选携带。
|
||||
</div>
|
||||
<ul v-else class="condition-list">
|
||||
<li
|
||||
@@ -141,11 +141,11 @@
|
||||
</div>
|
||||
|
||||
<p class="loading-msg">
|
||||
当前页面会把匹配结果合并为一个巡店删除任务推送;多个店铺会在同一个任务和同一个结果文件中汇总。
|
||||
启动后会把所有已确认的店铺汇总成一个任务处理,结果合并到同一个文件中。
|
||||
</p>
|
||||
|
||||
<div v-if="queuePushResult" class="queue-debug-card">
|
||||
<div class="section-title queue-debug-title">队列状态</div>
|
||||
<div class="section-title queue-debug-title">任务状态</div>
|
||||
<div class="queue-debug-line">{{ queuePushResult }}</div>
|
||||
<pre v-if="queuePayloadText" class="queue-debug-payload">{{
|
||||
queuePayloadText
|
||||
@@ -476,7 +476,7 @@ function formatMatchStatus(status?: string) {
|
||||
MATCHED: "已匹配",
|
||||
PENDING: "待匹配",
|
||||
CONFLICT: "需人工确认",
|
||||
INDEX_STALE: "索引过期",
|
||||
INDEX_STALE: "匹配已过期",
|
||||
};
|
||||
return map[value] || value || "-";
|
||||
}
|
||||
@@ -485,12 +485,12 @@ function formatMatchRemark(row: PatrolDeleteShopQueueItem) {
|
||||
const message = (row.matchMessage || "").trim();
|
||||
if (message) return message;
|
||||
if (row.matched && row.matchStatus === "MATCHED") {
|
||||
return "索引已命中,可启动任务";
|
||||
return "已匹配成功,可启动任务";
|
||||
}
|
||||
if (row.matched) {
|
||||
return "已命中索引,请结合状态列确认";
|
||||
return "已匹配成功,请查看状态确认";
|
||||
}
|
||||
return "未命中或未就绪,请检查店铺名";
|
||||
return "未匹配成功,请检查店铺名";
|
||||
}
|
||||
|
||||
function buildTemplateCountrySections(): PatrolDeleteCountrySection[] {
|
||||
@@ -1011,7 +1011,7 @@ async function waitForTaskTerminal(taskId: number) {
|
||||
}
|
||||
if (activeTaskId.value !== taskId) return "DELETED";
|
||||
if (transientErrorCount > 0) {
|
||||
queuePushResult.value = `任务 ${taskId} 后端已恢复,继续等待执行结果...`;
|
||||
queuePushResult.value = `任务 ${taskId} 服务已恢复,继续等待执行结果...`;
|
||||
}
|
||||
transientErrorCount = 0;
|
||||
const item = findHistoryItemByTaskId(taskId);
|
||||
@@ -1026,10 +1026,10 @@ async function waitForTaskTerminal(taskId: number) {
|
||||
transientErrorCount += 1;
|
||||
if (transientErrorCount >= MAX_TRANSIENT_ERRORS) {
|
||||
throw new Error(
|
||||
`任务 ${taskId} 等待后端恢复超时,请稍后刷新查看状态`,
|
||||
`任务 ${taskId} 等待服务恢复超时,请稍后刷新查看状态`,
|
||||
);
|
||||
}
|
||||
queuePushResult.value = `任务 ${taskId} 执行中,正在等待后端服务恢复(${transientErrorCount}/${MAX_TRANSIENT_ERRORS})...`;
|
||||
queuePushResult.value = `任务 ${taskId} 执行中,正在等待服务恢复(${transientErrorCount}/${MAX_TRANSIENT_ERRORS})...`;
|
||||
}
|
||||
await sleep(getTaskPollIntervalMs());
|
||||
}
|
||||
@@ -1065,7 +1065,7 @@ async function processQueue() {
|
||||
const created = await withTransientRetry(
|
||||
() => createPatrolDeleteTask(runnable.map(buildTaskItem)),
|
||||
(attempt, maxAttempts) => {
|
||||
queuePushResult.value = `后端服务暂时不可用,正在重试创建任务(${attempt}/${maxAttempts})...`;
|
||||
queuePushResult.value = `服务暂时不可用,正在重试创建任务(${attempt}/${maxAttempts})...`;
|
||||
},
|
||||
);
|
||||
const createdItems = created.items || [];
|
||||
@@ -1092,7 +1092,7 @@ async function processQueue() {
|
||||
await submitPatrolDeleteTaskResult(created.taskId, {
|
||||
shops: createdItems.map((createdItem) => ({
|
||||
shopName: createdItem.shopName || "",
|
||||
error: `任务 ${created.taskId} 数据校验未通过,已阻止推送`,
|
||||
error: `任务 ${created.taskId} 数据校验未通过,已阻止启动`,
|
||||
countrySections: createdItem.countrySections || [],
|
||||
cartRatios: createdItem.cartRatios || [],
|
||||
shopDone: true,
|
||||
@@ -1102,7 +1102,7 @@ async function processQueue() {
|
||||
})),
|
||||
});
|
||||
await refreshTaskViews();
|
||||
queuePushResult.value = `任务 ${created.taskId} 数据校验未通过,已阻止推送`;
|
||||
queuePushResult.value = `任务 ${created.taskId} 数据校验未通过,已阻止启动`;
|
||||
clearActiveQueueTask();
|
||||
return;
|
||||
}
|
||||
@@ -1112,7 +1112,7 @@ async function processQueue() {
|
||||
await submitPatrolDeleteTaskResult(created.taskId, {
|
||||
shops: createdItems.map((createdItem) => ({
|
||||
shopName: createdItem.shopName || "",
|
||||
error: pushResult?.error || `任务 ${created.taskId} 推送失败`,
|
||||
error: pushResult?.error || `任务 ${created.taskId} 启动失败`,
|
||||
countrySections: createdItem.countrySections || [],
|
||||
cartRatios: createdItem.cartRatios || [],
|
||||
shopDone: true,
|
||||
@@ -1126,13 +1126,13 @@ async function processQueue() {
|
||||
});
|
||||
for (const item of runnable) removeMatchedRowLocally(item);
|
||||
await refreshTaskViews();
|
||||
queuePushResult.value = `任务 ${created.taskId} 推送失败`;
|
||||
queuePushResult.value = `任务 ${created.taskId} 启动失败`;
|
||||
clearActiveQueueTask();
|
||||
return;
|
||||
}
|
||||
|
||||
for (const item of runnable) removeMatchedRowLocally(item);
|
||||
queuePushResult.value = `任务 ${created.taskId} 已入队,共 ${createdItems.length} 个店铺、${selectedCountryNames.value.length} 个国家,等待执行完成`;
|
||||
queuePushResult.value = `任务 ${created.taskId} 已提交,共 ${createdItems.length} 个店铺、${selectedCountryNames.value.length} 个国家,等待执行完成`;
|
||||
|
||||
const finalStatus = await waitForTaskTerminal(created.taskId);
|
||||
queuePushResult.value = `任务 ${created.taskId} ${finalStatus === "SUCCESS" ? "已完成" : finalStatus === "DELETED" ? "已删除" : "执行失败"}`;
|
||||
@@ -1205,7 +1205,7 @@ async function deleteTaskRecord(item: PatrolDeleteHistoryItem) {
|
||||
}
|
||||
removeHistoryItemLocally(item);
|
||||
await loadCandidates();
|
||||
ElMessage.success("后端记录已不存在,已同步移除本地记录");
|
||||
ElMessage.success("记录已不存在,已同步移除本地记录");
|
||||
return;
|
||||
}
|
||||
ElMessage.error(error instanceof Error ? error.message : "删除失败");
|
||||
@@ -1257,24 +1257,24 @@ async function batchDeleteHistory(views: TaskItemView[]) {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.module-page { min-height: 100vh; background: #151a25; }
|
||||
.module-page { min-height: 100vh; background: #242424; }
|
||||
.main-content { display: flex; min-height: calc(100vh - 56px); height: calc(100vh - 56px); }
|
||||
.left-panel { width: 400px; background: #1c2333; padding: 20px; overflow-y: auto; border-right: 1px solid #2e3a52; }
|
||||
.right-panel { flex: 1; display: flex; flex-direction: column; min-width: 0; background: #151a25; }
|
||||
.left-panel { width: 400px; background: #242424; padding: 20px; overflow-y: auto; border-right: 1px solid #2e3a52; }
|
||||
.right-panel { flex: 1; display: flex; flex-direction: column; min-width: 0; background: #242424; }
|
||||
.section-title { font-size: 13px; color: #a0acbe; margin-bottom: 10px; }
|
||||
.condition-title { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
|
||||
.condition-title-hint { flex: 1; min-width: 0; color: #d6a95a; font-size: 12px; text-align: right; line-height: 1.35; }
|
||||
.input-zone { border: 1px dashed #3e4a62; border-radius: 10px; padding: 16px; background: #2e3a52; margin-bottom: 20px; }
|
||||
.input-zone { border: 1px dashed #3e4a62; border-radius: 10px; padding: 16px; background: #242424; margin-bottom: 20px; }
|
||||
.hint { color: #5e6878; font-size: 12px; margin-bottom: 12px; line-height: 1.5; text-align: left; }
|
||||
.input-row { display: flex; gap: 10px; align-items: center; }
|
||||
.input-row :deep(.el-input) { flex: 1; }
|
||||
.opt-btn { padding: 8px 12px; font-size: 12px; color: #c8d2e2; background: #2e3a52; border: 1px solid #3e4a62; border-radius: 6px; cursor: pointer; white-space: nowrap; }
|
||||
.opt-btn { padding: 8px 12px; font-size: 12px; color: #c8d2e2; background: #242424; border: 1px solid #3e4a62; border-radius: 6px; cursor: pointer; white-space: nowrap; }
|
||||
.opt-btn:hover:not(:disabled) { color: #3498db; border-color: #3498db; }
|
||||
.opt-btn:disabled { opacity: 0.6; cursor: not-allowed; }
|
||||
.empty-candidates { color: #5e6878; font-size: 13px; padding: 16px; border: 1px dashed #333; border-radius: 8px; margin-bottom: 16px; }
|
||||
.candidate-table-scroll { max-height: 320px; overflow: auto; margin-bottom: 18px; border-radius: 8px; border: 1px solid #2e3a52; }
|
||||
.candidate-table { --el-table-bg-color: #2e3a52; --el-table-tr-bg-color: #2e3a52; --el-table-header-bg-color: #2e3a52; --el-table-text-color: #c8d2e2; --el-table-border-color: #333; }
|
||||
.condition-panel { margin-bottom: 18px; border: 1px solid #2e3a52; border-radius: 8px; background: #222; padding: 12px; }
|
||||
.candidate-table { --el-table-bg-color: #242424; --el-table-tr-bg-color: #242424; --el-table-header-bg-color: #2e3a52; --el-table-text-color: #c8d2e2; --el-table-border-color: #333; }
|
||||
.condition-panel { margin-bottom: 18px; border: 1px solid #2e3a52; border-radius: 8px; background: #242424; padding: 12px; }
|
||||
.condition-input-row { display: flex; gap: 10px; align-items: center; margin-bottom: 10px; }
|
||||
.condition-input-row :deep(.el-input) { flex: 1; }
|
||||
.empty-conditions { color: #5e6878; font-size: 12px; padding: 10px 4px; }
|
||||
@@ -1300,8 +1300,8 @@ async function batchDeleteHistory(views: TaskItemView[]) {
|
||||
.subsection-title { font-size: 13px; color: #a0acbe; margin: 8px 0 10px; }
|
||||
.match-empty { color: #5e6878; font-size: 13px; padding: 12px 8px; margin-bottom: 12px; text-align: center; }
|
||||
.match-table { margin-bottom: 18px; }
|
||||
.match-table :deep(.el-table__body tr:hover > td.el-table__cell), .match-table :deep(.el-table__body tr.hover-row > td.el-table__cell), .match-table :deep(.el-table__body tr.current-row > td.el-table__cell) { background-color: var(--el-table-tr-bg-color, #222) !important; }
|
||||
.result-table { --el-table-bg-color: #222; --el-table-tr-bg-color: #222; --el-table-header-bg-color: #2e3a52; --el-table-text-color: #c8d2e2; --el-table-border-color: #333; }
|
||||
.match-table :deep(.el-table__body tr:hover > td.el-table__cell), .match-table :deep(.el-table__body tr.hover-row > td.el-table__cell), .match-table :deep(.el-table__body tr.current-row > td.el-table__cell) { background-color: var(--el-table-tr-bg-color, #242424) !important; }
|
||||
.result-table { --el-table-bg-color: #242424; --el-table-tr-bg-color: #242424; --el-table-header-bg-color: #2e3a52; --el-table-text-color: #c8d2e2; --el-table-border-color: #333; }
|
||||
.ok { color: #27ae60; }
|
||||
.fail { color: #e67e22; }
|
||||
.download { padding: 6px 10px; border-radius: 6px; font-size: 12px; background: rgba(52, 152, 219, 0.18); color: #69b6ff; border: none; cursor: pointer; }
|
||||
|
||||
Reference in New Issue
Block a user