xsh 3 gadi atpakaļ
vecāks
revīzija
345ac40945

+ 110 - 5
public/static/weather/index.html

@@ -6,22 +6,127 @@
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>Document</title>
     <script src="https://s3.pstatp.com/cdn/expire-1-M/jquery/3.3.1/jquery.min.js"></script>
+    <script src="./js/echarts.min.js"></script>
+    <style>
+        #echarts-weather {
+            width: 800px;
+            height: 400px;
+        }
+    </style>
 </head>
-<body style="margin: 0;">
-    <div id="he-plugin-standard"></div>
+<body style="margin: 0; text-align: center">
+    <div id="he-plugin-standard" style="margin: 0 auto"></div>
+    <div id="echarts-weather"></div>
 <script>
     WIDGET = {
         "CONFIG": {
-            "layout": "2",
-            "width": "300",
+            "layout": "1",
+            "width": "800",
             "height": "400",
             "background": "1",
             "dataColor": "FFFFFF",
-            "borderRadius": "5",
+            "textAlign": 'center',
+            "borderRadius": "0",
             "key": "bfab9d72ee5d4719a5e96fb50436c396"
         }
     }
+    let farmId = localStorage.getItem('lastFarmId');
+    const token = localStorage.getItem('accessToken');
+    var myChart = echarts.init(document.getElementById('echarts-weather'))
+    let options = {
+      title: {
+        text: '未来24小时温度变化',
+        left: 'center',
+        color: '#fff',
+        textStyle : {
+          color: '#fff'
+        }
+      },
+      tooltip: {
+        trigger: 'axis',
+      },
+      color: ['#FFFFFF'],
+      xAxis: [
+        {
+          type: 'category',
+          data: [],
+          axisPointer: {
+            type: 'shadow'
+          },
+          axisLine: {
+            show: false,
+            lineStyle: {
+              color: '#fff',
+            }
+          },
+          axisTick:{
+            show:false
+          },
+        }
+      ],
+      yAxis: [
+        {
+          type: 'value',
+          axisLabel: {
+            formatter: '{value}℃'
+          },
+          axisLine: {
+            show: false,
+            lineStyle: {
+              color: '#fff',
+            }
+          },
+          axisTick:{
+            show:false
+          },
+        }
+      ],
+      series: [
+        {
+          name: '温度',
+          type: 'line',
+          // stack: 'Total',
+          smooth: true,
+          areaStyle: {},
+          emphasis: {
+            focus: 'series'
+          },
+          itemStyle : {
+            color: '#fff',
+            borderColor: '#fff',
+            normal: {
+              label : {
+                show: true,
+                textStyle: {
+                  fontSize: 14
+                }
+              }
+            }
+          },
+          data: []
+        }
+      ]
+    }
+    $.ajax({
+      url: `http://115.238.57.190:8100/produce/weather/info?farmId=${farmId}`,
+      type: 'POST',
+      headers: {
+        accessToken: token
+      },
+      success: function(res) {
+        if(res.code === 10000) {
+          options.series[0].data = res.data.tempList;
+          let arr = [];
+          res.data.timeList.forEach(item => {
+            arr.push(item.substring(5, 16))
+          })
+          options.xAxis[0].data = arr;
+          myChart.setOption(options)
+        }
+      }
+    })
 </script>
 <script src="https://widget.qweather.net/standard/static/js/he-standard-common.js?v=2.0"></script>
 </body>
 </html>
+

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 12 - 0
public/static/weather/js/echarts.min.js


BIN
src/assets/images/login.png


BIN
src/assets/images/pwd.png


BIN
src/assets/weather/baoxue.png


BIN
src/assets/weather/baoyu.png


BIN
src/assets/weather/bingbao.png


BIN
src/assets/weather/daxue.png


BIN
src/assets/weather/dayu.png


BIN
src/assets/weather/duoyunzhuanqing.png


BIN
src/assets/weather/leiyu.png


BIN
src/assets/weather/leizhenyu.png


BIN
src/assets/weather/qingtian.png


BIN
src/assets/weather/qingzhuanduoyun.png


BIN
src/assets/weather/shachenbao.png


BIN
src/assets/weather/xiaoxue.png


BIN
src/assets/weather/xiaoyu.png


BIN
src/assets/weather/yintian.png


BIN
src/assets/weather/youwu.png


BIN
src/assets/weather/yujiaxue.png


BIN
src/assets/weather/zhenyu.png


BIN
src/assets/weather/zhongxue.png


BIN
src/assets/weather/zhongyu.png


+ 5 - 1
src/main.js

@@ -13,7 +13,7 @@ import store from './store'
 import 'lib-flexible/flexible'
 import './assets/ttf/font.css';
 import echart from 'echarts';
-import { DatePicker, Row, Col, Select, Option, Icon } from 'element-ui';
+import { DatePicker, Row, Col, Select, Option, Icon, Input, Button, Message } from 'element-ui';
 
 Vue.config.productionTip = false
 Vue.prototype.$echarts = echart
@@ -23,6 +23,10 @@ Vue.use(Col)
 Vue.use(Select)
 Vue.use(Option)
 Vue.use(Icon)
+Vue.use(Input)
+Vue.use(Button)
+Vue.use(Message)
+Vue.prototype.$message = Message;
 
 new Vue({
   router,

+ 8 - 0
src/router/index.js

@@ -13,6 +13,14 @@ const routes = [
     name: 'MainLayout',
     component: () => import('../views/MainLayout.vue'),
     children: mainRouterChildren
+  },
+  {
+    path: '/login',
+    name: 'Login',
+    component: () => import('../views/Login/Login.vue'),
+    meta: {
+      title: '登录',
+    },
   }
 ]
 

+ 44 - 1
src/store/index.js

@@ -1,14 +1,57 @@
 import Vue from 'vue'
 import Vuex from 'vuex'
-
+import { getFarm } from '../utils/api'
 Vue.use(Vuex)
 
 export default new Vuex.Store({
   state: {
+      color: '#31C3A6',
+      mode: true,
+      ip: 'http://115.238.57.190:8100',
+      // 所选择的farmId
+      farmId: '',
+      farmList: [],
   },
+
   mutations: {
+    setColor(state, data) {
+      state.color = data
+    },
+    setMode(state, data){
+      state.mode = data
+    },
+    SET_FARMID(state, data) {
+      state.farmId = data;
+    },
+    SET_FARMLIST(state, data) {
+      state.farmList = data;
+    }
   },
   actions: {
+    setModeAsync(context, data) {
+      context.commit('setMode' ,data)
+    },
+    setColorAsync(context, data) {
+      context.commit('setColor', data)
+    },
+    setFarmIdAsync(context,data) {
+      context.commit('SET_FARMID', data)
+    },
+    // 获取牧场列表
+    GetFarm({ commit }){
+      return new Promise((resolve, reject) => {
+        getFarm().then(res => {
+          if (res.code === 10000) {
+            commit('SET_FARMLIST', res.data);
+            resolve(res.data);
+          } else {
+            reject(new Error(res.message))
+          }
+        }).catch(error => {
+          reject(error)
+        })
+      })
+    }
   },
   modules: {
   }

+ 37 - 0
src/utils/api.js

@@ -0,0 +1,37 @@
+import axios from './http';
+
+/** 获取天气 **/
+export function getWeather(data) {
+  return axios({
+    url: '/produce/weather/info',
+    method: 'post',
+    params: data
+  })
+}
+
+// 登录
+export function Login(data) {
+  return axios({
+    url: '/admin/my/loginMultilevel',
+    method: 'post',
+    data: data
+  })
+}
+
+// 牧场列表
+export function getFarm(data) {
+  return axios({
+    url: '/admin/farm/getFarm',
+    method: 'get',
+    params: data
+  })
+}
+
+// 选择牧场
+export function getFarmId(data) {
+  return axios({
+    url: 'admin/accountMultilevel/getLastFarmId',
+    method: 'get',
+    params: data,
+  })
+}

+ 37 - 1
src/utils/http.js

@@ -25,12 +25,17 @@ instance.interceptors.request.use(
     // 但是即使token存在,也有可能token是过期的,所以在每次的请求头中携带token
     // 后台根据携带的token判断用户的登录情况,并返回给我们对应的状态码
     // 而后我们可以在响应拦截器中,根据状态码进行一些统一的操作。
-
+    const token = localStorage.getItem('accessToken')
+    const lastFarmId = Number(localStorage.getItem('lastFarmId'));
+    token && (config.headers.accessToken = token)
     removePending(config); //在一个ajax发送前执行一下取消操作
     config.cancelToken = new cancelToken((c)=>{
       // 这里的ajax标识我是用请求地址&请求方式拼接的字符串,当然你可以选择其他的一些方式
       pending.push({ u: config.url + '&' + config.method, f: c });
     });
+
+    let data = config.data || config.params || {}
+    data.farmId = lastFarmId
     return config
   },
   error => Promise.error(error)
@@ -50,6 +55,22 @@ instance.interceptors.response.use(
   }
 )
 
+/**
+ * 跳转登录页
+ * 携带当前页面路由,以期在登录页面完成登录后返回当前页面
+ */
+const toLogin = () => {
+  let path = '/';
+  if(router.currentRoute.fullPath.indexOf('login') === -1) {
+    path =  router.currentRoute.fullPath
+  }
+  router.replace({
+    path: '/login',
+    query: {
+      redirect: path
+    }
+  });
+}
 
 /**
  * 请求失败后的错误统一处理
@@ -59,6 +80,21 @@ instance.interceptors.response.use(
 const errorHandle = (status, other) => {
   // 状态码判断
   switch (status) {
+    // 401: 未登录状态,跳转登录页
+    case 401:
+      toLogin();
+      break;
+    // 403 token过期
+    // 清除token并跳转登录页
+    case 403:
+      Message.error('登录过期,请重新登录');
+      localStorage.removeItem('accessToken');
+      localStorage.removeItem('UserName');
+      localStorage.removeItem('UserId');
+      setTimeout(() => {
+        toLogin();
+      }, 1000);
+      break;
     // 404请求不存在
     case 404:
       Message.error('请求的资源不存在');

+ 152 - 0
src/views/Login/Login.vue

@@ -0,0 +1,152 @@
+<template>
+  <div class="login">
+    <div class="loginLogo"></div>
+    <div class="loginText">
+      <h2>数智牧场综合管理系统</h2>
+      <div class="loginForm">
+        <el-input
+            style="height: 50px; line-height: 50px;"
+            placeholder="请输入登录名"
+            v-model="userName"
+            size="large">
+          <i class="el-icon-user-solid" slot="prefix" style="font-size: 28px; line-height: 50px; margin-left: 5px"></i>
+        </el-input>
+        <div style="height: 20px"></div>
+        <el-input
+            style="height: 50px"
+            placeholder="请输入登录密码"
+            v-model="passWord"
+            type="password"
+            size="large">
+          <i class="pwd" slot="prefix"></i>
+        </el-input>
+        <div style="height: 20px"></div>
+        <el-row :gutter="20">
+          <el-col :span="15">
+            <el-input
+                style="height: 50px"
+                placeholder="请输入验证码"
+                v-model="code"
+                size="large">
+              <i class="pwd" slot="prefix"></i>
+            </el-input>
+          </el-col>
+          <el-col :span="9">
+            <img id="kaptchaImage" :src=" ip + '/admin/my/send'" @click="refset" alt="">
+          </el-col>
+        </el-row>
+        <div style="height: 20px"></div>
+        <el-button @click="onSubmit" style="width: 100%; height: 50px; background-color: #1ABC9C; color: #fff;" >登录</el-button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { Login} from '../../utils/api';
+import { mapState, } from 'vuex'
+export default {
+  name: "Login",
+  data() {
+    return {
+      userName: '',
+      passWord: '',
+      code: '',
+    }
+  },
+  computed: {
+    ...mapState(['ip'])
+  },
+  methods: {
+    onSubmit() {
+      let params = {
+        accountName: this.userName,
+        password: this.passWord,
+        code: this.code,
+      }
+      Login(params).then(res => {
+        if(res.code === 10000) {
+          localStorage.setItem('accessToken', res.data.token);
+          localStorage.setItem('UserName', res.data.accountName);
+          localStorage.setItem('UserId', res.data.id);
+          this.$message.success('登录成功');
+          let url = this.$route.query.redirect;
+          if(url) {
+            this.$router.replace(url);
+          } else {
+            this.$router.replace('/');
+          }
+        } else {
+          this.$message.error(res.message);
+          this.refset();
+        }
+      })
+    },
+    // 刷新
+    refset() {
+      let img = document.getElementById('kaptchaImage');
+      img.setAttribute('src', this.ip + '/admin/my/send?'+ Math.floor(Math.random() * 100));
+    }
+  }
+}
+</script>
+
+<style scoped>
+  /deep/.el-input__inner {
+    height: 50px;
+    line-height: 50px;
+    padding: 0 0 0 50px;
+  }
+  .login {
+    width: 100%;
+    height: 100vh;
+    background-color: #1ABC9C;
+    position: relative;
+  }
+  .loginLogo {
+    width: 100%;
+    height: 400px;
+    background-image: url("../../assets/images/login.png");
+    background-size: 100% 100%;
+    position: absolute;
+    top: 50%;
+    margin: -300px 0 0 0;
+  }
+  .loginText {
+    width: 420px;
+    height: 400px;
+    background-color: #fff;
+    border-radius: 10px;
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    margin: -250px 0 0 -210px;
+    box-sizing: border-box;
+    padding: 10px;
+    box-shadow: 0 0 10px rgb(0 0 0 / 35%);
+    text-align: center;
+  }
+  h2 {
+    font-size: 28px;
+    color: #1ABC9C;
+    font-weight: 600;
+    padding-top: 10px;
+  }
+  .loginForm {
+    width: 280px;
+    margin: 40px auto 0;
+    /*height: 300px;*/
+  }
+  .pwd {
+    display: inline-block;
+    width: 28px;
+    height: 50px;
+    font-size: 28px;
+    background-image: url("../../assets/images/pwd.png");
+    background-repeat: no-repeat;
+    background-size: 100% 60%;
+    background-position: 100% 42%;
+    line-height: 50px;
+    margin-left: 5px
+  }
+</style>

+ 180 - 7
src/views/MainLayout.vue

@@ -3,7 +3,28 @@
     <div class="main-title">{{title}}</div>
     <div class="main-left">
       <!--  天气    -->
-      <div v-show="isHome" class="main-home" @click="showWeather = true">天气</div>
+      <div v-show="isHome" class="main-home" @click="showWeather = true">
+        <div class="weatherBox" v-if="Object.keys(weather).length !== 0">
+          <div class="box-left">
+            <i class="qing" v-if="weather.day_weather === '晴'"></i>
+            <i class="duoyun" v-else-if="weather.day_weather === '多云'"></i>
+            <i class="yin" v-else-if="weather.day_weather === '阴'"></i>
+            <i class="xiaoyu" v-else-if="weather.day_weather === '小雨'"></i>
+            <i class="zyu" v-else-if="weather.day_weather === '中雨'"></i>
+            <i class="dyu" v-else-if="weather.day_weather === '大雨'"></i>
+            <i class="byu" v-else-if="weather.day_weather === '暴雨'"></i>
+            <i class="xxue" v-else-if="weather.day_weather === '小雪'"></i>
+            <i class="zxue" v-else-if="weather.day_weather === '中雪'"></i>
+            <i class="dxue" v-else-if="weather.day_weather === '大雪'"></i>
+            <i class="bxue" v-else-if="weather.day_weather === '暴学'"></i>
+          </div>
+          <div class="box-right">
+            <p class="fontSize">{{weather.day_weather}}</p>
+            <p class="fontSize">{{weather.min_degree}}-{{weather.max_degree}}℃</p>
+          </div>
+        </div>
+        <div v-else @click="refresh">抓取天气数据失败,请重试</div>
+      </div>
       <!--  返回首页    -->
       <div v-show="!isHome" class="main-back" @click="back">首页</div>
     </div>
@@ -11,24 +32,48 @@
       <!-- 时间     -->
       <div v-show="isHome" class="main-time">{{currentTime}}</div>
       <!--  天气    -->
-      <div v-show="!isHome" class="main-home">天气</div>
+      <div v-show="!isHome" class="main-home">
+        <div class="weatherBox" v-if="Object.keys(weather).length !== 0">
+          <div class="box-left">
+            <i class="qing" v-if="weather.day_weather === '晴'"></i>
+            <i class="duoyun" v-else-if="weather.day_weather === '多云'"></i>
+            <i class="yin" v-else-if="weather.day_weather === '阴'"></i>
+            <i class="xiaoyu" v-else-if="weather.day_weather === '小雨'"></i>
+            <i class="zyu" v-else-if="weather.day_weather === '中雨'"></i>
+            <i class="dyu" v-else-if="weather.day_weather === '大雨'"></i>
+            <i class="byu" v-else-if="weather.day_weather === '暴雨'"></i>
+            <i class="xxue" v-else-if="weather.day_weather === '小雪'"></i>
+            <i class="zxue" v-else-if="weather.day_weather === '中雪'"></i>
+            <i class="dxue" v-else-if="weather.day_weather === '大雪'"></i>
+            <i class="bxue" v-else-if="weather.day_weather === '暴学'"></i>
+          </div>
+          <div class="box-right">
+            <p class="fontSize">{{weather.day_weather}}</p>
+            <p class="fontSize">{{weather.min_degree}}-{{weather.max_degree}}℃</p>
+          </div>
+        </div>
+        <div v-else @click="refresh">抓取天气数据失败,请重试</div>
+      </div>
     </div>
     <div class="main-bottom">青莲食品</div>
     <div class="content">
       <router-view></router-view>
     </div>
     <transition name = "moveL">
-      <div id="weather" v-show="showWeather">
+      <div id="weather" v-if="showWeather">
         <div style="text-align: left">
-          <i class="el-icon-back" style="font-size: 24px; color: #fff" @click="showWeather = false"></i>
+          <i class="el-icon-back" style="font-size: 24px; color: #fff; cursor: pointer" @click="showWeather = false"></i>
         </div>
-        <iframe style="height: 400px" src="static/weather/index.html" frameborder="0"></iframe>
+        <iframe style="width: 800px; height: 800px; z-index: 9999" src="static/weather/index.html" frameborder="0"></iframe>
       </div>
     </transition>
   </div>
 </template>
 
 <script>
+import {getFarmId, getWeather} from "@/utils/api";
+import { mapActions } from 'vuex'
+
 export default {
   name: "MainLayout",
   data() {
@@ -37,7 +82,10 @@ export default {
       isHome: true,
       currentTime: '',
       timer4: null,
-      showWeather: false
+      showWeather: false,
+      weather: {},
+      // 天气报警
+      weatherInfo: {}
     }
   },
   watch: {
@@ -55,6 +103,7 @@ export default {
     }
   },
   methods: {
+    ...mapActions(['GetFarm', 'setFarmIdAsync']),
     initTime() {
       var _this = this;
       this.timer4 = setInterval(function() {
@@ -85,9 +134,29 @@ export default {
     },
     back() {
       this.$router.push('/')
+    },
+    init() {
+      getFarmId().then(res => {
+        if(res.code === 10000) {
+          this.setFarmIdAsync(res.data);
+          localStorage.setItem('lastFarmId', res.data);
+          this.refresh()
+        }
+      })
+    },
+    // 刷新拿到数据
+    refresh() {
+      getWeather({}).then(res => {
+        if(res.code === 10000) {
+          this.weather = res.data;
+          this.weatherInfo = JSON.parse(res.data.alarm)
+        }
+      })
     }
   },
   mounted() {
+    this.init()
+    this.GetFarm()
     this.title = this.$route.meta.title;
     if (this.$route.name === 'Home') {
       this.isHome = true;
@@ -186,7 +255,8 @@ export default {
   #weather {
     background-color: rgba(0, 0, 0, .5);
     position: absolute;
-    height: 450px;
+    width: 800px;
+    height: 800px;
     top: 0;
     left: 0;
   }
@@ -202,4 +272,107 @@ export default {
   .moveL-leave-to {
     transform: translateX(-100%);
   }
+  .weatherBox {
+    width: 100%;
+    height: 100%;
+    box-sizing: border-box;
+    padding: 0  20px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    cursor: pointer;
+  }
+  .box-left {
+    width: 35px;
+    height: 35px;
+  }
+  .box-right {
+    width: 60px;
+    height: 100%;
+    margin-left: 20px;
+  }
+  .qing {
+    width: 100%;
+    height: 100%;
+    display: inline-block;
+    background: url("../assets/weather/qingtian.png") no-repeat;
+    background-size: 100% 100%;
+  }
+  .fontSize {
+    height: 20px;
+    margin: 0;
+    line-height: 20px;
+    text-align: left;
+    color: #28BCCA;
+  }
+  .duoyun {
+    width: 100%;
+    height: 100%;
+    display: inline-block;
+    background: url("../assets/weather/qingzhuanduoyun.png") no-repeat;
+    background-size: 100% 100%;
+  }
+  .yin {
+    width: 100%;
+    height: 100%;
+    display: inline-block;
+    background: url("../assets/weather/yintian.png") no-repeat;
+    background-size: 100% 100%;
+  }
+  .xiaoyu {
+    width: 100%;
+    height: 100%;
+    display: inline-block;
+    background: url("../assets/weather/xiaoyu.png") no-repeat;
+    background-size: 100% 100%;
+  }
+  .zyu {
+    width: 100%;
+    height: 100%;
+    display: inline-block;
+    background: url("../assets/weather/zhongyu.png") no-repeat;
+    background-size: 100% 100%;
+  }
+  .dyu {
+    width: 100%;
+    height: 100%;
+    display: inline-block;
+    background: url("../assets/weather/dayu.png") no-repeat;
+    background-size: 100% 100%;
+  }
+  .byu {
+    width: 100%;
+    height: 100%;
+    display: inline-block;
+    background: url("../assets/weather/baoyu.png") no-repeat;
+    background-size: 100% 100%;
+  }
+  .xxue{
+    width: 100%;
+    height: 100%;
+    display: inline-block;
+    background: url("../assets/weather/xiaoxue.png") no-repeat;
+    background-size: 100% 100%;
+  }
+  .zxue{
+    width: 100%;
+    height: 100%;
+    display: inline-block;
+    background: url("../assets/weather/zhongxue.png") no-repeat;
+    background-size: 100% 100%;
+  }
+  .dxue{
+    width: 100%;
+    height: 100%;
+    display: inline-block;
+    background: url("../assets/weather/daxue.png") no-repeat;
+    background-size: 100% 100%;
+  }
+  .bxue{
+    width: 100%;
+    height: 100%;
+    display: inline-block;
+    background: url("../assets/weather/baoxue.png") no-repeat;
+    background-size: 100% 100%;
+  }
 </style>