mirror of
https://github.com/jumpserver/lina.git
synced 2025-08-18 23:07:41 +00:00
feat: Job 支持运行参数
This commit is contained in:
parent
95945a3b20
commit
4b84a77a5a
@ -5,9 +5,11 @@
|
|||||||
style="height: 100%;width: 100%;vertical-align: middle;display: inline-block;background-color: #1ab394"
|
style="height: 100%;width: 100%;vertical-align: middle;display: inline-block;background-color: #1ab394"
|
||||||
>
|
>
|
||||||
<template v-for="(item,index) in toolbar">
|
<template v-for="(item,index) in toolbar">
|
||||||
<el-button v-if="item.type==='button'" :key="index" size="mini">
|
<el-tooltip :key="index" :content="item.tip" placement="top">
|
||||||
<i :class="item.icon" />
|
<el-button v-if="item.type==='button'" size="mini" type="primary" @click="item.callback">
|
||||||
</el-button>
|
<i :class="item.icon" />
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<codemirror ref="myCm" v-model="iValue" :options="cmOptions" />
|
<codemirror ref="myCm" v-model="iValue" :options="cmOptions" />
|
||||||
@ -64,6 +66,7 @@ export default {
|
|||||||
return this.value
|
return this.value
|
||||||
},
|
},
|
||||||
set(val) {
|
set(val) {
|
||||||
|
this.$emit('update:value', val)
|
||||||
this.$emit('change', val)
|
this.$emit('change', val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -701,7 +701,9 @@
|
|||||||
"Module": "模块",
|
"Module": "模块",
|
||||||
"Asset": "资产",
|
"Asset": "资产",
|
||||||
"Plan": "计划",
|
"Plan": "计划",
|
||||||
"AssetAmount": "资产数量"
|
"AssetAmount": "资产数量",
|
||||||
|
"SelectAdhoc": "选择命令",
|
||||||
|
"SaveAdhoc": "保存命令"
|
||||||
},
|
},
|
||||||
"perms": {
|
"perms": {
|
||||||
"": "",
|
"": "",
|
||||||
|
@ -12,13 +12,6 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
cmOptions: {
|
|
||||||
tabSize: 4,
|
|
||||||
mode: 'shell',
|
|
||||||
theme: 'base16-light',
|
|
||||||
lineNumbers: true,
|
|
||||||
line: true
|
|
||||||
},
|
|
||||||
url: '/api/v1/ops/adhocs/',
|
url: '/api/v1/ops/adhocs/',
|
||||||
fields: [
|
fields: [
|
||||||
[this.$t('common.Basic'), ['name', 'module', 'args']]
|
[this.$t('common.Basic'), ['name', 'module', 'args']]
|
||||||
|
86
src/views/ops/Job/AdhocOpenDialog.vue
Normal file
86
src/views/ops/Job/AdhocOpenDialog.vue
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
<template>
|
||||||
|
<GenericListTableDialog
|
||||||
|
:header-actions="headerActions"
|
||||||
|
:visible.sync="iVisible"
|
||||||
|
v-bind="config"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { GenericListTableDialog } from '@/layout/components'
|
||||||
|
import { ActionsFormatter } from '@/components/TableFormatters'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
GenericListTableDialog
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
account: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
config: {
|
||||||
|
title: this.$t('ops.SelectAdhoc'),
|
||||||
|
visible: false,
|
||||||
|
width: '60%',
|
||||||
|
tableConfig: {
|
||||||
|
url: `/api/v1/ops/adhocs/`,
|
||||||
|
columns: ['name', 'module', 'args', 'actions'],
|
||||||
|
columnsMeta: {
|
||||||
|
actions: {
|
||||||
|
formatter: ActionsFormatter,
|
||||||
|
formatterArgs: {
|
||||||
|
hasUpdate: false,
|
||||||
|
hasClone: false,
|
||||||
|
hasDelete: false,
|
||||||
|
extraActions: [
|
||||||
|
{
|
||||||
|
title: '选择',
|
||||||
|
name: 'select',
|
||||||
|
can: true,
|
||||||
|
callback: ({ row }) => {
|
||||||
|
this.$emit('select', row)
|
||||||
|
this.iVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
headerActions: {
|
||||||
|
hasImport: false,
|
||||||
|
hasExport: false,
|
||||||
|
hasLeftActions: false,
|
||||||
|
hasColumnSetting: false,
|
||||||
|
hasSearch: false,
|
||||||
|
searchConfig: {
|
||||||
|
getUrlQuery: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
iVisible: {
|
||||||
|
get() {
|
||||||
|
return this.visible
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$emit('update:visible', val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
79
src/views/ops/Job/AdhocSaveDialog.vue
Normal file
79
src/views/ops/Job/AdhocSaveDialog.vue
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<template>
|
||||||
|
<Dialog
|
||||||
|
v-if="iVisible"
|
||||||
|
:title="$tc('ops.SaveAdhoc')"
|
||||||
|
:visible.sync="iVisible"
|
||||||
|
width="40%"
|
||||||
|
top="1vh"
|
||||||
|
:show-cancel="false"
|
||||||
|
:show-confirm="false"
|
||||||
|
>
|
||||||
|
<GenericCreateUpdateForm v-if="ready" v-bind="$data" />
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Dialog from '@/components/Dialog'
|
||||||
|
import { GenericCreateUpdateForm } from '@/layout/components'
|
||||||
|
import CodeEditor from '@/components/FormFields/CodeEditor'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Dialog, GenericCreateUpdateForm
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
args: {
|
||||||
|
type: String,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
ready: false,
|
||||||
|
url: '/api/v1/ops/adhocs/',
|
||||||
|
fields: [
|
||||||
|
['', ['name', 'module', 'args']]
|
||||||
|
],
|
||||||
|
initial: {
|
||||||
|
module: 'shell',
|
||||||
|
args: ''
|
||||||
|
},
|
||||||
|
fieldsMeta: {
|
||||||
|
args: {
|
||||||
|
label: 'content',
|
||||||
|
component: CodeEditor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
iVisible: {
|
||||||
|
set(val) {
|
||||||
|
this.$emit('update:visible', val)
|
||||||
|
},
|
||||||
|
get() {
|
||||||
|
return this.visible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, mounted() {
|
||||||
|
this.initial.args = this.args
|
||||||
|
this.ready = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.el-row-divider {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-prop-label {
|
||||||
|
float: right;
|
||||||
|
padding-right: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
79
src/views/ops/Job/JobCodeEditor.vue
Normal file
79
src/views/ops/Job/JobCodeEditor.vue
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<AdhocOpenDialog v-if="showOpenAdhocDialog" :visible.sync="showOpenAdhocDialog" @select="onSelectAdhoc" />
|
||||||
|
<AdhocSaveDialog
|
||||||
|
v-if="showOpenAdhocSaveDialog"
|
||||||
|
:args="iValue"
|
||||||
|
:visible.sync="showOpenAdhocSaveDialog"
|
||||||
|
/>
|
||||||
|
<CodeEditor :value.sync="iValue" :toolbar="toolbar" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import CodeEditor from '@/components/FormFields/CodeEditor'
|
||||||
|
import AdhocOpenDialog from '@/views/ops/Job/AdhocOpenDialog'
|
||||||
|
import AdhocSaveDialog from '@/views/ops/Job/AdhocSaveDialog'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
CodeEditor,
|
||||||
|
AdhocOpenDialog,
|
||||||
|
AdhocSaveDialog
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: [String, Object],
|
||||||
|
default: () => ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showOpenAdhocDialog: false,
|
||||||
|
showOpenAdhocSaveDialog: false,
|
||||||
|
toolbar: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
icon: 'fa fa-folder-open-o',
|
||||||
|
tip: 'Open Command',
|
||||||
|
callback: () => {
|
||||||
|
this.openAdhocSelectDialog()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
icon: 'fa fa-save',
|
||||||
|
tip: 'Save Command',
|
||||||
|
callback: () => {
|
||||||
|
this.openAdhocSaveDialog()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
iValue: {
|
||||||
|
get() {
|
||||||
|
return this.value
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$emit('change', val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, methods: {
|
||||||
|
openAdhocSelectDialog() {
|
||||||
|
this.showOpenAdhocDialog = true
|
||||||
|
},
|
||||||
|
openAdhocSaveDialog() {
|
||||||
|
this.showOpenAdhocSaveDialog = true
|
||||||
|
},
|
||||||
|
onSelectAdhoc(adhoc) {
|
||||||
|
this.iValue = adhoc.args
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
92
src/views/ops/Job/JobRunDialog.vue
Normal file
92
src/views/ops/Job/JobRunDialog.vue
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<template>
|
||||||
|
<Dialog
|
||||||
|
v-if="iVisible"
|
||||||
|
:title="$tc('ops.SaveAdhoc')"
|
||||||
|
:visible.sync="iVisible"
|
||||||
|
width="50%"
|
||||||
|
top="1vh"
|
||||||
|
:show-cancel="false"
|
||||||
|
:show-confirm="false"
|
||||||
|
>
|
||||||
|
<el-form ref="form" :model="form" label-width="140px">
|
||||||
|
<el-form-item v-for="(item,key,index) in vars" :key="index" :label="item.label">
|
||||||
|
<template v-if="item.type === 'select'">
|
||||||
|
<el-select v-model="form[key]">
|
||||||
|
<el-option
|
||||||
|
v-for="option in item.options"
|
||||||
|
:key="option.value"
|
||||||
|
:label="option.label"
|
||||||
|
:value="option.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<el-input v-model="form[key]" />
|
||||||
|
</template>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" @click="onSubmit">执行</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Dialog from '@/components/Dialog'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Dialog
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
vars: {},
|
||||||
|
form: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
iVisible: {
|
||||||
|
set(val) {
|
||||||
|
this.$emit('update:visible', val)
|
||||||
|
},
|
||||||
|
get() {
|
||||||
|
return this.visible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.vars = JSON.parse(this.item.parameters_define)
|
||||||
|
for (const key of Object.keys(this.vars)) {
|
||||||
|
this.form[key] = this.vars[key].default || ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onSubmit() {
|
||||||
|
this.$emit('submit', this.item, JSON.stringify(this.form))
|
||||||
|
this.iVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.el-row-divider {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-prop-label {
|
||||||
|
float: right;
|
||||||
|
padding-right: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -1,14 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="ready">
|
<div v-if="ready">
|
||||||
<GenericCreateUpdatePage v-bind="$data" />
|
<GenericCreateUpdatePage ref="form" v-bind="$data" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { GenericCreateUpdatePage } from '@/layout/components'
|
import { GenericCreateUpdatePage } from '@/layout/components'
|
||||||
import CodeEditor from '@/components/FormFields/CodeEditor'
|
|
||||||
import AssetSelect from '@/components/AssetSelect'
|
import AssetSelect from '@/components/AssetSelect'
|
||||||
import { JsonEditor } from '@/components/FormFields'
|
import { JsonEditor } from '@/components/FormFields'
|
||||||
|
import JobCodeEditor from '@/views/ops/Job/JobCodeEditor'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@ -17,6 +17,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
ready: false,
|
ready: false,
|
||||||
|
showOpenAdhocDialog: false,
|
||||||
instantTask: false,
|
instantTask: false,
|
||||||
jobType: '',
|
jobType: '',
|
||||||
url: '/api/v1/ops/jobs/',
|
url: '/api/v1/ops/jobs/',
|
||||||
@ -24,7 +25,7 @@ export default {
|
|||||||
[this.$t('common.Basic'), ['name', 'type', 'instant', 'comment']],
|
[this.$t('common.Basic'), ['name', 'type', 'instant', 'comment']],
|
||||||
[this.$t('common.Task'), ['module', 'args', 'playbook', 'chdir', 'timeout']],
|
[this.$t('common.Task'), ['module', 'args', 'playbook', 'chdir', 'timeout']],
|
||||||
[this.$t('ops.Asset'), ['assets', 'runas', 'runas_policy']],
|
[this.$t('ops.Asset'), ['assets', 'runas', 'runas_policy']],
|
||||||
[this.$t('ops.Variable'), ['variables']],
|
[this.$t('ops.Variable'), ['parameters_define']],
|
||||||
[this.$t('ops.Plan'), ['runAfterSave', 'periodic', 'crontab']]
|
[this.$t('ops.Plan'), ['runAfterSave', 'periodic', 'crontab']]
|
||||||
],
|
],
|
||||||
initial: {
|
initial: {
|
||||||
@ -34,7 +35,7 @@ export default {
|
|||||||
runas_policy: 'skip',
|
runas_policy: 'skip',
|
||||||
runAfterSave: false,
|
runAfterSave: false,
|
||||||
instant: false,
|
instant: false,
|
||||||
variables: '{}',
|
parameters_define: '{}',
|
||||||
timeout: 60,
|
timeout: 60,
|
||||||
periodic: false,
|
periodic: false,
|
||||||
crontab: '0 0 * * *'
|
crontab: '0 0 * * *'
|
||||||
@ -81,14 +82,14 @@ export default {
|
|||||||
hidden: (formValue) => {
|
hidden: (formValue) => {
|
||||||
return formValue.type !== 'adhoc'
|
return formValue.type !== 'adhoc'
|
||||||
},
|
},
|
||||||
component: CodeEditor
|
component: JobCodeEditor
|
||||||
},
|
},
|
||||||
instant: {
|
instant: {
|
||||||
hidden: () => {
|
hidden: () => {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
variables: {
|
parameters_define: {
|
||||||
label: this.$t('ops.Variable'),
|
label: this.$t('ops.Variable'),
|
||||||
component: JsonEditor
|
component: JsonEditor
|
||||||
},
|
},
|
||||||
@ -139,6 +140,16 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
this.ready = true
|
this.ready = true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
openAdhocSelectDialog() {
|
||||||
|
this.showOpenAdhocDialog = true
|
||||||
|
},
|
||||||
|
onSelectAdhoc(item) {
|
||||||
|
|
||||||
|
},
|
||||||
|
onOpenSaveAdhocDialog() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,18 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<GenericListPage :table-config="tableConfig" :header-actions="headerActions" />
|
<div>
|
||||||
|
<JobRunDialog v-if="showJobRunDialog" :visible.sync="showJobRunDialog" :item="item" @submit="runJob" />
|
||||||
|
<GenericListPage :table-config="tableConfig" :header-actions="headerActions" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import GenericListPage from '@/layout/components/GenericListPage'
|
import GenericListPage from '@/layout/components/GenericListPage'
|
||||||
import { ActionsFormatter } from '@/components/TableFormatters'
|
import { ActionsFormatter } from '@/components/TableFormatters'
|
||||||
import { openTaskPage } from '@/utils/jms'
|
import { openTaskPage } from '@/utils/jms'
|
||||||
|
import JobRunDialog from '@/views/ops/Job/JobRunDialog'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
JobRunDialog,
|
||||||
GenericListPage
|
GenericListPage
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
item: {},
|
||||||
|
runtime_parameters: {},
|
||||||
|
showJobRunDialog: false,
|
||||||
tableConfig: {
|
tableConfig: {
|
||||||
url: '/api/v1/ops/jobs/',
|
url: '/api/v1/ops/jobs/',
|
||||||
columns: [
|
columns: [
|
||||||
@ -46,7 +54,12 @@ export default {
|
|||||||
type: 'running',
|
type: 'running',
|
||||||
can: true,
|
can: true,
|
||||||
callback: ({ row }) => {
|
callback: ({ row }) => {
|
||||||
this.runJob(row)
|
if (row.parameters_define) {
|
||||||
|
this.item = row
|
||||||
|
this.showJobRunDialog = true
|
||||||
|
} else {
|
||||||
|
this.runJob(row)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -65,8 +78,12 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
runJob(row) {
|
runJob(row, parameters) {
|
||||||
this.$axios.post('/api/v1/ops/job-executions/', { job: row.id }).then(data => {
|
console.log(row)
|
||||||
|
this.$axios.post('/api/v1/ops/job-executions/', {
|
||||||
|
job: row.id,
|
||||||
|
parameters: parameters
|
||||||
|
}).then(data => {
|
||||||
this.$axios.get(`/api/v1/ops/job-executions/${data.id}/`).then(d => {
|
this.$axios.get(`/api/v1/ops/job-executions/${data.id}/`).then(d => {
|
||||||
openTaskPage(d.task_id)
|
openTaskPage(d.task_id)
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user