增加代码检测,和映射

This commit is contained in:
wuweihua
2026-10-13 13:39:15 +08:00
parent b40033f424
commit 52816ad618
22 changed files with 1573 additions and 0 deletions
@@ -0,0 +1,132 @@
<template>
<el-drawer v-model="visible" size="920px" title="产品套餐比对" append-to-body destroy-on-close>
<div v-loading="loading">
<el-empty v-if="!loading && !result" description="暂无结果" />
<template v-else-if="result">
<el-alert
v-if="result.truncated"
type="warning"
:closable="false"
show-icon
class="mb12"
title="订单超过上限,仅对已扫描部分进行比对"
/>
<el-descriptions :column="3" border size="small" class="mb12">
<el-descriptions-item label="筛选订单数">{{ result.orderTotal ?? 0 }}</el-descriptions-item>
<el-descriptions-item label="已扫描">{{ result.scannedOrders ?? 0 }}</el-descriptions-item>
<el-descriptions-item label="套餐截止时间">{{ result.asOfTime || '-' }}</el-descriptions-item>
<el-descriptions-item label="套餐产品数">{{ result.packageProductCount ?? 0 }}</el-descriptions-item>
<el-descriptions-item label="订单产品数">{{ result.distinctOrderProducts ?? 0 }}</el-descriptions-item>
<el-descriptions-item label="命中/缺失">
<el-tag type="success" size="small">{{ result.matchedCount ?? 0 }}</el-tag>
<span class="sep">/</span>
<el-tag type="danger" size="small">{{ result.missingCount ?? 0 }}</el-tag>
</el-descriptions-item>
</el-descriptions>
<el-tabs v-model="activeTab">
<el-tab-pane :label="missingTabLabel" name="missing">
<el-table :data="result.missingProducts || []" border size="small" max-height="520">
<el-table-column prop="customerCode" label="客户代码" min-width="110" show-overflow-tooltip />
<el-table-column prop="upstreamCode" label="上游产品代码" min-width="120" show-overflow-tooltip />
<el-table-column prop="productName" label="产品名称" min-width="140" show-overflow-tooltip />
<el-table-column prop="mappedCode" label="映射后代码" min-width="120" show-overflow-tooltip>
<template #default="{ row }">{{ row.mappedCode || '-' }}</template>
</el-table-column>
<el-table-column prop="orderCount" label="订单数" width="90" align="center" />
<el-table-column label="示例订单" min-width="180" show-overflow-tooltip>
<template #default="{ row }">{{ (row.sampleOrderIds || []).join(', ') || '-' }}</template>
</el-table-column>
</el-table>
<el-empty v-if="!(result.missingProducts || []).length" description="未发现缺失产品" />
</el-tab-pane>
<el-tab-pane label="全部比对" name="all">
<el-table :data="result.orderProducts || []" border size="small" max-height="520">
<el-table-column prop="customerCode" label="客户代码" min-width="110" show-overflow-tooltip />
<el-table-column prop="upstreamCode" label="上游产品代码" min-width="120" show-overflow-tooltip />
<el-table-column prop="productName" label="产品名称" min-width="140" show-overflow-tooltip />
<el-table-column prop="mappedCode" label="映射后代码" min-width="120" show-overflow-tooltip>
<template #default="{ row }">{{ row.mappedCode || '-' }}</template>
</el-table-column>
<el-table-column label="是否在套餐" width="120" align="center">
<template #default="{ row }">
<el-tag v-if="row.covered" size="small" type="success">在套餐</el-tag>
<el-tag v-else size="small" type="danger">不在套餐</el-tag>
</template>
</el-table-column>
<el-table-column label="命中方式" min-width="140" show-overflow-tooltip>
<template #default="{ row }">{{ hitText(row) }}</template>
</el-table-column>
<el-table-column prop="orderCount" label="订单数" width="90" align="center" />
</el-table>
</el-tab-pane>
<el-tab-pane :label="packageTabLabel" name="package">
<el-table :data="result.packageProducts || []" border size="small" max-height="520">
<el-table-column prop="customerCode" label="客户代码" min-width="110" show-overflow-tooltip />
<el-table-column prop="productCode" label="套餐产品代码" min-width="130" show-overflow-tooltip />
<el-table-column prop="productName" label="产品名称" min-width="160" show-overflow-tooltip />
</el-table>
<el-empty v-if="!(result.packageProducts || []).length" description="客户未绑定套餐产品" />
</el-tab-pane>
</el-tabs>
</template>
</div>
</el-drawer>
</template>
<script setup>
import { ElMessage } from 'element-plus'
import { checkOrderSourceProducts } from '@/api/monitor/orderSource'
const visible = ref(false)
const loading = ref(false)
const result = ref(null)
const activeTab = ref('missing')
const missingTabLabel = computed(() => {
const n = result.value?.missingCount ?? 0
return '缺失产品 (' + n + ')'
})
const packageTabLabel = computed(() => {
const n = result.value?.packageProductCount ?? 0
return '套餐产品 (' + n + ')'
})
function hitText(row) {
if (!row) return '-'
if (row.inPackage) return '直接命中'
if (row.mappedInPackage) return '映射后命中'
if (row.mappedCode) return '有映射但仍不在套餐'
return '无映射'
}
function open(query) {
if (!query || !query.customerCodes || !query.beginTime || !query.endTime) {
ElMessage.warning('请先选择客户和提货时间')
return
}
visible.value = true
activeTab.value = 'missing'
result.value = null
loading.value = true
checkOrderSourceProducts(query).then(res => {
result.value = res.data || null
if ((result.value?.missingCount || 0) > 0) {
activeTab.value = 'missing'
} else {
activeTab.value = 'all'
}
}).catch(() => {
result.value = null
}).finally(() => {
loading.value = false
})
}
defineExpose({ open })
</script>
<style scoped>
.mb12 { margin-bottom: 12px; }
.sep { margin: 0 6px; color: var(--el-text-color-secondary); }
</style>
@@ -46,6 +46,16 @@
@click="openFilterSync()"
>同步计费</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Search"
:loading="checkLoading"
v-hasPermi="['monitor:orderSource:list']"
@click="handleCheckProducts()"
>检测产品</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
@@ -93,6 +103,7 @@
@success="onSyncSuccess"
/>
<order-source-sync-log-drawer ref="logDrawerRef" />
<order-source-product-check-drawer ref="productCheckDrawerRef" />
</div>
</template>
@@ -101,11 +112,14 @@ import { ElMessage } from 'element-plus'
import { listOrderSource, syncOrderSourceSelected } from '@/api/monitor/orderSource'
import OrderSourceSyncDialog from './components/OrderSourceSyncDialog.vue'
import OrderSourceSyncLogDrawer from './components/OrderSourceSyncLogDrawer.vue'
import OrderSourceProductCheckDrawer from './components/OrderSourceProductCheckDrawer.vue'
const { proxy } = getCurrentInstance()
const tableRef = ref()
const syncDialogRef = ref()
const logDrawerRef = ref()
const productCheckDrawerRef = ref()
const checkLoading = ref(false)
const syncingKey = ref(null)
const batchLoading = ref(false)
const syncFloat = ref(null)
@@ -281,6 +295,24 @@ function handleSyncOne(row) {
})
}
function handleCheckProducts() {
const q = buildFilterQuery()
if (!q.customerCodes || !q.beginTime || !q.endTime) {
ElMessage.warning('请先选择客户和提货时间')
return
}
const codes = Array.isArray(q.customerCodes) ? q.customerCodes.filter(v => v != null && String(v).trim() !== '') : []
if (!codes.length) {
ElMessage.warning('请先选择客户和提货时间')
return
}
q.customerCodes = codes
checkLoading.value = true
productCheckDrawerRef.value?.open(q)
window.setTimeout(() => { checkLoading.value = false }, 300)
}
function handleBatchSync(selection) {
if (!selection || !selection.length) return
proxy.$modal.confirm('确认同步选中的 ' + selection.length + ' 条订单?', '二次确认').then(() => {