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:
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 []
|
||||
|
||||
Reference in new issue
Block a user