mirror of
https://github.com/jumpserver/lina.git
synced 2025-08-02 07:27:01 +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"
|
||||
>
|
||||
<template v-for="(item,index) in toolbar">
|
||||
<el-button v-if="item.type==='button'" :key="index" size="mini">
|
||||
<i :class="item.icon" />
|
||||
</el-button>
|
||||
<el-tooltip :key="index" :content="item.tip" placement="top">
|
||||
<el-button v-if="item.type==='button'" size="mini" type="primary" @click="item.callback">
|
||||
<i :class="item.icon" />
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</div>
|
||||
<codemirror ref="myCm" v-model="iValue" :options="cmOptions" />
|
||||
@ -64,6 +66,7 @@ export default {
|
||||
return this.value
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('update:value', val)
|
||||
this.$emit('change', val)
|
||||
}
|
||||
}
|
||||
|
@ -701,7 +701,9 @@
|
||||
"Module": "模块",
|
||||
"Asset": "资产",
|
||||
"Plan": "计划",
|
||||
"AssetAmount": "资产数量"
|
||||
"AssetAmount": "资产数量",
|
||||
"SelectAdhoc": "选择命令",
|
||||
"SaveAdhoc": "保存命令"
|
||||
},
|
||||
"perms": {
|
||||
"": "",
|
||||
|
@ -12,13 +12,6 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
cmOptions: {
|
||||
tabSize: 4,
|
||||
mode: 'shell',
|
||||
theme: 'base16-light',
|
||||
lineNumbers: true,
|
||||
line: true
|
||||
},
|
||||
url: '/api/v1/ops/adhocs/',
|
||||
fields: [
|
||||
[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>
|
||||
<div v-if="ready">
|
||||
<GenericCreateUpdatePage v-bind="$data" />
|
||||
<GenericCreateUpdatePage ref="form" v-bind="$data" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { GenericCreateUpdatePage } from '@/layout/components'
|
||||
import CodeEditor from '@/components/FormFields/CodeEditor'
|
||||
import AssetSelect from '@/components/AssetSelect'
|
||||
import { JsonEditor } from '@/components/FormFields'
|
||||
import JobCodeEditor from '@/views/ops/Job/JobCodeEditor'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -17,6 +17,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
ready: false,
|
||||
showOpenAdhocDialog: false,
|
||||
instantTask: false,
|
||||
jobType: '',
|
||||
url: '/api/v1/ops/jobs/',
|
||||
@ -24,7 +25,7 @@ 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.Variable'), ['variables']],
|
||||
[this.$t('ops.Variable'), ['parameters_define']],
|
||||
[this.$t('ops.Plan'), ['runAfterSave', 'periodic', 'crontab']]
|
||||
],
|
||||
initial: {
|
||||
@ -34,7 +35,7 @@ export default {
|
||||
runas_policy: 'skip',
|
||||
runAfterSave: false,
|
||||
instant: false,
|
||||
variables: '{}',
|
||||
parameters_define: '{}',
|
||||
timeout: 60,
|
||||
periodic: false,
|
||||
crontab: '0 0 * * *'
|
||||
@ -81,14 +82,14 @@ export default {
|
||||
hidden: (formValue) => {
|
||||
return formValue.type !== 'adhoc'
|
||||
},
|
||||
component: CodeEditor
|
||||
component: JobCodeEditor
|
||||
},
|
||||
instant: {
|
||||
hidden: () => {
|
||||
return true
|
||||
}
|
||||
},
|
||||
variables: {
|
||||
parameters_define: {
|
||||
label: this.$t('ops.Variable'),
|
||||
component: JsonEditor
|
||||
},
|
||||
@ -139,6 +140,16 @@ export default {
|
||||
} else {
|
||||
this.ready = true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openAdhocSelectDialog() {
|
||||
this.showOpenAdhocDialog = true
|
||||
},
|
||||
onSelectAdhoc(item) {
|
||||
|
||||
},
|
||||
onOpenSaveAdhocDialog() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,26 @@
|
||||
<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>
|
||||
|
||||
<script>
|
||||
import GenericListPage from '@/layout/components/GenericListPage'
|
||||
import { ActionsFormatter } from '@/components/TableFormatters'
|
||||
import { openTaskPage } from '@/utils/jms'
|
||||
import JobRunDialog from '@/views/ops/Job/JobRunDialog'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
JobRunDialog,
|
||||
GenericListPage
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
item: {},
|
||||
runtime_parameters: {},
|
||||
showJobRunDialog: false,
|
||||
tableConfig: {
|
||||
url: '/api/v1/ops/jobs/',
|
||||
columns: [
|
||||
@ -46,7 +54,12 @@ export default {
|
||||
type: 'running',
|
||||
can: true,
|
||||
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: {
|
||||
runJob(row) {
|
||||
this.$axios.post('/api/v1/ops/job-executions/', { job: row.id }).then(data => {
|
||||
runJob(row, parameters) {
|
||||
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 => {
|
||||
openTaskPage(d.task_id)
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user