hanbaoshan
2020-07-29 0876e51d0f968ce38a048a78f9ebafcb8841f9bc
添加系统维护
2个文件已添加
3个文件已修改
652 ■■■■ 已修改文件
package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/settings/components/BasicSetting.vue 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/settings/index/App.vue 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/vindicate/index/App.vue 515 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/vindicate/index/main.ts 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json
@@ -14,6 +14,7 @@
    "echarts": "^4.8.0",
    "element-ui": "^2.13.2",
    "less-loader": "^6.2.0",
    "moment": "^2.27.0",
    "pug": "^3.0.0",
    "pug-plain-loader": "^1.0.0",
    "qs": "^6.9.4",
src/pages/settings/components/BasicSetting.vue
@@ -5,6 +5,7 @@
      v-model="activeName"
      v-loading="loading"
      :element-loading-text="loadingText"
      type="card"
    >
      <!-- 本机信息 -->
      <el-tab-pane label="本机信息" name="first">
@@ -17,6 +18,7 @@
          class="menu-css"
          @open="menuOpen"
          @close="menuClose"
        >
          <!-- 本机信息 -->
          <el-submenu index="0">
@@ -351,34 +353,25 @@
        <cluster-management></cluster-management>
      </el-tab-pane>
      <el-tab-pane label="外部网络" name="fourth">
        <el-row :gutter="20">
          <el-col :span="10">
            <div>
              <div class="flex-box">
                <div style="line-height:32px;">
                  <el-radio v-model="ipServer.diyOrLocalIP" :label="1">设置外部IP</el-radio>
                  <el-radio v-model="ipServer.diyOrLocalIP" :label="0">选用本机IP</el-radio>
                </div>
                <div class="ml10" style="width:205px;">
                  <ip-input :ip="ipServer.ip" @on-blur="ipServer.ip = arguments[0]"></ip-input>
                </div>
              </div>
              <div class="flex-box p5" >
                <span style="line-height:32px;">域名</span>
                <div style="margin-left:14px;width:205px;">
                  <el-input size="small" style v-model="ipServer.localhost"></el-input>
                </div>
              </div>
              <div class="flex-box" >
                <span style="line-height:32px;">本地文件端口</span>
                <div style="margin-left:14px;width:205px;">
                  <el-input size="small" style v-model="ipServer.localFilePort"></el-input>
                </div>
              </div>
            </div>
          </el-col>
          <!-- <el-col :span="14">
            <div>
        <div class="flex-box">
          <label>设置外部IP</label>
          <div style="width:300px;">
            <ip-input :ip="ipServer.ip" @on-blur="ipServer.ip = arguments[0]"></ip-input>
          </div>
          <el-checkbox label="选用本机IP" size="small" style="margin-left: 20px"></el-checkbox>
        </div>
        <div class="flex-box">
          <label>域名</label>
          <el-input size="small"  v-model="ipServer.localhost"></el-input>
        </div>
        <div class="flex-box">
          <label>本地文件端口</label>
          <el-input size="small"  v-model="ipServer.localFilePort"></el-input>
        </div>
        <div class="mt15 save-btn" style="width:460px; margin-bottom:20px; float:left;">
          <el-button type="primary" @click="submitResource" size="small">保存</el-button>
        </div>
        <div>
              <el-table
                :data="ipServer.fileTable"
                border
@@ -416,11 +409,6 @@
                </el-table-column>
              </el-table>
            </div>
          </el-col>-->
        </el-row>
        <div class="mt15 save-btn" style="width:1000px;float:left;">
          <el-button type="primary" @click="submitResource" size="small">保存</el-button>
        </div>
      </el-tab-pane>
      <el-tab-pane label="权限管理" name="user" >
        <authority-management v-if="activeName === 'user'"></authority-management>
@@ -1088,7 +1076,7 @@
  height: 100%;
  .el-form {
    width: 1000px;
    margin-top: 30px;
    // margin-left: -80px;
    .el-form-item {
      text-align: left;
@@ -1148,49 +1136,7 @@
    font-weight: 600;
    background-color: #e4e6ed;
  }
  #e-basic-setting {
    .el-tabs__header {
      border: 0px solid #dcdfe6;
      .el-tabs__item {
        padding: 5px 50px;
        height: 50px;
        font-family: PingFangSC-Regular;
        font-size: 14px;
        color: #222222;
        text-align: center;
        border: 0px solid transparent;
      }
      .el-tabs__item:nth-child(2) {
        padding-left: 50px;
      }
      .el-tabs__item:last-child {
        padding-right: 50px;
      }
      .el-tabs__item.is-active {
        color: #ff7733;
        font-weight: bold;
        // border-right-color: #fff;
        // border-left-color: #fff;
      }
      .el-tabs__item:not(.is-disabled):hover {
        color: #ff7733;
      }
    }
    .el-tabs__active-bar {
      background-color: #ff7733;
    }
    .xiangqin-label {
      text-align: left;
      width: 85px;
      font-size: 14px;
      line-height: 30px;
    }
    .xiangqing-info {
      text-align: left;
      font-size: 14px;
      line-height: 30px;
    }
  }
  #cut_min_duration {
    .el-slider__bar {
@@ -1272,6 +1218,16 @@
}
</style>
<style lang="scss" scoped>
.flex-box{
  display: flex;
  height: 50px;
  label{
    width: 120px;
  }
  .el-input{
    width: 300px;
  }
}
.menu-css,
.el-menu {
  border-right: none;
@@ -1280,7 +1236,7 @@
  margin: 0;
  padding-left: 0;
  background-color: #ffffff;
  .tree-font {
    font-family: PingFangSC-Medium;
    font-size: 14px;
src/pages/settings/index/App.vue
@@ -74,7 +74,7 @@
  width: 100% !important;
  box-sizing: border-box;
  padding: 10px;
  background-color: #e9ebf2;
  background-color: #f8f9fb;
  .s-system-manage-breadcrumb {
    height: 5%;
    box-sizing: border-box;
@@ -107,7 +107,7 @@
      }
      .el-tabs__item.is-active {
        color: #3d68e1;
        font-weight: bold;
        // border-right-color: #fff;
        // border-left-color: #fff;
      }
@@ -116,12 +116,15 @@
      }
    }
  }
  .el-tabs__header{
    margin-bottom: 0;
  }
  .el-tabs__content {
    height: calc(100% - 64px);
    width: calc(100% - 20px);
    box-sizing: border-box;
    overflow-y: auto;
    padding: 10px 40px !important;
    padding: 20px 40px !important;
    background: #fff;
    .el-tab-pane {
      width: 100%;
      .s-title {
src/pages/vindicate/index/App.vue
New file
@@ -0,0 +1,515 @@
<template>
    <el-tabs
      id="systemMaintenance"
      v-model="activeName"
      v-loading="loading"
      :element-loading-text="loadingText"
    >
      <el-tab-pane label="设备维护" name="first" >
        <div class="s-system-maintenance">
        <div class="box-card">
          <div class="ui-top-view">
            <div class="ui-top-title">重启</div>
          </div>
          <el-divider></el-divider>
          <div class="box-card-content">
                <el-button type="primary" size="small" style="width:80px" @click="reboot">重启</el-button>
                <b class="card-text">重启节点</b>
            <el-row style="margin-top:20px">
              <el-col>
                <vue-cron :expression="rebootCron" @update="setRebootCron" />
              </el-col>
            </el-row>
          </div>
        </div>
        <!--
        <div class="box-card">
          <div class="ui-top-view">
            <div class="ui-top-title">恢复默认值</div>
          </div>
          <el-divider></el-divider>
          <div class="box-card-content">
            <el-row>
              <el-col :span="1">
                <el-button type="primary" size="small">简单恢复</el-button>
              </el-col>
              <el-col :span="23">
                <b class="card-text">简单恢复设备参数</b>
              </el-col>
            </el-row>
            <el-row style="margin-top:20px">
              <el-col :span="1">
                <el-button type="primary" size="small">完全恢复</el-button>
              </el-col>
              <el-col :span="23">
                <b class="card-text">完全恢复设备参数到出厂设置</b>
              </el-col>
            </el-row>
          </div>
        </div>
        <div class="box-card">
          <div class="ui-top-view">
            <div class="ui-top-title">参数导入导出</div>
          </div>
          <el-divider></el-divider>
          <div class="box-card-content">
            <el-row :gutter="4">
              <el-col :span="1">
                <el-button type="info" size="small" style="width:80px">导入</el-button>
              </el-col>
              <el-col :span="3" style="padding-left:30px">
                <el-input placeholder="上传参数文件" size="small" :readonly="true">
                  <el-upload slot="suffix" action="https://jsonplaceholder.typicode.com/posts/">
                    <el-button
                      type="text"
                      icon="el-icon-upload2"
                      size="small"
                      style="font-size:18px; color:#0088ff"
                    ></el-button>
                  </el-upload>
                </el-input>
              </el-col>
            </el-row>
            <el-row style="margin-top:20px">
              <el-col :span="1">
                <el-button type="primary" size="small">设备参数</el-button>
              </el-col>
              <el-col :span="23">
                <b class="card-text">参数导出</b>
              </el-col>
            </el-row>
          </div>
        </div>
        -->
        <div class="box-card">
          <div class="ui-top-view">
            <div class="ui-top-title">升级</div>
          </div>
        </div>
        <el-divider></el-divider>
        <div class="box-card-content">
          <el-row :gutter="4">
            <el-col :span="6">
              <file-uploader
                single
                uploadPlaceholder="上传升级文件"
                url="/data/api-v/sysset/patchUpdate"
                @complete="onFileUpload"
                @file-added="onFileAdded"
              />
            </el-col>
            <el-col :span="2">
              <el-button
                type="primary"
                size="small"
                style="width:80px"
                @click="upgrade"
                :disabled="!fileAdded"
                :loading="upgrading"
              >升级</el-button>
            </el-col>
            <el-col :span="16" class="upload-msg">
              <span v-html="patchUpdateStatus"></span>
            </el-col>
          </el-row>
        </div>
      </div>
      </el-tab-pane>
      <el-tab-pane label="数据库维护" name="second" >
        <div class="box">
          <p class="title">
            <label>数据清理</label>
          </p>
          <div class="range">
            <div class="left">
              <p>选择数据范围:</p>
            </div>
            <div class="middle">
              <el-date-picker
                v-model="dataRange"
                type="daterange"
                range-separator="至"
                start-placeholder="开始日期"
                end-placeholder="结束日期"
                style="height:38px"
                :picker-options="pickerOptions"
              ></el-date-picker>
            </div>
            <div class="right">
              <el-button @click="deleteData" style="height:38px;background:#ff0000;color:white">删除数据</el-button>
            </div>
          </div>
          <div class="tip">
            <i class="iconfont icontishi-zhuyi"></i>
            <p class="zhuyi">请注意,按以上日期范围删除的数据不可恢复,立即生效,请谨慎操作</p>
          </div>
        </div>
      </el-tab-pane>
    </el-tabs>
</template>
<script>
import { rebootServer, getDevInfo, getRebootTask, setRebootTask, fileUpload, doUpgrade,deleteDate } from "@/api/system"
import VueCron from "@/components/subComponents/VueCron"
import FileUploader from "@/components/subComponents/FileUpload/index"
export default {
  components: {
    VueCron,
    FileUploader
  },
  data() {
    return {
      timer: null,
      buttonAuthority: sessionStorage.getItem("buttonAuthoritys") || [],
      rebootCron: "",
      activeName: "first",
      restartValue: "不重启",
      restartTimeValue: new Date(2019, 9, 10, 18, 40),
      loading: false,
      loadingText: '',
      probeSum: 0,
      patchUpdateStatus: "",
      dataRange: [
        this.$moment().format("YYYY-MM-DD HH:mm:ss"),
        this.$moment().format("YYYY-MM-DD HH:mm:ss")
      ],
      fileUploadUrl: fileUpload,
      patchFile: {},
      pickerOptions: {
        disabledDate(time) {
          var day = new Date()
          day.setTime(day.getTime() - 24 * 60 * 60 * 1000)
          return time.getTime() > day;
        },
      },
      upgrading: false,
      fileAdded: false
    };
  },
  mounted() {
    this.getRebootCron()
    if (!this.isShow('videoSystem:sysManage:sysfix')) {
      console.log("默认显示数据库维护")
      this.activeName = "second"
    }
  },
  computed: {
    isAdmin() {
      if (
        sessionStorage.getItem('userInfo') &&
        sessionStorage.getItem('userInfo') !== ''
      ) {
        let loginName = JSON.parse(sessionStorage.getItem('userInfo')).username
        return (
          loginName === 'superadmin' || loginName === 'basic'
        )
      }
      return false;
    }
  },
  methods: {
    isShow (authority) {
      if (this.isAdmin) {
        return true
      } else if (
        this.buttonAuthority.indexOf(',' + authority + ',') > -1
      ) {
        return true
      } else {
        return false
      }
    },
    format(array) {
      return [
        this.$moment(array[0]).format("YYYY-MM-DD"),
        this.$moment(array[1]).format("YYYY-MM-DD")
      ];
    },
    getRebootCron() {
      getRebootTask().then(rsp => {
        this.rebootCron = rsp.data
      })
    },
    setRebootCron(value) {
      this.rebootCron = value
      setRebootTask({ task: value }).then(rsp => {
        if (rsp && rsp.success) {
          this.$notify({
            type: "success",
            message: "配置成功"
          })
        }
      }).catch(err => {
        this.$notify({
          type: "error",
          message: "配置失败"
        })
      })
    },
    reboot() {
      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)
          }
        })
      })
    },
    deleteData() {
      var timeRange = this.format(this.dataRange);
      var showStartTime = timeRange[0]
      var showEndTime = timeRange[1]
      console.log("时间:",showStartTime,showEndTime)
      this.$confirm("提示:"+showStartTime+" 至 "+showEndTime+" 产生的全部数据将被删除,此操作立即生效,不可恢复,是否删除?", {
        center: true,
        cancelButtonClass: "comfirm-class-cancle",
        confirmButtonClass: "comfirm-class-sure"
      }).then(() => {
        this.loading = true
        this.loadingText = "正在删除数据,请稍候!"
        var param = {
          startTime: showStartTime,
          endTime: showEndTime
        }
        deleteDate(param).then(resp => {
          if (resp.success) {
            this.$message({
              type: "success",
              message: "删除数据成功"
            })
            this.loading = false
          }
        }).catch(err => {
          this.$message({
            type: "error",
            message: "删除数据失败!"
          })
          this.loading = false
        })
      }).catch(() => {
        console.log("取消了!")
      })
    },
    reLogin() {
      this.$router.push("/")
    },
    probeServer(callback) {
      this.probeSum++;
      let _this = this
      if (this.probeSum > 60) {
        this.$confirm('连接服务器失败, 请刷新页面或联系管理员', '失败', {
          type: 'error',
          cancelButtonClass: 'comfirm-class-cancle',
          confirmButtonClass: 'comfirm-class-sure'
        }).then(() => {
          // _this.$router.push("/")
          callback()
        })
        return
      }
      this.timer = setTimeout(() => {
        getDevInfo().then(() => {
          // _this.$router.push("/")
          callback()
        }).catch(err => {
          _this.probeServer(callback)
        })
      }, 10000)
    },
    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()
      })
    }
  }
};
</script>
<style lang="scss">
.s-system-maintenance {
  width: 100%;
  height: 100%;
  .box-card {
    text-align: left;
    height: auto;
    margin: 10px 0px;
    .box-card-content {
      padding-bottom: 40px;
      .card-text {
        padding: 0 30px;
        line-height: 32px;
      }
    }
  }
  .upload-icon {
    font-size: 18px;
    color: #0088ff;
  }
  .upload-msg {
    padding-left: 10px;
    text-align: left;
    span {
      line-height: 32px;
      font-size: 13px;
    }
  }
}
.box{
  width: 50%;
  min-width: 700px;
  height: 270px;
  border: 1px solid #eee;
  .title {
    font-size:20px;
    font-weight: bold;
    text-align: left;
    padding: 20px;
    border-bottom: 1px solid #eee;
  }
  .range {
    width: 100%;
    padding-top: 30px;
    height: 38px;
    .left {
      width: 120px;
      float: left;
      text-align: right;
      font-size: 14px;
      p {
        height: 38px;
        line-height: 38px;
        margin: 0;
      }
    }
    .middle {
      width: 50%;
      min-width: 400px;
      height: 38px;
      float: left;
    }
    .right {
      width: 20%;
      height: 38px;
      float: left;
    }
  }
  .tip {
    width: 100%;
    padding: 30px 0px 0px 30px;
    height: 34px;
    .zhuyi {
      font-size: 14px;
      height: 34px;
      line-height: 34px;
      margin-left: 20px;
      float: left;
    }
    i {
      font-size: 32px;
      color: #e99038;
      float: left;
    }
  }
}
#systemMaintenance{
  .el-tabs__header {
      border: 0px solid #dcdfe6;
      .el-tabs__item {
        padding: 5px 50px;
        height: 50px;
        font-family: PingFangSC-Regular;
        font-size: 14px;
        color: #222222;
        text-align: center;
        border: 0px solid transparent;
      }
      .el-tabs__item:nth-child(2) {
        padding-left: 50px;
      }
      .el-tabs__item:last-child {
        padding-right: 50px;
      }
      .el-tabs__item.is-active {
        color: #ff7733;
        font-weight: bold;
        // border-right-color: #fff;
        // border-left-color: #fff;
      }
      .el-tabs__item:not(.is-disabled):hover {
        color: #ff7733;
      }
  }
  .el-tabs__active-bar {
    background-color: #ff7733;
  }
  .el-tabs__content {
    padding-left: 15px !important;
  }
}
</style>
src/pages/vindicate/index/main.ts
New file
@@ -0,0 +1,13 @@
import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import moment from 'moment';
import App from './App.vue'
Vue.use(ElementUI)
Vue.prototype.$moment = moment;
new Vue({
  el: '#app',
  render: h => h(App)
})