From 6bbf8781719acdf2ef3a8070049d04b907aa1d82 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Tue, 21 Oct 2025 16:39:54 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E3=80=90mall=20=E5=95=86=E5=9F=8E?= =?UTF-8?q?=E3=80=91=E5=95=86=E5=93=81=E5=8F=91=E5=B8=83=20-=20=E5=BA=93?= =?UTF-8?q?=E5=AD=98=E4=BB=B7=E6=A0=BC=E3=80=90antd=E3=80=91100%:=20?= =?UTF-8?q?=E8=BF=81=E7=A7=BB=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spu/modules/product-attributes.vue | 23 +++++++++++-------- .../mall/product/spu/modules/sku-list.vue | 19 ++++----------- packages/@core/base/shared/src/utils/util.ts | 19 +++++++++++++++ 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/apps/web-antd/src/views/mall/product/spu/modules/product-attributes.vue b/apps/web-antd/src/views/mall/product/spu/modules/product-attributes.vue index 1731497c6..f54bf3c51 100644 --- a/apps/web-antd/src/views/mall/product/spu/modules/product-attributes.vue +++ b/apps/web-antd/src/views/mall/product/spu/modules/product-attributes.vue @@ -29,7 +29,7 @@ interface Props { isDetail?: boolean; } -const inputValue = ref(''); // 输入框值 +const inputValue = ref([]); // 输入框值(tags 模式使用数组) const attributeIndex = ref(null); // 获取焦点时记录当前属性项的index // 输入框显隐控制 const inputVisible = computed(() => (index: number) => { @@ -95,26 +95,29 @@ const showInput = async (index: number) => { // 定义 success 事件,用于操作成功后的回调 const handleInputConfirm = async (index: number, propertyId: number) => { - if (inputValue.value) { + // 从数组中取最后一个输入的值(tags 模式下 inputValue 是数组) + const currentValue = inputValue.value?.[inputValue.value.length - 1]?.trim(); + + if (currentValue) { // 1. 重复添加校验 if ( attributeList.value?.[index]?.values?.find( - (item) => item.name === inputValue.value, + (item) => item.name === currentValue, ) ) { message.warning('已存在相同属性值,请重试'); attributeIndex.value = null; - inputValue.value = ''; + inputValue.value = []; return; } // 2.1 情况一:属性值已存在,则直接使用并结束 const existValue = attributeOptions.value.find( - (item) => item.name === inputValue.value, + (item) => item.name === currentValue, ); if (existValue) { attributeIndex.value = null; - inputValue.value = ''; + inputValue.value = []; attributeList.value?.[index]?.values?.push({ id: existValue.id!, name: existValue.name, @@ -127,11 +130,11 @@ const handleInputConfirm = async (index: number, propertyId: number) => { try { const id = await createPropertyValue({ propertyId, - name: inputValue.value, + name: currentValue, }); attributeList.value?.[index]?.values?.push({ id, - name: inputValue.value, + name: currentValue, }); message.success($t('common.createSuccess')); emit('success', attributeList.value); @@ -140,7 +143,7 @@ const handleInputConfirm = async (index: number, propertyId: number) => { } } attributeIndex.value = null; - inputValue.value = ''; + inputValue.value = []; }; /** 获取商品属性下拉选项 */ @@ -179,11 +182,11 @@ const getAttributeOptions = async (propertyId: number) => { :ref="setInputRef" v-model:value="inputValue" allow-clear - class="!w-30" mode="tags" :max-tag-count="1" :filter-option="true" size="small" + style="width: 100px" @blur="handleInputConfirm(index, item.id)" @change="handleInputConfirm(index, item.id)" @keyup.enter="handleInputConfirm(index, item.id)" diff --git a/apps/web-antd/src/views/mall/product/spu/modules/sku-list.vue b/apps/web-antd/src/views/mall/product/spu/modules/sku-list.vue index 89dd2efe0..eb6f5718b 100644 --- a/apps/web-antd/src/views/mall/product/spu/modules/sku-list.vue +++ b/apps/web-antd/src/views/mall/product/spu/modules/sku-list.vue @@ -7,7 +7,7 @@ import type { MallSpuApi } from '#/api/mall/product/spu'; import { ref, watch } from 'vue'; -import { formatToFraction, isEmpty } from '@vben/utils'; +import { copyValueToTarget, formatToFraction, isEmpty } from '@vben/utils'; import { Button, Image, Input, InputNumber, message } from 'ant-design-vue'; @@ -59,20 +59,11 @@ const skuList = ref([ }, ]); // 批量添加时的临时数据 -/** 商品图预览 */ -const imagePreview = (imgUrl: string) => { - // TODO @puhui999: 图片预览 - // createImageViewer({ - // zIndex: 9_999_999, - // urlList: [imgUrl], - // }); -}; - /** 批量添加 */ const batchAdd = () => { validateProperty(); formData.value!.skus!.forEach((item: MallSpuApi.Sku) => { - // copyValueToTarget(item, skuList.value[0]); + copyValueToTarget(item, skuList.value[0]); }); }; @@ -478,8 +469,7 @@ defineExpose({ generateTableData, validateSku, getSkuTableRef }); v-if="row.picUrl" :src="row.picUrl" class="h-[50px] w-[50px] cursor-pointer" - :preview="false" - @click="imagePreview(row.picUrl)" + :preview="true" /> @@ -563,8 +553,7 @@ defineExpose({ generateTableData, validateSku, getSkuTableRef }); diff --git a/packages/@core/base/shared/src/utils/util.ts b/packages/@core/base/shared/src/utils/util.ts index ea7ddbedd..fd202ed50 100644 --- a/packages/@core/base/shared/src/utils/util.ts +++ b/packages/@core/base/shared/src/utils/util.ts @@ -68,3 +68,22 @@ export const getUrlValue = ( const url = new URL(decodeURIComponent(urlStr)); return url.searchParams.get(key) ?? ''; }; + +/** + * 将值复制到目标对象,且以目标对象属性为准,例:target: {a:1} source:{a:2,b:3} 结果为:{a:2} + * @param target 目标对象 + * @param source 源对象 + */ +export const copyValueToTarget = (target: any, source: any) => { + const newObj = Object.assign({}, target, source); + // 删除多余属性 + Object.keys(newObj).forEach((key) => { + // 如果不是target中的属性则删除 + if (!Object.keys(target).includes(key)) { + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete newObj[key]; + } + }); + // 更新目标对象值 + Object.assign(target, newObj); +};