655 lines
17 KiB
Vue
655 lines
17 KiB
Vue
<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>
|