mirror of https://github.com/openspug/spug
A web update
parent
61b697cd16
commit
0e57c71896
|
@ -24,7 +24,8 @@ class AddSelect extends React.Component {
|
||||||
store.record = {
|
store.record = {
|
||||||
is_audit: false,
|
is_audit: false,
|
||||||
host_ids: [undefined],
|
host_ids: [undefined],
|
||||||
actions: [{target: 'server'}]
|
host_actions: [],
|
||||||
|
server_actions: []
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import { Form, Input, Button, message, Col, Radio, Icon } from 'antd';
|
import { Form, Input, Button, message, Divider, Icon } from 'antd';
|
||||||
import Editor from 'react-ace';
|
import Editor from 'react-ace';
|
||||||
import 'ace-builds/src-noconflict/mode-sh';
|
import 'ace-builds/src-noconflict/mode-sh';
|
||||||
import 'ace-builds/src-noconflict/theme-tomorrow';
|
import 'ace-builds/src-noconflict/theme-tomorrow';
|
||||||
|
@ -19,9 +19,11 @@ class Ext2Setup3 extends React.Component {
|
||||||
|
|
||||||
handleSubmit = () => {
|
handleSubmit = () => {
|
||||||
this.setState({loading: true});
|
this.setState({loading: true});
|
||||||
store.record['extend'] = '2';
|
const info = store.record;
|
||||||
store.record['actions'] = store.record['actions'].filter(x => x.title && x.data);
|
info['extend'] = '2';
|
||||||
http.post('/api/app/', store.record)
|
info['host_actions'] = info['host_actions'].filter(x => x.title && x.data);
|
||||||
|
info['server_actions'] = info['server_actions'].filter(x => x.title && x.data);
|
||||||
|
http.post('/api/app/', info)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
message.success('保存成功');
|
message.success('保存成功');
|
||||||
store.ext2Visible = false;
|
store.ext2Visible = false;
|
||||||
|
@ -30,23 +32,14 @@ class Ext2Setup3 extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const actions = store.record['actions'];
|
const server_actions = store.record['server_actions'];
|
||||||
|
const host_actions = store.record['host_actions'];
|
||||||
return (
|
return (
|
||||||
<Form labelCol={{span: 6}} wrapperCol={{span: 14}} className={styles.ext2Form}>
|
<Form labelCol={{span: 6}} wrapperCol={{span: 14}} className={styles.ext2Form}>
|
||||||
{actions.map((item, index) => (
|
{server_actions.map((item, index) => (
|
||||||
<div key={index} style={{marginBottom: 30, position: 'relative'}}>
|
<div key={index} style={{marginBottom: 30, position: 'relative'}}>
|
||||||
<Form.Item required label={`动作${index + 1}`}>
|
<Form.Item required label={`本地动作${index + 1}`}>
|
||||||
<Col span={9}>
|
<Input value={item['title']} onChange={e => item['title'] = e.target.value} placeholder="请输入"/>
|
||||||
<Input value={item['title']} onChange={e => item['title'] = e.target.value} placeholder="请输入"/>
|
|
||||||
</Col>
|
|
||||||
<Col span={15}>
|
|
||||||
<Form.Item labelCol={{span: 6}} wrapperCol={{span: 18}} label="目标">
|
|
||||||
<Radio.Group value={item['target']} onChange={e => item['target'] = e.target.value}>
|
|
||||||
<Radio value="server">服务本机</Radio>
|
|
||||||
<Radio value="host">目标主机</Radio>
|
|
||||||
</Radio.Group>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item required label="执行内容">
|
<Form.Item required label="执行内容">
|
||||||
|
@ -59,21 +52,47 @@ class Ext2Setup3 extends React.Component {
|
||||||
onChange={v => item['data'] = v}
|
onChange={v => item['data'] = v}
|
||||||
placeholder="请输入要执行的动作"/>
|
placeholder="请输入要执行的动作"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{actions.length > 1 && (
|
<div className={styles.delAction} onClick={() => server_actions.splice(index, 1)}>
|
||||||
<div className={styles.delAction} onClick={() => actions.splice(index, 1)}><Icon
|
<Icon type="minus-circle"/>移除
|
||||||
type="minus-circle"/>移除</div>
|
</div>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<Form.Item wrapperCol={{span: 14, offset: 6}}>
|
<Form.Item wrapperCol={{span: 14, offset: 6}}>
|
||||||
<Button type="dashed" block onClick={() => actions.push({target: 'server'})}>
|
<Button type="dashed" block onClick={() => server_actions.push({target: 'server'})}>
|
||||||
<Icon type="plus"/>添加执行动作
|
<Icon type="plus"/>添加本地执行动作(在服务端本地执行)
|
||||||
</Button>
|
</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Divider/>
|
||||||
|
{host_actions.map((item, index) => (
|
||||||
|
<div key={index} style={{marginBottom: 30, position: 'relative'}}>
|
||||||
|
<Form.Item required label={`目标主机动作${index + 1}`}>
|
||||||
|
<Input value={item['title']} onChange={e => item['title'] = e.target.value} placeholder="请输入"/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item required label="执行内容">
|
||||||
|
<Editor
|
||||||
|
mode="sh"
|
||||||
|
theme="tomorrow"
|
||||||
|
width="100%"
|
||||||
|
height="100px"
|
||||||
|
value={item['data']}
|
||||||
|
onChange={v => item['data'] = v}
|
||||||
|
placeholder="请输入要执行的动作"/>
|
||||||
|
</Form.Item>
|
||||||
|
<div className={styles.delAction} onClick={() => host_actions.splice(index, 1)}>
|
||||||
|
<Icon type="minus-circle"/>移除
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
<Form.Item wrapperCol={{span: 14, offset: 6}}>
|
<Form.Item wrapperCol={{span: 14, offset: 6}}>
|
||||||
|
<Button type="dashed" block onClick={() => host_actions.push({target: 'server'})}>
|
||||||
|
<Icon type="plus"/>添加目标主机执行动作(在部署目标主机执行)
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item wrapperCol={{span: 14, offset: 6}} help="Spug 将遵循先本地后目标主机的原则,按照顺序依次执行添加的动作,例如:本地动作1 -> 本地动作2 -> 目标主机动作1 -> 目标主机动作2 ...">
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
disabled={actions.filter(x => x.title && x.data).length === 0}
|
disabled={[...host_actions, ...server_actions].filter(x => x.title && x.data).length === 0}
|
||||||
loading={this.state.loading}
|
loading={this.state.loading}
|
||||||
onClick={this.handleSubmit}>提交</Button>
|
onClick={this.handleSubmit}>提交</Button>
|
||||||
<Button style={{marginLeft: 20}} onClick={() => store.page -= 1}>上一步</Button>
|
<Button style={{marginLeft: 20}} onClick={() => store.page -= 1}>上一步</Button>
|
||||||
|
|
|
@ -8,7 +8,7 @@ import store from './store';
|
||||||
import lds from 'lodash';
|
import lds from 'lodash';
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
class Index extends React.Component {
|
class Ext1Index extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
|
@ -105,7 +105,7 @@ class Index extends React.Component {
|
||||||
<Steps.Step {...this.getStatus('local', 4)} title="检出后任务"/>
|
<Steps.Step {...this.getStatus('local', 4)} title="检出后任务"/>
|
||||||
<Steps.Step {...this.getStatus('local', 5)} title="执行打包"/>
|
<Steps.Step {...this.getStatus('local', 5)} title="执行打包"/>
|
||||||
</Steps>}>
|
</Steps>}>
|
||||||
<pre className={styles.console}>{lds.get(store.outputs, 'local.data')}</pre>
|
<pre className={styles.ext1Console}>{lds.get(store.outputs, 'local.data')}</pre>
|
||||||
</Collapse.Panel>
|
</Collapse.Panel>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ class Index extends React.Component {
|
||||||
<Steps.Step {...this.getStatus(item.id, 4)} title="发布后任务"/>
|
<Steps.Step {...this.getStatus(item.id, 4)} title="发布后任务"/>
|
||||||
</Steps>
|
</Steps>
|
||||||
</div>}>
|
</div>}>
|
||||||
<pre className={styles.console}>{lds.get(store.outputs, `${item.id}.data`)}</pre>
|
<pre className={styles.ext1Console}>{lds.get(store.outputs, `${item.id}.data`)}</pre>
|
||||||
</Collapse.Panel>
|
</Collapse.Panel>
|
||||||
))}
|
))}
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
@ -133,4 +133,4 @@ class Index extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Index
|
export default Ext1Index
|
|
@ -0,0 +1,110 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import { Steps, PageHeader, Spin, Tag, Button, Icon } from 'antd';
|
||||||
|
import http from 'libs/http';
|
||||||
|
import history from 'libs/history';
|
||||||
|
import styles from './index.module.css';
|
||||||
|
import store from './store';
|
||||||
|
import lds from 'lodash';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
class Ext2Index extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
fetching: true,
|
||||||
|
loading: false,
|
||||||
|
request: {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.id = this.props.match.params.id;
|
||||||
|
http.get(`/api/deploy/request/${this.id}/`)
|
||||||
|
.then(res => store.request = res)
|
||||||
|
.finally(() => this.setState({fetching: false}))
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
if (this.socket) this.socket.close();
|
||||||
|
store.request = {targets: []};
|
||||||
|
store.outputs = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
handleDeploy = () => {
|
||||||
|
this.setState({loading: true});
|
||||||
|
http.post(`/api/deploy/request/${this.id}/`)
|
||||||
|
.then(({token, outputs}) => {
|
||||||
|
store.request.status = '2';
|
||||||
|
store.outputs = outputs;
|
||||||
|
this.socket = new WebSocket(`ws://localhost:8000/ws/exec/${token}/`);
|
||||||
|
this.socket.onopen = () => {
|
||||||
|
this.socket.send('ok');
|
||||||
|
};
|
||||||
|
this.socket.onmessage = e => {
|
||||||
|
if (e.data === 'pong') {
|
||||||
|
this.socket.send('ping')
|
||||||
|
} else {
|
||||||
|
const {key, data, step, status} = JSON.parse(e.data);
|
||||||
|
if (data !== undefined) store.outputs[key]['data'] += data;
|
||||||
|
if (step !== undefined) store.outputs[key]['step'] = step;
|
||||||
|
if (status !== undefined) store.outputs[key]['status'] = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => this.setState({loading: false}))
|
||||||
|
};
|
||||||
|
|
||||||
|
getStatus = (key, n) => {
|
||||||
|
const step = lds.get(store.outputs, `${key}.step`, -1);
|
||||||
|
const isError = lds.get(store.outputs, `${key}.status`) === 'error';
|
||||||
|
const icon = <Icon type="loading"/>;
|
||||||
|
if (n > step) {
|
||||||
|
return {key: n, status: 'wait'}
|
||||||
|
} else if (n === step) {
|
||||||
|
return isError ? {key: n, status: 'error'} : {key: n, status: 'process', icon}
|
||||||
|
} else {
|
||||||
|
return {key: n, status: 'finish'}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
getStatusAlias = () => {
|
||||||
|
if (Object.keys(store.outputs).length !== 0) {
|
||||||
|
for (let item of [{id: 'local'}, ...store.request.targets]) {
|
||||||
|
if (lds.get(store.outputs, `${item.id}.status`) === 'error') {
|
||||||
|
return <Tag color="red">发布异常</Tag>
|
||||||
|
} else if (lds.get(store.outputs, `${item.id}.step`, -1) < 5) {
|
||||||
|
return <Tag color="blue">发布中</Tag>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return <Tag color="green">发布成功</Tag>
|
||||||
|
} else {
|
||||||
|
return <Tag>{store.request['status_alias'] || '...'}</Tag>
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {app_name, env_name, status} = store.request;
|
||||||
|
return (
|
||||||
|
<Spin spinning={this.state.fetching}>
|
||||||
|
<PageHeader
|
||||||
|
title="应用发布"
|
||||||
|
subTitle={`${app_name} - ${env_name}`}
|
||||||
|
style={{padding: 0}}
|
||||||
|
tags={this.getStatusAlias()}
|
||||||
|
extra={<Button loading={this.state.loading} type="primary" disabled={!['1', '-3'].includes(status)}
|
||||||
|
onClick={this.handleDeploy}>发布</Button>}
|
||||||
|
onBack={() => history.goBack()}/>
|
||||||
|
<div className={styles.ext2Block}>
|
||||||
|
<Steps direction="vertical" className={styles.ext2Step}>
|
||||||
|
<Steps.Step {...this.getStatus('local', 0)} title="建立连接"/>
|
||||||
|
<Steps.Step {...this.getStatus('local', 1)} title="发布准备"/>
|
||||||
|
</Steps>
|
||||||
|
<pre className={styles.ext2Console}>{lds.get(store.outputs, 'local.data')}</pre>
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Ext2Index
|
|
@ -10,12 +10,35 @@
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.console {
|
.ext1Console {
|
||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
max-height: 300px;
|
max-height: 300px;
|
||||||
padding: 10px 15px;
|
padding: 10px 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ext2Block {
|
||||||
|
display: flex;
|
||||||
|
background-color: #fff;
|
||||||
|
margin-top: 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #d9d9d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ext2Console {
|
||||||
|
flex: 1;
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ext2Step {
|
||||||
|
padding: 24px;
|
||||||
|
width: 220px;
|
||||||
|
border-right: 1px solid #e8e8e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ext2Step :global(.ant-steps-item) {
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
|
@ -17,6 +17,12 @@ class Ext2Form extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if (hostStore.records.length === 0) {
|
||||||
|
hostStore.fetchRecords()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleSubmit = () => {
|
handleSubmit = () => {
|
||||||
if (this.state.host_ids.length === 0) {
|
if (this.state.host_ids.length === 0) {
|
||||||
return message.error('请至少选择一个要发布的目标主机')
|
return message.error('请至少选择一个要发布的目标主机')
|
||||||
|
@ -24,11 +30,13 @@ class Ext2Form extends React.Component {
|
||||||
this.setState({loading: true});
|
this.setState({loading: true});
|
||||||
const formData = this.props.form.getFieldsValue();
|
const formData = this.props.form.getFieldsValue();
|
||||||
formData['id'] = store.record.id;
|
formData['id'] = store.record.id;
|
||||||
formData['body'] = this.state.body;
|
formData['app_id'] = store.record.app_id;
|
||||||
http.post('/api/exec/template/', formData)
|
formData['extra'] = [formData['extra']];
|
||||||
|
formData['host_ids'] = this.state.host_ids;
|
||||||
|
http.post('/api/deploy/request/', formData)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
message.success('操作成功');
|
message.success('操作成功');
|
||||||
store.formVisible = false;
|
store.ext2Visible = false;
|
||||||
store.fetchRecords()
|
store.fetchRecords()
|
||||||
}, () => this.setState({loading: false}))
|
}, () => this.setState({loading: false}))
|
||||||
};
|
};
|
||||||
|
@ -63,13 +71,18 @@ class Ext2Form extends React.Component {
|
||||||
<Input placeholder="请输入申请标题"/>
|
<Input placeholder="请输入申请标题"/>
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item label="环境变量(_SPUG_RELEASE)" help="可以在自定义脚本中引用该变量,用于设置本次发布相关的动态变量,在脚本中通过 $_SPUG_RELEASE 来使用该值">
|
||||||
|
{getFieldDecorator('extra', {initialValue: info['extra']})(
|
||||||
|
<Input placeholder="请输入环境变量 _SPUG_RELEASE 的值"/>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
<Form.Item label="备注信息">
|
<Form.Item label="备注信息">
|
||||||
{getFieldDecorator('desc', {initialValue: info['desc']})(
|
{getFieldDecorator('desc', {initialValue: info['desc']})(
|
||||||
<Input placeholder="请输入备注信息"/>
|
<Input placeholder="请输入备注信息"/>
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item required label="发布目标主机">
|
<Form.Item required label="发布目标主机">
|
||||||
{info['host_ids'].map(id => (
|
{info['app_host_ids'].map(id => (
|
||||||
<Tag.CheckableTag key={id} checked={host_ids.includes(id)} onChange={v => this.handleChange(id, v)}>
|
<Tag.CheckableTag key={id} checked={host_ids.includes(id)} onChange={v => this.handleChange(id, v)}>
|
||||||
{lds.get(hostStore.idMap, `${id}.name`)}({lds.get(hostStore.idMap, `${id}.hostname`)}:{lds.get(hostStore.idMap, `${id}.port`)})
|
{lds.get(hostStore.idMap, `${id}.name`)}({lds.get(hostStore.idMap, `${id}.hostname`)}:{lds.get(hostStore.idMap, `${id}.port`)})
|
||||||
</Tag.CheckableTag>
|
</Tag.CheckableTag>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import { Modal, Button, Menu, Icon } from 'antd';
|
import { Modal, Button, Menu, Icon } from 'antd';
|
||||||
import store from './store';
|
import store from './store';
|
||||||
|
@ -45,6 +46,7 @@ class SelectApp extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {env_id} = this.state;
|
const {env_id} = this.state;
|
||||||
|
const records = appStore.records.filter(x => String(x.env_id) === env_id);
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
visible
|
visible
|
||||||
|
@ -66,13 +68,15 @@ class SelectApp extends React.Component {
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.right}>
|
<div className={styles.right}>
|
||||||
<div className={styles.title}>{lds.get(envStore.idMap, `${env_id}.name`)}</div>
|
<div className={styles.title}>{lds.get(envStore.idMap, `${env_id}.name`)}</div>
|
||||||
{appStore.records.map(item => (
|
{records.map(item => (
|
||||||
<Button key={item.id} type="primary" className={styles.appBlock} onClick={() => this.handleClick(item)}>
|
<Button key={item.id} type="primary" className={styles.appBlock} onClick={() => this.handleClick(item)}>
|
||||||
<div style={{width: 135, overflow: 'hidden', textOverflow: 'ellipsis'}}>
|
<div style={{width: 135, overflow: 'hidden', textOverflow: 'ellipsis'}}>
|
||||||
<Icon type={item.extend === '1' ? 'ordered-list' : 'build'} style={{marginRight: 10}}/>{item.name}
|
<Icon type={item.extend === '1' ? 'ordered-list' : 'build'} style={{marginRight: 10}}/>{item.name}
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
))}
|
))}
|
||||||
|
{records.length === 0 &&
|
||||||
|
<div className={styles.tips}>该环境下还没有可发布的应用哦,快去<Link to="/deploy/app">应用管理</Link>创建应用吧。</div>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -44,7 +44,7 @@ class ComTable extends React.Component {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return <React.Fragment>
|
return <React.Fragment>
|
||||||
<Icon type="build"/> xxx
|
<Icon type="build"/> {info.extra[0]}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ class ComTable extends React.Component {
|
||||||
switch (info.status) {
|
switch (info.status) {
|
||||||
case '-3':
|
case '-3':
|
||||||
return <React.Fragment>
|
return <React.Fragment>
|
||||||
<Link to={`/deploy/do/${info.id}`}>发布</Link>
|
<Link to={`/deploy/do/ext${info['app_extend']}/${info.id}`}>发布</Link>
|
||||||
<Divider type="vertical"/>
|
<Divider type="vertical"/>
|
||||||
<LinkButton
|
<LinkButton
|
||||||
disabled={info.type === '2'}
|
disabled={info.type === '2'}
|
||||||
|
@ -106,10 +106,10 @@ class ComTable extends React.Component {
|
||||||
<LinkButton onClick={() => store.showForm(info)}>编辑</LinkButton>
|
<LinkButton onClick={() => store.showForm(info)}>编辑</LinkButton>
|
||||||
<Divider type="vertical"/>
|
<Divider type="vertical"/>
|
||||||
<LinkButton onClick={() => this.handleDelete(info)}>删除</LinkButton>
|
<LinkButton onClick={() => this.handleDelete(info)}>删除</LinkButton>
|
||||||
</React.Fragment>
|
</React.Fragment>;
|
||||||
case '1':
|
case '1':
|
||||||
return <React.Fragment>
|
return <React.Fragment>
|
||||||
<Link to={`/deploy/do/${info.id}`}>发布</Link>
|
<Link to={`/deploy/do/ext${info['app_extend']}/${info.id}`}>发布</Link>
|
||||||
<Divider type="vertical"/>
|
<Divider type="vertical"/>
|
||||||
<LinkButton onClick={() => this.handleDelete(info)}>删除</LinkButton>
|
<LinkButton onClick={() => this.handleDelete(info)}>删除</LinkButton>
|
||||||
</React.Fragment>;
|
</React.Fragment>;
|
||||||
|
|
|
@ -27,4 +27,9 @@
|
||||||
height: 60px;
|
height: 60px;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tips {
|
||||||
|
margin-top: 32px;
|
||||||
|
color: #888;
|
||||||
}
|
}
|
|
@ -1,11 +1,13 @@
|
||||||
import { makeRoute } from "../../libs/router";
|
import { makeRoute } from "../../libs/router";
|
||||||
import app from './app';
|
import app from './app';
|
||||||
import request from './request';
|
import request from './request';
|
||||||
import doIndex from './do';
|
import doExt1Index from './do/Ext1Index';
|
||||||
|
import doExt2Index from './do/Ext2Index';
|
||||||
|
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
makeRoute('/app', app),
|
makeRoute('/app', app),
|
||||||
makeRoute('/request', request),
|
makeRoute('/request', request),
|
||||||
makeRoute('/do/:id', doIndex),
|
makeRoute('/do/ext1/:id', doExt1Index),
|
||||||
|
makeRoute('/do/ext2/:id', doExt2Index),
|
||||||
]
|
]
|
Loading…
Reference in New Issue