heyujie
2021-04-29 18dfd3d183e68db6306b34500813cca8f8c689c9
系统维护和系统设置
12个文件已添加
8个文件已修改
3493 ■■■■■ 已修改文件
public/apps.json 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/subComponents/CardItem.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/humanPoseTrack/index/App.vue 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/humanPoseTrack/index/main.ts 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/humanPoseTrack/index/mixins.ts 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/maintain/components/CloudNode.vue 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/maintain/components/switchBar.vue 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/maintain/index/App.vue 628 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/maintain/index/main.ts 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/maintain/views/backUp.vue 326 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/maintain/views/generalSettings.vue 456 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/maintain/views/restartSettings.vue 384 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/maintain/views/systemClean.vue 215 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/maintain/views/updateSettings.vue 478 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/systemSettings/index/App.vue 373 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/systemSettings/views/NetSettings.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/systemSettings/views/clusterManagement.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/systemSettings/views/generalSettings.vue 221 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/systemSettings/views/keyboardLanguage.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/vindicate/index/App.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/apps.json
@@ -232,6 +232,53 @@
      "progressMsg": ""
    },
    {
      "id": "ee64fe23-7631-4ef9-9aca-ea09673693bf",
      "name": "系统维护(新版)",
      "package": "maintain",
      "type": "2",
      "url": "/view/maintain/",
      "title": "系统维护(新版)",
      "width": 1200,
      "height": 650,
      "iconBlob": "",
      "icon": "../../images/app-mid/vindicate.png",
      "version": "1.0.0",
      "create_time": "2020-10-09 14:00:11",
      "create_by": "",
      "update_time": "",
      "update_by": "",
      "isDelete": 0,
      "isDefault": true,
      "remoteVersion": "",
      "installed": true,
      "isUpgrade": false,
      "progressMsg": ""
    },
    {
      "id": "ee64fe23-7631-4ef9-9aca-ea09673693df",
      "name": "人体骨骼跟踪",
      "package": "humanPoseTrack",
      "type": "2",
      "url": "/view/humanPoseTrack/",
      "title": "人体骨骼跟踪",
      "width": 1200,
      "height": 650,
      "iconBlob": "",
      "icon": "../../images/app-mid/vindicate.png",
      "version": "1.0.0",
      "create_time": "2020-10-09 14:00:11",
      "create_by": "",
      "update_time": "",
      "update_by": "",
      "isDelete": 0,
      "isDefault": true,
      "remoteVersion": "",
      "installed": true,
      "isUpgrade": false,
      "progressMsg": ""
    },
    {
      "id": "1e51abbf-a4dd-4cf9-9eee-2149102d6d62",
      "name": "比对库管理",
      "package": "library",
src/components/subComponents/CardItem.vue
@@ -295,7 +295,7 @@
    <!-- 没有底库,非比对,普通模式 一定有targetInfo,并且targetInfo个数为1-->
    <div
      v-else-if="data.targetInfo !== null && data.targetInfo[0].picSmUrl !== '' && data.targetInfo.length == 1"
      v-else-if="data.targetInfo !== null && data.targetInfo[0].picSmUrl !== ''"
      class="s-card-right-signal"
    >
      <div
src/pages/humanPoseTrack/index/App.vue
New file
@@ -0,0 +1,82 @@
<template>
  <div class="column">
  </div>
</template>
<script>
export default {
  name: "VideoManage",
  components: {},
  data() {
    return {
    };
  },
  mounted() {
    // debugger
    let arr=  window.location.host.split(":")
    const newURL = 'http://'+ arr[0]+":8082"
    window.location.href  = newURL;
    this.screenHeight = document.documentElement.clientHeight;
    window.onresize = () => {
      return (() => {
        this.screenHeight = document.documentElement.clientHeight;
      })();
    };
    // this.$refs[`item_${0}`][0].style.backgroundColor = "#353A8A";
  },
  methods: {
  },
  directives: {
    drag(el, binding) {
      const dialogHeaderEl = el.querySelector(".el-dialog__header");
      const dragDom = el.querySelector(".el-dialog");
      dialogHeaderEl.style.cursor = "move";
      const sty =
        dragDom.currentStyle || window.getComputedStyle(dragDom, null);
      dialogHeaderEl.onmousedown = (e) => {
        const disX = e.clientX - dialogHeaderEl.offsetLeft;
        const disY = e.clientY - dialogHeaderEl.offsetTop;
        let styL, styT;
        if (sty.left.includes("%")) {
          styL =
            +document.body.clientWidth * (+sty.left.replace(/\%/g, "") / 100);
          styT =
            +document.body.clientHeight * (+sty.top.replace(/\%/g, "") / 100);
        } else {
          styL = +sty.left.replace(/\px/g, "");
          styT = +sty.top.replace(/\px/g, "");
        }
        document.onmousemove = function (e) {
          const l = e.clientX - disX;
          const t = e.clientY - disY;
          dragDom.style.left = `${l + styL}px`;
          dragDom.style.top = `${t + styT}px`;
        };
        document.onmouseup = function (e) {
          document.onmousemove = null;
          document.onmouseup = null;
        };
      };
    },
  },
  watch: {
  },
};
</script>
<style lang="scss" scoped>
.column {
  height: 100%;
  display: flex;
  flex-direction: row;
  flex: 1;
  flex-basis: auto;
  box-sizing: border-box;
}
</style>
src/pages/humanPoseTrack/index/main.ts
New file
@@ -0,0 +1,30 @@
import Vue from "vue";
import App from './App.vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import "@/assets/css/element-variables.scss";
import ToggleButton from 'vue-js-toggle-button';
import VueAwesomeSwiper from "vue-awesome-swiper";
import "swiper/dist/css/swiper.css";
import * as VueWindow from "@hscmap/vue-window";
import moment from 'moment';
import Mixin from "./mixins";
Vue.prototype.$moment = moment;
Vue.use(ElementUI);
Vue.use(ToggleButton);
Vue.use(VueAwesomeSwiper as any);
Vue.use(VueWindow);
Vue.filter('moment', function (value, formatString) {
  formatString = formatString || 'YYYY-MM-DD HH:mm:ss';
  return moment(value).format(formatString);
});
Vue.mixin(Mixin);
new Vue({
  el: '#app',
  render: h => h(App)
})
src/pages/humanPoseTrack/index/mixins.ts
New file
@@ -0,0 +1,25 @@
import TreeDataPool from "@/Pool/TreeData";
import DataStackPool from "@/Pool/dataStack"
import DataPool from "@/Pool/PollData"
import VideoManageData from "@/Pool/VideoManageData";
import TaskMange from '@/Pool/TaskMange'
/* eslint-disable */
const onlyTreeDataPool = new TreeDataPool
const onlyDataStack = new DataStackPool
const onlyDataPool = new DataPool
const onlyVideoManageData = new VideoManageData
const onlyTaskMange = new TaskMange
const mixin = {
  data() {
    return {
      TreeDataPool: onlyTreeDataPool,
      DataStackPool: onlyDataStack,
      VideoManageData: onlyVideoManageData,
      TaskMange: onlyTaskMange,
      PollData: onlyDataPool
    };
  },
};
export default mixin;
src/pages/maintain/components/CloudNode.vue
New file
@@ -0,0 +1,149 @@
<template>
  <div class="cloud">
    <div class="inner">
      <div class="rect">
        <serfDiagram
          ref="inside-nodes"
          :members="insideNodes"
          :agent="agentName"
          :sizeX="insideSizeX"
          :sizeY="insideSizeY"
          :startX="insideStartX"
          :isShowHover="true"
          class="inside-nodes"
        ></serfDiagram>
      </div>
    </div>
    <div class="outer" v-if="outsideNodes.length">
      <serfDiagram
        ref="outer-nodes"
        :members="outsideNodes"
        :agent="agentName"
        :sizeX="280"
        :sizeY="370"
        :startX="60"
        class="outer-nodes"
      ></serfDiagram>
    </div>
  </div>
</template>
<script>
import SerfDiagram from "@/components/serfDiagram";
export default {
  name: "cloudNode",
  props: {
    nodes: Array,
  },
  components: {
    SerfDiagram,
  },
  data() {
    return {
      agentName: "",
      nodeIcons: [],
      //insideNodes: [],
      BaseWidth: 150,
      BaseHeight: 70,
      minWidth: 0,
      minHeight: 0,
    };
  },
  mounted() {
    console.log(this.nodes);
    //this.getInsideNodes();
  },
  methods: {
    getRandom(index) {
      if (index % 2 == 0) {
        return Math.random() * 20;
      } else {
        return Math.random() * 50;
      }
    },
    getInsideNodes() {
      let arr = this.nodes.filter(
        (item) => item.hardwareType == "01" || item.hardwareType == "02"
      );
      let len = arr.length;
      let lefts = [];
      let tops = [];
      this.insideNodes = arr.map((item, index) => {
        lefts.push((20 - len) * (index + 1) + this.getRandom(index));
        tops.push(30 * (index + 1));
        return {
          l: 10 + this.getRandom(index),
          t: 30 * (index + 1),
          nodeName: item.nodeName,
          id: item.id,
          workType: item.workType,
        };
      });
      this.minWidth = Math.max(...lefts) - Math.min(...lefts);
      this.minHeight = Math.max(...tops) - Math.min(...tops);
      console.log("w,h", this.minWidth, this.minHeight);
    },
  },
  computed: {
    cloudPic() {
      return "/images/settings/cloud.png";
    },
    insideNodes() {
      return this.nodes.filter(
        (item) => item.hardwareType == "01" || item.hardwareType == "02"
      );
    },
    insideSizeX() {
      return 160 + 200 * 0.2 * this.insideNodes.length <= 400
        ? 160 + 200 * 0.2 * this.insideNodes.length
        : 400;
    },
    insideSizeY() {
      return 140 + 200 * 0.2 * this.insideNodes.length <= 380
        ? 140 + 200 * 0.2 * this.insideNodes.length
        : 380;
    },
    insideStartX() {
      return this.insideSizeX / 3;
    },
    outsideNodes() {
      return this.nodes.filter((item) => item.hardwareType == "03");
    },
  },
};
</script>
<style lang="scss">
.cloud {
  width: 100%;
  display: flex;
  .inner {
    background: url("/images/settings/easy-cloud.png") no-repeat;
    background-size: 100%;
    margin-top: -55px;
    margin-left: 55px;
    .rect {
      position: relative;
      margin: 130px 100px 70px;
      .node {
        position: absolute;
        .node-icon {
          width: 40px;
          height: 40px;
        }
        .node-name {
          font-size: 14px;
          color: #333;
        }
      }
    }
  }
  .outer {
    width: 40%;
    position: relative;
    text-align: left;
    .node {
      position: absolute;
    }
  }
}
</style>
src/pages/maintain/components/switchBar.vue
New file
@@ -0,0 +1,42 @@
<template>
  <div class="switch-bar">
    <div class="name">{{ barName }}</div>
    <el-switch
      v-model="value"
      active-color="rgba(61, 104, 225, 1)"
      @change="switchChange"
    >
    </el-switch>
  </div>
</template>
<script>
export default {
  data() {
    return {
      // value: false,
    };
  },
  props: ["barName","value"],
  methods: {
    switchChange(val) {
      this.$emit("switchChange",val);
    },
  },
};
</script>
<style lang="scss">
.switch-bar {
  display: flex;
  align-items: center;
  height: 50px;
  padding: 0 25px;
  background-color: rgba(248, 248, 248, 1);
  justify-content: space-between;
  border-radius: 12px;
  margin-bottom: 10px;
  .name {
    font-size: 14px;
  }
}
</style>
src/pages/maintain/index/App.vue
New file
@@ -0,0 +1,628 @@
<template>
  <div class="container">
    <div class="container-left">
      <div
        class="left-card"
        v-for="(item, index) in menuArr"
        :key="index"
        @click="openMenu(item, index)"
      >
        <span class="icon iconfont">&#xe646;</span>
        <span class="card-text">{{ item.name }}</span>
      </div>
    </div>
    <systemClean
      v-if="activePage == '系统清理'"
      style="width: 100%"
    ></systemClean>
    <updateSettings
      v-if="activePage == '更新设置'"
      style="width: 100%"
    ></updateSettings>
    <back-up
      v-if="activePage == '备份还原'"
      style="width: 100%"
    ></back-up>
    <restartSettings
      v-if="activePage == '重启设置'"
      style="width: 100%"
    ></restartSettings>
  </div>
</template>
<script>
import {
  getClockInfo,
  saveClockInfo,
  testNTPserver,
} from "@/api/system";
import switchBar from "../components/switchBar";
import ipInput from "@/components/subComponents/IPInput";
import systemClean from "../views/systemClean";
import updateSettings from "../views/updateSettings";
import BackUp from "../views/backUp";
import restartSettings from "../views/restartSettings";
export default {
  name: "settings",
  components: {
    switchBar,
    ipInput,
    systemClean,
    updateSettings,
    BackUp,
    restartSettings,
  },
  data() {
    return {
      browserTimer: null,
      menuArr: [
        { name: "更新设置" },
        { name: "备份还原" },
        { name: "系统清理" },
        { name: "重启设置" },
      ],
      jpgArr: [{}, {}, {}, {}, {}, {}, {}, {}, {}],
      activePage: "更新设置",
      activeIndex: 0,
      clockTimer: null,
    };
  },
  beforeDestroy() {
    clearTimeout(this.clockTimer);
    clearInterval(this.browserTimer);
  },
  mounted() {
    const s = document.getElementsByClassName("left-card")[0];
    s.style.backgroundColor = "rgba(61, 104, 225, 1)";
    s.style.color = "#fff";
  },
  methods: {
    openMenu(item, i) {
      const old = document.getElementsByClassName("left-card")[
        this.activeIndex
      ];
      old.style.backgroundColor = "initial";
      old.style.color = "rgba(81, 81, 81, 1)";
      this.activePage = item.name;
      this.activeIndex = i;
      const s = document.getElementsByClassName("left-card")[i];
      s.style.backgroundColor = "rgba(61, 104, 225, 1)";
      s.style.color = "#fff";
    },
  },
};
</script>
<style lang="scss">
.container {
  height: 100%;
  display: flex;
  flex-direction: row;
  flex: 1;
  flex-basis: auto;
  box-sizing: border-box;
  .container-left {
    height: 100%;
    width: 210px;
    overflow: auto;
    box-sizing: border-box;
    flex-shrink: 0;
    padding: 10px;
    border-right: 5px solid rgba(248, 248, 248, 1);
    box-sizing: border-box;
    .left-card {
      height: 55px;
      cursor: pointer;
      border-radius: 12px;
      margin-bottom: 10px;
      display: flex;
      align-items: center;
      .iconfont {
        margin-left: 25px;
        margin-right: 10px;
        font-size: 24px;
      }
      .card-text {
        font-size: 16px;
      }
    }
    .left-card:hover {
      background-color: rgba(61, 104, 225, 1);
      color: #fff;
    }
  }
  .container-center {
    height: 100%;
    width: 280px;
    overflow: auto;
    flex-shrink: 0;
    padding: 10px;
    border-right: 5px solid rgba(248, 248, 248, 1);
    box-sizing: border-box;
    .account-left {
      .add-account {
        color: rgba(61, 104, 225, 1);
        margin-top: 50px;
        .iconfont {
          cursor: pointer;
          font-size: 32px;
        }
      }
      .account-card {
        height: 50px;
        background-color: rgba(248, 248, 248, 1);
        margin-bottom: 10px;
        display: flex;
        align-items: center;
        padding: 0 20px;
        box-sizing: border-box;
        border-radius: 10px;
        cursor: pointer;
        .touxiang {
          height: 35px;
          width: 35px;
          background-color: bisque;
          border-radius: 17.5px;
        }
        .user-name {
          margin-left: 10px;
          font-size: 14px;
        }
      }
    }
    .datetime-left {
      .time-card {
        height: 105px;
        background-color: rgba(248, 248, 248, 1);
        margin-bottom: 30px;
        border-radius: 10px;
        .head {
          height: 30px;
          line-height: 30px;
          text-align: left;
          box-sizing: border-box;
          padding: 0 10px;
          font-size: 14px;
          .icon {
            margin-right: 5px;
            color: rgba(61, 104, 225, 1);
          }
        }
        .time-main {
          height: 42px;
          line-height: 42px;
          font-family: Consolas;
          font-size: 36px;
        }
        .date-bot {
          height: 25px;
          font-size: 14px;
          line-height: 25px;
          color: #868686;
          display: flex;
          justify-content: space-evenly;
        }
      }
      .line {
        display: flex;
        align-items: center;
        height: 50px;
        padding: 0 25px;
        background-color: rgba(248, 248, 248, 1);
        justify-content: space-between;
        border-radius: 12px;
        margin-bottom: 10px;
        .name {
          font-size: 14px;
        }
      }
    }
  }
  .container-right {
    flex: 1;
    flex-basis: auto;
    overflow: auto;
    box-sizing: border-box;
    position: relative;
    padding: 20px 40px;
    .account-right {
      .account-content {
        .content-top {
          height: 120px;
          width: 350px;
          margin: 0 auto;
          display: flex;
          align-items: center;
          justify-content: center;
          margin-bottom: 20px;
          .touxiang-big {
            width: 100px;
            height: 100px;
            background-color: bisque;
            border-radius: 50px;
          }
          .user-desc {
            height: 100px;
            display: flex;
            flex-direction: column;
            align-items: baseline;
            min-width: 200px;
            .username {
              margin: 5px 15px;
              height: 30px;
              line-height: 30px;
              width: 90px;
              text-align: left;
              font-size: 15px;
              display: flex;
              align-items: center;
            }
            .nickname {
              margin: 5px 15px;
              font-size: 14px;
              .input-nick {
                width: 50px;
                margin-right: 5px;
              }
              .iconfont {
                font-size: 14px;
                margin-left: 5px;
              }
            }
          }
        }
        .list-btn {
          display: flex;
          flex-direction: column;
          align-items: center;
          .item-btn {
            width: 500px;
            height: 45px;
            background-color: #f0f0f0;
            margin-bottom: 15px;
            border-radius: 10px;
            line-height: 45px;
            font-size: 15px;
            cursor: pointer;
          }
          .item-btn:hover {
            color: rgba(255, 153, 102, 1);
          }
        }
      }
      .title {
        height: 30px;
        line-height: 30px;
        /* background-color: aliceblue; */
        margin-bottom: 10px;
        font-size: 16px;
        font-weight: 600;
      }
      .change-pw {
        .p-title {
          text-align: left;
          font-size: 15px;
          margin-top: 5px;
        }
      }
      .el-form-item {
        margin-bottom: 0;
        .el-input__inner {
          background-color: rgba(240, 240, 240, 1);
          border: none;
          border-radius: 12px;
          height: 45px;
          padding: 0 20px;
          font-size: 15px;
        }
        .el-input__clear {
          color: dimgray;
          font-size: 17px;
          line-height: 45px;
        }
        .el-input__suffix {
          right: 1px;
          top: -0.5px;
          width: 45px;
          // background-color: rgba(61, 104, 225, 1);
          /* color: white; */
          border-radius: 12px;
        }
      }
      .permission {
        .line {
          display: flex;
          align-items: center;
          height: 50px;
          padding: 0 25px;
          background-color: rgba(248, 248, 248, 1);
          justify-content: space-between;
          border-radius: 12px;
          margin-bottom: 10px;
          .name {
            font-size: 14px;
          }
        }
      }
      .add-account-page {
        // background-color: lightcyan;
        // padding: 10px 50px;
        .upload-group {
          height: 120px;
          width: 350px;
          margin: 0 auto;
          overflow: hidden;
          .upload-jpg {
            height: 50px;
            width: 50px;
            float: left;
            margin: 0 10px;
            background-color: antiquewhite;
            margin-bottom: 20px;
            border-radius: 25px;
          }
        }
        .fill-group {
          .p-title {
            text-align: left;
          }
        }
      }
    }
    .datetime-right {
      .el-form-item.is-required:not(.is-no-asterisk)
        > .el-form-item__label:before,
      .el-form-item.is-required:not(.is-no-asterisk)
        .el-form-item__label-wrap
        > .el-form-item__label:before {
        display: none;
      }
      .el-form-item {
        margin-bottom: 10px;
        height: 50px;
        background: #f8f8f8;
        padding: 4px 20px;
        -webkit-box-sizing: border-box;
        box-sizing: border-box;
        border-radius: 10px;
        .el-form-item__label {
          text-align: left;
          line-height: 42px;
        }
      }
      .el-form-item__content {
        line-height: 40px;
        position: relative;
        font-size: 14px;
      }
      .ip-input-container {
        max-width: none !important;
      }
      .ntp-time {
        .right {
          display: flex;
          align-items: baseline;
          .el-input-number--small {
            width: 100%;
          }
          .el-button--text {
            margin-left: 10px;
            text-decoration: underline;
          }
        }
        .ntp-bar {
          height: 40px;
          background-color: rgba(248, 248, 248, 1);
          display: flex;
          align-items: center;
          justify-content: space-between;
          padding: 0 10px;
          border-radius: 10px;
          margin-bottom: 10px;
          .title {
            min-width: 70px;
          }
          .input-area {
            width: 450px;
            height: 30px;
            background-color: rgba(240, 240, 240, 1);
            border-radius: 10px;
            line-height: 30px;
            font-size: 14px;
          }
        }
        .int-bar {
          height: 40px;
          background-color: rgba(248, 248, 248, 1);
          display: flex;
          align-items: center;
          justify-content: space-between;
          padding: 0 10px;
          border-radius: 10px;
          margin-bottom: 10px;
          .title {
            min-width: 130px;
          }
          .right {
            width: 450px;
            display: flex;
            align-items: center;
            height: 30px;
            .input-area {
              // width: 410px;
              background-color: rgba(240, 240, 240, 1);
              border-radius: 10px;
              line-height: 30px;
              width: -webkit-fill-available;
              font-size: 14px;
            }
            .test {
              width: 40px;
            }
          }
        }
      }
      .manual-time {
        .clock-wrap {
          height: 75px;
          background-color: #f8f8f8;
          display: flex;
          justify-content: center;
          align-items: center;
          margin-bottom: 10px;
          border-radius: 10px;
          .clock {
            display: flex;
            align-items: center;
            height: 90px;
            justify-content: space-evenly;
            .iconfont {
              cursor: pointer;
              color: rgba(134, 134, 134, 1);
            }
            .iconfont:hover {
              background-color: gainsboro;
            }
            .hour {
              background-color: rgba(240, 240, 240, 1);
              display: flex;
              align-items: center;
              width: 100px;
              height: 50px;
              justify-content: space-evenly;
              border-radius: 10px;
            }
            .dnum {
              width: 40px;
              height: 40px;
              line-height: 40px;
              font-size: 34px;
              font-family: Consolas;
              display: flex;
              align-items: center;
              .input-box {
                width: inherit;
                border: none;
                border-radius: 5px;
                height: 35px;
                font-size: 28px;
                text-align: center;
              }
              .input-box:focus {
                outline: none;
              }
            }
            .control {
              width: 20px;
              .fanzhuan {
                display: inline-block;
                -moz-transform: scaleY(-1);
                -webkit-transform: scaleY(-1);
                -o-transform: scaleY(-1);
                transform: scaleY(-1);
              }
            }
            .sep {
              font-family: Consolas;
              width: 40px;
              font-size: 34px;
              height: 40px;
              line-height: 40px;
            }
            .mins {
              background-color: #f0f0f0;
              display: flex;
              align-items: center;
              width: 110px;
              height: 50px;
              justify-content: space-evenly;
              border-radius: 10px;
            }
          }
        }
        .adjust-bar {
          display: flex;
          justify-content: space-between;
          align-items: center;
          margin-bottom: 10px;
          border-radius: 10px;
          height: 50px;
          background-color: rgba(248, 248, 248, 1);
          .middle {
            font-size: 14px;
          }
          .input-box {
            width: 80px;
            border: none;
            border-radius: 5px;
            height: 25px;
            font-size: 18px;
            text-align: center;
          }
          .input-box:focus {
            outline: none;
          }
          .minus {
            width: 50px;
            height: 50px;
            background-color: #f0f0f0;
            font-size: 35px;
            border-radius: 10px;
            cursor: pointer;
            line-height: 50px;
            color: rgba(134, 134, 134, 1);
          }
          .plus {
            width: 50px;
            height: 50px;
            cursor: pointer;
            background-color: #f0f0f0;
            font-size: 35px;
            border-radius: 10px;
            line-height: 50px;
            color: rgba(134, 134, 134, 1);
          }
        }
      }
    }
    .btns {
      display: flex;
      justify-content: space-between;
      margin-top: 20px;
      .cancel {
        height: 40px;
        width: 48%;
        cursor: pointer;
        border-radius: 8px;
        background-color: rgba(240, 240, 240, 1);
        line-height: 40px;
        font-size: 14px;
      }
      .ok {
        height: 40px;
        width: 48%;
        cursor: pointer;
        border-radius: 8px;
        background-color: rgba(61, 104, 225, 1);
        color: #fff;
        line-height: 40px;
        font-size: 14px;
      }
    }
  }
}
</style>
src/pages/maintain/index/main.ts
New file
@@ -0,0 +1,16 @@
import Vue from 'vue';
import App from './App.vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import "@/assets/css/element-variables.scss";
import moment from 'moment';
Vue.use(ElementUI)
Vue.prototype.$moment = moment;
new Vue({
  el: '#app',
  render: h => h(App)
})
src/pages/maintain/views/backUp.vue
New file
@@ -0,0 +1,326 @@
<template>
  <div class="all">
    <div class="backup-content">
      <div class="backup-center" ref="left">
        <div class="menu-item" @click="openRight(0)">
          <div class="con">
            <span class="icon iconfont">&#xe646;</span>
            <span class="menu-text">自动备份设置</span>
          </div>
        </div>
        <div class="menu-item" @click="openRight(1)">
          <div class="con">
            <span class="icon iconfont">&#xe646;</span>
            <span class="menu-text">从备份中恢复</span>
          </div>
        </div>
      </div>
      <div class="backup-right">
        <div class="auto" v-if="activePage == 0">
          <div class="bar">
            <div class="name">自动备份</div>
            <el-switch
              v-model="isBackUp"
              active-color="rgba(61, 104, 225, 1)"
              @change="switchChange"
            >
            </el-switch>
          </div>
          <div class="bar">
            <div class="name">备份目录</div>
            <input type="file" id="file_input" webkitdirectory directory />
          </div>
          <div class="bar">
            <div class="name">备份间隔 / 天</div>
            <el-input
              v-model="interval"
              :placeholder="'请输入天数'"
              @change="handleChange"
              size="small"
            ></el-input>
            <!-- :controls="false" -->
          </div>
          <div class="bar">
            <div class="name">备份数据保存时间 / 天</div>
            <el-input
              v-model="lifeSpan"
              placeholder="请输入天数"
              @change="handleChange"
              size="small"
            ></el-input>
          </div>
          <div class="bar">
            <div class="name">自动备份</div>
            <el-button type="primary" size="small" @click="backUpNow"
              >立即备份</el-button
            >
          </div>
        </div>
        <div class="recover" v-if="activePage == 1">
          <div class="title">显示备份的文件范围:{{ 5 }}</div>
          <div class="table-head">
            <span class="line1">自动备份时间</span>
            <span class="line1">备份文件名称</span>
            <span class="line2">操作</span>
          </div>
          <div class="bar" v-for="(item, i) in fileList" :key="i">
            <span class="time">{{ item.time }}</span>
            <span class="time">{{ item.name }}</span>
            <span class="operation">恢复</span>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  mounted() {},
  data() {
    return {
      langList: [
        { name: "简体中文" },
        { name: "英文" },
        { name: "繁体中文(香港)" },
      ],
      fileList: [
        { time: "2010-10-02 12:30:09", name: "文件1" },
        { time: "2010-10-02 12:30:09", name: "文件12121212121" },
        { time: "2010-10-02", name: "文件2211" },
        { time: "2011", name: "备份文件2" },
      ],
      activePage: 0,
      interval: "",
      lifeSpan: "",
      options: [
        {
          value: "选项1",
          label: "手动",
        },
        {
          value: "选项2",
          label: "自动",
        },
      ],
      isBackUp: true,
    };
  },
  methods: {
    openRight(typ) {
      const es = document.getElementsByClassName("menu-item");
      es[this.activePage].style.backgroundColor = "#f8f8f8";
      es[this.activePage].style.color = "rgba(54, 54, 54, 1)";
      es[typ].style.backgroundColor = "rgba(61, 104, 225, 1)";
      es[typ].style.color = "#fff";
      this.activePage = typ;
    },
    handleChange() {},
    backUpNow() {
      this.$confirm("您是否确认立即备份所有应用的配置数据?", "立即备份", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
      }).then(() => {
        this.$message({
          type: "success",
          message: "备份成功",
        });
      });
      //  .then((resp) => {
      //         if (resp.success) {
      //           this.$message({
      //             type: "success",
      //             message: "删除数据成功",
      //           });
      //           this.loading = false;
      //         }
      //       })
      //       .catch((err) => {
      //         this.$message({
      //           type: "error",
      //           message: "删除数据失败!",
      //         });
      //         this.loading = false;
      //       });
    },
    switchChange(val) {
      console.log(val);
    },
  },
};
</script>
<style lang="scss">
.all {
  width: 100%;
}
.backup-content {
  height: 100%;
  display: flex;
  flex-direction: row;
  flex: 1;
  flex-basis: auto;
  box-sizing: border-box;
  .backup-center {
    height: 100%;
    width: 280px;
    overflow: auto;
    box-sizing: border-box;
    flex-shrink: 0;
    padding: 10px;
    border-right: 5px solid #f8f8f8;
    .menu-item {
      background-color: #f8f8f8;
      height: 50px;
      margin-bottom: 10px;
      border-radius: 8px;
      line-height: 50px;
      box-sizing: border-box;
      font-size: 14px;
      cursor: pointer;
      padding: 0 20px;
      display: flex;
      justify-content: space-between;
      .con {
        .iconfont {
          margin-right: 10px;
        }
        .menu-text {
          font-size: 15px;
        }
      }
    }
  }
  .backup-right {
    flex: 1;
    flex-basis: auto;
    overflow: auto;
    box-sizing: border-box;
    position: relative;
    padding: 20px 40px;
    .el-form-item.is-required:not(.is-no-asterisk)
      > .el-form-item__label:before,
    .el-form-item.is-required:not(.is-no-asterisk)
      .el-form-item__label-wrap
      > .el-form-item__label:before {
      display: none;
    }
    .el-select {
      width: 100%;
    }
    .el-form-item {
      margin-bottom: 10px;
      height: 50px;
      background: #f8f8f8;
      padding: 4px 20px;
      -webkit-box-sizing: border-box;
      box-sizing: border-box;
      border-radius: 10px;
      .el-form-item__label {
        text-align: left;
        line-height: 42px;
      }
    }
    .el-form-item__content {
      line-height: 40px;
      position: relative;
      font-size: 14px;
    }
    .ip-input-container {
      max-width: none !important;
    }
    .auto {
      .bar {
        display: flex;
        align-items: center;
        height: 50px;
        padding: 0 25px;
        background-color: #f8f8f8;
        justify-content: space-between;
        border-radius: 12px;
        margin-bottom: 10px;
        .name {
          font-size: 15px;
          text-align: left;
          min-width: 180px;
        }
        .el-input {
          width: 100%;
          .el-input {
            height: auto;
          }
          .el-input__inner {
            border: none;
            border-radius: 8px;
            background-color: rgba(240, 240, 240, 1);
            text-align: left;
          }
        }
      }
    }
    .recover {
      .title {
        font-size: 13px;
        color: #868686;
        text-align: left;
        padding: 0 10px;
        margin-bottom: 10px;
      }
      .table-head {
        height: 30px;
        line-height: 30px;
        display: flex;
        // justify-content: space-between;
        box-sizing: border-box;
        font-size: 15px;
        padding: 0 10px;
        margin-bottom: 5px;
        .line1 {
          flex: 4;
          text-align: left;
        }
        .line2 {
          flex: 1;
          text-align: right;
        }
      }
      .bar {
        height: 40px;
        background-color: rgba(248, 248, 248, 1);
        display: flex;
        box-sizing: border-box;
        padding: 0 10px;
        align-items: center;
        border-radius: 8px;
        color: #797979;
        font-size: 14px;
        margin-bottom: 10px;
        .time {
          width: 45%;
          text-align: left;
        }
        .operation {
          color: rgba(26, 115, 232, 1);
          cursor: pointer;
          width: 10%;
          text-align: right;
        }
      }
    }
    .save-btn {
      background-color: #3d68e1;
      width: 240px;
      height: 40px;
      margin: 0 auto;
      border-radius: 10px;
      color: #fff;
      line-height: 40px;
      font-size: 14px;
      margin-top: 20px;
    }
  }
}
</style>
src/pages/maintain/views/generalSettings.vue
New file
@@ -0,0 +1,456 @@
<template>
  <div class="all">
    <div class="cluster-content">
      <div class="cluster-center" ref="left">
        <div class="menu-item" @click="openRight('basic')">
          <div>设备信息</div>
        </div>
        <div class="menu-item" @click="openRight('video')">
          <div>事件录像时长</div>
        </div>
        <div class="menu-item" @click="openRight('sound')">
          <div>事件声音</div>
        </div>
      </div>
      <div class="cluster-right">
        <div class="lang" v-if="activePage == 'basic'">
          <div class="bar" v-for="(item, i) in basioInfoList" :key="i">
            <span class="name">{{ item.name }}</span>
            <span class="desc">{{ item.desc }}</span>
          </div>
        </div>
        <div class="lang" v-if="activePage == 'video'">
          <div class="min-dur">
            <div class="title">视频截取最短时长</div>
            <div class="entity">
              <div class="sec">{{ alarmConf.min_video_len }}s</div>
              <div class="block">
                <el-slider
                  v-model="alarmConf.min_video_len"
                  id="cut_min_duration"
                  :min="0"
                  :max="100"
                  :show-tooltip="false"
                >
                </el-slider>
              </div>
              <el-input-number
                v-model="alarmConf.min_video_len"
                controls-position="right"
                :min="0"
                :max="100"
                size="mini"
              ></el-input-number>
              &nbsp;s
            </div>
          </div>
          <div class="min-dur">
            <div class="title">视频截取最长时长</div>
            <div class="entity">
              <div class="sec">{{ alarmConf.max_video_len }}s</div>
              <div class="block">
                <el-slider
                  v-model="alarmConf.max_video_len"
                  id="cut_max_duration"
                  :min="0"
                  :max="100"
                  :show-tooltip="false"
                >
                </el-slider>
              </div>
              <el-input-number
                v-model="alarmConf.max_video_len"
                controls-position="right"
                :min="0"
                :max="100"
                size="mini"
              ></el-input-number>
              &nbsp;s
            </div>
          </div>
          <div class="save-btn" @click="submitAlarm">保存</div>
        </div>
        <div class="lang" v-if="activePage == 'sound'">
          <div class="title">事件声音</div>
          <div
            class="bar"
            v-for="(item, i) in soundList"
            :key="i"
            @click="clickSound(item, i)"
            ref="soundBar"
          >
            <div class="left-part">
              <span class="icon iconfont">&#xe646;</span>
              <span class="name"> {{ item.name }}</span>
            </div>
            <div class="btns">
              <span class="icon iconfont">&#xe646;</span>
              <span class="icon iconfont">&#xe646;</span>
            </div>
          </div>
        <div class="add-group">
  <el-upload
            class="upload-demo"
            drag
            action="https://jsonplaceholder.typicode.com/posts/"
            multiple
            v-show="showUpload"
          >
            <i class="el-icon-upload"></i>
            <div class="el-upload__text">
              事件声音文件拖到此处,或<em>点击上传</em> <br />
              仅支持mp3/wma等格式
            </div>
          </el-upload>
          <div             v-show="!showUpload"
></div>
          <div class="add-btn">
            <span class="icon iconfont" @click="showUpload=!showUpload">&#xe646;</span>
          </div>
        </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import { saveAlarmConfig } from "@/api/system";
import cloudNode from "../components/CloudNode";
import ipInput from "@/components/subComponents/IPInput";
import { isIPv4 } from "@/scripts/validate";
import switchBar from "../components/switchBar";
export default {
  data() {
    const checkPwd = (rule, value, callback) => {
      if (!value) {
        return callback(new Error("密码不能为空"));
      }
      setTimeout(() => {
        if (value.length != 6) {
          callback(new Error("密码应为6位!"));
        } else {
          callback();
        }
      }, 1000);
    };
    return {
      isHighClass: false,
      ruleForm: {
        deviceName: "",
        port: "",
      },
      wifiForm: {
        name: "",
        password: "",
      },
      wireArr: [{ name: "有线网络1" }, { name: "有线网络2" }],
      inWifiDetail: false,
      wifiList: [{ name: "无线网络1" }, { name: "无线网络2" }],
      isOpenWifi: false,
      inWireDetail: false,
      wireForm: {},
      showUpload:false,
      alarmConf: {
        min_video_len: 0,
        max_video_len: 0,
      },
      basioInfoList: [
        { name: "简体中文", desc: "fesF" },
        { name: "英文", desc: "fesF" },
        { name: "繁体中文(香港)", desc: "fesF" },
      ],
      soundList: [{ name: "2.mp3" }, { name: "3.mp3" }],
      wireFormRules: {},
      activePage: "basic",
      rules: {
        deviceName: [
          { required: true, message: "请输入设备名称", trigger: "change" },
        ],
      },
      ipv4Form: {},
      ipv6Form: {},
      ipv4FormRules: {},
      ipv6FormRules: {},
      options: [
        {
          value: "选项1",
          label: "手动",
        },
        {
          value: "选项2",
          label: "自动",
        },
      ],
      value: "",
    };
  },
  components: {
    cloudNode,
    ipInput,
    switchBar,
  },
  mounted() {},
  beforeDestroy() {},
  props: ["barName"],
  methods: {
    openRight(typ) {
      this.activePage = typ;
    },
    wifiControl(val) {},
    checkWifi() {
      this.inWifiDetail = true;
    },
    checkWire(item) {
      this.inWireDetail = true;
    },
    clickSound(item, i) {
      this.$refs["soundBar"].forEach((x) => {
        x.style.backgroundColor = "rgba(248, 248, 248, 1)";
      });
      this.$refs["soundBar"][i].style.backgroundColor =
        "rgba(233, 233, 233, 1)";
    },
    submitAlarm() {
      saveAlarmConfig(this.alarmConf).then((res) => {
        if (res && res.success) {
          this.$notify({
            type: "success",
            message: "保存成功",
          });
        }
      });
    },
  },
};
</script>
<style lang="scss">
.all {
  width: 100%;
}
.cluster-content {
  height: 100%;
  display: flex;
  flex-direction: row;
  flex: 1;
  flex-basis: auto;
  box-sizing: border-box;
  .cluster-center {
    height: 100%;
    width: 280px;
    overflow: auto;
    box-sizing: border-box;
    flex-shrink: 0;
    padding: 10px;
    border-right: 5px solid #f8f8f8;
    // background-color: lavender;
    .menu-item {
      background-color: #f8f8f8;
      height: 40px;
      margin-bottom: 10px;
      border-radius: 8px;
      line-height: 40px;
      box-sizing: border-box;
      font-size: 14px;
      padding: 0 20px;
      display: flex;
      justify-content: space-between;
    }
  }
  .cluster-right {
    flex: 1;
    flex-basis: auto;
    overflow: auto;
    // background-color: rgba(240, 242, 245, 1);
    box-sizing: border-box;
    position: relative;
    padding: 20px 40px;
    // .create-new .join-exist {
    .el-form-item.is-required:not(.is-no-asterisk)
      > .el-form-item__label:before,
    .el-form-item.is-required:not(.is-no-asterisk)
      .el-form-item__label-wrap
      > .el-form-item__label:before {
      display: none;
    }
    .el-select {
      width: 100%;
    }
    .el-form-item {
      margin-bottom: 10px;
      height: 50px;
      background: #f8f8f8;
      padding: 4px 20px;
      -webkit-box-sizing: border-box;
      box-sizing: border-box;
      border-radius: 10px;
      .el-form-item__label {
        text-align: left;
        line-height: 42px;
      }
    }
    .el-form-item__content {
      line-height: 40px;
      position: relative;
      font-size: 14px;
    }
    .ip-input-container {
      max-width: none !important;
    }
    .lang {
      .title {
        height: 35px;
        line-height: 35px;
        font-size: 16px;
        text-align: left;
        margin-bottom: 5px;
      }
      .bar {
        height: 50px;
        background-color: rgba(248, 248, 248, 1);
        border-radius: 10px;
        line-height: 50px;
        box-sizing: border-box;
        padding: 0 30px 0 20px;
        display: flex;
        justify-content: space-between;
        margin-bottom: 10px;
        cursor: pointer;
        .left-part {
          .icon {
            color: rgba(191, 191, 191, 1);
            font-size: 16px;
            margin-right: 5px;
          }
        }
        .name {
          font-size: 15px;
        }
        .btns {
          width: 50px;
          display: flex;
          justify-content: space-between;
          color: rgba(191, 191, 191, 1);
        }
        .desc {
          font-size: 14px;
          color: rgba(134, 134, 134, 1);
        }
      }
      .bar:hover {
        background-color: rgba(233, 233, 233, 1);
      }
      .add-group{
      margin-top: 170px;
    height: 235px;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
      }
      .upload-demo {
        .el-upload-dragger {
          width: 290px;
        }
      }
      .add-btn {
        height: 40px;
        line-height: 40px;
        margin-top: 10px;
        .icon {
          font-size: 30px;
          color: rgba(61, 104, 225, 1);
        }
      }
      .min-dur {
        box-sizing: border-box;
        padding: 0 20px;
        background-color: rgba(248, 248, 248, 1);
        height: 95px;
        margin-bottom: 20px;
        border-radius: 15px;
        .title {
          height: 45px;
          line-height: 45px;
          text-align: left;
          box-sizing: border-box;
          padding: 0 6px;
          font-size: 14px;
        }
      }
      .entity {
        display: flex;
        align-items: center;
        height: 30px;
        .sec {
          min-width: 30px;
          line-height: 80px;
          margin-right: 10px;
          color: rgba(120, 120, 120, 1);
          font-size: 14px;
        }
        .block {
          flex: 1;
          margin: 0 20px 0 6px;
        }
        .el-input-number--mini {
          width: 80px;
        }
        .el-input-number.is-controls-right[class*="mini"] [class*="increase"],
        .el-input-number.is-controls-right[class*="mini"] [class*="decrease"] {
          width: 23px;
        }
        .el-input-number.is-controls-right .el-input__inner {
          padding-left: 13px;
          padding-right: 37px;
        }
        #cut_min_duration {
          .el-slider__bar {
            background-color: #3d68e1;
          }
          .el-slider__button-wrapper .el-tooltip {
            width: 18px;
            height: 18px;
            border: 4px solid #3d68e1;
            box-sizing: border-box;
          }
        }
        #cut_max_duration {
          .el-slider__bar {
            background-color: #ff9e6e;
          }
          .el-slider__button-wrapper .el-tooltip {
            width: 18px;
            height: 18px;
            border: 4px solid #ff9e6e;
            box-sizing: border-box;
          }
        }
      }
    }
    .save-btn {
      background-color: #3d68e1;
      width: 240px;
      height: 40px;
      margin: 0 auto;
      border-radius: 10px;
      color: #fff;
      line-height: 40px;
      font-size: 14px;
      margin-top: 20px;
    }
  }
}
</style>
src/pages/maintain/views/restartSettings.vue
New file
@@ -0,0 +1,384 @@
<template>
  <div class="restart">
    <div class="restart-set">
      <div class="t">重启设置</div>
      <div class="bar">
        <div class="name">重启节点</div>
        <el-button
          class="reset-btn"
          type="primary"
          size="small"
          @click="restart"
          >重启</el-button
        >
      </div>
    </div>
    <div class="restart-set">
      <div class="t">定时重启</div>
      <div class="bar">
        <div class="name">重启周期</div>
        <el-select
          v-model="every"
          placeholder="关闭"
          size="small"
          @change="changeEvery"
        >
          <el-option
            v-for="item in options"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          >
          </el-option>
        </el-select>
      </div>
      <div class="bar" v-if="every == 'monthly'">
        <div class="name">重启日期</div>
        <el-select
          v-model="cronValueObj.day"
          placeholder="请选择"
          size="small"
          @change="updateExpression"
        >
          <el-option
            v-for="item in days"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          ></el-option>
        </el-select>
      </div>
      <div class="bar" v-if="every == 'weekly'">
        <div class="name">重启日期</div>
        <el-select
          v-model="cronValueObj.week"
          placeholder="请选择"
          size="small"
          @change="updateExpression"
        >
          <el-option label="星期一" value="1"></el-option>
          <el-option label="星期二" value="2"></el-option>
          <el-option label="星期三" value="3"></el-option>
          <el-option label="星期四" value="4"></el-option>
          <el-option label="星期五" value="5"></el-option>
          <el-option label="星期六" value="6"></el-option>
          <el-option label="星期日" value="7"></el-option>
        </el-select>
      </div>
      <div class="bar" v-if="every != 'close'">
        <div class="name">重启时间</div>
        <el-time-picker
          v-model="time"
          :picker-options="{ selectableRange: '00:00:00 - 23:59:59' }"
          value-format="HH:mm"
          format="HH:mm"
          placeholder="任意时间点"
          size="small"
          @change="updateExpression"
        ></el-time-picker>
      </div>
    </div>
    <el-button class="save-btn" type="primary" @click="save">保存</el-button>
  </div>
</template>
<script>
import {
  rebootServer,
  getDevInfo,
  getRebootTask,
  setRebootTask,
  fileUpload,
  doUpgrade,
  deleteDate,
} from "@/api/system";
export default {
  data() {
    return {
      time: "",
      saveBtn: false,
      timer: null,
      probeSum: 0,
      cronText: "",
      cronValueObj: {
        min: "*",
        hour: "*",
        day: "*",
        month: "*",
        week: "*",
      },
      options: [
        {
          value: "close",
          label: "关闭",
        },
        {
          value: "daily",
          label: "每日",
        },
        {
          value: "weekly",
          label: "每周",
        },
        {
          value: "monthly",
          label: "每月",
        },
      ],
      every: "close",
      rebootCron: "",
    };
  },
  computed: {
    days: () => {
      let arr = [];
      for (let i = 1; i < 32; i++) {
        arr.push({
          label: i + "日",
          value: i + "",
        });
      }
      return arr;
    },
  },
  components: {},
  mounted() {
    this.getRebootCron();
  },
  beforeDestroy() {},
  methods: {
    resolveExp() {
      // "准备反解析", this.expression;
      if (this.rebootCron.length) {
        let arr = this.rebootCron.split(" ");
        if (arr.length >= 5) {
          //6 位以上是合法表达式
          this.cronValueObj.min = arr[0];
          this.cronValueObj.hour = arr[1];
          this.cronValueObj.day = arr[2];
          this.cronValueObj.month = "*";
          this.cronValueObj.week = arr[4];
        }
        if (this.cronValueObj.week != "*") {
          this.every = "weekly";
        } else if (this.cronValueObj.day != "*") {
          this.every = "monthly";
        } else {
          this.every = "daily";
        }
        this.time = this.cronValueObj.hour + ":" + this.cronValueObj.min;
      } else {
        //没有传入的表达式 则还原
        this.clearCron();
      }
    },
    clearCron() {
      this.cronValueObj.min = "*";
      this.cronValueObj.hour = "*";
      this.cronValueObj.day = "*";
      this.cronValueObj.month = "*";
      this.cronValueObj.week = "*";
    },
    getRebootCron() {
      getRebootTask().then((rsp) => {
        this.rebootCron = rsp.data;
      });
    },
    reLogin() {
      this.$router.push("/");
    },
    restart() {
      this.$confirm("确定要重启该节点吗?", {
        center: true,
        cancelButtonClass: "comfirm-class-cancle",
        confirmButtonClass: "comfirm-class-sure",
      }).then(() => {
        // this.loading = true;
        // this.loadingText = "智能计算节点正在重启,请耐心等待..."
        rebootServer()
          .then((rsp) => {
            this.probeServer(this.reLogin);
          })
          .catch((err) => {
            if (err.status == 400) {
              // this.loading = false;
              this.$notify({
                type: "error",
                message: "重启计算节点失败",
              });
            } else {
              this.probeServer(this.reLogin);
            }
          });
      });
    },
    probeServer(cb) {
      this.probeSum++;
      let _this = this;
      if (this.probeSum > 60) {
        this.$confirm("连接服务器失败, 请刷新页面或联系管理员", "失败", {
          type: "error",
          cancelButtonClass: "comfirm-class-cancle",
          confirmButtonClass: "comfirm-class-sure",
        }).then(() => {
          cb();
        });
        return;
      }
      this.timer = setTimeout(() => {
        getDevInfo()
          .then(() => {
            cb();
          })
          .catch((err) => {
            _this.probeServer(cb);
          });
      }, 10000);
    },
    save() {
      this.rebootCron = this.cronText;
      setRebootTask({ task: this.cronText })
        .then((rsp) => {
          if (rsp && rsp.success) {
            this.$notify({
              type: "success",
              message: "配置成功",
            });
          }
        })
        .catch((err) => {
          this.$notify({
            type: "error",
            message: "配置失败",
          });
        });
    },
    changeEvery() {
      this.saveBtn = true;
      if (this.every === "close") {
        this.cronText = "";
        return;
      }
      if (this.every === "monthly") {
        this.cronValueObj.week = "*";
        this.cronValueObj.day = "1";
        if (!this.time.length) {
          this.time = "00:00";
        }
      }
      if (this.every === "weekly") {
        this.cronValueObj.day = "*";
        this.cronValueObj.week = "1";
        if (!this.time.length) {
          this.time = "00:00";
        }
      }
      if (this.every === "daily") {
        this.cronValueObj.day = "*";
        this.cronValueObj.week = "*";
      }
      this.updateExpression();
    },
    updateExpression() {
      this.saveBtn = true;
      if (this.time.length) {
        let arr = this.time.split(":");
        this.cronValueObj.hour = arr[0];
        this.cronValueObj.min = arr[1];
      }
      this.crontabValueString();
    },
    crontabValueString() {
      let obj = this.cronValueObj;
      this.cronText =
        obj.min +
        " " +
        obj.hour +
        " " +
        obj.day +
        " " +
        obj.month +
        " " +
        obj.week;
    },
  },
  watch: {
    rebootCron() {
      this.resolveExp();
    },
  },
};
</script>
<style lang="scss">
.all {
  width: 100%;
}
.restart {
  margin: 0 auto;
  padding: 20px;
  .t {
    box-sizing: border-box;
    text-align: left;
    width: 70%;
    margin: 0 auto;
    padding: 10px;
    font-size: 16px;
  }
  .bar {
    height: 50px;
    width: 70%;
    background: rgba(248, 248, 248, 1);
    margin: 0 auto;
    min-width: 300px;
    display: flex;
    justify-content: space-between;
    box-sizing: border-box;
    padding: 0 20px;
    align-items: center;
    border-radius: 10px;
    margin-bottom: 10px;
    .reset-btn {
      width: 70px;
      height: 32px;
      border-radius: 5px;
    }
    .el-select {
      width: 100%;
    }
    .name {
      min-width: 150px;
      text-align: left;
      font-size: 14px;
    }
    .el-input__inner::placeholder {
      color: rgba(107, 107, 107, 1);
    }
    .el-input--small .el-input__inner {
      height: 32px;
      line-height: 32px;
      border: none;
      background: rgba(240, 240, 240, 1);
    }
    .el-select .el-input .el-select__caret {
      color: rgba(138, 138, 138, 1);
      font-size: 15px;
    }
    .el-date-editor.el-input,
    .el-date-editor.el-input__inner {
      width: 100%;
    }
  }
  .save-btn {
    width: 260px;
    margin-top: 50px;
  }
}
</style>
src/pages/maintain/views/systemClean.vue
New file
@@ -0,0 +1,215 @@
<template>
  <div class="clear"
      v-loading="loading"
      :element-loading-text="loadingText"
  >
    <div class="head">
      <span class="t">请选择要清理的数据范围</span>
      <el-date-picker
        style="width: 100%"
        v-model="dataRange"
        type="daterange"
        align="right"
        size="small"
        range-separator="至"
        start-placeholder="开始日期"
        end-placeholder="结束日期"
        :picker-options="pickerOptions"
      >
      </el-date-picker>
    </div>
    <div class="desc">
      <div class="disk-img"></div>
      <div class="cap">
        <div class="cap-text">磁盘可用:{{ 21 }}%</div>
        <div class="cap-bar">
          <div class="inner-bar"></div>
        </div>
      </div>
      <el-button type="primary" @click="deleteData">数据清理</el-button>
      <div class="warm">
        <!-- <span class="icon iconfont" style="margin-right:5px">&#xe690;</span> -->
        <i class="iconfont icontishi-zhuyi"></i>
        <span class="text"
          >请注意,按以上日期范围删除的数据不可恢复,立即生效,请谨慎操作!</span
        >
      </div>
    </div>
  </div>
</template>
<script>
import { deleteDate } from "@/api/system";
export default {
  data() {
    return {
      pickerOptions: {
        disabledDate(time) {
          var day = new Date();
          day.setTime(day.getTime() - 24 * 60 * 60 * 1000);
          return time.getTime() > day;
        },
      },
      loading: false,
      loadingText: '',
      dataRange: [
        this.$moment().format("YYYY-MM-DD HH:mm:ss"),
        this.$moment().format("YYYY-MM-DD HH:mm:ss"),
      ],
      pickerOptions: {
        disabledDate(time) {
          var day = new Date();
          day.setTime(day.getTime() - 24 * 60 * 60 * 1000);
          return time.getTime() > day;
        },
      },
    };
  },
  mounted() {},
  methods: {
    deleteData() {
      var timeRange = this.format(this.dataRange);
      var showStartTime = timeRange[0];
      var showEndTime = timeRange[1];
      this.$confirm(
        "提示:" +
          showStartTime +
          " 至 " +
          showEndTime +
          " 产生的全部数据将被删除,此操作立即生效,不可恢复,是否删除?",
        {
          center: true,
          cancelButtonClass: "comfirm-class-cancle",
          confirmButtonClass: "comfirm-class-sure",
        }
      )
        .then(() => {
          this.loading = true
          this.loadingText = "正在删除数据,请稍候!"
          deleteDate({
            startTime: showStartTime,
            endTime: showEndTime,
          })
            .then((resp) => {
              if (resp.success) {
                this.$message({
                  type: "success",
                  message: "删除数据成功",
                });
                this.loading = false
              }
            })
            .catch((err) => {
              this.$message({
                type: "error",
                message: "删除数据失败!",
              });
              this.loading = false
            });
        })
        .catch(() => {});
    },
    format(array) {
      return [
        this.$moment(array[0]).format("YYYY-MM-DD"),
        this.$moment(array[1]).format("YYYY-MM-DD"),
      ];
    },
  },
};
</script>
<style lang="scss">
.all {
  width: 100%;
}
.clear {
  margin: 0 auto;
  padding: 20px;
  .head {
    height: 50px;
    background-color: rgba(248, 248, 248, 1);
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: space-around;
    box-sizing: border-box;
    padding: 0 20px;
    width: 560px;
    margin: 0 auto;
    .t {
      font-size: 14px;
      min-width: 175px;
      text-align: left;
    }
    .el-range-editor--small.el-input__inner {
      border: none;
    }
    .el-range-editor--small .el-range-separator {
    line-height: 26px;
}
  }
  .desc {
    margin-top: 50px;
    .disk-img {
      height: 100px;
      width: 100px;
      margin: 0 auto;
      margin-bottom: 10px;
      background-color: aquamarine;
    }
    .cap {
      height: 50px;
      margin: 0 auto;
      width: 160px;
      margin-bottom: 20px;
      .cap-bar {
        height: 8px;
        background: rgba(242, 242, 242, 1);
        //
        margin: 0 auto;
        border-radius: 2px;
        .inner-bar {
          background: #3a8120;
          width: 40%;
          height: 100%;
          border-radius: 2px;
        }
      }
      .cap-text {
        text-align: right;
        height: 25px;
        line-height: 25px;
        font-size: 12px;
      }
    }
    .el-button--primary {
      width: 200px;
      font-size: 15px;
    }
    .warm {
      line-height: 30px;
      height: 30px;
      margin-top: 10px;
      display: flex;
      align-items: center;
      justify-content: center;
      .iconfont {
          font-size: 16px;
        color: #e99038;
        margin-right: 5px;
      }
      .text {
        color: rgba(187, 187, 187, 1);
        font-size: 14px;
      }
    }
  }
}
</style>
src/pages/maintain/views/updateSettings.vue
New file
@@ -0,0 +1,478 @@
<template>
  <div class="all">
    <div class="cluster-content">
      <div class="cluster-center" ref="left">
        <div class="menu-item" @click="openRight(0)">
          <div class="con">
            <span class="icon iconfont">&#xe646;</span>
            <span class="menu-text">系统更新</span>
          </div>
        </div>
        <div class="menu-item" @click="openRight(1)">
          <div class="con">
            <span class="icon iconfont">&#xe646;</span>
            <span class="menu-text">更新设置</span>
          </div>
        </div>
      </div>
      <div class="cluster-right">
        <div class="net-set" v-if="activePage == 0">
          <el-radio-group v-model="radio2" size="medium">
            <el-radio-button label="检查更新"></el-radio-button>
            <el-radio-button label="上传更新"></el-radio-button>
          </el-radio-group>
          <div class="update-center" v-if="radio2 == '检查更新'">
            <div class="spin-bg"></div>
            <div class="line"></div>
            <div class="desc">{{ "检查到最新版本:1.0.2" }}</div>
            <el-button type="primary" size="small">更新</el-button>
          </div>
          <div class="upload-center" v-if="radio2 == '上传更新'">
            <!-- uploadPlaceholder="上传升级文件" -->
            <div class="top">
              <div class="up-text">上传更新文件</div>
              <fileUploader
                single
                url="/data/api-v/sysset/patchUpdate"
                @complete="onFileUpload"
                @file-added="onFileAdded"
              />
              <el-button
                type="primary"
                size="small"
                style="width: 80px"
                @click="upgrade"
                :disabled="!fileAdded"
                :loading="upgrading"
                >升级</el-button
              >
            </div>
            <div class="update-center">
              <div class="spin-bg"></div>
              <div class="line"></div>
              <div class="desc">{{ "检查到最新版本:1.0.2" }}</div>
              <el-button type="primary" size="small">更新</el-button>
            </div>
            <!-- <span v-html="patchUpdateStatus"></span> -->
          </div>
          <div class="cur-version">当前版本:{{ "1.0.1" }}</div>
        </div>
        <div class="wifi" v-if="activePage == 1">
          <div class="content">
            <div class="title">系统更新设置</div>
            <div class="bar">
              <div class="name">自动清理软件包缓存</div>
              <el-switch
                v-model="sys_auto_clear"
                active-color="rgba(61, 104, 225, 1)"
                @change="switchChange('sys_auto_clear')"
              >
              </el-switch>
            </div>
            <div class="bar">
              <div class="name">更新提醒</div>
              <el-switch
                v-model="sys_remind"
                active-color="rgba(61, 104, 225, 1)"
                @change="switchChange('sys_remind')"
              >
              </el-switch>
            </div>
            <div class="bar" v-if="sys_remind">
              <div class="name">自动下载更新</div>
              <el-switch
                v-model="sys_auto_download"
                active-color="rgba(61, 104, 225, 1)"
                @change="switchChange('sys_auto_download')"
              >
              </el-switch>
            </div>
          </div>
          <div class="content">
            <div class="title">应用/算法更新设置</div>
            <div class="bar">
              <div class="name">自动清理软件包缓存</div>
              <el-switch
                v-model="app_auto_clear"
                active-color="rgba(61, 104, 225, 1)"
                @change="switchChange('app_auto_clear')"
              >
              </el-switch>
            </div>
            <div class="bar">
              <div class="name">更新提醒</div>
              <el-switch
                v-model="app_remind"
                active-color="rgba(61, 104, 225, 1)"
                @change="switchChange('app_remind')"
              >
              </el-switch>
            </div>
            <div class="bar" v-if="app_remind">
              <div class="name">自动下载更新</div>
              <el-switch
                v-model="app_auto_download"
                active-color="rgba(61, 104, 225, 1)"
                @change="switchChange('app_auto_download')"
              >
              </el-switch>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import { getDevInfo, fileUpload, doUpgrade } from "@/api/system";
import FileUploader from "@/components/subComponents/FileUpload/index";
export default {
  components: {
    FileUploader,
  },
  data() {
    return {
      wifiList: [{ name: "无线网络1" }, { name: "无线网络2" }],
      radio2: "检查更新",
      activePage: 0,
      patchUpdateStatus: "",
      probeSum: 0,
      sys_auto_clear: false,
      sys_remind: false,
      sys_auto_download: false,
      app_auto_clear: false,
      app_remind: false,
      app_auto_download: false,
      timer: null,
      patchFile: {},
      fileAdded: false,
      upgrading: false,
    };
  },
  mounted() {},
  methods: {
    onFileUpload(file) {
      this.patchUpdateStatus = `<span style="color:green">上传成功, 点击升级按钮开始升级</span>`;
      this.patchFile = { ...file };
      this.fileAdded = true;
    },
    onFileAdded() {
      this.patchUpdateStatus = "";
    },
    upgrade() {
      this.upgrading = true;
      this.patchUpdateStatus = `<span style="color:red">正在升级...</span>`;
      doUpgrade(this.patchFile)
        .then((rsp) => {
          this.upgrading = false;
          if (rsp && rsp.success) {
            clearTimeout(this.timer);
            this.doneUpgrade();
          }
        })
        .catch((err) => {
          if (err.code) {
            this.upgrading = false;
            this.patchUpdateStatus = `<span style="color:red">${err.data}</span>`;
            clearTimeout(this.timer);
          } else {
            this.probeServer(this.doneUpgrade);
          }
        });
    },
    doneUpgrade() {
      this.upgrading = false;
      this.patchUpdateStatus = `<span style="color:green">升级成功</span>`;
      let _this = this;
      this.$confirm("升级成功, 请重新登录系统", "成功", {
        type: "success",
        cancelButtonClass: "comfirm-class-cancle",
        confirmButtonClass: "comfirm-class-sure",
      }).then(() => {
        _this.reLogin();
      });
    },
    reLogin() {
      this.$router.push("/");
    },
    probeServer(cb) {
      this.probeSum++;
      let _this = this;
      if (this.probeSum > 60) {
        this.$confirm("连接服务器失败, 请刷新页面或联系管理员", "失败", {
          type: "error",
          cancelButtonClass: "comfirm-class-cancle",
          confirmButtonClass: "comfirm-class-sure",
        }).then(() => {
          cb();
        });
        return;
      }
      this.timer = setTimeout(() => {
        getDevInfo()
          .then(() => {
            cb();
          })
          .catch((err) => {
            _this.probeServer(cb);
          });
      }, 10000);
    },
    openRight(typ) {
      const es = document.getElementsByClassName("menu-item");
      es[this.activePage].style.backgroundColor = "#f8f8f8";
      es[this.activePage].style.color = "rgba(54, 54, 54, 1)";
      es[typ].style.backgroundColor = "rgba(61, 104, 225, 1)";
      es[typ].style.color = "#fff";
      this.activePage = typ;
    },
    switchChange(typ) {
      console.log(this[typ]);
    },
  },
};
</script>
<style lang="scss">
.all {
  width: 100%;
}
.cluster-content {
  height: 100%;
  display: flex;
  flex-direction: row;
  flex: 1;
  flex-basis: auto;
  box-sizing: border-box;
  .cluster-center {
    height: 100%;
    width: 280px;
    overflow: auto;
    box-sizing: border-box;
    flex-shrink: 0;
    padding: 10px;
    border-right: 5px solid #f8f8f8;
    // background-color: lavender;
    .menu-item {
      background-color: #f8f8f8;
      height: 50px;
      margin-bottom: 10px;
      border-radius: 8px;
      line-height: 50px;
      box-sizing: border-box;
      font-size: 14px;
      cursor: pointer;
      padding: 0 20px;
      display: flex;
      justify-content: space-between;
      .con {
        .iconfont {
          margin-right: 10px;
        }
        .menu-text {
          font-size: 15px;
        }
      }
    }
  }
  .cluster-right {
    flex: 1;
    flex-basis: auto;
    overflow: auto;
    box-sizing: border-box;
    position: relative;
    padding: 20px 40px;
    .el-form-item.is-required:not(.is-no-asterisk)
      > .el-form-item__label:before,
    .el-form-item.is-required:not(.is-no-asterisk)
      .el-form-item__label-wrap
      > .el-form-item__label:before {
      display: none;
    }
    .el-select {
      width: 100%;
    }
    .el-form-item {
      margin-bottom: 10px;
      height: 50px;
      background: #f8f8f8;
      padding: 4px 20px;
      -webkit-box-sizing: border-box;
      box-sizing: border-box;
      border-radius: 10px;
      .el-form-item__label {
        text-align: left;
        line-height: 42px;
      }
    }
    .el-form-item__content {
      line-height: 40px;
      position: relative;
      font-size: 14px;
    }
    .ip-input-container {
      max-width: none !important;
    }
    .net-set {
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      height: 95%;
      // .el-radio-button__inner {
      //   // color: #333333;
      //   border: none;
      // }
      .update-center {
        height: 160px;
        .spin-bg {
          width: 70px;
          height: 70px;
          background: rgba(230, 230, 230, 1);
          margin: 0 auto;
          border-radius: 35px;
        }
        .line {
          width: 180px;
          height: 5px;
          background: #e6e6e6;
          border-radius: 5px;
          margin: 5px auto;
        }
        .desc {
          height: 20px;
          line-height: 20px;
          font-size: 14px;
          color: rgba(161, 161, 161, 1);
          margin-bottom: 10px;
        }
        .el-button {
          width: 120px;
        }
        .el-button--small {
          font-size: 14px;
        }
      }
      .upload-center {
        height: 340px;
        // margin: 0 auto;
         .update-center {
        height: 160px;
        .spin-bg {
          width: 70px;
          height: 70px;
          background: rgba(230, 230, 230, 1);
          margin: 0 auto;
          border-radius: 35px;
        }
        .line {
          width: 180px;
          height: 5px;
          background: #e6e6e6;
          border-radius: 5px;
          margin: 5px auto;
        }
        .desc {
          height: 20px;
          line-height: 20px;
          font-size: 14px;
          color: rgba(161, 161, 161, 1);
          margin-bottom: 10px;
        }
        .el-button {
          width: 120px;
        }
        .el-button--small {
          font-size: 14px;
        }
      }
        .top {
          display: flex;
          justify-content: space-evenly;
          align-items: center;
          background: rgba(248, 248, 248, 1);
          box-sizing: border-box;
          padding: 8px 10px;
          border-radius: 8px;
          .el-input--small .el-input__inner {
            border: none;
          }
          .uploader-btn {
            padding: 6px 8px;
            .el-icon-upload2 {
              font-size: 21px;
              font-weight: 600;
            }
          }
        }
        .up-text {
          height: 32px;
          line-height: 32px;
          font-size: 14px;
          min-width: 105px;
          margin-right: 5px;
        }
        .file-uploader {
          width: 100%;
          margin-right: 20px;
          min-width: 150px;
        }
      }
      .cur-version {
        font-size: 14px;
      }
    }
    .wifi {
      .content {
        margin-bottom: 20px;
      }
      .bar {
        display: flex;
        align-items: center;
        height: 50px;
        padding: 0 25px;
        background-color: #f8f8f8;
        justify-content: space-between;
        border-radius: 12px;
        margin-bottom: 10px;
        .name {
          font-size: 15px;
        }
      }
      .title {
        text-align: left;
        padding: 10px;
        font-size: 16px;
      }
    }
    .save-btn {
      background-color: #3d68e1;
      width: 240px;
      height: 40px;
      margin: 0 auto;
      border-radius: 10px;
      color: #fff;
      line-height: 40px;
      font-size: 14px;
      margin-top: 20px;
    }
  }
}
</style>
src/pages/systemSettings/index/App.vue
@@ -22,6 +22,8 @@
            class="account-card"
            v-for="(item, index) in accountArr"
            :key="index"
            ref="account-card"
            @click="openAccount(item, index)"
          >
            <div class="touxiang">
              <img src="" alt="" />
@@ -64,14 +66,35 @@
      v-if="activePage == '账户' || activePage == '日期时间'"
    >
      <div class="account-right" v-if="activePage == '账户'">
        <div class="account-content" v-if="inAccountDetail == false">
        <div
          class="account-content"
          v-if="inAccountDetail == false && isAddAccount == false"
        >
          <div class="content-top">
            <div class="touxiang-big"></div>
            <div class="user-desc">
              <div class="username">飞利浦</div>
              <div class="username">
                <span class="icon iconfont" style="margin-right: 5px"
                  >&#xe690;</span
                >
                <span>飞利浦</span>
              </div>
              <div class="nickname">
                <span>兔兔</span>
                <span class="icon iconfont">&#xe60c;</span>
                <span>昵称:</span>
                <span v-show="!showInputNickName">{{ inputNickName }}</span>
                <input
                  type="text"
                  class="input-nick"
                  ref="input-nick"
                  v-show="showInputNickName"
                  v-model="inputNickName"
                  @blur="hideInputNick"
                  @keydown.enter="hideInputNick"
                />
                <span class="icon iconfont" @click="editNickName"
                  >&#xe60c;</span
                >
              </div>
            </div>
          </div>
@@ -85,26 +108,38 @@
        <div class="change-pw" v-if="inAccountDetail && isChangePw">
          <div class="title">修改密码</div>
          <div class="p-title">当前密码:</div>
          <el-form
            :model="passwordForm"
            :rules="rules"
            ref="passwordForm"
            class="password-form"
          >
            <el-form-item>
              <div class="p-title">当前密码:</div>
          <el-input
            placeholder="必填"
            v-model="input1"
            show-password
          ></el-input>
          <div class="p-title">新密码:</div>
          <el-input
            placeholder="必填"
            v-model="input2"
            show-password
          ></el-input>
          <div class="p-title">确认密码:</div>
          <el-input
            placeholder="必填"
            v-model="input3"
            show-password
          ></el-input>
              <el-input
                placeholder="必填"
                v-model="passwordForm.curPassword"
                show-password
              ></el-input>
            </el-form-item>
            <el-form-item>
              <div class="p-title">新密码:</div>
              <el-input
                placeholder="必填"
                v-model="passwordForm.newPassword"
                show-password
              ></el-input>
            </el-form-item>
            <el-form-item>
              <div class="p-title">确认密码:</div>
              <el-input
                placeholder="必填"
                v-model="passwordForm.confirmPassword"
                show-password
              ></el-input>
            </el-form-item>
          </el-form>
          <div class="btns">
            <div class="cancel" @click="cancelChangePassword">取消</div>
            <div class="ok">保存</div>
@@ -142,7 +177,7 @@
          </div>
        </div>
        <div class="add-account-page" v-if="inAccountDetail && isAddAccount">
        <div class="add-account-page" v-if="isAddAccount">
          <div class="title">添加账户</div>
          <div class="upload-group">
            <div
@@ -150,7 +185,7 @@
              v-for="(item, index) in jpgArr"
              :key="index"
            ></div>
            <div
            <!-- <div
              class="upload-jpg"
              style="height: 0px; visibility: hidden"
            ></div>
@@ -165,33 +200,47 @@
            <div
              class="upload-jpg"
              style="height: 0px; visibility: hidden"
            ></div>
            ></div> -->
          </div>
          <div class="fill-group">
            <div class="p-title">用户名:</div>
            <el-input
              placeholder="必填"
              v-model="input1"
              show-password
            ></el-input>
            <div class="p-title">昵称</div>
            <el-input
              placeholder="选填"
              v-model="input2"
              show-password
            ></el-input>
            <div class="p-title">密码:</div>
            <el-input
              placeholder="必填"
              v-model="input3"
              show-password
            ></el-input>
            <div class="p-title">确认密码:</div>
            <el-input
              placeholder="必填"
              v-model="input3"
              show-password
            ></el-input>
            <el-form
              :model="addForm"
              :rules="rules"
              ref="addForm"
              class="add-form"
            >
              <el-form-item>
                <div class="p-title">用户名:</div>
                <el-input
                  placeholder="必填"
                  v-model="addForm.userName"
                ></el-input>
              </el-form-item>
              <el-form-item>
                <div class="p-title">昵称:</div>
                <el-input
                  placeholder="必填"
                  v-model="addForm.nickName"
                ></el-input>
              </el-form-item>
              <el-form-item>
                <div class="p-title">密码:</div>
                <el-input
                  placeholder="必填"
                  v-model="addForm.password"
                  show-password
                ></el-input>
              </el-form-item>
              <el-form-item>
                <div class="p-title">确认密码:</div>
                <el-input
                  placeholder="必填"
                  v-model="addForm.confirmPassword"
                  show-password
                ></el-input>
              </el-form-item>
            </el-form>
          </div>
          <div class="btns">
            <div class="cancel" @click="cancelAdd">取消</div>
@@ -337,31 +386,39 @@
          </div>
          <div class="adjust-bar">
            <div class="minus" @click="minusOne('mth')">-</div>
            <div class="middle">
                 <span v-show="!showMonthInput">{{ syncMonth }}</span>
            <div class="middle" @click="showInput('Month')">
              <span v-show="!showMonthInput">{{ syncMonth }}</span>
              <input
                class="input-box"
                v-show="showMonthInput"
                ref="iptYrs"
                oninput="value=value.replace(/[^\d]/g,'');if(value.length>4)value=value.slice(0,4);"
                ref="iptMonth"
                oninput="value=value.replace(/[^\d]/g,'');if(value.length>2)value=value.slice(0,2);if(+value>12)value='12'"
                type="text"
                v-model="inputMonth"
                @blur="hideInput('Month')"
                @keydown.enter="hideInput('Month')"
              />
              月
            </div>
            <div class="plus" @click="plusOne('mth')">+</div>
          </div>
          <div class="adjust-bar">
            <div class="minus" @click="minusOne('day')">-</div>
            <div class="middle">{{ syncDay }} 日</div>
            <div class="middle" @click="showInput('Day')">
              <span v-show="!showDayInput">{{ syncDay }}</span>
              <input
                class="input-box"
                v-show="showDayInput"
                ref="iptDay"
                oninput="value=value.replace(/[^\d]/g,'');if(value.length>2)value=value.slice(0,2);if(+value>31)value='31'"
                type="text"
                v-model="inputDay"
                @blur="hideInput('Day')"
                @keydown.enter="hideInput('Day')"
              />
              日
            </div>
            <div class="plus" @click="plusOne('day')">+</div>
          </div>
        </div>
@@ -437,10 +494,13 @@
      browserTimer: null,
      timezone: "",
      isRealtime: false,
      inputNickName: "兔兔",
      showHourInput: false,
      showMinInput: false,
      showSecInput: false,
      showYrsInput: false,
      showMonthInput: false,
      showDayInput: false,
      timestamp: 0,
      inAccountDetail: false,
@@ -473,6 +533,21 @@
      inputMin: "",
      inputSec: "",
      inputYrs: "",
      showInputNickName: false,
      inputMonth: "",
      inputDay: "",
      passwordForm: {
        curPassword: "",
        newPassword: "",
        confirmPassword: "",
      },
      activeAccount: 0,
      addForm: {
        userName: "",
        nickName: "",
        password: "",
        confirmPassword: "",
      },
    };
  },
  beforeDestroy() {
@@ -490,6 +565,22 @@
    });
  },
  methods: {
    editNickName() {
      this.showInputNickName = true;
      this.$refs["input-nick"].focus();
    },
    hideInputNick() {
      this.showInputNickName = false;
    },
    openAccount(item, i) {
      this.$refs[`account-card`].forEach((x) => {
        x.style.backgroundColor = "rgba(248, 248, 248, 1)";
        x.style.color = "#2c3e50";
      });
      this.$refs[`account-card`][i].style.backgroundColor =
        "rgba(61, 104, 225, 1)";
      this.$refs[`account-card`][i].style.color = "#fff";
    },
    minusOne(typ) {
      this.isSyncBrowser = false;
      this.syncBrowser(false);
@@ -602,6 +693,7 @@
      }
    },
    submitClock() {
      debugger;
      if (this.syncType === "1") {
        if (this.ntpServer === "") {
          this.$notify({
@@ -612,7 +704,7 @@
        } else if (this.timeInterval === "") {
          this.timeInterval = 1;
        }
      } else {
      } else if (this.isSyncBrowser) {
        if (this.settime === "") {
          this.$notify({
            type: "error",
@@ -620,6 +712,8 @@
          });
          return false;
        }
      } else {
        this.settime = `${this.syncYrs}-${this.syncMonth}-${this.syncDay} ${this.syncHour}:${this.syncMin}:${this.syncSec}`;
      }
      let requestBody = {
        timeZone: this.timezone,
@@ -727,7 +821,7 @@
    },
    openChangePw() {},
    showAddAccount() {
      this.inAccountDetail = true;
      this.inAccountDetail = false;
      this.isAddAccount = true;
    },
    cancelAdd() {
@@ -803,11 +897,9 @@
      this.isNtp = !v;
      v && (this.syncType = "2");
      if (v) {
        [
          this.syncYrs,
          this.syncMonth,
          this.syncDay,
        ] = this.equipmentDate.split("-");
        [this.syncYrs, this.syncMonth, this.syncDay] = this.equipmentDate.split(
          "-"
        );
        [this.syncHour, this.syncMin, this.syncSec] = this.equipmentTime.split(
          ":"
        );
@@ -867,32 +959,38 @@
    border-right: 5px solid rgba(248, 248, 248, 1);
    box-sizing: border-box;
    .account-left {
      .account-list {
        height: 530px;
      }
      .add-account {
        color: rgba(61, 104, 225, 1);
        margin-top: 50px;
        .iconfont {
          cursor: pointer;
          font-size: 30px;
          font-size: 32px;
        }
      }
      .account-card {
        height: 40px;
        background-color: goldenrod;
        height: 50px;
        background-color: rgba(248, 248, 248, 1);
        margin-bottom: 10px;
        display: flex;
        align-items: center;
        padding: 0 20px;
        box-sizing: border-box;
        border-radius: 10px;
        cursor: pointer;
        .touxiang {
          height: 30px;
          width: 30px;
          background-color: green;
          height: 35px;
          width: 35px;
          background-color: bisque;
          border-radius: 17.5px;
        }
        .user-name {
          margin-left: 10px;
          font-size: 14px;
        }
      }
    }
    .datetime-left {
      .time-card {
@@ -953,28 +1051,46 @@
    .account-right {
      .account-content {
        .content-top {
          height: 150px;
          background-color: antiquewhite;
          height: 120px;
          width: 350px;
          margin: 0 auto;
          display: flex;
          align-items: center;
          justify-content: center;
          margin-bottom: 20px;
          .touxiang-big {
            width: 100px;
            height: 100px;
            background-color: indigo;
            background-color: bisque;
            border-radius: 50px;
          }
          .user-desc {
            background-color: khaki;
            height: 100px;
            width: 150px;
            display: flex;
            flex-direction: column;
            align-items: baseline;
            min-width: 200px;
            .username {
              margin: 5px 15px;
              height: 30px;
              line-height: 30px;
              width: 90px;
              text-align: left;
              font-size: 15px;
              display: flex;
              align-items: center;
            }
            .nickname {
              margin: 5px 15px;
              font-size: 14px;
              .input-nick {
                width: 50px;
                margin-right: 5px;
              }
              .iconfont {
                font-size: 14px;
                margin-left: 5px;
              }
            }
          }
        }
@@ -985,15 +1101,56 @@
          align-items: center;
          .item-btn {
            width: 500px;
            height: 50px;
            background-color: rgba(240, 240, 240, 1);
            margin-bottom: 10px;
            height: 45px;
            background-color: #f0f0f0;
            margin-bottom: 15px;
            border-radius: 10px;
            line-height: 45px;
            font-size: 15px;
            cursor: pointer;
          }
          .item-btn:hover {
            color: rgba(255, 153, 102, 1);
          }
        }
      }
      .title {
        height: 30px;
        line-height: 30px;
        /* background-color: aliceblue; */
        margin-bottom: 10px;
        font-size: 16px;
        font-weight: 600;
      }
      .change-pw {
        .p-title {
          text-align: left;
          font-size: 15px;
          margin-top: 5px;
        }
      }
      .el-form-item {
        margin-bottom: 0;
        .el-input__inner {
          background-color: rgba(240, 240, 240, 1);
          border: none;
          border-radius: 12px;
          height: 45px;
          padding: 0 20px;
          font-size: 15px;
        }
        .el-input__clear {
          color: dimgray;
          font-size: 17px;
          line-height: 45px;
        }
        .el-input__suffix {
          right: 1px;
          top: -0.5px;
          width: 45px;
          // background-color: rgba(61, 104, 225, 1);
          /* color: white; */
          border-radius: 12px;
        }
      }
      .permission {
@@ -1013,17 +1170,21 @@
      }
      .add-account-page {
        background-color: lightcyan;
        padding: 10px 50px;
        // background-color: lightcyan;
        // padding: 10px 50px;
        .upload-group {
          background-color: lightgrey;
          height: 100px;
          display: flex;
          height: 120px;
          width: 350px;
          margin: 0 auto;
          overflow: hidden;
          .upload-jpg {
            height: 40px;
            width: 40px;
            background-color: lightcoral;
            height: 50px;
            width: 50px;
            float: left;
            margin: 0 10px;
            background-color: antiquewhite;
            margin-bottom: 20px;
            border-radius: 25px;
          }
        }
        .fill-group {
@@ -1219,18 +1380,18 @@
          .middle {
            font-size: 14px;
          }
           .input-box {
                width: 80px;
                border: none;
                border-radius: 5px;
                height: 25px;
                font-size: 18px;
                text-align: center;
              }
          .input-box {
            width: 80px;
            border: none;
            border-radius: 5px;
            height: 25px;
            font-size: 18px;
            text-align: center;
          }
              .input-box:focus {
                outline: none;
              }
          .input-box:focus {
            outline: none;
          }
          .minus {
            width: 50px;
            height: 50px;
@@ -1257,12 +1418,12 @@
    .btns {
      display: flex;
      justify-content: space-between;
      margin-top: 200px;
      margin-top: 20px;
      .cancel {
        height: 40px;
        width: 48%;
        cursor: pointer;
        border-radius: 8px;
        background-color: rgba(240, 240, 240, 1);
        line-height: 40px;
@@ -1271,7 +1432,7 @@
      .ok {
        height: 40px;
        width: 48%;
        cursor: pointer;
        border-radius: 8px;
        background-color: rgba(61, 104, 225, 1);
        color: #fff;
src/pages/systemSettings/views/NetSettings.vue
@@ -428,12 +428,13 @@
  box-sizing: border-box;
  .cluster-center {
    height: 100%;
    width: 260px;
    width: 280px;
    overflow: auto;
    box-sizing: border-box;
    flex-shrink: 0;
    padding: 10px;
    background-color: lavender;
    padding: 10px;    border-right: 5px solid #f8f8f8;
    // background-color: lavender;
    .menu-item {
      background-color: #f8f8f8;
      height: 40px;
src/pages/systemSettings/views/clusterManagement.vue
@@ -594,12 +594,12 @@
  box-sizing: border-box;
  .cluster-center {
    height: 100%;
    width: 260px;
    width: 280px;
    overflow: auto;
    box-sizing: border-box;
    flex-shrink: 0;
    padding: 10px;
    background-color: lightpink;
    // background-color: lightpink;
    .menu-item {
      background-color: #f8f8f8;
      height: 40px;
src/pages/systemSettings/views/generalSettings.vue
@@ -16,54 +16,100 @@
        <div class="lang" v-if="activePage == 'basic'">
          <div class="bar" v-for="(item, i) in basioInfoList" :key="i">
            <span class="name">{{ item.name }}</span>
            <span class="name">{{ item.desc }}</span>
            <span class="desc">{{ item.desc }}</span>
          </div>
        </div>
        <div class="lang" v-if="activePage == 'video'">
          <div class="min-dur">
            <div class="title">视频截取最短时长</div>
            <div class="entity">
              <div class="sec">{{ alarmConf.min_video_len }} s</div>
              <div class="sec">{{ alarmConf.min_video_len }}s</div>
              <div class="block">
                <el-slider
                  v-model="alarmConf.min_video_len"
                  id="cut_min_duration"
                  :min="0"
                  :max="100"
                  show-input
                  :show-tooltip="false"
                >
                </el-slider>
              </div>
              <el-input-number
                v-model="alarmConf.min_video_len"
                controls-position="right"
                :min="0"
                :max="100"
                size="mini"
              ></el-input-number>
              &nbsp;s
            </div>
          </div>
          <div class="min-dur">
            <div class="title">视频截取最长时长</div>
            <div class="entity">
              <div class="sec">{{ alarmConf.max_video_len }} s</div>
              <div class="sec">{{ alarmConf.max_video_len }}s</div>
              <div class="block">
                <el-slider
                  v-model="alarmConf.max_video_len"
                  id="cut_max_duration"
                  :min="0"
                  :max="100"
                  show-input
                  :show-tooltip="false"
                >
                </el-slider>
              </div>
              <el-input-number
                v-model="alarmConf.max_video_len"
                controls-position="right"
                :min="0"
                :max="100"
                size="mini"
              ></el-input-number>
              &nbsp;s
            </div>
          </div>
          <div class="save-btn" @click="submitAlarm">保存</div>
        </div>
        <div class="lang" v-if="activePage == 'sound'">
            <div class="title">事件声音</div>
          <div class="bar" v-for="(item, i) in keyboardList" :key="i">
            <span class="name">
              <span class="icon iconfont">&#xe646;</span>{{ item.name }}</span
            >
          <div class="title">事件声音</div>
          <div
            class="bar"
            v-for="(item, i) in soundList"
            :key="i"
            @click="clickSound(item, i)"
            ref="soundBar"
          >
            <div class="left-part">
              <span class="icon iconfont">&#xe646;</span>
              <span class="name"> {{ item.name }}</span>
            </div>
            <div class="btns">
              <span class="icon iconfont">&#xe646;</span>
              <span class="icon iconfont">&#xe646;</span>
            </div>
          </div>
        <div class="add-group">
  <el-upload
            class="upload-demo"
            drag
            action="https://jsonplaceholder.typicode.com/posts/"
            multiple
            v-show="showUpload"
          >
            <i class="el-icon-upload"></i>
            <div class="el-upload__text">
              事件声音文件拖到此处,或<em>点击上传</em> <br />
              仅支持mp3/wma等格式
            </div>
          </el-upload>
          <div             v-show="!showUpload"
></div>
          <div class="add-btn">
            <span class="icon iconfont" @click="showUpload=!showUpload">&#xe646;</span>
          </div>
        </div>
        </div>
      </div>
    </div>
@@ -71,22 +117,8 @@
</template>
<script>
import {
  createSerfCluster,
  randomPwd,
  search,
  getSearchNodes,
  stopSearching,
  findCluster,
  updateClusterName,
  joinCluster,
  leave,
  getVrrp,
  setVrrp,
  createESNode,
  addESNode,
  getEsClusterInfo,
} from "@/api/clusterManage";
import { saveAlarmConfig } from "@/api/system";
import cloudNode from "../components/CloudNode";
import ipInput from "@/components/subComponents/IPInput";
import { isIPv4 } from "@/scripts/validate";
@@ -123,6 +155,7 @@
      isOpenWifi: false,
      inWireDetail: false,
      wireForm: {},
      showUpload:false,
      alarmConf: {
        min_video_len: 0,
        max_video_len: 0,
@@ -132,7 +165,7 @@
        { name: "英文", desc: "fesF" },
        { name: "繁体中文(香港)", desc: "fesF" },
      ],
      keyboardList: [{ name: "Hanyu Pinyin(algtr)" }, { name: "ENG" }],
      soundList: [{ name: "2.mp3" }, { name: "3.mp3" }],
      wireFormRules: {},
      activePage: "basic",
@@ -177,6 +210,23 @@
    checkWire(item) {
      this.inWireDetail = true;
    },
    clickSound(item, i) {
      this.$refs["soundBar"].forEach((x) => {
        x.style.backgroundColor = "rgba(248, 248, 248, 1)";
      });
      this.$refs["soundBar"][i].style.backgroundColor =
        "rgba(233, 233, 233, 1)";
    },
    submitAlarm() {
      saveAlarmConfig(this.alarmConf).then((res) => {
        if (res && res.success) {
          this.$notify({
            type: "success",
            message: "保存成功",
          });
        }
      });
    },
  },
};
</script>
@@ -194,12 +244,14 @@
  box-sizing: border-box;
  .cluster-center {
    height: 100%;
    width: 260px;
    width: 280px;
    overflow: auto;
    box-sizing: border-box;
    flex-shrink: 0;
    padding: 10px;
    background-color: lavender;
    border-right: 5px solid #f8f8f8;
    // background-color: lavender;
    .menu-item {
      background-color: #f8f8f8;
      height: 40px;
@@ -254,32 +306,88 @@
      max-width: none !important;
    }
    .lang {
      .title {
        height: 35px;
        line-height: 35px;
        font-size: 16px;
        text-align: left;
        margin-bottom: 5px;
      }
      .bar {
        height: 50px;
        background-color: aliceblue;
        background-color: rgba(248, 248, 248, 1);
        border-radius: 10px;
        line-height: 50px;
        box-sizing: border-box;
        padding: 0 20px;
        padding: 0 30px 0 20px;
        display: flex;
        justify-content: space-between;
        margin-bottom: 10px;
        cursor: pointer;
        .left-part {
          .icon {
            color: rgba(191, 191, 191, 1);
            font-size: 16px;
            margin-right: 5px;
          }
        }
        .name {
          font-size: 15px;
        }
        .btns {
          width: 50px;
          display: flex;
          justify-content: space-between;
          color: rgba(191, 191, 191, 1);
        }
        .desc {
          font-size: 14px;
          color: rgba(134, 134, 134, 1);
        }
      }
      .bar:hover {
        background-color: rgba(233, 233, 233, 1);
      }
      .add-group{
      margin-top: 170px;
    height: 235px;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
      }
      .upload-demo {
        .el-upload-dragger {
          width: 290px;
        }
      }
      .add-btn {
        height: 40px;
        line-height: 40px;
        margin-top: 10px;
        .icon {
          font-size: 30px;
          color: rgba(61, 104, 225, 1);
        }
      }
      .min-dur {
        box-sizing: border-box;
        padding: 0 10px;
        padding: 0 20px;
        background-color: rgba(248, 248, 248, 1);
        height: 100px;
        height: 95px;
        margin-bottom: 20px;
        border-radius: 15px;
        .title {
          height: 50px;
          line-height: 50px;
          height: 45px;
          line-height: 45px;
          text-align: left;
          box-sizing: border-box;
          padding: 0 10px;
          padding: 0 6px;
          font-size: 14px;
        }
      }
      .entity {
        display: flex;
        align-items: center;
@@ -288,10 +396,47 @@
        .sec {
          min-width: 30px;
          line-height: 80px;
          margin-right: 15px;
          margin-right: 10px;
          color: rgba(120, 120, 120, 1);
          font-size: 14px;
        }
        .block {
          flex: auto;
          flex: 1;
          margin: 0 20px 0 6px;
        }
        .el-input-number--mini {
          width: 80px;
        }
        .el-input-number.is-controls-right[class*="mini"] [class*="increase"],
        .el-input-number.is-controls-right[class*="mini"] [class*="decrease"] {
          width: 23px;
        }
        .el-input-number.is-controls-right .el-input__inner {
          padding-left: 13px;
          padding-right: 37px;
        }
        #cut_min_duration {
          .el-slider__bar {
            background-color: #3d68e1;
          }
          .el-slider__button-wrapper .el-tooltip {
            width: 18px;
            height: 18px;
            border: 4px solid #3d68e1;
            box-sizing: border-box;
          }
        }
        #cut_max_duration {
          .el-slider__bar {
            background-color: #ff9e6e;
          }
          .el-slider__button-wrapper .el-tooltip {
            width: 18px;
            height: 18px;
            border: 4px solid #ff9e6e;
            box-sizing: border-box;
          }
        }
      }
    }
src/pages/systemSettings/views/keyboardLanguage.vue
@@ -152,12 +152,13 @@
  box-sizing: border-box;
  .cluster-center {
    height: 100%;
    width: 260px;
    width: 280px;
    overflow: auto;
    box-sizing: border-box;
    flex-shrink: 0;
    padding: 10px;
    background-color: lavender;
    padding: 10px;    border-right: 5px solid #f8f8f8;
    // background-color: lavender;
    .menu-item {
      background-color: #f8f8f8;
      height: 40px;
src/pages/vindicate/index/App.vue
@@ -293,6 +293,7 @@
          startTime: showStartTime,
          endTime: showEndTime
        }
          debugger
        deleteDate(param).then(resp => {
          if (resp.success) {
            this.$message({