fix(pl): keep multi-brand site feedback when plan product row is stale

Persist submitted brand qtys even if plan brand_mode lookup fails; resolve soft-deleted plan products for brand metadata instead of substituting another product; stop seeding all actual qty onto the first brand option.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-07-31 07:06:41 +08:00
1 parent d1daedc17d
commit 5a9abfdd5d
6 files changed
+220 -54

No files matched your search

@@ -201,27 +201,7 @@
setQty(brandId, normalized)
}
watch(
() => [props.brandMode, props.requiredBrandId, props.brandOptions] as const,
() => {
if (props.brandMode !== 'required') return
const id = props.requiredBrandId || props.brandOptions[0]?.brandId
if (!id) return
const opt = props.brandOptions.find((o) => o.brandId === id)
const existing = props.modelValue.find((r) => r.brandId === id)
if (!existing) {
emitRows([
...props.modelValue,
{
brandId: id,
brandName: opt?.brandName || '指定品牌',
qty: 0
}
])
}
},
{ immediate: true }
)
// 偏好品牌预选由父级初始化;组件内不再强制回填,避免取消后被再次插入
</script>
<style scoped lang="scss">
@@ -80,6 +80,14 @@
<span class="product-card__badge">产品 {{ idx + 1 }}/{{ editableItems.length }}</span>
</div>
<div class="meta-grid">
<div class="meta-item">
<div class="meta-item__label">别名</div>
<div class="meta-item__value">{{ item.aliasName || '—' }}</div>
</div>
<div class="meta-item">
<div class="meta-item__label">品牌</div>
<div class="meta-item__value">{{ formatBrandLabel(item) }}</div>
</div>
<div class="meta-item">
<div class="meta-item__label">规格型号</div>
<div class="meta-item__value">{{ item.specification || '—' }}</div>
@@ -191,6 +199,7 @@
import BrandQtyChipsField from '@/components/business/brand-qty-chips-field/index.vue'
import PublicMobileShell from '@/layouts/PublicMobileShell.vue'
import { buildAmapNavigationUrl } from '@/utils/amap/navigation'
import { resolvePlanBrandDisplayLabel } from '@/utils/pl-display'
import 'vant/es/dialog/style'
import 'vant/es/toast/style'
@@ -262,6 +271,10 @@
return unit ? `${qty} ${unit}` : String(qty)
}
function formatBrandLabel(item: PublicIoOrderItem) {
return resolvePlanBrandDisplayLabel(item) || '—'
}
function statusLabel(s?: string) {
const map: Record<string, string> = {
in_progress: '进行中',
@@ -288,19 +301,23 @@
}
function mapBrandQtyRows(it: PublicIoOrderItem): BrandQtyItem[] {
const existing = (it.brandQtys || []).map((row) => ({
brandId: row.brandId,
brandName: row.brandName || '',
qty: Number(row.qty ?? 0)
}))
const existing = (it.brandQtys || [])
.filter((row) => Number(row.qty ?? 0) > 0)
.map((row) => ({
brandId: row.brandId,
brandName: row.brandName || '',
qty: Number(row.qty ?? 0)
}))
if (existing.length) return existing
if (it.brandMode === 'required') {
const brandId = it.brandId || it.brandOptions?.[0]?.brandId || ''
// 指定品牌:仅预选计划上的 brandId,禁止把总量塞到 options 第一项
if (it.brandMode === 'required' && it.brandId) {
const brandName =
it.brandName || it.brandOptions?.find((o) => o.brandId === brandId)?.brandName || '指定品牌'
it.brandName ||
it.brandOptions?.find((o) => o.brandId === it.brandId)?.brandName ||
'指定品牌'
const seedQty = it.actualQty != null ? Number(it.actualQty) : 0
return brandId ? [{ brandId, brandName, qty: seedQty }] : []
return [{ brandId: it.brandId, brandName, qty: seedQty }]
}
return []
@@ -98,6 +98,14 @@
</span>
</div>
<div class="meta-grid">
<div class="meta-item">
<div class="meta-item__label">别名</div>
<div class="meta-item__value">{{ item.aliasName || '—' }}</div>
</div>
<div class="meta-item">
<div class="meta-item__label">品牌</div>
<div class="meta-item__value">{{ formatBrandLabel(item) }}</div>
</div>
<div class="meta-item">
<div class="meta-item__label">规格型号</div>
<div class="meta-item__value">{{ item.model || '—' }}</div>
@@ -205,7 +213,7 @@
import BrandQtyChipsField from '@/components/business/brand-qty-chips-field/index.vue'
import PublicMobileShell from '@/layouts/PublicMobileShell.vue'
import { buildAmapNavigationUrl } from '@/utils/amap/navigation'
import { formatPlPersonnelNameWithRole } from '@/utils/pl-display'
import { formatPlPersonnelNameWithRole, resolvePlanBrandDisplayLabel } from '@/utils/pl-display'
import 'vant/es/toast/style'
import '@/styles/public-mobile-vant.scss'
@@ -290,6 +298,10 @@
return unit ? `${qty} ${unit}` : String(qty)
}
function formatBrandLabel(item: PublicTransportProduct) {
return resolvePlanBrandDisplayLabel(item) || '—'
}
function resolveFileUrl(url: string) {
if (!url) return ''
if (/^https?:\/\//i.test(url)) return url
@@ -307,21 +319,23 @@
}
function mapBrandQtyRows(prod: PublicTransportProduct): BrandQtyItem[] {
const existing = (prod.brandQtys || []).map((row) => ({
brandId: row.brandId,
brandName: row.brandName || '',
qty: Number(row.qty ?? 0)
}))
const existing = (prod.brandQtys || [])
.filter((row) => Number(row.qty ?? 0) > 0)
.map((row) => ({
brandId: row.brandId,
brandName: row.brandName || '',
qty: Number(row.qty ?? 0)
}))
if (existing.length) return existing
if (prod.brandMode === 'required') {
const brandId = prod.brandId || prod.brandOptions?.[0]?.brandId || ''
// 指定品牌:仅预选计划上的 brandId,禁止把总量塞到 options 第一项
if (prod.brandMode === 'required' && prod.brandId) {
const brandName =
prod.brandName ||
prod.brandOptions?.find((o) => o.brandId === brandId)?.brandName ||
prod.brandOptions?.find((o) => o.brandId === prod.brandId)?.brandName ||
'指定品牌'
const seedQty = prod.actualQty != null ? Number(prod.actualQty) : 0
return brandId ? [{ brandId, brandName, qty: seedQty }] : []
return [{ brandId: prod.brandId, brandName, qty: seedQty }]
}
return []