feat(web-admin): choose display name and brand constraint on quote/contract lines
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
ba98108659
commit
cd33befa07
7 files changed
+360
-11
No files matched your search
@@ -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[]
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -183,6 +183,11 @@
|
||||
<el-table :data="detailContract.products" class="list-table" stripe empty-text="暂无产品明细">
|
||||
<el-table-column label="序号" type="index" min-width="60" align="center" header-align="center" />
|
||||
<el-table-column label="产品名称" prop="productName" min-width="120" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="品牌" min-width="100" :show-overflow-tooltip="true">
|
||||
<template #default="{ row }">
|
||||
<span>{{ formatBrandConstraintLabel(row.brandMode, row.brandName) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="型号/规格" prop="model" min-width="130" :show-overflow-tooltip="true">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.model || scope.row.productModel || '-' }}</span>
|
||||
@@ -877,6 +882,7 @@ import { getOpportunity } from '@/api/crm/opportunity';
|
||||
import { useDictStore } from '@/store/modules/dict';
|
||||
import DictTag from '@/components/DictTag/index.vue';
|
||||
import { $modal } from '@/utils/modal';
|
||||
import { formatBrandConstraintLabel } from '@/utils/crm-product-brand'
|
||||
import { parseTime } from '@/utils/format';
|
||||
import { useContractPerm } from '@/hooks/business/useContractPerm';
|
||||
import { canDeleteByCreator, filterDeletableByCreator, allRowsDeletableByCreator, CREATOR_DELETE_TIP } from '@/utils/creator-delete';
|
||||
|
||||
@@ -247,7 +247,68 @@
|
||||
<el-table-column label="序号" type="index" min-width="60" align="center" header-align="center" />
|
||||
<el-table-column label="产品名称" prop="productName" min-width="160" :show-overflow-tooltip="true">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.productName" placeholder="请输入产品名称" clearable size="small" readonly />
|
||||
<el-select
|
||||
v-if="(scope.row.nameOptions || []).length > 1"
|
||||
v-model="scope.row.productName"
|
||||
placeholder="选择展示名称"
|
||||
filterable
|
||||
allow-create
|
||||
default-first-option
|
||||
size="small"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="name in scope.row.nameOptions"
|
||||
:key="name"
|
||||
:label="name"
|
||||
:value="name"
|
||||
/>
|
||||
</el-select>
|
||||
<el-input
|
||||
v-else
|
||||
v-model="scope.row.productName"
|
||||
placeholder="请输入产品名称"
|
||||
clearable
|
||||
size="small"
|
||||
readonly
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="品牌要求" min-width="120">
|
||||
<template #default="scope">
|
||||
<el-select
|
||||
v-if="(scope.row.brandOptions || []).length"
|
||||
v-model="scope.row.brandMode"
|
||||
placeholder="品牌要求"
|
||||
size="small"
|
||||
style="width: 100%"
|
||||
@change="(val) => handleBrandModeChange(scope.row, val)"
|
||||
>
|
||||
<el-option label="不限品牌" value="any" />
|
||||
<el-option label="指定品牌" value="required" />
|
||||
</el-select>
|
||||
<span v-else class="text-muted">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="品牌" min-width="120">
|
||||
<template #default="scope">
|
||||
<el-select
|
||||
v-if="scope.row.brandMode === 'required' && (scope.row.brandOptions || []).length"
|
||||
v-model="scope.row.brandId"
|
||||
placeholder="选择品牌"
|
||||
size="small"
|
||||
style="width: 100%"
|
||||
@change="(val) => handleBrandIdChange(scope.row, val)"
|
||||
>
|
||||
<el-option
|
||||
v-for="b in scope.row.brandOptions"
|
||||
:key="b.id"
|
||||
:label="b.brandName"
|
||||
:value="b.id"
|
||||
/>
|
||||
</el-select>
|
||||
<span v-else-if="scope.row.brandMode === 'any'">不限</span>
|
||||
<span v-else class="text-muted">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="型号/规格" prop="productModel" min-width="130" :show-overflow-tooltip="true">
|
||||
@@ -546,6 +607,13 @@ import CustomerSelector from '@/components/CustomerSelector.vue'
|
||||
import ContactSelector from '@/components/ContactSelector.vue'
|
||||
import QuoteSelector from '@/components/QuoteSelector.vue'
|
||||
import { removeProductsNotAllowedByHazard } from '@/utils/crm-supplier-hazard'
|
||||
import {
|
||||
applyBrandModeChange,
|
||||
applyBrandSelectChange,
|
||||
buildProductNameOptions,
|
||||
initLineBrandMetaFromProduct
|
||||
} from '@/utils/crm-product-brand'
|
||||
import { fetchProductDetail } from '@/api/crm/product'
|
||||
import ApprovalDialog from './ApprovalDialog.vue'
|
||||
import { getContactByCustomerId } from '@/api/crm/customer'
|
||||
import type { CustomerVO, ContactVO } from '@/api/crm/customer/types'
|
||||
@@ -890,6 +958,11 @@ const loadContractDetail = async (id: number | string) => {
|
||||
productModel: product.model || '',
|
||||
isToxic: Number(product.isToxic || 0),
|
||||
isExplosive: Number(product.isExplosive || 0),
|
||||
brandMode: product.brandMode || undefined,
|
||||
brandId: product.brandId || undefined,
|
||||
brandName: product.brandName || undefined,
|
||||
nameOptions: product.productName ? [product.productName] : [],
|
||||
brandOptions: [],
|
||||
priceTiers: (product.priceTiers || []).map((t: any) => {
|
||||
let ids: string[] = []
|
||||
if (Array.isArray(t.letterOssIds) && t.letterOssIds.length) {
|
||||
@@ -909,6 +982,8 @@ const loadContractDetail = async (id: number | string) => {
|
||||
deliveryMethod: product.deliveryMethod || ''
|
||||
}))
|
||||
|
||||
await enrichContractProductBrandMeta(form.value.products)
|
||||
|
||||
if (contractData.contractType === 'framework') {
|
||||
form.value.products.forEach((product: any) => {
|
||||
product.price = 0
|
||||
@@ -1139,7 +1214,7 @@ const handleQuoteConfirm = (quote: QuoteVO) => {
|
||||
if (quote.productList && quote.productList.length > 0) {
|
||||
$modal
|
||||
.confirm('是否要从报价单中带入产品明细?')
|
||||
.then(() => {
|
||||
.then(async () => {
|
||||
const isFw = form.value.contractType === 'framework'
|
||||
form.value.products = quote.productList!.map((item: any) => ({
|
||||
productId: item.productId,
|
||||
@@ -1161,8 +1236,14 @@ const handleQuoteConfirm = (quote: QuoteVO) => {
|
||||
description: item.description || '',
|
||||
remark: item.remark || '',
|
||||
sort: item.sort,
|
||||
brandMode: item.brandMode || undefined,
|
||||
brandId: item.brandId || undefined,
|
||||
brandName: item.brandName || undefined,
|
||||
nameOptions: item.productName ? [item.productName] : [],
|
||||
brandOptions: [],
|
||||
priceTiers: isFw ? [] : undefined
|
||||
}))
|
||||
await enrichContractProductBrandMeta(form.value.products)
|
||||
calculateTotalAmount()
|
||||
})
|
||||
.catch(() => {})
|
||||
@@ -1490,6 +1571,7 @@ const handleAddProduct = () => {
|
||||
const handleProductSelected = (products: any[]) => {
|
||||
const isFw = form.value.contractType === 'framework'
|
||||
products.forEach((product) => {
|
||||
const brandMeta = initLineBrandMetaFromProduct(product)
|
||||
form.value.products.push({
|
||||
productId: product.id,
|
||||
productName: product.productName,
|
||||
@@ -1508,6 +1590,7 @@ const handleProductSelected = (products: any[]) => {
|
||||
remark: '',
|
||||
isToxic: Number(product.isToxic || 0),
|
||||
isExplosive: Number(product.isExplosive || 0),
|
||||
...brandMeta,
|
||||
priceTiers: isFw ? [] : undefined
|
||||
})
|
||||
})
|
||||
@@ -1517,6 +1600,43 @@ const handleProductSelected = (products: any[]) => {
|
||||
calculateTotalAmount()
|
||||
}
|
||||
|
||||
const handleBrandModeChange = (row: ExtendedContractProductForm, val: string) => {
|
||||
applyBrandModeChange(row, val)
|
||||
}
|
||||
|
||||
const handleBrandIdChange = (row: ExtendedContractProductForm, val: string) => {
|
||||
applyBrandSelectChange(row, val, row.brandOptions || [])
|
||||
}
|
||||
|
||||
async function enrichContractProductBrandMeta(lines: ExtendedContractProductForm[]) {
|
||||
await Promise.all(
|
||||
(lines || []).map(async (line) => {
|
||||
if (!line.productId) return
|
||||
try {
|
||||
const res: any = await fetchProductDetail({ id: String(line.productId) })
|
||||
const data = res?.data ?? res
|
||||
if (!data) return
|
||||
const meta = initLineBrandMetaFromProduct(data)
|
||||
line.standardProductName = meta.standardProductName
|
||||
line.nameOptions = buildProductNameOptions(meta.standardProductName, data.aliases)
|
||||
if (line.productName && !line.nameOptions.includes(String(line.productName))) {
|
||||
line.nameOptions = [...line.nameOptions, String(line.productName)]
|
||||
}
|
||||
line.brandOptions = meta.brandOptions
|
||||
if (meta.brandOptions.length) {
|
||||
if (!line.brandMode) line.brandMode = 'any'
|
||||
} else {
|
||||
line.brandMode = undefined
|
||||
line.brandId = undefined
|
||||
line.brandName = undefined
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('enrich contract brand meta failed', line.productId, e)
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
/** 规范化税率展示 */
|
||||
const normalizeTaxRateDisplay = (value: any, defaultValue = 0): number => {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
@@ -1685,7 +1805,10 @@ const buildProductsPayload = () => {
|
||||
packageSpec: product.packageSpec,
|
||||
deliveryMethod: product.deliveryMethod,
|
||||
sort: product.sort ?? idx + 1,
|
||||
remark: product.remark
|
||||
remark: product.remark,
|
||||
brandMode: product.brandMode || null,
|
||||
brandId: product.brandMode === 'required' ? product.brandId || null : null,
|
||||
brandName: product.brandMode === 'required' ? product.brandName || null : null
|
||||
}
|
||||
if (product.id) {
|
||||
base.id = product.id
|
||||
@@ -1839,6 +1962,10 @@ const handleSaveDraft = async () => {
|
||||
$modal.msgWarning(`第${rowNum}行产品的产品名称不能为空`)
|
||||
return
|
||||
}
|
||||
if ((product.brandOptions || []).length && product.brandMode === 'required' && !product.brandId) {
|
||||
$modal.msgWarning(`第${rowNum}行产品请选择指定品牌`)
|
||||
return
|
||||
}
|
||||
}
|
||||
data.products = buildProductsPayload()
|
||||
} else {
|
||||
@@ -1890,6 +2017,10 @@ const handleSubmit = async () => {
|
||||
$modal.msgWarning(`第${rowNum}行产品的产品名称不能为空`)
|
||||
return false
|
||||
}
|
||||
if ((product.brandOptions || []).length && product.brandMode === 'required' && !product.brandId) {
|
||||
$modal.msgWarning(`第${rowNum}行产品请选择指定品牌`)
|
||||
return false
|
||||
}
|
||||
if (!product.quantity || Number(product.quantity) <= 0) {
|
||||
$modal.msgWarning(`第${rowNum}行产品的数量不能为空且必须大于0`)
|
||||
return false
|
||||
|
||||
@@ -75,6 +75,11 @@
|
||||
>
|
||||
<el-table-column type="index" label="序号" min-width="60" align="center" header-align="center" />
|
||||
<el-table-column label="产品名称" prop="productName" min-width="120" align="center" header-align="center" show-overflow-tooltip />
|
||||
<el-table-column label="品牌" min-width="100" align="center" header-align="center" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<span>{{ formatBrandConstraintLabel(row.brandMode, row.brandName) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="型号/规格" prop="model" min-width="130" align="center" header-align="center" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<span>{{ row.model || '—' }}</span>
|
||||
@@ -318,6 +323,7 @@ import { useDictStore } from '@/store/modules/dict'
|
||||
import { useQuotePerm } from '@/hooks/business/useQuotePerm'
|
||||
import { canDeleteByCreator, CREATOR_DELETE_TIP } from '@/utils/creator-delete'
|
||||
import { $modal } from '@/utils/modal'
|
||||
import { formatBrandConstraintLabel } from '@/utils/crm-product-brand'
|
||||
import { parseTime } from '@/utils/format'
|
||||
import {
|
||||
getQuote,
|
||||
|
||||
@@ -131,7 +131,67 @@
|
||||
<el-table-column type="index" label="序号" min-width="60" align="center" header-align="center" />
|
||||
<el-table-column label="产品名称" prop="productName" min-width="160" :show-overflow-tooltip="true">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.productName" placeholder="请输入产品名称" clearable readonly />
|
||||
<el-select
|
||||
v-if="(scope.row.nameOptions || []).length > 1"
|
||||
v-model="scope.row.productName"
|
||||
placeholder="选择展示名称"
|
||||
filterable
|
||||
allow-create
|
||||
default-first-option
|
||||
size="small"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="name in scope.row.nameOptions"
|
||||
:key="name"
|
||||
:label="name"
|
||||
:value="name"
|
||||
/>
|
||||
</el-select>
|
||||
<el-input
|
||||
v-else
|
||||
v-model="scope.row.productName"
|
||||
placeholder="请输入产品名称"
|
||||
clearable
|
||||
readonly
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="品牌要求" min-width="120">
|
||||
<template #default="scope">
|
||||
<el-select
|
||||
v-if="(scope.row.brandOptions || []).length"
|
||||
v-model="scope.row.brandMode"
|
||||
placeholder="品牌要求"
|
||||
size="small"
|
||||
style="width: 100%"
|
||||
@change="(val) => handleBrandModeChange(scope.row, val)"
|
||||
>
|
||||
<el-option label="不限品牌" value="any" />
|
||||
<el-option label="指定品牌" value="required" />
|
||||
</el-select>
|
||||
<span v-else class="text-muted">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="品牌" min-width="120">
|
||||
<template #default="scope">
|
||||
<el-select
|
||||
v-if="scope.row.brandMode === 'required' && (scope.row.brandOptions || []).length"
|
||||
v-model="scope.row.brandId"
|
||||
placeholder="选择品牌"
|
||||
size="small"
|
||||
style="width: 100%"
|
||||
@change="(val) => handleBrandIdChange(scope.row, val)"
|
||||
>
|
||||
<el-option
|
||||
v-for="b in scope.row.brandOptions"
|
||||
:key="b.id"
|
||||
:label="b.brandName"
|
||||
:value="b.id"
|
||||
/>
|
||||
</el-select>
|
||||
<span v-else-if="scope.row.brandMode === 'any'">不限</span>
|
||||
<span v-else class="text-muted">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="型号/规格" prop="model" min-width="130" :show-overflow-tooltip="true">
|
||||
@@ -477,6 +537,13 @@ import { fetchUserOptions } from '@/api/admin';
|
||||
import { fetchContactsByCustomerId } from '@/api/crm/contact';
|
||||
import { listAllSupplierInfo, type SupplierInfoVO } from '@/api/crm/supplierInfo';
|
||||
import { removeProductsNotAllowedByHazard } from '@/utils/crm-supplier-hazard'
|
||||
import {
|
||||
applyBrandModeChange,
|
||||
applyBrandSelectChange,
|
||||
buildProductNameOptions,
|
||||
initLineBrandMetaFromProduct
|
||||
} from '@/utils/crm-product-brand'
|
||||
import { fetchProductDetail } from '@/api/crm/product'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
@@ -797,8 +864,14 @@ const getQuoteInfo = async (id: string | number) => {
|
||||
deliveryMethod: item.deliveryMethod || '', // 送货方式
|
||||
description: item.description,
|
||||
isToxic: Number(item.isToxic || 0),
|
||||
isExplosive: Number(item.isExplosive || 0)
|
||||
}));
|
||||
isExplosive: Number(item.isExplosive || 0),
|
||||
brandMode: item.brandMode || undefined,
|
||||
brandId: item.brandId || undefined,
|
||||
brandName: item.brandName || undefined,
|
||||
nameOptions: item.productName ? [item.productName] : [],
|
||||
brandOptions: []
|
||||
}))
|
||||
await enrichQuoteProductBrandMeta(form.value.products)
|
||||
}
|
||||
|
||||
// 加载附件数据
|
||||
@@ -1163,6 +1236,7 @@ const handleAddProduct = () => {
|
||||
/** 产品选择确认 */
|
||||
const handleProductConfirm = (products: any[]) => {
|
||||
products.forEach((product) => {
|
||||
const brandMeta = initLineBrandMetaFromProduct(product)
|
||||
// 允许重复添加相同产品:直接追加到 products 列表
|
||||
const productForm: QuoteProductForm = {
|
||||
productId: product.id,
|
||||
@@ -1179,11 +1253,49 @@ const handleProductConfirm = (products: any[]) => {
|
||||
packageSpec: '',
|
||||
deliveryMethod: '',
|
||||
isToxic: Number(product.isToxic || 0),
|
||||
isExplosive: Number(product.isExplosive || 0)
|
||||
};
|
||||
form.value.products?.push(productForm);
|
||||
});
|
||||
};
|
||||
isExplosive: Number(product.isExplosive || 0),
|
||||
...brandMeta
|
||||
}
|
||||
form.value.products?.push(productForm)
|
||||
})
|
||||
}
|
||||
|
||||
const handleBrandModeChange = (row: QuoteProductForm, val: string) => {
|
||||
applyBrandModeChange(row, val)
|
||||
}
|
||||
|
||||
const handleBrandIdChange = (row: QuoteProductForm, val: string) => {
|
||||
applyBrandSelectChange(row, val, row.brandOptions || [])
|
||||
}
|
||||
|
||||
async function enrichQuoteProductBrandMeta(lines: QuoteProductForm[]) {
|
||||
await Promise.all(
|
||||
(lines || []).map(async (line) => {
|
||||
if (!line.productId) return
|
||||
try {
|
||||
const res: any = await fetchProductDetail({ id: String(line.productId) })
|
||||
const data = res?.data ?? res
|
||||
if (!data) return
|
||||
const meta = initLineBrandMetaFromProduct(data)
|
||||
line.standardProductName = meta.standardProductName
|
||||
line.nameOptions = buildProductNameOptions(meta.standardProductName, data.aliases)
|
||||
if (line.productName && !line.nameOptions.includes(line.productName)) {
|
||||
line.nameOptions = [...line.nameOptions, line.productName]
|
||||
}
|
||||
line.brandOptions = meta.brandOptions
|
||||
if (meta.brandOptions.length) {
|
||||
if (!line.brandMode) line.brandMode = 'any'
|
||||
} else {
|
||||
line.brandMode = undefined
|
||||
line.brandId = undefined
|
||||
line.brandName = undefined
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('enrich brand meta failed', line.productId, e)
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
/** 规范化税率展示:整数不带小数,有小数才保留 */
|
||||
const normalizeTaxRateDisplay = (value: any, defaultValue = 0): number => {
|
||||
@@ -1447,6 +1559,11 @@ const handleSaveDraft = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((product.brandOptions || []).length && product.brandMode === 'required' && !product.brandId) {
|
||||
$modal.msgWarning(`第${rowNum}行产品请选择指定品牌`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!product.quantity || product.quantity <= 0) {
|
||||
$modal.msgWarning(`第${rowNum}行产品的数量不能为空且必须大于0`);
|
||||
return;
|
||||
@@ -1551,6 +1668,11 @@ const handleSubmit = async () => {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((product.brandOptions || []).length && product.brandMode === 'required' && !product.brandId) {
|
||||
$modal.msgWarning(`第${rowNum}行产品请选择指定品牌`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!product.quantity || product.quantity <= 0) {
|
||||
$modal.msgWarning(`第${rowNum}行产品的数量不能为空且必须大于0`);
|
||||
return;
|
||||
|
||||
Reference in new issue
Block a user