feat(mes): 新增物料产品选择器 V2 组件

pull/871/MERGE
YunaiV 2026-04-05 12:28:29 +08:00
parent 9f9ac51edf
commit 1f9380ba90
2 changed files with 97 additions and 78 deletions

View File

@ -1,78 +0,0 @@
<template>
<div class="head-container">
<el-input v-model="filterName" class="mb-20px" clearable placeholder="请输入分类名称">
<template #prefix>
<Icon icon="ep:search" />
</template>
</el-input>
</div>
<div class="head-container">
<el-tree
ref="treeRef"
:data="itemTypeList"
:expand-on-click-node="false"
:filter-node-method="filterNode"
:props="defaultProps"
default-expand-all
highlight-current
node-key="id"
@node-click="handleNodeClick"
/>
</div>
</template>
<script lang="ts" setup>
import { ElTree } from 'element-plus'
import { MdItemTypeApi } from '@/api/mes/md/item/type'
import { defaultProps, handleTree } from '@/utils/tree'
defineOptions({ name: 'MesItemTypeTree' })
const filterName = ref('')
const itemTypeList = ref<Tree[]>([])
const treeRef = ref<InstanceType<typeof ElTree>>()
/** 获得分类树 */
const getTree = async () => {
const res = await MdItemTypeApi.getItemTypeSimpleList()
itemTypeList.value = []
itemTypeList.value.push(...handleTree(res))
}
/** 基于名字过滤 */
const filterNode = (name: string, data: Tree) => {
if (!name) {
return true
}
return data.name.includes(name)
}
/** 处理分类被点击 */
let currentNode: any = {}
const handleNodeClick = async (row: { [key: string]: any }, treeNode: any) => {
if (currentNode && currentNode.name === row.name) {
treeNode.checked = !treeNode.checked
} else {
treeNode.checked = true
}
if (treeNode.checked) {
currentNode = row
emits('node-click', row)
} else {
treeRef.value!.setCurrentKey(undefined)
emits('node-click', undefined)
currentNode = null
}
}
const emits = defineEmits(['node-click'])
/** 监听过滤名称 */
watch(filterName, (val) => {
treeRef.value!.filter(val)
})
/** 初始化 */
onMounted(async () => {
await getTree()
})
</script>

View File

@ -0,0 +1,97 @@
<!--
MES 物料分类树面板
功能加载物料分类树 + 关键字过滤 + 点击节点通知父组件
用法<MdItemTypeTree @node-click="handleTypeClick" />
说明
- 组件 mount 后自动加载数据也可通过 ref 调用 loadTree() 手动刷新
- 支持 toggle点击已选中节点会取消选中emit undefined
Events:
nodeClick(data: MdItemTypeVO | undefined) 点击树节点时触发取消选中时为 undefined
Expose:
loadTree() 手动刷新分类树
clearCurrent() 清除当前选中节点高亮
-->
<template>
<el-input
v-model="filterText"
placeholder="搜索分类"
clearable
class="mb-12px"
:prefix-icon="iconSearch"
/>
<el-tree
ref="treeRef"
:data="treeData"
:props="treeProps"
:expand-on-click-node="false"
:filter-node-method="filterNode"
default-expand-all
highlight-current
node-key="id"
@node-click="handleNodeClick"
/>
</template>
<script setup lang="ts">
import { MdItemTypeApi, MdItemTypeVO } from '@/api/mes/md/item/type'
import { handleTree } from '@/utils/tree'
import { Search as iconSearch } from '@element-plus/icons-vue'
defineOptions({ name: 'MdItemTypeTree' })
const emit = defineEmits<{
nodeClick: [data: MdItemTypeVO | undefined]
}>()
const treeRef = ref() // Ref
const filterText = ref('') //
const treeData = ref<MdItemTypeVO[]>([]) //
const treeProps = { children: 'children', label: 'name' } //
let currentNodeId: number | undefined // ID toggle
/** 过滤树节点(按名称匹配) */
const filterNode = (value: string, data: MdItemTypeVO) => {
if (!value) {
return true
}
return data.name?.includes(value)
}
/** 监听搜索关键字变化,触发树过滤 */
watch(filterText, (val) => {
treeRef.value?.filter(val)
})
/** 点击树节点:支持 toggle再次点击同一节点取消选中 */
const handleNodeClick = (data: MdItemTypeVO) => {
if (currentNodeId === data.id) {
//
treeRef.value?.setCurrentKey(undefined)
currentNodeId = undefined
emit('nodeClick', undefined)
} else {
//
currentNodeId = data.id
emit('nodeClick', data)
}
}
/** 加载分类树数据 */
const loadTree = async () => {
const list = await MdItemTypeApi.getItemTypeSimpleList()
treeData.value = handleTree(list)
}
onMounted(() => {
loadTree()
})
/** 清除当前选中节点高亮 */
const clearCurrent = () => {
treeRef.value?.setCurrentKey(undefined)
currentNodeId = undefined
}
defineExpose({ loadTree, clearCurrent })
</script>