asd/asd-pc/components/xiaolu-tree/tree.vue

655 lines
17 KiB
Vue
Raw Normal View History

2024-11-21 11:06:22 +08:00
<template>
<view>
<view class="header">
<search v-if="searchIf" ref="sea" @confirm="confirmSearch" @add="addGroup" />
<view class="title">
<scroll-view scroll-x style="width: 100%;white-space: nowrap;" :scroll-left="scrollLeft">
<view v-for="(item,index) in tree_stack" class="inline-item" :key="index">
<view class="inline-item" v-if="index==0" @click="backTree(item,-1)">
<text :class="[(index==tree_stack.length-1&&!isre)?'none':'active']">全部</text>
</view>
<view v-if="index==0&&isre" @click="backTree(item,-2)"
:class="[index==tree_stack.length-1&&isre]?'none inline-item':'active inline-item'">
<!-- <i class="iconfont icon-z043 iconclass" />-->
<view style="display: inline-block;">
<u-icon name="arrow-right" color="#D0D4DB" size="14"></u-icon>
</view>
搜索结果
</view>
<view class="inline-item" @click="backTree(item,index)" v-if="index!=0">
<!-- <i class="iconfont icon-z043 iconclass" /> -->
<view style="display: inline-block;">
<u-icon name="arrow-right" color="#D0D4DB" size="14"></u-icon>
</view>
<text :class="index==tree_stack.length-1?'none inline-ite':'active'">
{{item[props.label]}}
</text>
</view>
</view>
</scroll-view>
</view>
</view>
<view>
<view class="container-list">
<u-swipe-action>
<template v-for="(item, index) in tree">
<u-swipe-action-item v-if="item.type=='user'" :options="options2"
:disabled="item.type=='system'?true:false" :key="item.id" @click="operateClick"
:name="item.type+item.id">
<view class="common" @click="handleClick(item,index)">
<label class="content">
<view class="list-item" v-show="isCheck">
<!-- 多选 -->
<view class="checkbox" v-if="props.multiple" @click.stop="handleClick(item,-1)">
<span v-if="isSelect(item)">
<i v-if="item.bx&&newCheckList.length!=0"
class="iconfont icon-banxuanzhongshousuo1-shi icons" />
<i v-else class="iconfont icon-xuanzhong txt icon-selected" />
</span>
<i v-else-if="item.qx" class="iconfont icon-xuanzhong txt icon-selected" />
<i v-else-if="item.bx"
class="iconfont icon-banxuanzhongshousuo1-shi icons" />
<i style="color: #b8b8b8;" v-else class="iconfont icon-weixuanzhong txt" />
</view>
<!-- 单选 -->
<view class="checkbox" v-else-if="(props.nodes?item.user?true:false:true)"
@click.stop="handleClick(item,-1)">
<i v-if="radioSelect(item)" class="txt iconfont icon-selected" />
<i style="color: #b8b8b8;" v-else class="txt iconfont icon-weixuanzhong1" />
</view>
</view>
<view class="avator" v-if="isAvator&&item.user" @click.stop="goDetails(item)">
<img
:src="item.avatar?(item.avatar.indexOf('http')!=-1?item.avatar:basePicUrl+item.avatar):avatorUrl">
</view>
<view class="lable-text">{{item[props.label]}}</view>
<view class="right">
<!-- <i v-if="!item.user&&item.children.length>0"
class="iconfont icon-z043 iconclass"></i> -->
<u-icon v-if="!item.user&&item.children.length>0" name="arrow-right"></u-icon>
</view>
</label>
</view>
</u-swipe-action-item>
<u-swipe-action-item v-else :options="options1"
:disabled="item.type=='system'?true:false" :key="item.id" @click="operateClick"
:name="item.type+item.id">
<view class="common" @click="handleClick(item,index)">
<label class="content">
<view class="list-item" v-show="isCheck">
<!-- 多选 -->
<view class="checkbox" v-if="props.multiple" @click.stop="handleClick(item,-1)">
<span v-if="isSelect(item)">
<i v-if="item.bx&&newCheckList.length!=0"
class="iconfont icon-banxuanzhongshousuo1-shi icons" />
<i v-else class="iconfont icon-xuanzhong txt icon-selected" />
</span>
<i v-else-if="item.qx" class="iconfont icon-xuanzhong txt icon-selected" />
<i v-else-if="item.bx"
class="iconfont icon-banxuanzhongshousuo1-shi icons" />
<i style="color: #b8b8b8;" v-else class="iconfont icon-weixuanzhong txt" />
</view>
<!-- 单选 -->
<view class="checkbox" v-else-if="(props.nodes?item.user?true:false:true)"
@click.stop="handleClick(item,-1)">
<i v-if="radioSelect(item)" class="txt iconfont icon-selected" />
<i style="color: #b8b8b8;" v-else class="txt iconfont icon-weixuanzhong1" />
</view>
</view>
<view class="avator" v-if="isAvator&&item.user" @click.stop="goDetails(item)">
<img
:src="item.avatar?(item.avatar.indexOf('http')!=-1?item.avatar:basePicUrl+item.avatar):avatorUrl">
</view>
<view class="lable-text">{{item[props.label]}}</view>
<view class="right">
<!-- <i v-if="!item.user&&item.children.length>0"
class="iconfont icon-z043 iconclass"></i> -->
<u-icon v-if="!item.user&&item.children.length>0" name="arrow-right"></u-icon>
</view>
</label>
</view>
</u-swipe-action-item>
</template>
</u-swipe-action>
</view>
</view>
<u-picker :show="isShow" :columns="columns" keyName="groupName" title="将联系人添加至" closeOnClickOverlay
@confirm="removeSure" @cancel="isShow=false" @close="isShow=false"></u-picker>
<u-modal :show="isShow1" :content='content' showCancelButton closeOnClickOverlay @confirm="deleteSure"
@cancel="isShow1=false" @close="isShow1=false"></u-modal>
<!-- <view class="btn box_sizing">
<button class="sureBtn" type="primary" @click="backConfirm">确认</button>
</view> -->
</view>
</template>
<script>
import search from './search/index.vue'
import {
deleteAddress,
myAddressList,
addAddressBook
} from "@/common/api/api.js"
export default {
name: "treeComponent",
data() {
return {
basePicUrl: this.$basePicUrl,
content: "",
value: "",
isShow1: false,
isShow: false,
isre: false,
tree: Object.freeze(this.treeNone),
newNum: 0,
oldNum: 0,
catchTreeNone: [...this.treeNone],
tree_stack: [1],
searchResult: [],
newCheckList: this.checkList,
scrollLeft: 999,
nodePathArray: [],
options1: [{
text: '删除',
style: {
backgroundColor: '#f56c6c',
}
}],
options2: [{
text: '添加至',
style: {
backgroundColor: '#3c9cff',
}
}, {
text: '删除',
style: {
backgroundColor: '#f56c6c',
}
}],
columns: [],
}
},
components: {
search
},
computed: {
isSelect() {
return (item) => {
const checkList = this.newCheckList
if (checkList.length == 0) {
this.props.checkStrictly ? (item.bx = 0, item.qx = 0) : ''
return false
}
const i = checkList.findIndex(e => {
return item[this.keyCode] == e[this.keyCode]
}) > -1
return i && !item.qx
}
},
radioSelect() {
const list = this.newCheckList
return (item) => {
return list.length > 0 && item[this.keyCode] == list[0][this.keyCode]
}
},
keyCode() {
return this.keyValue
}
},
created() {
this.Init()
},
methods: {
goDetails(item) {
this.$emit("toPerson", item);
},
// 移动联系人
removeSure(data) {
console.log(data.value[0]);
let params = {
"addressUserId": this.personId,
"createBy": "",
"createTime": "",
"groupName": "",
"gruopId": data.value[0].id,
"id": "",
"type": "1",
"updateBy": "",
"updateTime": "",
"userId": ""
}
addAddressBook(params).then(res => {
if (res.code == 200) {
uni.showToast({
title: "添加成功",
icon: "success",
duration: 2000
})
this.isShow = false;
this.$emit("reload")
} else {
uni.showToast({
title: "添加失败",
icon: "none",
duration: 2000
})
}
})
},
//删除联系人
deleteSure() {
deleteAddress(null, "?id=" + this.personId).then(res => {
if (res.code == 200) {
uni.showToast({
title: "删除成功",
icon: "success",
duration: 2000
})
this.isShow1 = false;
this.$emit("reload")
} else {
uni.showToast({
title: "删除失败",
icon: "none",
duration: 2000
})
}
})
},
sure() {
this.show = false;
},
operateClick(data) {
if (data.name.indexOf('user') != -1) {
this.personId = data.name.replace("user", "");
if (data.index == 0) {
//移动 联系人
//请求自建分组列表
myAddressList().then(res => {
if (res.code == 200) {
this.columns = [
[...res.result.records]
];
this.isShow = true;
} else {
uni.showToast({
title: "获取自建分组失败",
icon: "none",
duration: 2000
})
}
})
} else {
//删除联系人
this.content = "是否要删除该联系人"
this.isShow1 = true;
}
}
if (data.name.indexOf('my') != -1) {
//删除自建分组
this.personId = data.name.replace("my", "");
this.content = "是否要删除该分组"
this.isShow1 = true;
}
},
addGroup(value) {
this.$emit("add", value)
},
// 初始化
Init() {
if (this.newCheckList.length !== 0) {
let {
tree_stack,
props,
catchTreeNone,
newCheckList
} = this
if (props.multiple) {
if (props.checkStrictly) {
this.checkAllChoose();
}
} else {
this.getNodeRoute(catchTreeNone, newCheckList[0][this.keyCode])
let arr = this.nodePathArray.reverse()
console.log(arr)
if (arr.length == 0) return
this.tree_stack = tree_stack.concat(arr);
this.tree = this.tree_stack[this.tree_stack.length - 1].children;
}
}
},
// 点击项目处理
handleClick(item, index) {
console.log(item);
let children = item[this.props.children]
if (index > -1 && children && children.length > 0) {
console.log(index)
this.toChildren(item)
} else if (this.props.multiple) {
this.checkboxChange(item, index, item.bx, item.qx)
} else {
this.checkbox(item, index)
}
},
// 获取路径
getPath() {
const {
keyCode,
tree_stack,
props
} = this
const path = [...tree_stack].map(e => {
const item = Object.assign({}, e)
delete item[props.children]
return item
})
return path.slice(1, path.length) || []
},
//多选
async checkboxChange(item, index, bx, qx) {
let that = this;
const {
props
} = that
if (!props.multiple) return;
let findIdex = that.newCheckList.findIndex(e => item[this.keyCode] == e[this.keyCode]);
const path = this.getPath()
if (findIdex > -1) { //反选
if (props.checkStrictly) { //关联子级
if (item.user) { //用户
that.newCheckList.splice(findIdex, 1)
} else { //非用户,取消所有下一级
that.getIdBydelete(item.children)
}
} else {
that.newCheckList.splice(findIdex, 1)
}
} else { //选中
if (!item.user && props.checkStrictly) { //选中下一级
if (qx || bx) { //取消下级
await that.getIdBydelete(item.children);
item.qx = 0;
item.bx = 0;
} else {
item.qx = 1;
item.bx = 0;
const {
id,
name,
user
} = item
const newObj = {
id,
name,
user
}
const pathList = this.tree_stack.length === 1 ? [newObj, ...path] : [...path, newObj]
await that.chooseChild(item.children, pathList);
}
this.$forceUpdate()
return
}
that.newCheckList.push({
...item,
path
});
}
},
// 取消下一级的选中
getIdBydelete(arr) {
arr.forEach(e => {
if (e.user) {
for (var i = 0; i < this.newCheckList.length; i++) {
if (e[this.keyCode] == this.newCheckList[i][this.keyCode]) {
this.newCheckList.splice(i, 1)
break;
}
}
} else {
this.getIdBydelete(e.children)
}
})
},
// 关联下一级,选中
chooseChild(arr, path) {
let that = this;
const oldPath = [...path]
for (var i = 0, len = arr.length; i < len; i++) {
let item = arr[i];
if (item.user) {
that.newCheckList.push({
...item,
path: oldPath
})
} else {
const newItem = {
...item
}
delete newItem[that.props.children]
const newPath = [...oldPath, newItem]
that.chooseChild(item.children, newPath)
}
}
},
// (tree为目标树targetId为目标节点id)
getNodeRoute(tree, targetId) {
for (let index = 0; index < tree.length; index++) {
if (tree[index].children) {
let endRecursiveLoop = this.getNodeRoute(tree[index].children, targetId)
if (endRecursiveLoop) {
this.nodePathArray.push(tree[index])
return true
}
}
if (tree[index][this.keyCode] === targetId) {
return true
}
}
},
//单选
checkbox(item, index) {
const path = this.getPath()
this.$set(this, 'newCheckList', [{
...item,
path
}])
if (item.user) {
//直接发起聊天
console.log("12432");
this.$emit("toChat", item)
}
},
//到下一级
toChildren(item) {
if (item.user) return
var that = this;
uni.showLoading({
title: '加载中'
})
let children = that.props.children;
if (!item.user && item[children].length > 0 && !(that.tree_stack[0][this.keyCode] == item[this.keyCode])) {
that.tree = item[children];
that.tree_stack.push(item);
}
this.$nextTick(() => {
uni.hideLoading()
this.scrollLeft += 200;
})
if (this.props.checkStrictly) this.checkAllChoose();
},
//搜索
confirmSearch(val) {
this.searchResult = []
this.search(this.catchTreeNone, val)
this.isre = true
this.tree_stack.splice(1, 1000)
uni.showLoading({
title: '正在查找'
})
setTimeout(() => {
this.tree = this.searchResult
uni.hideLoading()
}, 300)
},
search(data, keyword) {
var that = this
let children = that.props.children
for (var i = 0, len = data.length; i < len; i++) {
if (data[i].name.indexOf(keyword) >= 0) {
that.searchResult.push(data[i])
}
if (!data[i].user && data[i][children].length > 0) {
that.search(data[i][children], keyword)
}
}
},
checkAllChoose() {
let o = false,
t = true;
this.tree.forEach((e, i) => {
if (!e.user) {
e.qx = o;
e.bx = o;
this.computAllNumber(e.children);
// console.log(this.newNum,this.oldNum)
if (this.newNum != 0 && this.oldNum != 0) {
if (this.newNum == this.oldNum) {
e.qx = t;
e.bx = o;
} else {
e.qx = o;
e.bx = t;
}
}
if (this.newNum != 0 && this.oldNum == 0) {
this.$set(this.tree[i], 'bx', o);
this.$set(this.tree[i], 'qx', o);
}
this.$forceUpdate()
this.newNum = 0
this.oldNum = 0
}
})
},
computAllNumber(arr) {
for (let j = 0; j < arr.length; j++) {
var e = arr[j];
this.checkSum(e[this.keyCode])
if (e.user) {
this.newNum++;
} else {
this.computAllNumber(e.children)
}
}
},
checkSum(id) {
for (let i = 0; i < this.newCheckList.length; i++) {
if (id == this.newCheckList[i][this.keyCode]) {
this.oldNum++;
break
}
}
},
//返回其它层
backTree(item, index) {
console.log(index);
let that = this,
tree_stack = that.tree_stack,
max = 10000;
if (index === -1) {
that.tree = that.catchTreeNone
that.tree_stack.splice(1, max)
that.isre = false
that.$refs.sea.clears()
} else if (index === -2) {
that.tree = that.searchResult
that.tree_stack.splice(1, max)
} else {
if (tree_stack.length - index > 2) {
tree_stack.forEach((item, i) => {
if (i > index) {
that.tree_stack.splice(i, max)
}
})
} else if (index !== tree_stack.length - 1) {
that.tree_stack.splice(tree_stack.length - 1, 1)
}
that.tree = item[that.props.children]
}
if (this.props.checkStrictly) this.checkAllChoose();
this.$forceUpdate()
},
backConfirm() {
this.$emit('sendValue', this.newCheckList, 'back')
}
},
props: {
treeNone: {
type: Array,
default: () => {
return []
}
},
//是否开启选中
isCheck: {
type: Boolean,
default: () => {
return false
}
},
isAvator: {
type: Boolean,
default: () => {
return false
}
},
checkList: {
type: Array,
default: () => []
},
parentList: {
type: Array,
default: () => []
},
searchIf: {
type: Boolean,
default: () => true
},
keyValue: {
type: String,
default: 'id',
},
avatorUrl: {
type: String,
default: '',
},
props: {
type: Object,
default: () => {
return {
label: 'name',
children: 'children',
multiple: false,
checkStrictly: false, //不关联
}
}
}
},
}
</script>
<style lang="scss" scoped>
@import './css/style.scss';
@import url("./css/icon.css");
</style>