[update] 树形弹框

This commit is contained in:
lideqin
2024-08-07 20:37:25 +08:00
parent a116128c18
commit 325baf72b2
3 changed files with 259 additions and 166 deletions
+1 -1
View File
@@ -149,7 +149,7 @@
:fieldName="item.dbFieldName" :fieldName="item.dbFieldName"
:nameStr="formInline[item.dbFieldName + '_dictText']" :nameStr="formInline[item.dbFieldName + '_dictText']"
@nameChange="treeDataSelectNameChange" @nameChange="treeDataSelectNameChange"
:optionsHref="item.fieldHref" :optionsHref="item.treeFirstHref"
:dict-id="item.dictId"/> :dict-id="item.dictId"/>
</a-form-model-item> </a-form-model-item>
</div> </div>
+231 -91
View File
@@ -13,10 +13,9 @@
<a-input-search style="margin-bottom: 1px" :placeholder="$t('pleaseEnter') + $t('treeSelection.primaryNodeName')" @search="onSearch" /> <a-input-search style="margin-bottom: 1px" :placeholder="$t('pleaseEnter') + $t('treeSelection.primaryNodeName')" @search="onSearch" />
<a-tree <a-tree
ref="tree" ref="tree"
:checkStrictly="checkStrictly"
:checkable="checkable" :checkable="checkable"
:checkStrictly="true"
:replaceFields="replaceFields" :replaceFields="replaceFields"
:loadedKeys="loadedKeys"
:class="treeScreenClass" :class="treeScreenClass"
:treeData="treeData" :treeData="treeData"
:autoExpandParent="autoExpandParent" :autoExpandParent="autoExpandParent"
@@ -25,7 +24,8 @@
@expand="onExpand" @expand="onExpand"
:loadData="loadData" :loadData="loadData"
:expandedKeys="expandedKeys" :expandedKeys="expandedKeys"
:checkedKeys="checkedKeys"> :checkedKeys="checkedKeys"
:selectedKeys.sync="selectedKeys">
<template slot="title" slot-scope="{dataRef}"> <template slot="title" slot-scope="{dataRef}">
<span v-if="searchValue && dataRef[replaceFields.title].indexOf(searchValue) > -1"> <span v-if="searchValue && dataRef[replaceFields.title].indexOf(searchValue) > -1">
@@ -38,12 +38,29 @@
<p class="modal-content-title">{{ $t('treeSelection.selectedData') }}</p> <p class="modal-content-title">{{ $t('treeSelection.selectedData') }}</p>
<div v-if="dataSourceRight && dataSourceRight.length > 0" class="name-content"> <div v-if="dataSourceRight && dataSourceRight.length > 0" class="name-content">
<div v-for="(item, index) in dataSourceRight" :key="item.code" class="name-div"> <div v-for="(item, index) in dataSourceRight" :key="item[replaceFields.key]" class="name-div">
{{ item.name }} {{ item[replaceFields.title] }}
<a-icon type="close" @click="handleDelete(item, index)" /> <a-icon type="close" @click="handleDelete(item, index)" />
</div> </div>
</div> </div>
<a-empty v-else /> <a-empty v-else />
<!--底部父子关联操作和确认取消按钮-->
<template slot="footer" v-if="treeOpera && checkable">
<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>
{{ treeOperationText }} <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="handleOk" type="primary" >{{ $t('confirm') }}</a-button>
</div>
</template>
</j-modal> </j-modal>
</template> </template>
@@ -61,7 +78,7 @@ export default {
checkable: { // 是否多选 checkable: { // 是否多选
type: Boolean, type: Boolean,
required: false, required: false,
default: true default: false
}, },
// 是否校验必选 // 是否校验必选
checkRequired: { checkRequired: {
@@ -81,22 +98,15 @@ export default {
required: false, required: false,
default: false default: false
}, },
// 存储字段 [key field]
storeField: {
type: String,
default: 'id',
required: false
},
// 显示字段 [label field]
textField: {
type: String,
default: 'name',
required: false
},
dictId: { dictId: {
type: String, type: String,
required: false, required: false,
default: '' default: ''
},
treeOpera: { // 是否可以切换父子关联
type: Boolean,
required: false,
default: true
} }
}, },
computed: { computed: {
@@ -105,6 +115,9 @@ export default {
'my-dept-select-tree': true, 'my-dept-select-tree': true,
fullscreen: this.fullscreen fullscreen: this.fullscreen
} }
},
treeOperationText () {
return this.parentChildRelate ? this.$t('parentChildConnection') : this.$t('cancelConnection')
} }
}, },
watch: { watch: {
@@ -126,9 +139,9 @@ export default {
if (val === '/laws/standard/partName/') { if (val === '/laws/standard/partName/') {
// 是涉及系统/部件 // 是涉及系统/部件
this.replaceFields = { children: 'childPartNameList', title: 'name', key: 'id' } this.replaceFields = { children: 'childPartNameList', title: 'name', key: 'id' }
this.lazyLoadHref = '' this.lazyLoadHref = '/laws/standard/partName/getChild'
this.searchFieldName = 'name' this.searchFieldName = 'nodeName'
this.lazyLoadPidFieldName = '' this.lazyLoadPidFieldName = 'dictItemId'
} else { // 标签库 } else { // 标签库
this.replaceFields = { children: 'childrenList', title: 'itemText', key: 'id' } this.replaceFields = { children: 'childrenList', title: 'itemText', key: 'id' }
this.lazyLoadHref = '/laws/dictTree/getChild' this.lazyLoadHref = '/laws/dictTree/getChild'
@@ -138,18 +151,23 @@ export default {
} }
} }
}, },
created () {
// if (this.treeOpera) {
// this.switchCheckStrictly(1)
// }
},
data () { data () {
return { return {
width: 800, width: 800,
visible: false, visible: false,
confirmLoading: false, confirmLoading: false,
checkStrictly: true, parentChildRelate: false, // 父子节点是否关联
autoExpandParent: false, // 是否自动展开父节点 autoExpandParent: false, // 是否自动展开父节点
treeData: [], treeData: [],
expandedKeys: [], expandedKeys: [],
checkedKeys: [], checkedKeys: [],
checkedRows: [], checkedRows: [],
loadedKeys: [], // 已经加载的节点 selectedKeys: [],
searchValue: '', // 查询框内容 searchValue: '', // 查询框内容
replaceFields: {}, replaceFields: {},
dataSourceRight: [], dataSourceRight: [],
@@ -163,50 +181,145 @@ export default {
this.visible = true this.visible = true
this.checkedRows = [] this.checkedRows = []
this.checkedKeys = [] this.checkedKeys = []
this.selectedKeys = []
this.searchValue = '' this.searchValue = ''
this.getTreeData() this.getTreeData()
if (this.value) {
if (this.checkable) {
this.checkedKeys = this.value.split(',')
} else {
this.selectedKeys = this.value.split(',')
}
// 初始化选中数据列表
this.getSelectedList(this.value)
}
}, },
onCheck (checkedKeys, info) { onCheck (checkedKeys, info) {
console.log('----------onCheck', checkedKeys, info) console.log('----------onCheck', checkedKeys)
if (!this.checkable) { console.log('----------info.checked', info.checked)
// // 不是多选 console.log('----------info.node', info.node.dataRef)
// const arr = checkedKeys.checked.filter(item => !this.checkedKeys.includes(item)) if (this.checkable) {
// this.checkedKeys = [...arr] // 是多选
// this.checkedRows = (this.checkedKeys.length === 0) ? [] : [info.node.dataRef] if (this.parentChildRelate) {
} else { // 是父子关联
if (this.checkStrictly) { if (info.checked) {
this.checkedKeys = checkedKeys.checked // 是选中数据了
let childrenList = []
if (info.node.dataRef[this.replaceFields.children]) {
// 有子节点获取子节点数据
childrenList = info.node.dataRef[this.replaceFields.children].map(item => item[this.replaceFields.key])
}
this.checkedKeys = [...this.checkedKeys, ...checkedKeys.checked, ...childrenList]
} else {
// 是取消选中了,把当前和子节点都取消选中
let currAndChildNode = []
if (info.node.dataRef[this.replaceFields.children]) {
// 有子节点获取子节点数据
const childrenNode = info.node.dataRef[this.replaceFields.children].map(item => item[this.replaceFields.key])
currAndChildNode = [...childrenNode, info.node.dataRef[this.replaceFields.key]]
} else {
currAndChildNode = [info.node.dataRef[this.replaceFields.key]]
}
this.checkedKeys = this.checkedKeys.filter(item => !currAndChildNode.includes(item))
}
// 处理下方显示已选数据
if (info.checked) {
console.log('------------增加了数据')
// 说明是增加了数据,把点击的数据和子数据追加进去
for (const key of checkedKeys.checked) {
// 当前选中没在选中列表中的加进去
if (!this.dataSourceRight.find(item => item[this.replaceFields.key] === key)) {
// 右侧不存在,追加到右侧表格
this.dataSourceRight.push(info.node.dataRef)
}
}
if (info.node.dataRef[this.replaceFields.children]) {
// 有子集追加
for (const keyItem of info.node.dataRef[this.replaceFields.children]) {
// 当前选中的子集没在列表中的加进去
if (!this.dataSourceRight.find(item => item[this.replaceFields.key] === keyItem[this.replaceFields.key])) {
// 右侧不存在,追加到右侧表格
this.dataSourceRight.push(keyItem)
}
}
}
} else {
console.log('----------删除了数据')
// 说明是删除了数据
if (this.checkedKeys && this.checkedKeys.length > 0) {
// 还有选中数据,从dataSourceRight里面找到点击的数据和他的子数据清空
for (let i = 0; i < this.dataSourceRight.length; i++) {
if (!this.checkedKeys.find(item => item === this.dataSourceRight[i][this.replaceFields.key])) {
// 表格选中中没有找到这一条数据,说明已经被删了
this.dataSourceRight.splice(i, 1)
i--
}
}
} else {
// 已经没有选中数据了,直接清空展示数据
this.dataSourceRight = []
}
}
} else { } else {
this.checkedKeys = checkedKeys // 不是父子关联
console.log('-----------checkedKeys', this.checkedKeys, checkedKeys)
if (info.checked) {
// 是选中数据了
this.checkedKeys = [...this.checkedKeys, ...checkedKeys.checked]
} else {
// 是取消选中了
this.checkedKeys = this.checkedKeys.filter(item => item !== info.node.dataRef[this.replaceFields.key])
}
// 处理下方显示已选数据
if (info.checked) {
console.log('------------不父子关联增加了数据')
// 说明是增加了数据,把点击的数据追加进去
for (const key of checkedKeys.checked) {
// 当前选中没在选中列表中的加进去
if (!this.dataSourceRight.find(item => item[this.replaceFields.key] === key)) {
// 右侧不存在,追加到右侧表格
this.dataSourceRight.push(info.node.dataRef)
}
}
} else {
console.log('----------不父子关联删除了数据')
// 说明是删除了数据
if (this.checkedKeys && this.checkedKeys.length > 0) {
// 还有选中数据,从dataSourceRight里面找到点击的数据和他的子数据清空
for (let i = 0; i < this.dataSourceRight.length; i++) {
if (!this.checkedKeys.find(item => item === this.dataSourceRight[i][this.replaceFields.key])) {
// 表格选中中没有找到这一条数据,说明已经被删了
this.dataSourceRight.splice(i, 1)
i--
}
}
} else {
// 已经没有选中数据了,直接清空展示数据
this.dataSourceRight = []
}
}
} }
this.checkedRows = this.getCheckedRows(this.checkedKeys)
} }
}, },
onSelect (selectedKeys, info) { onSelect (selectedKeys, info) {
// 取消关联的情况下才走onSelect的逻辑 // 取消关联的情况下才走onSelect的逻辑
if (this.checkStrictly) { if (!this.parentChildRelate) {
const keys = [] if (selectedKeys && selectedKeys.length > 0) {
keys.push(selectedKeys[0]) // 说明是选中了数据
if (!this.checkedKeys || this.checkedKeys.length === 0 || !this.checkable) { this.selectedKeys = [...selectedKeys]
this.checkedKeys = [...keys] this.dataSourceRight = [info.node.dataRef]
this.checkedRows = [info.node.dataRef]
} else { } else {
const currKey = info.node.dataRef.key // 没有数据,直接清空
if (this.checkedKeys.indexOf(currKey) >= 0) { this.selectedKeys = []
this.checkedKeys = this.checkedKeys.filter(item => item !== currKey) this.dataSourceRight = []
} else {
this.checkedKeys.push(...keys)
}
} }
this.checkedRows = this.getCheckedRows(this.checkedKeys)
} }
}, },
onExpand (expandedKeys) { onExpand (expandedKeys) {
this.expandedKeys = expandedKeys this.expandedKeys = expandedKeys
}, },
// 异步加载 // 异步加载
loadData (node) { async loadData (node) {
console.log('-------node', node)
if (node.dataRef.children) { if (node.dataRef.children) {
return return
} }
@@ -219,10 +332,9 @@ export default {
} }
// 父节点id // 父节点id
params.dictItemId = node.dataRef.id params.dictItemId = node.dataRef.id
getAction(this.lazyLoadHref, params).then(res => { await getAction(this.lazyLoadHref, params).then(res => {
if (res.success) { if (res.success) {
node[this.replaceFields.children] = res.result.record node.dataRef[this.replaceFields.children] = res.result.record || res.result
this.loadedKeys.push(node.id)
} }
}).finally(() => { }).finally(() => {
this.confirmLoading = false this.confirmLoading = false
@@ -254,6 +366,16 @@ export default {
} }
} }
}, },
// 切换父子关联
switchCheckStrictly (v) {
if (v === 1) {
// 取消父子关联
this.parentChildRelate = false
} else if (v === 2) {
// 增加父子关联
this.parentChildRelate = true
}
},
getTreeData () { getTreeData () {
this.confirmLoading = true this.confirmLoading = true
const params = {} const params = {}
@@ -266,65 +388,46 @@ export default {
this.confirmLoading = false this.confirmLoading = false
}) })
}, },
// 已选数据列表的删除
handleDelete (record, index) {
this.dataSourceRight.splice(index, 1)
if (this.checkable) {
// 多选从checkedKeys里面筛选出去
this.checkedKeys = this.checkedKeys.filter(item => item !== record[this.replaceFields.key])
} else {
// 单选从selectedKeys里面筛选出去
this.selectedKeys = this.selectedKeys.filter(item => item !== record[this.replaceFields.key])
}
},
handleOk () { handleOk () {
if (this.checkRequired && (!this.checkedKeys || this.checkedKeys.length === 0)) { if (this.checkRequired && (!this.checkedKeys || this.checkedKeys.length === 0)) {
this.$message.warning(this.$t('selectLeastOne')) this.$message.warning(this.$t('selectLeastOne'))
return return
} }
if (!this.checkedKeys || this.checkedKeys.length === 0) { this.$emit('nameChange', this.dataSourceRight.map(item => item[this.replaceFields.title]).join(','))
this.$emit('ok', '') this.$emit('change', this.dataSourceRight.map(item => item[this.replaceFields.key]).join(','))
} else { this.$emit('listChange', this.dataSourceRight)
const checkRow = this.getCheckedRows(this.checkedKeys)
const keyStr = this.checkedKeys.join(',')
this.$emit('ok', checkRow, keyStr)
}
this.close() this.close()
}, },
// 根据 checkedKeys 获取 rows
getCheckedRows (checkedKeys) {
const forChildren = (list, key) => {
for (const item of list) {
if (item[this.storeField] === key) {
return item
}
if (item[this.replaceFields.children] instanceof Array) {
const value = forChildren(item[this.replaceFields.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
},
getSelectedList (codes) { getSelectedList (codes) {
const params = { const params = {
selectNodeCodes: codes selectNodeCodes: codes,
dictId: this.dictId
} }
let url let url
// 涉及系统/部件 // 涉及系统/部件
if (this.optionsHref === '/laws/standard/partName/') { if (this.optionsHref === '/laws/standard/partName/') {
url = '/laws/standard/partName/echo' url = '/laws/standard/partName/echo'
} else if (this.optionsHref === '/laws/lawsLabelDatabase/queryTreeList') { // 标签库 } else { // 标签库
url = '/laws/lawsLabelDatabase/queryByCodes' // url = '/laws/lawsLabelDatabase/queryByCodes'
url = '/laws/standard/partName/echo'
} }
if (!url) { if (!url) {
return return
} }
postAction(url, params).then(res => { postAction(url, params).then(res => {
if (res.success) { if (res.success) {
const nameArr = (res.result || []).map(item => item[this.text]) this.dataSourceRight = JSON.parse(JSON.stringify(res.result))
// 抛出名称
this.$emit('initComp', nameArr.join(','))
} }
}) })
} }
@@ -333,6 +436,9 @@ export default {
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
/deep/ .ant-modal-content {
padding-bottom: 18px;
}
.my-dept-select-tree{ .my-dept-select-tree{
height:350px; height:350px;
@@ -347,5 +453,39 @@ export default {
font-weight: 500; font-weight: 500;
margin-right: 12px; margin-right: 12px;
margin-bottom: 0; margin-bottom: 0;
margin-top: 16px;
}
.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;
}
.name-content {
display: flex;
flex-wrap: wrap;
max-height: 200px;
overflow-y: auto;
.name-div {
width: auto;
padding: 5px 16px;
margin-right: 12px;
margin-top: 8px;
background: rgba(0, 100, 250, 0.08);
border-radius: 4px 4px 4px 4px;
opacity: 1;
color: @primary-color;
white-space: nowrap;
/deep/ .anticon {
margin-left: 4px;
}
}
} }
</style> </style>
+27 -74
View File
@@ -1,18 +1,19 @@
<template> <template>
<div class="components-input-demo-presuffix"> <div class="components-input-demo-presuffix">
<a-input @click="openModal" :placeholder="$t('pleaseSelect')" v-model="nameStr" readOnly :disabled="disabled"> <a-input @click="openModal" :placeholder="$t('pleaseSelect')" v-model="nameStr" :title="nameStr" readOnly>
<a-icon v-if="storeVals" slot="suffix" type="close-circle" @click="handleEmpty" title="清空"/> <a-icon v-if="nameStr" slot="suffix" type="close-circle" @click="handleEmpty" title="清空"/>
</a-input> </a-input>
<tree-data-select-modal <tree-data-select-modal
ref="selectModal" ref="selectModal"
:checkable="checkable" :checkable="checkable"
:value="value" :value="value"
:storeField="storeField"
:textField="textField"
:dict-id="dictId" :dict-id="dictId"
v-bind="$attrs"
:options-href="optionsHref" :options-href="optionsHref"
@ok="handleOK"/> @change="handleChange"
@nameChange="nameChange"
@listChange="listChange"/>
</div> </div>
</template> </template>
@@ -38,35 +39,13 @@ export default {
required: false, required: false,
default: false default: false
}, },
// 自定义返回字段,默认返回 id
customReturnField: {
type: String,
default: ''
},
// 获取数据的接口 // 获取数据的接口
optionsHref: { optionsHref: {
type: String, type: String,
required: false, required: false,
default: '' default: ''
}, },
// 是否返回选中的对象 // 名称字符串
backObj: {
type: Boolean,
default: false,
required: false
},
// 存储字段 [key field]
storeField: {
type: String,
default: 'id',
required: false
},
// 显示字段 [label field]
textField: {
type: String,
default: 'name',
required: false
},
nameStr: { nameStr: {
type: String, type: String,
required: false, required: false,
@@ -83,66 +62,40 @@ export default {
default: '' default: ''
} }
}, },
watch: {
nameStr: {
immediate: true,
handler (val) {
console.log('----------nameStr', val)
}
}
},
data () { data () {
return { return {
visible: false, visible: false,
confirmLoading: false, confirmLoading: false
storeVals: '', // [key values]
textVals: '' // [label values]
}
},
mounted () {
this.storeVals = this.value
},
watch: {
value (val) {
this.storeVals = val
} }
}, },
methods: { methods: {
// 返回选中的部门信息
backObjInfo () {
if (this.backObj === true) {
if (this.storeVals && this.storeVals.length > 0) {
const arr1 = this.storeVals.split(',')
const arr2 = this.textVals.split(',')
const info = []
for (let i = 0; i < arr1.length; i++) {
info.push({
value: arr1[i],
text: arr2[i]
})
}
this.$emit('back', info)
}
}
},
openModal () { openModal () {
this.$refs.selectModal.show() this.$refs.selectModal.show()
}, },
handleOK (rows) { handleChange (value) {
if (!rows && rows.length <= 0) { this.$emit('change', value, this.fieldName)
this.textVals = '' },
this.storeVals = '' nameChange (value) {
} else { this.$emit('nameChange', value, this.fieldName)
const arr1 = [] },
const arr2 = [] listChange (value) {
for (const dep of rows) { this.$emit('listChange', value, this.fieldName)
arr1.push(dep[this.storeField])
arr2.push(dep[this.textField])
}
this.storeVals = arr1.join(',')
this.textVals = arr2.join(',')
}
this.$emit('change', this.storeVals)
this.$emit('nameChange', this.textVals, this.fieldName)
this.backObjInfo()
}, },
handleEmpty () { handleEmpty () {
if (this.disabled) { if (this.disabled) {
return return
} }
this.handleOK('') this.handleChange('')
this.nameChange('')
this.listChange([])
} }
}, },
model: { model: {