perf: 重新设计菜单和交互流程

This commit is contained in:
Aaron3S
2022-11-29 19:43:26 +08:00
parent bb910aa447
commit 5b1bc4478c
16 changed files with 247 additions and 178 deletions

View File

@@ -691,8 +691,10 @@
"privilegeOnly": "仅选择特权账号",
"privilegeFirst": "优先选择特权账号",
"skip": "忽略当前资产",
"QuickJob": "快捷作业",
"instantAdhoc": "即时命令",
"myAdhoc": "我的命令",
"AdhocManage": "命令管理",
"PlaybookManage": "Playbook管理",
"history": "历史记录",
"createAdhoc": "创建命令",
"AdhocDetail": "命令详情",
@@ -840,6 +842,8 @@
"SessionList": "会话记录",
"BatchCommand": "批量命令",
"BatchScript": "批量脚本",
"Executions": "执行历史",
"ScriptManage": "脚本管理",
"TicketsTodo": "待办工单",
"TicketsDone": "已办工单",
"TicketsNew": "提交工单",
@@ -896,7 +900,7 @@
"GatewayUpdate": "更新网关",
"TaskCenter": "任务中心",
"JobCenter": "作业中心",
"JobList": "作业列表",
"JobList": "作业管理",
"JobCreate": "创建作业",
"JobUpdate": "更新作业",
"JobDetail": "作业详情",

View File

@@ -89,6 +89,17 @@ export default {
permissions: []
},
children: [
{
path: 'quick-job',
name: 'QuickJob',
hidden: true,
component: () => import('@/views/ops/Job/QuickJob'),
meta: {
title: i18n.t('ops.QuickJob'),
permissions: [],
activeMenu: '/workbench/ops/job'
}
},
{
path: 'job',
name: 'Job',
@@ -144,17 +155,49 @@ export default {
]
},
{
path: 'adhoc',
name: 'Adhoc',
component: () => import('@/views/ops/Adhoc'),
path: 'scripts',
name: 'ScriptManage',
component: () => import('@/views/ops/ScriptManage'),
meta: {
title: i18n.t('route.BatchCommand'),
title: i18n.t('route.ScriptManage'),
permissions: []
}
},
{
path: 'command/:id',
component: () => import('@/views/ops/Adhoc/my/AdhocDetail'),
path: 'executions',
name: 'Executions',
component: () => import('@/views/ops/Executions'),
meta: {
title: i18n.t('route.Executions'),
permissions: []
}
},
{
path: 'adhoc/:id/update',
name: 'AdhocUpdate',
component: () => import('@/views/ops/ScriptManage/Adhoc/AdhocUpdateCreate'),
hidden: true,
meta: {
title: i18n.t('route.updateAdhoc'),
permissions: [],
activeMenu: '/workbench/ops/adhoc'
}
},
{
path: 'adhoc/create',
name: 'AdhocCreate',
hidden: true,
component: () => import('@/views/ops/ScriptManage/Adhoc/AdhocUpdateCreate'),
meta: {
title: i18n.t('ops.createAdhoc'),
permissions: [],
activeMenu: '/workbench/ops/adhoc'
}
},
{
path: 'adhoc/:id',
component: () => import('@/views/ops/ScriptManage/Adhoc/AdhocDetail'),
name: 'AdhocDetail',
hidden: true,
meta: {
@@ -164,41 +207,10 @@ export default {
}
},
{
path: 'command/:id/update',
name: 'AdhocUpdate',
component: () => import('@/views/ops/Adhoc/my/AdhocUpdateCreate'),
hidden: true,
meta: {
title: i18n.t('route.updateAdhoc'),
permissions: [],
activeMenu: '/workbench/ops/adhoc'
}
},
{
path: 'command/create',
name: 'AdhocCreate',
hidden: true,
component: () => import('@/views/ops/Adhoc/my/AdhocUpdateCreate'),
meta: {
title: i18n.t('ops.createAdhoc'),
permissions: [],
activeMenu: '/workbench/ops/adhoc'
}
},
{
path: 'playbook',
name: 'Playbook',
component: () => import('@/views/ops/Playbook'),
meta: {
title: i18n.t('route.BatchScript'),
permissions: []
}
},
{
path: 'flow/create',
path: 'playbook/create',
name: 'PlaybookCreate',
hidden: true,
component: () => import('@/views/ops/Playbook/PlaybookUpdateCreate'),
component: () => import('@/views/ops/ScriptManage/Playbook/PlaybookUpdateCreate'),
meta: {
title: i18n.t('route.PlaybookCreate'),
permissions: [],

View File

@@ -1,51 +0,0 @@
<template>
<TabPage
:submenu="submenu"
:active-menu.sync="activeMenu"
>
<component :is="activeMenu" :query="{type:'adhoc'}" />
</TabPage>
</template>
<script>
import { TabPage } from '@/layout/components'
import MyAdhoc from '@/views/ops/Adhoc/MyAdhoc'
import InstantAdhoc from '@/views/ops/Adhoc/InstantAdhoc'
import JobHistory from '@/views/ops/Job/JobDetail/JobHistory'
export default {
name: 'Index',
components: {
TabPage,
MyAdhoc,
InstantAdhoc,
JobHistory
},
data() {
return {
activeMenu: 'MyAdhoc',
submenu: [
{
title: this.$t('ops.instantAdhoc'),
name: 'InstantAdhoc'
},
{
title: this.$t('ops.myAdhoc'),
name: 'MyAdhoc'
},
{
title: this.$t('ops.history'),
name: 'JobHistory'
}
]
}
},
mounted() {
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,114 @@
<template>
<div>
<GenericListPage :table-config="tableConfig" :header-actions="headerActions" />
</div>
</template>
<script>
import { ActionsFormatter } from '@/components/TableFormatters'
import { GenericListPage } from '@/layout/components'
export default {
components: {
GenericListPage
},
data() {
return {
uploadDialogVisible: false,
tableConfig: {
url: '/api/v1/ops/job-executions/',
columns: [
'id', 'job_type', 'is_finished', 'is_success', 'time_cost', 'date_created', 'actions'
],
columnsMeta: {
name: {
formatterArgs: {
can: true
}
},
is_finished: {
label: this.$t('ops.isFinished'),
width: '96px',
formatter: (row) => {
if (row.is_finished) {
return <i Class='fa fa-check text-primary'/>
}
return <i Class='fa fa-times text-danger'/>
},
formatterArgs: {
width: '14px'
}
},
is_success: {
label: this.$t('ops.isSuccess'),
width: '96px',
formatter: (row) => {
if (!row.is_finished) {
return <i Class='fa fa fa-spinner fa-spin'/>
}
if (row.is_success) {
return <i Class='fa fa-check text-primary'/>
}
return <i Class='fa fa-times text-danger'/>
},
formatterArgs: {
width: '14px'
}
},
time_cost: {
label: this.$t('ops.time'),
width: '100px',
formatter: function(row) {
if (row.time_cost) {
return row.time_cost.toFixed(2) + 's'
}
return '-'
}
},
actions: {
formatter: ActionsFormatter,
formatterArgs: {
hasUpdate: false,
hasDelete: false,
hasClone: false,
extraActions: [
{
title: this.$t('详情'),
name: 'detail',
can: true,
callback: ({ row }) => {
// this.$router.push({name: 'JobCreate', query: {type: 'adhoc', id: row.id}})
}
},
{
title: this.$t('日志'),
name: 'detail',
can: true,
callback: ({ row }) => {
// this.$router.push({name: 'JobCreate', query: {type: 'adhoc', id: row.id}})
}
}
]
}
}
}
},
headerActions: {
hasCreate: false,
canCreate: false,
hasRefresh: true,
hasExport: false,
hasImport: false,
hasMoreActions: false,
onCreate: () => {
this.uploadDialogVisible = true
}
}
}
}
}
</script>
<style>
</style>

View File

@@ -27,8 +27,8 @@ export default {
[this.$t('common.Basic'), ['name', 'type', 'instant', 'comment']],
[this.$t('common.Task'), ['module', 'args', 'playbook', 'chdir', 'timeout']],
[this.$t('ops.Asset'), ['assets', 'runas', 'runas_policy']],
[this.$t('ops.Plan'), ['runAfterSave', 'is_periodic', 'crontab']],
[this.$t('ops.Parameter'), ['use_parameter_define', 'parameters_define']]
[this.$t('ops.Parameter'), ['use_parameter_define', 'parameters_define']],
[this.$t('ops.Plan'), ['runAfterSave', 'is_periodic', 'crontab']]
],
initial: {
type: 'adhoc',
@@ -121,7 +121,6 @@ export default {
}
},
use_parameter_define: {
label: this.$t('ops.UseParameterDefine'),
type: 'switch',
hidden: () => {
return this.instantTask
@@ -168,8 +167,7 @@ export default {
this.ready = true
}
},
methods: {
}
methods: {}
}
</script>

View File

@@ -1,45 +1,51 @@
<template>
<el-collapse-transition>
<div style="display: flex;justify-items: center; flex-wrap: nowrap;justify-content:space-between;">
<div
v-show="iShowTree"
:style="{width: iShowTree?'20%': 0}"
class="transition-box tree-box"
>
<AutoDataZTree
ref="AutoDataZTree"
:key="DataZTree"
:setting="treeSetting"
class="auto-data-ztree"
/>
</div>
<div :style="iShowTree?('display: flex;width: 80%;'):('display: flex;width:100%;')">
<div class="mini">
<div style="display:block" class="mini-button" @click="iShowTree=!iShowTree">
<i v-show="iShowTree" class="fa fa-angle-left fa-x" /><i v-show="!iShowTree" class="fa fa-angle-right fa-x" />
</div>
</div>
<IBox class="transition-box" style="width: calc(100% - 17px);">
<el-form label-width="160px">
<el-form-item label="runas">
<el-input v-model="runas" />
</el-form-item>
<el-form-item label="runas policy">
<el-select v-model="runasPolicy">
<el-option v-for="(item,index) of runasPolicyOptions" :key="index" :value="item">
{{ item.label }}
</el-option>
</el-select>
</el-form-item>
</el-form>
<CodeEditor style="margin-bottom: 20px" :toolbar="toolbar" />
<Term ref="xterm" />
<div style="display: flex;margin-top:10px;justify-content: space-between" />
</IBox>
<Page>
<el-collapse-transition>
<div style="display: flex;justify-items: center; flex-wrap: nowrap;justify-content:space-between;">
<div
v-show="iShowTree"
:style="{width: iShowTree?'20%': 0}"
class="transition-box tree-box"
>
<AutoDataZTree
ref="AutoDataZTree"
:key="DataZTree"
:setting="treeSetting"
class="auto-data-ztree"
/>
</div>
<div :style="iShowTree?('display: flex;width: 80%;'):('display: flex;width:100%;')">
<div class="mini">
<div style="display:block" class="mini-button" @click="iShowTree=!iShowTree">
<i v-show="iShowTree" class="fa fa-angle-left fa-x" /><i
v-show="!iShowTree"
class="fa fa-angle-right fa-x"
/>
</div>
</div>
<IBox class="transition-box" style="width: calc(100% - 17px);">
<el-form label-width="160px">
<el-form-item label="runas">
<el-input v-model="runas" />
</el-form-item>
<el-form-item label="runas policy">
<el-select v-model="runasPolicy">
<el-option v-for="(item,index) of runasPolicyOptions" :key="index" :value="item">
{{ item.label }}
</el-option>
</el-select>
</el-form-item>
</el-form>
<CodeEditor style="margin-bottom: 20px" :toolbar="toolbar" />
<Term ref="xterm" />
<div style="display: flex;margin-top:10px;justify-content: space-between" />
</IBox>
</div>
</div>
</div>
</el-collapse-transition>
</el-collapse-transition>
</Page>
</template>
<script>
@@ -47,10 +53,12 @@ import AutoDataZTree from '@/components/AutoDataZTree'
import Term from '@/components/Term'
import IBox from '@/components/IBox'
import CodeEditor from '@/components/FormFields/CodeEditor'
import Page from '@/layout/components/Page'
export default {
name: 'CommandExecution',
components: {
Page,
Term,
AutoDataZTree,
IBox,
@@ -147,17 +155,6 @@ export default {
},
getSelectedAssetsNode() {
const nodes = this.$refs.AutoDataZTree.$refs.dataztree.$refs.ztree.getCheckedNodes()
// const assetsNodeId = []
// const assetsNode = []
// nodes.forEach(function (node) {
// if (node.meta.type === 'asset' && !node.isHidden) {
// const protocolsStr = node.meta.data.protocols + ''
// if (assetsNodeId.indexOf(node.id) === -1 && protocolsStr.indexOf('ssh') > -1) {
// assetsNodeId.push(node.id)
// assetsNode.push(node)
// }
// }
// })
return nodes
},
enableWS() {
@@ -204,12 +201,7 @@ export default {
this.$axios.post(
url, data
).then(res => {
console.log(res)
setTimeout(() => {
this.$axios.get(`/api/v1/ops/jobs/${res.id}/`).then((data) => {
this.writeExecutionOutput(data.task_id)
}, 100)
})
this.writeExecutionOutput(res.task_id)
})
}
}

View File

@@ -108,18 +108,30 @@ export default {
hasRefresh: true,
hasExport: false,
hasImport: false,
hasMoreActions: false
hasMoreActions: false,
extraActions: [
{
name: this.$t('ops.QuickJob'),
title: this.$t('ops.QuickJob'),
has: () => {
return true
},
callback: () => {
this.$router.push({ name: 'QuickJob' })
}
}
]
}
}
},
methods: {
runJob(row, parameters) {
console.log(row)
this.$axios.post('/api/v1/ops/job-executions/', {
job: row.id,
parameters: parameters
}).then(() => {
this.$message.success(this.$tc('ops.TaskDispatch'))
this.$router.push({ name: 'Executions' })
})
}
}

View File

@@ -1,12 +0,0 @@
<template>
<div />
</template>
<script>
export default {
}
</script>
<style scoped>
</style>

View File

@@ -8,7 +8,7 @@
<script>
import { GenericDetailPage } from '@/layout/components'
import AdhocDetail from '@/views/ops/Adhoc/my/AdhocDetail/AdhocDetail'
import AdhocDetail from '@/views/ops/ScriptManage/Adhoc/AdhocDetail/AdhocDetail'
export default {
components: {

View File

@@ -8,7 +8,7 @@
<script>
import GenericListTable from '@/layout/components/GenericListTable'
import { ActionsFormatter } from '@/components/TableFormatters'
import UploadDialog from '@/views/ops/Playbook/UploadDialog'
import UploadDialog from '@/views/ops/ScriptManage/Playbook/UploadDialog'
export default {
components: {

View File

@@ -10,27 +10,27 @@
<script>
import { TabPage } from '@/layout/components'
import PlaybookList from '@/views/ops/Playbook/PlaybookList'
import History from '@/views/ops/Playbook/HIstory'
import Adhoc from '@/views/ops/ScriptManage/Adhoc'
import Playbook from '@/views/ops/ScriptManage/Playbook'
export default {
name: 'Index',
components: {
TabPage,
PlaybookList,
History
Adhoc,
Playbook
},
data() {
return {
activeMenu: 'PlaybookList',
activeMenu: 'Adhoc',
submenu: [
{
title: 'Playbook',
name: 'PlaybookList'
title: this.$t('ops.AdhocManage'),
name: 'Adhoc'
},
{
title: this.$t('ops.history'),
name: 'History'
title: this.$t('ops.PlaybookManage'),
name: 'Playbook'
}
]
}