feat: 商品详情联调2

This commit is contained in:
zc 2025-10-28 23:21:44 +08:00
parent 6b3895b6a1
commit a31beb08f2
5 changed files with 164 additions and 99 deletions

View File

@ -27,14 +27,12 @@
size="small" size="small"
class="w-40" class="w-40"
@keyup.enter="handleInputConfirm(data)" @keyup.enter="handleInputConfirm(data)"
@blur="handleInputCancel(node, data)" @blur="treeRef.remove(node)"
/> />
<div> <div>
<el-button type="primary" link @click="onEdit(data)" size="small">编辑 </el-button> <el-button type="primary" link @click="onEdit(data)" size="small">编辑 </el-button>
<el-button type="primary" link @click="append(data)" size="small"> 添加 </el-button> <el-button type="primary" link @click="append(data)" size="small"> 添加 </el-button>
<el-button type="danger" size="small" link @click="remove(node, data)"> <el-button type="danger" size="small" link @click="onDelete(node)"> 删除 </el-button>
删除
</el-button>
</div> </div>
</div> </div>
</template> </template>
@ -86,14 +84,6 @@ const handleInputConfirm = async (data: any) => {
curId.value = NaN curId.value = NaN
} }
//
const handleInputCancel = (node: Node, data: Data) => {
if (data.id === Infinity) {
remove(node, data)
}
curId.value = NaN
}
// //
const append = async (data: Data) => { const append = async (data: Data) => {
const node = treeRef.value.getNode(data.id) const node = treeRef.value.getNode(data.id)
@ -116,16 +106,21 @@ const append = async (data: Data) => {
treeRef.value.append(newChild, data) treeRef.value.append(newChild, data)
node.expanded = true node.expanded = true
nextTick(() => { nextTick(() => {
inputRef.value.focus() const timer = setTimeout(() => {
clearTimeout(timer)
inputRef.value.focus()
}, 500)
}) })
} }
// //
const remove = (node: Node, data: Data) => { const onDelete = async (node: Node) => {
const parent = node.parent await api.commodity.updateAppCategory.post!({
const children: Tree[] = parent?.data.children || parent?.data id: node.data.id,
const index = children.findIndex((d) => d.id === data.id) isDelete: 1
children.splice(index, 1) })
treeRef.value.remove(node)
ElMessage.success('删除成功')
} }
const defaultProps = { const defaultProps = {

View File

@ -27,83 +27,84 @@
size="small" size="small"
class="w-40" class="w-40"
@keyup.enter="handleInputConfirm(data)" @keyup.enter="handleInputConfirm(data)"
@blur="handleInputCancel(node, data)" @blur="treeRef.remove(node)"
/> />
<template v-if="!data.hasOriginChild && !data.isProperty">
<el-input
ref="propertyTypeInputRef"
class="w-20"
size="small"
v-if="visiblePropertyType[data.id]"
v-model="inputPropertyTypeValue"
@keyup.enter="onAddPropertyType(data)"
@blur="visiblePropertyType[data.id] = false"
></el-input>
<el-button
v-else
type="primary"
size="small"
class="ml-2 !text-[10px] !px-2 !py-1 !pb-0.5 -mt-0.5"
@click="onClickPropertyTypeBtn(data)"
>新增属性</el-button
>
</template>
<template v-if="data.isProperty"> <template v-if="data.isProperty">
<dl class="flex items-center"> <dl class="flex items-center">
<dt class="text-sm text-[#666] mb-2">{{ data.categoryPropertyName }}</dt> <dt class="text-sm text-[#666] mb-2">{{ data.categoryPropertyName }}</dt>
<dd class="flex mb-2 flex-wrap"> <dd class="flex mb-2 flex-wrap">
<div v-for="child in data.vvPropertyValueList" :key="data.id + '-' + child.id"> <div v-for="child in data.vvPropertyValueList" :key="data.id + '-' + child.id">
<el-input
v-if="curPropertyValueId === child.id"
ref="editPropertyValueInputRef"
class="w-20"
size="small"
v-model="inputEditPropertyValue"
@keyup.enter="onEditPropertyValue(child)"
@blur="curPropertyValueId = NaN"
></el-input>
<el-tag <el-tag
v-else
closable closable
effect="plain" effect="plain"
type="primary" type="primary"
class="mr-1" class="mr-1"
@click="onClickPropertyValue(child)"
@close="onClosePropertyValue(child.id, data)" @close="onClosePropertyValue(child.id, data)"
>{{ child.categoryPropertyValue }}</el-tag >{{ child.categoryPropertyValue }}</el-tag
> >
</div> </div>
<el-popover <el-input
:visible="visibleProperty[data.id]" ref="propertyValueInputRef"
placement="bottom" class="w-20"
title="请输入属性值" size="small"
:width="200" v-if="visiblePropertyValue[data.id]"
trigger="click" v-model="inputPropertyValue"
@keyup.enter="onAddPropertyValue(data)"
@blur="visiblePropertyValue[data.id] = false"
></el-input>
<el-button
v-else
type="primary"
size="small"
class="ml-2 !text-[10px] !px-2 !py-1 !pb-0.5"
@click="onClickPropertyBtn(data)"
>新增属性值</el-button
> >
<template #reference>
<el-button
type="primary"
size="small"
class="ml-2 !text-white"
@click="visibleProperty[data.id] = true"
>新增属性值</el-button
>
</template>
<el-input
v-model="inputPropertyValue"
@keyup.enter="onAddPropertyValue(data)"
@blur="visibleProperty[data.id] = false"
></el-input>
</el-popover>
<el-popover
:visible="visiblePropertyType[data.id]"
placement="bottom"
title="请输入属性标题"
:width="200"
trigger="click"
>
<template #reference>
<el-button
type="primary"
size="small"
class="ml-2 !text-white"
@click="visiblePropertyType[data.id] = true"
>新增属性</el-button
>
</template>
<el-input
v-model="inputPropertyTypeValue"
@keyup.enter="onAddPropertyType(data)"
@blur="visiblePropertyType[data.id] = false"
></el-input>
</el-popover>
<el-button <el-button
type="danger" type="danger"
size="small" size="small"
class="ml-2 !text-white" class="!text-[10px] !px-2 !py-1 !pb-0.5"
@click="onDeleteProperty(data.id)" @click="onDeleteProperty(node, data.id)"
>删除属性</el-button >删除属性</el-button
> >
</dd> </dd>
</dl> </dl>
</template> </template>
</div> </div>
<div> <div v-if="!data.isProperty">
<el-button type="primary" link @click="onEdit(data)" size="small">编辑 </el-button> <el-button type="primary" link @click="onEdit(data)" size="small">编辑 </el-button>
<el-button type="primary" link @click="append(data)" size="small"> 添加 </el-button> <el-button type="primary" link @click="append(data)" size="small"> 添加 </el-button>
<el-button type="danger" size="small" link @click="remove(node, data)"> <el-button type="danger" size="small" link @click="onDelete(node)"> 删除 </el-button>
删除
</el-button>
</div> </div>
</div> </div>
</template> </template>
@ -156,12 +157,14 @@ const handleInputConfirm = async (data: any) => {
curId.value = NaN curId.value = NaN
} }
// //
const handleInputCancel = (node: Node, data: Data) => { const onDelete = async (node: Node) => {
if (data.id === Infinity) { await api.commodity.updateCategory.post!({
remove(node, data) id: node.data.id,
} isDelete: 1
curId.value = NaN })
treeRef.value.remove(node)
ElMessage.success('删除成功')
} }
// //
@ -170,7 +173,7 @@ const append = async (data: Data) => {
curId.value = Infinity curId.value = Infinity
curParentId.value = data.id curParentId.value = data.id
const newChild = { id: curId.value, name: '', label2: 'test', hasChild: false } const newChild = { id: curId.value, name: '', label2: 'test', hasChild: false }
if (!node.expanded) { if (!node.childNodes.length) {
await api.commodity.getCategoryList.post!<any>({ parentId: data.id || 0 }).then((res) => { await api.commodity.getCategoryList.post!<any>({ parentId: data.id || 0 }).then((res) => {
res.data.forEach((item: any) => { res.data.forEach((item: any) => {
treeRef.value.append( treeRef.value.append(
@ -186,18 +189,13 @@ const append = async (data: Data) => {
treeRef.value.append(newChild, data) treeRef.value.append(newChild, data)
node.expanded = true node.expanded = true
nextTick(() => { nextTick(() => {
inputRef.value.focus() const timer = setTimeout(() => {
clearTimeout(timer)
inputRef.value.focus()
}, 500)
}) })
} }
//
const remove = (node: Node, data: Data) => {
const parent = node.parent
const children: Tree[] = parent?.data.children || parent?.data
const index = children.findIndex((d) => d.id === data.id)
children.splice(index, 1)
}
const defaultProps = { const defaultProps = {
label: 'name', label: 'name',
children: 'children', children: 'children',
@ -222,6 +220,8 @@ const handleLoadNode = (node, resolve) => {
resolve( resolve(
res.data.map((item: any) => ({ res.data.map((item: any) => ({
...item, ...item,
vvCategoryPropertyDTOList: item.vvCategoryPropertyDTOList || [],
hasOriginChild: item.hasChild,
hasChild: item.hasChild || !!item.vvCategoryPropertyDTOList?.length, hasChild: item.hasChild || !!item.vvCategoryPropertyDTOList?.length,
children: item.hasChild ? [] : undefined children: item.hasChild ? [] : undefined
})) }))
@ -230,12 +230,12 @@ const handleLoadNode = (node, resolve) => {
} }
} }
const visibleProperty = ref<Record<number, boolean>>({}) const visiblePropertyValue = ref<Record<number, boolean>>({})
const inputPropertyValue = ref('') const inputPropertyValue = ref('')
const visiblePropertyType = ref<Record<number, boolean>>({}) const visiblePropertyType = ref<Record<number, boolean>>({})
const inputPropertyTypeValue = ref('') const inputPropertyTypeValue = ref('')
// //
const onClosePropertyValue = async (id: number, data: any) => { const onClosePropertyValue = async (id: number, data: any) => {
const i = data.vvPropertyValueList.findIndex((item: any) => item.id === id) const i = data.vvPropertyValueList.findIndex((item: any) => item.id === id)
await api.commodity.deleteCategoryPropertyValue.post!({ id }) await api.commodity.deleteCategoryPropertyValue.post!({ id })
@ -250,27 +250,40 @@ const onAddPropertyValue = async (data: any = {}) => {
categoryPropertyId: data.id, categoryPropertyId: data.id,
categoryPropertyValue: inputPropertyValue.value categoryPropertyValue: inputPropertyValue.value
}) })
// testzc
data.vvPropertyValueList.push(res.data) data.vvPropertyValueList.push(res.data)
} }
visibleProperty.value[data.id] = false visiblePropertyValue.value[data.id] = false
inputPropertyValue.value = '' inputPropertyValue.value = ''
ElMessage.success('新增成功') ElMessage.success('新增成功')
} }
// //
const onAddPropertyType = async (data: any = {}) => { const onAddPropertyType = async (data: any = {}) => {
console.warn('----- my data is data111: ', data) const node = treeRef.value.getNode(data.id)
if (inputPropertyTypeValue.value) { if (inputPropertyTypeValue.value) {
const res = await api.commodity.updateCategoryProperty.post!({ const res = await api.commodity.updateCategoryProperty.post!<{
categoryId: data.categoryId, id: number
categoryName: data.categoryName, categoryPropertyName: string
}>({
categoryId: data.id,
categoryName: data.name,
categoryPropertyName: inputPropertyTypeValue.value categoryPropertyName: inputPropertyTypeValue.value
}) })
console.warn('----- my data is data.id: ', data.id) const newData = {
res.data.vvPropertyValueList = [] ...res.data,
const newData = res.data hasChild: 0,
// testzc isProperty: 1,
vvPropertyValueList: []
}
data.vvCategoryPropertyDTOList.push(newData)
if (!node.childNodes.length) {
data.vvCategoryPropertyDTOList.forEach((item: any) => {
treeRef.value.append({ ...item, hasChild: 0, isProperty: 1 }, data)
})
} else {
treeRef.value.append(newData, data)
}
node.expanded = true
visiblePropertyType.value[data.id] = false visiblePropertyType.value[data.id] = false
inputPropertyTypeValue.value = '' inputPropertyTypeValue.value = ''
ElMessage.success('新增成功') ElMessage.success('新增成功')
@ -278,15 +291,54 @@ const onAddPropertyType = async (data: any = {}) => {
} }
// //
const onDeleteProperty = async (id: number) => { const onDeleteProperty = async (node: Node, id: number) => {
handleMessageBox({ handleMessageBox({
msg: `是否删除属性?`, msg: `是否删除属性?`,
success: api.commodity.deleteCategoryProperty.post!, success: api.commodity.deleteCategoryProperty.post!,
data: { id } data: { id }
}).then(() => { }).then(() => {
// testzc treeRef.value.remove(node)
}) })
} }
const propertyTypeInputRef = ref()
const onClickPropertyTypeBtn = (data: any) => {
visiblePropertyType.value[data.id] = true
nextTick(() => {
propertyTypeInputRef.value.input!.focus()
})
}
const propertyValueInputRef = ref()
const onClickPropertyBtn = (data: any) => {
visiblePropertyValue.value[data.id] = true
nextTick(() => {
propertyValueInputRef.value.input!.focus()
})
}
const curPropertyValueId = ref(NaN)
const inputEditPropertyValue = ref('')
const editPropertyValueInputRef = ref()
const onClickPropertyValue = (data: any) => {
curPropertyValueId.value = data.id
inputEditPropertyValue.value = data.categoryPropertyValue
nextTick(() => {
const timer = setTimeout(() => {
clearTimeout(timer)
editPropertyValueInputRef.value[0].input!.focus()
}, 500)
})
}
const onEditPropertyValue = async (data: any) => {
await api.commodity.updateCategoryPropertyValue.post!({
id: data.id,
categoryPropertyValue: inputEditPropertyValue.value
})
ElMessage.success('编辑成功')
data.categoryPropertyValue = inputEditPropertyValue.value
curPropertyValueId.value = NaN
inputEditPropertyValue.value = ''
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -5,7 +5,7 @@ export const initConfig = () => {
dialog: [ dialog: [
{ {
title: { label: '商品标题', class: '!w-full', rule: true }, title: { label: '商品标题', class: '!w-full', rule: true },
appCategoryIds: { label: 'app类目', slot: 'appCategoryId', rule: true }, appCategoryId: { label: 'app类目', slot: 'appCategoryId', rule: true },
mainImageUrl: { label: '主图', slot: 'mainFile' }, mainImageUrl: { label: '主图', slot: 'mainFile' },
videoUrl: { label: '视频', slot: 'videoFile' }, videoUrl: { label: '视频', slot: 'videoFile' },
subImageUrl: { label: '副图', slot: 'subFile' }, subImageUrl: { label: '副图', slot: 'subFile' },

View File

@ -22,6 +22,8 @@ export const handleGetDialogData = (
defaultCheckedNodes.value.app = [data.appCategoryId1, data.appCategoryId2] defaultCheckedNodes.value.app = [data.appCategoryId1, data.appCategoryId2]
result.isTest = data.isTest result.isTest = data.isTest
result.title = data.title result.title = data.title
result.feature1 = data.feature1
result.feature2 = data.feature2
const files = [ const files = [
{ {
fileName: '主图', fileName: '主图',

View File

@ -79,6 +79,22 @@
</el-form-item> </el-form-item>
<el-form-item label="测试商品"> <el-form-item label="测试商品">
<el-switch v-model="$dialog.data.isTest" active-value="1" inactive-value="0" /> <el-switch v-model="$dialog.data.isTest" active-value="1" inactive-value="0" />
</el-form-item>
<el-form-item label="特色">
<div class="flex">
<el-input
class="w-1/2"
v-model="$dialog.data.feature1"
placeholder="请输入特色1"
></el-input>
<el-input
class="w-1/2 ml-2"
v-model="$dialog.data.feature2"
placeholder="请输入特色2"
></el-input>
</div>
</el-form-item>
<el-form-item>
<el-popover <el-popover
:visible="visiblePropertyLine" :visible="visiblePropertyLine"
placement="bottom" placement="bottom"