2025-10-29 17:47:47 +08:00

366 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div id="category-tree" class="p-2 bg-white">
<p>
类目展示
<el-input
v-if="addRootCategory.showInput"
class="w-20 !h-[22px]"
v-model="addRootCategory.inputValue"
ref="addRootCategoryInputRef"
@keyup.enter="onAddRootCategory"
@blur="addRootCategory.showInput = false"
></el-input>
<el-button
v-else
class="w-20 !h-[22px]"
type="primary"
size="small"
@click="onClickAddRootCategory"
>添加根类目</el-button
>
</p>
<el-tree
ref="treeRef"
:props="defaultProps"
node-key="id"
draggable
:render-after-expand="false"
check-strictly
:load="handleLoadNode"
lazy
highlight-current
:expand-on-click-node="false"
@node-click="handleNodeClick"
@node-drag-start="handleDragStart"
@node-drop="handleDropFinish"
>
<template #default="{ node, data }">
<div class="category-tree-node">
<div class="flex-1">
<span v-if="editChildCategoryId !== data.id">{{ data.name }}</span>
<el-input
ref="editChildCategoryInputRef"
v-else
v-model="data.label2"
size="small"
class="w-40"
@keyup.enter="handleEditChildCategoryConfirm(node, data)"
@blur="editChildCategoryId = NaN"
/>
<template v-if="data.isProperty">
<dl class="flex items-center">
<dt class="text-sm text-[#666] mb-2">
属性
<span v-if="editPropertyTypeId !== data.id">{{ data.categoryPropertyName }}</span>
<el-input
ref="editPropertyTypeInputRef"
v-else
v-model="data.label2"
size="small"
class="w-40"
@keyup.enter="handleEditPropertyTypeConfirm(node, data)"
@blur="editPropertyTypeId = NaN"
/>
</dt>
<dd class="flex mb-2 flex-wrap">
<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
v-else
closable
effect="plain"
type="primary"
class="mr-1"
@click="onClickPropertyValue(child)"
@close="onClosePropertyValue(child.id, data)"
>{{ child.categoryPropertyValue }}</el-tag
>
</div>
<el-input
ref="propertyValueInputRef"
class="w-20"
size="small"
v-if="visiblePropertyValue[data.id]"
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
>
<el-button
type="warning"
size="small"
class="!text-[10px] !px-2 !py-1 !pb-0.5"
@click="onEditPropertyType(node, data.id)"
>修改属性</el-button
>
<el-button
type="danger"
size="small"
class="!text-[10px] !px-2 !py-1 !pb-0.5"
@click="onDeleteProperty(node, data.id)"
>删除属性</el-button
>
</dd>
</dl>
</template>
</div>
<div v-if="!data.isProperty">
<template v-if="!data.hasOriginChild">
<el-input
ref="propertyTypeInputRef"
class="w-20"
size="small"
v-if="visiblePropertyType[data.id]"
v-model="inputPropertyTypeValue"
@keyup.enter="onAddPropertyType(node, data)"
@blur="visiblePropertyType[data.id] = false"
></el-input>
<el-button
v-else
type="success"
link
size="small"
@click="onClickPropertyTypeBtn(data)"
>新增属性</el-button
>
</template>
<el-button type="primary" link @click="onEdit(data)" size="small">编辑 </el-button>
<el-input
ref="addChildCategoryInputRef"
class="w-20"
size="small"
v-if="data.id === addChildCategoryId"
v-model="childCategoryInputValue"
@keyup.enter="handleAddChildCategoryConfirm(node, data)"
@blur="addChildCategoryId = NaN"
></el-input>
<el-button v-else type="warning" link @click="onAppend(node, data)" size="small">
添加子类目
</el-button>
<el-button type="danger" size="small" link @click="onDelete(node)"> 删除 </el-button>
</div>
</div>
</template>
</el-tree>
</div>
</template>
<script lang="ts" setup>
import { ElButton, ElMessage } from 'element-plus'
import type { RenderContentContext } from 'element-plus'
import { handleDragStart, handleDropFinish } from './use-drag'
import { handleMessageBox } from '@/utils/page'
import {
treeRef,
onEdit,
onAppend,
handleAddChildCategoryConfirm,
handleEditChildCategoryConfirm,
onDelete,
editChildCategoryId,
addChildCategoryId,
childCategoryInputValue,
editChildCategoryInputRef,
addChildCategoryInputRef,
addRootCategory,
addRootCategoryInputRef,
onClickAddRootCategory,
onAddRootCategory
} from './init-method'
type Node = RenderContentContext['node']
type Data = RenderContentContext['data']
const defaultProps = {
label: 'name',
children: 'children',
disabled: 'disabled',
isLeaf: (data: any) => {
return !data.hasChild
}
}
// 获取类目列表
const handleLoadNode = (node, resolve) => {
console.warn('----- my data is 222: ', 222)
if (node.data.vvCategoryPropertyDTOList?.length) {
resolve(
node.data.vvCategoryPropertyDTOList.map((item: any) => ({
...item,
hasChild: 0,
isProperty: 1
}))
)
} else {
api.commodity.getCategoryList.post!<any>({ parentId: node.data.id || 0 }).then((res) => {
resolve(
res.data.map((item: any) => ({
...item,
vvCategoryPropertyDTOList: item.vvCategoryPropertyDTOList || [],
hasOriginChild: item.hasChild,
hasChild: item.hasChild || !!item.vvCategoryPropertyDTOList?.length,
children: item.hasChild ? [] : undefined
}))
)
})
}
}
const visiblePropertyValue = ref<Record<number, boolean>>({})
const inputPropertyValue = ref('')
const visiblePropertyType = ref<Record<number, boolean>>({})
const inputPropertyTypeValue = ref('')
// 删除类目的属性值
const onClosePropertyValue = async (id: number, data: any) => {
const i = data.vvPropertyValueList.findIndex((item: any) => item.id === id)
await api.commodity.deleteCategoryPropertyValue.post!({ id })
data.vvPropertyValueList.splice(i, 1)
ElMessage.success('删除成功')
}
// 新增属性值回车确认
const onAddPropertyValue = async (data: any = {}) => {
if (inputPropertyValue.value) {
const res = await api.commodity.updateCategoryPropertyValue.post!({
categoryPropertyId: data.id,
categoryPropertyValue: inputPropertyValue.value
})
data.vvPropertyValueList.push(res.data)
}
visiblePropertyValue.value[data.id] = false
inputPropertyValue.value = ''
ElMessage.success('新增成功')
}
// 新增属性类型回车确定
const onAddPropertyType = async (node: Node, data: Data) => {
if (inputPropertyTypeValue.value) {
const res = await api.commodity.updateCategoryProperty.post!<{
id: number
categoryPropertyName: string
}>({
categoryId: data.id,
categoryName: data.name,
categoryPropertyName: inputPropertyTypeValue.value
})
const newData = {
...res.data,
hasChild: 0,
isProperty: 1,
vvPropertyValueList: []
}
data.vvCategoryPropertyDTOList.push(newData)
node.loaded = false
node.expand()
visiblePropertyType.value[data.id] = false
inputPropertyTypeValue.value = ''
ElMessage.success('新增成功')
}
}
// 删除属性
const onDeleteProperty = async (node: Node, id: number) => {
handleMessageBox({
msg: `是否删除属性?`,
success: api.commodity.deleteCategoryProperty.post!,
data: { id }
}).then(() => {
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 = ''
}
// 编辑属性类型相关
const editPropertyTypeId = ref(NaN)
const editPropertyTypeInputRef = ref()
const onEditPropertyType = (node: Node, id: number) => {
editPropertyTypeId.value = id
nextTick(() => {
editPropertyTypeInputRef.value.input!.focus()
})
}
// 编辑属性类型回车确认
const handleEditPropertyTypeConfirm = async (node: Node, data: any) => {
await api.commodity.updateCategoryProperty.post!({ ...data, categoryPropertyName: data.label2 })
ElMessage.success('编辑成功')
data.categoryPropertyName = data.label2
editPropertyTypeId.value = NaN
}
</script>
<style lang="scss" scoped>
#category-tree {
.category-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
}
:deep(.el-tree) {
.el-tree-node__content {
height: auto;
}
}
}
</style>