diff --git a/src/api/mall/product/spu.ts b/src/api/mall/product/spu.ts index 42350218..1556dd11 100644 --- a/src/api/mall/product/spu.ts +++ b/src/api/mall/product/spu.ts @@ -47,17 +47,13 @@ export interface Spu { recommendBest?: boolean // 是否精品 recommendNew?: boolean // 是否新品 recommendGood?: boolean // 是否优品 -} - -// TODO @puhui999: SpuRespVO 合并到 SPU 里?前端少点 VO 类哈; -export interface SpuRespVO extends Spu { - price: number - salesCount: number - marketPrice: number - costPrice: number - stock: number - createTime: Date - status: number + price?: number // 商品价格 + salesCount?: number // 商品销量 + marketPrice?: number // 市场价 + costPrice?: number // 成本价 + stock?: number // 商品库存 + createTime?: Date // 商品创建时间 + status?: number // 商品状态 } // 获得 Spu 列表 diff --git a/src/api/mall/promotion/seckill/seckillActivity.ts b/src/api/mall/promotion/seckill/seckillActivity.ts index 93b128f3..0f1f08d1 100644 --- a/src/api/mall/promotion/seckill/seckillActivity.ts +++ b/src/api/mall/promotion/seckill/seckillActivity.ts @@ -1,5 +1,5 @@ import request from '@/config/axios' -import { Sku, SpuRespVO } from '@/api/mall/product/spu' +import { Sku, Spu } from '@/api/mall/product/spu' export interface SeckillActivityVO { id: number @@ -21,6 +21,7 @@ export interface SeckillActivityVO { products: SeckillProductVO[] } +// 秒杀活动所需属性 export interface SeckillProductVO { spuId: number skuId: number @@ -28,11 +29,12 @@ export interface SeckillProductVO { stock: number } +// 扩展 Sku 配置 type SkuExtension = Sku & { productConfig: SeckillProductVO } -export interface SpuExtension extends SpuRespVO { +export interface SpuExtension extends Spu { skus: SkuExtension[] // 重写类型 } diff --git a/src/views/mall/product/spu/components/BasicInfoForm.vue b/src/views/mall/product/spu/components/BasicInfoForm.vue index c8cc6f57..501295b4 100644 --- a/src/views/mall/product/spu/components/BasicInfoForm.vue +++ b/src/views/mall/product/spu/components/BasicInfoForm.vue @@ -274,10 +274,7 @@ watch( const emit = defineEmits(['update:activeName']) const validate = async () => { // 校验 sku - if (!skuListRef.value.validateSku()) { - message.warning('商品相关价格不能低于 0.01 元!!') - throw new Error('商品相关价格不能低于 0.01 元!!') - } + skuListRef.value.validateSku() // 校验表单 if (!productSpuBasicInfoRef) return return await unref(productSpuBasicInfoRef).validate((valid) => { diff --git a/src/views/mall/product/spu/components/SkuList.vue b/src/views/mall/product/spu/components/SkuList.vue index da263686..e033b233 100644 --- a/src/views/mall/product/spu/components/SkuList.vue +++ b/src/views/mall/product/spu/components/SkuList.vue @@ -259,8 +259,10 @@ import { UploadImg } from '@/components/UploadFile' import type { Property, Sku, Spu } from '@/api/mall/product/spu' import { createImageViewer } from '@/components/ImageViewer' import { RuleConfig } from '@/views/mall/product/spu/components/index' +import { Properties } from './index' defineOptions({ name: 'SkuList' }) +const message = useMessage() // 消息弹窗 const props = defineProps({ propFormData: { @@ -268,7 +270,7 @@ const props = defineProps({ default: () => {} }, propertyList: { - type: Array, + type: Array as PropType, default: () => [] }, ruleConfig: { @@ -323,26 +325,47 @@ const tableHeaders = ref<{ prop: string; label: string }[]>([]) // 多属性表 /** * 保存时,每个商品规格的表单要校验下。例如说,销售金额最低是 0.01 这种。 */ -const validateSku = (): boolean => { +const validateSku = () => { const checks = ['price', 'marketPrice', 'costPrice'] + let warningInfo = '请检查商品各行相关属性配置,' let validate = true // 默认通过 - for (const sku of formData.value!.skus) { + for (const sku of formData.value!.skus!) { // 作为活动组件的校验 if (props.isActivityComponent) { for (const rule of props.ruleConfig) { - if (sku[rule.name] < rule.geValue) { + const arg = getValue(sku, rule.name) + if (!rule.rule(arg)) { validate = false // 只要有一个不通过则直接不通过 + warningInfo += rule.message break } } } else { if (checks.some((check) => sku[check] < 0.01)) { validate = false // 只要有一个不通过则直接不通过 + warningInfo = '商品相关价格不能低于 0.01 元!!' break } } + // 只要有一个不通过则结束后续的校验 + if (!validate) { + message.warning(warningInfo) + throw new Error(warningInfo) + } } - return validate +} +const getValue = (obj, arg) => { + const keys = arg.split('.') + let value = obj + for (const key of keys) { + if (value && typeof value === 'object' && key in value) { + value = value[key] + } else { + value = undefined + break + } + } + return value } const emit = defineEmits<{ @@ -417,13 +440,13 @@ const generateTableData = (propertyList: any[]) => { * 生成 skus 前置校验 */ const validateData = (propertyList: any[]) => { - const skuPropertyIds = [] + const skuPropertyIds: number[] = [] formData.value!.skus!.forEach((sku) => sku.properties ?.map((property) => property.propertyId) - .forEach((propertyId) => { - if (skuPropertyIds.indexOf(propertyId) === -1) { - skuPropertyIds.push(propertyId) + ?.forEach((propertyId) => { + if (skuPropertyIds.indexOf(propertyId!) === -1) { + skuPropertyIds.push(propertyId!) } }) ) @@ -457,7 +480,7 @@ const build = (propertyValuesList: Property[][]) => { /** 监听属性列表,生成相关参数和表头 */ watch( () => props.propertyList, - (propertyList) => { + (propertyList: Properties[]) => { // 如果不是多规格则结束 if (!formData.value!.specType) { return @@ -497,7 +520,7 @@ watch( return } // 添加新属性没有属性值也不做处理 - if (propertyList.some((item) => item.values.length === 0)) { + if (propertyList.some((item) => item.values!.length === 0)) { return } // 生成 table 数据,即 sku 列表 diff --git a/src/views/mall/product/spu/components/index.ts b/src/views/mall/product/spu/components/index.ts index 8c269e56..59c031e8 100644 --- a/src/views/mall/product/spu/components/index.ts +++ b/src/views/mall/product/spu/components/index.ts @@ -14,8 +14,19 @@ interface Properties { } interface RuleConfig { - name: string // 需要校验的字段 - geValue: number // TODO 暂定大于一个数字 + // 需要校验的字段 + // 例:name: 'name' 则表示校验 sku.name 的值 + // 例:name: 'productConfig.stock' 则表示校验 sku.productConfig.name 的值,此处 productConfig 表示我在 Sku 上扩展的属性 + name: string + // 校验规格为一个毁掉函数,其中 arg 为需要校验的字段的值。 + // 例:需要校验价格必须大于0.01 + // { + // name:'price', + // rule:(arg) => arg > 0.01 + // } + rule: (arg: any) => boolean + // 校验不通过时的消息提示 + message: string } /** diff --git a/src/views/mall/promotion/seckill/activity/components/SpuAndSkuList.vue b/src/views/mall/promotion/components/SpuAndSkuList.vue similarity index 59% rename from src/views/mall/promotion/seckill/activity/components/SpuAndSkuList.vue rename to src/views/mall/promotion/components/SpuAndSkuList.vue index 63268a35..e239a39a 100644 --- a/src/views/mall/promotion/seckill/activity/components/SpuAndSkuList.vue +++ b/src/views/mall/promotion/components/SpuAndSkuList.vue @@ -1,5 +1,5 @@