Merge branch 'master' into jym_dev

This commit is contained in:
jym503558564
2020-04-20 18:35:48 +08:00
14 changed files with 668 additions and 58 deletions

View File

@@ -21,3 +21,10 @@ export function getSessionCommands(id) {
method: 'get'
})
}
export function getTerminalDetail(id) {
return request({
url: `/api/v1/terminal/terminals/${id}/`,
method: 'get'
})
}

View File

@@ -1,9 +1,9 @@
<template>
<DataZTree ref="dataztree" :setting="treeSetting">
<slot slot="rMenu">
<li id="m_create" class="rmenu" tabindex="-1"><a><i class="fa fa-plus-square-o" /> 添加资产到节点 </a></li>
<li id="m_edit" class="rmenu" tabindex="-1" @click="editTreeNode"><a><i class="fa fa-pencil-square-o" /> 重命名节点 </a></li>
<li id="m_del" class="rmenu" tabindex="-1" @click="removeTreeNode"><a><i class="fa fa-minus-square" /> 删除节点 </a></li>
<li id="m_create" class="rmenu" tabindex="-1" @click="addTreeNode"><a><i class="fa fa-plus-square-o" /> {{ this.$t('tree.AddNode') }} </a></li>
<li id="m_edit" class="rmenu" tabindex="-1" @click="editTreeNode"><a><i class="fa fa-pencil-square-o" /> {{ this.$t('tree.RenameNode') }} </a></li>
<li id="m_del" class="rmenu" tabindex="-1" @click="removeTreeNode"><a><i class="fa fa-minus-square" /> {{ this.$t('tree.DeleteNode') }} </a></li>
<slot name="rMenu" />
</slot>
</DataZTree>
@@ -29,22 +29,30 @@ export default {
defaultSetting: {
async: {
enable: true,
url: this.setting.showAssets ? process.env.VUE_APP_BASE_API + this.setting.treeUrl : process.env.VUE_APP_BASE_API + this.setUrlParam(this.setting.treeUrl, 'assets', '1'),
url: `${process.env.VUE_APP_BASE_API}${this.setting.treeUrl}`,
autoParam: ['id=key', 'name=n', 'level=lv'],
type: 'get'
},
callback: {
onRightClick: this.onRightClick.bind(this),
onRename: this.onRename.bind(this)
onRename: this.onRename.bind(this),
onSelected: this.onSelected.bind(this),
beforeDrop: this.beforeDrop.bind(this),
onDrop: this.onDrop.bind(this)
// 尚未定义的函数
// beforeClick
// beforeDrag
// onDrag
// beforeAsync: this.defaultCallback.bind(this, 'beforeAsync')
}
}
},
current_node: '',
current_node_id: ''
}
},
computed: {
treeSetting() {
const treeSetting = merge(this.defaultSetting, this.setting)
console.log(treeSetting)
return treeSetting
},
zTree() {
@@ -91,21 +99,41 @@ export default {
if (this.rMenu) this.rMenu.css({ 'visibility': 'hidden' })
$('body').unbind('mousedown', this.onBodyMouseDown)
},
// Request URL: http://localhost/api/v1/assets/assets/?node_id=d8212328-538d-41a6-bcfd-1e8cc7e3aed4&show_current_asset=null&draw=2&limit=15&offset=0&_=1587022917769
onSelected: function(event, treeNode) {
this.current_node = treeNode
this.current_node_id = treeNode.meta.node.id
this.$emit('urlChange', `${this.setting.url}?node_id=${treeNode.meta.node.id}&show_current_asset=null`)
},
removeTreeNode: function() {
this.hideRMenu()
var currentNode = this.zTree.getSelectedNodes()[0]
console.log(currentNode)
if (!currentNode) {
return
}
this.$axios.delete(
`${this.nodeUrl}${currentNode.meta.node.id}/`,
`${this.treeSetting.nodeUrl}${currentNode.meta.node.id}/`,
).then(
this.zTree.removeNode(currentNode)
)
},
onRename: function(event, treeId, treeNode, isCancel) {
console.log(event, treeId, treeNode, isCancel)
var url = `${this.treeSetting.nodeUrl}${this.current_node_id}/`
if (isCancel) {
return
}
this.$axios.patch(
url,
{ 'value': treeNode.name }
).then(res => {
var assets_amount = treeNode.meta.node.assets_amount
if (!assets_amount) {
assets_amount = 0
}
treeNode.name = treeNode.name + ' (' + assets_amount + ')'
this.zTree.updateNode(treeNode)
})
},
onBodyMouseDown: function(event) {
if (!(event.target.id === 'rMenu' || $(event.target).parents('#rMenu').length > 0)) {
@@ -134,6 +162,56 @@ export default {
this.zTree.selectNode(treeNode)
this.showRMenu('node', event.clientX, event.clientY)
}
},
beforeDrop: function(treeId, treeNodes, targetNode, moveType) {
var treeNodesNames = []
$.each(treeNodes, function(index, value) {
treeNodesNames.push(value.name)
})
// TODO 修改默认确认框
var msg = '你想移动节点: `' + treeNodesNames.join(',') + '` 到 `' + targetNode.name + '` 下吗?'
return confirm(msg)
},
onDrop: function(event, treeId, treeNodes, targetNode, moveType) {
var treeNodesIds = []
$.each(treeNodes, function(index, value) {
console.log(value)
treeNodesIds.push(value.meta.node.id)
})
var the_url = `${this.treeSetting.nodeUrl}${targetNode.meta.node.id}/children/add/`
this.$axios.put(
the_url, {
nodes: treeNodesIds
}
).then((res) => {
console.log(res)
})
},
addTreeNode: function() {
this.hideRMenu()
var parentNode = this.zTree.getSelectedNodes()[0]
if (!parentNode) {
return
}
// http://localhost/api/v1/assets/nodes/85aa4ee2-0bd9-41db-9079-aa3646448d0c/children/
var url = `${this.treeSetting.nodeUrl}${parentNode.meta.node.id}/children/`
this.$axios.post(
url, {}
).then(data => {
var newNode = {
id: data['key'],
name: data['value'],
pId: parentNode.id,
meta: {
'node': data
}
}
newNode.checked = this.zTree.getSelectedNodes()[0].checked
this.zTree.addNodes(parentNode, 0, newNode)
var node = this.zTree.getNodeByParam('id', newNode.id, parentNode)
this.zTree.editName(node)
})
}
}
}

View File

@@ -17,7 +17,7 @@
// eslint-disable-next-line no-unused-vars
import $ from '@/utils/jquery-vendor.js'
import 'ztree'
import 'ztree/css/metroStyle/metroStyle.css'
import '@/styles/ztree.css'
const merge = require('deepmerge')
const defaultObject = {
@@ -55,6 +55,7 @@ export default {
},
methods: {
initTree: function() {
console.log(this.treeSetting)
this.$axios.get(this.treeSetting.treeUrl).then(res => {
this.zTree = $.fn.zTree.init($('#ztree'), this.treeSetting, res)
if (this.treeSetting.showRefresh) {

View File

@@ -43,15 +43,15 @@ export default {
}
},
callback: {
onRightClick: this.defaultCallback('onRightClick'),
onRename: this.defaultCallback('Rename'),
beforeClick: this.defaultCallback('beforeClick'),
onSelected: this.defaultCallback('onSelected'),
beforeDrag: this.defaultCallback('beforeDrag'),
onDrag: this.defaultCallback('onDrag'),
beforeDrop: this.defaultCallback('beforeDrop'),
onDrop: this.defaultCallback('onDrop'),
beforeAsync: this.defaultCallback('beforeAsync')
onRightClick: this.defaultCallback.bind(this, 'onRightClick'),
onRename: this.defaultCallback.bind(this, 'onRename'),
beforeClick: this.defaultCallback.bind(this, 'beforeClick'),
onSelected: this.defaultCallback.bind(this, 'onSelected'),
beforeDrag: this.defaultCallback.bind(this, 'beforeDrag'),
onDrag: this.defaultCallback.bind(this, 'onDrag'),
beforeDrop: this.defaultCallback.bind(this, 'beforeDrop'),
onDrop: this.defaultCallback.bind(this, 'onDrop'),
beforeAsync: this.defaultCallback.bind(this, 'beforeAsync')
}
}
}

View File

@@ -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">
<AutoDataZTree :setting="treeSetting" />
<AutoDataZTree :setting="treeSetting" @urlChange="handleUrlChange" />
</div>
<div :style="ShowTree?('display: flex;width: calc(100% - 250px);'):('display: flex;width:100%;')">
<div class="mini">

View File

@@ -407,7 +407,13 @@ const cn = {
'quickModify': '快速修改',
'replaySession': '回放会话:',
'downloadReplay': '下载录像:',
'go': '执行'
'go': '执行',
'terminalDetail': '终端详情',
'name': '名称:',
'sshPort': 'SSH端口:',
'httpPort': 'HTTP端口:',
'comment': '备注:',
'dateCreated': '创建日期:'
},
jobcenter: {
'RunTimes': '执行次数',
@@ -461,6 +467,11 @@ const cn = {
'MyTickets': '我的工单',
'AssignedMe': '待处理'
},
tree: {
'AddNode': '添加节点',
'RenameNode': '重命名节点',
'DeleteNode': '删除节点'
},
setting: {
'setting': '系统设置',
'basicsetting': '基本设置'

View File

@@ -301,7 +301,13 @@ const en = {
'quickModify': 'Quick Modify',
'replaySession': 'Replay session:',
'downloadReplay': 'Download replay:',
'go': 'Go'
'go': 'Go',
'terminalDetail': 'terminalDetail',
'name': 'Name:',
'sshPort': 'SSH port:',
'httpPort': 'Http port:',
'comment': 'Comment:',
'dateCreated': 'Date created:'
},
setting: {
'setting': 'System Setting',

View File

@@ -346,6 +346,20 @@ export const constantRoutes = [
name: 'TerminalList',
component: () => import('@/views/sessions/TerminalList'),
meta: { title: 'Terminal' }
},
{
path: 'terminal/:id',
name: 'TerminalDetail',
component: () => import('@/views/sessions/TerminalDetail'),
meta: { title: 'TerminalDetail' },
hidden: true
},
{
path: 'terminal/:id/update',
name: 'TerminalUpdate',
component: () => import('@/views/tree/index'),
meta: { title: 'TerminalUpdate' },
hidden: true
}
]
},

BIN
src/styles/loading.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

412
src/styles/ztree.css Normal file
View File

@@ -0,0 +1,412 @@
/*-------------------------------------
zTree Style using fontawesome instead of images
version: 1.1
author: Mike King
email: mikkelking @ hotmail . com
website: http://code.google.com/p/jquerytree/
-------------------------------------*/
/* Definitions ----------------------*/
/* End of Definitions ---------------*/
/* Imports -------------------------*/
/* End of Imports ------------------*/
.ztree * {
padding: 0;
margin: 0;
font-size: 12px;
font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif;
background-color: #f3f3f3;
}
.ztree {
margin: 0;
padding: 5px;
color: #676a6c;
background-color: #f3f3f3;
}
.ztree li {
padding: 0;
margin: 0;
list-style: none;
line-height: 17px;
text-align: left;
white-space: nowrap;
outline: 0;
}
.ztree li ul {
margin: 0px;
padding: 0 0 0 18px;
}
.ztree li a {
padding-right: 3px;
margin: 0;
cursor: pointer;
height: 20px;
color: #676a6c;
background-color: transparent;
text-decoration: none;
vertical-align: top;
display: inline-block;
}
.ztree li a input.rename {
height: 14px;
width: 80px;
padding: 0;
margin: 0;
color: #f3f3f3;
background-color: #676a6c;
font-size: 12px;
border: 1px #585956 solid;
*border: 0px;
}
.ztree li a:hover {
background: #e7f4f9;
border-radius: 2px;
box-shadow: inset 0 0 1px #cccccc;
}
.ztree li a.curSelectedNode {
padding-top: 0px;
background-color: #beebff;
color: #676a6c;
height: 20px;
opacity: 0.8;
}
.ztree li a.curSelectedNode_Edit {
padding-top: 0px;
background-color: #f3f3f3;
color: red;
height: 20px;
border: 1px #676a6c solid;
opacity: 0.8;
}
.ztree li a.tmpTargetNode_inner {
padding-top: 0px;
background-color: #f3f3f3;
color: #676a6c;
height: 20px;
border: 1px #666 solid;
opacity: 0.8;
filter: alpha(opacity=80);
}
.ztree li span {
line-height: 20px;
margin-right: 2px;
background-color: transparent;
}
.ztree li span.button {
line-height: 0;
margin: 0;
padding: 0;
width: 18px;
height: 20px;
display: inline-block;
vertical-align: top;
border: 0px solid;
cursor: pointer;
outline: none;
background-color: transparent;
background-repeat: no-repeat;
background-attachment: scroll;
}
.ztree li span.button::before {
color: #676a6c;
font-family: FontAwesome;
padding-top: 10px;
}
.ztree li span.button.chk {
margin: 0px;
cursor: auto;
width: 12px;
display: inline-block;
padding-top: 10px;
padding-left: 2px;
}
.ztree li span.button.chk.checkbox_false_full::before {
content: "\f096";
}
.ztree li span.button.chk.checkbox_false_full_focus::before {
content: "\f096";
color: #676a6c;
}
.ztree li span.button.chk.checkbox_false_part::before {
content: "\f096";
color: #aaaaaa;
}
.ztree li span.button.chk.checkbox_false_part_focus::before {
content: "\f096";
color: #cad96c;
}
.ztree li span.button.chk.checkbox_false_disable::before {
content: "\f096";
color: #808080;
}
.ztree li span.button.chk.checkbox_true_full::before {
content: "\f046";
}
.ztree li span.button.chk.checkbox_true_full_focus::before {
content: "\f046";
}
.ztree li span.button.chk.checkbox_true_part::before {
content: "\f14a";
}
.ztree li span.button.chk.checkbox_true_part_focus::before {
content: "\f14a";
color: #676a6c;
}
.ztree li span.button.chk.checkbox_true_full_focus::before {
content: "\f046";
color: #676a6c;
}
.ztree li span.button.chk.checkbox_true_part::before {
content: "\f046";
color: #aaaaaa;
}
.ztree li span.button.chk.checkbox_true_part_focus::before {
content: "\f046";
color: #cad96c;
}
.ztree li span.button.chk.checkbox_true_disable::before {
content: "\f046";
color: #808080;
}
.ztree li span.button.chk.radio_false_full::before {
content: "\f10c";
}
.ztree li span.button.chk.radio_false_full_focus::before {
content: "\f10c";
color: #676a6c;
}
.ztree li span.button.chk.radio_false_part::before {
content: "\f10c";
color: #aaaaaa;
}
.ztree li span.button.chk.radio_false_part_focus::before {
content: "\f10c";
color: #676a6c;
}
.ztree li span.button.chk.radio_false_disable::before {
content: "\f1db";
color: #808080;
}
.ztree li span.button.chk.radio_true_full::before {
content: "\f192";
}
.ztree li span.button.chk.radio_true_full_focus::before {
content: "\f192";
color: #676a6c;
}
.ztree li span.button.chk.radio_true_part::before {
content: "\f192";
color: #aaaaaa;
}
.ztree li span.button.chk.radio_true_part_focus::before {
content: "\f192";
color: #aaaaaa;
}
.ztree li span.button.chk.radio_true_disable::before {
content: "\f1db";
color: #808080;
}
.ztree li span.button.switch {
width: 18px;
height: 20px;
}
.ztree li span.button.root_open::before {
content: "\f107";
padding-top: 10px;
padding-left: 2px;
display: inline-block;
}
.ztree li span.button.root_close::before {
content: "\f105";
padding-top: 10px;
padding-left: 2px;
display: inline-block;
}
.ztree li span.button.roots_open::before {
content: "\f107";
padding-top: 10px;
padding-left: 2px;
display: inline-block;
}
.ztree li span.button.roots_close::before {
content: "\f105";
padding-top: 10px;
padding-left: 2px;
display: inline-block;
}
.ztree li span.button.center_open::before {
content: "\f107";
padding-top: 10px;
padding-left: 2px;
display: inline-block;
}
.ztree li span.button.center_close::before {
content: "\f105";
padding-top: 10px;
padding-left: 2px;
display: inline-block;
}
.ztree li span.button.bottom_open::before {
content: "\f107";
padding-top: 10px;
padding-left: 2px;
display: inline-block;
}
.ztree li span.button.bottom_close::before {
content: "\f105";
padding-top: 10px;
padding-left: 2px;
display: inline-block;
}
.ztree li span.button.root_docu {
background: none;
}
.ztree li span.button.roots_docu::before {
content: "\f114";
padding-left: 2px;
display: inline-block;
color: #676a6c;
}
.ztree li span.button.center_docu::before {
padding-top: 10px;
padding-left: 2px;
display: inline-block;
color: #676a6c;
}
.ztree li span.button.bottom_docu::before {
padding-top: 10px;
padding-left: 2px;
display: inline-block;
color: #676a6c;
}
.ztree li span.button.noline_docu {
background: none;
}
.ztree li span.button.ico_open::before {
content: "\f07c";
font-family: FontAwesome;
padding-top: 10px;
padding-left: 2px;
display: inline-block;
color: #676a6c;
}
.ztree li span.button.ico_close::before {
content: "\f07b";
font-family: FontAwesome;
padding-top: 10px;
padding-left: 2px;
display: inline-block;
color: #676a6c;
}
.ztree li span.button.ico_docu::before {
content: "\f07b";
font-family: FontAwesome;
padding-top: 10px;
padding-left: 2px;
display: inline-block;
color: #676a6c;
}
.ztree li span.button.file_ico_docu::before {
content: "\f022";
font-family: FontAwesome;
padding-top: 10px;
padding-left: 2px;
display: inline-block;
color: #676a6c;
}
.ztree li span.button.linux_ico_docu::before {
content: "\f17c";
font-family: FontAwesome;
padding-top: 10px;
padding-left: 2px;
display: inline-block;
color: #676a6c;
}
.ztree li span.button.windows_ico_docu::before {
content: "\f17a";
font-family: FontAwesome;
padding-top: 10px;
padding-left: 2px;
display: inline-block;
color: #676a6c;
}
.ztree li span.button.edit {
margin-left: 4px;
margin-right: -1px;
vertical-align: top;
*vertical-align: middle;
padding-top: 10px;
}
.ztree li span.button.edit::before {
content: "\f044";
font-family: FontAwesome;
}
.ztree li span.button.remove {
margin-left: 4px;
margin-right: -1px;
vertical-align: top;
*vertical-align: middle;
padding-top: 10px;
}
.ztree li span.button.remove::before {
content: "\f1f8";
font-family: FontAwesome;
}
.ztree li span.button.add {
margin-left: 4px;
margin-right: -1px;
vertical-align: top;
*vertical-align: middle;
padding-top: 10px;
}
.ztree li span.button.add::before {
content: "\f067";
font-family: FontAwesome;
}
.ztree li span.button.ico_loading {
margin-right: 2px;
background: url(./loading.gif) no-repeat scroll 0 0 transparent;
vertical-align: top;
*vertical-align: middle;
}
ul.tmpTargetzTree {
background-color: #FFE6B0;
opacity: 0.8;
filter: alpha(opacity=80);
}
span.tmpzTreeMove_arrow {
width: 16px;
height: 20px;
display: inline-block;
padding: 0;
margin: 2px 0 0 1px;
border: 0 none;
position: absolute;
background-color: transparent;
background-attachment: scroll;
}
span.tmpzTreeMove_arrow::before {
content: "\f04b";
font-family: FontAwesome;
color: #676a6c;
}
ul.ztree.zTreeDragUL {
margin: 0;
padding: 0;
position: absolute;
width: auto;
height: auto;
overflow: hidden;
background-color: #cfcfcf;
border: 1px #676a6c dotted;
opacity: 0.8;
filter: alpha(opacity=80);
}
.ztreeMask {
z-index: 10000;
background-color: #cfcfcf;
opacity: 0.0;
filter: alpha(opacity=0);
position: absolute;
}

View File

@@ -17,9 +17,11 @@ export default {
treeSetting: {
showMenu: true,
showRefresh: true,
showAssets: false,
url: '/api/v1/assets/assets/',
nodeUrl: '/api/v1/assets/nodes/',
// ?assets=0不显示资产. =1显示资产
treeUrl: '/api/v1/assets/nodes/children/tree/?assets=0'
},
columns: [
{

View File

@@ -69,6 +69,10 @@ export default {
]
},
headerActions: {
hasRightActions: false,
hasExport: false,
hasImport: false,
hasRefresh: false,
hasBulkDelete: false,
createRoute: 'GatewayCreate'
}

View File

@@ -0,0 +1,83 @@
<template>
<GenericDetailPage :submenu="submenu" :active-menu="activeSubMenu" :title="title">
<div slot="detail">
<el-row :gutter="20">
<el-col :span="14">
<DetailCard :title="cardTitle" :items="detailItems" />
</el-col>
</el-row>
</div>
</GenericDetailPage>
</template>
<script>
import { GenericDetailPage } from '@/layout/components'
import DetailCard from '@/components/DetailCard/index'
import { getTerminalDetail } from '@/api/sessions'
export default {
name: 'TerminalDetail',
components: {
GenericDetailPage,
DetailCard
},
data() {
return {
terminalData: {},
activeSubMenu: 'detail',
submenu: [
{
title: this.$t('sessions.terminalDetail'),
name: 'detail'
}
]
}
},
computed: {
title() {
return this.$t('sessions.terminalDetail')
},
cardTitle() {
return this.terminalData.name
},
detailItems() {
return [
{
key: this.$t('sessions.name'),
value: this.terminalData.name
},
{
key: this.$t('sessions.remoteAddr'),
value: this.terminalData.remote_addr
},
{
key: this.$t('sessions.sshPort'),
value: this.terminalData.ssh_port
},
{
key: this.$t('sessions.httpPort'),
value: this.terminalData.http_port
},
{
key: this.$t('sessions.dateCreated'),
value: this.terminalData.date_created
},
{
key: this.$t('sessions.comment'),
value: this.terminalData.comment
}
]
}
},
mounted() {
getTerminalDetail(this.$route.params.id).then(data => {
this.terminalData = data
})
}
}
</script>
<style scoped>
</style>

View File

@@ -4,7 +4,7 @@
<script>
import { GenericListPage } from '@/layout/components'
import { DetailFormatter } from '@/components/ListTable/formatters/index'
import { ActionsFormatter, BooleanFormatter } from '@/components/ListTable/formatters'
export default {
components: {
@@ -13,47 +13,39 @@ export default {
data() {
return {
tableConfig: {
axiosConfig: {
raw: 1,
params: {
display: 1,
is_finished: 0
}
},
url: '/api/v1/terminal/terminals/',
columns: [
{
prop: 'name',
label: this.$tc('Name'),
key: 'name',
formatter: DetailFormatter,
sortable: true,
route: 'TerminalDetail'
},
{
prop: 'remote_addr',
label: this.$t('sessions.addr'),
columns: ['name', 'remote_addr', 'session_online', 'is_active', 'is_alive', 'actions'],
columnsMeta: {
name: {
sortable: 'custom'
},
{
prop: 'session_online',
label: this.$t('sessions.session'),
sortable: true
},
{
prop: 'is_active',
label: this.$t('sessions.active')
},
{
prop: 'is_alive',
label: this.$t('sessions.alive'),
remote_addr: {
sortable: 'custom'
},
is_active: {
label: this.$t('sessions.active'),
formatter: BooleanFormatter
},
is_alive: {
label: this.$t('sessions.alive')
},
session_online: {
label: this.$t('sessions.session')
},
actions: {
prop: 'id',
formatter: ActionsFormatter
}
]
}
},
headerActions: {
hasCreate: false,
hasBulkDelete: false,
hasUpload: false,
hasExport: false,
hasImport: false,
hasUpdate: false,
hasRefresh: false,
extraActions: [
{
name: 'StorageConfiguration',