feat: EBOM选择物料弹窗增加左侧分类树(issues-0311-3)
- form.vue: 选择物料弹窗从el-select远程搜索改为左右布局 左侧el-tree加载物料分类树(getItemTypeTreeselect) 右侧el-table展示物料列表,支持编码/名称搜索 点击树节点按分类过滤物料,参考Item管理页实现 - form.vue: 表格和输入框去掉size=small,恢复默认高度 - list.vue: 列表列宽从固定width改为min-width,增加show-overflow-tooltip Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -147,7 +147,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-table :data="lines" border size="small" max-height="420">
|
<el-table :data="lines" border max-height="420">
|
||||||
<el-table-column label="序号" type="index" width="60" align="center" />
|
<el-table-column label="序号" type="index" width="60" align="center" />
|
||||||
<el-table-column label="物料编码" min-width="160">
|
<el-table-column label="物料编码" min-width="160">
|
||||||
<template #default="{ row, $index }">
|
<template #default="{ row, $index }">
|
||||||
@@ -162,7 +162,7 @@
|
|||||||
<el-table-column prop="unitName" label="主计量" width="90" align="center" />
|
<el-table-column prop="unitName" label="主计量" width="90" align="center" />
|
||||||
<el-table-column label="计划线路" width="120" align="center">
|
<el-table-column label="计划线路" width="120" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-select v-model="row.supplyType" :disabled="readonly" size="small" style="width: 100%">
|
<el-select v-model="row.supplyType" :disabled="readonly" style="width: 100%">
|
||||||
<el-option label="采购" value="PURCHASE" />
|
<el-option label="采购" value="PURCHASE" />
|
||||||
<el-option label="自制" value="PRODUCE" />
|
<el-option label="自制" value="PRODUCE" />
|
||||||
<el-option label="委外" value="OUTSOURCE" />
|
<el-option label="委外" value="OUTSOURCE" />
|
||||||
@@ -171,7 +171,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="领料方式" width="120" align="center">
|
<el-table-column label="领料方式" width="120" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-select v-model="row.attr1" :disabled="readonly" size="small" style="width: 100%">
|
<el-select v-model="row.attr1" :disabled="readonly" style="width: 100%">
|
||||||
<el-option label="按单领用" value="ORDER" />
|
<el-option label="按单领用" value="ORDER" />
|
||||||
<el-option label="直接领用" value="DIRECT" />
|
<el-option label="直接领用" value="DIRECT" />
|
||||||
</el-select>
|
</el-select>
|
||||||
@@ -179,12 +179,12 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="quantity" label="分子" width="90" align="right">
|
<el-table-column prop="quantity" label="分子" width="90" align="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-input-number v-model="row.quantity" :min="0" :precision="4" :disabled="readonly" size="small" style="width: 100%" />
|
<el-input-number v-model="row.quantity" :min="0" :precision="4" :disabled="readonly" style="width: 100%" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="用量方式" width="120" align="center">
|
<el-table-column label="用量方式" width="120" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-select v-model="row.attr2" :disabled="readonly" size="small" style="width: 100%">
|
<el-select v-model="row.attr2" :disabled="readonly" style="width: 100%">
|
||||||
<el-option label="按比例" value="RATIO" />
|
<el-option label="按比例" value="RATIO" />
|
||||||
<el-option label="固定用量" value="FIXED" />
|
<el-option label="固定用量" value="FIXED" />
|
||||||
<el-option label="变动用量" value="VARIABLE" />
|
<el-option label="变动用量" value="VARIABLE" />
|
||||||
@@ -226,36 +226,80 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 选择子件物料 -->
|
<!-- 选择子件物料 -->
|
||||||
<el-dialog v-model="itemDialogVisible" title="选择物料" width="640px" destroy-on-close>
|
<el-dialog v-model="itemDialogVisible" title="选择物料" width="980px" destroy-on-close>
|
||||||
<el-select
|
<div class="item-dialog-body">
|
||||||
v-model="selectedItemId"
|
<div class="item-tree-panel" v-loading="itemTypeTreeLoading">
|
||||||
filterable
|
<el-input
|
||||||
remote
|
v-model="itemTypeFilterText"
|
||||||
placeholder="输入编码或名称搜索"
|
placeholder="请输入分类名称"
|
||||||
:remote-method="searchItems"
|
clearable
|
||||||
:loading="itemLoading"
|
:prefix-icon="Search"
|
||||||
style="width: 100%"
|
style="margin-bottom: 12px"
|
||||||
>
|
/>
|
||||||
<el-option
|
<el-tree
|
||||||
v-for="it in itemOptions"
|
ref="itemTypeTreeRef"
|
||||||
:key="it.itemId"
|
:data="itemTypeTreeData"
|
||||||
:label="`${it.itemCode} - ${it.itemName}`"
|
:props="{ label: 'label', children: 'children' }"
|
||||||
:value="it.itemId"
|
node-key="id"
|
||||||
/>
|
highlight-current
|
||||||
</el-select>
|
default-expand-all
|
||||||
<template #footer>
|
:expand-on-click-node="false"
|
||||||
<el-button @click="itemDialogVisible = false">取消</el-button>
|
:filter-node-method="filterItemTypeNode"
|
||||||
<el-button type="primary" @click="confirmItem">确定</el-button>
|
@node-click="handleItemTypeNodeClick"
|
||||||
</template>
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="item-table-panel">
|
||||||
|
<div class="item-search-bar">
|
||||||
|
<el-form :inline="true" @submit.prevent="loadSelectableItems">
|
||||||
|
<el-form-item label="物料编码">
|
||||||
|
<el-input v-model="itemSearchCode" placeholder="请输入" clearable style="width: 140px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="物料名称">
|
||||||
|
<el-input v-model="itemSearchName" placeholder="请输入" clearable style="width: 140px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" :loading="itemLoading" @click="loadSelectableItems">搜索</el-button>
|
||||||
|
<el-button @click="resetItemSearch">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<el-button link type="primary" @click="handleQueryAll">查询所有</el-button>
|
||||||
|
</div>
|
||||||
|
<el-table
|
||||||
|
v-loading="itemLoading"
|
||||||
|
:data="itemOptions"
|
||||||
|
border
|
||||||
|
stripe
|
||||||
|
max-height="380"
|
||||||
|
>
|
||||||
|
<el-table-column prop="itemCode" label="物料编码" width="160" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="itemName" label="物料名称" min-width="120" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="specification" label="型号规格" min-width="140" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="unitName" label="主计量" width="80" align="center" />
|
||||||
|
<el-table-column prop="itemOrProduct" label="供应方式" width="90" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ row.itemOrProduct === 'PRODUCT' ? '自制' : '采购' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="70" align="center" fixed="right">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-button link type="primary" @click="selectItem(row)">选择</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div class="item-table-pagination">
|
||||||
|
<span>共 {{ itemOptions.length }} 条</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted, reactive, ref } from 'vue'
|
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { ArrowDown, Plus } from '@element-plus/icons-vue'
|
import { ArrowDown, Plus, Search } from '@element-plus/icons-vue'
|
||||||
import {
|
import {
|
||||||
addBomHeader,
|
addBomHeader,
|
||||||
addBomLine,
|
addBomLine,
|
||||||
@@ -268,6 +312,7 @@ import {
|
|||||||
type BomLine
|
type BomLine
|
||||||
} from '@/api/masterdata/bom'
|
} from '@/api/masterdata/bom'
|
||||||
import { listMdItem, type MdItem } from '@/api/masterdata/item'
|
import { listMdItem, type MdItem } from '@/api/masterdata/item'
|
||||||
|
import { getItemTypeTreeselect } from '@/api/masterdata/itemtype'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -552,44 +597,95 @@ function confirmProduct() {
|
|||||||
const itemDialogVisible = ref(false)
|
const itemDialogVisible = ref(false)
|
||||||
const itemLoading = ref(false)
|
const itemLoading = ref(false)
|
||||||
const itemOptions = ref<MdItem[]>([])
|
const itemOptions = ref<MdItem[]>([])
|
||||||
const selectedItemId = ref<number | undefined>()
|
|
||||||
const editingLineIndex = ref<number>(-1)
|
const editingLineIndex = ref<number>(-1)
|
||||||
|
const itemSearchCode = ref('')
|
||||||
|
const itemSearchName = ref('')
|
||||||
|
const itemTypeTreeLoading = ref(false)
|
||||||
|
const itemTypeTreeData = ref<any[]>([])
|
||||||
|
const selectedItemTypeId = ref<number | undefined>()
|
||||||
|
const itemTypeFilterText = ref('')
|
||||||
|
const itemTypeTreeRef = ref<any>(null)
|
||||||
|
|
||||||
function openItemDialog(idx: number) {
|
function filterItemTypeNode(value: string, data: any) {
|
||||||
editingLineIndex.value = idx
|
if (!value) return true
|
||||||
selectedItemId.value = lines.value[idx]?.bomItemId
|
return data.label?.indexOf(value) !== -1
|
||||||
itemDialogVisible.value = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function searchItems(query: string) {
|
watch(itemTypeFilterText, (val) => {
|
||||||
if (!query) {
|
itemTypeTreeRef.value?.filter(val)
|
||||||
itemOptions.value = []
|
})
|
||||||
return
|
|
||||||
|
async function openItemDialog(idx: number) {
|
||||||
|
editingLineIndex.value = idx
|
||||||
|
itemSearchCode.value = ''
|
||||||
|
itemSearchName.value = ''
|
||||||
|
selectedItemTypeId.value = undefined
|
||||||
|
itemTypeFilterText.value = ''
|
||||||
|
itemDialogVisible.value = true
|
||||||
|
await loadItemTypeTree()
|
||||||
|
await loadSelectableItems()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadItemTypeTree() {
|
||||||
|
itemTypeTreeLoading.value = true
|
||||||
|
try {
|
||||||
|
const res = await getItemTypeTreeselect()
|
||||||
|
itemTypeTreeData.value = res.data || []
|
||||||
|
} finally {
|
||||||
|
itemTypeTreeLoading.value = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadSelectableItems() {
|
||||||
itemLoading.value = true
|
itemLoading.value = true
|
||||||
try {
|
try {
|
||||||
const res = await listMdItem({ itemCode: query, enableFlag: 'Y', pageNum: 1, pageSize: 50 })
|
const params: Record<string, any> = {
|
||||||
|
enableFlag: 'Y',
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 100
|
||||||
|
}
|
||||||
|
if (selectedItemTypeId.value) params.itemTypeId = selectedItemTypeId.value
|
||||||
|
if (itemSearchCode.value.trim()) params.itemCode = itemSearchCode.value.trim()
|
||||||
|
if (itemSearchName.value.trim()) params.itemName = itemSearchName.value.trim()
|
||||||
|
const res = await listMdItem(params)
|
||||||
itemOptions.value = res.rows.filter(it => it.itemId !== form.itemId)
|
itemOptions.value = res.rows.filter(it => it.itemId !== form.itemId)
|
||||||
} finally {
|
} finally {
|
||||||
itemLoading.value = false
|
itemLoading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function confirmItem() {
|
function resetItemSearch() {
|
||||||
|
itemSearchCode.value = ''
|
||||||
|
itemSearchName.value = ''
|
||||||
|
selectedItemTypeId.value = undefined
|
||||||
|
itemTypeTreeRef.value?.setCurrentKey(null)
|
||||||
|
loadSelectableItems()
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleQueryAll() {
|
||||||
|
itemSearchCode.value = ''
|
||||||
|
itemSearchName.value = ''
|
||||||
|
selectedItemTypeId.value = undefined
|
||||||
|
itemTypeTreeRef.value?.setCurrentKey(null)
|
||||||
|
loadSelectableItems()
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleItemTypeNodeClick(node: any) {
|
||||||
|
selectedItemTypeId.value = node?.id ?? node?.itemTypeId
|
||||||
|
loadSelectableItems()
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectItem(selected: MdItem) {
|
||||||
const idx = editingLineIndex.value
|
const idx = editingLineIndex.value
|
||||||
const selected = itemOptions.value.find(i => i.itemId === selectedItemId.value)
|
if (idx < 0) return
|
||||||
if (idx < 0 || !selected) {
|
|
||||||
itemDialogVisible.value = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const row = lines.value[idx]
|
const row = lines.value[idx]
|
||||||
row.bomItemId = selected.itemId
|
row.bomItemId = selected.itemId
|
||||||
row.bomItemCode = selected.itemCode
|
row.bomItemCode = selected.itemCode
|
||||||
row.bomItemName = selected.itemName
|
row.bomItemName = selected.itemName
|
||||||
row.bomItemSpec = selected.specification
|
row.bomItemSpec = selected.specification
|
||||||
row.unitOfMeasure = selected.unitOfMeasure || '' // 必填
|
row.unitOfMeasure = selected.unitOfMeasure || ''
|
||||||
row.unitName = selected.unitName || ''
|
row.unitName = selected.unitName || ''
|
||||||
row.itemOrProduct = selected.itemOrProduct || 'ITEM' // 必填
|
row.itemOrProduct = selected.itemOrProduct || 'ITEM'
|
||||||
itemDialogVisible.value = false
|
itemDialogVisible.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -652,5 +748,57 @@ onMounted(load)
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-dialog-body {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
min-height: 460px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-tree-panel {
|
||||||
|
width: 220px;
|
||||||
|
min-width: 220px;
|
||||||
|
border: 1px solid #ebeef5;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 8px;
|
||||||
|
overflow: auto;
|
||||||
|
max-height: 460px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-table-panel {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-search-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 4px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-search-bar :deep(.el-form-item) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-table-pagination {
|
||||||
|
margin-top: 8px;
|
||||||
|
text-align: right;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lines-card :deep(.el-table__body .el-table__cell) {
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lines-card :deep(.el-input__wrapper),
|
||||||
|
.lines-card :deep(.el-input-number .el-input__wrapper),
|
||||||
|
.lines-card :deep(.el-select .el-input__wrapper) {
|
||||||
|
min-height: 36px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -86,10 +86,11 @@
|
|||||||
:data="bomList"
|
:data="bomList"
|
||||||
border
|
border
|
||||||
stripe
|
stripe
|
||||||
|
style="width: 100%"
|
||||||
@row-dblclick="goView"
|
@row-dblclick="goView"
|
||||||
>
|
>
|
||||||
<el-table-column label="序号" type="index" width="60" align="center" />
|
<el-table-column label="序号" type="index" width="60" align="center" />
|
||||||
<el-table-column prop="bomCode" label="单据编码" width="140">
|
<el-table-column prop="bomCode" label="单据编码" min-width="200" show-overflow-tooltip>
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-link type="primary" @click="goView(row)">{{ row.bomCode }}</el-link>
|
<el-link type="primary" @click="goView(row)">{{ row.bomCode }}</el-link>
|
||||||
</template>
|
</template>
|
||||||
@@ -102,9 +103,9 @@
|
|||||||
<el-table-column prop="version" label="版本号" width="90" align="center">
|
<el-table-column prop="version" label="版本号" width="90" align="center">
|
||||||
<template #default="{ row }">{{ row.version || '1.00' }}</template>
|
<template #default="{ row }">{{ row.version || '1.00' }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="versionDesc" label="版本说明" width="120" show-overflow-tooltip />
|
<el-table-column prop="versionDesc" label="版本说明" min-width="120" show-overflow-tooltip />
|
||||||
<el-table-column prop="drawingNo" label="图纸号" width="150" show-overflow-tooltip />
|
<el-table-column prop="drawingNo" label="图纸号" min-width="150" show-overflow-tooltip />
|
||||||
<el-table-column prop="status" label="单据状态" width="100" align="center">
|
<el-table-column prop="status" label="单据状态" width="100" align="center" show-overflow-tooltip>
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<span :class="getStatusClass(row.status)">{{ getStatusLabel(row.status) }}</span>
|
<span :class="getStatusClass(row.status)">{{ getStatusLabel(row.status) }}</span>
|
||||||
</template>
|
</template>
|
||||||
@@ -127,22 +128,23 @@
|
|||||||
:data="bomList"
|
:data="bomList"
|
||||||
border
|
border
|
||||||
stripe
|
stripe
|
||||||
|
style="width: 100%"
|
||||||
@selection-change="handleSelectionChange"
|
@selection-change="handleSelectionChange"
|
||||||
>
|
>
|
||||||
<el-table-column type="selection" width="50" align="center" />
|
<el-table-column type="selection" width="50" align="center" />
|
||||||
<el-table-column prop="bomCode" label="单据编码" width="140" align="center" />
|
<el-table-column prop="bomCode" label="单据编码" min-width="200" align="center" show-overflow-tooltip />
|
||||||
<el-table-column prop="createTime" label="单据日期" width="110" align="center">
|
<el-table-column prop="createTime" label="单据日期" width="110" align="center">
|
||||||
<template #default="{ row }">{{ formatDate(row.createTime) }}</template>
|
<template #default="{ row }">{{ formatDate(row.createTime) }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="status" label="单据状态" width="100" align="center">
|
<el-table-column prop="status" label="单据状态" width="100" align="center" show-overflow-tooltip>
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<span :class="getStatusClass(row.status)">{{ getStatusLabel(row.status) }}</span>
|
<span :class="getStatusClass(row.status)">{{ getStatusLabel(row.status) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="businessType" label="业务类型" width="120" align="center" />
|
<el-table-column prop="businessType" label="业务类型" min-width="120" align="center" />
|
||||||
<el-table-column prop="businessDept" label="业务部门" width="120" align="center" />
|
<el-table-column prop="businessDept" label="业务部门" min-width="120" align="center" />
|
||||||
<el-table-column prop="businessUser" label="业务人员" width="120" align="center" />
|
<el-table-column prop="businessUser" label="业务人员" min-width="120" align="center" />
|
||||||
<el-table-column prop="businessStatus" label="业务状态" width="120" align="center" />
|
<el-table-column prop="businessStatus" label="业务状态" min-width="120" align="center" />
|
||||||
<el-table-column prop="approveTime" label="审核日期" width="110" align="center" />
|
<el-table-column prop="approveTime" label="审核日期" width="110" align="center" />
|
||||||
<el-table-column label="操作" width="140" align="center" fixed="right">
|
<el-table-column label="操作" width="140" align="center" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
|
|||||||
Reference in New Issue
Block a user