电子信息毕业设计VUE+websocket+Echart+服务器的智能农业管理系统

目录

一、作品介绍

二、开发环境

三、系统功能截图

1.登录界面

2.设备管理

3.配置管理界面

4.历史数据

5.数据分析 

6. 权限管理

7.远程管理 

四、部分关键代码


一、作品介绍

    现在农业在互联网的不断发展下,给到了农业生产带来了很多新的思路,本次毕业设计作品是在团队+自己敬爱的指导周老师+学长+本人(当然还要感谢我的母校,培养我很简单,管饱就好,哈哈哈),在诸多的指导帮助下设计出来的,设计不易,供大家码农朋友提供参考学习,本人来自于普通的农村家庭。也希望自己的作品能够为以后的乡村建设提供一份美丽的答卷。

   对于我们的传统农业生产方式,对于农田的参数检测、病虫害预警、远程管控等的实时效果能力达不到,对于现在的农作物而言,我们知道,农作物最重要的生长标准环境就是农地里的光照、温湿度、病虫害等等的因素,但是我们现在的传统生产方式是远远达不到要求的,对于监管来说,达不到时效性,就没有生产性可言,而且现在的乡村,存在着农田分配不均匀、人工管理耗时费力等等,诸多的因素下,设计了本农业智能田地系统,实现的是可以通过远程操作农田设备,比如小型机器人、喷洒车等等,实现远程操作。

二、开发环境

  毕业设计之Vue+WebSocket+ECharts+服务器的智能农业管理系统
开发语言:Java
框架:Vue3
数据库:mysql 5.6
数据库工具:Navicat11
开发软件:visual studio code
前端框架:vue.js+ECharts-Element-ui
 

三、系统功能截图

1.登录界面

当用户需要登录的时候,用户可以通过使用账号密码操作登录到系统,登录需要进行验证,当用户登录账号密码不对的时候会有错误提示。

2.设备管理

该界面给到向用户展示届满,罗列了一系列农田设备得到的数据信息,向我们用户提供数据,“搜索”button,可以由系统向数据库信息那边进行数据校验对比,在数据库得到数据索引即可对数据进行排序罗列出来。

3.配置管理界面

集体向用户展示现场农田传回来的设备的配置信息,用户可以实时监管看农田设备的数据信息,看看哪里有没有损坏什么的,比如设备运行的日期、分、设备号等等。

4.历史数据

本设计通过使用百度地图插件等处理,配合远程摄像头等操作,向用户展示地图现场传回的地理位置数据信息,该部分模块还配有温湿度折线图,采用的是ECharts可视化图表进行现场温湿度(近一周)的功能展示。

5.数据分析 

用户通过点击导航栏,进入“数据分析”界面,展现界面模块数据分析现场传回病虫害图片展示、病虫害占比率以饼图展示、文本框形式展示最新病虫害信息以及未来十五天预测信息等。

6. 权限管理

智能农业管理系统权限管理界面,用户点击左边导航栏,进入“权限管理”界面,用户可以对任意模块权限进行管理;还可以进行超级管理员、管路员、用户分配权限增删改查功能。

7.远程管理 

四、部分关键代码

login.vue

<template>
    <div class="login_container">
        <!-- 登录模块盒子 -->
<div class="login-box">
<!-- 图片盒子 -->
<div class="avatar_box">
    <img src="../assets/1234.png" alt="">
    <h3 class="text">云 智 舟</h3>
</div>
<!-- 登陆表单区域 -->
<el-form label-width="0px" class="login_form" :model="loginForm" :rules="loginFormRules" ref="loginFormRef">
    <!-- :model数据绑定对象,绑定到login from这个表单中,rules表单的验证规则对象 -->
    <!-- 用户登录 -->
  <el-form-item prop="username">
    <el-input  prefix-icon="el-icon-user-solid" v-model="loginForm.username" size="mini" ></el-input>
    <!-- v-model双向绑定,绑定到用户名 -->
  </el-form-item>
  <!-- 密码 -->
  <el-form-item prop="password">
    <el-input  prefix-icon="el-icon-lock" v-model="loginForm.password" type="password" size="mini" ></el-input>
     <!-- v-model双向绑定,绑定到用户登录密码,type="password可以使得密码隐藏"-->
  </el-form-item>
  <!-- 按钮区域 -->
  <el-form-item class="btns">
    <el-button type="primary" @click="login" size="mini" >登录</el-button>
    <!-- 为登录绑定一个单击事件,名为login -->
    <el-button type="info" @click="resetLoginForm" size="mini">重置</el-button>
    <!-- click绑定单击事件,名为resetloginfrom -->
  </el-form-item>
  </el-form>
    </div>
</div>
</template>

<script>
import {Login} from '../network/login'
export default {
  data () {
    return {
      // 登录表单的数据绑定对象
      loginForm: {
        username: '',
        password: ''
      },
      // 表单的验证规则对象
      loginFormRules: {
        // 验证用户名是否合法
        username: [
          { required: true, message: '请输入登录名称', trigger: 'blur' },
          { min: 3, max: 10, message: '长度在 3 到 10 个字符', trigger: 'blur' }
        // trigger便是失去焦点后出发这一次验证
        ],
        // 验证密码是否合法
        password: [
          { required: true, message: '请输入登录密码', trigger: 'blur' },
          { min: 3, max: 15, message: '长度在 3 到 15 个字符', trigger: 'blur' }
        ]
      }
    }
  },
  methods: {
    // 点击重置按钮,重置表单
    resetLoginForm () {
      this.$refs.loginFormRef.resetFields()
    },
    login () {
      this.$refs.loginFormRef.validate( valid => {
        if (!valid) {return this.$message.error('用户名密码不正确')}
      Login(this.loginForm).then( res => {
        console.log(res);
        if (res.code !== 0)
         {return this.$message.error('登录失败')}

        this.$message.success('登陆成功')
        window.sessionStorage.setItem('token', res.token)
        this.$router.push('/home')


      }).catch( error => {
        console.log(error);
      })

        // const { data: res } = await this..post('login', this.loginForm)
        // if (res.meta.status !== 200) return this.$message.error('登录失败')
        // this.$message.success('登陆成功')
        // // console.log(res)
        // window.sessionStorage.setItem('token', res.data.token)
        // this.$router.push('/home')
        // validate回调函数,完成登录表单前的预校验
        // 将登陆成功以后的token,保存到客户端的sessionstorage中
        // 项目中除了登陆之外的其他api接口,必须将token保存到客户端
        // this.$router.push('/home)是通过编程式导航跳转到后台,路由地址为/home
      })
    }
  }
}
</script>

home.vue

<template>
    <div class="login_container">
        <!-- 登录模块盒子 -->
<div class="login-box">
<!-- 图片盒子 -->
<div class="avatar_box">
    <img src="../assets/1234.png" alt="">
    <h3 class="text">云 智 舟</h3>
</div>
<!-- 登陆表单区域 -->
<el-form label-width="0px" class="login_form" :model="loginForm" :rules="loginFormRules" ref="loginFormRef">
    <!-- :model数据绑定对象,绑定到login from这个表单中,rules表单的验证规则对象 -->
    <!-- 用户登录 -->
  <el-form-item prop="username">
    <el-input  prefix-icon="el-icon-user-solid" v-model="loginForm.username" size="mini" ></el-input>
    <!-- v-model双向绑定,绑定到用户名 -->
  </el-form-item>
  <!-- 密码 -->
  <el-form-item prop="password">
    <el-input  prefix-icon="el-icon-lock" v-model="loginForm.password" type="password" size="mini" ></el-input>
     <!-- v-model双向绑定,绑定到用户登录密码,type="password可以使得密码隐藏"-->
  </el-form-item>
  <!-- 按钮区域 -->
  <el-form-item class="btns">
    <el-button type="primary" @click="login" size="mini" >登录</el-button>
    <!-- 为登录绑定一个单击事件,名为login -->
    <el-button type="info" @click="resetLoginForm" size="mini">重置</el-button>
    <!-- click绑定单击事件,名为resetloginfrom -->
  </el-form-item>
  </el-form>
    </div>
</div>
</template>

<script>
import {Login} from '../network/login'
export default {
  data () {
    return {
      // 登录表单的数据绑定对象
      loginForm: {
        username: '',
        password: ''
      },
      // 表单的验证规则对象
      loginFormRules: {
        // 验证用户名是否合法
        username: [
          { required: true, message: '请输入登录名称', trigger: 'blur' },
          { min: 3, max: 10, message: '长度在 3 到 10 个字符', trigger: 'blur' }
        // trigger便是失去焦点后出发这一次验证
        ],
        // 验证密码是否合法
        password: [
          { required: true, message: '请输入登录密码', trigger: 'blur' },
          { min: 3, max: 15, message: '长度在 3 到 15 个字符', trigger: 'blur' }
        ]
      }
    }
  },
  methods: {
    // 点击重置按钮,重置表单
    resetLoginForm () {
      this.$refs.loginFormRef.resetFields()
    },
    login () {
      this.$refs.loginFormRef.validate( valid => {
        if (!valid) {return this.$message.error('用户名密码不正确')}
      Login(this.loginForm).then( res => {
        console.log(res);
        if (res.code !== 0)
         {return this.$message.error('登录失败')}

        this.$message.success('登陆成功')
        window.sessionStorage.setItem('token', res.token)
        this.$router.push('/home')


      }).catch( error => {
        console.log(error);
      })

        // const { data: res } = await this..post('login', this.loginForm)
        // if (res.meta.status !== 200) return this.$message.error('登录失败')
        // this.$message.success('登陆成功')
        // // console.log(res)
        // window.sessionStorage.setItem('token', res.data.token)
        // this.$router.push('/home')
        // validate回调函数,完成登录表单前的预校验
        // 将登陆成功以后的token,保存到客户端的sessionstorage中
        // 项目中除了登陆之外的其他api接口,必须将token保存到客户端
        // this.$router.push('/home)是通过编程式导航跳转到后台,路由地址为/home
      })
    }
  }
}
</script>

<style lang="less" scoped>
.login_container {
    background-color: #2b4b6b;
    height: 100%;
}
.login-box {
    width: 360px;
    height: 240px;
    background-color: #fff;
    border-radius: 3px;
    position: absolute;
    left: 50%; //距离左侧50%
    top: 50%; // 距离顶部505
    transform: translate(-50%, -50%); //横轴上移动50%,纵移动50%
}
 .avatar_box {
        height: 100px;
        width: 100px;
        border: 1px solid #eee;
        border-radius: 50%;
        padding: 10px;
        box-shadow: 0 0 10px #eee;
        position: absolute;
        left: 50%;
        top:-40%;
        transform: translate(-50%);
        background-color: rgb(32, 181, 201);
        img {
            width: 100%;
            height: 100%;
            border-radius: 50%;
            background-color: #eee;
        }
    }

.login_form {
    position: absolute;
    bottom: 0;
    width: 100%;
    padding: 0 20px;
    box-sizing: border-box;
}
    .btns {
        display: flex;
        justify-content: flex-end;
    }
    .text {
      text-align: center;
      margin-top: 10px;
      font-size: 20px;
      font-family: 宋体;
    }
</style>

equip.vue


</template>
<script>
import {getTable,getdetail} from '../../network/equip'
// import { Login } from '../../network/login'
export default {
  data () {
    return {
      //搜索的id
      id:null,
      SeriesNumber:'',
      queryInfo: {
        formart: 'josn',
        pagenum: 1,
        pagesize: 3,
      },
      total:7,
      input: '',
      input2: '',
      input3: '',
      coordinate: '',
      // 表格中的开关
      // valueswitch: true,
      // 定义tablelist这个为一个数组
      TableList: [],
    
      // 控制对话框的显示与隐藏
      ToMoreVisible: false,
   
      value: '',
      value2: '',
      // checked: false,
      currentPage1: 5,
      currentPage2: 5,
      currentPage3: 5,
      currentPage4: 5,
    }
  },
  // 创建一个表格数据
  created () {
    this.getTableList()
  },
    mounted () {
  },
  methods: {
    // 获取表格数据
    getTableList(){
      getTable(this.queryInfo).then(res => {
        this.TableList = res.results
        console.log(res);
      }).catch(err => {
        console.log(err);
      })
    },
    // 搜索框获取到表格里面的数据
    getssList(){
      getdetail(this.SeriesNumber).then(res => {
        // this.getssList.push()
        // 方法为:先清空,后push出去this.tablelist = [],再this.tablelist.push(res)
        this.TableList = []
         this.TableList.push(res)
         console.log(res)
      }).catch(err => {
      console.log(err);
      })
    },

    // 监听pagesize改变的事件
    handleSizeChange (newSize) {
      // console.log(newSize)
      this.queryInfo.pagesize = newSize
      this.getTableList()
    },
    // 监听页码值改变的事件
    handleCurrentChange (newPage) {
       this.queryInfo.pagenum = newPage
        this.getTableList()
        console.log(newPage)
    },
    // 点击跳转到配置管理的事件
    todeploy () {
      this.$router.push('/deploy')
    },
    // 点击跳转到远程管理界面
    toremote () {
      this.$router.push('/remote')
    },
  }
}
</script>


deloy.vue

<template>
<div>
   <el-row class="rowstyle">
  <el-col :span="3"><el-button type="primary" size="medium">参数获取</el-button></el-col>

  <el-col :span="3" ><el-button type="primary" size="medium">参数配置</el-button></el-col>
  </el-row>
  <!-- 设置一个卡片视图 -->
<el-card style="width:100%;margin-top:20px">
  <el-table
      :data="tableData" style="width: 100%">
  <el-table-column prop="date" label="日期" width="180"></el-table-column>
      <el-table-column prop="name" label="姓名" width="180"></el-table-column>
      <el-table-column prop="address" label="地址"></el-table-column>
      <el-table-column width="180">
      <template>
        <el-select v-model="value" placeholder="选择设备" class="select1">
    <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"></el-option>
       </el-select>
      </template></el-table-column>
      <el-table-column width="180">
          <el-button type="info" size="mini"><a href="javascript:location.reload()" style="text-decoration:none">刷新</a></el-button>
      </el-table-column>
    </el-table>
</el-card>
  <!-- 表单 -->
  <el-form  label-width="80px" style="margin-top:20px" :data="DataList">
    <el-row :gutter="80">
      <el-col :span="8">
           <el-form-item label="序号:">
     <el-select v-model="value" placeholder="请选择序号">
    <el-option
      v-for="item in options"
      :key="item.value"
      :label="item.label"
      :value="item.value">
    </el-option>
  </el-select>
  </el-form-item>
      </el-col>

      <el-col :span="8">
           <el-form-item label="名称:">
    <el-select v-model="value1" placeholder="请选择设备号">
    <el-option
      v-for="item in options1"
      :key="item.value1"
      :label="item.label1"
      :value="item.value1">
    </el-option>
  </el-select>
  </el-form-item>
      </el-col>
  </div>

</template>

<script>
import {getData} from '../../network/deploy'
export default {
  data () {
    return {
      input: '',
      options: [{
      }],
      value: '',
      value1: '',
      tableData: [{
        name: '王小明',
        date: '2010010',
        address: '2021年5月28日'
      }]
    }
  },
  created () {
    this.getDataList()
},
methods: {
  // 获取表格数据
    getDataList(){
      getData().then(res => {
        this.DataList = res
        console.log(res);
      }).catch(err => {
        console.log(err);
      })
    }
}
}
</script>

history.vue

<template>
<div>
   <el-row class="rowstyle">
  <el-col :span="3"><el-button type="primary" size="medium">参数获取</el-button></el-col>
  <el-col :span="3" ><el-button type="primary" size="medium">参数配置</el-button></el-col>
  </el-row>
  <!-- 设置一个卡片视图 -->
<el-card style="width:100%;margin-top:20px">
  <el-table
      :data="tableData" style="width: 100%">
  <el-table-column prop="date" label="日期" width="180"></el-table-column>
      <el-table-column prop="name" label="姓名" width="180"></el-table-column>
      <el-table-column prop="address" label="地址"></el-table-column>
      <el-table-column width="180">
      <template>
        <el-select v-model="value" placeholder="选择设备" class="select1">
    <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"></el-option>
       </el-select>
      </template></el-table-column>
      <el-table-column width="180">
          <el-button type="info" size="mini"><a href="javascript:location.reload()" style="text-decoration:none">刷新</a></el-button>
      </el-table-column>
    </el-table>
</el-card>
  <!-- 表单 -->
  <el-form  label-width="80px" style="margin-top:20px" :data="DataList">
    <el-row :gutter="80">
      <el-col :span="8">
           <el-form-item label="序号:">
     <el-select v-model="value" placeholder="请选择序号">
    <el-option
      v-for="item in options"
      :key="item.value"
      :label="item.label"
      :value="item.value">
    </el-option>
  </el-select>
  </el-form-item>
      </el-col
      <el-col :span="8">
           <el-form-item label="名称:">
    <el-select v-model="value1" placeholder="请选择设备号">
    <el-option
      v-for="item in options1"
      :key="item.value1"
      :label="item.label1"
      :value="item.value1">
    </el-option>
  </el-select>
  </el-form-item>
      </el-col>
      <el-col :span="8">
           <el-form-item label="类型:">
    <el-select v-model="value" placeholder="请选择类型号">
    <el-option
      v-for="item in options"
      :key="item.value"
      :label="item.label"
      :value="item.value"> </el-option> </el-select></el-form-item </el-col>
    </el-row>
  </el-form> <el-button class="save">保存</el-button><el-button class="recover">恢复默认</el-button>
  </div
</template>

<script>
import {getData} from '../../network/deploy'
export default {
  data () {
    return {
      input: '',
        address: '2021年5月28日'
      }]
    }
  },
  created () {
    this.getDataList()
},
methods: {
  // 获取表格数据
    getDataList(){
      getData().then(res => {
        this.DataList = res
        console.log(res);
      }).catch(err => {
        console.log(err);
      })
    }
}
}
</script>

power.vue

<template>
<div>
  <el-table
    :data="tableData"
    style="width: 100%"
    height="350" border stripe>
    <el-table-column type="index"></el-table-column>
    <el-table-column  prop="powername" label="权限名称" width="200"></el-table-column>
    <el-table-column prop="poweraddress" label="位置" width="120"></el-table-column>
    <el-table-column prop="level" label="权限等级" width="350">
        <template>
            <el-tag closable @click="remove">超级管理员</el-tag>
            <el-tag type="success" closable @click="remove">管理员</el-tag>
            <el-tag type="warning" closable @click="remove">用户</el-tag>
        </template>
    </el-table-column>
    <el-table-column  label="操作" width="400">
        <template>
<el-button type="primary" icon="el-icon-edit" size="mini">查看</el-button>
<el-button type="danger" icon="el-icon-delete" size="mini">删除</el-button>
<el-button type="warning" icon="el-icon-setting" size="mini" @click="showsetpowerdialog">分配添加</el-button>
        </template>
    </el-table-column>
  </el-table>

  <!-- 添加分配对话框 -->
  <el-dialog
  title="添加分配"
  :visible.sync="setpowerdialogVisible"
  width="50%">
  <span>您所要添加分配的权限</span>
  <span slot="footer" class="dialog-footer">
    <el-button @click="setpowerdialogVisible = false">取 消</el-button>
    <el-button type="primary" @click="setpowerdialogVisible = false">确 定</el-button>
  </span>
</el-dialog>
</div>
</template>

<script>
export default {
  data () {
    return {
      tableData: [{
        powername: '设备管理权限',
        poweraddress: 'equip',
        level: ''
      }, {
        powername: '配置管理权限',
        poweraddress: 'deploy',
        level: ''
      }, {
        powername: '历史数据权限',
        poweraddress: 'history',
        level: ''
      }, {
        powername: '数据分析权限',
        poweraddress: 'analysis',
        level: ''
      }, {
        powername: '权限管理权限',
        poweraddress: 'power',
        level: ''
      }, {
        powername: '远程管理权限',
        poweraddress: 'remote',
        level: ''
      }],
      // 控制对话框的显示与隐藏
      setpowerdialogVisible: false
    }
  },
  created () {},
  methods: {
    async remove () {
    // 根据弹框删除
      const confirmResult = await this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).catch(err => err)
      if (confirmResult !== 'comfirm') {
        return this.$message.info('取消删除')
      }
      console.log('确认了删除')
    },
    // 展示分配添加对话框
    showsetpowerdialog () {
      this.setpowerdialogVisible = true
    }
  }
}
</script>
<style lang="less" scoped>
</style>

remote.vue

<script>
// 引入video样式
import 'video.js/dist/video-js.css'
import 'vue-video-player/src/custom-theme.css'
export default {
  data () {
    const self = this
    return {
      //喷杀控制显示隐藏
      PS:true,
      // 摄像头部分的显示与隐藏
      camera:false,
      

      // 视频流
      playerOptions: {
        playbackRates: [0.7, 1.0, 1.5, 2.0], // 播放速度
        autoplay: false, // 如果true,浏览器准备好时开始回放。
        controls: true, // 控制条
        preload: 'auto', // 视频预加载
        muted: false, // 默认情况下将会消除任何音频。
        loop: false, // 导致视频一结束就重新开始。
        language: 'zh-CN',
        aspectRatio: '16:9', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
        fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
        sources: [{
          type: 'video/mp4',
          src: ''// 你所放置的视频的地址,最好是放在服务器上
        }],
        poster: 'http://192.168.1.2:8081/', // 你的封面地址(覆盖在视频上面的图片)
        width: document.documentElement.clientWidth,
        notSupportedMessage: '此视频暂无法播放,请稍后再试' // 允许覆盖Video.js无法播放媒体源时显示的默认信息。
      },
      input: '',
      // 地图部分代码
      center: [121.59996, 31.197646],
      lng: 0,
      lat: 0,
      loaded: false,
      plugin: [
        {
          enableHighAccuracy: true,
          timeout: 100,
          maximumAge: 0,
          convert: true,
          showButton: true,
          buttonPosition: 'RB',
          showMarker: true,
          showCircle: true,
          panToLocation: true,
          zoomToAccuracy: true,
          extensions: 'all',

          pName: 'Geolocation',
          events: {
            init (o) {
              // o 是高德地图定位插件实例
              o.getCurrentPosition((status, result) => {
                console.log(result)
                if (result && result.position) {
                  self.lng = result.position.lng
                  self.lat = result.position.lat
                  self.center = [self.lng, self.lat]
                  self.loaded = true
                  self.$nextTick()
                }
              })
            }
          }
        }
      ]
    }
  },
methods:{
  PsIsShow(){
    this.PS = true
  },
  cameraisshow(){
    this.camera = !this.camera
  }

}
}
</script>

总结:工程我会放在“资源”一栏,大家可以供参考,谢谢!

猜你喜欢

转载自blog.csdn.net/Lushengshi/article/details/126084648