Skip to content

Commit f1eed82

Browse files
authored
feat: env management (#76)
1 parent 790d64c commit f1eed82

File tree

19 files changed

+544
-3
lines changed

19 files changed

+544
-3
lines changed

app/controller/envManagement.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
const Controller = require('egg').Controller;
2+
const _ = require('lodash');
3+
4+
class EnvManagementController extends Controller{
5+
//环境列表
6+
async queryEnvs() {
7+
const { ctx, app } = this;
8+
const { tags, search } = ctx.request.query;
9+
const data = await ctx.service.envManagement.queryEnvs({ tags, search });
10+
ctx.body = app.utils.response(true, data);
11+
}
12+
//新增环境
13+
async addEnv(){
14+
const {ctx, app} = this;
15+
const {envName, hostIp, url, remark, tagIds} = ctx.request.body;
16+
if (_.isNil(envName)) throw new Error('缺少必要参数 envName');
17+
if (_.isNil(url)) throw new Error('缺少必要参数 url');
18+
const result = await ctx.service.envManagement.addEnv({
19+
envName,hostIp,url,remark,tags:tagIds.join(',')
20+
});
21+
ctx.body = app.utils.response(true,result.get({
22+
plain: true
23+
}));
24+
}
25+
//编辑环境
26+
async editEnv(){
27+
const {ctx,app} = this;
28+
const {id,envName,hostIp,url,remark,tagIds} = ctx.request.body;
29+
if (_.isNil(id)) throw new Error('缺少必要参数id');
30+
await ctx.service.envManagement.editEnv({
31+
id,
32+
envName,
33+
hostIp,
34+
url,
35+
remark,
36+
tags: tagIds ? tagIds.join(',') : undefined
37+
});
38+
ctx.body = app.utils.response(true);
39+
}
40+
//删除环境
41+
async deleteEnv(){
42+
const {ctx,app} = this;
43+
const {id} = ctx.request.query;
44+
if (_.isNil(id)) throw new Error('缺少必要参数id');
45+
await ctx.service.envManagement.deleteEnv(id);
46+
ctx.body = app.utils.response(true)
47+
}
48+
}
49+
50+
module.exports = EnvManagementController;

app/model/env_management.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module.exports = app => {
2+
const { STRING, INTEGER, DATE } = app.Sequelize;
3+
const EnvManagement = app.model.define('env_management', {
4+
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
5+
envName:{type:STRING(255),field:'env_name'},
6+
hostIp:{type:STRING(20),field:'host_ip'},
7+
url:{type:STRING(2048),field:'url'},
8+
remark: STRING(255),
9+
tags:{type:STRING(60),field:'tag_ids'},
10+
status: {type:INTEGER(2),defaultValue:1},
11+
createdAt: DATE,
12+
updatedAt: DATE
13+
},{
14+
freezeTableName: true
15+
});
16+
17+
return EnvManagement;
18+
};

app/router.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ module.exports = app => {
2929
app.post('/api/host-management/edit-host', app.controller.hostManagement.editHost);
3030
app.delete('/api/host-management/delete-host', app.controller.hostManagement.deleteHost);
3131
/**
32+
* 环境管理
33+
*/
34+
app.get('/api/env-management/env-list', app.controller.envManagement.queryEnvs);
35+
app.post('/api/env-management/add-env', app.controller.envManagement.addEnv);
36+
app.post('/api/env-management/edit-env', app.controller.envManagement.editEnv);
37+
app.delete('/api/env-management/delete-env', app.controller.envManagement.deleteEnv);
38+
/**
3239
* 配置中心
3340
*/
3441
app.post('/api/config-center/config-list', app.controller.configCenter.getConfigList);

app/service/envManagement.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
const _ = require('lodash');
2+
const Service = require('egg').Service;
3+
4+
class EnvManagementService extends Service {
5+
async queryEnvs(params) {
6+
const { ctx } = this;
7+
const { tags = '', search = '' } = params;
8+
let envResult = await ctx.model.EnvManagement.findAll({
9+
attributes: ['id', 'envName', 'hostIp', 'url', 'remark', 'tags'],
10+
where: {
11+
status: 1,
12+
$or: [
13+
{
14+
envName: { '$like': `%${search}%` }
15+
},
16+
{
17+
hostIp: { '$like': `%${search}%` }
18+
}
19+
]
20+
}
21+
});
22+
let tagsResult = await ctx.model.TagManagement.findAll();
23+
let result = [];
24+
envResult.forEach(item => {
25+
let tagids = item.get('tags').split(',');
26+
let tagArrs = tagsResult.filter(ele => {
27+
return tagids.includes(`${ele.get('id')}`)
28+
});
29+
item.set('tags', tagArrs);
30+
if (tags) {
31+
if (tags.split(',').some(ele => tagids.includes(`${ele}`))) {
32+
result.push(item)
33+
}
34+
} else {
35+
result.push(item)
36+
}
37+
});
38+
return result
39+
}
40+
addEnv(env){
41+
const {ctx} = this;
42+
return ctx.model.EnvManagement.create(env);
43+
}
44+
editEnv(env){
45+
const {ctx} = this;
46+
const {id, envName, hostIp, url, remark, tags} = env;
47+
const newEnv = {};
48+
if (!_.isNil(envName)) newEnv.envName = envName;
49+
if (!_.isNil(hostIp)) newEnv.hostIp = hostIp;
50+
if (!_.isNil(url)) newEnv.url = url;
51+
if (!_.isNil(remark)) newEnv.remark = remark;
52+
if (!_.isNil(tags)) newEnv.tags = tags;
53+
54+
return ctx.model.EnvManagement.update(newEnv,{
55+
where:{
56+
id
57+
}
58+
})
59+
}
60+
deleteEnv(id){
61+
const {ctx} = this;
62+
return ctx.model.EnvManagement.update({
63+
status:0
64+
},{
65+
where:{
66+
id
67+
}
68+
});
69+
}
70+
}
71+
module.exports = EnvManagementService;

app/web/api/url.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,29 @@ export default {
113113
method: 'delete',
114114
url: '/api/host-management/delete-host'
115115
},
116+
/**
117+
* 环境管理
118+
*/
119+
//获取环境列表
120+
getEnvList: {
121+
method: 'get',
122+
url: '/api/env-management/env-list'
123+
},
124+
//新增环境
125+
addEnv: {
126+
method: 'post',
127+
url: '/api/env-management/add-env'
128+
},
129+
//编辑环境
130+
editEnv: {
131+
method: 'post',
132+
url: '/api/env-management/edit-env'
133+
},
134+
//删除环境
135+
deleteEnv: {
136+
method: 'delete',
137+
url: '/api/env-management/delete-env'
138+
},
116139
/**
117140
* 配置中心
118141
*/

app/web/layouts/header/header.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useState, useEffect } from 'react';
2-
import { AppstoreOutlined, CloudOutlined, DesktopOutlined, TagOutlined, SettingOutlined, QuestionCircleOutlined } from '@ant-design/icons';
2+
import { AppstoreOutlined, CloudOutlined, CloudServerOutlined, DesktopOutlined, TagOutlined, SettingOutlined, QuestionCircleOutlined } from '@ant-design/icons';
33
import { Layout, Menu } from 'antd';
44
import { SyncOutlined } from '@ant-design/icons';
55
import { Link } from 'react-router-dom';
@@ -27,8 +27,13 @@ const navMenuList: any = [{
2727
}, {
2828
name: '主机管理',
2929
path: '/page/host-management',
30-
icon: <DesktopOutlined />,
30+
icon: <CloudServerOutlined />,
3131
routers: ['host-management']
32+
}, {
33+
name: '环境管理',
34+
path: '/page/env-management',
35+
icon: <DesktopOutlined />,
36+
routers: ['env-management']
3237
}, {
3338
name: '配置中心',
3439
path: '/page/config-center',
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import React, { useState, useEffect, useRef, Fragment } from 'react';
2+
import { isEmpty, isFunction, isNull } from 'lodash';
3+
import { Modal, Input, Spin, message as Message, Select, Form } from 'antd';
4+
import { API } from '@/api';
5+
const FormItem = Form.Item;
6+
const { TextArea } = Input;
7+
const { Option } = Select
8+
9+
const EnvForm = (props: any) => {
10+
const { value, tagList = [], forwardRef } = props;
11+
const { envName, hostIp, url, remark, tags = [] } = value;
12+
const tagIds = tags.map((item: any) => Number(item.id));
13+
return (
14+
<Form
15+
labelCol={{ span: 5 }}
16+
wrapperCol={{ span: 17 }}
17+
ref={forwardRef}
18+
initialValues={{
19+
envName: envName,
20+
hostIp: hostIp,
21+
url: url,
22+
tagIds: tagIds,
23+
remark: remark
24+
}}
25+
>
26+
<FormItem
27+
label="环境名称"
28+
name="envName"
29+
rules={[{ required: true, message: '请输入环境名称' }]}
30+
hasFeedback
31+
>
32+
<Input placeholder="请输入环境名称" />
33+
</FormItem>
34+
<FormItem
35+
label="主机IP"
36+
name="hostIp"
37+
rules={[{ required: true, message: '请输入主机IP' }]}
38+
hasFeedback
39+
>
40+
<Input placeholder="请输入主机IP" />
41+
</FormItem>
42+
<Fragment>
43+
<FormItem
44+
label="访问地址"
45+
name="url"
46+
rules={[{ required: true, message: '请输入访问地址' }]}
47+
hasFeedback
48+
>
49+
<TextArea placeholder="请输入访问地址" rows={2} maxLength={2000} />
50+
</FormItem>
51+
</Fragment>
52+
<FormItem
53+
label="标签"
54+
name="tagIds"
55+
rules={[{
56+
type: 'array',
57+
required: true, message: '请选择标签'
58+
}]}
59+
hasFeedback
60+
>
61+
<Select mode="multiple" placeholder="请选择标签">
62+
{
63+
tagList.map((item: any) => <Option key={item.id} value={item.id}>{item.tagName}</Option>)
64+
}
65+
</Select>
66+
</FormItem>
67+
<FormItem
68+
label="备注"
69+
name="remark"
70+
hasFeedback
71+
>
72+
<TextArea placeholder="请输入备注" rows={4} />
73+
</FormItem>
74+
</Form>
75+
)
76+
};
77+
78+
const EnvFormRef = React.forwardRef((props: any, ref: any) => {
79+
return <EnvForm {...props} forwardRef={ref} />
80+
})
81+
82+
const EnvModal = (props: any) => {
83+
const { value, visible, onOk, onCancel, tagList } = props;
84+
const [confirmLoading, setConfirmLoading] = useState(false);
85+
const envFormRef: any = useRef(null);
86+
const isAdd = isEmpty(value);
87+
const { id, envName } = value;
88+
const handleModalOk = () => {
89+
if (!isNull(envFormRef.current)) {
90+
envFormRef.current.validateFields()
91+
.then((values: any) => {
92+
setConfirmLoading(true);
93+
API[isAdd ? 'addEnv' : 'editEnv']({
94+
id: isAdd ? undefined : id,
95+
...values
96+
}).then((response: any) => {
97+
setConfirmLoading(false);
98+
const { success } = response;
99+
if (success) {
100+
Message.success(isAdd ? '环境新增成功' : `环境「${envName}」编辑成功`);
101+
isFunction(onOk) && onOk(values);
102+
}
103+
})
104+
})
105+
}
106+
}
107+
const handleModalCancel = () => {
108+
isFunction(onCancel) && onCancel();
109+
}
110+
useEffect(() => {
111+
if (!visible) {
112+
setConfirmLoading(false);
113+
}
114+
}, [props.visible])
115+
return <Modal
116+
title={isAdd ? '新增环境' : '编辑环境'}
117+
visible={visible}
118+
maskClosable={false}
119+
confirmLoading={confirmLoading}
120+
onOk={handleModalOk}
121+
onCancel={handleModalCancel}>
122+
<Spin spinning={confirmLoading}>
123+
{visible && <EnvFormRef tagList={tagList} value={value} ref={envFormRef} />}
124+
</Spin>
125+
</Modal>
126+
}
127+
export default EnvModal;

0 commit comments

Comments
 (0)