parent
4410bdd93c
commit
c254222b5f
@ -37,7 +37,6 @@ import { useTagsViewStore } from '@/store/modules/tagsView'
|
|||||||
import { BasicInfoForm, DescriptionForm, OtherSettingsForm } from './components'
|
import { BasicInfoForm, DescriptionForm, OtherSettingsForm } from './components'
|
||||||
// 业务api
|
// 业务api
|
||||||
import * as ProductSpuApi from '@/api/mall/product/spu'
|
import * as ProductSpuApi from '@/api/mall/product/spu'
|
||||||
import * as PropertyApi from '@/api/mall/product/property'
|
|
||||||
import { convertToInteger, formatToFraction } from '@/utils'
|
import { convertToInteger, formatToFraction } from '@/utils'
|
||||||
|
|
||||||
const { t } = useI18n() // 国际化
|
const { t } = useI18n() // 国际化
|
||||||
@ -105,25 +104,6 @@ const getDetail = async () => {
|
|||||||
item.subCommissionSecondPrice = formatToFraction(item.subCommissionSecondPrice)
|
item.subCommissionSecondPrice = formatToFraction(item.subCommissionSecondPrice)
|
||||||
})
|
})
|
||||||
formData.value = res
|
formData.value = res
|
||||||
// 只有是多规格才处理
|
|
||||||
if (res.specType) {
|
|
||||||
// TODO @puhui999:可以直接拿 propertyName 拼接处规格 id + 属性,可以看下商品 uniapp 详情的做法
|
|
||||||
// fix: 考虑到 sku 数量和通过属性算出来的sku不一致的情况
|
|
||||||
const propertyIds = []
|
|
||||||
res.skus.forEach((sku) =>
|
|
||||||
sku.properties
|
|
||||||
?.map((property) => property.propertyId)
|
|
||||||
.forEach((propertyId) => {
|
|
||||||
if (propertyIds.indexOf(propertyId) === -1) {
|
|
||||||
propertyIds.push(propertyId)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
const properties = await PropertyApi.getPropertyListAndValue({ propertyIds })
|
|
||||||
await nextTick()
|
|
||||||
// 回显商品属性
|
|
||||||
basicInfoRef.value.addAttribute(properties)
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
formLoading.value = false
|
formLoading.value = false
|
||||||
}
|
}
|
||||||
@ -141,7 +121,7 @@ const submitForm = async () => {
|
|||||||
await unref(descriptionRef)?.validate()
|
await unref(descriptionRef)?.validate()
|
||||||
await unref(otherSettingsRef)?.validate()
|
await unref(otherSettingsRef)?.validate()
|
||||||
const deepCopyFormData = cloneDeep(unref(formData.value)) // 深拷贝一份 fix:这样最终 server 端不满足,不需要恢复,
|
const deepCopyFormData = cloneDeep(unref(formData.value)) // 深拷贝一份 fix:这样最终 server 端不满足,不需要恢复,
|
||||||
// TODO 兜底处理 sku 空数据详见 SkuList TODO
|
// TODO 兜底处理 sku 空数据
|
||||||
formData.value.skus.forEach((sku) => {
|
formData.value.skus.forEach((sku) => {
|
||||||
// 因为是空数据这里判断一下商品条码是否为空就行
|
// 因为是空数据这里判断一下商品条码是否为空就行
|
||||||
if (sku.barCode === '') {
|
if (sku.barCode === '') {
|
||||||
|
@ -98,14 +98,14 @@
|
|||||||
<el-form-item v-if="formData.specType" label="商品属性">
|
<el-form-item v-if="formData.specType" label="商品属性">
|
||||||
<!-- TODO @puhui999:参考 https://admin.java.crmeb.net/store/list/creatProduct 添加规格好做么?添加的时候,不用输入备注哈 fix-->
|
<!-- TODO @puhui999:参考 https://admin.java.crmeb.net/store/list/creatProduct 添加规格好做么?添加的时候,不用输入备注哈 fix-->
|
||||||
<el-button class="mr-15px mb-10px" @click="attributesAddFormRef.open">添加规格</el-button>
|
<el-button class="mr-15px mb-10px" @click="attributesAddFormRef.open">添加规格</el-button>
|
||||||
<ProductAttributes :propertyList="propertyList" />
|
<ProductAttributes :propertyList="propertyList" @success="generateSkus" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<template v-if="formData.specType && propertyList.length > 0">
|
<template v-if="formData.specType && propertyList.length > 0">
|
||||||
<el-form-item label="批量设置">
|
<el-form-item label="批量设置">
|
||||||
<SkuList :is-batch="true" :prop-form-data="formData" :propertyList="propertyList" />
|
<SkuList :is-batch="true" :prop-form-data="formData" :propertyList="propertyList" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="属性列表">
|
<el-form-item label="属性列表">
|
||||||
<SkuList :prop-form-data="formData" :propertyList="propertyList" />
|
<SkuList ref="skuListRef" :prop-form-data="formData" :propertyList="propertyList" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
<el-form-item v-if="!formData.specType">
|
<el-form-item v-if="!formData.specType">
|
||||||
@ -114,7 +114,7 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
<ProductAttributesAddForm ref="attributesAddFormRef" @success="addAttribute" />
|
<ProductAttributesAddForm ref="attributesAddFormRef" :propertyList="propertyList" />
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" name="ProductSpuBasicInfoForm" setup>
|
<script lang="ts" name="ProductSpuBasicInfoForm" setup>
|
||||||
import { PropType } from 'vue'
|
import { PropType } from 'vue'
|
||||||
@ -141,15 +141,11 @@ const attributesAddFormRef = ref() // 添加商品属性表单 TODO @puhui999:
|
|||||||
const productSpuBasicInfoRef = ref() // 表单Ref TODO @puhui999:小写开头哈 fix
|
const productSpuBasicInfoRef = ref() // 表单Ref TODO @puhui999:小写开头哈 fix
|
||||||
// TODO @puhui999:attributeList 改成 propertyList,会更统一一点 fix
|
// TODO @puhui999:attributeList 改成 propertyList,会更统一一点 fix
|
||||||
const propertyList = ref([]) // 商品属性列表
|
const propertyList = ref([]) // 商品属性列表
|
||||||
/** 添加商品属性 */
|
const skuListRef = ref() // 商品属性列表Ref
|
||||||
// TODO @puhui999:propFormData 算出来 fix: 因为ProductAttributesAddForm添加属性成功回调得使用不能完全依赖于propFormData
|
|
||||||
const addAttribute = (property: any) => {
|
|
||||||
Array.isArray(property) ? (propertyList.value = property) : propertyList.value.push(property)
|
|
||||||
}
|
|
||||||
/** 调用 SkuList generateTableData 方法*/
|
/** 调用 SkuList generateTableData 方法*/
|
||||||
// const generateSkus(propertyList){
|
const generateSkus = (propertyList) => {
|
||||||
// skuList.value.generateTableData()
|
skuListRef.value.generateTableData(propertyList)
|
||||||
// }
|
}
|
||||||
const formData = reactive<SpuType>({
|
const formData = reactive<SpuType>({
|
||||||
name: '', // 商品名称
|
name: '', // 商品名称
|
||||||
categoryId: null, // 商品分类
|
categoryId: null, // 商品分类
|
||||||
@ -191,6 +187,26 @@ watch(
|
|||||||
formData.sliderPicUrls = data['sliderPicUrls'].map((item) => ({
|
formData.sliderPicUrls = data['sliderPicUrls'].map((item) => ({
|
||||||
url: item
|
url: item
|
||||||
}))
|
}))
|
||||||
|
// 只有是多规格才处理
|
||||||
|
if (formData.specType) {
|
||||||
|
// TODO @puhui999:可以直接拿 propertyName 拼接处规格 id + 属性,可以看下商品 uniapp 详情的做法
|
||||||
|
// fix: 直接拿返回的 skus 属性逆向生成出 propertyList
|
||||||
|
const properties = []
|
||||||
|
formData.skus.forEach((sku) => {
|
||||||
|
sku.properties.forEach(({ propertyId, propertyName, valueId, valueName }) => {
|
||||||
|
// 添加属性
|
||||||
|
if (!properties.some((item) => item.id === propertyId)) {
|
||||||
|
properties.push({ id: propertyId, name: propertyName, values: [] })
|
||||||
|
}
|
||||||
|
// 添加属性值
|
||||||
|
const index = properties.findIndex((item) => item.id === propertyId)
|
||||||
|
if (!properties[index].values.some((value) => value.id === valueId)) {
|
||||||
|
properties[index].values.push({ id: valueId, name: valueName })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
propertyList.value = properties
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// fix: 去掉深度监听只有对象引用发生改变的时候才执行,解决改一动多的问题
|
// fix: 去掉深度监听只有对象引用发生改变的时候才执行,解决改一动多的问题
|
||||||
@ -217,7 +233,7 @@ const validate = async () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
defineExpose({ validate, addAttribute })
|
defineExpose({ validate })
|
||||||
|
|
||||||
/** 分销类型 */
|
/** 分销类型 */
|
||||||
const changeSubCommissionType = () => {
|
const changeSubCommissionType = () => {
|
||||||
|
@ -2,23 +2,25 @@
|
|||||||
<el-col v-for="(item, index) in attributeList" :key="index">
|
<el-col v-for="(item, index) in attributeList" :key="index">
|
||||||
<div>
|
<div>
|
||||||
<el-text class="mx-1">属性名:</el-text>
|
<el-text class="mx-1">属性名:</el-text>
|
||||||
<el-text class="mx-1">{{ item.name }}</el-text>
|
<el-tag class="mx-1" closable type="success" @close="handleCloseProperty(index)"
|
||||||
|
>{{ item.name }}
|
||||||
|
</el-tag>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<el-text class="mx-1">属性值:</el-text>
|
<el-text class="mx-1">属性值:</el-text>
|
||||||
<el-tag
|
<el-tag
|
||||||
v-for="(value, valueIndex) in item.values"
|
v-for="(value, valueIndex) in item.values"
|
||||||
:key="value.id"
|
:key="value.id"
|
||||||
:disable-transitions="false"
|
|
||||||
class="mx-1"
|
class="mx-1"
|
||||||
closable
|
closable
|
||||||
@close="handleClose(index, valueIndex)"
|
@close="handleCloseValue(index, valueIndex)"
|
||||||
>
|
>
|
||||||
{{ value.name }}
|
{{ value.name }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
<el-input
|
<el-input
|
||||||
v-show="inputVisible(index)"
|
v-show="inputVisible(index)"
|
||||||
ref="InputRef"
|
:id="`input${index}`"
|
||||||
|
:ref="setInputRef"
|
||||||
v-model="inputValue"
|
v-model="inputValue"
|
||||||
class="!w-20"
|
class="!w-20"
|
||||||
size="small"
|
size="small"
|
||||||
@ -51,7 +53,15 @@ const inputVisible = computed(() => (index) => {
|
|||||||
if (attributeIndex.value === null) return false
|
if (attributeIndex.value === null) return false
|
||||||
if (attributeIndex.value === index) return true
|
if (attributeIndex.value === index) return true
|
||||||
})
|
})
|
||||||
const InputRef = ref() //标签输入框Ref
|
const inputRef = ref([]) //标签输入框Ref
|
||||||
|
/** 解决 ref 在 v-for 中的获取问题*/
|
||||||
|
const setInputRef = (el) => {
|
||||||
|
if (el === null || typeof el === 'undefined') return
|
||||||
|
// 如果不存在id相同的元素才添加
|
||||||
|
if (!inputRef.value.some((item) => item.input?.attributes.id === el.input?.attributes.id)) {
|
||||||
|
inputRef.value.push(el)
|
||||||
|
}
|
||||||
|
}
|
||||||
const attributeList = ref([]) // 商品属性列表
|
const attributeList = ref([]) // 商品属性列表
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
propertyList: {
|
propertyList: {
|
||||||
@ -72,19 +82,22 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
/** 删除标签 tagValue 标签值*/
|
/** 删除属性值*/
|
||||||
const handleClose = (index, valueIndex) => {
|
const handleCloseValue = (index, valueIndex) => {
|
||||||
attributeList.value[index].values?.splice(valueIndex, 1)
|
attributeList.value[index].values?.splice(valueIndex, 1)
|
||||||
}
|
}
|
||||||
|
/** 删除属性*/
|
||||||
|
const handleCloseProperty = (index) => {
|
||||||
|
attributeList.value?.splice(index, 1)
|
||||||
|
}
|
||||||
/** 显示输入框并获取焦点 */
|
/** 显示输入框并获取焦点 */
|
||||||
const showInput = async (index) => {
|
const showInput = async (index) => {
|
||||||
attributeIndex.value = index
|
attributeIndex.value = index
|
||||||
// TODO 嗯!!!自动获取焦点还是有点问题,后续继续改进
|
inputRef.value[index].focus()
|
||||||
// 因为组件在ref中所以需要用索引获取对应的Ref
|
|
||||||
InputRef.value[index]!.input!.focus()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
||||||
|
|
||||||
/** 输入框失去焦点或点击回车时触发 */
|
/** 输入框失去焦点或点击回车时触发 */
|
||||||
const handleInputConfirm = async (index, propertyId) => {
|
const handleInputConfirm = async (index, propertyId) => {
|
||||||
if (inputValue.value) {
|
if (inputValue.value) {
|
||||||
@ -93,6 +106,7 @@ const handleInputConfirm = async (index, propertyId) => {
|
|||||||
const id = await PropertyApi.createPropertyValue({ propertyId, name: inputValue.value })
|
const id = await PropertyApi.createPropertyValue({ propertyId, name: inputValue.value })
|
||||||
attributeList.value[index].values.push({ id, name: inputValue.value })
|
attributeList.value[index].values.push({ id, name: inputValue.value })
|
||||||
message.success(t('common.createSuccess'))
|
message.success(t('common.createSuccess'))
|
||||||
|
emit('success', attributeList.value)
|
||||||
} catch {
|
} catch {
|
||||||
message.error('添加失败,请重试') // TODO 缺少国际化
|
message.error('添加失败,请重试') // TODO 缺少国际化
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,25 @@ const formRules = reactive({
|
|||||||
name: [{ required: true, message: '名称不能为空', trigger: 'blur' }]
|
name: [{ required: true, message: '名称不能为空', trigger: 'blur' }]
|
||||||
})
|
})
|
||||||
const formRef = ref() // 表单 Ref
|
const formRef = ref() // 表单 Ref
|
||||||
|
const attributeList = ref([]) // 商品属性列表
|
||||||
|
const props = defineProps({
|
||||||
|
propertyList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.propertyList,
|
||||||
|
(data) => {
|
||||||
|
if (!data) return
|
||||||
|
attributeList.value = data
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
)
|
||||||
/** 打开弹窗 */
|
/** 打开弹窗 */
|
||||||
const open = async () => {
|
const open = async () => {
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
@ -42,7 +60,6 @@ const open = async () => {
|
|||||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||||
|
|
||||||
/** 提交表单 */
|
/** 提交表单 */
|
||||||
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
|
||||||
const submitForm = async () => {
|
const submitForm = async () => {
|
||||||
// 校验表单
|
// 校验表单
|
||||||
if (!formRef) return
|
if (!formRef) return
|
||||||
@ -56,12 +73,12 @@ const submitForm = async () => {
|
|||||||
const res = await PropertyApi.getPropertyListAndValue({ name: data.name })
|
const res = await PropertyApi.getPropertyListAndValue({ name: data.name })
|
||||||
if (res.length === 0) {
|
if (res.length === 0) {
|
||||||
const propertyId = await PropertyApi.createProperty(data)
|
const propertyId = await PropertyApi.createProperty(data)
|
||||||
emit('success', { id: propertyId, ...formData.value, values: [] })
|
attributeList.value.push({ id: propertyId, ...formData.value, values: [] })
|
||||||
} else {
|
} else {
|
||||||
if (res[0].values === null) {
|
if (res[0].values === null) {
|
||||||
res[0].values = []
|
res[0].values = []
|
||||||
}
|
}
|
||||||
emit('success', res[0]) // 因为只用一个
|
attributeList.value.push(res[0]) // 因为只用一个
|
||||||
}
|
}
|
||||||
message.success(t('common.createSuccess'))
|
message.success(t('common.createSuccess'))
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
|
@ -212,10 +212,6 @@ const generateTableData = (propertyList: any[]) => {
|
|||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* TODO 嗯。。有一个问题回显数据时已删除的 sku 会被重新添加暂时没想到好办法,保存时先手动重新删除一下因为是一条空数据很好辨别 不手动删也没是提交表单时会检测删除空sku来兜底
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
formData.value.skus.push(row)
|
formData.value.skus.push(row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,4 +298,6 @@ watch(
|
|||||||
immediate: true
|
immediate: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
// 暴露出生成 sku 方法给添加属性成功时调用 fix: 为了在只有一个属性下 spu 回显 skus 属性和和商品属性个数一致的情况下 添加属性值时添加 sku
|
||||||
|
defineExpose({ generateTableData })
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
Reference in New Issue
Block a user