mirror of
https://github.com/jumpserver/lina.git
synced 2026-01-24 05:50:06 +00:00
[update]添加Ztree
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
"axios": "0.18.1",
|
||||
"element-ui": "2.13.0",
|
||||
"eslint-plugin-html": "^6.0.0",
|
||||
"jquery": "^3.5.0",
|
||||
"js-cookie": "2.2.0",
|
||||
"less": "^3.10.3",
|
||||
"less-loader": "^5.0.0",
|
||||
@@ -42,7 +43,8 @@
|
||||
"vue-i18n": "^8.15.5",
|
||||
"vue-router": "3.0.6",
|
||||
"vue-select": "^3.9.5",
|
||||
"vuex": "3.1.0"
|
||||
"vuex": "3.1.0",
|
||||
"ztree": "^3.5.24"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.0.0",
|
||||
|
||||
@@ -59,10 +59,9 @@ export default {
|
||||
// Object.assign(data, { node_id: '', asset_id: node.id })
|
||||
// }
|
||||
if (node.type === 'node') {
|
||||
console.log(this.url)
|
||||
this.$emit('urlChanged', this.internalUrl + '?node_id=' + node.id)
|
||||
this.$emit('nodeClicked', this.internalUrl + '?node_id=' + node.id)
|
||||
} else {
|
||||
this.$emit('urlChanged', this.internalUrl + '?asset_id=' + node.id)
|
||||
this.$emit('assetClicked', this.internalUrl + '?asset_id=' + node.id)
|
||||
}
|
||||
|
||||
// this.$axios.get(this.url, { params: data }).then(res => {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<el-collapse-transition>
|
||||
<div style="display: flex;justify-items: center; flex-wrap: nowrap;justify-content:space-between;">
|
||||
<div v-show="ShowTree" :style="ShowTree?('width:250px;'):('width:0;')" class="transition-box">
|
||||
<TreeNode :tree-url="tableConfig.treeurl" :url="tableConfig.url" @urlChanged="handleUrlChange" />
|
||||
<ZTree :tree-url="tableConfig.treeurl" :url="tableConfig.url" @nodeClicked="handleUrlChange" @assetClicked="handleUrlChange" />
|
||||
</div>
|
||||
<div :style="ShowTree?('display: flex;width: calc(100% - 250px);'):('display: flex;width:100%;')">
|
||||
<div class="mini">
|
||||
@@ -23,14 +23,15 @@
|
||||
|
||||
<script>
|
||||
import { Page } from '@/layout/components'
|
||||
import TreeNode from '../TreeNode'
|
||||
// import TreeNode from '../TreeNode'
|
||||
import ZTree from '../ZTree'
|
||||
import TreeListTable from './components/TreeListTable'
|
||||
export default {
|
||||
name: 'TreeTable',
|
||||
components: {
|
||||
Page,
|
||||
TreeListTable,
|
||||
TreeNode
|
||||
ZTree
|
||||
},
|
||||
props: {
|
||||
...TreeListTable.props,
|
||||
|
||||
331
src/components/ZTree/index.vue
Normal file
331
src/components/ZTree/index.vue
Normal file
@@ -0,0 +1,331 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="treebox">
|
||||
<ul id="ztree" class="ztree" />
|
||||
</div>
|
||||
<div id="rMenu">
|
||||
<ul class="dropdown-menu menu-actions">
|
||||
<li class="divider" />
|
||||
<li id="m_create" tabindex="-1" @click="addTreeNode"><a><i class="fa fa-plus-square-o" /> 添加资产到节点 </a></li>
|
||||
<li id="m_edit" tabindex="-1" @click="editTreeNode"><a><i class="fa fa-pencil-square-o" /> 重命名节点 </a></li>
|
||||
<li id="m_del" tabindex="-1" @click="removeTreeNode"><a><i class="fa fa-minus-square" /> 删除节点 </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 导入JQuery
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import $ from '@/utils/jquery-vendor.js'
|
||||
import 'ztree'
|
||||
import 'ztree/css/metroStyle/metroStyle.css'
|
||||
const defaultFunction = {
|
||||
type: Function,
|
||||
default: () => {}
|
||||
}
|
||||
const defaultString = {
|
||||
type: String,
|
||||
default: () => {}
|
||||
}
|
||||
const defaultBoolean = {
|
||||
type: Boolean,
|
||||
default: () => true
|
||||
}
|
||||
const defaultArray = {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
export default {
|
||||
name: 'ZTree',
|
||||
components: {
|
||||
|
||||
},
|
||||
props: {
|
||||
url: defaultString,
|
||||
treeUrl: defaultString,
|
||||
// treeNodeUrl: defaultString,
|
||||
showAssets: defaultBoolean,
|
||||
showMenu: defaultBoolean,
|
||||
// 额外右侧菜单
|
||||
otherMenu: defaultArray,
|
||||
onRightClick: defaultFunction,
|
||||
beforeClick: defaultFunction,
|
||||
onRename: defaultFunction,
|
||||
beforeDrag: defaultFunction,
|
||||
onDrag: defaultFunction,
|
||||
beforeDrop: defaultFunction,
|
||||
onDrop: defaultFunction,
|
||||
beforeAsync: defaultFunction,
|
||||
onSelected: defaultFunction
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
setting: {
|
||||
view: {
|
||||
dblClickExpand: false,
|
||||
showLine: true
|
||||
},
|
||||
data: {
|
||||
simpleData: {
|
||||
enable: true
|
||||
}
|
||||
},
|
||||
async: {
|
||||
enable: true,
|
||||
url: this.showAssets ? process.env.VUE_APP_BASE_API + this.treeUrl : process.env.VUE_APP_BASE_API + this.setUrlParam(this.treeUrl, 'assets', '1'),
|
||||
autoParam: ['id=key', 'name=n', 'level=lv'],
|
||||
type: 'get'
|
||||
},
|
||||
edit: {
|
||||
enable: true,
|
||||
showRemoveBtn: false,
|
||||
showRenameBtn: false,
|
||||
drag: {
|
||||
isCopy: true,
|
||||
isMove: true
|
||||
}
|
||||
},
|
||||
callback: {
|
||||
onRightClick: this.OnRightClick || this.defaultOnRightClick,
|
||||
beforeClick: this.beforeClick || this.defaultBeforeClick,
|
||||
onRename: this.onRename || this.defaultOnRename,
|
||||
onSelected: this.onSelected || this.defaultCallback('On selected'),
|
||||
beforeDrag: this.beforeDrag || this.defaultCallback('On selected'),
|
||||
onDrag: this.onDrag || this.defaultOnDrop('On selected'),
|
||||
beforeDrop: this.beforeDrop || this.defaultBeforeDrop,
|
||||
onDrop: this.onDrop || this.defaultOnDrop,
|
||||
beforeAsync: this.beforeAsync || this.defaultCallback('Before async')
|
||||
}
|
||||
},
|
||||
zTree: '',
|
||||
rMenu: ''
|
||||
}
|
||||
},
|
||||
computed() {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
this.initTree()
|
||||
$('.treebox').css('height', window.innerHeight - 60)
|
||||
},
|
||||
methods: {
|
||||
initTree: function() {
|
||||
this.$axios.get(this.treeUrl).then(res => {
|
||||
this.zTree = $.fn.zTree.init($('#ztree'), this.setting, res)
|
||||
this.rootNodeAddDom(
|
||||
this.zTree,
|
||||
() => {
|
||||
this.$axios.post(
|
||||
'/api/v1/assets/nodes/00000000-0000-0000-0000-000000000000/tasks/',
|
||||
{ action: 'refresh_cache' }
|
||||
).then(res => {
|
||||
this.initTree()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
if (this.showMenu) {
|
||||
this.rMenu = $('#rMenu')
|
||||
}
|
||||
if (this.otherMenu) {
|
||||
$('.menu-actions').append(this.otherMenu)
|
||||
}
|
||||
})
|
||||
},
|
||||
rootNodeAddDom: function(ztree, callback) {
|
||||
var refreshIcon = "<a id='tree-refresh'><i class='fa fa-refresh'></i></a>"
|
||||
var rootNode = ztree.getNodes()[0]
|
||||
if (rootNode) {
|
||||
var $rootNodeRef = $('#' + rootNode.tId + '_a')
|
||||
$rootNodeRef.after(refreshIcon)
|
||||
} else {
|
||||
$rootNodeRef = $('#' + ztree.setting.treeId)
|
||||
$rootNodeRef.html(refreshIcon)
|
||||
}
|
||||
var refreshIconRef = $('#tree-refresh')
|
||||
refreshIconRef.bind('click', function() {
|
||||
ztree.destroy()
|
||||
callback()
|
||||
})
|
||||
},
|
||||
showRMenu: function(type, x, y) {
|
||||
var offset = $('#ztree').offset()
|
||||
var scrollTop = document.querySelector('.treebox').scrollTop
|
||||
x -= offset.left
|
||||
y -= offset.top + scrollTop
|
||||
x += document.body.scrollLeft
|
||||
y += document.body.scrollTop + document.documentElement.scrollTop
|
||||
this.rMenu.css({ 'top': y + 'px', 'left': x + 'px', 'visibility': 'visible' })
|
||||
$('#rMenu ul').show()
|
||||
$('body').bind('mousedown', this.onBodyMouseDown)
|
||||
},
|
||||
defaultCallback: function(action) {
|
||||
console.log(action)
|
||||
},
|
||||
defaultOnRightClick: function(event, treeId, treeNode) {
|
||||
if (!this.showMenu) {
|
||||
return
|
||||
}
|
||||
if (!treeNode && event.target.tagName.toLowerCase() !== 'button' && $(event.target).parents('a').length === 0) {
|
||||
this.zTree.cancelSelectedNode()
|
||||
this.showRMenu('root', event.clientX, event.clientY)
|
||||
} else if (treeNode && !treeNode.noR) {
|
||||
this.zTree.selectNode(treeNode)
|
||||
this.showRMenu('node', event.clientX, event.clientY)
|
||||
}
|
||||
},
|
||||
defaultBeforeClick: function(treeId, treeNode, clickFlag) {
|
||||
return true
|
||||
},
|
||||
defaultOnDrop: function(event, treeId, treeNodes, targetNode, moveType) {
|
||||
var treeNodesIds = []
|
||||
$.each(treeNodes, function(index, value) {
|
||||
treeNodesIds.push(value.meta.node.id)
|
||||
})
|
||||
|
||||
// var the_url = "{% url 'api-assets:node-add-children' pk=DEFAULT_PK %}".replace('{{ DEFAULT_PK }}', targetNode.meta.node.id)
|
||||
// var body = { nodes: treeNodesIds }
|
||||
// TODO
|
||||
this.$axios.put(
|
||||
|
||||
)
|
||||
},
|
||||
// TODO
|
||||
defaultOnRename: function(treeId, treeNode, clickFlag) {
|
||||
return true
|
||||
},
|
||||
editTreeNode: function() {
|
||||
this.hideRMenu()
|
||||
var current_node = this.zTree.getSelectedNodes()[0]
|
||||
if (!current_node) {
|
||||
return
|
||||
}
|
||||
if (current_node) {
|
||||
current_node.name = current_node.meta.node.value
|
||||
}
|
||||
this.zTree.editName(current_node)
|
||||
},
|
||||
onBodyMouseDown: function(event) {
|
||||
if (!(event.target.id === 'rMenu' || $(event.target).parents('#rMenu').length > 0)) {
|
||||
this.rMenu.css({ 'visibility': 'hidden' })
|
||||
}
|
||||
},
|
||||
hideRMenu: function() {
|
||||
if (this.rMenu) this.rMenu.css({ 'visibility': 'hidden' })
|
||||
$('body').unbind('mousedown', this.onBodyMouseDown)
|
||||
},
|
||||
defaultBeforeDrop: function(treeId, treeNodes, targetNode, moveType) {
|
||||
var treeNodesNames = []
|
||||
$.each(treeNodes, function(index, value) {
|
||||
treeNodesNames.push(value.name)
|
||||
})
|
||||
|
||||
var msg = '你想移动节点: `' + treeNodesNames.join(',') + '` 到 `' + targetNode.name + '` 下吗?'
|
||||
return confirm(msg)
|
||||
},
|
||||
setUrlParam: function(url, name, value) {
|
||||
var urlArray = url.split('?')
|
||||
if (urlArray.length === 1) {
|
||||
url += '?' + name + '=' + value
|
||||
} else {
|
||||
var oriParam = urlArray[1].split('&')
|
||||
var oriParamMap = {}
|
||||
$.each(oriParam, function(index, value) {
|
||||
var v = value.split('=')
|
||||
oriParamMap[v[0]] = v[1]
|
||||
})
|
||||
oriParamMap[name] = value
|
||||
url = urlArray[0] + '?'
|
||||
var newParam = []
|
||||
$.each(oriParamMap, function(index, value) {
|
||||
newParam.push(index + '=' + value)
|
||||
})
|
||||
url += newParam.join('&')
|
||||
}
|
||||
return url
|
||||
},
|
||||
removeTreeNode: function() {
|
||||
this.hideRMenu()
|
||||
var current_node = this.zTree.getSelectedNodes()[0]
|
||||
if (!current_node) {
|
||||
return
|
||||
}
|
||||
// var url = "{% url 'api-assets:node-detail' pk=DEFAULT_PK %}".replace('{{ DEFAULT_PK }}', current_node_id)
|
||||
// requestApi({
|
||||
// url: url,
|
||||
// method: 'DELETE',
|
||||
// success: function() {
|
||||
// zTree.removeNode(current_node)
|
||||
// }
|
||||
// })
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='less' scoped>
|
||||
div#rMenu {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
text-align: left;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 999;
|
||||
float: left;
|
||||
padding: 0 0;
|
||||
margin: 2px 0 0;
|
||||
list-style: none;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_processing {
|
||||
opacity: .9;
|
||||
border: none;
|
||||
}
|
||||
div#rMenu li{
|
||||
margin: 1px 0;
|
||||
cursor: pointer;
|
||||
list-style: none outside none;
|
||||
}
|
||||
.dropdown-menu {
|
||||
border: medium none;
|
||||
min-width: 160px;
|
||||
background-color: #fff;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 0 3px rgba(86, 96, 117, 0.7);
|
||||
display: block;
|
||||
float: left;
|
||||
font-size: 12px;
|
||||
left: 0;
|
||||
list-style: none outside none;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
text-shadow: none;
|
||||
top: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
.ztree /deep/ .fa-refresh {
|
||||
font: normal normal normal 14px/1 FontAwesome !important;
|
||||
}
|
||||
.dropdown a:hover {
|
||||
background-color: #f1f1f1
|
||||
}
|
||||
.dropdown-menu > li > a {
|
||||
border-radius: 3px;
|
||||
color: inherit;
|
||||
line-height: 25px;
|
||||
margin: 4px;
|
||||
text-align: left;
|
||||
font-weight: normal;
|
||||
display: block;
|
||||
padding: 3px 20px;
|
||||
clear: both;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.dropdown-menu>li>a:hover, .dropdown-menu>li>a:focus {
|
||||
color: #262626;
|
||||
text-decoration: none;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
</style>
|
||||
4
src/utils/jquery-vendor.js
vendored
Normal file
4
src/utils/jquery-vendor.js
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import $ from 'jquery'
|
||||
window.$ = $
|
||||
window.jQuery = $
|
||||
export default $
|
||||
@@ -14,7 +14,7 @@ export default {
|
||||
return {
|
||||
tableConfig: {
|
||||
url: '/api/v1/assets/assets/',
|
||||
treeurl: '/api/v1/assets/nodes/children/tree/',
|
||||
treeurl: '/api/v1/assets/nodes/children/tree/?assets=0',
|
||||
columns: [
|
||||
{
|
||||
prop: 'hostname',
|
||||
|
||||
12
yarn.lock
12
yarn.lock
@@ -5597,6 +5597,11 @@ jest@^23.6.0:
|
||||
import-local "^1.0.0"
|
||||
jest-cli "^23.6.0"
|
||||
|
||||
jquery@>=1.4.4, jquery@^3.5.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.5.0.tgz#9980b97d9e4194611c36530e7dc46a58d7340fc9"
|
||||
integrity sha512-Xb7SVYMvygPxbFMpTFQiHh1J7HClEaThguL15N/Gg37Lri/qKyhRGZYzHRyLH8Stq3Aow0LsHO2O2ci86fCrNQ==
|
||||
|
||||
js-base64@^2.1.8, js-base64@^2.1.9:
|
||||
version "2.5.2"
|
||||
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.2.tgz#313b6274dda718f714d00b3330bbae6e38e90209"
|
||||
@@ -9986,3 +9991,10 @@ yorkie@^2.0.0:
|
||||
is-ci "^1.0.10"
|
||||
normalize-path "^1.0.0"
|
||||
strip-indent "^2.0.0"
|
||||
|
||||
ztree@^3.5.24:
|
||||
version "3.5.24"
|
||||
resolved "https://registry.yarnpkg.com/ztree/-/ztree-3.5.24.tgz#b63fe52981fdf2c329675cfd2772f0d147521ff1"
|
||||
integrity sha1-tj/lKYH98sMpZ1z9J3Lw0UdSH/E=
|
||||
dependencies:
|
||||
jquery ">=1.4.4"
|
||||
|
||||
Reference in New Issue
Block a user