| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- <template>
- <div class="fm-outline-header">
- <el-input v-model="filterText" placeholder="Filter node" clearable />
- </div>
- <div class="fm-outline-content">
- <el-scrollbar ref="scrollRef">
- <el-tree
- ref="treeRef"
- class="filter-tree"
- :data="treeData"
- :props="defaultProps"
- default-expand-all
- highlight-current
- :expand-on-click-node="false"
- :filter-node-method="filterNode"
- :indent="16"
- node-key="id"
- @node-click="onNodeClick"
- check-on-click-node
- >
- <template #default="{ node }">
- <div class="custom-tree-node" :class="{'is-bind': node.data?.dataBind}">
- <span v-html="node.label"></span>
- </div>
- </template>
- </el-tree>
- </el-scrollbar>
- </div>
- </template>
- <script>
- export default {
- props: ['data', 'show'],
- data () {
- return {
- filterText: '',
- defaultProps: {
- children: 'children',
- label: 'label',
- disabled: 'disabled'
- },
- treeData: [],
- currentKey: ''
- }
- },
- emits: ['select'],
- mounted () {
- this.treeData = this.loadNode(this.data)
- this.loadTreeWidthStyle()
- },
- methods: {
- filterNode (value, data) {
- if (!value) return true
- return data.label.includes(value)
- },
- loadNode (list) {
- let currentNode = []
- for (let i = 0; i < list.length; i++) {
- if (!list[i].type) continue
- currentNode.push({
- id: list[i].key,
- label: (
- list[i].type == 'custom' ? ('<i class="fm-iconfont icon-extend"></i> ') : (
- list[i].icon ? `<i class=" fm-iconfont ${list[i].icon}"></i> ` : '<i class="fm-iconfont"></i>'))
- +`<span class="custom-tree-node-type">${list[i].name ? list[i].name : this.$t('fm.components.fields.'+list[i].type)}</span>`
- + (list[i].model ? ` { <span class="custom-tree-node-model">${list[i].model}</span> }` : ''),
- children: [],
- dataBind: list[i].options?.dataBind
- })
- if (list[i].type == 'grid') {
- currentNode[i].children = this.loadNode(list[i].columns)
- }
- if (list[i].type == 'col') {
- currentNode[i].children = this.loadNode(list[i].list)
- }
- if (list[i].type == 'report') {
- // 处理表格布局结构,便于大纲树展示
- let reportList = []
- for (let r = 0; r < list[i].rows.length; r++) {
- for (let c = 0; c < list[i].rows[r].columns.length; c++) {
- let td = list[i].rows[r].columns[c]
- if (!td.options.invisible) {
- reportList.push(td)
- }
- }
- }
- currentNode[i].children = this.loadNode(reportList)
- }
- if (list[i].type == 'td') {
- currentNode[i].children = this.loadNode(list[i].list)
- }
- if (list[i].type == 'tabs') {
- for (let t = 0; t < list[i].tabs.length; t++) {
- currentNode[i].children.push({
- label: list[i].tabs[t].label,
- children: [],
- disabled: true
- })
- currentNode[i].children[t].children = this.loadNode(list[i].tabs[t].list)
- }
- }
- if (list[i].type == 'collapse') {
- for (let t = 0; t < list[i].tabs.length; t++) {
- currentNode[i].children.push({
- label: list[i].tabs[t].title,
- children: [],
- disabled: true
- })
- currentNode[i].children[t].children = this.loadNode(list[i].tabs[t].list)
- }
- }
- if (list[i].type == 'inline') {
- currentNode[i].children = this.loadNode(list[i].list)
- }
- if (list[i].type == 'table') {
- currentNode[i].children = this.loadNode(list[i].tableColumns)
- }
- if (list[i].type == 'subform') {
- currentNode[i].children = this.loadNode(list[i].list)
- }
- if (list[i].type == 'dialog') {
- currentNode[i].children = this.loadNode(list[i].list)
- }
- if (list[i].type == 'card') {
- currentNode[i].children = this.loadNode(list[i].list)
- }
- if (list[i].type == 'group') {
- currentNode[i].children = this.loadNode(list[i].list)
- }
- }
- return currentNode
- },
- loadTreeWidthStyle () {
- if (!this.show) return
- document.querySelector('.fm-outline-content .el-scrollbar__view').removeAttribute('style')
- let realWidth = document.querySelector('.fm-outline-content .el-scrollbar__wrap').scrollWidth
- document.querySelector('.fm-outline-content .el-scrollbar__view').setAttribute('style', `width: ${realWidth <= 250 ? realWidth : (realWidth + 5)}px`)
- },
- onNodeClick (data, node) {
- if (data.id) {
- this.$emit('select', data.id)
- this.currentKey = data.id
- } else {
- this.$refs.treeRef?.setCurrentKey(this.currentKey)
- }
- },
- setCurrentKey (key, isScrollTo) {
- this.currentKey = key
- this.$refs.treeRef?.setCurrentKey(key)
- setTimeout(() => {
- isScrollTo && this.scrollTo()
- }, 200)
- },
- scrollTo () {
- // 计算当前选中元素距离容器顶部距离
- let y = document.querySelector('.fm-outline-content .is-current')?.offsetTop
- let containerHeight = document.querySelector('.fm-outline-content').offsetHeight
- let containerTop = document.querySelector('.fm-outline-content').getBoundingClientRect().top
- let scorllTop = document.querySelector('.fm-outline-content .el-scrollbar__view').getBoundingClientRect().top
- let top = scorllTop - containerTop
- if (y > -top + containerHeight || y < -top) {
- this.$refs.scrollRef.setScrollTop(y)
- }
- }
- },
- watch: {
- filterText (val) {
- this.$refs.treeRef.filter(val)
- },
- data: {
- deep: true,
- handler (val) {
- this.treeData = this.loadNode(val)
- this.loadTreeWidthStyle()
- this.$nextTick(() => {
- this.$refs.treeRef?.setCurrentKey(this.currentKey)
- this.$refs.treeRef.filter(this.filterText)
- })
- }
- }
- }
- }
- </script>
- <style lang="scss">
- .fm-outline-header{
- padding: 12px;
- height: 56px;
- }
- .fm-outline-content{
- height: calc(100% - 56px);
- .custom-tree-node{
- display: inline-block;
- font-size: 12px;
- line-height: 12px;
- .fm-iconfont{
- vertical-align: top;
- font-size: 14px;
- }
- &.is-bind{
- >span>.custom-tree-node-model{
- color: #67C23A;
- }
- }
- }
- .el-tree-node>.el-tree-node__children{
- overflow: unset;
- }
- .el-tree-node.is-current{
- >.el-tree-node__content{
- background: #c6e2ff;
- >.custom-tree-node{
- // background: #c6e2ff;
- }
- }
- }
- .filter-tree{
- margin-bottom: 10px;
- }
- }
- html.dark{
- .fm-outline-content{
- .el-tree-node.is-current{
- >.el-tree-node__content{
- background: #213d5b;
- }
- }
- }
- }
- </style>
|