Files
2026-08-12 17:19:37 +08:00

448 lines
16 KiB
Vue

<template>
<Modal v-model="modal" title="选择用户" width="720px" :mask-closable="false" :closable="false">
<Tabs class="tabs-panel" type="card" v-if="firstTabIndex && firstTabIndex.length > 1" v-model="firstTabIndex" @on-click="firstTabChange">
<TabPane v-for="(item, index) in firstTabData" :label="item" :name="index + ''"></TabPane>
</Tabs>
<AutoComplete @on-search="handleSearch" @on-select="handleSelect" placeholder="输入名字搜索" v-model="searchTreeName" :clearable="true" class="auto-box">
<Option v-for="item in currentFlatten" :value="item.name">
<span>{{ item.name }}</span>
<span class="fr info">{{ item.group }}</span>
</Option>
</AutoComplete>
<div class="tree-wrap fix">
<div class="tree-panel fl">
<ul class="tree-tab-ul fix">
<li
@click="secondTabChange(index)"
:style="{ width: 100 / secondTabData.length + '%' }"
:class="{ active: index == secondTabIndex, fl: true }"
v-for="(item, index) in secondTabData"
>
{{ item }}
</li>
</ul>
<div class="tree-box">
<div :id="ztreeDomId" class="ztree"></div>
</div>
</div>
<div class="arrow-box fl">
<svg t="1626916477711" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10021" width="36" height="36">
<path
d="M138.935 256.078v511.844h63.42V256.078h-63.42z m126.842 0v511.844h127.215V256.078H265.777zM885.064 512L583.254 64.323v191.755H456.414v511.844h126.842v191.755L885.064 512z"
p-id="10022"
fill="#2d8cf0"
></path>
</svg>
</div>
<div class="user-panel fr">
<div class="title-box fix">
<Checkbox @on-change="checkAllUser" v-model="isCheckUserAll">全选</Checkbox>
<div class="fr">{{ tempUserList.length }}</div>
<a href="javascript:;" @click="delCheckUser" v-if="tempUserList.findIndex(x => x.isCheck) > -1">删除选中</a>
</div>
<ul class="user-box">
<li :class="{ active: item.isCheck }" v-for="(item, index) in tempUserList" @click="checkUserOne(item)">
{{ item.name }}
<span class="info">{{ item.group }}</span>
</li>
</ul>
</div>
</div>
<div slot="footer">
<i-Button type="primary" @click="submit">提交</i-Button>
<i-Button @click="modal = false" style="margin-left: 8px">取消</i-Button>
</div>
</Modal>
</template>
<script>
require("@public/libs/ztree/zTreeStyle.css");
import "@public/libs/ztree/jquery.ztree.all.min.js";
export default {
props: {
treeData: {
type: Array,
default() {
return [];
},
},
userids: {
type: Array,
default() {
return [];
},
},
ignoreIds: {
type: Array,
default() {
return [];
},
},
},
model: {
prop: "userids",
event: "change",
},
data() {
return {
ztreeDomId: null,
modal: false,
isCheckUserAll: false,
firstTabIndex: 0,
secondTabIndex: 0,
cacheMap: new Map(),
currentTree: [],
currentFlatten: [],
searchTreeName: null,
tempUserList: [],
isDisabled: false,
};
},
watch: {
searchTreeName(val) {
this.handleSearch(val);
},
},
computed: {
firstTabData() {
if (this.treeData.length > 1) return this.treeData.map(x => x.name);
else return [];
},
secondTabData() {
if (this.treeData.length == 0) return [];
return this.treeData[this.firstTabIndex].data.map(x => x.name);
},
currentTreeFlatten() {
const flatten = (data, pid, pname) => {
return data.reduce((arr, { id, name, children = [], type }) => arr.concat([{ id, name, pid, type, group: pname }], flatten(children, id, name)), []);
};
if (!this.currentTree) return [];
var newArr = flatten(this.currentTree, 0, "");
return newArr;
},
},
mounted() {
this.isDisabled = this.ignoreIds.length > 0;
this.ztreeDomId = this.uuid();
},
methods: {
show() {
this.modal = true;
this.firstTabChange("0");
},
firstTabChange(index) {
this.firstTabIndex = index;
this.secondTabChange(0);
},
secondTabChange(index) {
const _this = this;
if (index != 0 && this.secondTabIndex == index) return;
this.secondTabIndex = index;
this.changeEmpty();
this.initTree();
},
handleSearch(query) {
const _this = this;
let arr = [],
searchArr = this.currentTreeFlatten.filter(x => x.type == 2 && x.name.indexOf(query) != -1);
for (const item of searchArr) {
!arr.map(x => _this.getSplitId(x.id)).includes(_this.getSplitId(item.id)) && arr.push(item);
}
this.currentFlatten = arr;
},
handleSelect(query) {
const _this = this;
if (query.indexOf(",") != -1) query = query.split(",")[0];
var treeObj = $.fn.zTree.getZTreeObj(this.ztreeDomId);
var node = treeObj.getNodeByParam("name", query, null);
if (!!node) treeObj.checkNode(node, true, true, true);
},
formatTree(tree, level = 0) {
const _this = this;
tree.forEach(element => {
element.open = level == 0;
element.type = 1;
element.id = element.id + "," + element.pid;
element.checked = false;
if (typeof element.children !== "undefined" && element.children.length > 0) element.children = _this.formatTree(element.children, level + 1);
else {
element.type = 2;
}
});
return tree;
},
initTree() {
const _this = this;
let first = _this.firstTabIndex,
second = _this.secondTabIndex,
cacheKey = first + "," + second,
cacheMap = _this.cacheMap,
tree = this.treeData[first].data[second].data;
if (!!tree && typeof tree === "function") {
var cacheData = cacheMap.get(cacheKey);
if (!cacheData) {
tree().then(data => {
cacheMap.set(cacheKey, data);
_this.createTree(data, _this.ztreeDomId);
});
} else {
_this.createTree(cacheData, _this.ztreeDomId);
}
} else {
_this.createTree(tree, _this.ztreeDomId);
}
},
createTree(_data, _domId) {
const _this = this;
var jtree = JSON.parse(JSON.stringify(_data));
var ftree = _this.formatTree(jtree);
_this.currentTree = ftree;
//_this.tempUserList = JSON.parse(JSON.stringify(_this.userids));
let treeSetting = {
view: {
dblClickExpand: false,
showIcon: false,
},
check: {
enable: true,
chkboxType: { Y: "ps", N: "ps" },
},
callback: {},
};
function formatUser(tree, checked) {
const recursionCheckIds = tree => {
let arrIds = [];
for (const key in tree) {
const element = tree[key];
if (element.type == 2 && !element.chkDisabled) arrIds.push({ id: element.id, tid: element.tId });
if (typeof element.children !== "undefined" && element.children) {
var childIds = recursionCheckIds(element.children);
arrIds = [...arrIds, ...childIds];
}
}
return arrIds;
};
var checkIds = recursionCheckIds([tree]);
var checkUserList = _this.currentTreeFlatten.filter(x => checkIds.map(x => x.id).includes(x.id));
let checkUserArr = [];
for (const element of checkUserList) {
var findObj = checkIds.find(x => x.id == element.id);
if (!!findObj && checkUserArr.findIndex(x => x.id == element.id) === -1 && _this.tempUserList.findIndex(x => x.id == element.id) === -1) {
checkUserArr.push({ ...element, isCheck: false, tid: findObj.tid });
}
}
if (checked) _this.tempUserList = _this.tempUserList.concat(checkUserArr);
else {
var ids = checkUserList.map(x => x.id);
_this.tempUserList = _this.tempUserList.filter(x => !ids.includes(x.id));
}
}
//当禁止时,是否还显示在右侧
var isCheckFormat = treeNode => {
let id = _this.getSplitId(treeNode.id);
return _this.ignoreIds.findIndex(x => x == id) === -1;
};
treeSetting.callback.onClick = (event, treeId, treeNode, clickFlag) => {
let check = treeNode.checked;
let treeObj = $.fn.zTree.getZTreeObj(treeId);
treeObj.checkNode(treeNode, !check, true);
if (isCheckFormat(treeNode)) formatUser(treeNode, treeNode.checked);
};
treeSetting.callback.onCheck = (event, treeId, treeNode) => {
if (isCheckFormat(treeNode)) formatUser(treeNode, treeNode.checked);
};
var treeObj = $.fn.zTree.init($("#" + _domId), treeSetting, ftree);
//checkUser
var nodes = treeObj.getNodesByFilter(x => _this.userids.includes(_this.getSplitId(x.id)));
var arr = [];
nodes.forEach(element => {
var splitId = _this.getSplitId(element.id); //重复id只选择第一个
if (!arr.includes(splitId)) treeObj.checkNode(element, true, true, true);
arr.push(splitId);
});
var ignorNodes = treeObj.getNodesByFilter(x => _this.ignoreIds.includes(_this.getSplitId(x.id)));
ignorNodes.forEach(element => {
treeObj.checkNode(element, true, true, true);
treeObj.setChkDisabled(element, true);
});
},
checkAllUser(check) {
//全选用户
const _this = this;
_this.tempUserList.forEach(element => {
element.isCheck = check;
});
},
checkUserOne(item) {
item.isCheck = !item.isCheck;
let tlist = this.tempUserList;
this.isCheckUserAll = tlist.length > 0 && tlist.filter(x => x.isCheck).length == tlist.length;
},
delCheckUser() {
//删除选中用户
const _this = this;
let tlist = _this.tempUserList,
delArr = [];
for (const item of tlist) {
item.isCheck && delArr.push(item);
}
var treeObj = $.fn.zTree.getZTreeObj(_this.ztreeDomId);
delArr.forEach(element => {
var node = treeObj.getNodeByTId(element.tid);
treeObj.checkNode(node, false, true, true);
});
_this.isCheckUserAll = false;
},
changeEmpty() {
this.tempUserList = [];
this.searchTreeName = "";
},
submit() {
const _this = this;
let objArr = [],
idsArr = this.tempUserList.map(x => _this.getSplitId(x.id));
idsArr = Array.from(new Set(idsArr));
this.$emit("change", idsArr);
function delKey(obj, ...args) {
args.forEach(v => {
delete obj[v];
});
return obj;
}
idsArr.forEach(element => {
let findObj = _this.tempUserList.find(x => _this.getSplitId(x.id) == element);
delKey(findObj, "id", "isCheck", "tid", "pid", "type");
let item = { ...findObj, id: element };
if (_this.isDisabled) item.disabled = this.userids.findIndex(x => x == element) !== -1;
objArr.push(item);
});
this.$emit("on-submit", objArr);
this.modal = false;
},
getSplitId(strId) {
if (typeof strId === "string" && strId.indexOf(",") != -1) return parseInt(strId.split(",")[0]);
else return strId;
},
uuid() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
var r = (Math.random() * 16) | 0,
v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
},
},
};
</script>
<style lang="scss" scoped>
.tree-wrap {
height: 430px;
position: relative;
}
.tree-panel {
border: 1px solid #eee;
width: 280px;
height: 430px;
overflow: hidden;
}
.tree-tab-ul {
li {
background: #f7f7f7;
border-bottom: 1px solid #eee;
height: 34px;
line-height: 34px;
text-align: center;
cursor: pointer;
}
li.active {
background: #fff;
color: #2d8cf0;
border-bottom: none;
cursor: default;
}
}
.tree-box {
padding: 4px 0;
height: 394px;
width: auto;
overflow-y: auto;
border: none;
}
.user-panel {
border: 1px solid #eee;
width: 280px;
.title-box {
background: #f7f7f7;
height: 34px;
line-height: 34px;
padding: 0 12px;
a {
text-decoration: none;
float: right;
margin-right: 20px;
outline: none;
}
}
.user-box {
height: 396px;
overflow-y: auto;
li {
line-height: 32px;
padding-left: 12px;
cursor: pointer;
.info {
float: right;
margin-right: 12px;
font-size: 12px;
color: gray;
}
}
li:hover {
background: #f3f3f3;
}
li.active {
background: #e4edf6;
}
}
}
.arrow-box {
width: 128px;
text-align: center;
position: relative;
top: 50%;
margin-top: -17px;
}
.auto-box {
width: 200px;
margin-bottom: 10px;
/deep/.ivu-select-item .info {
font-size: 12px;
color: gray;
position: relative;
top: 2px;
}
}
/deep/ .ztree li {
overflow: hidden;
}
/deep/ .ztree li a {
width: 100%;
}
/deep/ .ztree li a:hover {
text-decoration: none;
}
/deep/ .ivu-auto-complete .ivu-select-dropdown-list {
max-height: 310px;
overflow-y: auto;
}
</style>