Quellcode durchsuchen

对接工作站设置

林旭祥 vor 7 Monaten
Ursprung
Commit
3701aa321f

+ 37 - 1
src/api/module/common.ts

@@ -94,7 +94,7 @@ export default {
     });
   },
 
-  //关闭工作站
+  //下课
   closeExamForce: (data: any) => {
     return req({
       url: '/school/close_exam_force',
@@ -103,6 +103,42 @@ export default {
     });
   },
 
+  //关闭工作站
+  stopGpu: (data: any) => {
+    return req({
+      url: '/school/stop_gpu',
+      method: 'post',
+      data: data
+    });
+  },
+
+  //重启工作站
+  restartGpu: (data: any) => {
+    return req({
+      url: '/school/restart_gpu',
+      method: 'post',
+      data: data
+    });
+  },
+
+  //重启后获取工作站状态
+  checkWkState: (data: any) => {
+    return req({
+      url: '/school/check_wk_state',
+      method: 'post',
+      data: data
+    });
+  },
+
+  //关闭LED
+  closeLedScreen: (data: any) => {
+    return req({
+      url: '/school/close_led_screen',
+      method: 'post',
+      data: data
+    });
+  },
+
   //测试手势
   cmdtest: (data: any) => {
     return req({

+ 21 - 0
src/assets/styles/index.scss

@@ -49,6 +49,7 @@ ul li {
     }
   }
 }
+
 .messageBoxClass {
   background: radial-gradient(96% 96% at 2% 32%, #ffffff 0%, #fcfdfd 54%, #e1e4e7 100%);
   width: 40% !important;
@@ -95,6 +96,26 @@ ul li {
   }
 }
 
+.close {
+  width: 3.2rem;
+  height: 3.2rem;
+  box-sizing: border-box;
+  border: 1px solid #979797;
+  background-image: url('@/assets/images/common/close.png');
+  background-position: center;
+  background-repeat: no-repeat;
+  background-size: 45% 45%;
+  background-color: rgba(216, 216, 216, 0.8);
+  border-radius: 50%;
+  transition: all 0.5s;
+  cursor: pointer;
+
+  &:hover {
+    transform: rotate(180deg);
+    background-color: rgba(216, 216, 216, 1);
+  }
+}
+
 .basketballv1 {
   .el-loading-spinner {
     &::before {

+ 551 - 0
src/components/AddItemWindow/index.vue

@@ -0,0 +1,551 @@
+<template>
+  <div>
+    <Transition :enter-active-class="proxy?.animate.mask.enter" :leave-active-class="proxy?.animate.mask.leave">
+      <div class="mask" v-if="optionWindow.show"></div>
+    </Transition>
+    <Transition :enter-active-class="proxy?.animate.dialog.enter" :leave-active-class="proxy?.animate.dialog.leave">
+      <div class="optionWindow" v-if="optionWindow.show">
+        <div class="box">
+          <div class="top">
+            <div class="close" @click="close"></div>
+          </div>
+          <div class="content">
+            <div class="areaBox">
+              <div class="content-title content-title2">
+                {{ project.key !== 'skiprope' ? '测试区域' : '设备组' }}
+              </div>
+              <div class="testAreaChooseRoll">
+                <div class="li" v-for="(item, index) in areaList"
+                  :class="{ 'select': chooseArea.includes(item.key), 'ing': item.value != '0' }" :key="index"
+                  @click="getChooseArea(item)">
+                  <div>{{ item.name }}</div>
+                </div>
+              </div>
+              <div @click="getAllArea" class="allBtn" :class="{ 'active': chooseAllState }">{{ chooseAllState ? '重 置' :
+                '全 选' }}</div>
+            </div>
+            <!-- <div class="standardBox">
+              <div class="content-title content-title2">评分标准</div>
+              <div class="standardBoxBtn">
+                <div v-for="(item, index) in standardList" :class="{ 'select': optionForm.standard == item.value }"
+                  :key="index" class="li" @click="getChooseStandard(item)">
+                  <div>{{ item.label }}</div>
+                </div>
+              </div>
+            </div> -->
+            <div class="switchList">
+              <div class="li">
+                <span>举右手识别</span>
+                <el-switch v-model="optionForm.gesture" :active-value="true" :inactive-value="false"
+                  style="--el-switch-on-color: #08FFA9; --el-switch-off-color: #ACACAC" />
+              </div>
+              <div class="li" v-if="project.key.slice(0, 3) != 'run'">
+                <span>体验模式</span>
+                <el-switch v-model="optionForm.demo" :active-value="1" :inactive-value="0"
+                  style="--el-switch-on-color: #08FFA9; --el-switch-off-color: #ACACAC" />
+              </div>
+              <div class="li" v-if="['skiprope'].includes(project.key)">
+                <span>接收心率</span>
+                <el-switch v-model="optionForm.hasHB" :active-value="true" :inactive-value="false"
+                  style="--el-switch-on-color: #08FFA9; --el-switch-off-color: #ACACAC" />
+              </div>
+            </div>
+            <div v-if="['heartbeat'].includes(project.key)">
+              <div>设置运动量目标</div>
+              <div>
+                平均心率:
+                <div style="display: flex;">
+                  <el-input v-model="optionForm.standHBL" />
+                  ~
+                  <el-input v-model="optionForm.standHBH" />
+                </div>
+              </div>
+              <div>
+                预警心率:
+                <div>
+                  <el-input v-model="optionForm.highHB" size="small" />
+                </div>
+              </div>
+            </div>
+            <div class="switchList">
+              <div class="li" v-if="['jumprope', 'jumpingjack', 'situp'].includes(project.key)">
+                <span>时长</span>
+                <el-select v-model="optionForm.time" :popper-append-to-body="false" placeholder="请选择">
+                  <el-option v-for="item in timeList" :key="item.value" :label="item.label" :value="item.value" />
+                </el-select>
+              </div>
+              <div class="li" v-if="['jumprope', 'jumpingjack', 'situp'].includes(project.key)">
+                <span>音乐</span>
+                <el-select v-model="optionForm.music" :popper-append-to-body="false" placeholder="请选择" clearable>
+                  <el-option v-for="item in musicList" :key="item.id" :label="item.name" :value="item.url" />
+                </el-select>
+              </div>
+            </div>
+          </div>
+          <div class="bottom">
+            <div class="btn" @click="confirm">
+              <el-icon class="is-loading" v-if="loading">
+                <Loading />
+              </el-icon>
+              <div>确 定</div>
+            </div>
+          </div>
+          <div class="boxBg" :style="{ backgroundImage: 'url(static/images/train/' + project.key + '.png)' }">
+          </div>
+        </div>
+      </div>
+    </Transition>
+  </div>
+
+</template>
+<script setup lang="ts">
+import useAppStore from '@/store/modules/app';
+const { proxy } = getCurrentInstance() as any;
+const router = useRouter();
+
+//父值
+const props = defineProps({
+  projectList: {
+    type: Array as any,
+    default: () => []
+  },
+});
+
+//评分标准,数据字典无需双向绑定
+const standardList = [{ label: '考试', value: 0 }, { label: '体测', value: 1 }]
+
+//时长选择,数据字典无需双向绑定
+const timeList =
+  [{
+    label: '10秒',
+    value: 10
+  }, {
+    label: '20秒',
+    value: 20
+  }, {
+    label: '30秒',
+    value: 30
+  }, {
+    label: '1分钟',
+    value: 60
+  }, {
+    label: '2分钟',
+    value: 120
+  }, {
+    label: '3分钟',
+    value: 180
+  }, {
+    label: '5分钟',
+    value: 300
+  }];
+
+const data = reactive<any>({
+  optionForm: {
+    gesture: true,
+    standard: 0
+  },
+  optionWindow: {
+    show: false,
+    time: "",
+  },
+  project: {},
+  musicList: [],
+  classList: [],
+  chooseArea: [],
+  chooseAllState: false,
+  loading: false,
+});
+
+const { optionForm, optionWindow, project, musicList, classList, chooseArea, chooseAllState, loading } = toRefs(data);
+
+//打开
+const open = (data: any) => {
+  console.log("data", data);
+  getClass();
+  getMusic();
+  project.value = data;
+  chooseArea.value = [];
+  optionWindow.value.show = true;
+};
+
+//关闭
+const close = () => {
+  optionWindow.value.show = false;
+};
+
+//筛选测试区
+const areaList = computed(() => {
+  let area = [];
+  let list = props.projectList.filter((item: any) => {
+    return item.key == project.value.key;
+  })
+  if (list.length > 0) {
+    area = list[0].area;
+  }
+  //console.log("area", area)
+  return area;
+});
+
+//获取音乐
+const getMusic = () => {
+  const list: any = useAppStore().getMusic();
+  if (list.length) {
+    musicList.value = list;
+  } else {
+    proxy?.$http.train.musicList().then((res: any) => {
+      if (res.data.length > 0) {
+        let myList: any = res.data;
+        musicList.value = myList;
+        useAppStore().setMusic(myList);
+      }
+    });
+  }
+
+};
+
+//获取班级列表
+const getClass = () => {
+  const list: any = useAppStore().getClass();
+  if (list.length) {
+    classList.value = list;
+  } else {
+    let params = {
+      page: 1,
+      per_page: 9999,
+    };
+    proxy?.$http.common.classList(params).then((res: any) => {
+      if (res.data.length > 0) {
+        let myList: any = res.data;
+        classList.value = myList;
+        useAppStore().setClass(myList);
+      }
+    });
+  }
+};
+
+//选择测试区
+const getChooseArea = (data: any) => {
+  if (chooseArea.value.length > 10) {
+    optionForm.value.gesture = false;
+  } else {
+    optionForm.value.gesture = true;
+  }
+  let id = data.key;
+  let inData = chooseArea.value.includes(id);
+  if (inData) {
+    //已存在就移除
+    chooseArea.value = chooseArea.value.filter((item: any) => {
+      return item != id
+    })
+  } else {
+    //不存在就点选
+    chooseArea.value.push(id);
+  }
+};
+
+//选择测试标准
+const getChooseStandard = (data: any) => {
+  optionForm.value.standard = data.value;
+};
+
+//全选或全取消测试区
+const getAllArea = (data: any) => {
+  chooseAllState.value = !chooseAllState.value;
+  if (chooseAllState.value) {
+    //全选
+    chooseArea.value = areaList.value.filter((item: any) => {
+      return item.value == 0;
+    }).map((item: any) => {
+      return item.key;
+    })
+  } else {
+    //全取消
+    chooseArea.value = [];
+  }
+};
+
+//确定
+const confirm = (data: any) => {
+  optionForm.value.project = project.value.key;
+  optionForm.value.classes = classList.value.map((item: any) => { return item.id; }).join();
+  optionForm.value.area = chooseArea.value.join();
+  console.log("optionForm", optionForm.value);
+  if (!optionForm.value.classes) {
+    getClass();
+    let message = "没有班级,将重新加载班级请重新操作";
+    ElMessage({ message: message, type: 'error', duration: 3 * 1000 });
+    return false;
+  }
+  if (!optionForm.value.area) {
+    let message = "请选择测试区";
+    ElMessage({ message: message, type: 'error', duration: 3 * 1000 });
+    return false;
+  }
+  if (optionForm.value.standard == null) {
+    let message = "请选择评分标准";
+    ElMessage({ message: message, type: 'error', duration: 3 * 1000 });
+    return false;
+  }
+  loading.value = true;
+  if (chooseArea.value.length > 1) {
+    //多区域
+    router.push({ path: '/train/multiple', query: optionForm.value });
+  }
+  else if (["run50", "run70", "run100", "run200", "run400", "run800", "run1000", "run15x4", "run10x4", "run50x8"].includes(project.value.key)) {
+    //跑步项目
+    router.push({ path: '/train/run', query: optionForm.value });
+  } else {
+    //单项
+    router.push({ path: '/train/test', query: optionForm.value });
+  }
+};
+
+onMounted(() => {
+})
+
+onBeforeUnmount(() => {
+  loading.value = false;
+})
+
+//暴露给父组件用
+defineExpose({
+  open,
+  close,
+  optionWindow
+})
+</script>
+<style lang="scss" scoped>
+.mask {
+  position: fixed;
+  height: 100vh;
+  width: 100vw;
+  top: 0;
+  left: 0;
+  background: rgba(0, 0, 0, 0.78);
+  z-index: 998;
+}
+
+.optionWindow {
+  position: fixed;
+  height: 100vh;
+  width: 100vw;
+  top: 0;
+  left: 0;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  color: #FFFFFF;
+  z-index: 999;
+
+  .box {
+    width: 50%;
+    border-radius: 1.6rem;
+    background: linear-gradient(46deg, #092941 -83%, #2A484B 95%);
+    box-shadow: inset 0px 1px 0px 2px rgba(255, 255, 255, 0.2);
+    position: relative;
+
+    .top {
+      color: #ffffff;
+      display: flex;
+      justify-content: flex-end;
+      position: relative;
+      z-index: 2;
+    }
+
+    .content {
+      max-height: 65vh;
+      margin-bottom: 2vh;
+      position: relative;
+      z-index: 2;
+
+      .content-title {
+        font-size: 1.65rem;
+        display: flex;
+        justify-content: center;
+      }
+
+      .content-title2 {
+        padding: 0 0 2.5vh 0;
+      }
+
+      .areaBox {
+        padding-bottom: 2vh;
+        text-align: center;
+
+        .testAreaChooseRoll {
+          width: 100%;
+          max-height: 30vh;
+          overflow-y: scroll;
+          display: flex;
+          flex-wrap: wrap;
+          justify-content: center;
+          padding: 0 20px 0 30px;
+          box-sizing: border-box;
+          margin-bottom: 5px;
+
+          .li {
+            border: 3px solid #979797;
+            color: #ffffff;
+            font-size: 1.6rem;
+            margin: 0 8px 16px 8px;
+            padding: 5px 8px;
+            min-width: 2.6rem;
+            border-radius: 4px;
+            font-weight: bold;
+            text-align: center;
+            cursor: pointer;
+          }
+
+          .select {
+            border: 3px solid #ffffff;
+            background: #ffffff;
+            color: #1A293A;
+          }
+
+          .ing {
+            border: 3px solid #ff0000;
+            color: #ff0000;
+          }
+
+          &::-webkit-scrollbar {
+            width: 10px;
+          }
+
+          &::-webkit-scrollbar-thumb {
+            border-width: 2px;
+            border-radius: 4px;
+            border-style: dashed;
+            border-color: transparent;
+            background-color: rgba(26, 62, 78, 0.9);
+            background-clip: padding-box;
+          }
+
+          &::-webkit-scrollbar-button:hover {
+            border-radius: 6px;
+            background: rgba(26, 62, 78, 1);
+          }
+
+        }
+
+        .allBtn {
+          display: inline;
+          margin: 0 auto;
+          cursor: pointer;
+        }
+      }
+
+      .standardBox {
+        padding: 2.5vh 0;
+
+        .standardBoxBtn {
+          display: flex;
+          width: 42%;
+          height: 3.6rem;
+          line-height: 3.6rem;
+          font-size: 1.65rem;
+          margin: 0 auto;
+          border-radius: 1.8rem;
+          font-size: 2rem;
+          text-align: center;
+          color: #1A293A;
+          background: #ACACAC;
+          overflow: hidden;
+
+          .li {
+            width: 50%;
+            text-align: center;
+            cursor: pointer;
+          }
+
+          .select {
+            border-radius: 1.8rem;
+            box-shadow: inset 0px 1px 0px 2px rgba(255, 255, 255, 0.5577);
+            background: radial-gradient(50% 181% at 163% 0%, #35FFC6 0%, #00FFE8 100%);
+          }
+        }
+      }
+
+
+      .switchList {
+        padding: 2.5vh 0;
+        display: flex;
+        justify-content: center;
+
+        .li {
+          display: flex;
+          align-items: center;
+          margin: 0 2rem;
+
+          span {
+            font-size: 1.65rem;
+            margin-right: 8px;
+            flex-shrink: 0;
+          }
+
+          .el-select {
+            width: 100px;
+          }
+        }
+      }
+
+
+    }
+
+    .bottom {
+      height: 3.59rem;
+      padding: 2.5rem 0;
+      align-items: center;
+      color: #ffffff;
+      display: flex;
+      justify-content: space-around;
+      position: relative;
+      z-index: 2;
+
+      .btn {
+        width: 33%;
+        height: 3.59rem;
+        line-height: 3.59rem;
+        font-size: 2rem;
+        margin: 0 auto;
+        border-radius: 0.83rem;
+        font-size: 2rem;
+        text-align: center;
+        color: #1A293A;
+        background: radial-gradient(141% 126% at 5% 93%, #8EFFA9 0%, #07FFE7 100%);
+        box-shadow: inset 0px 1px 0px 2px rgba(255, 255, 255, 0.5577);
+        cursor: pointer;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+
+        .is-loading {
+          margin-right: 5px;
+        }
+      }
+    }
+
+    .boxBg {
+      width: 100%;
+      height: 100%;
+      display: block;
+      background-position: center center;
+      background-repeat: no-repeat;
+      background-size: contain;
+      position: absolute;
+      left: 0;
+      top: 0;
+      z-index: 1;
+      opacity: 0.1;
+    }
+  }
+
+  .close {
+    margin: 1.5rem 1.5rem 0 0;
+
+    &:hover {
+      transform: rotate(180deg);
+      background-color: rgba(216, 216, 216, 1);
+    }
+  }
+}
+</style>

+ 0 - 17
src/components/ChooseStudent/index.vue

@@ -319,23 +319,6 @@ defineExpose({
       }
 
       .close {
-        width: 3.2rem;
-        height: 3.2rem;
-        box-sizing: border-box;
-        border: 1px solid #979797;
-        background-image: url("@/assets/images/common/close.png");
-        background-position: center;
-        background-repeat: no-repeat;
-        background-size: 45% 45%;
-        background-color: rgba(216, 216, 216, 0.8);
-        border-radius: 50%;
-        transition: all 0.5s;
-        cursor: pointer;
-
-        &:hover {
-          transform: rotate(180deg);
-          background-color: rgba(216, 216, 216, 1);
-        }
       }
     }
 

+ 0 - 17
src/components/Header/index.vue

@@ -171,26 +171,9 @@ $waiPadding: 6.51rem;
 }
 
 .close {
-  width: 3.2rem;
-  height: 3.2rem;
   position: absolute;
   right: calc($waiPadding - 3.2rem);
   top: calc($topPadding / 2 - 3.2rem/4);
-  box-sizing: border-box;
-  border: 1px solid #979797;
-  background-image: url("@/assets/images/common/close.png");
-  background-position: center;
-  background-repeat: no-repeat;
-  background-size: 45% 45%;
-  background-color: rgba(216, 216, 216, 0.8);
-  border-radius: 50%;
-  transition: all 0.5s;
-  cursor: pointer;
-
-  &:hover {
-    transform: rotate(180deg);
-    background-color: rgba(216, 216, 216, 1);
-  }
 }
 
 .close2 {

+ 0 - 17
src/components/OptionWindow/index.vue

@@ -540,24 +540,7 @@ defineExpose({
   }
 
   .close {
-    width: 3.2rem;
-    height: 3.2rem;
     margin: 1.5rem 1.5rem 0 0;
-    box-sizing: border-box;
-    border: 1px solid #979797;
-    background-image: url("@/assets/images/common/close.png");
-    background-position: center;
-    background-repeat: no-repeat;
-    background-size: 45% 45%;
-    background-color: rgba(216, 216, 216, 0.8);
-    border-radius: 50%;
-    transition: all 0.5s;
-    cursor: pointer;
-
-    &:hover {
-      transform: rotate(180deg);
-      background-color: rgba(216, 216, 216, 1);
-    }
   }
 }
 </style>

+ 0 - 17
src/components/ReportWindow/index.vue

@@ -491,23 +491,6 @@ defineExpose({
         }
 
         .close {
-          width: 3.2rem;
-          height: 3.2rem;
-          box-sizing: border-box;
-          border: 1px solid #979797;
-          background-image: url("@/assets/images/common/close.png");
-          background-position: center;
-          background-repeat: no-repeat;
-          background-size: 45% 45%;
-          background-color: rgba(216, 216, 216, 0.8);
-          border-radius: 50%;
-          transition: all 0.5s;
-          cursor: pointer;
-
-          &:hover {
-            transform: rotate(180deg);
-            background-color: rgba(216, 216, 216, 1);
-          }
         }
       }
 

+ 332 - 0
src/components/WorkstationWindow/index.vue

@@ -0,0 +1,332 @@
+<template>
+  <div>
+    <Transition :enter-active-class="proxy?.animate.mask.enter" :leave-active-class="proxy?.animate.mask.leave">
+      <div class="mask" v-if="optionWindow.show"></div>
+    </Transition>
+    <Transition :enter-active-class="proxy?.animate.dialog.enter" :leave-active-class="proxy?.animate.dialog.leave">
+      <div class="optionWindow" v-if="optionWindow.show">
+        <div class="box">
+          <div class="top">
+            <div class="title">{{ optionWindow.title }}</div>
+            <div class="close" @click="close"></div>
+          </div>
+          <div class="content">
+            <div class="left">工作站:</div>
+            <div class="right"> <el-select v-model="optionForm.worker" placeholder="请选择工作站">
+                <el-option v-for="(item, k) in workers" :key="item[0]" :label="k" :value="item[0]">
+                  <span style="float: left; font-size: 15px">{{ k }} <i v-if="item[3] == '待重启'"
+                      class="el-icon-refresh"></i> </span>
+                  <span style="float: right; color: #8492a6; font-size: 15px">{{ item[1] }}</span>
+                </el-option>
+              </el-select></div>
+
+          </div>
+          <div class="bottom">
+            <div class="btn" @click="confirm">
+              <el-icon class="is-loading" v-if="loading">
+                <Loading />
+              </el-icon>
+              <div>确 定</div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </Transition>
+  </div>
+
+</template>
+<script setup lang="ts">
+const { proxy } = getCurrentInstance() as any;
+const emit = defineEmits(['returnData']);
+
+const data = reactive<any>({
+  optionForm: {
+    worker: ''
+  },
+  optionWindow: {
+    show: false,
+    type: "",
+    title: "",
+  },
+  workers: [],
+  loading: false,
+  stateLoading: false,
+  timerManager: {},//计时器管理
+});
+
+const { optionForm, optionWindow, workers, loading, stateLoading, timerManager } = toRefs(data);
+
+//打开
+const open = (type: any, title: any) => {
+  getWorkstation();
+  optionForm.value.worker = '';
+  loading.value = false;
+  optionWindow.value.type = type;
+  optionWindow.value.title = title;
+  optionWindow.value.show = true;
+};
+
+//关闭
+const close = () => {
+  optionWindow.value.show = false;
+};
+
+//获取工作站
+const getWorkstation = async () => {
+  let myInfo: any = localStorage.getItem("userInfo");
+  let userInfo = JSON.parse(myInfo);
+  let params: any = {
+    school_id: userInfo.school_id
+  };
+  let res = await proxy?.$http.common.allExams(params)
+  workers.value = res.workers
+};
+
+//确定
+const confirm = () => {
+  if (!optionForm.value.worker) {
+    return false;
+  }
+  if (optionWindow.value.type == 'close') {
+    closeWorkstation();
+  }
+  if (optionWindow.value.type == 'restart') {
+    restartWorkstation();
+  }
+  if (optionWindow.value.type == 'led') {
+    ledWorkstation();
+  }
+};
+
+//关闭工作站
+const closeWorkstation = async () => {
+  let params: any = {
+    wk_md5: optionForm.value.worker
+  };
+  loading.value = true;
+  let res = await proxy?.$http.common.stopGpu(params).finally(() => {
+    loading.value = false;
+  })
+  if (res.status == 200) {
+    proxy?.$modal.msgSuccess('操作成功');
+    close();
+    emit('returnData', {});
+  } else {
+    proxy?.$modal.msgError(res.message);
+  }
+};
+
+//重启工作站
+const restartWorkstation = async () => {
+  let myInfo: any = localStorage.getItem("userInfo");
+  let userInfo = JSON.parse(myInfo);
+  let params: any = {
+    school_id: userInfo.school_id,
+    wk_md5: optionForm.value.worker
+  };
+  loading.value = true;
+  let res = await proxy?.$http.common.restartGpu(params).finally(() => {
+    loading.value = false;
+  })
+  if (res.status == 200) {
+    proxy?.$modal.msgSuccess('指令已发送,等待重启中...');
+    close();
+    stateLoading.value = ElLoading.service({ text: '重启中...', background: 'rgba(0, 0, 0, 0.8)' });
+    getCheckWkState();
+  } else {
+    proxy?.$modal.msgError(res.message);
+  }
+};
+
+//获取工作站状态
+const getCheckWkState = async () => {
+  if (timerManager.value.stateTimer == null) {
+    timerManager.value.stateOutTimer = setTimeout(() => {
+      getClearTimer();
+      stateLoading.value?.close();
+      emit('returnData', {});
+      proxy?.$modal.msgError("重启超时");
+    }, 23000)
+  }
+  let params: any = {
+    wk_md5: optionForm.value.worker
+  };
+  loading.value = true;
+  let res = await proxy?.$http.common.checkWkState(params).finally(() => {
+    loading.value = false;
+  })
+  if (parseInt(res) > 0) {
+    proxy?.$modal.msgSuccess('工作站重启成功');
+    getClearTimer();
+    stateLoading.value?.close();
+    emit('returnData', {});
+  } else {
+    timerManager.value.stateTimer = setTimeout(() => {
+      getCheckWkState();
+    }, 2000)
+  }
+};
+
+//关闭LED屏幕
+const ledWorkstation = async () => {
+  let myInfo: any = localStorage.getItem("userInfo");
+  let userInfo = JSON.parse(myInfo);
+  let params: any = {
+    school_id: userInfo.school_id,
+    wk_md5: optionForm.value.worker
+  };
+  loading.value = true;
+  let res = await proxy?.$http.common.closeLedScreen(params)
+  if (res.status == 200) {
+    proxy?.$modal.msgSuccess('指令已发送,等待LED关闭中...');
+    close();
+    loading.value = false;
+    emit('returnData', {});
+  } else {
+    proxy?.$modal.msgError(res.message);
+    loading.value = false;
+  }
+};
+
+/**
+ * 清空定时任务
+*/
+const getClearTimer = (data?: any) => {
+  if (data) {
+    //清除指定
+    clearInterval(timerManager.value[data])
+    timerManager.value[data] = null;
+  } else {
+    //清除全部
+    for (let key in timerManager.value) {
+      if (timerManager.value.hasOwnProperty(key)) {
+        clearInterval(timerManager.value[key])
+        timerManager.value[key] = null;
+      }
+    }
+  }
+};
+
+onMounted(() => {
+})
+
+onBeforeUnmount(() => {
+  loading.value = false;
+})
+
+//暴露给父组件用
+defineExpose({
+  open,
+  close,
+  optionWindow
+})
+</script>
+<style lang="scss" scoped>
+.mask {
+  position: fixed;
+  height: 100vh;
+  width: 100vw;
+  top: 0;
+  left: 0;
+  background: rgba(0, 0, 0, 0.78);
+  z-index: 998;
+}
+
+.optionWindow {
+  position: fixed;
+  height: 100vh;
+  width: 100vw;
+  top: 0;
+  left: 0;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  color: #FFFFFF;
+  z-index: 999;
+
+  .box {
+    width: 50%;
+    border-radius: 1.6rem;
+    background: linear-gradient(60deg, #092941 -85%, #2A484B 96%);
+    box-shadow: inset 0px 1px 0px 2px rgba(255, 255, 255, 0.3);
+    padding: 20px;
+
+    .top {
+      color: #ffffff;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 20px;
+
+      .title {
+        font-size: 1.93rem;
+        color: #13ED84;
+      }
+
+      .close {}
+    }
+
+    .content {
+      max-height: 65vh;
+      margin-bottom: 2vh;
+      display: flex;
+      align-items: center;
+
+      .left {
+        flex-shrink: 0;
+      }
+
+      .right {
+        width: 100%;
+      }
+    }
+
+    .bottom {
+      height: 3.59rem;
+      padding: 2.5rem 0 0 0;
+      align-items: center;
+      color: #ffffff;
+      display: flex;
+      justify-content: space-around;
+      position: relative;
+      z-index: 2;
+
+      .btn {
+        width: 33%;
+        height: 3.59rem;
+        line-height: 3.59rem;
+        font-size: 2rem;
+        margin: 0 auto;
+        border-radius: 0.83rem;
+        font-size: 2rem;
+        text-align: center;
+        color: #1A293A;
+        background: radial-gradient(141% 126% at 5% 93%, #8EFFA9 0%, #07FFE7 100%);
+        box-shadow: inset 0px 1px 0px 2px rgba(255, 255, 255, 0.5577);
+        cursor: pointer;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+
+        .is-loading {
+          margin-right: 5px;
+        }
+      }
+    }
+
+    .boxBg {
+      width: 100%;
+      height: 100%;
+      display: block;
+      background-position: center center;
+      background-repeat: no-repeat;
+      background-size: contain;
+      position: absolute;
+      left: 0;
+      top: 0;
+      z-index: 1;
+      opacity: 0.1;
+    }
+  }
+}
+</style>

+ 3 - 0
src/types/components.d.ts

@@ -7,6 +7,8 @@ export {}
 /* prettier-ignore */
 declare module 'vue' {
   export interface GlobalComponents {
+    '副本': typeof import('./../components/WorkstationWindow - 副本/index.vue')['default']
+    AddItemWindow: typeof import('./../components/AddItemWindow/index.vue')['default']
     ChooseStudent: typeof import('./../components/ChooseStudent/index.vue')['default']
     ElAvatar: typeof import('element-plus/es')['ElAvatar']
     ElButton: typeof import('element-plus/es')['ElButton']
@@ -26,5 +28,6 @@ declare module 'vue' {
     ReportWindow: typeof import('./../components/ReportWindow/index.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']
     RouterView: typeof import('vue-router')['RouterView']
+    WorkstationWindow: typeof import('./../components/WorkstationWindow/index.vue')['default']
   }
 }

+ 0 - 33
src/views/course/index.vue

@@ -125,39 +125,6 @@ onMounted(() => {
 $topPadding: 5.19rem;
 $waiPadding: 6.51rem;
 
-.logo {
-  img {
-    width: 14.563rem;
-  }
-
-  position: absolute;
-  left: $waiPadding;
-  top: $topPadding;
-}
-
-.close {
-  width: 3.2rem;
-  height: 3.2rem;
-  position: absolute;
-  right: calc($waiPadding - 3.2rem);
-  top: $topPadding;
-  box-sizing: border-box;
-  border: 1px solid #979797;
-  background-image: url("@/assets/images/common/close.png");
-  background-position: center;
-  background-repeat: no-repeat;
-  background-size: 45% 45%;
-  background-color: rgba(216, 216, 216, 0.8);
-  border-radius: 50%;
-  transition: all 0.5s;
-  cursor: pointer;
-
-  &:hover {
-    transform: rotate(180deg);
-    background-color: rgba(216, 216, 216, 1);
-  }
-}
-
 .menu {
   width: calc(100% - ($waiPadding * 2));
   height: 75vh;

+ 23 - 16
src/views/set/config.vue

@@ -18,11 +18,12 @@
     </div>
     <div class="footerBtn">
       <div class="btn" @click="addGpuExam">添加项目</div>
-      <div class="btn" @click="closeLedScreen">关闭LED屏幕</div>
-      <div class="btn" @click="restartGpu">重启工作站</div>
-      <div class="btn" @click="stopGpu">关闭工作站</div>
+      <div class="btn" @click="openWorkstation('led', '关闭LED屏幕')">关闭LED屏幕</div>
+      <div class="btn" @click="openWorkstation('restart', '重启工作站')">重启工作站</div>
+      <div class="btn" @click="openWorkstation('close', '关闭工作站')">关闭工作站</div>
       <div class="btn" @click="getExamList">刷新</div>
     </div>
+    <WorkstationWindow ref="workstationWindowRef" @returnData="returnRefresh" />
   </div>
 </template>
 
@@ -31,6 +32,7 @@ import dataDictionary from "@/utils/dataDictionary"
 const { proxy } = getCurrentInstance() as any;
 const router = useRouter();
 const dic: any = dataDictionary;
+const workstationWindowRef = ref();
 
 const data = reactive<any>({
   examList: [],
@@ -107,21 +109,12 @@ const addGpuExam = (row: any) => {
 
 };
 
-//关闭LED屏幕
-const closeLedScreen = (row: any) => {
-
-};
-
-//重启工作站
-const restartGpu = (row: any) => {
-
-};
-
-//关闭工作站
-const stopGpu = (row: any) => {
-
+//操作工作站
+const openWorkstation = (type: any, title: any) => {
+  workstationWindowRef.value.open(type, title);
 };
 
+//部署
 const chooseItem = (item: any) => {
   // let itemName = this.exams[item]
   let isOn = false
@@ -139,6 +132,7 @@ const chooseItem = (item: any) => {
   }
 };
 
+//删除项目
 const delExamConf = (item: any) => {
   let conTitle = `是否移除项目-${item[0]}`
   proxy?.$modal.confirm(conTitle).then(() => {
@@ -186,6 +180,7 @@ const delExamConf = (item: any) => {
   });
 };
 
+// 下课
 const closeExam = (item: any) => {
   let myInfo: any = localStorage.getItem("userInfo");
   let userInfo = JSON.parse(myInfo);
@@ -203,6 +198,14 @@ const closeExam = (item: any) => {
   })
 };
 
+
+/**
+ * 返回刷新列表
+*/
+const returnRefresh = () => {
+  getExamList();
+};
+
 /**
  * 返回
 */
@@ -213,6 +216,10 @@ const confirmExit = () => {
 onMounted(() => {
   getExamList();
 })
+
+onActivated(() => {
+  getExamList()
+})
 </script>
 
 <style lang="scss" scoped>

+ 0 - 33
src/views/train/index.vue

@@ -98,39 +98,6 @@ onBeforeUnmount(() => {
 $topPadding: 5.19rem;
 $waiPadding: 6.51rem;
 
-.logo {
-  img {
-    width: 14.563rem;
-  }
-
-  position: absolute;
-  left: $waiPadding;
-  top: $topPadding;
-}
-
-.close {
-  width: 3.2rem;
-  height: 3.2rem;
-  position: absolute;
-  right: calc($waiPadding - 3.2rem);
-  top: $topPadding;
-  box-sizing: border-box;
-  border: 1px solid #979797;
-  background-image: url("@/assets/images/common/close.png");
-  background-position: center;
-  background-repeat: no-repeat;
-  background-size: 45% 45%;
-  background-color: rgba(216, 216, 216, 0.8);
-  border-radius: 50%;
-  transition: all 0.5s;
-  cursor: pointer;
-
-  &:hover {
-    transform: rotate(180deg);
-    background-color: rgba(216, 216, 216, 1);
-  }
-}
-
 .menu {
   width: calc(100% - ($waiPadding * 2));
   height: 72vh;

+ 1 - 16
src/views/train/run.vue

@@ -4,7 +4,7 @@
     <Transition :enter-active-class="proxy?.animate.dialog.enter" :leave-active-class="proxy?.animate.dialog.leave">
       <div class="time" v-show="[42].includes(examState)">{{
         countdownNumFormat
-      }}</div>
+        }}</div>
     </Transition>
     <div class="main">
       <template v-if="isLongRun">
@@ -1030,21 +1030,6 @@ $waiPadding: 6.51rem;
         .close {
           width: 2rem;
           height: 2rem;
-          box-sizing: border-box;
-          border: 1px solid #979797;
-          background-image: url("@/assets/images/common/close.png");
-          background-position: center;
-          background-repeat: no-repeat;
-          background-size: 45% 45%;
-          background-color: rgba(216, 216, 216, 0.8);
-          border-radius: 50%;
-          transition: all 0.5s;
-          cursor: pointer;
-
-          &:hover {
-            transform: rotate(180deg);
-            background-color: rgba(216, 216, 216, 1);
-          }
         }
       }
     }