diff --git a/spug_api/apps/exec/models.py b/spug_api/apps/exec/models.py index 0f86076..f4102b9 100644 --- a/spug_api/apps/exec/models.py +++ b/spug_api/apps/exec/models.py @@ -12,6 +12,7 @@ class ExecTemplate(models.Model, ModelMixin): type = models.CharField(max_length=50) body = models.TextField() interpreter = models.CharField(max_length=20) + host_ids = models.TextField(default='[]') desc = models.CharField(max_length=255, null=True) created_at = models.CharField(max_length=20, default=human_datetime) @@ -22,6 +23,11 @@ class ExecTemplate(models.Model, ModelMixin): def __repr__(self): return '' % self.name + def to_view(self): + tmp = self.to_dict() + tmp['host_ids'] = json.loads(self.host_ids) + return tmp + class Meta: db_table = 'exec_templates' ordering = ('-id',) diff --git a/spug_api/apps/exec/views.py b/spug_api/apps/exec/views.py index 775f090..a5d1d8a 100644 --- a/spug_api/apps/exec/views.py +++ b/spug_api/apps/exec/views.py @@ -18,7 +18,7 @@ class TemplateView(View): def get(self, request): templates = ExecTemplate.objects.all() types = [x['type'] for x in templates.order_by('type').values('type').distinct()] - return json_response({'types': types, 'templates': [x.to_dict() for x in templates]}) + return json_response({'types': types, 'templates': [x.to_view() for x in templates]}) @auth('exec.template.add|exec.template.edit') def post(self, request): @@ -28,6 +28,7 @@ class TemplateView(View): Argument('type', help='请选择模版类型'), Argument('body', help='请输入模版内容'), Argument('interpreter', default='sh'), + Argument('host_ids', type=list, handler=json.dumps, default=[]), Argument('desc', required=False) ).parse(request.body) if error is None: diff --git a/spug_web/src/pages/exec/task/TemplateSelector.js b/spug_web/src/pages/exec/task/TemplateSelector.js index 5ed991a..82d69ad 100644 --- a/spug_web/src/pages/exec/task/TemplateSelector.js +++ b/spug_web/src/pages/exec/task/TemplateSelector.js @@ -32,28 +32,33 @@ class TemplateSelector extends React.Component { handleSubmit = () => { if (this.state.selectedRows.length > 0) { - const {body, interpreter} = this.state.selectedRows[0] - this.props.onOk(body, interpreter) + const {host_ids, body, interpreter} = this.state.selectedRows[0] + this.props.onOk(host_ids, body, interpreter) } this.props.onCancel() }; - columns = [{ - title: '类型', - dataIndex: 'type', - }, { - title: '名称', - dataIndex: 'name', - ellipsis: true - }, { - title: '内容', - dataIndex: 'body', - ellipsis: true - }, { - title: '备注', - dataIndex: 'desc', - ellipsis: true - }]; + columns = [ + { + title: '名称', + dataIndex: 'name', + ellipsis: true + }, { + title: '类型', + dataIndex: 'type', + }, { + title: '目标主机', + dataIndex: 'host_ids', + render: v => `${v.length}台` + }, { + title: '内容', + dataIndex: 'body', + ellipsis: true + }, { + title: '备注', + dataIndex: 'desc', + ellipsis: true + }]; render() { const {selectedRows} = this.state; @@ -84,7 +89,7 @@ class TemplateSelector extends React.Component { store.f_name = e.target.value} placeholder="请输入"/> - + { + return () => { + store.host_ids = [] + if (store.showConsole) { + store.switchConsole() + } + } + }, []) + function handleSubmit() { setLoading(true) const host_ids = store.host_ids; @@ -37,7 +46,8 @@ function TaskIndex() { .finally(() => setLoading(false)) } - function handleTemplate(command, interpreter) { + function handleTemplate(host_ids, command, interpreter) { + if (host_ids.length > 0) store.host_ids = host_ids setInterpreter(interpreter) setCommand(command) } diff --git a/spug_web/src/pages/exec/template/Form.js b/spug_web/src/pages/exec/template/Form.js index 5ceffbe..7f3f819 100644 --- a/spug_web/src/pages/exec/template/Form.js +++ b/spug_web/src/pages/exec/template/Form.js @@ -8,6 +8,7 @@ import { observer } from 'mobx-react'; import { ExclamationCircleOutlined } from '@ant-design/icons'; import { Modal, Form, Input, Select, Button, Radio, message } from 'antd'; import { ACEditor } from 'components'; +import Selector from 'pages/host/Selector'; import { http, cleanCommand } from 'libs'; import store from './store'; @@ -15,12 +16,14 @@ export default observer(function () { const [form] = Form.useForm(); const [loading, setLoading] = useState(false); const [body, setBody] = useState(store.record.body); + const [visible, setVisible] = useState(false); function handleSubmit() { setLoading(true); const formData = form.getFieldsValue(); formData['id'] = store.record.id; formData['body'] = cleanCommand(body); + formData['host_ids'] = store.record.host_ids; http.post('/api/exec/template/', formData) .then(res => { message.success('操作成功'); @@ -91,10 +94,19 @@ export default observer(function () { height="300px"/> )} + + {info.host_ids.length > 0 && 已选择 {info.host_ids.length} 台} + + + setVisible(false)} + onOk={(_, ids) => info.host_ids = ids}/> ) }) \ No newline at end of file diff --git a/spug_web/src/pages/exec/template/Table.js b/spug_web/src/pages/exec/template/Table.js index c270c2e..a54565d 100644 --- a/spug_web/src/pages/exec/template/Table.js +++ b/spug_web/src/pages/exec/template/Table.js @@ -69,7 +69,7 @@ class ComTable extends React.Component { ( store.showForm(info)}>编辑 - this.handleDelete(info)}>删除 + this.handleDelete(info)}>删除 )}/> )} diff --git a/spug_web/src/pages/exec/template/store.js b/spug_web/src/pages/exec/template/store.js index 541f10e..2419719 100644 --- a/spug_web/src/pages/exec/template/store.js +++ b/spug_web/src/pages/exec/template/store.js @@ -26,7 +26,7 @@ class Store { .finally(() => this.isFetching = false) }; - showForm = (info = {interpreter: 'sh'}) => { + showForm = (info = {interpreter: 'sh', host_ids: []}) => { this.formVisible = true; this.record = info }