feat:【mall 商城】商品发布 - 库存价格【antd】80%: 完善 sku form 逻辑
This commit is contained in:
@@ -1,7 +1,5 @@
|
|||||||
import type { VbenFormSchema } from '#/adapter/form';
|
import type { VbenFormSchema } from '#/adapter/form';
|
||||||
|
|
||||||
import { h } from 'vue';
|
|
||||||
|
|
||||||
import { DeliveryTypeEnum, DICT_TYPE } from '@vben/constants';
|
import { DeliveryTypeEnum, DICT_TYPE } from '@vben/constants';
|
||||||
import { getDictOptions } from '@vben/hooks';
|
import { getDictOptions } from '@vben/hooks';
|
||||||
import { handleTree } from '@vben/utils';
|
import { handleTree } from '@vben/utils';
|
||||||
@@ -11,8 +9,6 @@ import { getSimpleBrandList } from '#/api/mall/product/brand';
|
|||||||
import { getCategoryList } from '#/api/mall/product/category';
|
import { getCategoryList } from '#/api/mall/product/category';
|
||||||
import { getSimpleTemplateList } from '#/api/mall/trade/delivery/expressTemplate';
|
import { getSimpleTemplateList } from '#/api/mall/trade/delivery/expressTemplate';
|
||||||
|
|
||||||
import SkuList from './sku-list.vue';
|
|
||||||
|
|
||||||
/** 基础设置的表单 */
|
/** 基础设置的表单 */
|
||||||
export function useInfoFormSchema(): VbenFormSchema[] {
|
export function useInfoFormSchema(): VbenFormSchema[] {
|
||||||
return [
|
return [
|
||||||
@@ -110,7 +106,6 @@ export function useInfoFormSchema(): VbenFormSchema[] {
|
|||||||
/** 价格库存的表单 */
|
/** 价格库存的表单 */
|
||||||
export function useSkuFormSchema(
|
export function useSkuFormSchema(
|
||||||
propertyList: any[] = [],
|
propertyList: any[] = [],
|
||||||
ruleConfig: any[] = [],
|
|
||||||
isDetail: boolean = false,
|
isDetail: boolean = false,
|
||||||
): VbenFormSchema[] {
|
): VbenFormSchema[] {
|
||||||
return [
|
return [
|
||||||
@@ -164,11 +159,8 @@ export function useSkuFormSchema(
|
|||||||
{
|
{
|
||||||
fieldName: 'singleSkuList',
|
fieldName: 'singleSkuList',
|
||||||
label: '',
|
label: '',
|
||||||
component: h(SkuList),
|
component: 'Input',
|
||||||
componentProps: {
|
componentProps: {},
|
||||||
propertyList,
|
|
||||||
ruleConfig,
|
|
||||||
},
|
|
||||||
dependencies: {
|
dependencies: {
|
||||||
triggerFields: ['specType'],
|
triggerFields: ['specType'],
|
||||||
// 当 specType 为 false(单规格)时显示
|
// 当 specType 为 false(单规格)时显示
|
||||||
@@ -191,11 +183,8 @@ export function useSkuFormSchema(
|
|||||||
{
|
{
|
||||||
fieldName: 'batchSkuList',
|
fieldName: 'batchSkuList',
|
||||||
label: '批量设置',
|
label: '批量设置',
|
||||||
component: h(SkuList),
|
component: 'Input',
|
||||||
componentProps: {
|
componentProps: {},
|
||||||
isBatch: true,
|
|
||||||
propertyList,
|
|
||||||
},
|
|
||||||
dependencies: {
|
dependencies: {
|
||||||
triggerFields: ['specType'],
|
triggerFields: ['specType'],
|
||||||
// 当 specType 为 true(多规格)且 propertyList 有数据时显示,且非详情模式
|
// 当 specType 为 true(多规格)且 propertyList 有数据时显示,且非详情模式
|
||||||
@@ -207,12 +196,8 @@ export function useSkuFormSchema(
|
|||||||
{
|
{
|
||||||
fieldName: 'multiSkuList',
|
fieldName: 'multiSkuList',
|
||||||
label: '规格列表',
|
label: '规格列表',
|
||||||
component: h(SkuList),
|
component: 'Input',
|
||||||
componentProps: {
|
componentProps: {},
|
||||||
propertyList,
|
|
||||||
ruleConfig,
|
|
||||||
isDetail,
|
|
||||||
},
|
|
||||||
dependencies: {
|
dependencies: {
|
||||||
triggerFields: ['specType'],
|
triggerFields: ['specType'],
|
||||||
// 当 specType 为 true(多规格)且 propertyList 有数据时显示
|
// 当 specType 为 true(多规格)且 propertyList 有数据时显示
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { PropertyAndValues, RuleConfig } from './index';
|
|||||||
|
|
||||||
import type { MallSpuApi } from '#/api/mall/product/spu';
|
import type { MallSpuApi } from '#/api/mall/product/spu';
|
||||||
|
|
||||||
import { computed, onMounted, ref, watch } from 'vue';
|
import { onMounted, ref, watch } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import { ContentWrap, Page, useVbenModal } from '@vben/common-ui';
|
import { ContentWrap, Page, useVbenModal } from '@vben/common-ui';
|
||||||
@@ -24,6 +24,7 @@ import {
|
|||||||
import { getPropertyList } from './index';
|
import { getPropertyList } from './index';
|
||||||
import ProductAttributes from './product-attributes.vue';
|
import ProductAttributes from './product-attributes.vue';
|
||||||
import ProductPropertyAddForm from './product-property-add-form.vue';
|
import ProductPropertyAddForm from './product-property-add-form.vue';
|
||||||
|
import SkuList from './sku-list.vue';
|
||||||
|
|
||||||
const spuId = ref<number>();
|
const spuId = ref<number>();
|
||||||
const { params, name } = useRoute();
|
const { params, name } = useRoute();
|
||||||
@@ -63,6 +64,7 @@ const formData = ref<MallSpuApi.Spu>({
|
|||||||
const propertyList = ref<PropertyAndValues[]>([]); // 商品属性列表
|
const propertyList = ref<PropertyAndValues[]>([]); // 商品属性列表
|
||||||
const formLoading = ref(false); // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
const formLoading = ref(false); // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||||
const isDetail = ref(false); // 是否查看详情
|
const isDetail = ref(false); // 是否查看详情
|
||||||
|
const skuListRef = ref(); // 商品属性列表 Ref
|
||||||
|
|
||||||
// sku 相关属性校验规则
|
// sku 相关属性校验规则
|
||||||
const ruleConfig: RuleConfig[] = [
|
const ruleConfig: RuleConfig[] = [
|
||||||
@@ -88,15 +90,6 @@ const ruleConfig: RuleConfig[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// 动态生成 sku form schema
|
|
||||||
const skuFormSchema = computed(() => {
|
|
||||||
return useSkuFormSchema(
|
|
||||||
propertyList.value,
|
|
||||||
ruleConfig,
|
|
||||||
isDetail.value || false,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const [InfoForm, infoFormApi] = useVbenForm({
|
const [InfoForm, infoFormApi] = useVbenForm({
|
||||||
commonConfig: {
|
commonConfig: {
|
||||||
componentProps: {
|
componentProps: {
|
||||||
@@ -119,8 +112,18 @@ const [SkuForm, skuFormApi] = useVbenForm({
|
|||||||
labelWidth: 120,
|
labelWidth: 120,
|
||||||
},
|
},
|
||||||
layout: 'horizontal',
|
layout: 'horizontal',
|
||||||
schema: skuFormSchema.value,
|
schema: useSkuFormSchema(propertyList.value, isDetail.value),
|
||||||
showDefaultActions: false,
|
showDefaultActions: false,
|
||||||
|
handleValuesChange: (values, fieldsChanged) => {
|
||||||
|
if (fieldsChanged.includes('subCommissionType')) {
|
||||||
|
formData.value.subCommissionType = values.subCommissionType;
|
||||||
|
changeSubCommissionType();
|
||||||
|
}
|
||||||
|
if (fieldsChanged.includes('specType')) {
|
||||||
|
formData.value.specType = values.specType;
|
||||||
|
onChangeSpec();
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const [ProductPropertyAddFormModal, productPropertyAddFormApi] = useVbenModal({
|
const [ProductPropertyAddFormModal, productPropertyAddFormApi] = useVbenModal({
|
||||||
@@ -227,11 +230,8 @@ const getDetail = async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
formData.value = res;
|
formData.value = res;
|
||||||
// 将 SKU 的属性,整理成 PropertyAndValues 数组
|
|
||||||
propertyList.value = getPropertyList(res);
|
|
||||||
// 初始化各表单值(异步)
|
// 初始化各表单值(异步)
|
||||||
infoFormApi.setValues(res);
|
infoFormApi.setValues(res);
|
||||||
// 特殊处理 SpuSkuFormData
|
|
||||||
skuFormApi.setValues(res);
|
skuFormApi.setValues(res);
|
||||||
deliveryFormApi.setValues(res);
|
deliveryFormApi.setValues(res);
|
||||||
descriptionFormApi.setValues(res);
|
descriptionFormApi.setValues(res);
|
||||||
@@ -240,18 +240,58 @@ const getDetail = async () => {
|
|||||||
formLoading.value = false;
|
formLoading.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 将 SKU 的属性,整理成 PropertyAndValues 数组
|
||||||
|
propertyList.value = getPropertyList(formData.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// =========== sku form 逻辑 ===========
|
||||||
|
|
||||||
|
function openPropertyAddForm() {
|
||||||
|
productPropertyAddFormApi.open();
|
||||||
|
}
|
||||||
|
|
||||||
/** 调用 SkuList generateTableData 方法*/
|
/** 调用 SkuList generateTableData 方法*/
|
||||||
const generateSkus = (propertyList: any[]) => {
|
const generateSkus = (propertyList: any[]) => {
|
||||||
// skuListRef.value.generateTableData(propertyList)
|
skuListRef.value.generateTableData(propertyList);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 分销类型 */
|
||||||
|
const changeSubCommissionType = () => {
|
||||||
|
// 默认为零,类型切换后也要重置为零
|
||||||
|
for (const item of formData.value.skus!) {
|
||||||
|
item.firstBrokeragePrice = 0;
|
||||||
|
item.secondBrokeragePrice = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 选择规格 */
|
||||||
|
const onChangeSpec = () => {
|
||||||
|
// 重置商品属性列表
|
||||||
|
propertyList.value = [];
|
||||||
|
// 重置sku列表
|
||||||
|
formData.value.skus = [
|
||||||
|
{
|
||||||
|
price: 0,
|
||||||
|
marketPrice: 0,
|
||||||
|
costPrice: 0,
|
||||||
|
barCode: '',
|
||||||
|
picUrl: '',
|
||||||
|
stock: 0,
|
||||||
|
weight: 0,
|
||||||
|
volume: 0,
|
||||||
|
firstBrokeragePrice: 0,
|
||||||
|
secondBrokeragePrice: 0,
|
||||||
|
},
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
// 监听 sku form schema 变化,更新表单
|
// 监听 sku form schema 变化,更新表单
|
||||||
watch(
|
watch(
|
||||||
skuFormSchema,
|
propertyList,
|
||||||
(newSchema) => {
|
() => {
|
||||||
skuFormApi.updateSchema(newSchema);
|
skuFormApi.updateSchema(
|
||||||
|
useSkuFormSchema(propertyList.value, isDetail.value),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
{ deep: true },
|
{ deep: true },
|
||||||
);
|
);
|
||||||
@@ -266,7 +306,7 @@ onMounted(async () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ProductPropertyAddFormModal />
|
<ProductPropertyAddFormModal :property-list="propertyList" />
|
||||||
|
|
||||||
<Page auto-content-height>
|
<Page auto-content-height>
|
||||||
<ContentWrap class="h-full w-full pb-8">
|
<ContentWrap class="h-full w-full pb-8">
|
||||||
@@ -278,13 +318,18 @@ onMounted(async () => {
|
|||||||
<InfoForm class="w-3/5" />
|
<InfoForm class="w-3/5" />
|
||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
<Tabs.TabPane tab="价格库存" key="sku">
|
<Tabs.TabPane tab="价格库存" key="sku">
|
||||||
<SkuForm class="w-3/5">
|
<SkuForm class="w-full">
|
||||||
|
<template #singleSkuList>
|
||||||
|
<SkuList
|
||||||
|
ref="skuListRef"
|
||||||
|
:prop-form-data="formData"
|
||||||
|
:property-list="propertyList"
|
||||||
|
:rule-config="ruleConfig"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
<template #productAttributes>
|
<template #productAttributes>
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button class="mb-10px mr-15px" @click="openPropertyAddForm">
|
||||||
class="mb-10px mr-15px"
|
|
||||||
@click="productPropertyAddFormApi.open"
|
|
||||||
>
|
|
||||||
添加属性
|
添加属性
|
||||||
</Button>
|
</Button>
|
||||||
<ProductAttributes
|
<ProductAttributes
|
||||||
@@ -294,6 +339,22 @@ onMounted(async () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<template #batchSkuList>
|
||||||
|
<SkuList
|
||||||
|
:is-batch="true"
|
||||||
|
:prop-form-data="formData"
|
||||||
|
:property-list="propertyList"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #multiSkuList>
|
||||||
|
<SkuList
|
||||||
|
ref="skuListRef"
|
||||||
|
:is-detail="isDetail"
|
||||||
|
:prop-form-data="formData"
|
||||||
|
:property-list="propertyList"
|
||||||
|
:rule-config="ruleConfig"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
</SkuForm>
|
</SkuForm>
|
||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
<Tabs.TabPane tab="物流设置" key="delivery">
|
<Tabs.TabPane tab="物流设置" key="delivery">
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ const [Form, formApi] = useVbenForm({
|
|||||||
|
|
||||||
// 初始化弹窗
|
// 初始化弹窗
|
||||||
const [Modal, modalApi] = useVbenModal({
|
const [Modal, modalApi] = useVbenModal({
|
||||||
|
destroyOnClose: true, // 关键:关闭时销毁弹窗,确保每次打开都是全新状态
|
||||||
async onConfirm() {
|
async onConfirm() {
|
||||||
const { valid } = await formApi.validate();
|
const { valid } = await formApi.validate();
|
||||||
if (!valid) return;
|
if (!valid) return;
|
||||||
@@ -118,7 +119,6 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 情况二:如果是不存在的属性,则需要执行新增
|
// 情况二:如果是不存在的属性,则需要执行新增
|
||||||
modalApi.lock();
|
|
||||||
try {
|
try {
|
||||||
const data = { name } as MallPropertyApi.Property;
|
const data = { name } as MallPropertyApi.Property;
|
||||||
const propertyId = await createProperty(data);
|
const propertyId = await createProperty(data);
|
||||||
@@ -131,8 +131,9 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
message.success($t('common.createSuccess'));
|
message.success($t('common.createSuccess'));
|
||||||
await modalApi.close();
|
await modalApi.close();
|
||||||
emit('success');
|
emit('success');
|
||||||
} finally {
|
} catch (error) {
|
||||||
modalApi.unlock();
|
// 发生错误时不关闭弹窗
|
||||||
|
console.error('添加属性失败:', error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async onOpenChange(isOpen: boolean) {
|
async onOpenChange(isOpen: boolean) {
|
||||||
|
|||||||
@@ -214,11 +214,8 @@ const validateData = (propertyList: PropertyAndValues[]): boolean => {
|
|||||||
sku.properties
|
sku.properties
|
||||||
?.map((property: MallSpuApi.Property) => property.propertyId)
|
?.map((property: MallSpuApi.Property) => property.propertyId)
|
||||||
?.forEach((propertyId?: number) => {
|
?.forEach((propertyId?: number) => {
|
||||||
if (
|
if (!skuPropertyIds.includes(propertyId!)) {
|
||||||
propertyId !== undefined &&
|
skuPropertyIds.push(propertyId!);
|
||||||
!skuPropertyIds.indexOf(propertyId) === -1
|
|
||||||
) {
|
|
||||||
skuPropertyIds.push(propertyId);
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user