From cd33befa07340d211f895737e726d6d38a594131 Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Tue, 28 Jul 2026 09:30:38 +0800 Subject: [PATCH] feat(web-admin): choose display name and brand constraint on quote/contract lines Co-authored-by: Cursor --- web-admin/src/api/crm/contract/types.ts | 6 + web-admin/src/api/crm/quote/types.ts | 8 + web-admin/src/utils/crm-product-brand.ts | 70 +++++++++ .../components/ContractDetailDialog.vue | 6 + .../components/ContractFormDialog.vue | 137 ++++++++++++++++- .../quote/components/QuoteDetailDialog.vue | 6 + .../crm/quote/components/QuoteFormPanel.vue | 138 +++++++++++++++++- 7 files changed, 360 insertions(+), 11 deletions(-) create mode 100644 web-admin/src/utils/crm-product-brand.ts diff --git a/web-admin/src/api/crm/contract/types.ts b/web-admin/src/api/crm/contract/types.ts index 676658814..6a6eee774 100644 --- a/web-admin/src/api/crm/contract/types.ts +++ b/web-admin/src/api/crm/contract/types.ts @@ -62,6 +62,12 @@ export interface ContractProductForm { remark?: string isToxic?: number isExplosive?: number + brandMode?: string + brandId?: string + brandName?: string + standardProductName?: string + nameOptions?: string[] + brandOptions?: Array<{ id: string; brandName: string }> priceTiers?: ContractProductPriceTierForm[] } diff --git a/web-admin/src/api/crm/quote/types.ts b/web-admin/src/api/crm/quote/types.ts index 0462c663c..03f04433d 100644 --- a/web-admin/src/api/crm/quote/types.ts +++ b/web-admin/src/api/crm/quote/types.ts @@ -47,6 +47,14 @@ export interface QuoteProductForm { remark?: string isToxic?: number isExplosive?: number + /** required=指定品牌 any=不限品牌;无品牌产品不传 */ + brandMode?: string + brandId?: string + brandName?: string + /** 以下仅前端编辑态使用,提交时可一并带上(后端忽略未知字段) */ + standardProductName?: string + nameOptions?: string[] + brandOptions?: Array<{ id: string; brandName: string }> } export interface QuoteForm { diff --git a/web-admin/src/utils/crm-product-brand.ts b/web-admin/src/utils/crm-product-brand.ts new file mode 100644 index 000000000..37cc0aaac --- /dev/null +++ b/web-admin/src/utils/crm-product-brand.ts @@ -0,0 +1,70 @@ +/** CRM 产品行:展示名 / 品牌约定(报价、合同共用) */ + +export type BrandOption = { id: string; brandName: string } + +export function buildProductNameOptions( + standardName?: string | null, + aliases?: Array<{ aliasName?: string } | null> | null +): string[] { + const names = [String(standardName || '').trim()] + for (const a of aliases || []) { + const n = String(a?.aliasName || '').trim() + if (n) names.push(n) + } + return [...new Set(names.filter(Boolean))] +} + +export function formatBrandConstraintLabel( + brandMode?: string | null, + brandName?: string | null +): string { + if (!brandMode) return '—' + if (brandMode === 'required') return String(brandName || '').trim() || '—' + if (brandMode === 'any') return '不限品牌' + return '—' +} + +export function initLineBrandMetaFromProduct(product: { + productName?: string + brands?: Array<{ id?: string; brandName?: string; status?: string }> + aliases?: Array<{ aliasName?: string }> +}) { + const brands = (product.brands || []).filter((b) => (b.status || 'on') === 'on' && b.id && b.brandName) + const standardProductName = String(product.productName || '').trim() + return { + standardProductName, + nameOptions: buildProductNameOptions(standardProductName, product.aliases), + brandOptions: brands.map((b) => ({ + id: String(b.id), + brandName: String(b.brandName) + })) as BrandOption[], + brandMode: brands.length ? ('any' as const) : undefined, + brandId: undefined as string | undefined, + brandName: undefined as string | undefined + } +} + +export function applyBrandModeChange( + row: { + brandMode?: string + brandId?: string + brandName?: string + }, + mode: string | undefined +) { + row.brandMode = mode + if (mode !== 'required') { + row.brandId = undefined + row.brandName = undefined + } +} + +export function applyBrandSelectChange( + row: { brandId?: string; brandName?: string }, + brandId: string | undefined, + options: BrandOption[] +) { + row.brandId = brandId + const hit = options.find((o) => o.id === brandId) + row.brandName = hit?.brandName +} diff --git a/web-admin/src/views/crm/contract/components/ContractDetailDialog.vue b/web-admin/src/views/crm/contract/components/ContractDetailDialog.vue index 619bb2c3f..6e4ebf5fb 100644 --- a/web-admin/src/views/crm/contract/components/ContractDetailDialog.vue +++ b/web-admin/src/views/crm/contract/components/ContractDetailDialog.vue @@ -183,6 +183,11 @@ + + +