qms项目中的物料数据有很多,若是直接通过select下拉展示,首先是数据太多,会卡住,然后展示的内容也不全,目前物料有三个层级,分别一级物料、二级物料、三级物料,若是多加几个筛选条件,那最后获取到的数据就不是很多,然后就想到重新写个组件展示,
实现效果:
目前有两个框,一个展示选中的物料类别,一个是选中的物料名称,希望通过,点击一级物料列表项,获取到二级物料列表,点击二级物料列表项,获取三级物料列表,点击三级物料列表项,获取到物料清单,点击待选择物料列表项,选中物料列表新增一个物料,可以多选,点击选中的物料列表项,物料列表删除该物料,同时取消该物料的选中状态;若是点击一级物料列表项,则重新获取二级物料列表,同时把三级物料列表、待选择物料列表、已选择物料列表清空;点击二级物料列表时,则重新获取三级物料列表,同时把待选择物料列表、已选择物料列表清空;点击三级物料列表时,则重新获取待选择物料列表,同时把已选择物料列表清空;
20240126_190247
代码如下
materialType.vue
<template>
<div>
<div @click="inputClick()" style="cursor: pointer;">
<!--通过css样式 pointer-events:none; 控制设为disabled的input可以点击 -->
<a-input v-model:value="selectName" disabled style="pointer-events:none;width:100%;" placeholder="请选择" ref="searchInput" autocomplete="off">%
</a-input>
</div>
<a-modal v-model:visible="visible" @ok="handleOk" @cancel="handleCancel" width="850px" height="400px">
<template #title>
<div style="font-weight: 600; font-size: 16px">物料</div>
</template>
<div class="warp flex_between">
<div class="flex_7">
<div class="line30">未选择</div>
<div class="flex_between">
<div class="borderRight borderBottom table_title table_width150">一级物料</div>
<div class="borderRight borderBottom table_title table_width150">二级物料</div>
<div class="borderRight borderBottom table_title table_width150">三级物料</div>
<div class="borderBottom table_title table_width200">物料名称</div>
</div>
<div class="flex_between">
<div class="borderRight max_height table_width150">
<div v-for="(item,index) in firstData" :key="index" :title="item.label" @click="firstClick(item)" :class="{'list_style':item.value!=firstTier,'list_active':item.value==firstTier}">{{item.label}}</div>
</div>
<div class="borderRight max_height table_width150">
<div v-for="(item,index) in secondData" :key="index" :title="item.label" @click="secondClick(item)" :class="{'list_style':item.value!=secondTier,'list_active':item.value==secondTier}">{{item.label}}</div>
</div>
<div class="borderRight max_height table_width150">
<div v-for="(item,index) in thirdData" :key="index" :title="item.label" @click="thirdClick(item)" :class="{'list_style':item.value!=thirdTier,'list_active':item.value==thirdTier}">{{item.label}}</div>
</div>
<div class="max_height table_width200">
<div v-for="(item,index) in waitData" :key="index" :title="item.label" @click="waitClick(item)" :class="{'list_style':selectedMaterialName.includes(item.value),'list_active':selectedMaterialName.includes(item.value)}">{{item.label}}</div>
</div>
</div>
</div>
<div class="flex_3" >
<div class="line30">选中</div>
<div class="borderBottom table_title">物料名称</div>
<div style="height:calc(100% - 30px);">
<div style="width:100%;height:100%;" class="max_height">
<div v-for="(item,index) in selectedData" :title="item.label" :key="index" @click="selectedClick(item)" class="list_style">{{item.label}}</div>
</div>
</div>
</div>
</div>
</a-modal>
</div>
</template>
<script setup>
import {onMounted, ref,defineEmits,defineProps, onBeforeUnmount, watch, nextTick} from 'vue';
import {defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
import qs from 'qs'
const { createMessage } = useMessage();
const visible = ref(false);
const emits = defineEmits(['check']);
const props = defineProps({
//选中的物料级别
checkLevel: {
type: Object,
default:{},
}, //字段
//选中的物料
checkedMaterial: {
type: Array,
default:[],
}, //字段
});
const selectedMaterialName=ref([]);//选中的物料名称数组,进行选中状态判断
const selectName=ref('');//选中返回值
const levels=[];//接收传过来的物料级别
levels.value=props.checkLevel;
const materials=[];//接收传过来的物料编号
materials.value=props.checkedMaterial;
const firstTier=ref('');//选中的第一列物料code
const firstTierName=ref('');//选中的第一列物料名称
const secondTier=ref('');//选中的第二列物料code
const secondTierName=ref('');//选中的第二列物料名称
const thirdTier=ref('');//选中的第三列物料code
const thirdTierName=ref('');//选中的第三列物料名称
//第一级物料列表
const firstData=ref([]);
//第二级物料列表
const secondData=ref([]);
//第三级物料列表
const thirdData=ref([]);
//待选择物料清单列表
const waitData=ref([]);
//选中的物料清单列表
const selectedData=ref([]);
onMounted(() => {
// console.log(levels.value,'物料级别回显值');
// console.log(materials.value,'选中物料回显值');
//一级物料级别、二级物料级别、三级物料级别同时存在才会回显数据
if(levels.value.firstTier&&levels.value.secondTier&&levels.value.thirdTier){
firstTier.value=levels.value.firstTier;
secondTier.value=levels.value.secondTier;
thirdTier.value=levels.value.thirdTier;
getFirstList();
getOtherList(2,levels.value.firstTier);
getOtherList(3,levels.value.secondTier);
getMaterialList();
}else{
//传过来的数据为空时,则只显示一级物料
getFirstList();
}
});
//获取一级物料列表
async function getFirstList(){
let url = '/materiel/tierLlist/'+1;
await defHttp.get({ url}, { isTransformResponse: false }).then((res) => {
if (res.success) {
firstData.value=res.result;
//对一级物料列表进行遍历,根据传过来的物料编号,查找对应的物料名称
for(let i=0;i<firstData.value.length;i++){
if(firstTier.value==firstData.value[i].value){
firstTierName.value=firstData.value[i].label
}
}
} else {
createMessage.error(res.message);
}
});
}
//获取其他级别的物料列表
async function getOtherList(level,code){
let url = '/materiel/tierLlist/'+level;
let params={
code:code,
}
await defHttp.get({ url,params}, { isTransformResponse: false }).then((res) => {
if (res.success) {
if(level==2){
secondData.value=res.result;
//对二级物料列表进行遍历,根据传过来的物料编号,查找对应的物料名称
for(let i=0;i<secondData.value.length;i++){
if(secondTier.value==secondData.value[i].value){
secondTierName.value=secondData.value[i].label
}
}
}else if(level==3){
thirdData.value=res.result;
//对三级物料列表进行遍历,根据传过来的物料编号,查找对应的物料名称
for(let i=0;i<thirdData.value.length;i++){
if(thirdTier.value==thirdData.value[i].value){
thirdTierName.value=thirdData.value[i].label
}
}
}
//将一级物料名称、二级物料名称、三级物料名称进行组合,如 一级物料名称/二级物料名称/三级物料名称
selectName.value=firstTierName.value+'/'+secondTierName.value+'/'+thirdTierName.value;
} else {
createMessage.error(res.message);
}
});
}
//获取待选中物料
async function getMaterialList(){
let url = '/materiel/tierLlist/';
let params={
firstTier:firstTier.value,
secondTier:secondTier.value,
thirdTier:thirdTier.value,
}
await defHttp.get({ url,params}, { isTransformResponse: false }).then((res) => {
if (res.success) {
waitData.value=res.result;
//若是传过来的物料编号数组存在,与查到的待选择物料列表进行遍历,获取选中的物料列表,
if(materials.value){
for(let i=0;i<waitData.value.length;i++){
for(let j=0;j<materials.value.length;j++){
if(materials.value[j]==waitData.value[i].value){
selectedData.value.push(waitData.value[i])
}
}
}
// 对获取到的选中物料列表进行遍历,获取选中物料编号列表,用于待选则物料的选中状态判断
selectedMaterialName.value=selectedData.value.map(item=>{
return item.value
})
let levels={
firstTier:{value:firstTier.value,label:firstTierName.value},
secondTier:{value:secondTier.value,label:secondTierName.value},
thirdTier:{value:thirdTier.value,label:thirdTierName.value},
}
console.log(selectedData.value,'selectedData')
emits('check', selectedData.value,levels); //把选中的物料列表、选中的物料级别传过去
}
} else {
createMessage.error(res.message);
}
});
}
//一级物料点击事件
function firstClick(val){
//一级物料级别存在时,点击一级物料列表项,把二级物料列表、三级物料列表、待选择物料列表、已选择物料列表清空
if(firstTier.value!=val.value){
secondData.value=[];
thirdData.value=[];
waitData.value=[];
selectedData.value=[];
firstTier.value=val.value;//获取此时点击的一级物料名称、一级物料编号
firstTierName.value=val.label;
getOtherList(2,val.value);//重新获取此时点击的一级物料编号对应的二级物料列表
}
}
//二级物料点击事件
function secondClick(val){
//二级物料级别存在时,点击二级物料列表项,把三级物料列表、待选择物料列表、已选择物料列表清空
if(secondTier.value!=val.value){
thirdData.value=[];
waitData.value=[];
selectedData.value=[];
secondTier.value=val.value;//获取此时点击的二级物料名称、二级物料编号
secondTierName.value=val.label;
getOtherList(3,val.value)//重新获取此时点击的二级物料编号对应的三级物料列表
}
}
//三级物料点击事件
function thirdClick(val){
//三级物料级别存在时,点击三级物料列表项,把待选择物料列表、已选择物料列表清空
if(thirdTier.value!=val.value){
selectedData.value=[];
thirdTier.value=val.value;//获取此时点击的三级物料名称、三级物料编号
thirdTierName.value=val.label;
getMaterialList();//重新获取此时点击的一级二级三级物料编号对应的物料清单列表
}
}
//物料点击
function waitClick(val){
//对此时点击的待选择物料列表项进行判断,若是不存在已选中物料列表里面,则添加到已选中物料列表中,同时更新已选中物料编号数组
if(selectedMaterialName.value.includes(val.value)==false){
waitData.value.map(item=>{
if(item.value==val.value){
selectedData.value.push(item);
}
})
selectedMaterialName.value=selectedData.value.map(item=>{
return item.value
})
}else{
//对此时点击的待选择物料列表项进行判断,若是存在已选中物料列表里面,则遍历查到点击的物料编号在已选中物料列表中的索引,进行删除,同时更新已选中物料编号数组
selectedData.value.map((item,index)=>{
if(item.value==val.value){
selectedData.value.splice(index,1);
}
})
selectedMaterialName.value=selectedData.value.map(item=>{
return item.value
})
}
}
//已选中物料点击
function selectedClick(val){
//点击已选中物料列表项,遍历查到点击的物料编号在已选中物料列表中的索引,进行删除,同时更新已选中物料编号数组
selectedData.value.map((item,i)=>{
if(item.value==val.value){
selectedData.value.splice(i,1)
}
})
selectedMaterialName.value=selectedData.value.map(item=>{
return item.value
})
}
//点击显示弹窗
function inputClick(){
visible.value=true;
}
const handleCancel = (e) => {
visible.value = false;
}
const handleOk = (e) => {
// 点击确定时,把此时选中的物料列表、一级、二级、三级物料传过去
if(selectedData.value.length>0){
visible.value = false;
selectName.value=firstTierName.value+'/'+secondTierName.value+'/'+thirdTierName.value;//返回物料类别
let levels={
firstTier:{value:firstTier.value,label:firstTierName.value},
secondTier:{value:secondTier.value,label:secondTierName.value},
thirdTier:{value:thirdTier.value,label:thirdTierName.value},
}
emits('check', selectedData.value,levels); //把列表选中的值传过去
}else{
createMessage.warning('至少选中一个物料~');
}
};
</script>
<style lang="less" scoped>
.flex_between{
display:flex;
justify-content:center;
text-align: center;
}
.warp{
margin:10px;
border:1px solid #ddd;
height:auto;
border-top:none;
border-left:none;
box-sizing: border-box;
.flex_7{
// flex:7;
width:650px;
border:1px solid #ddd;
height:100%;
border-bottom:none;
}
.line30{
border-bottom:1px solid #ddd;
height:30px;
line-height:30px;
}
.borderRight{
border-right:1px solid #ddd;
width:100%;
}
.table_title{
font-size: 16px;
color: #333;
}
.borderBottom{
width:100%;
border-bottom:1px solid #ddd;
}
.max_height{
max-height: 500px;
overflow-y: scroll;
}
.table_width200{
width:200px;
}
.table_width150{
width:150px;
}
.flex_3{
// flex:3;
width:200px;
border-top:1px solid #ddd;
height:100%;
}
}
.list_style{
cursor: pointer;
}
.list_active{
color: rgb(24, 144, 255);
}
.list_style:hover{
color: #409eff;
}
</style>
引用组件
<template>
<a-card :bordered="false">
<a-tabs defaultActiveKey="4">
<a-tab-pane tab="物料名称组件" key="4">
<a-form :label-col="{style:{width:'150px'} }">
<a-row :gutter="24">
<a-col :span="8">
<a-form-item label="供货工艺类别:">
<material-type :checkedMaterial='selectedMaterial' :checkLevel='levels' @check='getMaterialLevel'></material-type>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="供货产品名称:">
<a-input v-model:value="selectedMaterialNames" disabled></a-input>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-tab-pane>
</a-tabs>
</a-card>
</template>
<script setup>
import {onMounted, ref,defineEmits,defineProps, onBeforeUnmount, watch, nextTick} from 'vue';
import materialType from '/@/components/materialType.vue';
onMounted(()=>{
getMaterialLevel();
})
//物料选择调用
const levels=ref(
{
firstTier:'A',
secondTier:'A.2',
thirdTier:'A.2.1',
}
)
const selectedMaterial=ref(
[
'02.10.MSP120H-11-01',
'02.10.MSP120H-30-01',
]
)
const selectedMaterialNames=ref('');//选中的产品名称
const checkedMaterial=ref([]);//回显的数据
let materielData=[];
function getMaterialLevel(materials,levels){
if(materials){
materielData=materials.map(item=>{
return item.label
});
selectedMaterialNames.value=materielData.toString();
}
// console.log(selectedMaterialNames.value,'选中物料名称')
}
//物料选择调用
</script>