记录一下自己开发的小插件
1、加载进度条,倒计时90秒(带遮罩)
<div class="loading-overlay" v-if="loadingVisible">
<el-progress type="circle" :percentage="loadingPercentage" :stroke-width="20" ></el-progress>
<p class="tips_css">升级中,请稍后!</p>
</div>
//data
loadingPercentage: 0,//进度百分比
timer: null,//定时器
loadingVisible: false,//开启遮罩
//methods
startLoading() {
this.loadingVisible = true;
this.loadingPercentage = 0;
this.timer = setInterval(() => {
if (this.loadingPercentage < 100) {
this.loadingPercentage += 1;
} else {
clearInterval(this.timer); // 停止计时器
// 延时 1 秒后执行关闭遮罩或其他操作
setTimeout(() => {
this.loadingVisible = false;
// 关闭遮罩或执行其他操作
}, 1000);
}
}, 900); // 每 900 毫秒(0.9秒)增加 1% 进度
},
//css
.loading-overlay {
flex-direction: column;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}
::v-deep .el-progress__text{
font-size: 24px !important;
color: rgb(30, 160, 225) !important;
}
::v-deep .el-progress-circle{
width: 150px !important;
height: 150px !important;
}
.tips_css{
font-size: 24px;
color: rgb(30, 160, 225)
}
2.带查询搜索功能的穿梭框,组件代码如下
<template>
<div class="compent-dialog-body">
<div style="padding:20px;">
<el-row :gutter="8">
<el-col :span="8">
<p class="kw_div_p">列表仓库</p>
</el-col>
<el-col :span="16">
<p class="kw_div_p">库位管理</p>
</el-col>
</el-row>
<el-row :gutter="24" style="height:100%">
<el-col :span="8">
<div class="kw_div">
<ul class="kw_ul">
<li v-for="(i,index) in warehouseList" :key="index" class="kw_li" @click="liClick(i,index)" :class="isActive == index?'active_color':''">
{{i.name}}
</li>
</ul>
</div>
</el-col>
<el-col :span="16">
<div class="kw_div">
<el-row :gutter="8">
<el-col :span="10">
<div class="trans_box">
<div class="trans_box_top">
<span class="trans_box_top_title">
<el-checkbox v-model="qbkwQx" @change="qbkwQxF" style="margin-right:10px;"></el-checkbox>全部库位
</span>
<span class="trans_box_top_tips">{{selectAllKwList.length}}/{{allKwLength}}</span>
</div>
<div class="trans_box_main">
<div class="trans_search">
<el-input placeholder="请输入库位查询" prefix-icon="el-icon-search" v-model="allSearchV" class="trans_search_input" @input='inputAll'> </el-input>
</div>
<div class="trans_list">
<template v-for="(i,index) in allKwList">
<label class="trans_list_label" :key="index">
<el-checkbox v-model="i.isCheck" class="trans_list_checkbox" @change='chooseAll(i)'><span class="trans_list_value">{{i.label}}</span></el-checkbox>
</label>
</template>
</div>
</div>
</div>
</el-col>
<el-col :span="2">
<div class="trans_mid">
<el-button icon="el-icon-arrow-left" type="primary" circle class="trans_mid_btn" :disabled='leftDis' @click="goLeft()"></el-button>
<el-button icon="el-icon-arrow-right" type="primary" circle class="trans_mid_btn" :disabled='rightDis' @click="goRight()"></el-button>
</div>
</el-col>
<el-col :span="10">
<div class="trans_box">
<div class="trans_box_top">
<span class="trans_box_top_title">
<el-checkbox v-model="dqkwQx" @change="dqkwQxF" style="margin-right:10px;"></el-checkbox>当前库位
</span>
<span class="trans_box_top_tips">{{selectNowKwList.length}}/{{nowKwLength}}</span>
</div>
<div class="trans_box_main">
<div class="trans_search">
<el-input placeholder="请输入库位查询" prefix-icon="el-icon-search" v-model="nowSearchV" class="trans_search_input" @input='inputNow'> </el-input>
</div>
<div class="trans_list">
<template v-for="(i,index) in nowKwList">
<label class="trans_list_label" :key="index">
<el-checkbox v-model="i.isCheck" class="trans_list_checkbox" @change='chooseNow(i)'><span class="trans_list_value">{{i.label}}</span></el-checkbox>
</label>
</template>
</div>
</div>
</div>
</el-col>
</el-row>
</div>
</el-col>
</el-row>
</div>
<div class="el-dialog__footer">
<el-button size="mini" @click="close">取消</el-button>
<el-button size="mini" type="primary" @click="submit">确认</el-button>
</div>
</div>
</template>
<script>
import * as wmsGoodsPosMsts from '@/api/wmsGoodsPosMsts'//请求api
import * as wmsGoodsAreaPosTbls from '@/api/wmsGoodsAreaPosTbls'//请求api
import waves from '@/directive/waves' // 水波纹指令
export default {
name: 'storageLocation',
components: {
// Pagination
},
directives: {
waves
},
props: ['shooseData',],
data() {
return {
allSearchV:'',//全部库位搜索
nowSearchV:'',//当前库位搜索
checkAllList:[],//多选选中
allKwList:[],//全部库位列表
selectAllKwList:[],//选择全部库位数据
nowKwList:[],//当前库位列表
selectNowKwList:[],//当前库位数据
leftDis:true,//左按钮状态
rightDis:true,//右按钮状态
beginAllKwList:[],//纪录初始库位
beginNowKwList:[],//纪录初始库位
qbkwQx:false,//全部库位全选
dqkwQx:false,//当前库位全选
multipleSelection: [], // 列表checkbox选中的值
currentRoleId: this.roleId,
tableKey: 0,
list: null,
total: 0,
listLoading: true,
listQuery: { // 查询条件
page: 1,
limit: 20,
key: '',
stockCode:'',
goodsAreaCode: ''
},
goodsareaDatas:[],
goodsareaDatasBase:[],
isActive:0,
warehouseList: [],//仓库列表
allKwLength:0,
nowKwLength:0,
}
},
created() {
this.listQuery.stockCode = this.shooseData.stockCode
this.listQuery.goodsAreaCode = this.shooseData.goodsAreaCode
this.getWarehouseList();//获取仓库列表
this.getUserLocation();//获取用户库位
},
mounted() {
},
methods: {
//全部库位全选
qbkwQxF(val){
if(val){
for (let i = 0; i < this.allKwList.length; i++) {
this.allKwList[i].isCheck = true
}
this.selectAllKwList = this.allKwList
}else{
for (let i = 0; i < this.allKwList.length; i++) {
this.allKwList[i].isCheck = false
}
this.selectAllKwList = []
}
},
// 当前库位全选
dqkwQxF(val){
if(val){
for (let i = 0; i < this.nowKwList.length; i++) {
this.nowKwList[i].isCheck = true
}
this.selectNowKwList = this.nowKwList
}else{
for (let i = 0; i < this.nowKwList.length; i++) {
this.nowKwList[i].isCheck = false
}
this.selectNowKwList = []
}
},
//全部库位列表搜索
inputAll(value){
this.allKwList = this.beginAllKwList
var t = []
if(value != '' && value != null && value != undefined ){
var reg = new RegExp(value)
for (let i = 0; i < this.allKwList.length; i++) {
if(reg.test(this.allKwList[i].name)){
t.push(this.allKwList[i])
}
}
this.allKwList = t
}
//全部库位删除选择数据
this.allKwList = this.allKwList.filter(item => !this.nowKwList.some(ele=>ele.goodsPosCode===item.goodsPosCode));
this.selectAllKwList = []//清空选择
this.allKwList.forEach(i=>{i.isCheck = false})//清空选择状态
this.qbkwQx = false//重置全选
this.allKwLength = this.allKwList.length//重新统计数量
},
//当前库位列表搜索
inputNow(value){
this.nowKwList = this.beginNowKwList
var t = []
if(value != '' && value != null && value != undefined ){
var reg = new RegExp(value)
for (let i = 0; i < this.nowKwList.length; i++) {
if(reg.test(this.nowKwList[i].name)){
t.push(this.nowKwList[i])
}
}
this.nowKwList = t
}
//当前库位删除选择数据
this.nowKwList = this.nowKwList.filter(item => !this.allKwList.some(ele=>ele.goodsPosCode===item.goodsPosCode));
this.selectNowKwList = []//清空选择
this.nowKwList.forEach(i=>{i.isCheck = false})//清空选择状态
this.dqkwQx = false//重置全选
this.nowKwLength = this.nowKwList.length//重新统计数量
},
//全部库位列表选择
chooseAll(row){
this.selectAllKwList = []
// 改变选择状态
for (let i = 0; i < this.allKwList.length; i++) {
if(this.allKwList[i].goodsPosCode == row.goodsPosCode){
this.allKwList[i].isCheck = row.isCheck
}
}
// 选中数据赋值
for (let i = 0; i < this.allKwList.length; i++) {
if(this.allKwList[i].isCheck){
this.selectAllKwList.push(this.allKwList[i])
}
}
var s= 0
// 改变全选状态
for (let i = 0; i < this.allKwList.length; i++) {
if(!this.allKwList[i].isCheck){
this.qbkwQx = false
}else{
s +=1
}
}
if(s == this.allKwList.length){
this.qbkwQx = true
}
},
//当前库位列表选择
chooseNow(row){
this.selectNowKwList = []
// 改变选择状态
for (let i = 0; i < this.nowKwList.length; i++) {
if(this.nowKwList[i].goodsPosCode == row.goodsPosCode){
this.nowKwList[i].isCheck = row.isCheck
}
}
// 选中数据赋值
for (let i = 0; i < this.nowKwList.length; i++) {
if(this.nowKwList[i].isCheck){
this.selectNowKwList.push(this.nowKwList[i])
}
}
var s= 0
// 改变全选状态
for (let i = 0; i < this.nowKwList.length; i++) {
if(!this.nowKwList[i].isCheck){
this.dqkwQx = false
}else{
s +=1
}
}
if(s == this.nowKwList.length){
this.dqkwQx = true
}
},
//当前库位删除- 向全部库位添加
goLeft(){
//重置选择
for (let i = 0; i < this.selectNowKwList.length; i++) {
this.selectNowKwList[i].isCheck = false
}
this.nowKwList.forEach(item =>{
item.isCheck = false
})
//全部库位添加数据
this.allKwList = this.allKwList.concat(this.selectNowKwList)
this.beginAllKwList = this.allKwList
//当前库位删除选择数据
this.nowKwList = this.nowKwList.filter(item => !this.allKwList.some(ele=>ele.goodsPosCode===item.goodsPosCode));
this.selectNowKwList=[]
this.dqkwQx = false
this.allKwLength = this.allKwList.length
this.nowKwLength = this.nowKwList.length
},
//全部库位删除- 向当前库位添加
goRight(){
//重置选择
for (let i = 0; i < this.selectAllKwList.length; i++) {
this.selectAllKwList[i].isCheck = false
}
this.allKwList.forEach(item =>{
item.isCheck = false
})
//赋值
this.nowKwList = this.nowKwList.concat(this.selectAllKwList)
this.beginNowKwList = this.nowKwList
//全部库位删除选择数据
this.allKwList = this.allKwList.filter(item => !this.nowKwList.some(ele=>ele.goodsPosCode===item.goodsPosCode));
this.selectAllKwList =[]
this.qbkwQx = false
this.allKwLength = this.allKwList.length
this.nowKwLength = this.nowKwList.length
},
//获取仓库列表
getWarehouseList(){
this.warehouseList = JSON.parse(JSON.stringify(this.$store.state.stockDatas))
var t = {
name:'全部仓库',
stockCode:'allStockCode'
}
this.warehouseList.unshift(t)
},
//获取用户库位
getUserLocation(){
var tdata={
goodsAreaCode:this.listQuery.goodsAreaCode,
// key:this.listQuery.key
}
this.$store.commit("updataListLoading",true)
// 请求自己的数据
wmsGoodsAreaPosTbls.searchPosByArea(tdata).then((res) => {
var tdata = res.result
for (let i = 0; i < tdata.length; i++) {
for (let j = 0; j < this.warehouseList.length; j++) {
if(tdata[i].stockCode){
if(this.warehouseList[j].stockCode == tdata[i].stockCode){
tdata[i].label = tdata[i].name + ' - ' + this.warehouseList[j].name;
}
}else{
tdata[i].label = tdata[i].name
}
}
}
this.nowKwList = tdata
this.beginNowKwList = tdata
this.getAllKwList();
this.nowKwLength = this.nowKwList.length
this.$store.commit("updataListLoading",false)
}).catch(() => {
this.$store.commit("updataListLoading",false)
})
},
//获取所有库位
getAllKwList(){
// 请求自己的数据
wmsGoodsPosMsts.searchAllPos().then((res) => {
// 数据处理
var tdata = res.result
for (let i = 0; i < tdata.length; i++) {
tdata[i].isCheck = false
for (let j = 0; j < this.warehouseList.length; j++) {
if(this.warehouseList[j].stockCode == tdata[i].stockCode){
tdata[i].label = tdata[i].name + ' - ' + this.warehouseList[j].name;
}
}
}
// 所有库位删除当前库位
this.allKwList = tdata.filter(item => !this.nowKwList.some(ele=>ele.goodsPosCode===item.goodsPosCode));
// 缓存全部库位
this.beginAllKwList = this.allKwList
this.allKwLength = this.allKwList.length
}).catch(() => {
// this.warehouseList = []
})
},
//点击行改变状态,从全部库位中筛选
liClick(row,index){
var tdata={}
if(row.stockCode == 'allStockCode'){
this.getAllKwList()
}else{
tdata={
stockCode:row.stockCode
}
// 请求自己的数据
wmsGoodsPosMsts.LoadForstockCode(tdata).then((res) => {
// 数据处理
var tdata = res.result
for (let i = 0; i < tdata.length; i++) {
tdata[i].isCheck = false
for (let j = 0; j < this.warehouseList.length; j++) {
if(this.warehouseList[j].stockCode == tdata[i].stockCode){
tdata[i].label = tdata[i].name + ' - ' + this.warehouseList[j].name;
}
}
}
// 所有库位删除当前库位
this.allKwList = tdata.filter(item => !this.nowKwList.some(ele=>ele.goodsPosCode===item.goodsPosCode));
// 缓存全部库位
this.beginAllKwList = this.allKwList
this.selectAllKwList = []//切换时清空选择列表
})
}
this.isActive = index
},
close() {
this.$emit('close')
},
submit() {
var subList = this.nowKwList
for (let i = 0; i < subList.length; i++) {
subList[i].goodsAreaCode = this.shooseData.goodsAreaCode
}
if(subList.length <= 0){
subList = [{goodsAreaCode:this.shooseData.goodsAreaCode}]
}
this.$store.commit("updataListLoading",true)
// 请求自己的数据
wmsGoodsAreaPosTbls.saveareapos(subList).then((res) => {
this.$emit('close')
this.$message.success(res.message)
this.$store.commit("updataListLoading",false)
}).catch(() => {
this.$message.error('操作失败,请重试')
this.$store.commit("updataListLoading",false)
})
},
},
watch:{
//当前库位选择数据变换
'selectNowKwList'(val){
if(val.length>0){
this.leftDis = false
}else{
this.leftDis = true
}
},
//全部库位选择数据变换
'selectAllKwList'(val){
if(val.length>0){
this.rightDis = false
}else{
this.rightDis = true
}
},
}
}
</script>
<style lang="scss" scoped>
.trans_box{
width: 100%;
border: 1px solid #ebeef5;
border-radius: 4px;
overflow: hidden;
background: #fff;
display: inline-block;
vertical-align: middle;
max-height: 100%;
box-sizing: border-box;
position: relative;
.trans_box_top{
height: 40px;
line-height: 40px;
background: #f5f7fa;
margin: 0;
padding-left: 15px;
border-bottom: 1px solid #ebeef5;
box-sizing: border-box;
color: #000;
.trans_box_top_title{
font-size: 16px;
color: #303133;
font-weight: 400
}
.trans_box_top_tips{
position: absolute;
right: 15px;
color: #909399;
font-size: 12px;
font-weight: 400;
}
}
.trans_box_main{
.trans_search{
text-align: center;
margin: 15px;
box-sizing: border-box;
display: block;
width: auto;
}
.trans_list{
height: 400px;
overflow: hidden;
overflow-y: scroll;
.trans_list_label{
cursor: pointer;
display: block;
height: 30px;
line-height: 30px;
padding-left: 15px;
// .trans_list_checkbox{
// background-color: #fff;
// border: 1px solid #dcdfe6;
// }
.trans_list_value{
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
box-sizing: border-box;
padding-left: 14px;
line-height: 30px;
color: #606266;
font-weight: 500;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif !important;
}
}
}
.trans_list::-webkit-scrollbar {
display: none; /* Chrome Safari */
}
}
}
.trans_mid{
margin-top: 200px;
.trans_mid_btn{
display: block;
margin: 20px 0;
}
}
.custom-theme .el-transfer-panel__body,.el-transfer-panel__body{
height: 500px !important;
}
.custom-theme .el-transfer-panel__list,.el-transfer-panel__list{
height: 500px;
}
.compent-dialog-body{
min-height: 500px;
/* 库位 */
.kw_div_p{
margin: 0 0 10px 0px;
border-left: 3px solid #409eff;
padding-left: 10px;
}
.kw_ul{
text-decoration: none;
list-style: none;
padding: 0;
margin-top: 0;
.kw_li{
height: 30px;
line-height: 30px;
padding-left: 20px;
cursor: pointer;
}
.active_color{
background: #f5f7fa;
}
}
}
</style>
3.Dialog指定位置打开
项目需求点击图片放大,弹窗适配大小,页面可放大缩小,弹窗唤出位置就需要再点击位置出唤出(避免页面放大时在屏幕外弹出等)
<!-- 图片点击代码 -->
<img :src="XXX" v-for="(j,jdx) in lIst" :key="jdx" @click="showImg($event, j.filePath)" style="cursor: pointer;"/>
<!-- 图片放大查看 -->
<el-dialog :visible.sync="imgDialog" width="30%" :modal-append-to-body="true" :style="dialogStyle" >
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
//查看图片
showImg(event,url){
// 计算Dialog的位置,这里简单地将Dialog定位在点击位置的右侧下方
const rect = event.target.getBoundingClientRect();
this.dialogStyle = {
// this.rowHeight自定义偏移位置
top: `${rect.top - this.rowHeight}px`,
left: `${rect.left -this.rowHeight}px`
};
this.dialogImageUrl = url
this.imgDialog = true
},
4.两种selectTree组件,
1、第一种单击选择,效果如下图
直接上代码,子组件:
<!--
* @description:树形下拉选择
* @author: Long
* @version: 1.0
* @updateDate: 2024-7-8
* @usage:用法
defaultValue: 默认值
treeData: 树形数据
disabled: 是否禁用
defaultProps: 配置选项
@clickSelectTree: 点击树形节点时触发
@clearSelectInput: 清空输入框时触发
<SelectTree v-model="editFormFl.faterClassName" :defaultValue="editFormFl.faterClassCode" :treeData="treeData" :disabled="isEditFl" :defaultProps="defaultProps" @clickSelectTree="handleSelectValueChange" style="width: 100%;"></SelectTree>
-->
<template>
<div style="display: inline-block;">
<el-select class="main-select-tree" ref="selectRef" v-model="value" style="width: 100%" clearable @clear="clearSelectInput" :disabled="disabled">
<el-input style="width: 100%; margin-left: 10px; margin-bottom: 10px" placeholder="输入关键字进行过滤" v-model="filterText" clearable ></el-input>
<el-option v-for="item in formatData(treeData)" :key="item.value" :label="item.label" :value="item.value" style="display: none" />
<el-tree class="my_select_Tree" ref="treeRef" :data="treeData" node-key="id" highlight-current :props="defaultProps" @node-click="handleNodeClick" :current-node-key="value" :expand-on-click-node="true" default-expand-all :filter-node-method="filterNode" />
</el-select>
</div>
</template>
<script>
export default {
name: "SelectTree",
props: {
selectValue: {
type: String,
default: "",
},
treeData: {
type: Array,
default: () => ([])
},
// 配置选项
defaultProps: {
type: Object,
default: () => ({ // 属性值为后端返回的对应的字段名
children: 'children',
label: 'className',
value: 'id'
})
},
//是否禁用
disabled: {
type: Boolean,
default: false
},
//默认选中值
defaultValue: {
type: String,
default: "",
},
},
data() {
return {
filterText: "",
value: "",
};
},
watch: {
filterText(val) {
this.$refs.treeRef.filter(val);
},
},
mounted() {
this.initialization()//初始化赋值
},
methods: {
// 初始化赋值
initialization(){
var that = this
this.findNodeById(this.treeData, this.defaultValue, function(node) {
that.value = node.className;
console.log('Found node name:', that.value); // 立即查看结果
});
},
//递归方法,获取树形结构中指定id的节点
findNodeById(tree, id, callback) {
for (let node of tree) {
if (node.id === id) {
// 找到节点,调用回调函数
callback(node);
return; // 如果只需要找到第一个匹配的节点,可以返回
}
if (node.children) {
// 如果节点有子节点,递归查找
this.findNodeById(node.children, id, callback);
}
}
},
//筛选方法
filterNode(value, data) {
if (!value) return true;
return data.className.indexOf(value) !== -1;
},
// 递归遍历数据
formatData(data) {
let options = [];
const formatDataRecursive = (data) => {
data.forEach((item) => {
options.push({ label: item.className, value: item.id });
if (item.children && item.children.length > 0) {
formatDataRecursive(item.children);
}
});
};
formatDataRecursive(data);
return options;
},
// 点击事件
handleNodeClick(node) {
this.value = node.className;
this.$refs.selectRef.blur();
this.$emit("clickSelectTree", node);
},
// 清空事件
clearSelectInput() {
this.$emit("clickSelectTree", "");
// 获取 el-tree 实例的引用
const elTree = this.$refs.treeRef;
// 将当前选中的节点设置为 null
elTree.setCurrentKey(null);
},
},
};
</script>
<style lang="scss" scoped>
.my_select_Tree .el-tree-node .is-current > .el-tree-node__content {
font-weight: bold;
color: #409eff;
}
.my_select_Tree .el-tree-node.is-current > .el-tree-node__content {
font-weight: bold;
color: #409eff;
}
</style>
2、第二种带多选框的下拉树形组件
<!--
* @description:树形下拉选择
* @author: Long
* @version: 1.0
* @updateDate: 2023-01-17 09:04:12
* @usage:用法
options: 树形数据
defaultProps: 树形数据属性
defaultValue: 默认选中的值
selectWidth: 下拉框宽度
placeholder: 下拉框提示语
filterable: 是否可搜索
appendToBody: 下拉框是否插入至body元素上
checkStrictly: 是否父子节点不关联
isCanDelete: 是否可删除
changeSelectDataList: 选中值变化时触发
disabledSelect: 是否禁用
<TreeSelect :options="areaOptions" :defaultProps="defaultProps" :defaultValue="defaultValue" @changeSelectDataList="changeSelectDataList" :selectWidth="'300'" style="margin:0 10px;" :placeholder="'请选择区域'"></TreeSelect>
-->
<template>
<div style="display: inline-block;">
<el-select v-model="selectValue" multiple :placeholder="placeholder" :filterable="filterable" :filter-method="dataFilter" :popper-append-to-body="appendToBody"
@remove-tag="removeTag" @clear="clearAll" :clearable="isCanDelete" :style="{ width: selectWidth + 'px'}" :disabled="disabledSelect" collapse-tags>
<el-option :value="selectTree" v-loading="treeLoading" element-loading-background="rgba(255, 255, 255, 0.5)"
element-loading-text="loading" class="option-style" disabled>
<div class="check-box">
<el-button type="text" @click="handlecheckAll">全选</el-button>
<el-button type="text" @click="handleReset">清空</el-button>
<el-button type="text" @click="handleReverseCheck">反选</el-button>
</div>
<el-tree :data="options" :props="defaultProps" class="tree-style" ref="treeNode" show-checkbox :node-key="defaultProps.value" :filter-node-method="filterNode" :default-checked-keys="defaultValue" :check-strictly="checkStrictly" @check-change="handleNodeChange"> </el-tree>
</el-option>
</el-select>
</div>
</template>
<script>
export default {
name: 'TreeSelect',
props: {
//编辑时回显的数组
defaultValue: {
type: Array,
default: () => ([])
},
//可用选项的数组
options: {
type: Array,
default: () => ([])
},
// 配置选项
defaultProps: {
type: Object,
default: () => ({ // 属性值为后端返回的对应的字段名
children: 'children',
label: 'label',
value: 'value'
})
},
// 是否将组件添加到body上面(组件在弹窗或者表格里面时可设为true)
appendToBody: {
type: Boolean,
default: false
},
// 是否可搜索
filterable: {
type: Boolean,
default: true // 不可以搜索
},
// 是否禁用下拉框
disabledSelect: {
type: Boolean,
default: false
},
// 父子不互相关联
checkStrictly: {
type: Boolean,
default: false // 关联
},
// 父类id字段名 (如果父子联动则必传该字段,不联动则不用传)
parentValue: {
type: String,
default: 'parentValue'
},
// 回显的值是否可被删除 true: 可以删除;false:不能删除
isCanDelete: {
type: Boolean,
default: true
},
placeholder: {
type: String,
default: '请选择'
},
// 不可删除报错
errMessage: {
type: String,
default: '该选项不可被删除'
},
//select宽度
selectWidth: {
type: String,
default: '200'
},
},
data () {
return {
selectTree: [], // 绑定el-option的值
selectValue: [], // 文本框中的标签
VALUE_NAME: this.defaultProps.value, // value转换后的字段
VALUE_TEXT: this.defaultProps.label, // label转换后的字段
treeLoading: false // 加载loading~
}
},
watch: {
// 监听回显的数据
defaultValue (val) {
if (val.length) {
this.$nextTick(() => {
let datalist = this.$refs.treeNode.getCheckedNodes()
if (!this.checkStrictly) {
const parentList = datalist.filter(v => v[this.defaultProps.children]).map(v => v[this.VALUE_NAME])
datalist = datalist.filter(v => parentList.indexOf(v[this.parentValue]) === -1)
}
this.selectTree = datalist
this.selectValue = datalist.map(v => v[this.VALUE_TEXT])
})
}
}
},
methods: {
// 全选
handlecheckAll () {
this.treeLoading = true
setTimeout(() => {
this.$refs.treeNode.setCheckedNodes(this.options)
this.treeLoading = false
}, 200)
},
// 清空
handleReset () {
if (this.isCanDelete) {
this.treeLoading = true
setTimeout(() => {
this.$refs.treeNode.setCheckedNodes([])
this.treeLoading = false
}, 200)
} else {
this.$message.error(this.errMessage)
}
},
// 反选处理方法
batchSelect(nodes, refs, flag, seleteds) {
if (Array.isArray(nodes)) {
nodes.forEach(element => {
refs.setChecked(element, flag, true)
})
}
if (Array.isArray(seleteds)) {
seleteds.forEach(node => {
refs.setChecked(node, !flag, true)
})
}
},
// 反选
handleReverseCheck() {
if (this.isCanDelete) {
this.treeLoading = true
setTimeout(() => {
let res = this.$refs.treeNode
let nodes = res.getCheckedNodes(true, true)
this.batchSelect(this.options, res, true, nodes)
this.treeLoading = false
}, 200)
} else {
this.$message.error(this.errMessage)
}
},
// 输入框关键字
dataFilter (val) {
this.$refs.treeNode.filter(val)
},
// 过滤
filterNode (value, data) {
if (!value) return true
return data[this.defaultProps.label].toLowerCase().indexOf(value.toLowerCase()) !== -1
},
// 选中节点
handleNodeChange(data,self,child) {
const flag = this.defaultValue.some(v => v === data[this.VALUE_NAME])
let datalist = this.$refs.treeNode.getCheckedNodes()
if (!self && !this.isCanDelete && flag) {
this.$message.error(this.errMessage)
this.$refs.treeNode.setChecked(data,true, true)
}
if (!this.checkStrictly) { // 如果联动则需处理父子值关系
const parentList = datalist.filter(v => v[this.defaultProps.children]).map(v => v[this.VALUE_NAME])
datalist = datalist.filter(v => parentList.indexOf(v[this.parentValue]) === -1)
}
this.selectTree = datalist
this.selectValue = datalist.map(v => v[this.VALUE_TEXT])
this.$emit('changeSelectDataList', this.selectTree)
},
// 移除单个标签
removeTag(tagName){
const flagName= this.selectTree.filter(v => v[this.VALUE_NAME] === this.defaultValue.find(item => item === v[this.VALUE_NAME])).map(v => v[this.VALUE_TEXT])
const flag = flagName.includes(tagName)
if (this.isCanDelete) { // 判断回显的值是否可删除
this.selectTree = this.selectTree.filter(v => v[this.VALUE_TEXT] !== tagName)
const selectTreeValue = this.selectTree.map(v => v[this.VALUE_NAME])
let setlist = this.$refs.treeNode.getCheckedNodes()
setlist = setlist.filter(v => v[this.VALUE_NAME] === selectTreeValue.find(item => item === v[this.VALUE_NAME]))
this.$nextTick(() => {
this.$refs.treeNode.setCheckedNodes(setlist)
})
this.$emit('changeSelectDataList', this.selectTree)
} else {
if (!flag) { // 判断回显时新增的是否可删除
this.selectTree = this.selectTree.filter(v => v[this.VALUE_TEXT] !== tagName)
const selectTreeValue = this.selectTree.map(v => v[this.VALUE_NAME])
let setlist = this.$refs.treeNode.getCheckedNodes()
setlist = setlist.filter(v => v[this.VALUE_NAME] === selectTreeValue.find(item => item === v[this.VALUE_NAME]))
this.$nextTick(() => {
this.$refs.treeNode.setCheckedNodes(setlist)
})
this.$emit('changeSelectDataList', this.selectTree)
} else {
this.selectValue = this.selectTree.map(v => v[this.VALUE_TEXT])
this.$message.error(this.errMessage)
}
}
},
// 文本框清空
clearAll(){
this.selectTree = []
this.$refs.treeNode.setCheckedNodes([])
this.$emit('changeSelectDataList', this.selectTree)
}
}
}
</script>
<style lang="scss" scoped>
.check-box{
padding: 0 20px;
}
::v-deep .el-scrollbar{
height: 280px;
.el-select-dropdown__wrap{
max-height: 280px;
overflow: hidden;
.el-select-dropdown__list{
padding: 0;
}
}
}
.option-style {
height: 280px;
padding: 0 0 10px 0 !important;
margin: 0;
overflow-y: auto;
cursor: default !important;
}
</style>