diff --git a/apps/web-antd/src/views/mall/product/spu/form/data.ts b/apps/web-antd/src/views/mall/product/spu/form/data.ts index 8596a610d..d2ff7eeb5 100644 --- a/apps/web-antd/src/views/mall/product/spu/form/data.ts +++ b/apps/web-antd/src/views/mall/product/spu/form/data.ts @@ -4,7 +4,6 @@ import { DeliveryTypeEnum, DICT_TYPE } from '@vben/constants'; import { getDictOptions } from '@vben/hooks'; import { handleTree } from '@vben/utils'; -import { z } from '#/adapter/form'; import { getSimpleBrandList } from '#/api/mall/product/brand'; import { getCategoryList } from '#/api/mall/product/category'; import { getSimpleTemplateList } from '#/api/mall/trade/delivery/expressTemplate'; @@ -33,7 +32,6 @@ export function useInfoFormSchema(): VbenFormSchema[] { { fieldName: 'categoryId', label: '分类名称', - // component: 'ApiCascader', component: 'ApiTreeSelect', componentProps: { api: async () => { @@ -285,7 +283,7 @@ export function useOtherFormSchema(): VbenFormSchema[] { componentProps: { min: 0, }, - rules: z.number().min(0).optional().default(0), + rules: 'required', }, { fieldName: 'giveIntegral', @@ -294,7 +292,7 @@ export function useOtherFormSchema(): VbenFormSchema[] { componentProps: { min: 0, }, - rules: z.number().min(0).optional().default(0), + rules: 'required', }, { fieldName: 'virtualSalesCount', @@ -303,7 +301,7 @@ export function useOtherFormSchema(): VbenFormSchema[] { componentProps: { min: 0, }, - rules: z.number().min(0).optional().default(0), + rules: 'required', }, ]; } diff --git a/apps/web-antd/src/views/mall/product/spu/form/index.ts b/apps/web-antd/src/views/mall/product/spu/form/index.ts index 99534f731..3ba57c4d9 100644 --- a/apps/web-antd/src/views/mall/product/spu/form/index.ts +++ b/apps/web-antd/src/views/mall/product/spu/form/index.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ import type { MallSpuApi } from '#/api/mall/product/spu'; +// TODO @puhui999:这个是不是 api 后端有定义类似的?如果是,是不是放到 api 哈? export interface PropertyAndValues { id: number; name: string; @@ -23,12 +24,8 @@ export interface RuleConfig { message: string; } -/** - * 获得商品的规格列表 - 商品相关的公共函数 - * - * @param spu - * @return PropertyAndValues 规格列表 - */ +// TODO @puhui999:这个是只有 index.ts 在用么?还是别的模块也会用 +/** 获得商品的规格列表 - 商品相关的公共函数 */ const getPropertyList = (spu: MallSpuApi.Spu): PropertyAndValues[] => { // 直接拿返回的 skus 属性逆向生成出 propertyList const properties: PropertyAndValues[] = []; @@ -62,4 +59,5 @@ const getPropertyList = (spu: MallSpuApi.Spu): PropertyAndValues[] => { export { getPropertyList }; // 导出组件 +// TODO @puhui999:如果 sku-list.vue 要对外,可以考虑在 spu 下面,搞个 components 模块;(目前看,别的模块应该会用到哈。);modules 是当前模块用到的,components 是跨模块要用到的。 export { default as SkuList } from './modules/sku-list.vue'; diff --git a/apps/web-antd/src/views/mall/product/spu/form/index.vue b/apps/web-antd/src/views/mall/product/spu/form/index.vue index 4d6b052e4..6266be68a 100644 --- a/apps/web-antd/src/views/mall/product/spu/form/index.vue +++ b/apps/web-antd/src/views/mall/product/spu/form/index.vue @@ -8,7 +8,7 @@ import { useRoute } from 'vue-router'; import { Page, useVbenModal } from '@vben/common-ui'; import { useTabs } from '@vben/hooks'; -import { convertToInteger, floatToFixed2, formatToFraction } from '@vben/utils'; +import { convertToInteger, formatToFraction } from '@vben/utils'; import { Button, Card, message } from 'ant-design-vue'; @@ -31,11 +31,6 @@ const spuId = ref(); const { params, name } = useRoute(); const { closeCurrentTab } = useTabs(); const activeTabName = ref('info'); - -function onTabChange(key: string) { - activeTabName.value = key; -} - const tabList = ref([ { key: 'info', @@ -58,44 +53,43 @@ const tabList = ref([ tab: '其它设置', }, ]); -// spu 表单数据 -const formData = ref({ - name: '', // 商品名称 - categoryId: undefined, // 商品分类 - keyword: '', // 关键字 - picUrl: '', // 商品封面图 - sliderPicUrls: [], // 商品轮播图 - introduction: '', // 商品简介 - deliveryTypes: [], // 配送方式数组 - deliveryTemplateId: undefined, // 运费模版 - brandId: undefined, // 商品品牌 - specType: false, // 商品规格 - subCommissionType: false, // 分销类型 - skus: [ - { - price: 0, // 商品价格 - marketPrice: 0, // 市场价 - costPrice: 0, // 成本价 - barCode: '', // 商品条码 - picUrl: '', // 图片地址 - stock: 0, // 库存 - weight: 0, // 商品重量 - volume: 0, // 商品体积 - firstBrokeragePrice: 0, // 一级分销的佣金 - secondBrokeragePrice: 0, // 二级分销的佣金 - }, - ], - description: '', // 商品详情 - sort: 0, // 商品排序 - giveIntegral: 0, // 赠送积分 - virtualSalesCount: 0, // 虚拟销量 -}); -const propertyList = ref([]); // 商品属性列表 -const formLoading = ref(true); // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 -const isDetail = ref(false); // 是否查看详情 + +const formLoading = ref(false); // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const isDetail = ref(name === 'ProductSpuDetail'); // 是否查看详情 const skuListRef = ref(); // 商品属性列表 Ref -// sku 相关属性校验规则 +const formData = ref({ + name: '', + categoryId: undefined, + keyword: '', + picUrl: '', + sliderPicUrls: [], + introduction: '', + deliveryTypes: [], + deliveryTemplateId: undefined, + brandId: undefined, + specType: false, + subCommissionType: false, + skus: [ + { + price: 0, + marketPrice: 0, + costPrice: 0, + barCode: '', + picUrl: '', + stock: 0, + weight: 0, + volume: 0, + firstBrokeragePrice: 0, + secondBrokeragePrice: 0, + }, + ], + description: '', + sort: 0, + giveIntegral: 0, + virtualSalesCount: 0, +}); // spu 表单数据 +const propertyList = ref([]); // 商品属性列表 const ruleConfig: RuleConfig[] = [ { name: 'stock', @@ -117,7 +111,7 @@ const ruleConfig: RuleConfig[] = [ rule: (arg) => arg >= 0.01, message: '商品成本价格必须大于等于 0.00 元!!!', }, -]; +]; // sku 相关属性校验规则 const [InfoForm, infoFormApi] = useVbenForm({ commonConfig: { @@ -146,11 +140,11 @@ const [SkuForm, skuFormApi] = useVbenForm({ handleValuesChange: (values, fieldsChanged) => { if (fieldsChanged.includes('subCommissionType')) { formData.value.subCommissionType = values.subCommissionType; - changeSubCommissionType(); + handleChangeSubCommissionType(); } if (fieldsChanged.includes('specType')) { formData.value.specType = values.specType; - onChangeSpec(); + handleChangeSpec(); } }, }); @@ -199,7 +193,13 @@ const [OtherForm, otherFormApi] = useVbenForm({ showDefaultActions: false, }); -async function onSubmit() { +/** tab 切换 */ +function handleTabChange(key: string) { + activeTabName.value = key; +} + +/** 提交表单 */ +async function handleSubmit() { const values: MallSpuApi.Spu = await infoFormApi .merge(skuFormApi) .merge(deliveryFormApi) @@ -216,7 +216,7 @@ async function onSubmit() { return; } values.skus.forEach((item) => { - // sku相关价格元转分 + // 金额转换:元转分 item.price = convertToInteger(item.price); item.marketPrice = convertToInteger(item.marketPrice); item.costPrice = convertToInteger(item.costPrice); @@ -224,7 +224,7 @@ async function onSubmit() { item.secondBrokeragePrice = convertToInteger(item.secondBrokeragePrice); }); } - // 处理轮播图列表 + // 处理轮播图列表 TODO @puhui999:这个是必须的哇? const newSliderPicUrls: any[] = []; values.sliderPicUrls!.forEach((item: any) => { // 如果是前端选的图 @@ -234,12 +234,13 @@ async function onSubmit() { }); values.sliderPicUrls = newSliderPicUrls; + // 提交数据 await (spuId.value ? updateSpu(values) : createSpu(values)); } /** 获得详情 */ async function getDetail() { - if (name === 'ProductSpuDetail') { + if (isDetail.value) { isDetail.value = true; infoFormApi.setDisabled(true); skuFormApi.setDisabled(true); @@ -247,45 +248,36 @@ async function getDetail() { descriptionFormApi.setDisabled(true); otherFormApi.setDisabled(true); } - const id = params.id as unknown as number; - if (id) { - try { - const res = await getSpu(spuId.value!); - res.skus?.forEach((item) => { - if (isDetail.value) { - item.price = floatToFixed2(item.price); - item.marketPrice = floatToFixed2(item.marketPrice); - item.costPrice = floatToFixed2(item.costPrice); - item.firstBrokeragePrice = floatToFixed2(item.firstBrokeragePrice); - item.secondBrokeragePrice = floatToFixed2(item.secondBrokeragePrice); - } else { - // 回显价格分转元 - item.price = formatToFraction(item.price); - item.marketPrice = formatToFraction(item.marketPrice); - item.costPrice = formatToFraction(item.costPrice); - item.firstBrokeragePrice = formatToFraction(item.firstBrokeragePrice); - item.secondBrokeragePrice = formatToFraction( - item.secondBrokeragePrice, - ); - } - }); - formData.value = res; - // 初始化各表单值(异步) - infoFormApi.setValues(res); - skuFormApi.setValues(res); - deliveryFormApi.setValues(res); - descriptionFormApi.setValues(res); - otherFormApi.setValues(res); - } finally { - formLoading.value = false; - } - } // 将 SKU 的属性,整理成 PropertyAndValues 数组 propertyList.value = getPropertyList(formData.value); + formLoading.value = true; + try { + const res = await getSpu(spuId.value!); + // 金额转换:元转分 + res.skus?.forEach((item) => { + item.price = formatToFraction(item.price); + item.marketPrice = formatToFraction(item.marketPrice); + item.costPrice = formatToFraction(item.costPrice); + item.firstBrokeragePrice = formatToFraction(item.firstBrokeragePrice); + item.secondBrokeragePrice = formatToFraction(item.secondBrokeragePrice); + }); + formData.value = res; + // 初始化各表单值 + infoFormApi.setValues(res).then(); + skuFormApi.setValues(res).then(); + deliveryFormApi.setValues(res).then(); + descriptionFormApi.setValues(res).then(); + otherFormApi.setValues(res).then(); + // 将 SKU 的属性,整理成 PropertyAndValues 数组 + propertyList.value = getPropertyList(formData.value); + } finally { + formLoading.value = false; + } } // =========== sku form 逻辑 =========== +/** 打开属性添加表单 */ function openPropertyAddForm() { productPropertyAddFormApi.open(); } @@ -296,7 +288,7 @@ function generateSkus(propertyList: any[]) { } /** 分销类型 */ -function changeSubCommissionType() { +function handleChangeSubCommissionType() { // 默认为零,类型切换后也要重置为零 for (const item of formData.value.skus!) { item.firstBrokeragePrice = 0; @@ -305,10 +297,10 @@ function changeSubCommissionType() { } /** 选择规格 */ -function onChangeSpec() { +function handleChangeSpec() { // 重置商品属性列表 propertyList.value = []; - // 重置sku列表 + // 重置 sku 列表 formData.value.skus = [ { price: 0, @@ -325,7 +317,7 @@ function onChangeSpec() { ]; } -// 监听 sku form schema 变化,更新表单 +/** 监听 sku form schema 变化,更新表单 */ watch( propertyList, () => { @@ -336,6 +328,7 @@ watch( { deep: true }, ); +/** 初始化 */ onMounted(async () => { spuId.value = params.id as unknown as number; if (!spuId.value) { @@ -355,18 +348,18 @@ onMounted(async () => { :loading="formLoading" :tab-list="tabList" :active-key="activeTabName" - @tab-change="onTabChange" + @tab-change="handleTabChange" > - +