feat(web-admin): align archive brand qty entry with chips UI

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-07-31 05:37:00 +08:00
1 parent 5c323f32c2
commit aea4caed5b
1 file changed
+42 -45
@@ -32,33 +32,17 @@
<span class="pl-archive-brand-qty-title">{{ row.productName }} · 按品牌填量</span>
<el-tag v-if="row.brandMode === 'required'" size="small" type="warning">指定品牌</el-tag>
<el-tag v-else size="small" type="info">不限品牌</el-tag>
<span
v-if="!isBrandQtySumMatch(row)"
class="pl-archive-brand-qty-warn"
>
各品牌合计须等于实际数量({{ Number(row.actualQty ?? 0) }})
</span>
</div>
<el-table :data="row.brandQtyRows || []" stripe size="small" class="list-table">
<el-table-column label="品牌" min-width="140" show-overflow-tooltip>
<template #default="{ row: brandRow }">
{{ brandRow.brandName || '—' }}
</template>
</el-table-column>
<el-table-column label="数量" min-width="140" align="right">
<template #default="{ row: brandRow }">
<el-input-number
v-model="brandRow.qty"
:min="0"
:precision="3"
:controls="false"
:disabled="row.brandMode === 'required'"
style="width: 100%"
@change="() => onBrandQtyChange(row)"
/>
</template>
</el-table-column>
</el-table>
<BrandQtyChipsField
v-model="row.brandQtyRows"
:brand-mode="archiveBrandMode(row)"
:required-brand-id="row.brandId"
:brand-options="row.brandOptions || []"
:unit="row.unit || '吨'"
variant="admin"
:actual-qty="Number(row.actualQty ?? 0)"
@update:actual-qty="(val) => onArchiveBrandActualQty(row, val)"
/>
</div>
</section>
@@ -163,6 +147,7 @@ import {
type PlIoOrder,
type Transport
} from '@/api/pl'
import BrandQtyChipsField from '@/components/business/brand-qty-chips-field/index.vue'
import PlPlanFormProductTable from '@/components/business/pl-plan-form-dialog/PlPlanFormProductTable.vue'
import PlPlanViewTabs from '@/components/business/pl-plan-view-tabs/index.vue'
import type { PlanFormProductRow } from '@/composables/usePlContractToPlan'
@@ -235,6 +220,11 @@ const brandedProductRows = computed(() =>
productRows.value.filter(row => row.brandMode === 'required' || row.brandMode === 'any')
)
function archiveBrandMode(row: PlanFormProductRow): 'any' | 'required' | null {
if (row.brandMode === 'any' || row.brandMode === 'required') return row.brandMode
return null
}
function brandQtySum(row: PlanFormProductRow): number {
return (row.brandQtyRows || []).reduce((sum, item) => sum + Number(item.qty || 0), 0)
}
@@ -244,9 +234,10 @@ function isBrandQtySumMatch(row: PlanFormProductRow): boolean {
return Math.abs(brandQtySum(row) - Number(row.actualQty ?? 0)) < 0.0005
}
function onBrandQtyChange(row: PlanFormProductRow) {
function onArchiveBrandActualQty(row: PlanFormProductRow, val: number) {
// any:合计回写实际数量;required:实际数量可在产品表改,芯片数量跟合计联动
if (row.brandMode === 'any') {
row.actualQty = Number(brandQtySum(row).toFixed(3))
row.actualQty = Number(val)
}
}
@@ -274,6 +265,7 @@ function mapPlanProducts(products: PlanProduct[]): PlanFormProductRow[] {
brandMode: item.brandMode,
brandId: item.brandId,
brandName: item.brandName,
brandOptions: [],
brandQtyRows: [],
model: item.model,
categoryName: item.categoryName,
@@ -315,26 +307,36 @@ async function initBrandQtyRows(rows: PlanFormProductRow[]) {
rows.forEach(row => {
const actual = Number(row.actualQty ?? 0)
if (row.brandMode === 'required') {
row.brandQtyRows = [
{
brandId: row.brandId || '',
brandName: row.brandName || '指定品牌',
qty: actual
}
]
const option = {
brandId: row.brandId || '',
brandName: row.brandName || '指定品牌'
}
row.brandOptions = option.brandId ? [option] : []
row.brandQtyRows = option.brandId
? [{ brandId: option.brandId, brandName: option.brandName, qty: actual }]
: []
return
}
if (row.brandMode === 'any') {
const brands = (detailMap.get(row.productId)?.brands || []).filter(
b => (b.status || 'on') === 'on'
)
row.brandQtyRows = brands.map(b => ({
row.brandOptions = brands.map(b => ({
brandId: b.id || '',
brandName: b.brandName,
qty: 0
brandName: b.brandName || ''
}))
if (row.brandQtyRows.length === 1) {
row.brandQtyRows[0].qty = actual
// 芯片交互:默认不预选;仅单品牌时预填实际数量
if (row.brandOptions.length === 1) {
row.brandQtyRows = [
{
brandId: row.brandOptions[0].brandId,
brandName: row.brandOptions[0].brandName,
qty: actual
}
]
row.actualQty = actual
} else {
row.brandQtyRows = []
}
}
})
@@ -594,11 +596,6 @@ async function handleSubmit() {
color: #334155;
}
.pl-archive-brand-qty-warn {
font-size: 12px;
color: var(--el-color-danger, #ef4444);
}
.pl-plan-freight-section {
.pl-plan-subtitle {
margin-top: 4px;