Commit 1771d0f4 by fairyly

feat: 增加树形demo

parent fc19c41c
......@@ -8,23 +8,26 @@
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="shortcut icon" href="./favicon.ico"/>
<title>好办管理平台</title>
</head>
<body style="min-width: 1400px;">
<div id="app"></div>
<!-- built files will be auto injected -->
<!-- 公共库引用 cdn -->
<script src="//web-1251519181.file.myqcloud.com/lib/vue/2.6.6/vue.min.js"></script>
<script src="//web-1251519181.file.myqcloud.com/lib/vue-router/3.0.2/vue-router.min.js"></script>
<script src="//web-1251519181.file.myqcloud.com/lib/vuex/3.1.0/vuex.min.js"></script>
<script src="//web-1251519181.file.myqcloud.com/components/img-preview.2.0.00.js"></script>
<script src="//web-1251519181.file.myqcloud.com/components/footer.2.0.04.js"></script>
<!-- <script src="https://cdn.ravenjs.com/3.26.2/vue/raven.min.js" crossorigin="anonymous"></script> -->
<script>
// Raven.config('https://3715a345910d4c768e7a1ec14619c2d5@sentry.io/1413672').install();
</script>
</body>
</html>
<head>
<meta charset="utf-8">
<link rel="shortcut icon" href="./favicon.ico" />
<title>好办管理平台</title>
</head>
<body style="min-width: 1400px;">
<div id="app"></div>
<!-- built files will be auto injected -->
<!-- 公共库引用 cdn -->
<script src="//web-1251519181.file.myqcloud.com/lib/vue/2.6.6/vue.min.js"></script>
<script src="//web-1251519181.file.myqcloud.com/lib/vue-router/3.0.2/vue-router.min.js"></script>
<script src="//web-1251519181.file.myqcloud.com/lib/vuex/3.1.0/vuex.min.js"></script>
<script src="//web-1251519181.file.myqcloud.com/components/img-preview.2.0.00.js"></script>
<script src="//web-1251519181.file.myqcloud.com/components/footer.2.0.04.js"></script>
<!-- <script src="https://cdn.ravenjs.com/3.26.2/vue/raven.min.js" crossorigin="anonymous"></script> -->
<script>
// Raven.config('https://3715a345910d4c768e7a1ec14619c2d5@sentry.io/1413672').install();
</script>
</body>
</html>
\ No newline at end of file
......@@ -31,9 +31,11 @@
"qrcodejs2": "0.0.2",
"script-loader": "^0.7.2",
"tinymce": "^4.8.3",
"v-contextmenu": "^2.9.0",
"vue-amap": "^0.5.10",
"vue-awesome-swiper": "^3.1.3",
"vue-clipboard2": "^0.2.0",
"vue-runtime-helpers": "^1.1.2",
"xlsx": "^0.13.5"
},
"devDependencies": {
......@@ -104,4 +106,4 @@
"last 2 versions",
"not ie <= 8"
]
}
\ No newline at end of file
}
<!--
* @Descripttion: 当前组件信息
* @version: 1.0.0
* @Author: 无尘
* @Date: 2019-08-14 16:51:07
* @LastEditors : 无尘
* @LastEditTime : 2020-01-14 14:44:57
-->
<!--
<wx-tree v-model="itemData" ></wx-tree>
import wxTree from './wx-tree.vue';
-->
<template>
<div class="m-l-10">
</div>
</template>
<script>
import draggable from 'vuedraggable';
import showMsg from '@/common/js/showmsg';
export default {
name: 'li-row',
components: {
draggable
},
props: {
value: {
type: [Object, Array],
default() {
return [];
}
},
itemData: {
type: [Object, Array],
default() {
return [];
}
}
},
data() {
return {
};
},
computed: {},
methods: {
/**
*
*/
},
watch: {
value: function(newData, oldData) {
const that = this;
that.trData = JSON.parse(JSON.stringify(newData));
}
},
mounted() {
const that = this;
that.trData = JSON.parse(JSON.stringify(that.value));
},
beforeDestroy() {
}
};
</script>
<style lang="less" scoped>
</style>
<template>
<el-dialog :title="treeSet.isSelectPerson ? '选择人员' : '选择部门'" width="660px" :visible.sync="treeSet.dialogVisible">
<div class="transfer-area">
<div class="select-area t-a-select">
<p class="title">选择</p>
<div class="tree-div">
<div class="input-container">
<el-input v-model="searchText" placeholder="请输入内容"></el-input>
</div>
<div class="select-div" style="width: 100%;">
<el-select v-model="brandSelection" :disabled="(!!currentBrand ? true : false) || (treeSet.storeType == 'addClerk' ? true : false)" placeholder="请选择品牌" @change="selectBrand" style="width: 100%;margin-top:20px;">
<el-option v-for="(item, index) in brands" :key="item.id" :label="item.label" :value="index">
{{ item.label }}
</el-option>
</el-select>
</div>
<!-- :default-expanded-keys="defaultOpen" -->
<el-tree class="search-menu" node-key="id" ref="tree" :check-strictly="true" :data="menuData" show-checkbox :highlight-current="true" :expand-on-click-node="false" icon-class="open-child" :props="myProps" :filter-node-method="filterNode" @check-change="getCurrentNode" @node-expand="nodeOpen" @node-collapse="nodeClose" @node-click="handleNodeClick">
<span class="custom-tree-node" :class="data.disableOpen ? 'disable-open' : ''" slot-scope="{ node, data }">
<span :datap="data.childrens">{{ data.label }}</span>
<span class="open-btn" v-if="!!data.childrens">
<!-- && !!data.childrens[0].groupId" && !!data.childrens.length-->
<el-button @click="nodeOpen(data, node)" :disabled="data.disableOpen" type="text" size="small">下级</el-button>
</span>
</span>
</el-tree>
</div>
</div>
<div class="selected-area t-a-select">
<p class="title">
已选
<a class="J_del-all" @click="delSelected('empty')">全部清除</a>
</p>
<div class="tree-div">
<ul class="selected-list">
<template v-if="selectedList.length > 0">
<li v-for="li in selectedList" class="list group-li" :class="li.groupId ? 'group-li' : 'person-li'" :key="li.id + li.label">
<div class="label"><i class="iconfont" :class="li.groupId ? 'icon-tongshi-zuzhijiagou' : 'icon-chengyuan'"></i>{{ li.label }}</div>
<div class="close-btn" @click="delSelected(li)">
<i class="el-icon-close"></i>
</div>
</li>
</template>
</ul>
</div>
</div>
</div>
<div class="btn-box t-rt p-b-10">
<el-button @click="treeSet.dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitSelected">确定</el-button>
</div>
</el-dialog>
</template>
<script>
import { getRequest } from '@/api/api';
export default {
name: 'vue-select-employee',
props: {
treeSet: {
type: Object,
default() {
return {
isSelectPerson: true,
dialogVisible: false,
isSingle: false // 是否单选
};
}
},
currentBrand: {
// 当前传入的品牌 id
type: String,
default() {
return '';
}
},
selectType: {
type: String,
default: 'all' // all 所有都可选, person 只选人, store 只选门店, group 只选分组, group-store 选门店/分组
},
forbidenList: {
// 传入需要禁用的分组的id
type: Array,
default() {
return [];
}
},
visibleNodes: {
type: [Array, String], // 设置仅可见的节点,如果不传则默认展示所有
default() {
return '';
}
},
defaultList: {
// 回显数据
type: Array,
default() {
return [];
}
},
appScene: {
// 使用场景
type: [String, Number],
default: ''
}
},
data() {
return {
searchText: '',
myProps: {
children: 'childrens',
label: 'label',
disabled: 'disabled'
},
menuData: [],
menusObj: {},
defaultOpen: [], // 默认展开节点的 key 的数组
selectedList: [],
brandSelection: 0, // 看了代码发现这里是取的索引值,不是品牌 id
brands: [],
hasOpened: false,
firstRender: true, // 判断是否是第一次渲染数据,用于切换品牌时判断
renderFlag: true, // 应用判断渲染
storeList: []
};
},
methods: {
/**
* 获取分组架构
*/
getGroupData() {
let that = this;
let params = {
isStoreGroup: 1,
appScene: that.appScene
};
getRequest('/haoban-manage-web/dept/deptList', params)
.then(res => {
let treeData = [];
if (res.data.errorCode == 1) {
treeData = res.data.result || [];
that.formatGroupData(treeData);
}
})
.catch(e => {});
},
/**
* 处理获取分组数据
*/
formatGroupData(data) {
let that = this;
let selType = that.selectType; // 传入:选择门店的类型(all 所有都可选, person 只选人,store 只选门店, group 只选分组, group-store 选门店/分组)
let fbdList = that.forbidenList; // 传入: 需要禁用的分组的 id
that.menusObj = {};
data.forEach(group => {
group.label = group.name || ''; // 新增
group.id = group.groupId || ''; // 新增
group.disableOpen = false; // 新增
let isForbiden = !!(fbdList.indexOf(group.id) > -1); // 判断当前分组是否在禁用分组列表内
group.disabled = group.hasPression != 1 || selType == 'person' || selType == 'store' || isForbiden; // 新增
let arr = [];
data.forEach(child => {
child.disableOpen = false;
child.disabled = child.hasPression != 1 || selType == 'person' || selType == 'store' || isForbiden;
if (child.parentId == group.groupId) {
arr.push(child);
}
});
// 把简单 json 数组转换成 父子关系的 json
if (arr.length > 0) {
group.childrens = arr;
} else if (group.level != 0 && that.selectType != 'group') {
group.childrens = [{ label: '' }]; // 默认有子级 { label: '' }
group.isLast = true;
}
if (group.level == 0) {
// 禁用分组
group.disabled = (group.childrens && group.childrens.length > 0) || (group.hasPression != 1 || selType == 'person' || selType == 'store' || isForbiden);
// console.log(group.disabled, group.childrens && group.childrens.length > 0, group.hasPression != 1 || selType == 'person' || selType == 'store' || isForbiden);
group.hasLoad = true;
that.brands.push(group);
if (group.childrens) {
that.defaultOpen.push(group.id);
}
}
that.menusObj[group.id] = group;
});
let brandSelectionId = that.treeSet.groupId ? that.treeSet.groupId : that.brands[0].id;
that.brands.forEach((el, idx) => {
if (el.id == brandSelectionId) {
that.brandSelection = idx;
}
});
that.menuData = [that.brands[that.brandSelection]]; // 设置树形结构数据
if (selType != 'group') {
// && that.treeSet.storeType != 'addClerk'
this.getStoreList(that.menuData[0]);
}
},
/**
* 树形菜单选择
*/
handleNodeClick(obj, node) {
this.$emit('handleTreeSelection', obj, node, 'node');
},
/**
* 获取当前复选框状态改变的节点,如果被选中,将禁用展开
*/
getCurrentNode(data, ifChecked, son) {
let that = this;
data.disableOpen = ifChecked;
that.$nextTick(() => {
that.selectedList = that.$refs.tree.getCheckedNodes();
if (that.treeSet.isSingle && that.selectedList.length > 1) {
let index = that.selectedList.indexOf(data);
that.selectedList.splice(1 - index, 1);
that.$refs.tree.setCheckedNodes(that.selectedList);
}
});
},
/**
* 节点展开时,禁用复选框
*/
nodeOpen(data, node) {
if (data.level == 0) {
data.disabled = true;
}
if (data.childrens[0].label == '') {
data.childrens = [];
}
// data.disabled = true;
// console.log(data, !data.hasLoad, this.selectType != 'group', this.treeSet.storeType, this.treeSet.openNextBool);
// openNextBool 没有设置 , 并且当前选择不是选分组, 并且不是添加店员
if (!data.hasLoad && this.selectType != 'group' && this.treeSet.storeType != 'addClerk' && !this.treeSet.openNextBool) {
this.getStoreList(data, 'openFlag');
data.hasLoad = true; // 标记为已经请求过子分组数据,下次展开不再请求
}
// openNextBool 已经设置 , 并且当前选择不是选分组, 并且不是添加店员
if (!data.hasLoad && this.selectType != 'group' && this.treeSet.storeType != 'addClerk' && this.treeSet.openNextBool) {
this.getStoreList(data, 'openFlag');
data.hasLoad = true; // 标记为已经请求过子分组数据,下次展开不再请求
}
if (this.treeSet.storeType == 'addClerk' && !data.hasLoad) {
this.getStoreList(data, 'openFlag');
data.hasLoad = true; // 标记为已经请求过子分组数据,下次展开不再请求
}
},
/**
* 获取门店列表
*/
getStoreList(parent, flag) {
let that = this;
let params = {
storeGroupId: parent.groupId,
showChild: 0,
pageNumber: 1,
pageSize: 1000000000, // 因为获取门店列表做了分页,所以取了一个极限值
showType: 2
};
getRequest('/haoban-manage-web/store/findSimplePage', params)
.then(res => {
let storeList = [];
if (res.data.errorCode == 1) {
if (parent.level != 0) {
parent.disabled = !!res.data.result.list && !!flag ? true : false;
}
that.$forceUpdate();
storeList = res.data.result.list == null ? [] : res.data.result.list;
that.storeList = res.data.result.list == null ? [] : res.data.result.list;
if (!res.data.result.list || !res.data.result.list.length) {
return false;
}
that.formatStoreList(storeList, parent);
if (that.$refs.tree) {
that.renderDefault();
}
that.renderFlag = false; // 应用中使用:设置默认参数,默认情况传入品牌的 groupId ,不再去请求门店数据,切换的时候再去请求
}
})
.catch(e => {});
},
/**
* 处理获取门店列表的数据
*/
formatStoreList(list, parent) {
let that = this;
let type = this.selectType;
list.forEach(li => {
li.id = li.storeId;
li.label = li.storeName;
li.hasLoad = true;
li.disabled = !!(type == 'person');
if (li.clerks.length && (type == 'all' || type == 'person')) {
li.clerks.forEach(clerks => {
clerks.label = clerks.name;
clerks.id = clerks.employeeClerkId;
});
li.childrens = li.clerks;
}
});
that.appendStore(list, parent);
},
// 追加当前门店
appendStore(list, parent) {
let that = this;
if (parent.isLast) {
// 应该是判断是不是最后一层
parent.childrens = list;
} else {
// 现在问题是每次都追加数据了
let arr = !!parent.childrens ? parent.childrens : [];
arr = arr.concat(list);
let hash = {};
// 去重数组对象
arr = arr.reduce(function(item, next) {
hash[next.id] ? '' : (hash[next.id] = true && item.push(next));
return item;
}, []);
parent.childrens = JSON.parse(JSON.stringify(arr));
// parent.isLast = true; // 追加后重新设置isLast
that.$forceUpdate();
}
if (parent.childrens.length > 0 && this.firstRender) {
this.firstRender = false;
this.defaultOpen.push(parent.id);
}
that.$forceUpdate();
that.$nextTick(() => {
// that.menuData = JSON.parse(JSON.stringify(that.menuData));
}); // this.renderDefault();
that.$forceUpdate();
},
/**
* 节点关闭时,取消复选框的禁用
*/
nodeClose(data, node, self) {
let selType = this.selectType;
if (data.storeId) {
data.disabled = selType == 'person';
} else {
let fbdList = this.forbidenList;
let isForbiden = fbdList.indexOf(data.id) > -1;
data.disabled = data.hasPression != 1 || isForbiden || selType == 'store' || selType == 'person';
}
},
/**
* 关键词搜索
*/
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1 || (data.phoneNumber || '').indexOf(value) !== -1;
},
/**
* 删除已选项
*/
delSelected(obj) {
let that = this;
if (obj == 'empty') {
for (let index = 0; index < that.selectedList.length; index++) {
that.selectedList.splice(index, 1);
index--;
}
this.$refs.tree.setCheckedNodes(that.selectedList);
} else {
let index = this.selectedList.indexOf(obj);
this.selectedList.splice(index, 1);
this.$refs.tree.setCheckedNodes(this.selectedList);
}
},
/**
* 外抛已选的数据
*/
submitSelected() {
this.$emit('handleSelectedList', this.selectedList);
this.treeSet.dialogVisible = false;
},
/**
* 选择品牌
*/
selectBrand(val) {
this.menuData = [this.brands[val]]; // 默认品牌数据为分组第一层数据
this.brands[val].hasLoad = true;
this.firstRender = true;
if (this.selectType != 'group') {
// 如果选择的不是 group (即:只选分组)
this.getStoreList(this.menuData[0]);
}
this.renderDefault();
},
/**
* 渲染回显数据
*/
renderDefault() {
let that = this;
that.$nextTick(() => {
let list = that.defaultList;
that.selectedList = list;
if (!!list.length) {
that.$refs.tree.setCheckedNodes(list);
}
list.forEach(item => {
if (item.employeeClerkId) {
that.defaultOpen = [item.storeId];
} else if (!item.storeId && !item.employeeClerkId) {
that.defaultOpen.push(that.menusObj[item.id].parentId);
}
});
});
}
},
beforeMount() {
this.getGroupData();
},
/* eslint-disable */
mounted() {
// this.renderDefault();
// 为了切换路由后可以重新选择品牌
let that = this;
if (!!that.currentBrand) {
setTimeout(() => {
that.brands.forEach((ele,index) => {
if(ele.id == that.currentBrand) { // 目前有些问题,brands 中只有groupId ,没有 brandId
that.brandSelection = index; // 之前 that.brandSelection 都是取得索引值,不是 id 值
}
})
that.selectBrand(that.brandSelection);
}, 500);
}
},
watch: {
searchText(newK, old) {
this.$refs.tree.filter(newK);
},
defaultList: {
handler(newValue, oldValue) {
if (!!this.$refs.tree) {
this.renderDefault();
}
},
deep: true
},
treeSet: {
handler(newValue, oldValue) {
if (newValue.dialogVisible && !this.hasOpened) {
this.hasOpened = true;
this.renderDefault();
}
},
deep: true
},
// 应用中使用到,需要禁止选择品牌,品牌的 brandId 外部传进来的需要是 groupId,然后对比当前组件内的 groupId;
currentBrand: function(newData, oldData) {
let that = this;
if (!!newData) {
that.brands.forEach((ele,index) => {
if(ele.id == newData) { // 目前有些问题,brands 中只有groupId ,没有 brandId
that.brandSelection = index; // 之前 that.brandSelection 都是取得索引值,不是 id 值
}
})
that.$nextTick(function () {
that.selectBrand(that.brandSelection);
})
}
}
},
destroyed() {
this.brandSelection = '';
},
};
</script>
<style lang="scss">
.p-b-10 {
padding-bottom: 10px;
}
.transfer-area {
display: flex;
margin-bottom: 40px;
.t-a-select {
width: 300px;
height: 415px;
background: rgba(255, 255, 255, 1);
border: 1px solid rgba(220, 223, 230, 1);
border-radius: 4px;
overflow: hidden;
&:first-child {
margin-right: 20px;
}
> .title {
width: 100%;
height: 42px;
line-height: 42px;
background: rgba(245, 247, 250, 1);
border-bottom: 1px solid rgba(220, 223, 230, 1);
border-radius: 4px;
text-indent: 15px;
color: #303133;
font-size: 16px;
.J_del-all {
font-size: 14px;
color: #409eff;
float: right;
cursor: pointer;
margin-right: 15px;
}
}
.tree-div {
width: 100%;
height: 373px;
overflow: auto;
padding: 15px;
box-sizing: border-box;
.search-menu {
margin-top: 20px;
color: #606266;
font-size: 14px;
min-width: 100%;
display: inline-block !important;
.el-tree-node {
.el-tree-node__content {
height: 36px;
position: relative;
.open-child {
position: absolute;
right: 0;
top: 0;
width: 36px;
height: 36px;
padding: 0;
box-sizing: border-box;
}
.custom-tree-node {
flex: 1;
height: 100%;
line-height: 36px;
.open-btn {
width: 50px;
height: 14px;
color: #409eff;
float: right;
text-align: right;
border-left: 1px solid #dcdfe6;
margin-top: 11px;
line-height: 14px;
}
&.disable-open {
z-index: 999;
}
}
&:hover {
background: none;
}
}
}
}
.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
background: none;
}
}
.selected-list {
.list {
padding: 12px 0;
display: flex;
.label {
flex: 1;
.iconfont {
color: #409eff;
margin-right: 5px;
}
}
.close-btn {
width: 16px;
height: 16px;
line-height: 18px;
text-align: center;
cursor: pointer;
border-radius: 100%;
font-size: 8px;
vertical-align: middle;
&:hover {
color: #fff;
background: #909399;
}
}
}
}
}
}
</style>
<template>
<el-dialog :title="treeSet.isSelectPerson ? '选择人员' : '选择部门'" width="660px" :visible.sync="treeSet.dialogVisible">
<div class="transfer-area">
<div class="select-area t-a-select">
<p class="title">选择</p>
<div class="tree-div">
<div class="input-container">
<el-input v-model="searchText" placeholder="请输入内容"></el-input>
</div>
<div class="select-div" style="width: 100%;">
<el-select v-model="brandSelection" :disabled="!!currentBrand ? true : false" placeholder="请选择品牌" @change="selectBrand" style="width: 100%;margin-top:20px;">
<el-option v-for="item in brands" :key="item.id" :label="item.label" :value="index">
{{ item.label }}
</el-option>
</el-select>
</div>
<el-tree class="search-menu" node-key="id" ref="tree" :check-strictly="true" :default-expanded-keys="defaultOpen" :data="menuData" show-checkbox :highlight-current="true" :expand-on-click-node="false" icon-class="open-child" :props="myProps" :filter-node-method="filterNode" @check-change="getCurrentNode" @node-expand="nodeOpen" @node-collapse="nodeClose" @node-click="handleNodeClick">
<span class="custom-tree-node" :class="data.disableOpen ? 'disable-open' : ''" slot-scope="{ node, data }">
<span>{{ data.label }}</span>
<span class="open-btn" v-if="!!data.childrens">
<el-button @click="nodeOpen(data, node)" :disabled="data.disableOpen" type="text" size="small">下级</el-button>
</span>
</span>
</el-tree>
</div>
</div>
<div class="selected-area t-a-select">
<p class="title">
已选
<a class="J_del-all" @click="delSelected('empty')">全部清除</a>
</p>
<div class="tree-div">
<ul class="selected-list">
<template v-if="selectedList.length > 0">
<li v-for="li in selectedList" class="list group-li" :class="li.groupId ? 'group-li' : 'person-li'" :key="li.id + li.label">
<div class="label"><i class="iconfont" :class="li.groupId ? 'icon-tongshi-zuzhijiagou' : 'icon-chengyuan'"></i>{{ li.label }}</div>
<div class="close-btn" @click="delSelected(li)">
<i class="el-icon-close"></i>
</div>
</li>
</template>
</ul>
</div>
</div>
</div>
<div class="btn-box t-rt p-b-10">
<el-button @click="treeSet.dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitSelected">确定</el-button>
</div>
</el-dialog>
</template>
<script>
import { getRequest } from '@/api/api';
export default {
name: 'vue-select-store',
props: {
treeSet: {
type: Object,
default() {
return {
isSelectPerson: true,
dialogVisible: false,
isSingle: false // 是否单选
};
}
},
currentBrand: {
// 当前传入的品牌 id
type: String,
default() {
return '';
}
},
selectType: {
type: String,
default: 'all' // all 所有都可选, person 只选人, store 只选门店, group 只选分组, group-store 选门店/分组
},
forbidenList: {
// 传入需要禁用的分组的id
type: Array,
default() {
return [];
}
},
visibleNodes: {
type: [Array, String], // 设置仅可见的节点,如果不传则默认展示所有
default() {
return '';
}
},
defaultList: {
// 回显数据
type: Array,
default() {
return [];
}
},
appScene: {
// 使用场景
type: [String, Number],
default: ''
}
},
data() {
return {
searchText: '',
myProps: {
children: 'childrens',
label: 'label',
disabled: 'disabled'
},
menuData: [],
menusObj: {},
defaultOpen: [], // 默认展开节点的 key 的数组
selectedList: [],
brandSelection: 0, // 看了代码发现这里是取的索引值,不是品牌 id
brands: [],
hasOpened: false,
firstRender: true, // 判断是否是第一次渲染数据,用于切换品牌时判断
renderFlag: true // 应用判断渲染
};
},
methods: {
/**
* 获取分组架构
*/
getGroupData() {
let that = this;
let params = {
isStoreGroup: 1,
appScene: that.appScene
};
getRequest('/haoban-manage-web/dept/deptList', params)
.then(res => {
let treeData = [];
if (res.data.errorCode == 1) {
treeData = res.data.result || [];
that.formatGroupData(treeData);
}
})
.catch(e => {});
},
/**
* 处理获取分组数据
*/
formatGroupData(data) {
let that = this;
let selType = that.selectType; // 传入:选择门店的类型(all 所有都可选, person 只选人,store 只选门店, group 只选分组, group-store 选门店/分组)
let fbdList = that.forbidenList; // 传入: 需要禁用的分组的 id
that.menusObj = {};
data.forEach(group => {
group.label = group.name || ''; // 新增
group.id = group.groupId || ''; // 新增
group.disableOpen = false; // 新增
let isForbiden = !!(fbdList.indexOf(group.id) > -1); // 判断当前分组是否在禁用分组列表内
group.disabled = group.hasPression != 1 || selType == 'person' || selType == 'store' || isForbiden; // 新增
let arr = [];
data.forEach(child => {
child.disableOpen = false;
child.disabled = child.hasPression != 1 || selType == 'person' || selType == 'store' || isForbiden;
if (child.parentId == group.groupId) {
arr.push(child);
}
});
// 把简单 json 数组转换成 父子关系的 json
if (arr.length > 0) {
group.childrens = arr;
} else if (group.level != 0 && that.selectType != 'group') {
group.childrens = [{ label: '' }];
group.isLast = true;
}
if (group.level == 0) {
// 禁用分组
group.disabled = (group.childrens && group.childrens.length > 0) || (group.hasPression != 1 || selType == 'person' || selType == 'store' || isForbiden);
group.hasLoad = true;
that.brands.push(group);
if (group.childrens) {
that.defaultOpen.push(group.id);
}
}
that.menusObj[group.id] = group;
});
that.menuData = [that.brands[0]]; // 设置树形结构数据
if (selType != 'group') {
this.getStoreList(that.menuData[0]);
}
},
/**
* 树形菜单选择
*/
handleNodeClick(obj, node) {
this.$emit('handleTreeSelection', obj, node, 'node');
},
/**
* 获取当前复选框状态改变的节点,如果被选中,将禁用展开
*/
getCurrentNode(data, ifChecked, son) {
data.disableOpen = ifChecked;
this.selectedList = this.$refs.tree.getCheckedNodes();
if (this.treeSet.isSingle && this.selectedList.length > 1) {
let index = this.selectedList.indexOf(data);
this.selectedList.splice(1 - index, 1);
this.$refs.tree.setCheckedNodes(this.selectedList);
}
},
/**
* 节点展开时,禁用复选框
*/
nodeOpen(node, data) {
node.disabled = true;
if (!node.hasLoad && this.selectType != 'group') {
this.getStoreList(node);
node.hasLoad = true; // 标记为已经请求过子分组数据,下次展开不再请求
}
},
/**
* 获取门店列表
*/
getStoreList(parent) {
let that = this;
let params = {
storeGroupId: parent.groupId,
showChild: 0,
pageNumber: 1,
pageSize: 1000000000, // 因为获取门店列表做了分页,所以取了一个极限值
showType: 2
};
getRequest('/haoban-manage-web/store/findSimplePage', params)
.then(res => {
let storeList = [];
if (res.data.errorCode == 1) {
storeList = res.data.result.list == null ? [] : res.data.result.list;
that.formatStoreList(storeList, parent);
if (that.$refs.tree) {
that.renderDefault();
}
that.renderFlag = false; // 应用中使用:设置默认参数,默认情况传入品牌的 groupId ,不再去请求门店数据,切换的时候再去请求
}
})
.catch(e => {});
},
/**
* 处理获取门店列表的数据
*/
formatStoreList(list, parent) {
let that = this;
let type = this.selectType;
list.forEach(li => {
li.id = li.storeId;
li.label = li.storeName;
li.hasLoad = true;
li.disabled = !!(type == 'person');
if (li.clerks.length && (type == 'all' || type == 'person')) {
li.clerks.forEach(clerks => {
clerks.label = clerks.name;
clerks.id = clerks.employeeClerkId;
});
li.childrens = li.clerks;
}
});
if (parent.isLast) {
// 应该是判断是不是最后一层
parent.childrens = list;
} else {
// 现在问题是每次都追加数据了
let arr = !!parent.childrens ? parent.childrens : [];
arr = arr.concat(list);
let hash = {};
// 去重数组对象
arr = arr.reduce(function(item, next) {
hash[next.storeId] ? '' : (hash[next.storeId] = true && item.push(next));
return item;
}, []);
parent.childrens = JSON.parse(JSON.stringify(arr));
// parent.isLast = true; // 追加后重新设置isLast
that.$forceUpdate();
}
if (parent.childrens.length > 0 && this.firstRender) {
this.firstRender = false;
this.defaultOpen.push(parent.id);
}
that.$forceUpdate();
that.$nextTick(() => {
that.menuData = JSON.parse(JSON.stringify(that.menuData));
}); // this.renderDefault();
that.$forceUpdate();
},
/**
* 节点关闭时,取消复选框的禁用
*/
nodeClose(data, node, self) {
let selType = this.selectType;
if (data.storeId) {
data.disabled = selType == 'person';
} else {
let fbdList = this.forbidenList;
let isForbiden = fbdList.indexOf(data.id) > -1;
data.disabled = data.hasPression != 1 || isForbiden || selType == 'store' || selType == 'person';
}
},
/**
* 关键词搜索
*/
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1 || (data.phoneNumber || '').indexOf(value) !== -1;
},
/**
* 删除已选项
*/
delSelected(obj) {
if (obj == 'empty') {
this.$refs.tree.setCheckedKeys(this.selectedList, false);
this.selectedList = this.$refs.tree.getCheckedNodes();
} else {
let index = this.selectedList.indexOf(obj);
this.selectedList.splice(index, 1);
this.$refs.tree.setCheckedNodes(this.selectedList);
}
},
/**
* 外抛已选的数据
*/
submitSelected() {
this.$emit('handleSelectedList', this.selectedList);
this.treeSet.dialogVisible = false;
},
/**
* 选择品牌
*/
selectBrand(id) {
let val = null;
this.brands.forEach((item, ind) => {
if (item.id === id) {
val = ind;
}
});
this.menuData = [this.brands[val]]; // 默认品牌数据为分组第一层数据
this.brands[val].hasLoad = true;
this.firstRender = true;
if (this.selectType != 'group') {
// 如果选择的不是 group (即:只选分组)
this.getStoreList(this.menuData[0]);
}
this.renderDefault();
},
/**
* 渲染回显数据
*/
renderDefault() {
let that = this;
that.$nextTick(() => {
let list = that.defaultList;
that.selectedList = list;
if (!!list.length) {
that.$refs.tree.setCheckedNodes(list);
}
list.forEach(item => {
if (item.employeeClerkId) {
that.defaultOpen = [item.storeId];
} else if (!item.storeId && !item.employeeClerkId) {
that.defaultOpen.push(that.menusObj[item.id].parentId);
}
});
});
}
},
beforeMount() {
this.getGroupData();
},
/* eslint-disable */
mounted() {
// this.renderDefault();
// 为了切换路由后可以重新选择品牌
let that = this;
if (!!that.currentBrand) {
setTimeout(() => {
that.brands.forEach((ele,index) => {
if(ele.id == that.currentBrand) { // 目前有些问题,brands 中只有groupId ,没有 brandId
that.brandSelection = index; // 之前 that.brandSelection 都是取得索引值,不是 id 值
}
})
that.selectBrand(that.brandSelection);
}, 500);
}
},
watch: {
searchText(newK, old) {
this.$refs.tree.filter(newK);
},
defaultList: {
handler(newValue, oldValue) {
if (!!this.$refs.tree) {
this.renderDefault();
}
},
deep: true
},
treeSet: {
handler(newValue, oldValue) {
if (newValue.dialogVisible && !this.hasOpened) {
this.hasOpened = true;
this.renderDefault();
}
},
deep: true
},
// 应用中使用到,需要禁止选择品牌,品牌的 brandId 外部传进来的需要是 groupId,然后对比当前组件内的 groupId;
currentBrand: function(newData, oldData) {
let that = this;
if (!!newData) {
that.brands.forEach((ele,index) => {
if(ele.id == newData) { // 目前有些问题,brands 中只有groupId ,没有 brandId
that.brandSelection = index; // 之前 that.brandSelection 都是取得索引值,不是 id 值
}
})
that.$nextTick(function () {
that.selectBrand(that.brandSelection);
})
}
}
},
destroyed() {
this.brandSelection = '';
},
};
</script>
<style lang="scss">
.p-b-10 {
padding-bottom: 10px;
}
.transfer-area {
display: flex;
margin-bottom: 40px;
.t-a-select {
width: 300px;
height: 415px;
background: rgba(255, 255, 255, 1);
border: 1px solid rgba(220, 223, 230, 1);
border-radius: 4px;
overflow: hidden;
&:first-child {
margin-right: 20px;
}
> .title {
width: 100%;
height: 42px;
line-height: 42px;
background: rgba(245, 247, 250, 1);
border-bottom: 1px solid rgba(220, 223, 230, 1);
border-radius: 4px;
text-indent: 15px;
color: #303133;
font-size: 16px;
.J_del-all {
font-size: 14px;
color: #409eff;
float: right;
cursor: pointer;
margin-right: 15px;
}
}
.tree-div {
width: 100%;
height: 373px;
overflow: auto;
padding: 15px;
box-sizing: border-box;
.search-menu {
margin-top: 20px;
color: #606266;
font-size: 14px;
min-width: 100%;
display: inline-block !important;
.el-tree-node {
.el-tree-node__content {
height: 36px;
position: relative;
.open-child {
position: absolute;
right: 0;
top: 0;
width: 36px;
height: 36px;
padding: 0;
box-sizing: border-box;
}
.custom-tree-node {
flex: 1;
height: 100%;
line-height: 36px;
.open-btn {
width: 50px;
height: 14px;
color: #409eff;
float: right;
text-align: right;
border-left: 1px solid #dcdfe6;
margin-top: 11px;
line-height: 14px;
}
&.disable-open {
z-index: 999;
}
}
&:hover {
background: none;
}
}
}
}
.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
background: none;
}
}
.selected-list {
.list {
padding: 12px 0;
display: flex;
.label {
flex: 1;
.iconfont {
color: #409eff;
margin-right: 5px;
}
}
.close-btn {
width: 16px;
height: 16px;
line-height: 18px;
text-align: center;
cursor: pointer;
border-radius: 100%;
font-size: 8px;
vertical-align: middle;
&:hover {
color: #fff;
background: #909399;
}
}
}
}
}
}
</style>
<template>
<el-dialog :title="treeSet.isSelectPerson ? '选择人员' : '选择部门'" width="660px" :visible.sync="treeSet.dialogVisible">
<div class="transfer-area">
<div class="select-area t-a-select">
<p class="title">选择</p>
<div class="tree-div">
<div class="input-container">
<el-input v-model="searchText" placeholder="请输入内容"></el-input>
</div>
<div class="select-div" style="width: 100%;">
<el-select v-model="brandSelection" :disabled="(!!currentBrand ? true : false) || (treeSet.storeType == 'addClerk' ? true : false)" placeholder="请选择品牌" @change="selectBrand" style="width: 100%;margin-top:20px;">
<el-option v-for="(item, index) in brands" :key="item.id" :label="item.label" :value="index">
{{ item.label }}
</el-option>
</el-select>
</div>
<!-- :default-expanded-keys="defaultOpen" -->
<el-tree class="search-menu" node-key="id" ref="tree" :check-strictly="true" :data="menuData" show-checkbox :highlight-current="true" :expand-on-click-node="false" icon-class="open-child" :props="myProps" :filter-node-method="filterNode" @check-change="getCurrentNode" @node-expand="nodeOpen" @node-collapse="nodeClose" @node-click="handleNodeClick">
<span class="custom-tree-node" :class="data.disableOpen ? 'disable-open' : ''" slot-scope="{ node, data }">
<span :datap="data.childrens">{{ data.label }}</span>
<span class="open-btn" v-if="!!data.childrens">
<!-- && !!data.childrens[0].groupId" && !!data.childrens.length-->
<el-button :datatype="data.disableOpen" @click="nodeOpen(data, node)" :disabled="data.disableOpen" type="text" size="small">下级</el-button>
</span>
</span>
</el-tree>
</div>
</div>
<div class="selected-area t-a-select">
<p class="title">
已选
<a class="J_del-all" @click="delSelected('empty')">全部清除</a>
</p>
<div class="tree-div">
<ul class="selected-list">
<template v-if="selectedList.length > 0">
<li v-for="li in selectedList" class="list group-li" :class="li.groupId ? 'group-li' : 'person-li'" :key="li.id + li.label">
<div class="label"><i class="iconfont" :class="li.groupId ? 'icon-tongshi-zuzhijiagou' : 'icon-chengyuan'"></i>{{ li.label }}</div>
<div class="close-btn" @click="delSelected(li)">
<i class="el-icon-close"></i>
</div>
</li>
</template>
</ul>
</div>
</div>
</div>
<div class="btn-box t-rt p-b-10">
<el-button @click="treeSet.dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitSelected">确定</el-button>
</div>
</el-dialog>
</template>
<script>
import { getRequest } from '@/api/api';
import { _throttle } from '@/common/js/public';
export default {
name: 'vue-select-employee',
props: {
treeSet: {
type: Object,
default() {
return {
isSelectPerson: true,
dialogVisible: false,
isSingle: false // 是否单选
};
}
},
currentBrand: {
// 当前传入的品牌 id
type: String,
default() {
return '';
}
},
selectType: {
type: String,
default: 'all' // all 所有都可选, person 只选人, store 只选门店, group 只选分组, group-store 选门店/分组
},
forbidenList: {
// 传入需要禁用的分组的id
type: Array,
default() {
return [];
}
},
visibleNodes: {
type: [Array, String], // 设置仅可见的节点,如果不传则默认展示所有
default() {
return '';
}
},
defaultList: {
// 回显数据
type: Array,
default() {
return [];
}
},
appScene: {
// 使用场景
type: [String, Number],
default: ''
}
},
data() {
return {
searchText: '',
myProps: {
children: 'childrens',
label: 'label',
disabled: 'disabled'
},
menuData: [],
menusObj: {},
defaultOpen: [], // 默认展开节点的 key 的数组
selectedList: [], // 已经选择的数据集合
brandSelection: 0, // 看了代码发现这里是取的索引值,不是品牌 id
brands: [],
hasOpened: false,
firstRender: true, // 判断是否是第一次渲染数据,用于切换品牌时判断
renderFlag: true, // 应用判断渲染
storeList: []
};
},
methods: {
/**
* 获取分组架构
*/
getGroupData() {
let that = this;
let params = {
isStoreGroup: 1,
appScene: that.appScene
};
getRequest('/haoban-manage-web/dept/deptList', params)
.then(res => {
let treeData = [];
if (res.data.errorCode == 1) {
treeData = res.data.result || [];
that.formatGroupData(treeData);
}
})
.catch(e => {});
},
/**
* 处理获取分组数据
*/
formatGroupData(data) {
let that = this;
let selType = that.selectType; // 传入:选择门店的类型(all 所有都可选, person 只选人,store 只选门店, group 只选分组, group-store 选门店/分组)
let fbdList = that.forbidenList; // 传入: 需要禁用的分组的 id
that.menusObj = {};
data.forEach(group => {
group.label = group.name || ''; // 新增
group.id = group.groupId || ''; // 新增
group.disableOpen = false; // 新增
let isForbiden = !!(fbdList.indexOf(group.id) > -1); // 判断当前分组是否在禁用分组列表内
group.disabled = group.hasPression != 1 || selType == 'person' || selType == 'store' || isForbiden; // 新增
let arr = [];
data.forEach(child => {
child.disableOpen = false;
child.disabled = child.hasPression != 1 || selType == 'person' || selType == 'store' || isForbiden;
if (child.parentId == group.groupId) {
arr.push(child);
}
});
// 把简单 json 数组转换成 父子关系的 json
if (arr.length > 0) {
group.childrens = arr;
} else if (group.level != 0 && that.selectType != 'group') {
group.childrens = [{ label: '' }]; // 默认有子级 { label: '' }
group.isLast = true;
}
if (group.level == 0) {
// 禁用分组
group.disabled = (group.childrens && group.childrens.length > 0) || (group.hasPression != 1 || selType == 'person' || selType == 'store' || isForbiden);
// console.log(group.disabled, group.childrens && group.childrens.length > 0, group.hasPression != 1 || selType == 'person' || selType == 'store' || isForbiden);
group.hasLoad = true;
that.brands.push(group);
if (group.childrens) {
that.defaultOpen.push(group.id);
}
}
that.menusObj[group.id] = group;
});
let brandSelectionId = that.treeSet.groupId ? that.treeSet.groupId : that.brands[0].id;
that.brands.forEach((el, idx) => {
if (el.id == brandSelectionId) {
that.brandSelection = idx;
}
});
that.menuData = [that.brands[that.brandSelection]]; // 设置树形结构数据
if (selType != 'group') {
// && that.treeSet.storeType != 'addClerk'
this.getStoreList(that.menuData[0]);
}
},
/**
* 树形菜单选择
*/
handleNodeClick(obj, node) {
this.$emit('handleTreeSelection', obj, node, 'node');
},
/**
* 获取当前复选框状态改变的节点,如果被选中,将禁用展开
*/
getCurrentNode: _throttle(function(data, ifChecked, son) {
// console.log('复选框状态变化:', data, ifChecked, son); // 之前会重复触发,原来是每次变化触发了监听 defaultList 方法
let that = this;
data.disableOpen = ifChecked;
that.$nextTick(() => {
that.selectedList = that.$refs.tree.getCheckedNodes();
if (that.treeSet.isSingle && that.selectedList.length > 1) {
let index = that.selectedList.indexOf(data);
that.selectedList.splice(1 - index, 1);
that.$refs.tree.setCheckedNodes(that.selectedList);
}
});
}, 100),
/**
* 节点展开时,禁用复选框
*/
nodeOpen(data, node) {
// 如果是第一级(顶级分组即品牌)展开下级,禁用复选框
if (data.level == 0) {
data.disabled = true;
}
// 如果不是第一级不是门店,展开下级,禁用复选框
if (data.level != 0 && data.type != 1) {
data.disabled = true;
}
// 如果是首次追加的空数据,先把 childrens 清空;
if (data.childrens[0].label == '') {
data.childrens = [];
}
// data.disabled = true;
// console.log('节点展开时,禁用复选框:', data, !data.hasLoad, this.selectType != 'group', this.treeSet.storeType, this.treeSet.openNextBool);
// openNextBool 没有设置 , 并且当前选择不是选分组, 并且不是添加店员
if (!data.hasLoad && this.selectType != 'group' && this.treeSet.storeType != 'addClerk' && !this.treeSet.openNextBool) {
this.getStoreList(data, 'openFlag');
data.hasLoad = true; // 标记为已经请求过子分组数据,下次展开不再请求
}
// openNextBool 已经设置 , 并且当前选择不是选分组, 并且不是添加店员
if (!data.hasLoad && this.selectType != 'group' && this.treeSet.storeType != 'addClerk' && this.treeSet.openNextBool) {
this.getStoreList(data, 'openFlag');
data.hasLoad = true; // 标记为已经请求过子分组数据,下次展开不再请求
}
if (this.treeSet.storeType == 'addClerk' && !data.hasLoad) {
this.getStoreList(data, 'openFlag');
data.hasLoad = true; // 标记为已经请求过子分组数据,下次展开不再请求
}
},
/**
* 获取门店列表
*/
getStoreList(parent, flag) {
let that = this;
let params = {
storeGroupId: parent.groupId,
showChild: 0,
pageNumber: 1,
pageSize: 1000000000, // 因为获取门店列表做了分页,所以取了一个极限值
showType: 2
};
getRequest('/haoban-manage-web/store/findSimplePage', params)
.then(res => {
let storeList = [];
if (res.data.errorCode == 1) {
if (parent.level != 0) {
parent.disabled = !!res.data.result.list && !!flag ? true : false;
}
that.$forceUpdate();
storeList = res.data.result.list == null ? [] : res.data.result.list;
that.storeList = res.data.result.list == null ? [] : res.data.result.list;
if (!res.data.result.list || !res.data.result.list.length) {
return false;
}
that.formatStoreList(storeList, parent);
if (that.$refs.tree) {
that.renderDefault();
}
that.renderFlag = false; // 应用中使用:设置默认参数,默认情况传入品牌的 groupId ,不再去请求门店数据,切换的时候再去请求
}
})
.catch(e => {});
},
/**
* 处理获取门店列表的数据
*/
formatStoreList(list, parent) {
let that = this;
let type = this.selectType;
list.forEach(li => {
li.id = li.storeId;
li.label = li.storeName;
li.hasLoad = true;
li.disabled = !!(type == 'person');
if (li.clerks.length && (type == 'all' || type == 'person')) {
li.clerks.forEach(clerks => {
clerks.label = clerks.name;
clerks.id = clerks.employeeClerkId;
});
li.childrens = li.clerks;
}
});
that.appendStore(list, parent);
},
// 追加当前门店
appendStore(list, parent) {
let that = this;
if (parent.isLast) {
// 应该是判断是不是最后一层
parent.childrens = list;
} else {
// 现在问题是每次都追加数据了
let arr = !!parent.childrens ? parent.childrens : [];
arr = arr.concat(list);
let hash = {};
// 去重数组对象
arr = arr.reduce(function(item, next) {
hash[next.id] ? '' : (hash[next.id] = true && item.push(next));
return item;
}, []);
parent.childrens = JSON.parse(JSON.stringify(arr));
// parent.isLast = true; // 追加后重新设置isLast
that.$forceUpdate();
}
if (parent.childrens.length > 0 && this.firstRender) {
this.firstRender = false;
this.defaultOpen.push(parent.id);
}
that.$forceUpdate();
//that.$nextTick(() => {
// that.menuData = JSON.parse(JSON.stringify(that.menuData));
//}); // this.renderDefault();
},
/**
* 节点关闭时,取消复选框的禁用
*/
nodeClose(data, node, self) {
let selType = this.selectType;
if (data.storeId) {
data.disabled = selType == 'person';
} else {
let fbdList = this.forbidenList;
let isForbiden = fbdList.indexOf(data.id) > -1;
data.disabled = data.hasPression != 1 || isForbiden || selType == 'store' || selType == 'person';
}
},
/**
* 关键词搜索
*/
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1 || (data.phoneNumber || '').indexOf(value) !== -1;
},
/**
* 删除已选项
*/
delSelected(obj) {
let that = this;
if (obj == 'empty') {
for (let index = 0; index < that.selectedList.length; index++) {
that.selectedList.splice(index, 1);
index--;
}
this.$refs.tree.setCheckedNodes(that.selectedList);
} else {
let index = this.selectedList.indexOf(obj);
this.selectedList.splice(index, 1);
this.$refs.tree.setCheckedNodes(this.selectedList);
}
},
/**
* 外抛已选的数据
*/
submitSelected() {
this.$emit('handleSelectedList', this.selectedList);
this.treeSet.dialogVisible = false;
},
/**
* 选择品牌
*/
selectBrand(val) {
this.menuData = [this.brands[val]]; // 默认品牌数据为分组第一层数据
this.brands[val].hasLoad = true;
this.firstRender = true;
if (this.selectType != 'group') {
// 如果选择的不是 group (即:只选分组)
this.getStoreList(this.menuData[0]);
}
this.renderDefault();
},
/**
* 渲染回显数据
*/
renderDefault() {
let that = this;
that.$nextTick(() => {
let list = that.selectedList;
if (!!list.length) {
that.$refs.tree.setCheckedNodes(list);
}
list.forEach(item => {
if (item.employeeClerkId) {
that.defaultOpen = [item.storeId];
} else if (!item.storeId && !item.employeeClerkId) {
if (!!that.menusObj[item.id]) {
that.defaultOpen.push(that.menusObj[item.id].parentId);
}
}
});
});
}
},
beforeMount() {
this.getGroupData();
},
/* eslint-disable */
mounted() {
// this.renderDefault();
// 为了切换路由后可以重新选择品牌
let that = this;
if (!!that.currentBrand) {
setTimeout(() => {
that.brands.forEach((ele,index) => {
if(ele.id == that.currentBrand) { // 目前有些问题,brands 中只有groupId ,没有 brandId
that.brandSelection = index; // 之前 that.brandSelection 都是取得索引值,不是 id 值
}
})
that.selectBrand(that.brandSelection);
}, 500);
}
},
watch: {
searchText(newK, old) {
this.$refs.tree.filter(newK);
},
defaultList: {
handler(newValue, oldValue) {
// 每次选择确认后,发现后端接口返回的数据和,这时候确认后返回的数据是不一样的;
// console.log("defaultList 变化了:",newValue,oldValue); // 发现每次复选框状态变了这里也触发了,所以修改
let that = this;
if (!!newValue.length) {
that.selectedList = JSON.parse(JSON.stringify(newValue));
}
if (!!that.$refs.tree) {
that.renderDefault();
}
}
},
treeSet: {
handler(newValue, oldValue) {
if (newValue.dialogVisible && !this.hasOpened) {
this.hasOpened = true;
this.renderDefault();
}
},
deep: true
},
// 应用中使用到,需要禁止选择品牌,品牌的 brandId 外部传进来的需要是 groupId,然后对比当前组件内的 groupId;
currentBrand: function(newData, oldData) {
let that = this;
if (!!newData) {
that.brands.forEach((ele,index) => {
if(ele.id == newData) { // 目前有些问题,brands 中只有groupId ,没有 brandId
that.brandSelection = index; // 之前 that.brandSelection 都是取得索引值,不是 id 值
}
})
that.$nextTick(function () {
that.selectBrand(that.brandSelection);
})
}
}
},
destroyed() {
this.brandSelection = '';
},
};
</script>
<style lang="scss">
.p-b-10 {
padding-bottom: 10px;
}
.transfer-area {
display: flex;
margin-bottom: 40px;
.t-a-select {
width: 300px;
height: 415px;
background: rgba(255, 255, 255, 1);
border: 1px solid rgba(220, 223, 230, 1);
border-radius: 4px;
overflow: hidden;
&:first-child {
margin-right: 20px;
}
> .title {
width: 100%;
height: 42px;
line-height: 42px;
background: rgba(245, 247, 250, 1);
border-bottom: 1px solid rgba(220, 223, 230, 1);
border-radius: 4px;
text-indent: 15px;
color: #303133;
font-size: 16px;
.J_del-all {
font-size: 14px;
color: #409eff;
float: right;
cursor: pointer;
margin-right: 15px;
}
}
.tree-div {
width: 100%;
height: 373px;
overflow: auto;
padding: 15px;
box-sizing: border-box;
.search-menu {
margin-top: 20px;
color: #606266;
font-size: 14px;
min-width: 100%;
display: inline-block !important;
.el-tree-node {
.el-tree-node__content {
height: 36px;
position: relative;
.open-child {
position: absolute;
right: 0;
top: 0;
width: 36px;
height: 36px;
padding: 0;
box-sizing: border-box;
}
.custom-tree-node {
flex: 1;
height: 100%;
line-height: 36px;
.open-btn {
width: 50px;
height: 14px;
color: #409eff;
float: right;
text-align: right;
border-left: 1px solid #dcdfe6;
margin-top: 11px;
line-height: 14px;
}
&.disable-open {
z-index: 999;
}
}
&:hover {
background: none;
}
}
}
}
.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
background: none;
}
}
.selected-list {
.list {
padding: 12px 0;
display: flex;
.label {
flex: 1;
.iconfont {
color: #409eff;
margin-right: 5px;
}
}
.close-btn {
width: 16px;
height: 16px;
line-height: 18px;
text-align: center;
cursor: pointer;
border-radius: 100%;
font-size: 8px;
vertical-align: middle;
&:hover {
color: #fff;
background: #909399;
}
}
}
}
}
}
</style>
......@@ -31,7 +31,10 @@ import vueGicImgPreview from '@gic-test/vue-gic-img-preview';
import vueOfficeUploadImage from '@gic-test/vue-office-upload-image';
import htmlToPdf from '@/components/utils/htmlToPdf';
import VueAMap from 'vue-amap';
import contentmenu from 'v-contextmenu'
import 'v-contextmenu/dist/index.css'
Vue.use(contentmenu);
Vue.use(VueAMap);
VueAMap.initAMapApiLoader({
key: 'd53a58848be368a7398dc56d5670fe9c',
......
......@@ -44,6 +44,11 @@ export const constantRouterMap = [
redirect: 'login'
},
{
path: '/tree',
name: '登录',
component: _import('login', 'tree')
},
{
path: '/login',
name: '登录',
component: _import('login', 'index')
......
......@@ -47,14 +47,6 @@
</div>
</template>
<script>
/* import 'swiper/dist/css/swiper.css';
import {
swiper,
swiperSlide
} from 'vue-awesome-swiper';
import countryMobile from '@/components/common/country-mobile.vue';
import verifyCode from '@/components/common/verify-code.vue';
import PhoneNumber from 'awesome-phonenumber'; */
import { _debounce } from '@/common/js/public';
import QRCode from 'qrcodejs2';
import errMsg from '@/common/js/error';
......@@ -75,10 +67,10 @@ export default {
// 企业列表
enterpriseList: [
/*{
enterpriseId : '1231',
logoUrl: require("../../assets/logo.png"),
enterpriseName: '达摩网络'
},*/
enterpriseId : '1231',
logoUrl: require("../../assets/logo.png"),
enterpriseName: '达摩网络'
},*/
],
// 登录
......@@ -94,9 +86,9 @@ export default {
const that = this;
// 模拟检查数据,有两个参数
/*{
name:,
path:
}*/
name:,
path:
}*/
that.$router.push({
path: val.path
});
......
<!--
* @Descripttion: 当前组件信息
* @version: 1.0.0
* @Author: 无尘
* @Date: 2019-08-14 16:51:07
* @LastEditors : 无尘
* @LastEditTime : 2020-01-14 14:44:57
-->
<!--
<org-tree v-if="item.children.length" :itemData="item.children" ></org-tree>
import orgTree from './org-tree.vue';
-->
<template>
<ul class="m-l-10">
<draggable :list="itemData" class="org-component" :options="leftOption" :move="onMove" @start="isDragging = true" @end="itemMoveEnd">
<li v-for="(item, index) in itemData" :key="index + 'gic'">
<div class="li-cell cursor-pointer" @click="toggleExpand(item)">{{ item.label }}</div>
<li-row v-show="!!item.children.length && item.expand" :itemData="item.children"></li-row>
</li>
</draggable>
</ul>
</template>
<script>
import draggable from 'vuedraggable';
export default {
name: 'li-row',
components: {
draggable
},
props: {
itemData: {
type: [Object, Array],
default() {
return [];
}
}
},
data() {
return {
// leftOption
leftOption: {
group: {
name: 'people',
pull: true,
put: false
},
sort: false,
disabled: false
}
};
},
methods: {
/**
* 展开或者关闭下级
*/
toggleExpand(item) {
console.log(item);
item.expand = item.expand ? false : true;
},
/**
* move{relatedContext, draggedContext}
*/
onMove(evt) {
// const that = this;
// 判断中间是否存在父级
const draggedElement = evt.draggedContext.element;
console.log(evt, !draggedElement.fixed);
return !draggedElement.fixed;
},
/**
* move end
*/
itemMoveEnd(evt) {
const that = this;
// 判断中间是否已经添加
console.log(that.itemData);
that.$forceUpdate();
}
},
watch: {
itemData: function(newData, oldData) {
const that = this;
that.trData = JSON.parse(JSON.stringify(newData));
}
},
mounted() {
const that = this;
that.trData = JSON.parse(JSON.stringify(that.itemData));
},
beforeDestroy() {
this.tempArr = [];
}
};
</script>
<style lang="less" scoped>
.li-cell {
line-height: 26px;
}
.w-110 {
width: 110px;
}
.w-320 {
width: 320px;
}
.m-t-14 {
margin-top: 14px;
}
.child-row {
padding-left: 10px;
}
</style>
<!--
* @Descripttion: 当前组件信息
* @version: 1.0.0
* @Author: 无尘
* @Date: 2018-10-10 14:44:45
* @LastEditors: 无尘
* @LastEditTime: 2018-10-10 14:44:45
-->
<template>
<div class="login-wrap">
<header>
<div class="login-wrap-header">
<img class="login-wrap-inline" src="../../assets/logo.png" alt="logo" />
<span class="login-wrap-inline">好办管理后台</span>
</div>
</header>
<section>
<!-- <ul class="list-content">
<draggable :list="gicData" class="compenent" :options="leftOption" :move="onMove" @start="isDragging = true" @end="itemMoveEnd">
<li v-for="(item, index) in gicData" :key="index + 'gic'">
<div class="li-cell">{{ item.label }}</div>
<org-tree v-if="item.children.length" :itemData="item.children"></org-tree>
</li>
</draggable>
</ul> -->
<org-tree :itemData="gicData"></org-tree>
<!-- <ul class="list-content">
<draggable :options="{ group: { name: 'people', pull: true, put: true }, sort: true }" v-model="wxData" class="drag-wrap">
<li v-for="(item, index) in wxData" :key="index + 'wx'">
<div class="li-cell">{{ item.label }}</div>
<wx-tree v-if="item.children.length" :itemData="item.children"></wx-tree>
</li>
</draggable>
</ul> -->
<wx-tree :itemData="wxData" v-model="wxData"></wx-tree>
<el-button type="primary" @click="getData">获取数据</el-button>
</section>
<footer class="p-t-35">
<vue-gic-footer></vue-gic-footer>
</footer>
</div>
</template>
<script>
import orgTree from './org-tree.vue';
import wxTree from './wx-tree.vue';
// import { _debounce } from '@/common/js/public';
// import errMsg from '@/common/js/error';
// import { postRequest } from '@/api/api';
export default {
name: 'login',
data() {
return {
// 企业列表
gicData: [
{
id: 1,
expand: false,
label: '总部1',
children: [
{
id: 11,
expand: false,
label: '总部11',
children: [
{
id: 111,
expand: false,
label: '总部111',
children: []
}
]
},
{
id: 12,
expand: false,
label: '总部12',
children: [
{
id: 121,
expand: false,
label: '总部121',
children: []
}
]
}
]
}
],
wxData: [
{
id: 2,
expand: false,
label: '总部2',
children: [
{
id: 21,
expand: false,
label: '总部21',
children: [
{
id: 211,
expand: true,
label: '总部211',
children: []
}
]
},
{
id: 22,
expand: false,
label: '总部22',
children: [
{
id: 221,
expand: true,
label: '总部221',
children: []
}
]
}
]
}
]
};
},
computed: {},
methods: {
getData() {
const that = this;
console.log(that.gicData, that.wxData);
},
/**
* 处理路由跳转
*/
toRouterView(val) {
const that = this;
// 模拟检查数据,有两个参数
that.$router.push({
path: val.path
});
}
},
mounted() {
// const that = this;
if (!!localStorage.getItem('userInfo')) {
localStorage.removeItem('userInfo');
}
},
components: {
orgTree,
wxTree
}
};
</script>
<style lang="less" scoped>
.list-content {
position: relative;
width: 500px;
height: 200px;
}
.li-cell {
line-height: 26px;
}
.flex {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.flex-column {
-webkit-flex-direction: column;
-moz-flex-direction: column;
-ms-flex-direction: column;
-o-flex-direction: column;
flex-direction: column;
}
.flex-row {
-webkit-flex-direction: row;
-moz-flex-direction: row;
-ms-flex-direction: row;
-o-flex-direction: row;
flex-direction: row;
}
.flex-align-center {
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
}
.flex-pack-center {
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
}
.flex-between {
-webkit-justify-content: space-between;
justify-content: space-between;
}
.p-lr-5 {
padding: 0 5px;
}
.color-676767 {
color: #676767;
}
.color-808080 {
color: #808080;
&.color-303133 {
color: #303133;
}
}
.login-wrap {
position: relative;
header {
width: 100%;
padding: 0;
margin: 0;
background: rgba(255, 255, 255, 1);
}
&-header {
width: 1400px;
height: 64px;
line-height: 64px;
padding: 0 0 0 60px;
margin: 0 auto;
background: rgba(255, 255, 255, 1);
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
/*-webkit-box-shadow: 0px 0px 10px rgba(147,165,184,0.13);
-moz-box-shadow: 0px 0px 10px rgba(147,165,184,0.13);
box-shadow: 0px 0px 10px rgba(147,165,184,0.13);*/
}
&-inline {
display: inline-block;
vertical-align: middle;
font-size: 20px;
color: #1f2f3d;
}
&-body {
width: 100%;
background: url('../../assets/login/banner.png') no-repeat center center;
background-size: auto 640px;
}
&-out {
position: relative;
width: 1400px;
height: 640px;
margin: 0 auto;
/*background: rgba(0,0,0,1);*/
}
&-inner {
position: absolute;
top: 140px;
right: 170px;
width: 303px;
height: 340px;
background: rgba(255, 255, 255, 1);
border: 1px solid rgba(235, 238, 245, 1);
border-radius: 4px;
-webkit-box-shadow: 2px 0px 12px rgba(6, 19, 33, 0.1);
-moz-box-shadow: 2px 0px 12px rgba(6, 19, 33, 0.1);
box-shadow: 2px 0px 12px rgba(6, 19, 33, 0.1);
&__block {
position: relative;
width: 100%;
height: 100%;
text-align: center;
}
&__head {
position: relative;
width: 100%;
height: 56px;
line-height: 56px;
border-bottom: 1px solid rgba(235, 238, 245, 1);
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
font-size: 18px;
color: #303133;
ul {
position: relative;
}
#line-active {
position: absolute;
bottom: 0;
left: 123px;
width: 56px;
height: 2px;
background: #1890ff;
z-index: 2;
transition: all 0.3s ease-in;
}
}
&__body {
position: relative;
width: 100%;
height: 317px;
text-align: center;
padding: 34px 0 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
.loginForm {
width: 100%;
padding: 0 20px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
.w-139 {
width: 139px;
}
.code-item {
text-align: left;
}
.el-button {
width: 100%;
padding: 0;
height: 40px;
line-height: 40px;
}
.el-input {
/deep/ .el-input__inner {
height: 40px;
line-height: 40px;
}
}
}
#qrcode {
width: 156px;
height: 156px;
margin: 0 auto;
}
}
&__title {
width: 100%;
margin-top: 20px;
font-size: 12px;
color: #606266;
&.m-t-5 {
margin-top: 5px;
}
.el-button {
font-size: 12px;
}
}
&__expired {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
position: absolute;
top: 34px;
left: 73px;
width: 157px;
height: 156px;
background: rgba(255, 255, 255, 1);
opacity: 0.9;
}
&__selectBody {
position: relative;
width: 100%;
height: 317px;
text-align: center;
padding: 32px 21px 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
.el-button--primary {
width: 100%;
margin-top: 27px;
}
}
&__swiper {
margin-top: 30px;
.swiper-cell {
cursor: pointer;
.swiper-slide-log_img {
padding: 6px;
border-radius: 8px;
text-align: center;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
&.defalut-bg {
padding: 25px;
background: #82c5ff;
-webkit-transform: scale(0.8);
-moz-transform: scale(0.8);
transform: scale(0.8);
i {
font-size: 35px;
color: #e5f3ff;
}
}
}
.img-bg {
background: #ededee;
-webkit-transform: scale(0.8);
-moz-transform: scale(0.8);
transform: scale(0.8);
}
&.current-item {
.swiper-slide-log_img {
-webkit-transform: scale(1);
-moz-transform: scale(1);
transform: scale(1);
&.defalut-bg {
/*padding: 25px;*/
-webkit-transform: scale(1);
-moz-transform: scale(1);
transform: scale(1);
}
}
}
}
.swiper-slide {
&__img {
width: 72px;
height: 72px;
border-radius: 8px;
}
&__p {
margin-top: 14px;
font-size: 14px;
color: #6b6d71;
}
}
.swiper-button-prev {
height: 97px;
margin-top: -66px;
left: 0;
padding-top: 55px;
background: #fff;
background-image: none;
i {
color: #303133;
}
}
.swiper-button-next {
height: 97px;
margin-top: -66px;
right: 0;
padding-top: 55px;
background: #fff;
background-image: none;
i {
color: #303133;
}
}
}
}
&-expired__title {
font-size: 12px;
color: #f56c6c;
}
.el-icon-refresh {
color: #1890ff;
cursor: pointer;
}
.el-button {
&.h-48 {
height: 48px;
}
}
}
</style>
<!--
* @Descripttion: 当前组件信息
* @version: 1.0.0
* @Author: 无尘
* @Date: 2019-08-14 16:51:07
* @LastEditors : 无尘
* @LastEditTime : 2020-01-14 14:44:57
-->
<!--
<wx-tree v-model="itemData" ></wx-tree>
import wxTree from './wx-tree.vue';
-->
<template>
<ul class="m-l-10">
<draggable :list="itemData" class="wx-component" :options="rightOption" @input="emitter" @change="changeData">
<li v-for="(item, index) in itemData" :key="index + 'gic'">
<div class="li-cell cursor-pointer" v-contextmenu:contextmenu @click="toggleExpand(item)">{{ item.label }}</div>
<v-contextmenu ref="contextmenu">
<v-contextmenu-item @click="addChild(item)">添加子部门</v-contextmenu-item>
<v-contextmenu-item @click="modChild(item)">修改名称</v-contextmenu-item>
<v-contextmenu-item @click="delChild(item)">删除</v-contextmenu-item>
<v-contextmenu-item>部门ID: {{ item.id }}</v-contextmenu-item>
</v-contextmenu>
<li-row v-if="item.expand" :itemData="item.children"></li-row
><!-- v-show="!!item.children.length && item.expand" -->
</li>
</draggable>
</ul>
</template>
<script>
import draggable from 'vuedraggable';
import showMsg from '@/common/js/showmsg';
export default {
name: 'li-row',
components: {
draggable
},
props: {
value: {
type: [Object, Array],
default() {
return [];
}
},
itemData: {
type: [Object, Array],
default() {
return [];
}
}
},
data() {
return {
rightOption: { group: { name: 'people', pull: true, put: true }, sort: true }
};
},
computed: {},
methods: {
/**
* 改变数组数据
*/
emitter(value) {
console.log(value);
this.$emit('input', value);
},
changeData(value) {
console.log(value);
},
/**
* 展开或者关闭下级
*/
toggleExpand(item) {
const that = this;
console.log(item);
item.expand = item.expand ? false : true;
if (!item.children.length) {
item.expand = true;
}
that.$forceUpdate();
},
/**
* 添加子部门
*/
addChild(item) {
const that = this;
console.log('添加:', item);
item.children.push({
id: 225,
expand: true,
label: '总部225',
children: []
});
that.$forceUpdate();
},
/**
* 修改名称
*/
modChild(item) {
const that = this;
console.log('修改:', item);
item.label = 2222;
that.$forceUpdate();
},
/**
* 删除
*/
delChild(item) {
const that = this;
console.log('删除:', item, that.itemData);
if (!!item.children.length) {
showMsg.showmsg('当前节点下有子节点,不可删除', 'warning');
return false;
}
let key = '';
that.itemData.forEach((ele, index) => {
if (ele.id == item.id) {
key = index;
}
});
that.itemData.splice(key, 1);
that.$forceUpdate();
}
},
watch: {
value: function(newData, oldData) {
const that = this;
that.trData = JSON.parse(JSON.stringify(newData));
}
},
mounted() {
const that = this;
that.trData = JSON.parse(JSON.stringify(that.value));
}
/* beforeDestroy() {} */
};
</script>
<style lang="less" scoped>
.li-cell {
min-height: 26px;
line-height: 26px;
}
.w-110 {
width: 110px;
}
.w-320 {
width: 320px;
}
.m-t-14 {
margin-top: 14px;
}
.child-row {
padding-left: 10px;
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment