mirror of https://github.com/openspug/spug
U 优化模版管理
parent
981fa28505
commit
375ac435e2
|
@ -12,6 +12,7 @@ class ExecTemplate(models.Model, ModelMixin):
|
||||||
type = models.CharField(max_length=50)
|
type = models.CharField(max_length=50)
|
||||||
body = models.TextField()
|
body = models.TextField()
|
||||||
interpreter = models.CharField(max_length=20)
|
interpreter = models.CharField(max_length=20)
|
||||||
|
host_ids = models.TextField(default='[]')
|
||||||
desc = models.CharField(max_length=255, null=True)
|
desc = models.CharField(max_length=255, null=True)
|
||||||
|
|
||||||
created_at = models.CharField(max_length=20, default=human_datetime)
|
created_at = models.CharField(max_length=20, default=human_datetime)
|
||||||
|
@ -22,6 +23,11 @@ class ExecTemplate(models.Model, ModelMixin):
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<ExecTemplate %r>' % self.name
|
return '<ExecTemplate %r>' % self.name
|
||||||
|
|
||||||
|
def to_view(self):
|
||||||
|
tmp = self.to_dict()
|
||||||
|
tmp['host_ids'] = json.loads(self.host_ids)
|
||||||
|
return tmp
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = 'exec_templates'
|
db_table = 'exec_templates'
|
||||||
ordering = ('-id',)
|
ordering = ('-id',)
|
||||||
|
|
|
@ -18,7 +18,7 @@ class TemplateView(View):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
templates = ExecTemplate.objects.all()
|
templates = ExecTemplate.objects.all()
|
||||||
types = [x['type'] for x in templates.order_by('type').values('type').distinct()]
|
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')
|
@auth('exec.template.add|exec.template.edit')
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
|
@ -28,6 +28,7 @@ class TemplateView(View):
|
||||||
Argument('type', help='请选择模版类型'),
|
Argument('type', help='请选择模版类型'),
|
||||||
Argument('body', help='请输入模版内容'),
|
Argument('body', help='请输入模版内容'),
|
||||||
Argument('interpreter', default='sh'),
|
Argument('interpreter', default='sh'),
|
||||||
|
Argument('host_ids', type=list, handler=json.dumps, default=[]),
|
||||||
Argument('desc', required=False)
|
Argument('desc', required=False)
|
||||||
).parse(request.body)
|
).parse(request.body)
|
||||||
if error is None:
|
if error is None:
|
||||||
|
|
|
@ -32,19 +32,24 @@ class TemplateSelector extends React.Component {
|
||||||
|
|
||||||
handleSubmit = () => {
|
handleSubmit = () => {
|
||||||
if (this.state.selectedRows.length > 0) {
|
if (this.state.selectedRows.length > 0) {
|
||||||
const {body, interpreter} = this.state.selectedRows[0]
|
const {host_ids, body, interpreter} = this.state.selectedRows[0]
|
||||||
this.props.onOk(body, interpreter)
|
this.props.onOk(host_ids, body, interpreter)
|
||||||
}
|
}
|
||||||
this.props.onCancel()
|
this.props.onCancel()
|
||||||
};
|
};
|
||||||
|
|
||||||
columns = [{
|
columns = [
|
||||||
title: '类型',
|
{
|
||||||
dataIndex: 'type',
|
|
||||||
}, {
|
|
||||||
title: '名称',
|
title: '名称',
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
ellipsis: true
|
ellipsis: true
|
||||||
|
}, {
|
||||||
|
title: '类型',
|
||||||
|
dataIndex: 'type',
|
||||||
|
}, {
|
||||||
|
title: '目标主机',
|
||||||
|
dataIndex: 'host_ids',
|
||||||
|
render: v => `${v.length}台`
|
||||||
}, {
|
}, {
|
||||||
title: '内容',
|
title: '内容',
|
||||||
dataIndex: 'body',
|
dataIndex: 'body',
|
||||||
|
@ -84,7 +89,7 @@ class TemplateSelector extends React.Component {
|
||||||
<Input allowClear value={store.f_name} onChange={e => store.f_name = e.target.value} placeholder="请输入"/>
|
<Input allowClear value={store.f_name} onChange={e => store.f_name = e.target.value} placeholder="请输入"/>
|
||||||
</SearchForm.Item>
|
</SearchForm.Item>
|
||||||
<SearchForm.Item span={8}>
|
<SearchForm.Item span={8}>
|
||||||
<Button type="primary" icon={<SyncOutlined />} onClick={store.fetchRecords}>刷新</Button>
|
<Button type="primary" icon={<SyncOutlined/>} onClick={store.fetchRecords}>刷新</Button>
|
||||||
</SearchForm.Item>
|
</SearchForm.Item>
|
||||||
</SearchForm>
|
</SearchForm>
|
||||||
<Table
|
<Table
|
||||||
|
|
|
@ -29,6 +29,15 @@ function TaskIndex() {
|
||||||
}
|
}
|
||||||
}, [loading])
|
}, [loading])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
store.host_ids = []
|
||||||
|
if (store.showConsole) {
|
||||||
|
store.switchConsole()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
function handleSubmit() {
|
function handleSubmit() {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
const host_ids = store.host_ids;
|
const host_ids = store.host_ids;
|
||||||
|
@ -37,7 +46,8 @@ function TaskIndex() {
|
||||||
.finally(() => setLoading(false))
|
.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)
|
setInterpreter(interpreter)
|
||||||
setCommand(command)
|
setCommand(command)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { observer } from 'mobx-react';
|
||||||
import { ExclamationCircleOutlined } from '@ant-design/icons';
|
import { ExclamationCircleOutlined } from '@ant-design/icons';
|
||||||
import { Modal, Form, Input, Select, Button, Radio, message } from 'antd';
|
import { Modal, Form, Input, Select, Button, Radio, message } from 'antd';
|
||||||
import { ACEditor } from 'components';
|
import { ACEditor } from 'components';
|
||||||
|
import Selector from 'pages/host/Selector';
|
||||||
import { http, cleanCommand } from 'libs';
|
import { http, cleanCommand } from 'libs';
|
||||||
import store from './store';
|
import store from './store';
|
||||||
|
|
||||||
|
@ -15,12 +16,14 @@ export default observer(function () {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [body, setBody] = useState(store.record.body);
|
const [body, setBody] = useState(store.record.body);
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
|
||||||
function handleSubmit() {
|
function handleSubmit() {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const formData = form.getFieldsValue();
|
const formData = form.getFieldsValue();
|
||||||
formData['id'] = store.record.id;
|
formData['id'] = store.record.id;
|
||||||
formData['body'] = cleanCommand(body);
|
formData['body'] = cleanCommand(body);
|
||||||
|
formData['host_ids'] = store.record.host_ids;
|
||||||
http.post('/api/exec/template/', formData)
|
http.post('/api/exec/template/', formData)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
message.success('操作成功');
|
message.success('操作成功');
|
||||||
|
@ -91,10 +94,19 @@ export default observer(function () {
|
||||||
height="300px"/>
|
height="300px"/>
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item label="目标主机">
|
||||||
|
{info.host_ids.length > 0 && <span style={{marginRight: 16}}>已选择 {info.host_ids.length} 台</span>}
|
||||||
|
<Button type="link" style={{padding: 0}} onClick={() => setVisible(true)}>选择主机</Button>
|
||||||
|
</Form.Item>
|
||||||
<Form.Item name="desc" label="备注信息">
|
<Form.Item name="desc" label="备注信息">
|
||||||
<Input.TextArea placeholder="请输入模板备注信息"/>
|
<Input.TextArea placeholder="请输入模板备注信息"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
|
<Selector
|
||||||
|
visible={visible}
|
||||||
|
selectedRowKeys={[...info.host_ids]}
|
||||||
|
onCancel={() => setVisible(false)}
|
||||||
|
onOk={(_, ids) => info.host_ids = ids}/>
|
||||||
</Modal>
|
</Modal>
|
||||||
)
|
)
|
||||||
})
|
})
|
|
@ -69,7 +69,7 @@ class ComTable extends React.Component {
|
||||||
<Table.Column title="操作" render={info => (
|
<Table.Column title="操作" render={info => (
|
||||||
<Action>
|
<Action>
|
||||||
<Action.Button auth="exec.template.edit" onClick={() => store.showForm(info)}>编辑</Action.Button>
|
<Action.Button auth="exec.template.edit" onClick={() => store.showForm(info)}>编辑</Action.Button>
|
||||||
<Action.Button auth="exec.template.del" onClick={() => this.handleDelete(info)}>删除</Action.Button>
|
<Action.Button danger auth="exec.template.del" onClick={() => this.handleDelete(info)}>删除</Action.Button>
|
||||||
</Action>
|
</Action>
|
||||||
)}/>
|
)}/>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -26,7 +26,7 @@ class Store {
|
||||||
.finally(() => this.isFetching = false)
|
.finally(() => this.isFetching = false)
|
||||||
};
|
};
|
||||||
|
|
||||||
showForm = (info = {interpreter: 'sh'}) => {
|
showForm = (info = {interpreter: 'sh', host_ids: []}) => {
|
||||||
this.formVisible = true;
|
this.formVisible = true;
|
||||||
this.record = info
|
this.record = info
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue