feat(web): 前端 SPA 化 + 工具页任务面板统一与历史批量删除

- SPA 化:22 个 MPA html 入口与 *-main.ts 合并为 index.html + vue-router(URL 无 .html 后缀),
  页面跳转全部 router-link,/new_web_source/xxx.html 旧路径归一为 /xxx
- 任务面板统一:共享 TaskCenterPanel/TaskItemCard/TaskStatCards/HistoryTaskLayer,
  16 个工具页右侧统一为统计卡 + 当前任务 + 历史任务弹层(任务ID/开始/结束/状态必展示)
- 历史记录支持单条删除 + 批量勾选删除(确认框/全选/失败提示)
- Java 7 模块(dedupe/convert/split/productrisk/shopmatch/pricetrack/deletebrand)
  history 接口补齐任务时间字段(VO+Service,复用 biz_file_task 列)
- 图片工作台/API 层(brand/permission/user)既有未提交改动一并提交
This commit is contained in:
2026-09-08 10:02:55 +08:00
parent abcfa5bef7
commit e248b6e43a
125 changed files with 7482 additions and 4304 deletions
@@ -1,32 +1,36 @@
<template>
<header class="amazon-top">
<div class="brand">
<router-link class="brand" :to="toolbarHref" title="返回工具台首页">
<span class="brand-logo"></span>
<div class="brand-text">
<span class="brand-text">
<span class="brand-name">数富AI</span>
<span class="brand-sub">亚马逊运营工具台</span>
</div>
</div>
</span>
</router-link>
<nav class="cat-tabs" aria-label="分类导航">
<template v-for="cat in visibleCats" :key="cat.key">
<a
<router-link
class="cat-tab"
:class="{ 'cat-tab--active': cat.key === activeCat }"
:href="`${toolbarHref}#group-${cat.key}`"
:to="`${toolbarHref}#group-${cat.key}`"
@click="onTabClick(cat.key)"
>
<span class="cat-dot" :style="{ background: cat.color }"></span>
<span class="cat-name">{{ cat.name }}</span>
<span class="cat-badge" :style="badgeStyle(cat)">{{ cat.tools.length }}</span>
<span class="cat-underline" :style="{ background: cat.color }"></span>
</a>
<span class="cat-tab-content">
<span class="cat-dot" :style="{ background: cat.color }"></span>
<span class="cat-name">{{ cat.name }}</span>
<span class="cat-badge" :style="badgeStyle(cat)">{{ cat.tools.length }}</span>
</span>
<span class="cat-underline" :style="underlineStyle(cat)"></span>
</router-link>
</template>
</nav>
<div class="top-right">
<a href="/home" class="btn-home">返回首页</a>
<BrandApiSecretSettingsButton />
<span class="help-mark" title="帮助">?</span>
<BrandApiSecretSettingsButton variant="topbar" />
<router-link class="help-btn" :to="workHref" title="采集工作台"></router-link>
<span class="help-btn" title="如需支持请点击底部BUG登记系统">?</span>
<span class="admin-chip"><span class="admin-badge">AD</span>{{ username }}</span>
</div>
</header>
</template>
@@ -50,17 +54,34 @@ const props = withDefaults(
},
)
const emit = defineEmits<{ change: [key: 'front' | 'ops' | 'logi'] }>()
const activeCat = computed(() => props.activeCat)
const visibleCats = ref<VisibleGroup[]>(TOOL_GROUPS.map((group) => ({ ...group, tools: [...group.tools] })))
const username = ref('admin')
/** 分类 tab 点击回到工具台对应分组 */
const toolbarHref = resolvePageHref('/new_web_source/amazon-console.html')
/** ⚙ 采集工作台:直达现有真实功能页(对齐 gemini-code 顶栏 ⚙ 入口) */
const workHref = resolvePageHref('/new_web_source/collect-data.html')
function onTabClick(key: 'front' | 'ops' | 'logi') {
emit('change', key)
}
/** 激活分类角标:分类色实底白字(对齐 gemini-code tab-badge 激活态) */
function badgeStyle(cat: VisibleGroup) {
return activeCat.value === cat.key ? { background: cat.color, color: '#FFFFFF' } : {}
}
/** 激活分类下划线(对齐 gemini-code tab-underline:底部 3px 分类色圆角条) */
function underlineStyle(cat: VisibleGroup) {
return activeCat.value === cat.key ? { background: cat.color } : {}
}
onMounted(async () => {
const localName = typeof window === 'undefined' ? '' : (window.localStorage.getItem('username') || '').trim()
if (localName) username.value = localName
try {
const keys = await getCurrentUserAppColumnKeys()
visibleCats.value = filterGroupsByPermission(TOOL_GROUPS, keys)
@@ -79,9 +100,10 @@ onMounted(async () => {
align-items: center;
justify-content: space-between;
gap: 20px;
padding: 0 24px;
background: #151a25;
border-bottom: 1px solid #2a3344;
padding: 0 28px;
background: #1a1f2e;
border-bottom: 1px solid #3e4a62;
font-family: "PingFang SC", "Microsoft YaHei UI", "Microsoft YaHei", "微软雅黑", sans-serif;
}
.brand {
@@ -89,6 +111,7 @@ onMounted(async () => {
align-items: center;
gap: 12px;
flex-shrink: 0;
text-decoration: none;
}
.brand-logo {
@@ -97,11 +120,12 @@ onMounted(async () => {
justify-content: center;
width: 38px;
height: 38px;
border-radius: 9px;
border-radius: 8px;
background: #f59e0b;
color: #fff;
font-size: 15px;
font-weight: 800;
font-size: 20px;
font-weight: 700;
box-shadow: 0 2px 8px rgba(245, 158, 11, 0.3);
}
.brand-text {
@@ -112,14 +136,13 @@ onMounted(async () => {
.brand-name {
color: #f5f8fc;
font-size: 16px;
font-weight: 800;
letter-spacing: 0.02em;
font-size: 17px;
font-weight: 700;
white-space: nowrap;
}
.brand-sub {
color: #5e6878;
color: #a0acbe;
font-size: 10px;
white-space: nowrap;
}
@@ -130,36 +153,46 @@ onMounted(async () => {
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
gap: 8px;
}
.cat-tab {
position: relative;
display: inline-flex;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
min-width: 132px;
height: 38px;
padding: 0 14px;
border-radius: 10px;
width: 140px;
height: 42px;
background: transparent;
color: #c8d2e2;
font-size: 13px;
font-weight: 700;
text-decoration: none;
transition: background 0.18s ease, color 0.18s ease;
transition: all 0.2s;
}
.cat-tab:hover {
background: #232a3b;
.cat-tab-content {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 14px;
border-radius: 8px;
transition: background 0.2s;
}
.cat-tab:hover .cat-tab-content {
background: #3d4a63;
color: #f5f8fc;
}
.cat-tab--active {
background: #3d4a63;
color: #f5f8fc;
}
.cat-tab--active .cat-tab-content {
background: #3d4a63;
}
.cat-dot {
width: 8px;
height: 8px;
@@ -171,33 +204,23 @@ onMounted(async () => {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 22px;
height: 18px;
padding: 0 4px;
border-radius: 999px;
background: #2b3447;
color: #5e6878;
padding: 1px 7px;
border-radius: 12px;
background: #343f55;
color: #a0acbe;
font-size: 10px;
font-weight: 800;
}
.cat-tab--active .cat-badge {
color: #fff;
font-weight: 700;
}
.cat-underline {
position: absolute;
left: 10px;
right: 10px;
bottom: -4px;
left: 0;
right: 0;
bottom: 0;
height: 3px;
border-radius: 2px;
border-radius: 3px 3px 0 0;
background: transparent;
opacity: 0;
}
.cat-tab--active .cat-underline {
opacity: 1;
transition: background 0.2s;
}
.top-right {
@@ -207,29 +230,45 @@ onMounted(async () => {
flex-shrink: 0;
}
.btn-home {
color: #a0acbe;
font-size: 13px;
text-decoration: none;
white-space: nowrap;
}
.btn-home:hover {
color: #fff;
}
.help-mark {
.help-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 22px;
min-width: 22px;
height: 22px;
border-radius: 50%;
background: #232a3b;
color: #a0acbe;
font-size: 13px;
font-weight: 800;
cursor: help;
color: #c8d2e2;
font-size: 16px;
font-weight: 700;
text-decoration: none;
cursor: pointer;
padding: 4px 8px;
}
.help-btn:hover {
color: #f5f8fc;
}
.admin-chip {
display: inline-flex;
align-items: center;
gap: 8px;
color: #c8d2e2;
font-size: 12px;
font-weight: 700;
white-space: nowrap;
}
.admin-badge {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 22px;
height: 20px;
padding: 0 4px;
background: #2a6b4f;
color: #ffffff;
font-size: 10px;
font-weight: 700;
}
@media (max-width: 1100px) {