377 lines
11 KiB
Vue
377 lines
11 KiB
Vue
<template>
|
|
<j-modal
|
|
:title="$t('workGroupSelect.selectWorkGroup')"
|
|
:width="modalWidth"
|
|
:visible="visible"
|
|
:confirmLoading="confirmLoading"
|
|
@ok="handleSubmit"
|
|
@cancel="handleCancel"
|
|
@update:fullscreen="isFullscreen"
|
|
wrapClassName="j-depart-select-modal"
|
|
switchFullscreen
|
|
:cancelText="$t('close')">
|
|
<a-spin tip="Loading..." :spinning="false">
|
|
<a-input-search style="margin-bottom: 1px" :placeholder="$t('workGroupSelect.enterWorkGroupPressEnter')" @search="onSearch" />
|
|
<a-tree
|
|
:checkable="true"
|
|
:class="treeScreenClass"
|
|
class="select-work-group-tree"
|
|
:treeData="treeData"
|
|
:checkStrictly="checkStrictly"
|
|
@check="onCheck"
|
|
@select="onSelect"
|
|
@expand="onExpand"
|
|
:autoExpandParent="autoExpandParent"
|
|
:expandedKeys="expandedKeys"
|
|
:selectedKeys.sync="selectedKeys"
|
|
:checkedKeys="checkedKeys">
|
|
|
|
<template slot="title" slot-scope="{title}">
|
|
<span v-if="title.indexOf(searchValue) > -1">
|
|
{{title.substr(0, title.indexOf(searchValue))}}
|
|
<span style="color: #f50">{{searchValue}}</span>
|
|
{{title.substr(title.indexOf(searchValue) + searchValue.length)}}
|
|
</span>
|
|
<span v-else>{{title}}</span>
|
|
</template>
|
|
</a-tree>
|
|
</a-spin>
|
|
<!--底部父子关联操作和确认取消按钮-->
|
|
<template slot="footer" v-if="treeOpera && multi">
|
|
<div class="drawer-bootom-button">
|
|
<a-dropdown style="float: left" :trigger="['click']" placement="topCenter">
|
|
<a-menu slot="overlay">
|
|
<a-menu-item key="1" @click="switchCheckStrictly(1)">{{ $t('parentChildConnection') }}</a-menu-item>
|
|
<a-menu-item key="2" @click="switchCheckStrictly(2)">{{ $t('cancelConnection') }}</a-menu-item>
|
|
</a-menu>
|
|
<a-button>
|
|
{{ $t('treeOperation') }} <a-icon type="up" />
|
|
</a-button>
|
|
</a-dropdown>
|
|
<a-button @click="handleCancel" type="primary" style="margin-right: 0.8rem">{{ $t('close') }}</a-button>
|
|
<a-button @click="handleSubmit" type="primary" >{{ $t('confirm') }}</a-button>
|
|
</div>
|
|
</template>
|
|
</j-modal>
|
|
</template>
|
|
|
|
<script>
|
|
import { getWorkGroupTreeList } from '@api/api'
|
|
|
|
export default {
|
|
name: 'WorkGroupSelectionModal',
|
|
props: ['modalWidth', 'multi', 'rootOpened', 'departId', 'store', 'text', 'treeOpera'],
|
|
data () {
|
|
return {
|
|
visible: false,
|
|
confirmLoading: false,
|
|
treeData: [],
|
|
autoExpandParent: true,
|
|
expandedKeys: [],
|
|
dataList: [],
|
|
checkedKeys: [],
|
|
checkedRows: [],
|
|
searchValue: '',
|
|
checkStrictly: true,
|
|
fullscreen: false,
|
|
selectedKeys: []
|
|
}
|
|
},
|
|
created () {
|
|
this.loadWorkGroup()
|
|
},
|
|
watch: {
|
|
departId () {
|
|
this.initDepartComponent()
|
|
},
|
|
visible: {
|
|
handler () {
|
|
this.initDepartComponent(true)
|
|
}
|
|
}
|
|
},
|
|
computed: {
|
|
treeScreenClass () {
|
|
return {
|
|
'my-dept-select-tree': true,
|
|
fullscreen: this.fullscreen,
|
|
'radio-tree': !this.multi
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
show (textVals) {
|
|
this.visible = true
|
|
this.checkedRows = []
|
|
this.checkedKeys = []
|
|
if (textVals) {
|
|
this.$nextTick(() => {
|
|
// 如果是多选就以逗号分开查找,否则就直接查找
|
|
const nodes = this.findKeysByNodes(this.multi ? textVals.split(',') : textVals)
|
|
this.checkedRows = nodes
|
|
this.checkedKeys = nodes.map(item => item.key)
|
|
this.selectedKeys = [...this.checkedKeys]
|
|
})
|
|
}
|
|
},
|
|
findKeysByNodes (titles) {
|
|
const _this = this
|
|
const nodes = []
|
|
function searchTree (node) {
|
|
// 如果是单选模式已经找到一个,就不继续查找了
|
|
if (!_this.multi && nodes.length) {
|
|
return
|
|
}
|
|
if (titles.includes(node.title)) {
|
|
nodes.push(node)
|
|
}
|
|
if (node.children) {
|
|
for (const child of node.children) {
|
|
searchTree(child)
|
|
}
|
|
}
|
|
}
|
|
this.treeData.forEach(data => {
|
|
searchTree(data)
|
|
})
|
|
return nodes
|
|
},
|
|
// 处理工作组树数据结构
|
|
dealTreeData (treeData) {
|
|
return treeData.map(item => {
|
|
item.title = item.name
|
|
item.value = item.id
|
|
item.key = item.id
|
|
item.disabled = !!(item.subset && item.subset.length)
|
|
item.children = this.dealTreeData(item.subset)
|
|
return item
|
|
})
|
|
},
|
|
loadWorkGroup () {
|
|
getWorkGroupTreeList().then(res => {
|
|
if (res.success) {
|
|
console.log(res.result)
|
|
const arr = this.dealTreeData(res.result)
|
|
this.reWriterWithSlot(arr)
|
|
this.treeData = arr
|
|
this.initDepartComponent()
|
|
if (this.rootOpened) {
|
|
this.initExpandedKeys(res.result)
|
|
}
|
|
}
|
|
})
|
|
},
|
|
initDepartComponent (flag) {
|
|
const arr = []
|
|
// 该方法两个地方用 1.visible改变事件重新设置选中项 2.组件编辑页面回显
|
|
const fieldName = flag === true ? 'key' : this.text
|
|
if (this.departId) {
|
|
const arr2 = this.departId.split(',')
|
|
for (const item of this.dataList) {
|
|
if (arr2.indexOf(item[this.store]) >= 0) {
|
|
arr.push(item[fieldName])
|
|
}
|
|
}
|
|
}
|
|
if (flag === true) {
|
|
this.checkedKeys = [...arr]
|
|
} else {
|
|
this.$emit('initComp', arr.join(','))
|
|
}
|
|
},
|
|
reWriterWithSlot (arr) {
|
|
for (const item of arr) {
|
|
if (item.children && item.children.length > 0) {
|
|
this.reWriterWithSlot(item.children)
|
|
const temp = Object.assign({}, item)
|
|
temp.children = {}
|
|
this.dataList.push(temp)
|
|
} else {
|
|
this.dataList.push(item)
|
|
item.scopedSlots = { title: 'title' }
|
|
}
|
|
}
|
|
},
|
|
initExpandedKeys (arr) {
|
|
if (arr && arr.length > 0) {
|
|
const keys = []
|
|
for (const item of arr) {
|
|
if (item.children && item.children.length > 0) {
|
|
keys.push(item.id)
|
|
}
|
|
}
|
|
this.expandedKeys = [...keys]
|
|
} else {
|
|
this.expandedKeys = []
|
|
}
|
|
},
|
|
onCheck (checkedKeys, info) {
|
|
if (!this.multi) {
|
|
const arr = checkedKeys.checked.filter(item => this.checkedKeys.indexOf(item) < 0)
|
|
this.checkedKeys = [...arr]
|
|
this.checkedRows = (this.checkedKeys.length === 0) ? [] : [info.node.dataRef]
|
|
} else {
|
|
if (this.checkStrictly) {
|
|
this.checkedKeys = checkedKeys.checked
|
|
} else {
|
|
this.checkedKeys = checkedKeys
|
|
}
|
|
this.checkedRows = this.getCheckedRows(this.checkedKeys)
|
|
}
|
|
},
|
|
onSelect (selectedKeys, info) {
|
|
// 取消关联的情况下才走onSelect的逻辑
|
|
if (this.checkStrictly) {
|
|
const keys = []
|
|
keys.push(selectedKeys[0])
|
|
if (!this.checkedKeys || this.checkedKeys.length === 0 || !this.multi) {
|
|
this.checkedKeys = [...keys]
|
|
this.checkedRows = [info.node.dataRef]
|
|
} else {
|
|
const currKey = info.node.dataRef.key
|
|
if (this.checkedKeys.indexOf(currKey) >= 0) {
|
|
this.checkedKeys = this.checkedKeys.filter(item => item !== currKey)
|
|
} else {
|
|
this.checkedKeys.push(...keys)
|
|
}
|
|
}
|
|
this.checkedRows = this.getCheckedRows(this.checkedKeys)
|
|
}
|
|
},
|
|
onExpand (expandedKeys) {
|
|
this.expandedKeys = expandedKeys
|
|
this.autoExpandParent = false
|
|
},
|
|
handleSubmit () {
|
|
if (!this.checkedKeys || this.checkedKeys.length === 0) {
|
|
this.$emit('ok', '')
|
|
} else {
|
|
const checkRow = this.getCheckedRows(this.checkedKeys)
|
|
const keyStr = this.checkedKeys.join(',')
|
|
this.$emit('ok', checkRow, keyStr)
|
|
}
|
|
this.handleClear()
|
|
},
|
|
handleCancel () {
|
|
this.handleClear()
|
|
},
|
|
handleClear () {
|
|
this.visible = false
|
|
this.checkedKeys = []
|
|
},
|
|
getParentKey (currKey, treeData) {
|
|
let parentKey
|
|
for (let i = 0; i < treeData.length; i++) {
|
|
const node = treeData[i]
|
|
if (node.children) {
|
|
if (node.children.some(item => item.key === currKey)) {
|
|
parentKey = node.key
|
|
} else if (this.getParentKey(currKey, node.children)) {
|
|
parentKey = this.getParentKey(currKey, node.children)
|
|
}
|
|
}
|
|
}
|
|
return parentKey
|
|
},
|
|
onSearch (value) {
|
|
const expandedKeys = this.dataList.map((item) => {
|
|
if (item.title.indexOf(value) > -1) {
|
|
return this.getParentKey(item.key, this.treeData)
|
|
}
|
|
return null
|
|
}).filter((item, i, self) => item && self.indexOf(item) === i)
|
|
|
|
Object.assign(this, {
|
|
expandedKeys,
|
|
searchValue: value,
|
|
autoExpandParent: true
|
|
})
|
|
},
|
|
// 根据 checkedKeys 获取 rows
|
|
getCheckedRows (checkedKeys) {
|
|
const forChildren = (list, key) => {
|
|
for (const item of list) {
|
|
if (item.id === key) {
|
|
return item
|
|
}
|
|
if (Array.isArray(item.children)) {
|
|
const value = forChildren(item.children, key)
|
|
if (value != null) {
|
|
return value
|
|
}
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
const rows = []
|
|
for (const key of checkedKeys) {
|
|
const row = forChildren(this.treeData, key)
|
|
if (row != null) {
|
|
rows.push(row)
|
|
}
|
|
}
|
|
return rows
|
|
},
|
|
switchCheckStrictly (v) {
|
|
if (v === 1) {
|
|
this.checkStrictly = false
|
|
} else if (v === 2) {
|
|
this.checkStrictly = true
|
|
}
|
|
},
|
|
isFullscreen (val) {
|
|
this.fullscreen = val
|
|
}
|
|
}
|
|
}
|
|
|
|
</script>
|
|
|
|
<style lang="less" scoped>
|
|
// 限制部门选择树高度,避免部门太多时点击确定不便
|
|
.my-dept-select-tree{
|
|
height:350px;
|
|
|
|
&.fullscreen{
|
|
height: calc(100vh - 250px);
|
|
}
|
|
overflow-y: scroll;
|
|
}
|
|
.drawer-bootom-button {
|
|
position: absolute;
|
|
bottom: 0;
|
|
width: 100%;
|
|
border-top: 1px solid #e8e8e8;
|
|
padding: 10px 16px;
|
|
text-align: right;
|
|
left: 0;
|
|
background: #fff;
|
|
border-radius: 0 0 2px 2px;
|
|
}
|
|
// 禁用的不需要显示选择框
|
|
.select-work-group-tree {
|
|
/deep/.ant-tree-checkbox-disabled {
|
|
display: none;
|
|
}
|
|
/deep/li.ant-tree-treenode-disabled > .ant-tree-node-content-wrapper span {
|
|
color: rgba(0, 0, 0, .65)
|
|
}
|
|
}
|
|
|
|
// 单选不显示选择框
|
|
.select-work-group-tree.radio-tree {
|
|
/deep/.ant-tree-checkbox {
|
|
//display: none;
|
|
opacity: 0;
|
|
position: absolute;
|
|
}
|
|
}
|
|
|
|
// 单选鼠标悬浮时宽度调整
|
|
.ant-tree.radio-tree /deep/ li .ant-tree-node-content-wrapper:hover {
|
|
margin-left: 0;
|
|
padding-left: 5px;
|
|
}
|
|
</style>
|