当前位置:   article > 正文

SpringBoot+Vue前后端分离虚拟机管理系统_springboot+vue 后台管理系统

springboot+vue 后台管理系统

项目介绍和展示

该项目主要运用spring boot,vue,Hadoop,搭建一个功能系统,实现登录注册账户,对多个虚拟机的管理操作,并且可以实现虚拟机的增删改查,一键免密,一键安装Hadoop等功能。如下:

SpringBoot+Vue前后端分离虚拟机管理系统

搭建环境

软件和环境会用到:
jdk1.8
mysql
node 16.150.0
navicat
idea2021.1.3

这里数据库,jdk等我就不详细讲,特别说明一下,我的前端后端都在idea上编写的,所以我单独说一下vue的安装搭建,vue的搭建详见我的博客https://blog.csdn.net/m0_53720901/article/details/125075349

后端项目部分

增加pom.xml依赖配置

这里我们增加了mybatis-plus的配置,因为我们后端使用spring boot会连接数据库,使用数据库保存更新数据。
然后增加了swagger,使用Swagger,就是把相关的信息存储在它定义的描述文件里面(yml或json格式),再通过维护这个描述文件可以去更新接口文档,以及生成各端代码。简单理解:swagger就是为了方便系统生成API接口文档的。
然后就是hutool ,JWT,远程连接Linux和SSH-2协议的包等的配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.9</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>vuesp</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>vuesp</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>

        <dependency>
            <groupId>com.microsoft.sqlserver</groupId>
            <artifactId>mssql-jdbc</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- mybatis-plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-actuator-autoconfigure</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity</artifactId>
            <version>1.7</version>
        </dependency>
        <!--swagger-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-boot-starter</artifactId>
            <version>3.0.0</version>
        </dependency>

        <!-- hutool  -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.20</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.2</version>
        </dependency>

        <!-- JWT -->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.10.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

<!--        远程连接Linux-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!-- SSH-2协议的包 -->
        <dependency>
            <groupId>ch.ethz.ganymed</groupId>
            <artifactId>ganymed-ssh2</artifactId>
            <version>262</version>
        </dependency>



    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>nexus-aliyun</id>
            <name>nexus-aliyun</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>public</id>
            <name>aliyun nexus</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
</project>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175

后端主要代码部分:

后端代码项目结构
在这里插入图片描述
conmon: 配置与前端交互返回的数据提示和内容
config: 跨域和redis
controller: 控制层
entity: 实体类
service: service层,处理接收到的数据,主要作功能代码
mapper: 从service到mapper,主要实现数据库的增删改查方法的实现

spring boot的经典代码部分;controller,entity,service,HostServiceImpl,mapper以及mapper.xml我就不在文章展示了,详情请查看文末获取全部源码。这里就展示后端与前端跨域的代码以及结果封装部分代码

跨域部分代码CorsConfig

package com.example.vuesp.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {

    // 当前跨域请求最大有效时长。这里默认1天
    private static final long MAX_AGE = 24 * 60 * 60;

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("http://localhost:8080"); // 1 设置访问源地址
        corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
        corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法
        corsConfiguration.setMaxAge(MAX_AGE);
        source.registerCorsConfiguration("/**", corsConfiguration); // 4 对接口配置跨域设置
        return new CorsFilter(source);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

结果封装部分代码conmon
因为是前后端分离的项目,所以我们有必要统一一个结果返回封装类,这样前后端交互的时候有个统一的标准,约定结果返回的数据是正常的或者遇到异常了。

Constants

package com.example.vuesp.common;

public interface Constants {
    String CODE_200 = "200";//成功
    String CODE_500 = "500";//系统错误
    String CODE_401 = "401";//权限不足
    String CODE_400 = "400";//参数错误
    String CODE_600 = "600";//其他业务异常
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Result

package com.example.vuesp.common;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 接口统一返回包装类
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {

    private String code;
    private String msg;
    private Object data;

    public static Result success() {
        return new Result(Constants.CODE_200, "", null);
    }

    public static Result success(Object data) {
        return new Result(Constants.CODE_200, "", data);
    }

    public static Result error(String code, String msg) {
        return new Result(code, msg, null);
    }

    public static Result error() {
        return new Result(Constants.CODE_500, "系统错误", null);
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

前端部分

在前面搭建好前端的环境项目后,将前端项目复制到idea上,方便操作执行,首先在idea新建一个Java项目然后将前端项目文件放于大文件夹下,如图我的前端项目为vue01放于后端项目下在这里插入图片描述
在这里插入图片描述
assets放前端所需要的图片
components放导航栏与上边框
router:设置路由–名字和资源映射起来
utils:与后端的请求配置
views;前端所有展示页面的代码
main.js:主要作用是初始化vue实例并使用需要的插件

登录注册页面布局

1登录页面Login.vue
这里我们用了一个数据库保存了用户的账号密码,并进行绑定,密码错误则不能进行登录。

<template>

    <div class="wrapper1" >
        <div style="margin: 0px 0px;width: 200px;height: 20px;padding: 0; border-radius: 10px">
            <div class="demo-image__placeholder" style="margin: 0px 0px;width: 400px;height: 40px;padding: 0px; border-radius: 100px">
                <div class="block">
                    <el-image :src="require('../assets/logo.png')"></el-image>
                </div>
            </div>
        </div>
        <div style="margin: 10px 300px;width: 500px;height: 40px;padding: 20px; border-radius: 10px">
            <div style="margin: 200px 70px">
                <el-carousel height="450px" :interval="1000">
                    <el-carousel-item v-for="item in imgs" :key="item">
                        <img :src="item" alt="" style="width: 100%">
                    </el-carousel-item>
                </el-carousel>
            </div>
        </div>
        <div style="margin: 100px 900px; background-color: #fff; width: 500px;height: 450px; padding: 20px; border-radius: 20px">
            <div style="margin: 20px 0; text-align: center; font-size: 24px;left: 400px"><b>登 录</b></div>
            <el-form :model="user" :rules="rules" ref="userForm">
                <el-form-item prop="username">
                    <el-input size="medium" style="margin: 30px 0" prefix-icon="el-icon-user" v-model="user.username"></el-input>
                </el-form-item>
                <el-form-item prop="password">
                    <el-input size="medium" style="margin: 50px 0" prefix-icon="el-icon-lock" show-password v-model="user.password"></el-input>
                </el-form-item>
                <el-form-item style="margin: 30px 0; text-align: center;left: 400px">
                    <el-button type="primary" size="small"  autocomplete="off" @click="login">登录</el-button>
                    <el-button type="warning" size="small"  autocomplete="off" @click="$router.push('/register')">注册</el-button>
                </el-form-item>
            </el-form>
        </div>
    </div>
</template>

<script>


    export default {
        name: "Login",
        data() {
            return {
               user: {},
                rules: {
                    username: [
                        {required: true, message: '请输入用户名', trigger: 'blur'},
                        {min: 3, max: 10, message: '长度在 3 到 5 个字符', trigger: 'blur'}
                    ],
                    password: [
                        {required: true, message: '请输入密码', trigger: 'blur'},
                        {min: 1, max: 20, message: '长度在 1 到 20 个字符', trigger: 'blur'}
                    ],

                },
                imgs: [
                    require('../assets/1.jpg'),
                    require('../assets/2.jpg'),
                    require('../assets/3.jpg')

                ],
                files: []
            }
        },
        methods: {
            login() {
                this.$refs['userForm'].validate((valid) => {
                    if (valid) {  // 表单校验合法
                        this.request.post("/user/login", this.user).then(res => {
                            if(res.code === '200') {
                                localStorage.setItem("user", JSON.stringify(res.data))  // 存储用户信息到浏览器
                                this.$router.push("/")
                                this.$message.success("登录成功!")
                            } else {
                                this.$message.error(res.msg)
                            }
                        })
                    }
                });
            }
        }
    }
</script>

<style >
    .wrapper1 {
        height: 100vh;
        background-image: linear-gradient(to bottom right, #C6F0F6 , #C6F0F6);
        overflow: hidden;
    }
</style>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93

2注册页面Register.vue
这里我们做了一个小细节,两次设置密码必须一致。

<template>
    <div class="wrapper">
        <div style="margin: 100px auto; background-color: #fff; width: 350px; height: 550px; padding: 20px; border-radius: 10px">
            <div style="margin: 20px 0; text-align: center; font-size: 24px"><b>注 册</b></div>
            <el-form :model="user" :rules="rules" ref="userForm">
                <el-form-item prop="nickname">
                    <el-input placeholder="请输入昵称" size="medium" style="margin: 5px 0" prefix-icon="el-icon-user" v-model="user.nickname"></el-input>
                </el-form-item>
                <el-form-item prop="username">
                    <el-input placeholder="请输入账号" size="medium" style="margin: 5px 0" prefix-icon="el-icon-user" v-model="user.username"></el-input>
                </el-form-item>
                <el-form-item prop="name">
                    <el-input placeholder="请输入集群名称" size="medium" style="margin: 5px 0" prefix-icon="el-icon-user" v-model="user.name"></el-input>
                </el-form-item>
                <el-form-item prop="number">
                    <el-input placeholder="请输入主机数" size="medium" style="margin: 5px 0" prefix-icon="el-icon-user" v-model="user.number"></el-input>
                </el-form-item>
                <el-form-item prop="password">
                    <el-input placeholder="请输入密码" size="medium" style="margin: 5px 0" prefix-icon="el-icon-lock" show-password v-model="user.password"></el-input>
                </el-form-item>
                <el-form-item prop="confirmPassword">
                    <el-input placeholder="请确认密码" size="medium" style="margin: 5px 0" prefix-icon="el-icon-lock" show-password v-model="user.confirmPassword"></el-input>
                </el-form-item>
                <el-form-item style="margin: 5px 0; text-align: right">
                    <el-button type="primary" size="small"  autocomplete="off" @click="login">注册</el-button>
                    <el-button type="warning" size="small"  autocomplete="off" @click="$router.push('/login')">返回登录</el-button>
                </el-form-item>
            </el-form>
        </div>
    </div>
</template>

<script>
    export default {
        name: "Login",
        data() {
            return {
                user: {},
                rules: {
                    nickname: [
                        { required: true, message: '请输入昵称', trigger: 'blur' },
                        { min: 1, max: 10, message: '长度在 1 到 20 个字符', trigger: 'blur' }
                    ],
                    username: [
                        { required: true, message: '请输入账号', trigger: 'blur' },
                        { min: 3, max: 20, message: '长度在 3 到 10 个字符', trigger: 'blur' }
                    ],
                    name: [
                        { required: true, message: '请输入集群名称', trigger: 'blur' },
                        { min: 1, max: 20, message: '长度在 1 到 20 个字符', trigger: 'blur' }
                    ],
                    number: [
                        { required: true, message: '请输入主机数', trigger: 'blur' },
                        { min: 1, max: 1, message: '长度在 1 到 1 个数字', trigger: 'blur' }
                    ],
                    password: [
                        { required: true, message: '请输入密码', trigger: 'blur' },
                        { min: 1, max: 20, message: '长度在 1 到 20 个字符', trigger: 'blur' }
                    ],
                    confirmPassword: [
                        { required: true, message: '请输入密码', trigger: 'blur' },
                        { min: 1, max: 20, message: '长度在 1 到 20 个字符', trigger: 'blur' }
                    ],
                }
            }
        },
        methods: {
            login() {
                this.$refs['userForm'].validate((valid) => {
                    if (valid) {  // 表单校验合法
                        if (this.user.password !== this.user.confirmPassword) {
                            this.$message.error("两次输入的密码不一致")
                            return false
                        }
                        this.request.post("/user/register", this.user).then(res => {
                            if(res.code === '200') {
                                this.$message.success("注册成功")
                            } else {
                                this.$message.error(res.msg)
                            }
                        })
                    }
                });
            }
        }
    }
</script>

<style>
    .wrapper {
        height: 100vh;
        background-image: linear-gradient(to bottom right, #FC466B , #3F5EFB);
        overflow: hidden;
    }
</style>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96

主体功能页面布局

1系统左边导航栏布局Aside.vue

<!--导航栏-->
<template>
    <el-menu :default-openeds="['1', '3']" style="min-height: 100%; overflow-x: hidden"
             background-color="rgb(48, 65, 86)"
             text-color="#fff"
             active-text-color="#3DA6CC"
             :collapse-transition="false"
             :collapse="isCollapse"
             router
    >
        <div style="height: 60px; line-height: 60px; text-align: center">
            <img src="../assets/压力.png" alt="" style="width: 27px; position: relative; top: 5px; right: 5px">
            <b style="color: white" v-show="logoTextShow">Hadoop|压力怪</b>
        </div>

        <el-menu-item index="/">
            <template slot="title">
            <i class="el-icon-s-home"></i>
            <span slot="title">首页</span>
            </template>
        </el-menu-item>

        <el-submenu index="1">
            <template slot="title">
                <i class="el-icon-menu"></i>
                <span slot="title">集群概览</span>
            </template>
            <el-menu-item index="/user">
                <i class="el-icon-s-custom"></i>
                <span slot="title">集群展示</span>
            </el-menu-item>
            <el-menu-item index="/Download">
                <i class="el-icon-download"></i>
                <span slot="title">产品安装</span>
            </el-menu-item>

            <el-menu-item index="/Validation">
                <i class="el-icon-loading"></i>
                <span slot="title">产品验证</span>
            </el-menu-item>
        </el-submenu>



    </el-menu>
</template>

<script>
    export default {
        name: "Aside",
        props: {
            isCollapse: Boolean,
            logoTextShow: Boolean
        }
    }
</script>

<style scoped>

</style>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

2系统顶上信息显示Header.vue

<template>
    <div style="line-height: 60px; display: flex">
        <div style="flex: 2;">

        </div>
        <el-dropdown style="width: 100px; cursor: pointer">
            <div style="display: inline-block">
                <img :src="require('../assets/1.jpg')" alt=""
                     style="width: 30px; border-radius: 50%; position: relative; top: 10px; right: 5px">
                <span style="font-weight:bold">{{ user.nickname }}</span><i class="el-icon-arrow-down" style="margin-left: 5px"></i>
            </div>
            <el-dropdown-menu slot="dropdown" style="width: 100px; text-align: center">
<!--                <el-dropdown-item style="font-size: 14px; padding: 5px 0">-->
<!--                    <router-link to="/person">个人信息</router-link>-->
<!--                </el-dropdown-item>-->
                <el-dropdown-item style="font-size: 14px; padding: 5px 0">
                    <span style="text-decoration: none" @click="logout">退出</span>
                </el-dropdown-item>
            </el-dropdown-menu>
        </el-dropdown>
    </div>
</template>

<script>
    export default {
        name: "Header",
        props: {
            collapseBtnClass: String,
            collapse: Boolean,
        },

        data() {
            return {
                user: localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : {}
            }
        },

        methods: {
            logout() {
                this.$router.push("/login")
                localStorage.removeItem("user")
                this.$message.success("退出成功")
            }
        }
    }
</script>

<style scoped>

</style>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

3首页Home.vue

<!--主页-->
<template>
    <div class="wrapper3" >
        <el-row style="top: 100px;left: 450px;">
            <!--            <span>压力怪</span>-->
                <span style="font-weight:bold;font-size: 35px;" type="success">压力怪!程序猿的选择~</span>
        </el-row>
        <el-row style="top: 470px;left: 1000px;">
<!--            <span>压力怪</span>-->
            <el-button type="primary" round @click="$router.push('/User')">
                <i class="el-icon-d-arrow-right" style="font-weight:bold;font-size: 35px">开始使用</i>
            </el-button>
        </el-row>
    </div>
</template>


<script>
    export default {
        name: "Home",
    }
</script>

<style>
    .wrapper3 {
        height: 85vh;
        background:#fff url(../assets/t.webp) top left/1300px 650px no-repeat;
        /*repeat 10px 0px*/
        overflow: hidden;
    }
</style>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

4集群展示页面

<!--集群页面-->
<template>
    <div>
        <div style="margin-bottom: 20px">
            <el-breadcrumb separator="/">
                <el-button type="info" style="font-size: 18px" @click="$router.push('/User')">
                    <i class="el-icon-back"></i>返回</el-button>
            </el-breadcrumb>
        </div>

        <div style="margin: 10px 0">
            <el-input style="width: 200px" placeholder="请输入主机名称" suffix-icon="el-icon-search" v-model="hostname"></el-input>
            <el-button class="ml-5" type="primary" @click="load">搜索</el-button>
        </div>

        <div style="margin: 10px 0">
            <el-button type="warning" @click="handleAdd">新增主机<i class="el-icon-circle-plus-outline"></i></el-button>
            <el-button type="primary" @click="pass">一键免密钥 <i class="el-icon-remove-outline"></i></el-button>
            <el-button type="primary" @click="jdk">一键JDK <i class="el-icon-remove-outline"></i></el-button>
            <el-button type="primary" @click="$router.push('/Download')">产品安装<i class="el-icon-download"></i></el-button>
            <el-button type="primary" @click="$router.push('/Validation')">产品验证<i class="el-icon-loading"></i></el-button>
        </div>

        <el-table :data="tableData" border stripe :header-cell-class-name="headerBg">
            <el-table-column prop="id" label="序号" width="200">
            </el-table-column>
            <el-table-column prop="hostname" label="主机名" width="250">
            </el-table-column>
            <el-table-column prop="ip" label="IP" width="200">
            </el-table-column>
            <el-table-column prop="role" label="节点" width="245">
            </el-table-column>
            <el-table-column prop="password" label="主机密码" width="200">
            </el-table-column>
            <el-table-column label="操作"  width="200" align="center">
                <template slot-scope="scope">

                    <el-popconfirm
                        class="ml-5"
                        confirm-button-text='确定'
                        cancel-button-text='我再想想'
                        icon="el-icon-info"
                        icon-color="red"
                        title="您确定删除吗?"
                        @confirm="del(scope.row.id)"
                >
                    <el-button type="danger" slot="reference">删除主机<i class="el-icon-remove-outline"></i></el-button>
                </el-popconfirm>
                </template>
            </el-table-column>
        </el-table>
        <!--翻页-->
        <div style="padding: 10px 0">
            <el-pagination
                    @size-change="handleSizeChange"
                    @current-change="handleCurrentChange"
                    :current-page="pageNum"
                    :page-sizes="[2, 5, 10, 20]"
                    :page-size="pageSize"
                    layout="total, sizes, prev, pager, next, jumper"
                    :total="total">
            </el-pagination>
        </div>

        <el-dialog title="集群信息" :visible.sync="dialogFormVisible" width="30%" >
            <el-form label-width="80px" size="small">
                <el-form-item label="主机名">
                    <el-input v-model="form.hostname" autocomplete="off"></el-input>
                </el-form-item>
                <el-form-item label="IP">
                    <el-input v-model="form.ip" autocomplete="off"></el-input>
                </el-form-item>
                <el-form-item label="节点">
                    <el-input v-model="form.role" autocomplete="off"></el-input>
                </el-form-item>
                <el-form-item label="主机密码">
                    <el-input v-model="form.password" autocomplete="off"></el-input>
                </el-form-item>
            </el-form>
            <div slot="footer" class="dialog-footer">
                <el-button @click="dialogFormVisible = false">取 消</el-button>
                <el-button type="primary" @click="save">确 定</el-button>
            </div>
        </el-dialog>
    </div>
</template>

<script>
    export default {
        name: "User",
        data() {
            return {
                tableData: [],
                total: 0,
                pageNum: 1,
                pageSize: 2,
                hostname: "",
                form: {},
                dialogFormVisible: false,
                headerBg: 'headerBg'
            }
        },
        created() {
            // 请求分页查询数据
            this.load()
        },
        methods: {
            load() {
                this.request.get("/host/page", {
                    params: {
                        pageNum: this.pageNum,
                        pageSize: this.pageSize,
                        hostname: this.hostname,
                    }
                }).then(res => {
                    console.log(res)
                    this.tableData = res.records
                    this.total = res.total

                })
            },
            handleAdd() {
                this.dialogFormVisible = true
                this.form = {}
            },
            save() {
                this.request.post("/host", this.form).then(res => {
                    if (res) {
                        this.$message.success("保存成功")
                        this.dialogFormVisible = false
                        this.load()
                    } else {
                        this.$message.error("保存失败")
                    }
                })
            },
            del(id) {
                this.request.delete("/host/" + id).then(res => {
                    if (res) {
                        this.$message.success("删除成功")
                        this.load()
                    } else {
                        this.$message.error("删除失败")
                    }
                })
            },
            handleSizeChange(pageSize) {
                console.log(pageSize)
                this.pageSize = pageSize
                this.load()
            },
            handleCurrentChange(pageNum) {
                console.log(pageNum)
                this.pageNum = pageNum
                this.load()
            },
            pass() {
                this.request.get("/pass").then(res => {
                    if(res.code === '200') {
                        this.$message.success("结果:"+res.data)
                    } else {
                        this.$message.error("失败")
                    }
                })
            },
            jdk() {
                this.request.get("/jdk").then(res => {
                    if(res.code === '200') {
                        this.$message.success("结果:"+res.data)
                    } else {
                        this.$message.error("失败")
                    }
                })
            },

        }
    }
</script>

<style>
    .headerBg {
        background: #eee!important;
    }
</style>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185

总结

项目做得不是很完美很好,有许多功能还未完善,也有许多bug但是自学vue做得这样子还是将就,博友们可以参考然后改进,欢迎提出意见与问题。欢迎交流,因为源码太多,需获取源码请评论。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/599478
推荐阅读
相关标签
  

闽ICP备14008679号