提交新增内容
This commit is contained in:
@@ -9,12 +9,43 @@
|
||||
|
||||
<div class="nav-tabs">
|
||||
<div class="nav-tab-group">
|
||||
<button type="button" class="nav-tab active">品牌检测</button>
|
||||
<button
|
||||
type="button"
|
||||
class="nav-tab"
|
||||
:class="{ active: activeTab === 'brand' }"
|
||||
@click="activeTab = 'brand'"
|
||||
>
|
||||
品牌检测
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="nav-tab"
|
||||
:class="{ active: activeTab === 'dedupe' }"
|
||||
@click="activeTab = 'dedupe'"
|
||||
>
|
||||
数据去重
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="nav-tab"
|
||||
:class="{ active: activeTab === 'convert' }"
|
||||
@click="activeTab = 'convert'"
|
||||
>
|
||||
格式转换
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="nav-tab"
|
||||
:class="{ active: activeTab === 'split' }"
|
||||
@click="activeTab = 'split'"
|
||||
>
|
||||
数据拆分
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main-content">
|
||||
<div v-if="activeTab === 'brand'" class="main-content">
|
||||
<aside class="left-panel">
|
||||
<div class="section-title">选择文件</div>
|
||||
<div class="upload-zone">
|
||||
@@ -106,26 +137,9 @@
|
||||
<button type="button" class="template-download-row" @click="downloadTemplateXlsx">
|
||||
<span class="template-download-icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" fill="none">
|
||||
<path
|
||||
d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z"
|
||||
stroke="rgba(255,255,255,0.92)"
|
||||
stroke-width="1.8"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M14 2v6h6"
|
||||
stroke="rgba(255,255,255,0.92)"
|
||||
stroke-width="1.8"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M8 13h8M8 17h5"
|
||||
stroke="rgba(255,255,255,0.86)"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z" stroke="rgba(255,255,255,0.92)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M14 2v6h6" stroke="rgba(255,255,255,0.92)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M8 13h8M8 17h5" stroke="rgba(255,255,255,0.86)" stroke-width="1.5" stroke-linecap="round" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="template-download-text">
|
||||
@@ -137,26 +151,9 @@
|
||||
<button type="button" class="template-download-row" @click="downloadTemplateZip">
|
||||
<span class="template-download-icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" fill="none">
|
||||
<path
|
||||
d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z"
|
||||
stroke="rgba(255,255,255,0.92)"
|
||||
stroke-width="1.8"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M14 2v6h6"
|
||||
stroke="rgba(255,255,255,0.92)"
|
||||
stroke-width="1.8"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M4 8h16M7 12h10M7 16h7"
|
||||
stroke="rgba(255,255,255,0.86)"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z" stroke="rgba(255,255,255,0.92)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M14 2v6h6" stroke="rgba(255,255,255,0.92)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M4 8h16M7 12h10M7 16h7" stroke="rgba(255,255,255,0.86)" stroke-width="1.5" stroke-linecap="round" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="template-download-text">
|
||||
@@ -188,10 +185,7 @@
|
||||
class="inline-progress"
|
||||
>
|
||||
<div class="progress-bar-bg small">
|
||||
<div
|
||||
class="progress-bar-fill"
|
||||
:style="{ width: `${getTaskProgressPercent(task)}%` }"
|
||||
></div>
|
||||
<div class="progress-bar-fill" :style="{ width: `${getTaskProgressPercent(task)}%` }"></div>
|
||||
</div>
|
||||
<span class="inline-progress-text">
|
||||
{{ task.progress_current || 0 }} / {{ task.progress_total || 0 }}
|
||||
@@ -227,6 +221,10 @@
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<BrandDedupeTab v-else-if="activeTab === 'dedupe'" />
|
||||
<BrandConvertTab v-else-if="activeTab === 'convert'" />
|
||||
<BrandSplitTab v-else-if="activeTab === 'split'" />
|
||||
</div>
|
||||
</PageShell>
|
||||
</template>
|
||||
@@ -249,8 +247,12 @@ import {
|
||||
type BrandTaskItem,
|
||||
} from '@/shared/api/brand'
|
||||
import { getPywebviewApi, hasPywebview } from '@/shared/bridges/pywebview'
|
||||
import BrandDedupeTab from '@/pages/brand/components/BrandDedupeTab.vue'
|
||||
import BrandConvertTab from '@/pages/brand/components/BrandConvertTab.vue'
|
||||
import BrandSplitTab from '@/pages/brand/components/BrandSplitTab.vue'
|
||||
|
||||
const hasPywebviewSupport = hasPywebview()
|
||||
const activeTab = ref<'brand' | 'dedupe' | 'convert' | 'split'>('brand')
|
||||
const selectedPaths = ref<string[]>([])
|
||||
const runMode = ref<'immediate' | 'task'>('immediate')
|
||||
const matchStrategy = ref<'Terms' | 'Simple'>('Terms')
|
||||
@@ -267,10 +269,7 @@ let taskRefreshTimer: number | null = null
|
||||
|
||||
const displayPaths = computed(() => selectedPaths.value.slice(0, 8))
|
||||
const progressPercent = computed(() => {
|
||||
if (!progressTotal.value) {
|
||||
return progressStatus.value === 'running' ? 12 : 100
|
||||
}
|
||||
|
||||
if (!progressTotal.value) return progressStatus.value === 'running' ? 12 : 100
|
||||
return Math.min(100, Math.round((progressCurrent.value / progressTotal.value) * 100))
|
||||
})
|
||||
|
||||
@@ -298,7 +297,6 @@ function getStatusLabel(status?: string) {
|
||||
failed: '失败',
|
||||
cancelled: '已取消',
|
||||
}
|
||||
|
||||
return statusMap[(status || '').toLowerCase()] || (status || '-')
|
||||
}
|
||||
|
||||
@@ -311,12 +309,10 @@ function getTaskProgressPercent(task: BrandTaskItem) {
|
||||
function stopTaskMonitor() {
|
||||
activeTaskId.value = null
|
||||
running.value = false
|
||||
|
||||
if (taskEvents) {
|
||||
taskEvents.close()
|
||||
taskEvents = null
|
||||
}
|
||||
|
||||
if (pollTimer !== null) {
|
||||
window.clearInterval(pollTimer)
|
||||
pollTimer = null
|
||||
@@ -345,7 +341,6 @@ async function refreshMonitoredTask(taskId: string | number) {
|
||||
progressStatus.value = status as typeof progressStatus.value
|
||||
stopTaskMonitor()
|
||||
await loadTasks()
|
||||
|
||||
if (status === 'success') ElMessage.success('生成完成,可下载结果')
|
||||
if (status === 'failed') ElMessage.error('生成失败')
|
||||
if (status === 'cancelled') ElMessage.info('已取消')
|
||||
@@ -640,12 +635,22 @@ onBeforeUnmount(() => {
|
||||
.nav-tab {
|
||||
padding: 8px 14px;
|
||||
font-size: 13px;
|
||||
color: #3498db;
|
||||
background: rgba(52, 152, 219, 0.2);
|
||||
color: #9fb9d3;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.nav-tab:hover {
|
||||
color: #d8ecff;
|
||||
background: rgba(52, 152, 219, 0.12);
|
||||
}
|
||||
|
||||
.nav-tab.active {
|
||||
color: #3498db;
|
||||
background: rgba(52, 152, 219, 0.2);
|
||||
}
|
||||
|
||||
.main-content {
|
||||
display: flex;
|
||||
height: calc(100vh - 56px);
|
||||
@@ -1093,4 +1098,4 @@ onBeforeUnmount(() => {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
Reference in New Issue
Block a user