mirror of https://github.com/shunfei/cronsun
节点分组
parent
a615b32ca9
commit
5a5faeb88b
|
@ -47,20 +47,20 @@ func InitRouters() (s *http.Server, err error) {
|
|||
subrouter.Handle("/nodes", h).Methods("GET")
|
||||
// get node group list
|
||||
h = BaseHandler{Handle: nodeHandler.GetGroups}
|
||||
subrouter.Handle("/nodes/groups", h).Methods("GET")
|
||||
subrouter.Handle("/node/groups", h).Methods("GET")
|
||||
// get a node group by group id
|
||||
h = BaseHandler{Handle: nodeHandler.GetGroupByGroupId}
|
||||
subrouter.Handle("/nodes/group/{id}", h).Methods("GET")
|
||||
subrouter.Handle("/node/group/{id}", h).Methods("GET")
|
||||
// create/update a node group
|
||||
h = BaseHandler{Handle: nodeHandler.UpdateGroup}
|
||||
subrouter.Handle("/nodes/group", h).Methods("PUT")
|
||||
subrouter.Handle("/node/group", h).Methods("PUT")
|
||||
// delete a node group
|
||||
h = BaseHandler{Handle: nodeHandler.DeleteGroup}
|
||||
subrouter.Handle("/nodes/group", h).Methods("DELETE")
|
||||
subrouter.Handle("/node/group/{id}", h).Methods("DELETE")
|
||||
|
||||
uidir := conf.Config.Web.UIDir
|
||||
if len(uidir) == 0 {
|
||||
uidir = path.Join("..", "..", "web", "ui", "dist")
|
||||
uidir = path.Join("web", "ui", "dist")
|
||||
}
|
||||
r.PathPrefix("/ui/").Handler(http.StripPrefix("/ui/", http.FileServer(http.Dir(uidir))))
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -5,7 +5,7 @@
|
|||
<router-link class="item" to="/" v-bind:class="{active: this.$route.path == '/'}"><i class="dashboard icon"></i> 仪表盘</router-link>
|
||||
<router-link class="item" to="/log" v-bind:class="{active: this.$route.path.indexOf('/log') === 0}"><i class="file text icon"></i> 日志</router-link>
|
||||
<router-link class="item" to="/job" v-bind:class="{active: this.$route.path.indexOf('/job') === 0}"><i class="calendar icon"></i> 任务</router-link>
|
||||
<router-link class="item" to="/node" v-bind:class="{active: this.$route.path.indexOf('/nodes') === 0}"><i class="server icon"></i> 节点</router-link>
|
||||
<router-link class="item" to="/node" v-bind:class="{active: this.$route.path.indexOf('/node') === 0}"><i class="server icon"></i> 节点</router-link>
|
||||
</div>
|
||||
<div style="height: 55px;"></div>
|
||||
<div class="ui container">
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
</td>
|
||||
<td class="center aligned"><i class="icon" v-bind:class="{pause: job.pause, play: !job.pause, green: !job.pause}"></i></td>
|
||||
<td>{{job.group}}</td>
|
||||
<td>{{job.name}}</td>
|
||||
<td><router-link :to="'/job/edit/'+job.group+'/'+job.id">{{job.name}}</router-link></td>
|
||||
<td>
|
||||
<span v-if="!job.latestStatus">-</span>
|
||||
<span v-else>{{formatTime(job.latestStatus.beginTime, job.latestStatus.endTime)}},于 {{job.latestStatus.node}} 耗时 {{formatDuration(job.latestStatus.beginTime, job.latestStatus.endTime)}}</span>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</div>
|
||||
<div class="field">
|
||||
<label>任务分组</label>
|
||||
<Dropdown title="选择分组" allowAdditions=true v-bind:items="groups" v-bind:selected="job.group" v-on:change="changeGroup"/>
|
||||
<Dropdown title="选择分组" v-bind:items="groups" v-bind:selected="job.group" v-on:change="changeGroup"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fields">
|
||||
|
@ -90,9 +90,11 @@ export default {
|
|||
removeRule: function(index){
|
||||
this.job.rules.splice(index, 1);
|
||||
},
|
||||
|
||||
changeRule: function(index, key, val){
|
||||
this.job.rules[index][key] = val;
|
||||
},
|
||||
|
||||
submit: function(){
|
||||
var exceptCode = this.action == 'CREATE' ? 201 : 200;
|
||||
this.loading = true;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<Dropdown title="节点分组" v-bind:items="nodeGroups" multiple="true"></Dropdown>
|
||||
<Dropdown title="节点分组" v-bind:items="nodeGroups" v-bind:selected="rule.gids" multiple="true" v-on:change="changeNodeGroups($event)"></Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
|
@ -43,13 +43,15 @@ export default {
|
|||
vm.activityNodes.push(resp[i].id);
|
||||
}
|
||||
}).do();
|
||||
this.$rest.GET('nodes/groups').onsucceed(200, (resp)=>{
|
||||
|
||||
|
||||
this.$rest.GET('node/groups').onsucceed(200, (resp)=>{
|
||||
var groups = [];
|
||||
for (var i in resp) {
|
||||
groups.push({value: resp[i].id, name: resp[i].name});
|
||||
}
|
||||
vm.nodeGroups = groups;
|
||||
});
|
||||
}).do();
|
||||
|
||||
$(this.$refs.ruletip).popup();
|
||||
},
|
||||
|
@ -61,6 +63,10 @@ export default {
|
|||
change: function(key, val){
|
||||
this.$emit('change', this.index, key, val);
|
||||
},
|
||||
changeNodeGroups: function(val){
|
||||
var gids = val.trim().length === 0 ? [] : val.split(',');
|
||||
this.change('gids', gids);
|
||||
},
|
||||
changeIncludeNodes: function(val){
|
||||
var nids = val.trim().length === 0 ? [] : val.split(',');
|
||||
this.change('nids', nids);
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
<template>
|
||||
<div>
|
||||
<router-link class="ui right floated primary button" to="/job/create"><i class="add to calendar icon"></i> 新任务</router-link>
|
||||
<button class="ui right floated icon button"><i class="refresh icon"></i></button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'job-toolbar'
|
||||
}
|
||||
</script>
|
|
@ -1,10 +1,12 @@
|
|||
<template>
|
||||
<div>
|
||||
<h3 class="ui horizontal divider header">当前节点: {{count}}</h3>
|
||||
<div class="ui label" title="手动下线/维护中的"><i class="cube icon"></i> 已下线节点</div>
|
||||
<div class="ui label" title="正常运行的节点"><i class="green cube icon"></i> 正常节点</div>
|
||||
<div class="ui label" title="节点因自身或网络等原因未检测到"><i class="red cube icon"></i> 故障节点</div>
|
||||
<h3 class="ui horizontal divider header"> </h3>
|
||||
<div class="clearfix">
|
||||
<router-link class="ui right floated primary button" to="/node/group"><i class="cubes icon"></i> 管理分组</router-link>
|
||||
<div class="ui label" title="手动下线/维护中的"><i class="cube icon"></i> 离线节点</div>
|
||||
<div class="ui label" title="正常运行的节点"><i class="green cube icon"></i> 正常节点</div>
|
||||
<div class="ui label" title="因自身或网络等原因未检测到节点存活"><i class="red cube icon"></i> 故障节点</div>
|
||||
</div>
|
||||
<h4 class="ui horizontal divider header">当前节点: {{count}}</h4>
|
||||
<div v-for="node in nodes" class="ui label"><i v-bind:class="{green: node.alived && node.connected, red: node.alived && !node.connected}" class="cube icon"></i> {{node.id}}</div
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
<style scope>
|
||||
#nodeGroups {
|
||||
margin: 15px 0;
|
||||
position: relative;
|
||||
column-width: 250px;
|
||||
}
|
||||
#nodeGroups>div {
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
border: 1px solid #D4D4D5; box-shadow: none; margin: 0px;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
#nodeGroups .ui.card>.content {padding: 1em 0 0;}
|
||||
#nodeGroups .ui.list:first-child {border-top: 1px solid #eee;}
|
||||
#nodeGroups .ui.divided.list>.item {padding: 0.5em 1em;}
|
||||
#nodeGroups .ui.card>.content>.header:not(.ui) {margin: 0 1em;}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="clearfix">
|
||||
<router-link class="ui right floated primary button" to="/node/group/create"><i class="add icon"></i> 新分组</router-link>
|
||||
<button class="ui right floated icon button" v-on:click="refresh"><i class="refresh icon"></i></button>
|
||||
</div>
|
||||
<div v-if="error != ''" class="header"><i class="attention icon"></i> {{error}}</div>
|
||||
<div id="nodeGroups">
|
||||
<div class="ui card" v-for="g in groups">
|
||||
<div class="content">
|
||||
<router-link class="header" :to="'/node/group/'+g.id">{{g.name}}</router-link>
|
||||
<div class="description">
|
||||
<div class="ui middle large aligned divided list">
|
||||
<div class="item" v-for="n in g.nids">{{n}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'node_group',
|
||||
data: function(){
|
||||
return {
|
||||
error: '',
|
||||
groups: []
|
||||
}
|
||||
},
|
||||
mounted: function(){
|
||||
this.refresh();
|
||||
},
|
||||
|
||||
methods: {
|
||||
refresh(){
|
||||
var vm = this;
|
||||
this.$rest.GET('node/groups').
|
||||
onsucceed(200, (resp)=>{
|
||||
vm.groups = resp;
|
||||
}).
|
||||
onfailed((data)=>{vm.error = data}).
|
||||
onend(()=>{vm.loading = false}).
|
||||
do();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,90 @@
|
|||
<template>
|
||||
<div v-if="error != ''" class="ui negative message">
|
||||
<div class="header"><i class="attention icon"></i> {{error}}</div>
|
||||
</div>
|
||||
<form v-else class="ui form" v-bind:class="{loading:loading}" v-on:submit.prevent>
|
||||
<h3 class="ui header">{{action == 'CREATE' ? '添加' : '更新'}}节点分组</h3>
|
||||
<div class="field">
|
||||
<input type="text" ref="name" v-model:value="group.name" placeholder="分组名称">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>分组节点</label>
|
||||
<Dropdown title="选择节点" multiple="true" v-bind:items="allNodes" v-bind:selected="group.nids" v-on:change="changeGroup"/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<button class="fluid blue ui button" type="button" v-on:click="submit"><i class="upload icon"></i> 保存分组</button>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Dropdown from './basic/Dropdown.vue';
|
||||
|
||||
export default {
|
||||
name: 'node_group_edit',
|
||||
data(){
|
||||
return {
|
||||
error: '',
|
||||
loading: false,
|
||||
action: '',
|
||||
allNodes: [],
|
||||
group: {
|
||||
id: '',
|
||||
name: '',
|
||||
nids: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted(){
|
||||
var vm = this;
|
||||
|
||||
if (this.$route.path.indexOf('/node/group/create') === 0) {
|
||||
this.action = 'CREATE';
|
||||
} else {
|
||||
this.action = 'UPDATE';
|
||||
this.loading = true;
|
||||
this.$rest.GET('node/group/'+this.$route.params.id).
|
||||
onsucceed(200, (resp)=>{
|
||||
vm.group = resp;
|
||||
}).
|
||||
onfailed((data)=>{vm.error = data.error}).
|
||||
onend(()=>{vm.loading = false}).
|
||||
do();
|
||||
}
|
||||
|
||||
this.$rest.GET('nodes').onsucceed(200, (resp)=>{
|
||||
var allNodes = [];
|
||||
for (var i in resp) {
|
||||
allNodes.push(resp[i].id);
|
||||
}
|
||||
vm.allNodes = allNodes;
|
||||
}).do();
|
||||
},
|
||||
|
||||
methods: {
|
||||
changeGroup(val, text){
|
||||
if (val.length == 0) {
|
||||
this.group.nids = [];
|
||||
return;
|
||||
}
|
||||
this.group.nids = val.split(',');
|
||||
},
|
||||
|
||||
submit(){
|
||||
var exceptCode = this.action == 'CREATE' ? 201 : 200;
|
||||
this.loading = true;
|
||||
var vm = this;
|
||||
this.$rest.PUT('node/group', this.group)
|
||||
.onsucceed(exceptCode, ()=>{vm.$router.push('/node/group')})
|
||||
.onfailed((resp)=>{console.log(resp)})
|
||||
.onend(()=>{vm.loading=false})
|
||||
.do();
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
Dropdown
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -27,6 +27,8 @@ import LogDetail from './components/LogDetail.vue';
|
|||
import Job from './components/Job.vue';
|
||||
import JobEdit from './components/JobEdit.vue';
|
||||
import Node from './components/Node.vue';
|
||||
import NodeGroup from './components/NodeGroup.vue';
|
||||
import NodeGroupEdit from './components/NodeGroupEdit.vue';
|
||||
|
||||
var routes = [
|
||||
{path: '/', component: Dash},
|
||||
|
@ -35,7 +37,10 @@ var routes = [
|
|||
{path: '/job', component: Job},
|
||||
{path: '/job/create', component: JobEdit},
|
||||
{path: '/job/edit/:group/:id', component: JobEdit},
|
||||
{path: '/node', component: Node}
|
||||
{path: '/node', component: Node},
|
||||
{path: '/node/group', component: NodeGroup},
|
||||
{path: '/node/group/create', component: NodeGroupEdit},
|
||||
{path: '/node/group/:id', component: NodeGroupEdit}
|
||||
];
|
||||
|
||||
var router = new VueRouter({
|
||||
|
|
Loading…
Reference in New Issue