Bladeren bron

日常开发

林旭祥 1 maand geleden
bovenliggende
commit
8985be8717
5 gewijzigde bestanden met toevoegingen van 211 en 104 verwijderingen
  1. 9 0
      src/api/module/train.ts
  2. 180 91
      src/components/OptionWindow/index.vue
  3. 0 10
      src/types/components.d.ts
  4. 21 2
      src/utils/trainWs.ts
  5. 1 1
      src/views/test/index.vue

+ 9 - 0
src/api/module/train.ts

@@ -20,4 +20,13 @@ export default {
 		});
 	},
 
+	//学生绑定设备
+	bindDevice: (data:any) => {
+		return req({
+			url: '/device/multi_device_bind',
+			method: 'post',
+			data: data,
+		});
+	},
+
 }

+ 180 - 91
src/components/OptionWindow/index.vue

@@ -15,14 +15,20 @@
                 {{ 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
+                  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 @click="getAllArea" class="allBtn" :class="{ 'active': chooseAllState }" v-if="!['skiprope','heartbeat'].includes(project.key)">
+                {{ chooseAllState ? '重 置' :
+                '全 选' }}
+              </div>
             </div>
             <!-- <div class="standardBox">
               <div class="content-title content-title2">评分标准</div>
@@ -34,55 +40,75 @@
               </div>
             </div> -->
             <div class="switchList">
-              <div class="li">
+              <div class="li" v-if="!['skiprope','heartbeat'].includes(project.key)">
                 <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" />
+                <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" />
+                <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>
+                <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 class="switchList">
-              <div class="li"
-                v-if="['situp', 'jumprope', 'jumpingjack', 'highknees', 'footballv1', 'basketballv1', 'volleyball', 'volleyballv1', 'pingpong'].includes(project.key)">
+              <div
+                class="li"
+                v-if="['situp', 'jumprope', 'jumpingjack', 'highknees', 'footballv1', 'basketballv1', 'volleyball', 'volleyballv1', 'pingpong', 'skiprope', 'heartbeat'].includes(project.key)"
+              >
                 <span>时长</span>
-                <el-select v-model="optionForm.time" :popper-append-to-body="false" placeholder="请选择">
+                <el-select v-model="optionForm.time" :popper-append-to-body="false" placeholder="请选择" v-if="['heartbeat'].includes(project.key)">
+                  <el-option v-for="item in timeListHeartbeat" :key="item.value" :label="item.label" :value="item.value" />
+                </el-select>
+                <el-select v-model="optionForm.time" :popper-append-to-body="false" placeholder="请选择" v-else>
                   <el-option v-for="item in timeList" :key="item.value" :label="item.label" :value="item.value" />
                 </el-select>
               </div>
-              <div class="li"
-                v-if="['situp', 'jumprope', 'jumpingjack', 'highknees', 'footballv1', 'basketballv1', 'volleyball', 'volleyballv1', 'pingpong'].includes(project.key)">
+              <div
+                class="li"
+                v-if="['situp', 'jumprope', 'jumpingjack', 'highknees', 'footballv1', 'basketballv1', 'volleyball', 'volleyballv1', 'pingpong', 'skiprope'].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 class="switchList" v-if="['heartbeat'].includes(project.key)">
+              <div class="li">
+                <span>平均心率</span>
+                <div style="display: flex;">
+                  <el-input v-model="optionForm.standHBL" />
+                  ~
+                  <el-input v-model="optionForm.standHBH" />
+                </div>
+              </div>
+            </div>
+            <div class="switchList" v-if="['heartbeat'].includes(project.key)">
+              <div class="li">
+                <span>预警心率</span>
+                <div>
+                  <el-input v-model="optionForm.highHB" />
+                </div>
+              </div>
+            </div>
           </div>
           <div class="bottom">
             <div class="btn" @click="confirm">
@@ -92,13 +118,11 @@
               <div>确 定</div>
             </div>
           </div>
-          <div class="boxBg" :style="{ backgroundImage: 'url(static/images/train/' + project.key + '.png)' }">
-          </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';
@@ -114,69 +138,115 @@ const props = defineProps({
   parentData: {
     type: Object,
     default: {}
-  },
+  }
 });
 
 //评分标准,数据字典无需双向绑定
-const standardList = [{ label: '考试', value: 0 }, { label: '体测', value: 1 }]
+const standardList = [
+  { label: '考试', value: 0 },
+  { label: '体测', value: 1 }
+];
 
 //时长选择,数据字典无需双向绑定
-const timeList =
-  [{
+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 timeListHeartbeat = [
+  {
+    label: '1分钟',
+    value: 1
+  },
+  {
+    label: '5分钟',
+    value: 5
+  },
+  {
+    label: '40分钟',
+    value: 40
+  },
+  {
+    label: '45分钟',
+    value: 45
+  },
+  {
+    label: '80分钟',
+    value: 80
+  },
+  {
+    label: '90分钟',
+    value: 90
+  }
+];
 
 const data = reactive<any>({
   optionForm: {
     gesture: true,
-    standard: 0
+    standard: 0,
+    standHBL: '110',
+    standHBH: '160',
+    highHB: '180'
   },
   optionWindow: {
     show: false,
-    time: "",
+    time: ''
   },
   project: {},
   musicList: [],
   classList: [],
   chooseArea: [],
   chooseAllState: false,
-  loading: false,
+  loading: false
 });
 
 const { optionForm, optionWindow, project, musicList, classList, chooseArea, chooseAllState, loading } = toRefs(data);
 
 //打开
 const open = async (data: any) => {
-  console.log("data", data);
+  console.log('data', data);
   await getClass();
   await getMusic();
   project.value = data;
   chooseArea.value = [];
-  if (['situp', 'jumprope', 'jumpingjack', 'highknees', 'footballv1', 'basketballv1', 'volleyball', 'volleyballv1', 'pingpong'].includes(project.value.key)) {
+  if (
+    ['situp', 'jumprope', 'jumpingjack', 'highknees', 'footballv1', 'basketballv1', 'volleyball', 'volleyballv1', 'pingpong', 'skiprope'].includes(
+      project.value.key
+    )
+  ) {
     optionForm.value.gesture = true;
     optionForm.value.time = 60; //默认60秒
     if (musicList.value.length > 0) {
-      optionForm.value.music = musicList.value[0].url;//默认第一首
+      optionForm.value.music = musicList.value[0].url; //默认第一首
     }
+  } else if (['heartbeat'].includes(project.value.key)) {
+    optionForm.value.time = 2700; //默认45分钟
   } else {
     optionForm.value.gesture = false;
   }
@@ -194,7 +264,7 @@ 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.sort((a: any, b: any) => a.key - b.key);
   }
@@ -225,7 +295,7 @@ const getClass = async () => {
   } else {
     let params = {
       page: 1,
-      per_page: 9999,
+      per_page: 9999
     };
     await proxy?.$http.common.classList(params).then((res: any) => {
       if (res.data.length > 0) {
@@ -239,16 +309,22 @@ const getClass = async () => {
 
 //选择测试区
 const getChooseArea = (data: any) => {
+  console.log("111111",data)
   let id = data.key;
   let inData = chooseArea.value.includes(id);
   if (inData) {
     //已存在就移除
     chooseArea.value = chooseArea.value.filter((item: any) => {
-      return item != id
-    })
+      return item != id;
+    });
   } else {
     //不存在就点选
-    chooseArea.value.push(id);
+    if(['skiprope','heartbeat'].includes(project.value.key)){
+      chooseArea.value = [];
+      chooseArea.value.push(id);
+    }else{
+      chooseArea.value.push(id);
+    }
   }
   if (chooseArea.value.length > 10) {
     optionForm.value.gesture = false;
@@ -267,11 +343,13 @@ 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;
-    })
+    chooseArea.value = areaList.value
+      .filter((item: any) => {
+        return item.value == 0;
+      })
+      .map((item: any) => {
+        return item.key;
+      });
     if (chooseArea.value.length > 10) {
       optionForm.value.gesture = false;
     }
@@ -286,23 +364,27 @@ const confirm = () => {
   if (loading.value == true) {
     return false;
   }
-  console.log("project.value", project.value)
+  console.log('project.value', project.value);
   optionForm.value.project = project.value.key;
   if (props.parentData.id) {
     optionForm.value.classes = props.parentData.class_ids.join();
   } else {
-    optionForm.value.classes = classList.value.map((item: any) => { return item.id; }).join();
+    optionForm.value.classes = classList.value
+      .map((item: any) => {
+        return item.id;
+      })
+      .join();
   }
   optionForm.value.area = chooseArea.value.join();
-  console.log("optionForm", optionForm.value);
+  console.log('optionForm', optionForm.value);
   if (!optionForm.value.classes) {
     getClass();
-    let message = "没有班级,将重新加载班级请重新操作";
+    let message = '没有班级,将重新加载班级请重新操作';
     ElMessage({ message: message, type: 'error', duration: 3 * 1000 });
     return false;
   }
   if (!optionForm.value.area) {
-    let message = "请选择测试区";
+    let message = '请选择测试区';
     ElMessage({ message: message, type: 'error', duration: 3 * 1000 });
     return false;
   }
@@ -315,15 +397,14 @@ const confirm = () => {
   if (props.parentData.id) {
     optionForm.value.taskId = props.parentData.id;
     optionForm.value.standard = props.parentData.type; //0考试 1体测
-    optionForm.value.taskCate = props.parentData.task_cate
+    optionForm.value.taskCate = props.parentData.task_cate;
   }
 
   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)) {
+  } 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 {
@@ -336,17 +417,16 @@ const confirm = () => {
 const getGesture = async (myProject: any, data: any) => {
   await getClass();
   project.value = myProject;
-  chooseArea.value = data.area.split(",");
+  chooseArea.value = data.area.split(',');
   optionForm.value = data;
   confirm();
-}
+};
 
-onMounted(() => {
-})
+onMounted(() => {});
 
 onBeforeUnmount(() => {
   loading.value = false;
-})
+});
 
 //暴露给父组件用
 defineExpose({
@@ -354,7 +434,7 @@ defineExpose({
   close,
   optionWindow,
   getGesture
-})
+});
 </script>
 <style lang="scss" scoped>
 .mask {
@@ -376,13 +456,13 @@ defineExpose({
   display: flex;
   justify-content: center;
   align-items: center;
-  color: #FFFFFF;
+  color: #ffffff;
   z-index: 999;
 
   .box {
     width: 50%;
     border-radius: 1.6rem;
-    background: linear-gradient(46deg, #092941 -83%, #2A484B 95%);
+    background: linear-gradient(46deg, #092941 -83%, #2a484b 95%);
     box-shadow: inset 0px 1px 0px 2px rgba(255, 255, 255, 0.2);
     position: relative;
 
@@ -441,7 +521,7 @@ defineExpose({
           .select {
             border: 3px solid #ffffff;
             background: #ffffff;
-            color: #1A293A;
+            color: #1a293a;
           }
 
           .ing {
@@ -466,7 +546,6 @@ defineExpose({
             border-radius: 6px;
             background: rgba(26, 62, 78, 1);
           }
-
         }
 
         .allBtn {
@@ -489,8 +568,8 @@ defineExpose({
           border-radius: 1.8rem;
           font-size: 2rem;
           text-align: center;
-          color: #1A293A;
-          background: #ACACAC;
+          color: #1a293a;
+          background: #acacac;
           overflow: hidden;
 
           .li {
@@ -502,12 +581,11 @@ defineExpose({
           .select {
             border-radius: 1.8rem;
             box-shadow: inset 0px 1px 0px 2px rgba(255, 255, 255, 0.3);
-            background: radial-gradient(50% 181% at 163% 0%, #35FFC6 0%, #00FFE8 100%);
+            background: radial-gradient(50% 181% at 163% 0%, #35ffc6 0%, #00ffe8 100%);
           }
         }
       }
 
-
       .switchList {
         padding: 2.5vh 0;
         display: flex;
@@ -524,13 +602,24 @@ defineExpose({
             flex-shrink: 0;
           }
 
-          .el-select {
+          ::v-deep(.el-select) {
             width: 100px;
+            font-size: 16px;
+            .el-select__selection {
+              font-weight: bold !important;
+            }
+          }
+
+          ::v-deep(.el-input) {
+            width: 100px;
+            font-size: 16px;
+            .el-input__inner {
+              text-align: center;
+              font-weight: bold !important;
+            }
           }
         }
       }
-
-
     }
 
     .bottom {
@@ -552,8 +641,8 @@ defineExpose({
         border-radius: 0.83rem;
         font-size: 2rem;
         text-align: center;
-        color: #1A293A;
-        background: radial-gradient(141% 126% at 5% 93%, #8EFFA9 0%, #07FFE7 100%);
+        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.3);
         cursor: pointer;
         display: flex;

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

@@ -9,16 +9,6 @@ declare module 'vue' {
   export interface GlobalComponents {
     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']
-    ElIcon: typeof import('element-plus/es')['ElIcon']
-    ElInput: typeof import('element-plus/es')['ElInput']
-    ElOption: typeof import('element-plus/es')['ElOption']
-    ElPagination: typeof import('element-plus/es')['ElPagination']
-    ElSelect: typeof import('element-plus/es')['ElSelect']
-    ElSwitch: typeof import('element-plus/es')['ElSwitch']
-    ElTable: typeof import('element-plus/es')['ElTable']
-    ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
     FaceWindow: typeof import('./../components/FaceWindow/index.vue')['default']
     Header: typeof import('./../components/Header/index.vue')['default']
     JumpRopeGame: typeof import('./../components/JumpRopeGame/index.vue')['default']

+ 21 - 2
src/utils/trainWs.ts

@@ -71,7 +71,7 @@ export function useWs() {
           let examId = `${parameter.project}_${item}`;
           if (parameter.taskId) {
             getTaskStarts(examId);
-          } else {
+          }else {
             getExamStarts(examId);
           }
           getNetWork(examId, (e: any) => {
@@ -109,7 +109,9 @@ export function useWs() {
         let examId = parameter.examId;
         if (parameter.taskId) {
           getTaskStarts(examId);
-        } else {
+        } else if(['skiprope','heartbeat'].includes(parameter.project)) {
+          getDeviceStarts(examId);
+        }  else {
           getExamStarts(examId);
         }
         getNetWork(examId, (e: any) => {
@@ -288,6 +290,23 @@ export function useWs() {
     );
   }
 
+  /**
+   * 设备连接成功
+   */
+  function getDeviceStarts(data?: any) {
+    let examId = data ? data : parameter.examId;
+    sendMessage(
+      'device_starts',
+      {
+        data: 'start_' + examId,
+        class_id: parameter.classes,
+        exam_type: parameter.standard,
+        etime: testTime
+      },
+      () => { }
+    );
+  }
+
   /**
    * 连接成功
    */

+ 1 - 1
src/views/test/index.vue

@@ -141,7 +141,7 @@ const getExam = () => {
 */
 const getOption = (data: any) => {
   if (!currentTask.value.id) {
-    proxy?.$modal.msgWarning(`请先选择左侧测试!`);
+    proxy?.$modal.msgWarning(`请先选择左侧专题!`);
     return false;
   }
   optionWindowRef.value.open(data);