From 9d9470557e36dd42f8771dffa5eb47d594ae7be9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E4=BA=8C=E7=8C=9B?= Date: Sat, 14 Dec 2019 18:12:36 +0800 Subject: [PATCH] A web update --- spug_web/src/menus.js | 1 + spug_web/src/pages/deploy/request/Ext1Form.js | 98 +++++++++++++++++ spug_web/src/pages/deploy/request/Form.js | 104 ++++++++++++++++++ .../src/pages/deploy/request/SelectApp.js | 86 +++++++++++++++ spug_web/src/pages/deploy/request/Table.js | 72 ++++++++++++ spug_web/src/pages/deploy/request/index.js | 36 ++++++ .../src/pages/deploy/request/index.module.css | 30 +++++ spug_web/src/pages/deploy/request/store.js | 24 ++++ spug_web/src/pages/deploy/routes.js | 2 + spug_web/src/pages/host/store.js | 4 + 10 files changed, 457 insertions(+) create mode 100644 spug_web/src/pages/deploy/request/Ext1Form.js create mode 100644 spug_web/src/pages/deploy/request/Form.js create mode 100644 spug_web/src/pages/deploy/request/SelectApp.js create mode 100644 spug_web/src/pages/deploy/request/Table.js create mode 100644 spug_web/src/pages/deploy/request/index.js create mode 100644 spug_web/src/pages/deploy/request/index.module.css create mode 100644 spug_web/src/pages/deploy/request/store.js diff --git a/spug_web/src/menus.js b/spug_web/src/menus.js index 6039b89..9742a52 100644 --- a/spug_web/src/menus.js +++ b/spug_web/src/menus.js @@ -10,6 +10,7 @@ export default [ { icon: 'flag', title: '应用发布', child: [ {title: '应用管理', path: '/deploy/app'}, + {title: '发布申请', path: '/deploy/request'}, ] }, {icon: 'schedule', title: '任务计划', path: '/schedule'}, diff --git a/spug_web/src/pages/deploy/request/Ext1Form.js b/spug_web/src/pages/deploy/request/Ext1Form.js new file mode 100644 index 0000000..4fa0bc5 --- /dev/null +++ b/spug_web/src/pages/deploy/request/Ext1Form.js @@ -0,0 +1,98 @@ +import React from 'react'; +import { observer } from 'mobx-react'; +import { Modal, Form, Input, Select, Col, Button, Tag, message } from 'antd'; +import hostStore from 'pages/host/store'; +import http from 'libs/http'; +import store from './store'; +import lds from 'lodash'; + +@observer +class Ext1Form extends React.Component { + constructor(props) { + super(props); + this.state = { + loading: false, + type: null, + host_ids: store.record['host_ids'].concat() + } + } + + handleSubmit = () => { + if (this.state.host_ids.length === 0) { + return message.error('请至少选择一个要发布的目标主机') + } + this.setState({loading: true}); + const formData = this.props.form.getFieldsValue(); + formData['id'] = store.record.id; + formData['body'] = this.state.body; + http.post('/api/exec/template/', formData) + .then(res => { + message.success('操作成功'); + store.formVisible = false; + store.fetchRecords() + }, () => this.setState({loading: false})) + }; + + handleChange = (id, v) => { + const host_ids = this.state.host_ids; + const index = host_ids.indexOf(id); + if (index === -1) { + this.setState({host_ids: [id, ...host_ids]}) + } else { + host_ids.splice(index, 1); + this.setState({host_ids}) + } + }; + + render() { + const info = store.record; + const {host_ids} = this.state; + const {getFieldDecorator} = this.props.form; + return ( + store.ext1Visible = false} + confirmLoading={this.state.loading} + onOk={this.handleSubmit}> +
+ + {getFieldDecorator('name', {initialValue: info['name']})( + + )} + + + + {getFieldDecorator('name', {initialValue: info['name']})( + + )} + + + + + + + {getFieldDecorator('desc', {initialValue: info['desc']})( + + )} + + + {info['host_ids'].map(id => ( + this.handleChange(id, v)}> + {lds.get(hostStore.idMap, `${id}.name`)}({lds.get(hostStore.idMap, `${id}.hostname`)}:{lds.get(hostStore.idMap, `${id}.port`)}) + + ))} + +
+
+ ) + } +} + +export default Form.create()(Ext1Form) \ No newline at end of file diff --git a/spug_web/src/pages/deploy/request/Form.js b/spug_web/src/pages/deploy/request/Form.js new file mode 100644 index 0000000..0c7cf5d --- /dev/null +++ b/spug_web/src/pages/deploy/request/Form.js @@ -0,0 +1,104 @@ +import React from 'react'; +import { observer } from 'mobx-react'; +import { Modal, Form, Input, Select, Col, Button, message } from 'antd'; +import { ACEditor } from 'components'; +import http from 'libs/http'; +import store from './store'; + +@observer +class ComForm extends React.Component { + constructor(props) { + super(props); + this.state = { + loading: false, + type: null, + body: store.record['body'], + } + } + + handleSubmit = () => { + this.setState({loading: true}); + const formData = this.props.form.getFieldsValue(); + formData['id'] = store.record.id; + formData['body'] = this.state.body; + http.post('/api/exec/template/', formData) + .then(res => { + message.success('操作成功'); + store.formVisible = false; + store.fetchRecords() + }, () => this.setState({loading: false})) + }; + + handleAddZone = () => { + Modal.confirm({ + icon: 'exclamation-circle', + title: '添加模板类型', + content: this.addZoneForm, + onOk: () => { + if (this.state.type) { + store.types.push(this.state.type); + this.props.form.setFieldsValue({'type': this.state.type}) + } + }, + }) + }; + + addZoneForm = ( +
+ + this.setState({type: val.target.value})}/> + +
+ ); + + render() { + const info = store.record; + const {getFieldDecorator} = this.props.form; + return ( + store.formVisible = false} + confirmLoading={this.state.loading} + onOk={this.handleSubmit}> +
+ + + {getFieldDecorator('type', {initialValue: info['type']})( + + )} + + + + + + + {getFieldDecorator('name', {initialValue: info['name']})( + + )} + + + this.setState({body: val})} + height="300px"/> + + + {getFieldDecorator('desc', {initialValue: info['desc']})( + + )} + +
+
+ ) + } +} + +export default Form.create()(ComForm) \ No newline at end of file diff --git a/spug_web/src/pages/deploy/request/SelectApp.js b/spug_web/src/pages/deploy/request/SelectApp.js new file mode 100644 index 0000000..d30da5e --- /dev/null +++ b/spug_web/src/pages/deploy/request/SelectApp.js @@ -0,0 +1,86 @@ +import React from 'react'; +import { observer } from 'mobx-react'; +import { Modal, Button, Menu, Icon } from 'antd'; +import store from './store'; +import styles from './index.module.css'; +import envStore from 'pages/config/environment/store'; +import hostStore from 'pages/host/store'; +import appStore from '../app/store'; +import lds from 'lodash'; + +@observer +class SelectApp extends React.Component { + constructor(props) { + super(props); + this.state = { + env_id: 0 + } + } + + componentDidMount() { + if (envStore.records.length === 0) { + envStore.fetchRecords().then(this._initEnv) + } else { + this._initEnv() + } + if (appStore.records.length === 0) { + appStore.fetchRecords() + } + if (hostStore.records.length === 0) { + hostStore.fetchRecords() + } + } + + _initEnv = () => { + if (envStore.records.length) { + this.setState({env_id: envStore.records[0].id}) + } + }; + + handleClick = (app) => { + store.record = app; + if (app.extend === '1') { + store.ext1Visible = true + } else { + store.ext2Visible = true + } + }; + + render() { + const {env_id} = this.state; + return ( + store.addVisible = false} + footer={null}> +
+
+ this.setState({env_id: selectedKeys[0]})}> + {envStore.records.map(item => {item.name})} + +
+
+
{lds.get(envStore.idMap, `${env_id}.name`)}
+ {appStore.records.map(item => ( + + ))} +
+
+
+ ) + } +} + +export default SelectApp \ No newline at end of file diff --git a/spug_web/src/pages/deploy/request/Table.js b/spug_web/src/pages/deploy/request/Table.js new file mode 100644 index 0000000..62280f1 --- /dev/null +++ b/spug_web/src/pages/deploy/request/Table.js @@ -0,0 +1,72 @@ +import React from 'react'; +import { observer } from 'mobx-react'; +import { Table, Divider, Modal, message } from 'antd'; +import http from 'libs/http'; +import store from './store'; +import { LinkButton } from "components"; + +@observer +class ComTable extends React.Component { + componentDidMount() { + store.fetchRecords() + } + + columns = [{ + title: '序号', + key: 'series', + render: (_, __, index) => index + 1, + width: 80, + }, { + title: '模版名称', + dataIndex: 'name', + }, { + title: '模版类型', + dataIndex: 'type', + }, { + title: '模版内容', + render: text => text.body, + ellipsis: true + }, { + title: '描述信息', + dataIndex: 'desc', + ellipsis: true + }, { + title: '操作', + render: info => ( + + store.showForm(info)}>编辑 + + this.handleDelete(info)}>删除 + + ) + }]; + + handleDelete = (text) => { + Modal.confirm({ + title: '删除确认', + content: `确定要删除【${text['name']}】?`, + onOk: () => { + return http.delete('/api/exec/template/', {params: {id: text.id}}) + .then(() => { + message.success('删除成功'); + store.fetchRecords() + }) + } + }) + }; + + render() { + let data = store.records; + if (store.f_name) { + data = data.filter(item => item['name'].toLowerCase().includes(store.f_name.toLowerCase())) + } + if (store.f_type) { + data = data.filter(item => item['type'].toLowerCase().includes(store.f_type.toLowerCase())) + } + return ( + + ) + } +} + +export default ComTable \ No newline at end of file diff --git a/spug_web/src/pages/deploy/request/index.js b/spug_web/src/pages/deploy/request/index.js new file mode 100644 index 0000000..f991a81 --- /dev/null +++ b/spug_web/src/pages/deploy/request/index.js @@ -0,0 +1,36 @@ +import React from 'react'; +import { observer } from 'mobx-react'; +import { Card, Input, Select, Button } from 'antd'; +import { SearchForm } from 'components'; +import SelectApp from './SelectApp'; +import Ext1Form from './Ext1Form'; +import ComTable from './Table'; +import store from './store'; + +export default observer(function () { + return ( + + + + + + + store.f_name = e.target.value} placeholder="请输入"/> + + + + + +
+ +
+ + {store.addVisible && } + {store.ext1Visible && } +
+ ) +}) \ No newline at end of file diff --git a/spug_web/src/pages/deploy/request/index.module.css b/spug_web/src/pages/deploy/request/index.module.css new file mode 100644 index 0000000..e243228 --- /dev/null +++ b/spug_web/src/pages/deploy/request/index.module.css @@ -0,0 +1,30 @@ +.container { + display: flex; + background-color: #fff; + padding: 16px 0; + min-height: 500px; +} +.left { + flex: 2; + border-right: 1px solid #e8e8e8; +} +.right { + flex: 7; + padding: 8px 40px; +} + +.title { + margin-bottom: 12px; + color: rgba(0, 0, 0, .85); + font-weight: 500; + font-size: 20px; + line-height: 28px; +} + +.appBlock { + margin-top: 20px; + width: 165px; + height: 60px; + font-size: 18px; + margin-right: 20px; +} \ No newline at end of file diff --git a/spug_web/src/pages/deploy/request/store.js b/spug_web/src/pages/deploy/request/store.js new file mode 100644 index 0000000..9a49258 --- /dev/null +++ b/spug_web/src/pages/deploy/request/store.js @@ -0,0 +1,24 @@ +import { observable } from "mobx"; +import http from 'libs/http'; + +class Store { + @observable records = []; + @observable types = []; + @observable record = {}; + @observable isFetching = false; + @observable addVisible = false; + @observable ext1Visible = false; + @observable ext2Visible = false; + + @observable f_name; + @observable f_type; + + fetchRecords = () => { + this.isFetching = true; + http.get('/api/app/') + .then(res => this.records = res) + .finally(() => this.isFetching = false) + }; +} + +export default new Store() \ No newline at end of file diff --git a/spug_web/src/pages/deploy/routes.js b/spug_web/src/pages/deploy/routes.js index 4a4547b..64b9951 100644 --- a/spug_web/src/pages/deploy/routes.js +++ b/spug_web/src/pages/deploy/routes.js @@ -1,7 +1,9 @@ import { makeRoute } from "../../libs/router"; import app from './app'; +import request from './request'; export default [ makeRoute('/app', app), + makeRoute('/request', request), ] \ No newline at end of file diff --git a/spug_web/src/pages/host/store.js b/spug_web/src/pages/host/store.js index 0092b4f..d593820 100644 --- a/spug_web/src/pages/host/store.js +++ b/spug_web/src/pages/host/store.js @@ -5,6 +5,7 @@ class Store { @observable records = []; @observable zones = []; @observable record = {}; + @observable idMap = {}; @observable isFetching = false; @observable formVisible = false; @@ -17,6 +18,9 @@ class Store { .then(({hosts, zones}) => { this.records = hosts; this.zones = zones; + for (let item of hosts) { + this.idMap[item.id] = item + } }) .finally(() => this.isFetching = false) };