demo
环境
Element ui + Axios + Gin + Gorm
ui
采用容器布局在table之上去平行分布 《添加主机》和《搜索主机》按钮
<template>
<div >
<!-- <el-button type="success">{{userInfo.nickname}}</el-button>-->
<el-row class="tac">
<el-container>
<!-- <el-header>-->
<!-- header-->
<!-- </el-header>-->
<el-main>
<el-row>
<el-col :span="24"> <!--占整行-->
<el-row>
<el-col :span="4" >
<el-button type="primary" icon="el-icon-plus" @click="AddHost">增加服务器</el-button>
</el-col>
<el-col :span="20" >
<!-- 搜索与添加区域 -->
<el-row :gutter="20">
<el-col :span="8">
<el-input prefix-icon="el-icon-search" placeholder="请输入搜索机器IP" v-model="queryInfo.query" clearable @clear="getSearchInfo()">
<el-button icon="el-icon-search"></el-button>
</el-input>
</el-col>
<el-col :span="4">
<el-button type="success" icon="el-icon-search" @click="getSearchInfo">搜索</el-button>
</el-col>
</el-row>
</el-col>
</el-row>
</el-col>
</el-row>
</el-main>
</el-container>
<el-col :span="4">
</el-col>
<el-col class="content-right" :span="24">
<el-card shadow="hover">
<el-table
v-loading="loading"
element-loading-text="🐱 喵~ 玩命加载中..."
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)"
:highlight-current-row=true
:stripe=true
:show-header=true
:header-cell-style="{background:'#bfeeee',color:'#1b1f1e'}"
:data="receiverInfos" style="width: auto">
<el-table-column
label="IP"
prop="Ip">
</el-table-column>
<el-table-column
label="DC"
prop="Dc">
</el-table-column>
<el-table-column
label="所属项目"
prop="Projectname">
</el-table-column>
<el-table-column
label="基础服务"
prop="Baseservice">
</el-table-column>
<el-table-column
label="CPU"
prop="Cpucores"
width="50">
</el-table-column>
<el-table-column
label="CPU负载"
prop="Cpuload1"
width="100">
<template slot-scope="scope">
<el-tag type="warning" v-if="scope.row.Cpuload1 >=0.1"> 💥{{scope.row.Cpuload1}} </el-tag>
<el-tag type="success" v-if="scope.row.Cpuload1 < 0.1"> {{scope.row.Cpuload1}} </el-tag>
<!-- <el-tag :type="parseInt(scope.row.Ramusedpercent) >'80' ? 'warning' : 'success'" >{{scope.row.Ramusedpercent}}</el-tag>-->
</template>
</el-table-column>
<el-table-column
label="硬盘大小"
prop="Disktotalgb"
width="80">
</el-table-column>
<el-table-column
label="硬盘使用率"
prop="Diskusedpercent"
width="100">
<template slot-scope="scope">
<el-tag type="warning" v-if="parseInt(scope.row.Diskusedpercent) >=80"> 💥{{scope.row.Diskusedpercent}} </el-tag>
<el-tag type="success" v-if="parseInt(scope.row.Diskusedpercent) < 80"> {{scope.row.Diskusedpercent}} </el-tag>
<!-- <el-tag :type="parseInt(scope.row.Ramusedpercent) >'80' ? 'warning' : 'success'" >{{scope.row.Ramusedpercent}}</el-tag>-->
</template>
</el-table-column>
<el-table-column
label="内存大小"
prop="Ramtotalmb"
width="80">
</el-table-column>
<el-table-column
label="内存使用率"
prop="Ramusedpercent"
width="100">
<template slot-scope="scope">
<el-tag type="warning" v-if="parseInt(scope.row.Ramusedpercent) >= 28"> 💥{{scope.row.Ramusedpercent}} </el-tag>
<el-tag type="success" v-if="parseInt(scope.row.Ramusedpercent) < 28"> {{scope.row.Ramusedpercent}} </el-tag>
<!-- <el-tag :type="parseInt(scope.row.Ramusedpercent) >'80' ? 'warning' : 'success'" >{{scope.row.Ramusedpercent}}</el-tag>-->
</template>
</el-table-column>
<el-table-column
label="Agent版本"
prop="Agentversion"
width="100">
</el-table-column>
<el-table-column
:show-overflow-tooltip="true"
label="更新时间"
prop="UpdatedAt">
<template slot-scope="scope">
<el-tag >{{dateTimeFormat(scope.row.CreatedAt)}} </el-tag>
<!-- {{ dateTimeFormat(scope.row.CreatedAt) }}-->
</template>
</el-table-column>
<el-table-column
align="right">
<template slot-scope="scope">
<!-- <el-button-->
<!-- size="mini"-->
<!-- @click="handleEdit(scope.$index, scope.row)">Edit</el-button>-->
<el-button
size="mini"
type="danger"
@click="handleSetOffline(scope.$index, scope.row)">下架</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[5, 10, 20, 40]"
:page-size="pagesize"
layout="total, sizes,prev, pager, next"
:total="total"
prev-text="上一页"
next-text="下一页">
</el-pagination>
</div>
<el-dialog :title="title" :visible.sync="dialogVisible" width="50%" :before-close="handleClose">
<el-form ref="form" :model="form" label-width="80px">
<!-- <el-form-item label="编号">-->
<!-- <el-input v-model="form.id"></el-input>-->
<!-- </el-form-item>-->
<el-form-item label="数据中心">
<el-input v-model="form.dc" width="100"></el-input>
</el-form-item>
<el-form-item label="ip">
<el-input v-model="form.ip" width="300"></el-input>
</el-form-item>
<el-form-item label="user">
<el-input v-model="form.user" width="100"></el-input>
</el-form-item>
<el-form-item label="SSH端口">
<el-input v-model="form.sshport" width="100"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button icon="el-icon-plus" type="primary" @click="save" :loading="DownloadLoading" >确 定</el-button>
</span>
</el-dialog>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
//main.js文件引入了 但是一直报错,在这里再次引入正常运行代码 ????
import Vue from "vue"
Vue.prototype.$http = require("axios")
export default {
data() {
return {
queryInfo: {
// 查询参数
query: '',
},
DownloadLoading:false,
title: "",
dialogVisible: false,
loading:false,
receiverInfos: [],
form: { dc:"",ip:"",user:'',sshport:''},
currentPage: 1, //默认显示页面为1
pagesize: 10, // 每页的数据条数
total:0
};
},
created() {
// 获取当前登录的用户信息
this.userInfo = JSON.parse(localStorage.getItem("userInfo") || "{}");
this.getReceiverInfos();
},
methods: {
//
getSearchInfo(){
if ( this.queryInfo.query == 0 ){
this.getReceiverInfos()
}else{
return this.$http
.post("/api/SearchOnlineHost",
{
ip: this.queryInfo.query,
},
)
.then(result => {
if (result.data.code === 200){
this.$message({
message: "共搜索到 "+result.data.total+" 条🐱~" ,
type: "success"
});
this.total = result.data.total;
this.receiverInfos = result.data.data;
return
}
})
.catch(err => {
// console.log(error.response.data.errMsg);
this.$message.error("搜索主机失败 🐱");
});
}
},
// 时间戳转换
dateTimeFormat(value) {
var now = new Date(new Date().getTime()),
y = now.getFullYear(),
m = now.getMonth() + 1,
d = now.getDate(),
x = y + "-" + (m < 10 ? "0" + m : m) + "-" + (d < 10 ? "0" + d : d);
return value.substring(0,19).replace(/T/g,'-')
},
// AddHost
AddHost() {
// this.form.id = "";
this.form.dc = "";
this.form.ip = "";
this.form.user = "";
this.form.sshport = "";
this.title = "增加服务器";
this.dialogVisible = true;
},
save() {
if (this.title == "增加服务器") {
this.DownloadLoading= true
let AddHost = {dc: "", ip: "",user:'',sshport:'' };
// // user.id = this.form.id;
AddHost.dc = this.form.dc;
AddHost.ip= this.form.ip;
AddHost.user=this.form.user;
AddHost.sshport=this.form.sshport;
return this.$http
.post("/api/AddHost",
{
dc: AddHost.dc,
ip: AddHost.ip,
user: AddHost.user,
sshport: AddHost.sshport,
},
)
.then(result => {
// return
this.DownloadLoading=false
if (result.data.status === 200){
this.$message({
message: result.data.msg+" 🐱~" ,
type: "success"
});
this.dialogVisible = false;
this.DownloadLoading=false
this.getReceiverInfos()
return
}else if (result.data.code === "5004") {
this.loading=false
this.$message({
message: result.data.msg+" 🐱~" ,
type: "error"
});
this.dialogVisible = false;
this.DownloadLoading=false
this.getReceiverInfos()
return
}
})
.catch(() => {
this.loading=false
this.DownloadLoading=false
this.getReceiverInfos()
// console.log(error.response.data.errMsg);
this.$message.error("添加失败 🐱");
});
}
},
//每页下拉显示数据
handleSizeChange: function(size) {
this.pagesize = size;
this.getReceiverInfos()
},
//点击第几页
handleCurrentChange: function(currentPage) {
this.currentPage = currentPage;
this.getReceiverInfos()
},
// 选择
handleSelectionChange(val) {
this.multipleSelection = val;
},
handleClose() {
this.dialogVisible = false;
},
getReceiverInfos() {
this.loading=true
this.$http({
method: "get",
url: "/api/GetAllNodeInfo",
params: {
currentpage: this.currentPage,
pagesize:this.pagesize
},
})
.then(result => {
this.loading=false
// console.log(result.data);
this.total = result.data.total;
this.receiverInfos = result.data.data;
})
.catch(err => {
console.dir(err);
});
},
handleDelete(index, row) {
this.$message.warning("开发中,先等等~");
console.log(index, row);
},
// 下架
handleSetOffline(index, rows) {
// this.userData.splice(index, 1);
this.$confirm('即将下架, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
//点击确定的操作(调用接口)
return this.$http
.post("/api/SetHostOffline",
{
// id:row.ID,
dc:rows.Dc,
ip:rows.Ip
},
)
.then(result => {
if (result.data.code === 20129){
this.$message({
message: rows.Ip+" "+result.data.msg+" 🐱~ ",
type: "success"
});
this.getReceiverInfos()
// this.getUser()
} else {
this.$message({
message: rows.Ip +" "+" 下架失败!" ,
type: "error"
});
this.getReceiverInfos()
}
}).catch(err => {
// console.log(error.response.data.errMsg);
this.$message.error("下架失败! 🐱");
this.getReceiverInfos()
});
}).catch(() => {
//几点取消的提示
this.$message.success("取消成功 🐱");
this.getReceiverInfos()
});
},
}
};
</script>
<style lang="less" scoped>
</style>
server
简单分页查询的后端,一律没放到model层
func SearchOnlineHost(c *gin.Context) {
type SearchOnlineHostStruct struct {
Ip string `form:"ip" json:"ip" uri:"ip" xml:"ip" binding:"required"`
}
var SearchOnlineHostPayload SearchOnlineHostStruct
if err := c.ShouldBindJSON(&SearchOnlineHostPayload); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var SearchOnlineHostInfo []model.HostInfo
var total int
model.DB.Where("ip like ? AND offline = ?", "%"+SearchOnlineHostPayload.Ip+"%", false).Find(&SearchOnlineHostInfo).Count(&total)
if err := model.DB.Where("ip like ? AND offline = ?", "%"+SearchOnlineHostPayload.Ip+"%", false).Order("updated_at desc").Find(&SearchOnlineHostInfo).Error; err != nil {
logrus.Error(err)
return
} else {
c.JSON(200, gin.H{
"code": e.SUCCESS,
"data": SearchOnlineHostInfo,
"msg": e.GetMsg(e.SUCCESS),
"total": total,
})
}
}
一楼沙发留名~