1、全局菜单栏新增点击父级菜单标题后在导航栏展开父级所有下一级菜单功能
2、登录页面按照新需求调整整体布局及样式
3、优化首页看板页面图表视图
已添加2个文件
已修改10个文件
948 ■■■■ 文件已修改
src/api/signage.js 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/login.jpeg 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/login.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/components/layouts/TabLayout.vue 64 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/layouts/UserLayout.vue 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/menu/index.js 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dashboard/Analysis.vue 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dashboard/BranchFactorySignage.vue 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dashboard/EquipmentSignage.vue 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dashboard/IndexSignage.vue 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dashboard/WorkshopSectionSignage.vue 171 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/user/Login.vue 556 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/signage.js
@@ -24,5 +24,9 @@
  // 设备OEE统计
  getEquipmentOEEStatistics: productionCode => getAction('/mdc/home/equipmentOEEStatistics', { productionCode }),
  // 设备OEE和利用率对比
  getEquipmentMonthStatisticsApi: productionCode => getAction('/mdc/home/equipmentMonthStatistics', { productionCode })
  getEquipmentMonthStatisticsApi: productionCode => getAction('/mdc/home/equipmentMonthStatistics', { productionCode }),
  // 工段级前7天利用率折线图
  getEquipmentDayUtilizationStatisticsApi: productionCode => getAction('/mdc/home/equipmentDayUtilizationStatistics', { productionCode }),
  // 上个月各设备OEE统计
  getEquipmentOEEMonthStatisticsApi: productionCode => getAction('/mdc/home/equipmentOEEMonthStatistics', { productionCode })
}
src/assets/login.jpeg
src/assets/login.jpg
src/components/layouts/TabLayout.vue
@@ -4,8 +4,8 @@
    <contextmenu :itemList="menuItemList" :visible.sync="menuVisible" style="z-index: 9999;" @select="onMenuSelect"/>
    <!-- update-end- author:sunjianlei --- date:20191009 --- for: 提升右键菜单的层级 -->
    <a-tabs
      v-if="$route.meta.title!=='首页'&&multipage"
      @contextmenu.native="e => onContextmenu(e)"
      v-if="$route.meta.title!=='首页'&&multipage"
      :active-key="activePage"
      class="tab-layout-tabs"
      style="height:52px"
@@ -14,12 +14,12 @@
      @change="changePage"
      @tabClick="tabCallBack"
      @edit="editPage">
      <a-tab-pane :id="page.fullPath" :key="page.fullPath" v-for="page in pageList"
      <a-tab-pane :id="page.path" :key="page.path" v-for="page in pageList"
                  :closable="!(page.meta.title=='首页')">
        <span slot="tab" :pagekey="page.fullPath">{{ page.meta.title }}</span>
        <span slot="tab" :pagekey="page.path">{{ page.meta.title }}</span>
      </a-tab-pane>
    </a-tabs>
    <div>
    <div :style="{padding: $route.meta.title=='首页'?'0':'12px 12px 0'}">
      <!-- update-begin-author:taoyan date:20201221 for:此处删掉transition标签 不知道为什么加上后 页面路由切换的时候即1及菜单切到2及菜单的时候 两个菜单页面会同时出现300-500秒左右 -->
      <keep-alive v-if="multipage">
        <router-view v-if="reloadFlag"/>
@@ -91,6 +91,7 @@
      this.pageList.push(currentRoute)
      this.linkList.push(currentRoute.fullPath)
      this.activePage = currentRoute.fullPath
      this.$bus.$on('clickMenuTitleSelected', this.clickMenuTitleSelected)
    },
    mounted() {
    },
@@ -123,10 +124,12 @@
        }
      },
      'activePage': function(key) {
        console.log('key', key)
        let index = this.linkList.lastIndexOf(key)
        let waitRouter = this.pageList[index]
        // 【TESTA-523】修复:不允许重复跳转路由异常
        if (waitRouter.fullPath !== this.$route.fullPath) {
        console.log('waitRouter', waitRouter, 'fullPath', this.$route.fullPath, waitRouter.fullPath !== this.$route.fullPath)
        if (waitRouter.path !== this.$route.fullPath) {
          this.$router.push(Object.assign({}, waitRouter))
        }
        this.changeTitle(waitRouter.meta.title)
@@ -166,6 +169,7 @@
      // update-begin-author:sunjianlei date:20200120 for: 动态更改页面标题
      changeTitle(title) {
        console.log('title', title)
        let projectTitle = 'MDC智慧车间'
        // 首页特殊处理
        if (this.$route.path === indexKey) {
@@ -177,6 +181,7 @@
      // update-end-author:sunjianlei date:20200120 for: 动态更改页面标题
      changePage(key) {
        console.log('changePage', key)
        this.activePage = key
      },
      tabCallBack() {
@@ -202,8 +207,8 @@
          return
        }
        console.log('this.pageList ', this.pageList)
        let removeRoute = this.pageList.filter(item => item.fullPath == key)
        this.pageList = this.pageList.filter(item => item.fullPath !== key)
        let removeRoute = this.pageList.filter(item => item.path == key)
        this.pageList = this.pageList.filter(item => item.path !== key)
        let index = this.linkList.indexOf(key)
        this.linkList = this.linkList.filter(item => item !== key)
        index = index >= this.linkList.length ? this.linkList.length - 1 : index
@@ -223,7 +228,7 @@
          this.emitPageClosed(removeRoute[0])
        }
        //update-end--Author:scott  Date:20201015 for:路由缓存问题,关闭了tab页时再打开就不刷新 #842
        this.tabCallBack()
      },
      // 触发 page-closed (页面关闭)全局事件
      emitPageClosed(closedRoute) {
@@ -284,7 +289,7 @@
          let indexContent = this.pageList.slice(0, 1)[0]
          this.linkList = this.linkList.slice(index, index + 1)
          this.pageList = this.pageList.slice(index, index + 1)
          this.linkList.unshift(indexContent.fullPath)
          this.linkList.unshift(indexContent.path)
          this.pageList.unshift(indexContent)
          this.activePage = this.linkList[1]
        }
@@ -298,17 +303,19 @@
        let index = this.linkList.indexOf(pageKey)
        this.linkList = this.linkList.slice(index)
        this.pageList = this.pageList.slice(index)
        this.linkList.unshift(indexContent.fullPath)
        this.linkList.unshift(indexContent.path)
        this.pageList.unshift(indexContent)
        // 若将激活页一并关闭则显示导航栏除首页第一个页面
        if (this.linkList.indexOf(this.activePage) < 0) {
          this.activePage = this.linkList[0]
          this.activePage = this.linkList[1]
        }
      },
      closeRight(pageKey) {
        let index = this.linkList.indexOf(pageKey)
        this.linkList = this.linkList.slice(0, index + 1)
        this.pageList = this.pageList.slice(0, index + 1)
        if (this.linkList.indexOf(this.activePage < 0)) {
        // 若将激活页一并关闭则显示导航栏最后一个页面
        if (this.linkList.indexOf(this.activePage) < 0) {
          this.activePage = this.linkList[this.linkList.length - 1]
        }
      },
@@ -340,6 +347,39 @@
      //新增一个返回方法
      excuteCallback(callback) {
        callback()
      },
      clickMenuTitleSelected(selectedMenus) {
        //console.log("新的路由",newRoute)
        console.log('clickTitle', this.activePage)
        this.activePage = selectedMenus[0].path
        if (!this.multipage) {
          this.linkList = [this.linkList[0], selectedMenus[0].path]
          this.pageList = [this.pageList[0], Object.assign({}, selectedMenus[0])]
          // update-begin-author:taoyan date:20200211 for: TASK #3368 【路由缓存】首页的缓存设置有问题,需要根据后台的路由配置来实现是否缓存
        } else if (indexKey == selectedMenus[0].path) {
          //首页时 判断是否缓存 没有缓存 刷新之
          if (selectedMenus[0].meta.keepAlive === false) {
            this.routeReload()
          }
          // update-end-author:taoyan date:20200211 for: TASK #3368 【路由缓存】首页的缓存设置有问题,需要根据后台的路由配置来实现是否缓存
        } else {
          // selectedMenus.forEach(menuItem => {
          //   if (!this.linkList.includes(menuItem.path)) {
          //     console.log('触发增加')
          //     this.linkList.push(menuItem.path)
          //     this.pageList.push(menuItem)
          //   } else {
          //     console.log('触发没有增加')
          //     let oldIndex = this.linkList.indexOf(menuItem.path)
          //     let oldPositionRoute = this.pageList[oldIndex]
          //     this.pageList.splice(oldIndex, 1, Object.assign({}, menuItem, { meta: oldPositionRoute.meta }))
          //   }
          // })
          // 点击标题后在导航栏覆盖前一个标题所展开的下级菜单
          this.linkList = [this.linkList[0], ...selectedMenus.map(item => item.path)]
          this.pageList = [this.pageList[0], ...selectedMenus]
        }
      }
    }
  }
src/components/layouts/UserLayout.vue
@@ -1,17 +1,17 @@
<template>
  <div id="userLayout" :class="['user-layout-wrapper', device]">
    <div class="container">
      <div class="top">
        <div class="header">
          <a href="/">
            <img src="~@/assets/lxzn.png" class="logo" alt="logo">
            <span class="title">MDC智慧车间</span>
          </a>
        </div>
        <!--<div class="desc">-->
          <!--Jeecg Boot 是中国最具影响力的 企业级 低代码平台-->
      <!--<div class="top">-->
        <!--<div class="header">-->
          <!--<a href="/">-->
            <!--<img src="~@/assets/lxzn_white.png" class="logo" alt="logo">-->
            <!--<span class="title">MDC智慧车间</span>-->
          <!--</a>-->
        <!--</div>-->
      </div>
        <!--&lt;!&ndash;<div class="desc">&ndash;&gt;-->
          <!--&lt;!&ndash;Jeecg Boot 是中国最具影响力的 企业级 低代码平台&ndash;&gt;-->
        <!--&lt;!&ndash;</div>&ndash;&gt;-->
      <!--</div>-->
      <route-view></route-view>
@@ -66,10 +66,13 @@
    .container {
      width: 100%;
      min-height: 100%;
      background: #f0f2f5 url(~@/assets/background.svg) no-repeat 50%;
      background: #f0f2f5 url(~@/assets/login.jpg) no-repeat 50%;
      background-size: 100%;
      padding: 110px 0 144px;
      /*padding: 110px 0 144px;*/
      position: relative;
      display: flex;
      align-items: center;
      justify-content: center;
      a {
        text-decoration: none;
@@ -77,6 +80,10 @@
      .top {
        text-align: center;
        position: absolute;
        top: 50px;
        left: 50px;
        .header {
          height: 44px;
@@ -95,13 +102,13 @@
          .logo {
            height: 44px;
            vertical-align: top;
            margin-right: 16px;
            margin-right: 10px;
            border-style: none;
          }
          .title {
            font-size: 33px;
            color: rgba(0, 0, 0, .85);
            font-size: 30px;
            color: #fff;
            font-family: "Chinese Quote", -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
            font-weight: 600;
            position: relative;
@@ -117,17 +124,15 @@
      }
      .main {
        min-width: 260px;
        width: 368px;
        margin: 0 auto;
        background-color: #fff;
        width: 1100px;
        border-radius: 10px;
      }
      .footer {
        position: absolute;
        width: 100%;
        bottom: 0;
        padding: 0 16px;
        margin: 48px 0 24px;
        text-align: center;
        .links {
@@ -142,7 +147,7 @@
          }
        }
        .copyright {
          color: rgba(0, 0, 0, 0.45);
          color: #fff;
          font-size: 14px;
        }
      }
src/components/menu/index.js
@@ -59,7 +59,6 @@
  methods: {
    // select menu item
    onOpenChange (openKeys) {
      // 在水平模式下时执行,并且不再执行后续
      if (this.mode === 'horizontal') {
        this.openKeys = openKeys
@@ -161,13 +160,32 @@
        </Item>
      )
    },
    handleTitleClick(record,event){
      this.selectedKeys=[]
      const routes = this.$route.matched.concat()
      const { hidden } = this.$route.meta
      if (routes.length >= 3 && hidden) {
        routes.pop()
        this.selectedKeys = [routes[routes.length - 1].path]
      } else {
        if (record.path === '/dashboard/analysis') {
          //如果是首页则直接跳转首页
          this.selectedKeys = [record]
        } else if (record.children && record.children.length > 0) {
          //如果不是首页且有子菜单则展开点击标题下的所有不含下级菜单的子菜单至导航栏并打开第一个子菜单页面,若子菜单标题下仍有下一级菜单则只需要点击含下级菜单的子菜单标题即可
          this.selectedKeys = record.children.filter(item => !item.hidden&&!item.children)
        }
      }
      this.$bus.$emit('clickMenuTitleSelected', this.selectedKeys)
    },
    renderSubMenu (menu) {
      const itemArr = []
      if (!menu.alwaysShow) {
        menu.children.forEach(item => itemArr.push(this.renderItem(item)))
      }
      return (
        <SubMenu {...{ key: menu.path }}>
        <SubMenu {...{ key: menu.path }} onTitleClick={this.handleTitleClick.bind(this.$event,menu)}>
          <span slot="title">
            {this.renderIcon(menu.meta.icon)}
            <span>{menu.meta.title}</span>
src/views/dashboard/Analysis.vue
@@ -81,5 +81,14 @@
</script>
<style lang="less" scoped>
  /deep/ .back-nav {
    width: 100px;
    height: 30px;
    color: #fff;
    position: absolute;
    top: 15px;
    left: 10px;
    cursor: pointer;
    z-index: 9999
  }
</style>
src/views/dashboard/BranchFactorySignage.vue
@@ -1,25 +1,18 @@
<template>
  <div class="page-container">
    <!--<div class="page-title">-->
    <!--<slot name="index_signage_nav"></slot>-->
    <!--&lt;!&ndash;<dv-decoration-11 class="workshop-nav" v-for="item in workshopList">&ndash;&gt;-->
    <!--&lt;!&ndash;{{item.workshopName}}&ndash;&gt;-->
    <!--&lt;!&ndash;</dv-decoration-11>&ndash;&gt;-->
    <!--</div>-->
    <div class="content-container">
      <div style="width: 25%" class="left-col">
        <div class="back-nav" @click="$emit('backToLastSignage','Index')" v-if="userType===4">
          <dv-decoration-7>上一级</dv-decoration-7>
        </div>
        <dv-border-box-9 style="padding: 30px 20px 0">
          <!--<div class="first-title">M D C 入 网 总 数 : 6 0 3 台</div>-->
          <div id="running_state_chart" style="width:100%;height: 400px;"></div>
          <div id="efficiency_chart" style="width: 100%;height: 350px"></div>
        </dv-border-box-9>
      </div>
      <div style="width: 42%" class="middle-col">
        <dv-border-box-9 style="padding: 30px 20px 0">
          <!--<div class="first-title">设 备 台 账 总 数 : 1 0 2 2 台</div>-->
          <div style="display: flex">
            <div id="tech_condition_chart" style="width:50%;height: 420px;"></div>
            <div id="warranty_malfunction_chart" style="width:50%;height: 420px;"></div>
@@ -59,6 +52,7 @@
          </div>
        </dv-border-box-9>
      </div>
      <div style="width: 32%">
        <dv-border-box-9 style="padding: 30px 0 20px">
          <div id="bar_chart" style="width:100%;height: 280px;"></div>
@@ -1033,12 +1027,6 @@
      color: #fff;
      margin-bottom: 10px;
      .workshop-nav {
        width: 120px;
        height: 40px;
        font-size: 12px;
        cursor: pointer;
      }
    }
    .content-container {
@@ -1047,17 +1035,6 @@
      justify-content: space-between;
      .left-col {
        .back-nav {
          width: 100px;
          height: 30px;
          color: #fff;
          position: absolute;
          top: 25px;
          left: 25px;
          cursor: pointer;
          z-index: 9999
        }
        .first-title {
          color: #00A8AC;
          font-size: 20px;
src/views/dashboard/EquipmentSignage.vue
@@ -621,17 +621,6 @@
      .left-col {
        padding: 0 10px 0;
        .back-nav {
          width: 100px;
          height: 30px;
          color: #fff;
          position: absolute;
          top: 15px;
          left: 15px;
          cursor: pointer;
          z-index: 9999
        }
        .equipmentId-container {
          height: 100%;
          color: #eee;
src/views/dashboard/IndexSignage.vue
@@ -1,22 +1,15 @@
<template>
  <div class="page-container">
    <!--<div class="page-title">-->
    <!--<slot name="index_signage_nav"></slot>-->
    <!--&lt;!&ndash;<dv-decoration-11 class="workshop-nav" v-for="item in workshopList">&ndash;&gt;-->
    <!--&lt;!&ndash;{{item.workshopName}}&ndash;&gt;-->
    <!--&lt;!&ndash;</dv-decoration-11>&ndash;&gt;-->
    <!--</div>-->
    <div class="content-container">
      <div style="width: 25%" class="left-col">
        <dv-border-box-9 style="padding: 30px 20px 0">
          <!--<div class="first-title">M D C 入 网 总 数 : 6 0 3 台</div>-->
          <div id="running_state_chart" style="width:100%;height: 300px"></div>
          <div id="efficiency_chart" style="width: 100%;height: 465px"></div>
        </dv-border-box-9>
      </div>
      <div style="width: 42%" class="middle-col">
        <dv-border-box-9 style="padding: 30px 20px 0">
          <!--<div class="first-title">设 备 台 账 总 数 : 1 0 2 2 台</div>-->
          <div style="display: flex">
            <div id="tech_condition_chart" style="width:50%;height: 340px;"></div>
            <div id="warranty_malfunction_chart" style="width:50%;height: 340px;"></div>
@@ -64,6 +57,7 @@
          </div>
        </dv-border-box-9>
      </div>
      <div style="width: 32%">
        <dv-border-box-9 style="padding: 30px 0 20px">
          <div id="bar_chart" style="width:100%;height: 280px"></div>
@@ -1033,13 +1027,6 @@
      flex-wrap: wrap;
      color: #fff;
      margin-bottom: 10px;
      .workshop-nav {
        width: 120px;
        height: 40px;
        font-size: 12px;
        cursor: pointer;
      }
    }
    .content-container {
@@ -1047,23 +1034,7 @@
      display: flex;
      justify-content: space-between;
      .left-col {
        .first-title {
          color: #00A8AC;
          font-size: 20px;
          text-align: center;
          font-weight: bold;
        }
      }
      .middle-col {
        .first-title {
          color: #00A8AC;
          font-size: 20px;
          text-align: center;
          font-weight: bold;
        }
        .support-plan-container {
          display: flex;
          justify-content: space-around;
src/views/dashboard/WorkshopSectionSignage.vue
@@ -5,13 +5,14 @@
        <div class="back-nav" @click="$emit('backToLastSignage','BranchFactory')" v-if="userType>=3">
          <dv-decoration-7>上一级</dv-decoration-7>
        </div>
        <dv-border-box-9 style="padding: 15px">
        <dv-border-box-9 style="padding: 15px 15px 0">
          <div id="tech_condition_chart" style="width:100%;height: 240px;"></div>
          <div id="warranty_malfunction_chart" style="width:100%;height: 240px;"></div>
          <div style="display: flex;">
            <div style="flex:0.5;display: flex;flex-direction:column;align-items: center">
              <dv-decoration-11 style="width:90%;height:60px;color: #ccc;font-size: 20px">三保计划</dv-decoration-11>
          <div>
            <div style="display: flex;flex-direction:column;align-items: center">
              <dv-decoration-11 style="width:45%;height:60px;color: #fff;font-size: 20px;align-self: flex-start">三保计划
              </dv-decoration-11>
              <div class="support-plan-container">
                <div class="support-plan-item" style="background:#5FE0AF">
                  <div>三保本月计划</div>
@@ -30,21 +31,21 @@
                <div class="support-plan-item" style="background:#FCAA29">
                  <div>延期</div>
                  <div class="plan-value-container">
                    <div class="plan-value">{{nextMonthMaintenancePlanNum}}</div>
                    <div class="plan-value">{{maintenanceExtensionNum}}</div>
                    <div>台</div>
                  </div>
                </div>
                <div class="support-plan-item" style="background:#F56C6C">
                  <div>超期</div>
                  <div class="plan-value-container">
                    <div class="plan-value">{{nextNextMonthMaintenancePlanNum}}</div>
                    <div class="plan-value">{{maintenanceOverdueNum}}</div>
                    <div>台</div>
                  </div>
                </div>
                <div class="support-plan-item" style="background:#D6BC52">
                  <div>下月计划</div>
                  <div class="plan-value-container">
                    <div class="plan-value">{{nextNextMonthMaintenancePlanNum}}</div>
                    <div class="plan-value">{{nextMonthMaintenancePlanNum}}</div>
                    <div>台</div>
                  </div>
                </div>
@@ -58,8 +59,12 @@
              </div>
            </div>
            <div style="flex:0.5;display: flex;justify-content: center">
              <dv-decoration-11 style="width:90%;height:60px;color: #ccc;font-size: 20px">二保计划</dv-decoration-11>
            <div style="display: flex;margin-top: 10px;justify-content: space-between;align-items: center;">
              <dv-decoration-11 style="width:45%;height:60px;font-size: 20px;color: #fff">二保计划</dv-decoration-11>
              <div
                style="flex:1;text-align:center;font-size: 25px;color: #9BD890;overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
                2024年4月1日大修
              </div>
            </div>
          </div>
        </dv-border-box-9>
@@ -136,10 +141,12 @@
        ],
        thisMonthMaintenancePlanNum: 0,
        thisMonthMaintenanceRealNum: 0,
        maintenanceExtensionNum: 0,
        maintenanceOverdueNum: 0,
        nextMonthMaintenancePlanNum: 0,
        nextNextMonthMaintenancePlanNum: 0,
        lineChart: '',
        lineChartData: [],
        lineChartData: {},
        gaugeChart1: '',
        gaugeChart2: '',
        gaugeChart3: '',
@@ -149,48 +156,7 @@
        gaugeChartData3: [],
        gaugeChartData4: [],
        barChart: '',
        barChartData: [
          {
            name: '2640221',
            value: 20
          },
          {
            name: '2640222',
            value: 40
          },
          {
            name: '2640223',
            value: 70
          },
          {
            name: '2640224',
            value: 30
          },
          {
            name: '2640225',
            value: 35
          },
          {
            name: '2640226',
            value: 80
          },
          {
            name: '2640227',
            value: 40
          },
          {
            name: '12640220',
            value: 60
          },
          {
            name: '12640221',
            value: 40
          },
          {
            name: '12640222',
            value: 35
          }
        ],
        barChartData: [],
        equipmentId: ''
      }
    },
@@ -209,6 +175,8 @@
        this.getWarrantyMalfunctionDataByApi()
        this.getRunningStateDataByApi()
        this.getMonthMaintenanceNumByApi()
        this.getLineChartDataByApi()
        this.getBarChartDataByApi()
      },
      /* 调用接口获取技术状态 */
@@ -241,15 +209,6 @@
          })
      },
      /* 调用接口获取设备运行状态 */
      getRunningStateDataByApi() {
        signageApi.getEquipmentStatusStatisticsApi(this.productionCode)
          .then(res => {
            if (res.success) this.runningStateData = res.result.list
            this.drawRunningStateChart(res.result.producitonId)
          })
      },
      /* 调用接口获取三保计划 */
      getMonthMaintenanceNumByApi() {
        signageApi.getThisMonthMaintenanceListApi(this.productionCode)
@@ -270,12 +229,45 @@
          })
      },
      /* 调用接口获取设备运行状态 */
      getRunningStateDataByApi() {
        signageApi.getEquipmentStatusStatisticsApi(this.productionCode)
          .then(res => {
            if (res.success) this.runningStateData = res.result.list
            this.drawRunningStateChart(res.result.producitonId)
          })
      },
      /* 调用接口获取前7天利用率 */
      getLineChartDataByApi() {
        signageApi.getEquipmentDayUtilizationStatisticsApi(this.productionCode)
          .then(res => {
            if (res.success) this.lineChartData = res.result
            this.drawLineChart()
          })
      },
      getBarChartDataByApi() {
        signageApi.getEquipmentOEEMonthStatisticsApi(this.productionCode)
          .then(res => {
            console.log('res=', res)
            if (res.success) {
              this.barChartData = res.result.map(item => {
                return {
                  name: item.equipmentId,
                  value: item.overallEquipmentEfficiency
                }
              })
            }
            this.drawBarChart()
          })
      },
      /* 绘制图表汇总方法 */
      drawCharts() {
        this.drawRunningStateChart()
        this.drawTechConditionChart()
        this.drawWarrantyMalfunctionChart()
        this.drawLineChart()
        this.drawGaugeChart()
        this.drawBarChart()
      },
@@ -288,7 +280,7 @@
            show: true, // 是否显示标题,默认为true
            text: '技术状态', // 主标题文本
            x: 'left', // 标题水平安放位置,可选值为'left'、'center'、'right'或具体的水平坐标值
            y: 'top', // 标题垂直安放位置,可选值为'top'、'bottom'、'center'或具体的垂直坐标值
            y: this.userType >= 3 ? '25' : 'top', // 标题垂直安放位置,可选值为'top'、'bottom'、'center'或具体的垂直坐标值
            textStyle: {
              // 主标题文本样式
              fontSize: 18,
@@ -481,7 +473,7 @@
          series: [
            {
              type: 'pie',
              // roseType: 'angle', // 玫瑰图
              roseType: 'angle', // 玫瑰图
              // selectedMode: "single",
              radius: ['35%', '55%'],
              center: ['50%', '50%'],
@@ -527,19 +519,19 @@
      drawLineChart() {
        this.lineChart = this.$echarts.init(document.getElementById('line_chart'))
        const newData = {
          xAxis: ['3月19日', '3月20日', '3月21日', '3月22日', '3月23日', '3月24日', '3月25日'],
          xAxis: this.lineChartData.dateList,
          yAxis: [
            {
              name: '利用率',
              value: [200, 600, 550, 360, 520, 520, 630]
              value: this.lineChartData.dataList.map(item => item.utilizationRate)
            },
            {
              name: '开动率',
              value: [230, 630, 440, 400, 740, 800, 600]
              value: this.lineChartData.dataList.map(item => item.startRate)
            },
            {
              name: '开机率',
              value: [900, 700, 400, 700, 800, 605, 730]
              value: this.lineChartData.dataList.map(item => item.openRate)
            }
          ],
          yAxisName: '前7天利用率(%)'
@@ -680,15 +672,6 @@
          // }
        }
        this.lineChart.setOption(option, true)
        // if (newData.xAxis.length <= 6) return
        // this.lineChartCarouselTime = setInterval(() => {
        //   this.barChartData.push(this.barChartData.shift())
        //   newData.xAxis.push(newData.xAxis.shift())
        //   newData.yAxis.forEach(item => item.value.push(item.value.shift()))
        //   this.$nextTick(() => {
        //     this.lineChart.setOption(option, true)
        //   })
        // }, 3000)
      },
      /* 绘制仪表盘图表 */
@@ -831,7 +814,7 @@
          height: 260,
          title: {
            show: true, // 是否显示标题,默认为true
            text: '上个月OEE', // 主标题文本
            text: '', // 主标题文本
            x: 'center', // 标题水平安放位置,可选值为'left'、'center'、'right'或具体的水平坐标值
            y: 'top', // 标题垂直安放位置,可选值为'top'、'bottom'、'center'或具体的垂直坐标值
            textStyle: {
@@ -987,12 +970,6 @@
      color: #fff;
      margin-bottom: 10px;
      .workshop-nav {
        width: 120px;
        height: 40px;
        font-size: 12px;
        cursor: pointer;
      }
    }
    .content-container {
@@ -1001,28 +978,17 @@
      justify-content: space-between;
      .left-col {
        .back-nav {
          width: 100px;
          height: 30px;
          color: #fff;
          position: absolute;
          top: 50px;
          left: 10px;
          cursor: pointer;
          z-index: 9999
        }
        .support-plan-container {
          width: 100%;
          display: flex;
          justify-content: space-around;
          flex-wrap: wrap;
          color: #fff;
          padding-top: 5px;
          padding-top: 20px;
          .support-plan-item {
            border-radius: 3px;
            width: 45%;
            width: 30%;
            padding: 5px 10px;
            margin-bottom: 10px;
@@ -1038,15 +1004,6 @@
              }
            }
          }
        }
      }
      .middle-col {
        .first-title {
          color: #00A8AC;
          font-size: 20px;
          text-align: center;
          font-weight: bold;
        }
      }
src/views/user/Login.vue
@@ -1,60 +1,75 @@
<template>
  <div class="main">
    <a-form-model
      class="user-layout-login"
      @keyup.enter.native="handleSubmit"
    >
      <a-tabs
        :activeKey="customActiveKey"
        :tabBarStyle="{ textAlign: 'center', borderBottom: 'unset' }"
        @change="handleTabClick"
      >
        <a-tab-pane
          key="tab1"
          tab="账号密码登录"
    <div style="display: flex;padding: 50px;">
      <div style="flex: 1;display: flex;align-items: center;justify-content: center;position: relative">
        <div class="top">
          <div class="header">
            <a href="/">
              <img src="~@/assets/lxzn.png" class="logo" alt="logo">
              <span class="title">MDC智慧车间</span>
            </a>
          </div>
        </div>
        <img src="@/assets/login.jpeg" width="60%">
      </div>
      <div style="width: 368px;margin: 30px 50px">
        <a-form-model
          class="user-layout-login"
          @keyup.enter.native="handleSubmit"
        >
          <login-account
            ref="alogin"
            @validateFail="validateFail"
            @success="requestSuccess"
            @fail="requestFailed"
          ></login-account>
        </a-tab-pane>
          <a-tabs
            :activeKey="customActiveKey"
            :tabBarStyle="{ textAlign: 'center', borderBottom: 'unset' }"
            @change="handleTabClick"
          >
            <a-tab-pane
              key="tab1"
              tab="账号密码登录"
            >
              <login-account
                ref="alogin"
                @validateFail="validateFail"
                @success="requestSuccess"
                @fail="requestFailed"
              ></login-account>
            </a-tab-pane>
        <!--<a-tab-pane key="tab2" tab="手机号登录">-->
        <!--<login-phone ref="plogin" @validateFail="validateFail" @success="requestSuccess" @fail="requestFailed"></login-phone>-->
        <!--</a-tab-pane>-->
      </a-tabs>
            <!--<a-tab-pane key="tab2" tab="手机号登录">-->
            <!--<login-phone ref="plogin" @validateFail="validateFail" @success="requestSuccess" @fail="requestFailed"></login-phone>-->
            <!--</a-tab-pane>-->
          </a-tabs>
      <a-form-model-item>
        <!--<a-checkbox @change="handleRememberMeChange" default-checked>自动登录</a-checkbox>-->
        <!--<router-link :to="{ name: 'alteration'}" class="forge-password" style="float: right;">-->
        <!--忘记密码-->
        <!--</router-link>-->
        <!--<router-link :to="{ name: 'register'}" class="forge-password" style="float: right;margin-right: 10px" >-->
        <!--注册账户-->
        <!--</router-link>-->
      </a-form-model-item>
          <a-form-model-item>
            <!--<a-checkbox @change="handleRememberMeChange" default-checked>自动登录</a-checkbox>-->
            <!--<router-link :to="{ name: 'alteration'}" class="forge-password" style="float: right;">-->
            <!--忘记密码-->
            <!--</router-link>-->
            <!--<router-link :to="{ name: 'register'}" class="forge-password" style="float: right;margin-right: 10px" >-->
            <!--注册账户-->
            <!--</router-link>-->
          </a-form-model-item>
      <a-form-item style="margin-top:24px">
        <a-button
          size="large"
          type="primary"
          htmlType="submit"
          class="login-button"
          :loading="loginBtn"
          @click.stop.prevent="handleSubmit"
          :disabled="loginBtn"
        >确定
        </a-button>
      </a-form-item>
          <a-form-item style="margin-top:24px">
            <a-button
              size="large"
              type="primary"
              htmlType="submit"
              class="login-button"
              :loading="loginBtn"
              @click.stop.prevent="handleSubmit"
              :disabled="loginBtn"
            >确定
            </a-button>
          </a-form-item>
      <a-form-model-item style="color: red">
        密级:内部&nbsp;&nbsp;&nbsp;&nbsp;警告:本系统禁止存储、处理、传输涉密信息
      </a-form-model-item>
          <a-form-model-item style="color: red">
            密级:内部&nbsp;&nbsp;&nbsp;&nbsp;警告:本系统禁止存储、处理、传输涉密信息
          </a-form-model-item>
    </a-form-model>
        </a-form-model>
      </div>
    </div>
    <!--<two-step-captcha v-if="requiredTwoStepCaptcha" :visible="stepCaptchaVisible" @success="stepCaptchaSuccess" @cancel="stepCaptchaCancel"></two-step-captcha>-->
    <login-select-tenant
      ref="loginSelect"
@@ -66,225 +81,274 @@
</template>
<script>
import Vue from 'vue'
import { ACCESS_TOKEN, ENCRYPTED_STRING } from '@/store/mutation-types'
// import ThirdLogin from './third/ThirdLogin'
import LoginSelectTenant from './LoginSelectTenant'
import TwoStepCaptcha from '@/components/tools/TwoStepCaptcha'
import { getEncryptedString } from '@/utils/encryption/aesEncrypt'
import { timeFix } from '@/utils/util'
  import Vue from 'vue'
  import { ACCESS_TOKEN, ENCRYPTED_STRING } from '@/store/mutation-types'
  // import ThirdLogin from './third/ThirdLogin'
  import LoginSelectTenant from './LoginSelectTenant'
  import TwoStepCaptcha from '@/components/tools/TwoStepCaptcha'
  import { getEncryptedString } from '@/utils/encryption/aesEncrypt'
  import { timeFix } from '@/utils/util'
import LoginAccount from './LoginAccount'
import LoginPhone from './LoginPhone'
import store from '@/store'
import { getAction } from '../../api/manage'
import UserPassword from '../../components/tools/UserPassword'
  import LoginAccount from './LoginAccount'
  import LoginPhone from './LoginPhone'
  import store from '@/store'
  import { getAction } from '../../api/manage'
  import UserPassword from '../../components/tools/UserPassword'
export default {
  components: {
    UserPassword,
    LoginSelectTenant,
    TwoStepCaptcha,
    // ThirdLogin,
    LoginAccount,
    LoginPhone,
    store
  },
  data() {
    return {
      customActiveKey: 'tab1',
      rememberMe: true,
      loginBtn: false,
      requiredTwoStepCaptcha: false,
      stepCaptchaVisible: false,
      encryptedString: {
        key: "",
        iv: "",
  export default {
    components: {
      UserPassword,
      LoginSelectTenant,
      TwoStepCaptcha,
      // ThirdLogin,
      LoginAccount,
      LoginPhone,
      store
    },
    data() {
      return {
        customActiveKey: 'tab1',
        rememberMe: true,
        loginBtn: false,
        requiredTwoStepCaptcha: false,
        stepCaptchaVisible: false,
        encryptedString: {
          key: '',
          iv: ''
        },
        url: {
          getPrimaryInfo: '/sys/sysAnnouncementSend/getPrimaryInfo'
        }
      }
    },
    created() {
      Vue.ls.remove(ACCESS_TOKEN)
      this.getRouterData()
      this.rememberMe = true
    },
    methods: {
      handleTabClick(key) {
        this.customActiveKey = key
      },
      url: {
        getPrimaryInfo: "/sys/sysAnnouncementSend/getPrimaryInfo"
      }
    }
  },
  created() {
    Vue.ls.remove(ACCESS_TOKEN)
    this.getRouterData();
    this.rememberMe = true
  },
  methods: {
    handleTabClick(key) {
      this.customActiveKey = key
    },
    handleRememberMeChange(e) {
      this.rememberMe = e.target.checked
    },
    /**跳转到登录页面的参数-账号获取*/
    getRouterData() {
      this.$nextTick(() => {
        let temp = this.$route.params.username || this.$route.query.username || ''
        if (temp) {
          this.$refs.alogin.acceptUsername(temp)
        }
      })
    },
    //登录
    handleSubmit() {
      this.loginBtn = true;
      if (this.customActiveKey === 'tab1') {
        // 使用账户密码登录
        this.$refs.alogin.handleLogin(this.rememberMe)
      } else {
        //手机号码登录
        this.$refs.plogin.handleLogin(this.rememberMe)
      }
    },
    // 校验失败
    validateFail() {
      this.loginBtn = false;
    },
    // 登录后台成功
    requestSuccess(loginResult) {
      // this.$router.push({ path: "/isps/userAnnouncement" }).catch(() => {
      //   console.log('登录跳转首页出错,这个错误从哪里来的')
      // })
      this.$router.push({ path: "/dashboard/analysis" }).catch(() => {
        console.log('登录跳转首页出错,这个错误从哪里来的')
      })
      this.$notification.success({
        message: '欢迎',
        description: `${timeFix()},欢迎回来`,
      });
      var userId = store.getters.userInfo.id;
      let that = this;
      getAction(this.url.getPrimaryInfo, { userId: userId }).then(res => {
        if (res.success) {
          for (var i = 0; i < res.result.length; i++) {
            that.$notification.success({
              message: '最新未读消息【' + res.result[i].msgCategory + '】',
              description: res.result[i].msgContent,
              duration: 60,
              icon: <a-icon type="exclamation-circle" style="color:red" />,
            });
      handleRememberMeChange(e) {
        this.rememberMe = e.target.checked
      },
      /**跳转到登录页面的参数-账号获取*/
      getRouterData() {
        this.$nextTick(() => {
          let temp = this.$route.params.username || this.$route.query.username || ''
          if (temp) {
            this.$refs.alogin.acceptUsername(temp)
          }
        })
      },
      //登录
      handleSubmit() {
        this.loginBtn = true
        if (this.customActiveKey === 'tab1') {
          // 使用账户密码登录
          this.$refs.alogin.handleLogin(this.rememberMe)
        } else {
          //手机号码登录
          this.$refs.plogin.handleLogin(this.rememberMe)
        }
      })
      // this.$refs.loginSelect.show(loginResult)
    },
    //登录后台失败
    requestFailed(err,username) {
      let description = ((err.response || {}).data || {}).message || err.message || "请求出现错误,请稍后再试"
      if(err.code!==5001&&err.code!==5002){
        this.$notification['error']({
          message: '登录失败',
          description: description,
          duration: 4,
        });
      }else{
        this.$notification['warning']({
          message: '提示',
          description: description,
          duration:1,
          onClose:()=>{
            console.log('err',err)
            this.$refs.userPassword.show(username)
          }
        });
      }
      //账户密码登录错误后更新验证码
      // if (this.customActiveKey === 'tab1' && description.indexOf('密码错误') > 0) {
      //   this.$refs.alogin.handleChangeCheckCode()
      // }
      this.loginBtn = false;
    },
    loginSelectOk() {
      this.loginSuccess()
    },
    //登录成功
    loginSuccess() {
      this.$router.push({ path: "/isps/userAnnouncement" }).catch(() => {
        console.log('登录跳转首页出错,这个错误从哪里来的')
      })
      this.$notification.success({
        message: '欢迎',
        description: `${timeFix()},欢迎回来`,
      });
    },
    stepCaptchaSuccess() {
      this.loginSuccess()
    },
    stepCaptchaCancel() {
      this.Logout().then(() => {
      },
      // 校验失败
      validateFail() {
        this.loginBtn = false
        this.stepCaptchaVisible = false
      })
    },
    //获取密码加密规则
    getEncrypte() {
      var encryptedString = Vue.ls.get(ENCRYPTED_STRING);
      if (encryptedString == null) {
        getEncryptedString().then((data) => {
          this.encryptedString = data
        });
      } else {
        this.encryptedString = encryptedString;
      },
      // 登录后台成功
      requestSuccess(loginResult) {
        // this.$router.push({ path: "/isps/userAnnouncement" }).catch(() => {
        //   console.log('登录跳转首页出错,这个错误从哪里来的')
        // })
        this.$router.push({ path: '/dashboard/analysis' }).catch(() => {
          console.log('登录跳转首页出错,这个错误从哪里来的')
        })
        this.$notification.success({
          message: '欢迎',
          description: `${timeFix()},欢迎回来`
        })
        var userId = store.getters.userInfo.id
        let that = this
        getAction(this.url.getPrimaryInfo, { userId: userId }).then(res => {
          if (res.success) {
            for (var i = 0; i < res.result.length; i++) {
              that.$notification.success({
                message: '最新未读消息【' + res.result[i].msgCategory + '】',
                description: res.result[i].msgContent,
                duration: 60,
                icon: <a-icon type = 'exclamation-circle'style = 'color:red' / >,
            })
            }
          }
        })
        // this.$refs.loginSelect.show(loginResult)
      },
      //登录后台失败
      requestFailed(err, username) {
        let description = ((err.response || {}).data || {}).message || err.message || '请求出现错误,请稍后再试'
        if (err.code !== 5001 && err.code !== 5002) {
          this.$notification['error']({
            message: '登录失败',
            description: description,
            duration: 4
          })
        } else {
          this.$notification['warning']({
            message: '提示',
            description: description,
            duration: 1,
            onClose: () => {
              console.log('err', err)
              this.$refs.userPassword.show(username)
            }
          })
        }
        //账户密码登录错误后更新验证码
        // if (this.customActiveKey === 'tab1' && description.indexOf('密码错误') > 0) {
        //   this.$refs.alogin.handleChangeCheckCode()
        // }
        this.loginBtn = false
      },
      loginSelectOk() {
        this.loginSuccess()
      },
      //登录成功
      loginSuccess() {
        this.$router.push({ path: '/isps/userAnnouncement' }).catch(() => {
          console.log('登录跳转首页出错,这个错误从哪里来的')
        })
        this.$notification.success({
          message: '欢迎',
          description: `${timeFix()},欢迎回来`
        })
      },
      stepCaptchaSuccess() {
        this.loginSuccess()
      },
      stepCaptchaCancel() {
        this.Logout().then(() => {
          this.loginBtn = false
          this.stepCaptchaVisible = false
        })
      },
      //获取密码加密规则
      getEncrypte() {
        var encryptedString = Vue.ls.get(ENCRYPTED_STRING)
        if (encryptedString == null) {
          getEncryptedString().then((data) => {
            this.encryptedString = data
          })
        } else {
          this.encryptedString = encryptedString
        }
      }
    }
  }
}
</script>
<style lang="less" scoped>
.user-layout-login {
  label {
    font-size: 14px;
  }
  .getCaptcha {
    display: block;
    width: 100%;
    height: 40px;
  }
  .user-layout-login {
    label {
      font-size: 14px;
    }
    .getCaptcha {
      display: block;
      width: 100%;
      height: 40px;
    }
  .forge-password {
    font-size: 14px;
  }
    .forge-password {
      font-size: 14px;
    }
  button.login-button {
    padding: 0 15px;
    font-size: 16px;
    height: 40px;
    width: 100%;
  }
    button.login-button {
      padding: 0 15px;
      font-size: 16px;
      height: 40px;
      width: 100%;
    }
  .user-login-other {
    text-align: left;
    margin-top: 24px;
    line-height: 22px;
    .user-login-other {
      text-align: left;
      margin-top: 24px;
      line-height: 22px;
    .item-icon {
      font-size: 24px;
      color: rgba(0, 0, 0, 0.2);
      margin-left: 16px;
      vertical-align: middle;
      cursor: pointer;
      transition: color 0.3s;
      .item-icon {
        font-size: 24px;
        color: rgba(0, 0, 0, 0.2);
        margin-left: 16px;
        vertical-align: middle;
        cursor: pointer;
        transition: color 0.3s;
      &:hover {
        color: #1890ff;
        &:hover {
          color: #1890ff;
        }
      }
      .register {
        float: right;
      }
    }
  }
    .register {
      float: right;
  /deep/ .ant-tabs-tab-active.ant-tabs-tab {
    font-size: 25px;
  }
  .top {
    text-align: center;
    position: absolute;
    top: 45px;
    .header {
      height: 44px;
      line-height: 44px;
      .badge {
        position: absolute;
        display: inline-block;
        line-height: 1;
        vertical-align: middle;
        margin-left: -12px;
        margin-top: -10px;
        opacity: 0.8;
      }
      .logo {
        height: 44px;
        vertical-align: top;
        margin-right: 10px;
        border-style: none;
      }
      .title {
        font-size: 30px;
        color: #000;
        font-family: "Chinese Quote", -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
        font-weight: 600;
        position: relative;
        top: 2px;
      }
    }
    .desc {
      font-size: 14px;
      color: rgba(0, 0, 0, 0.45);
      margin-top: 12px;
      margin-bottom: 40px;
    }
  }
}
</style>
<style>
.valid-error .ant-select-selection__placeholder {
  color: #f5222d;
}
  .valid-error .ant-select-selection__placeholder {
    color: #f5222d;
  }
</style>