林旭祥 10 ヶ月 前
コミット
5ab8da5b58

+ 14 - 7
src/api/module/common.ts

@@ -1,7 +1,6 @@
-import req from '../request'
+import req from '../request';
 
 export default {
-
   //登录
   login: (data: any) => {
     return req({
@@ -9,7 +8,7 @@ export default {
       method: 'post',
       data: data,
       headers: {
-        auth: false, //不要鉴权
+        auth: false //不要鉴权
       }
     });
   },
@@ -19,7 +18,7 @@ export default {
     return req({
       url: '/user/logout',
       method: 'get',
-      data: data,
+      data: data
     });
   },
 
@@ -28,7 +27,7 @@ export default {
     return req({
       url: '/user/userinfo',
       method: 'get',
-      data: data,
+      data: data
     });
   },
 
@@ -37,8 +36,16 @@ export default {
     return req({
       url: '/school/classes_list',
       method: 'get',
-      data: data,
+      data: data
     });
   },
 
-}
+  //获取学生列表
+  studentList: (data: any) => {
+    return req({
+      url: '/user/student_list',
+      method: 'get',
+      data: data
+    });
+  }
+};

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

@@ -0,0 +1,232 @@
+<template>
+  <div class="optionWindow" v-if="optionWindow.show">
+    <div class="box">
+      <div class="top">
+        <div>手动选择学生</div>
+        <div @click="close">关闭</div>
+      </div>
+      <div class="content">
+        <div class="searchBox">
+          <el-select v-model="optionForm.grade" :popper-append-to-body="false" placeholder="年级" clearable>
+            <el-option v-for="item in gradeList" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+          <el-select v-model="optionForm.class" :popper-append-to-body="false" placeholder="班级" clearable>
+            <el-option v-for="item in classData" :key="item.value" :label="item.name" :value="item.id" />
+          </el-select>
+          <el-input v-model="optionForm.name" placeholder="请输入学生姓名" clearable />
+          <el-button type="primary" @click="getStudent">搜索</el-button>
+        </div>
+        <div class="tableBox">
+          <el-table :data="tableData" border class="table" @row-click="handleSelectionChange" @row-dblclick="confirm"
+            highlight-current-row>
+            <el-table-column label="头像" width="120">
+              <template #default="scope">
+                <el-avatar :src="scope.row.logo_url || scope.row.face_pic" />
+              </template>
+            </el-table-column>
+            <el-table-column prop="className" label="班级" width="180" />
+            <el-table-column prop="name" label="姓名" width="180" />
+            <el-table-column prop="genderName" label="性别" />
+            <el-table-column prop="student_number" label="学号" />
+          </el-table>
+
+          <el-pagination layout="sizes, prev, pager, next" :total="page.total" :page-size="page.size"
+            :page-sizes="[20, 60, 120]" :current-page="page.page" @size-change="handleSizeChange"
+            @current-change="handleCurrentChange" />
+        </div>
+      </div>
+      <div class="bottom">
+        <div @click="close">取消</div>
+        <div @click="confirm">确定</div>
+      </div>
+    </div>
+  </div>
+</template>
+<script setup lang="ts">
+import useAppStore from '@/store/modules/app';
+import dataDictionary from "@/utils/dataDictionary"
+const { proxy } = getCurrentInstance() as any;
+const emit = defineEmits(['back']);
+
+//筛选班别
+const classData = computed(() => {
+  optionForm.value.class = "";
+  let list = classList.value.filter((item: any) => {
+    return item.grade == optionForm.value.grade;
+  })
+  return list;
+});
+
+//年级
+const gradeList = dataDictionary.gradeList;
+
+const data = reactive<any>({
+  optionForm: {
+    gesture: true,
+    hasHB: false,
+  },
+  optionWindow: {
+    show: false,
+    time: "",
+  },
+  classList: [],
+  tableData: [],
+  page: {
+    current: 1,
+    size: 60,
+    total: 0,
+  },
+  selectValue: [],
+});
+
+const { optionForm, optionWindow, classList, tableData, page, selectValue } = toRefs(data);
+
+//打开
+const open = (data: any) => {
+  getClass();
+  getStudent();
+  optionWindow.value.show = true;
+};
+
+//关闭
+const close = () => {
+  optionWindow.value.show = false;
+};
+
+//获取班级列表
+const getClass = () => {
+  const list: any = useAppStore().getClass();
+  if (list.length) {
+    classList.value = list;
+    console.log("classList.value", classList.value)
+  } else {
+    let params = {
+      per_page: 1000,
+      page: 1,
+    };
+    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 getStudent = () => {
+  let myInfo: any = localStorage.getItem("userInfo");
+  let userInfo = JSON.parse(myInfo);
+  let params: any = {
+    school_id: userInfo.school_id,
+    class_id: optionForm.value.class,
+    page: page.value.current,
+    per_page: page.value.size,
+  };
+  if (optionForm.value.name) {
+    params.name = optionForm.value.name;
+  }
+  proxy?.$http.common.studentList(params).then((res: any) => {
+    if (res.data.length > 0) {
+      tableData.value = res.data.map((item: any) => {
+        let classObj = classList.value.find((items: any) => {
+          return items.id == item.class_id;
+        })
+        item.className = classObj.name;
+        item.genderName = item.gender == 1 ? "男" : "女";
+        item.student_id = item.id;
+        return item;
+      });
+      page.value.total = res.total;
+    }
+  });
+};
+
+//切换页码
+const handleCurrentChange = (data: number) => {
+  page.value.current = data
+  getStudent()
+};
+
+//切换页数
+const handleSizeChange = (data: number) => {
+  page.value.current = 1
+  page.value.size = data
+  getStudent()
+};
+
+//被选行
+const handleSelectionChange = (data: any) => {
+  selectValue.value = data;
+};
+
+//确定
+const confirm = () => {
+  if (!selectValue.value.id) {
+    proxy?.$modal.msgError(`请选择!`);
+    return false;
+  }
+  emit('back', selectValue.value)
+  close();
+};
+
+onMounted(() => {
+})
+
+//暴露给父组件用
+defineExpose({
+  open,
+  close,
+  optionWindow
+})
+</script>
+<style lang="scss" scoped>
+.optionWindow {
+  position: fixed;
+  height: 100vh;
+  width: 100vw;
+  top: 0;
+  left: 0;
+  background: rgba(0, 0, 0, 0.3);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  color: #FFFFFF;
+
+  .box {
+    width: 50%;
+    background: #000000;
+
+    .top {
+      color: #ffffff;
+      display: flex;
+      justify-content: space-around;
+    }
+
+    .content {
+
+
+      .searchBox {
+        display: flex;
+      }
+
+      .tableBox {
+        .table {
+          height: 40vh;
+        }
+      }
+    }
+
+    .bottom {
+      height: 60px;
+      align-items: center;
+      color: #ffffff;
+      display: flex;
+      justify-content: space-around;
+    }
+  }
+
+
+}
+</style>

+ 2 - 1
src/components/OptionWindow/index.vue

@@ -291,6 +291,8 @@ defineExpose({
 
     .top {
       color: #ffffff;
+      display: flex;
+      justify-content: space-around;
     }
 
     .content {
@@ -318,4 +320,3 @@ defineExpose({
 
 }
 </style>
-@/store/modules/app

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

@@ -7,10 +7,18 @@ export {}
 /* prettier-ignore */
 declare module 'vue' {
   export interface GlobalComponents {
+    ChooseStudent: typeof import('./../components/ChooseStudent/index.vue')['default']
+    copy: typeof import('./../components/OptionWindow copy/index.vue')['default']
+    ElAvatar: typeof import('element-plus/es')['ElAvatar']
+    ElButton: typeof import('element-plus/es')['ElButton']
     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']
+    OptionTest: typeof import('./../components/OptionTest/index.vue')['default']
     OptionWindow: typeof import('./../components/OptionWindow/index.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']
     RouterView: typeof import('vue-router')['RouterView']

+ 66 - 18
src/utils/dataDictionary.ts

@@ -1,22 +1,70 @@
 let data = {
-  gradeObj: {
-    one: '一年级',
-    two: '二年级',
-    three: '三年级',
-    four: '四年级',
-    five: '五年级',
-    six: '六年级',
-    m_one: '初一',
-    m_two: '初二',
-    m_three: '初三',
-    h_one: '高一',
-    h_two: '高二',
-    h_three: '高三',
-    u_one: '大一',
-    u_two: '大二',
-    u_three: '大三',
-    u_four: '大四'
-  },
+  gradeList: [
+    {
+      label: '一年级',
+      value: 'one'
+    },
+    {
+      label: '二年级',
+      value: 'two'
+    },
+    {
+      label: '三年级',
+      value: 'three'
+    },
+    {
+      label: '四年级',
+      value: 'four'
+    },
+    {
+      label: '五年级',
+      value: 'five'
+    },
+    {
+      label: '六年级',
+      value: 'six'
+    },
+    {
+      label: '初一',
+      value: 'm_one'
+    },
+    {
+      label: '初二',
+      value: 'm_two'
+    },
+    {
+      label: '初三',
+      value: 'm_three'
+    },
+    {
+      label: '高一',
+      value: 'h_one'
+    },
+    {
+      label: '高二',
+      value: 'h_two'
+    },
+    {
+      label: '高三',
+      value: 'h_three'
+    },
+    {
+      label: '大一',
+      value: 'u_one'
+    },
+    {
+      label: '大二',
+      value: 'u_two'
+    },
+    {
+      label: '大三',
+      value: 'u_three'
+    },
+    {
+      label: '大四',
+      value: 'u_four'
+    }
+  ],
   project: {
     jump: '立定跳远',
     longjump: '急行跳远',

+ 44 - 15
src/views/train/test.vue

@@ -1,17 +1,27 @@
 <template>
-  <div>成绩:{{ currentResultObj.count }} {{ unit }}</div>
-  <div>得分:{{ currentResultObj.score }}</div>
-  <div @click="getProcess">走一套流程({{ examState == 3 ? "创建测试" : examState == 40 ? "开始人脸识别" : examState == 41 ? "停止人脸识别" :
-    examState ==
-      43 ? "开始测试" : examState == 42 ? "正在测试" : "请初始化" }})</div>
-  <div @click="getOpenOneTestAndStartFace" v-if="examState == 3 || examState == 40">开始人脸识别</div>
+  <div>
+    <div><el-avatar :src="faceCheckStu.logo_url || faceCheckStu.face_pic" @click="getChooseStudent" /></div>
+    <div>{{ faceCheckStu.name }}</div>
+    <div>成绩:{{ currentResultObj.count }} {{ unit }}</div>
+    <div>得分:{{ currentResultObj.score }}</div>
+    <div @click="getProcess">走一套流程({{ examState == 3 ? "创建测试" : examState == 40 ? "开始人脸识别" : examState == 41 ? "停止人脸识别"
+      :
+      examState ==
+        43 ? "开始测试" : examState == 42 ? "正在测试" : "请初始化" }})</div>
+    <div @click="getOpenOneTestAndStartFace" v-if="examState == 3 || examState == 40">1、开始人脸识别</div>
 
-  <div @click="getStopFace" v-if="examState == 41">停止人脸识别</div>
+    <div @click="getChooseStudent">2、选择学生</div>
+    <div @click="getStopFace" v-if="examState == 41">3、停止人脸识别</div>
 
-  <div @click="getStartOneTest" v-if="examState == 43">开始测试</div>
+    <div @click="getStartOneTest" v-if="examState == 43">4、开始测试</div>
 
-  <div @click="getRetest" v-if="examState == 3 || examState == 42">再测一次</div>
-  <div @click="confirmExit">退出</div>
+    <div @click="getRetest" v-if="examState == 3 || examState == 42">再测一次</div>
+
+
+    <div @click="confirmExit">退出</div>
+
+    <ChooseStudent ref="chooseStudentRef" @back="backStudent" />
+  </div>
 </template>
 
 <script setup name="TrainTest" lang="ts">
@@ -20,6 +30,7 @@ import dataDictionary from "@/utils/dataDictionary"
 const { proxy } = getCurrentInstance() as any;
 const router = useRouter();
 const route = useRoute();
+const chooseStudentRef = ref();
 const data = reactive<any>({
   timerManager: {},//计时器管理
   parameter: {},//参数
@@ -29,8 +40,9 @@ const data = reactive<any>({
   result_id: null,//测试ID
   currentResultObj: {},//成绩
   unit: "",//单位
+  faceCheckStu: {},//人脸信息
 });
-const { timerManager, parameter, testTime, userInfo, examState, result_id, currentResultObj, unit } = toRefs(data);
+const { timerManager, parameter, testTime, userInfo, examState, result_id, currentResultObj, unit, faceCheckStu } = toRefs(data);
 
 //接收消息
 const getMessage = (e: any) => {
@@ -77,6 +89,7 @@ const getMessage = (e: any) => {
   }
   //人脸识别状态
   if (e.cmd === 'face_check_result') {
+    faceCheckStu.value = e.data[0] || e.data;
   }
   //测试结束结果
   if (e.cmd === 'oneresult') {
@@ -94,7 +107,6 @@ const getMessage = (e: any) => {
       }
       data.count = count || "0";
       data.score = data.score || "0";
-
       currentResultObj.value = data;
     }
 
@@ -148,8 +160,8 @@ const getStopFace = () => {
   stopFace();
   faceConfirmOnly({
     result_id: result_id.value,
-    student_id: 1,
-    gender: 1
+    student_id: faceCheckStu.value.student_id,
+    gender: faceCheckStu.value.gender
   });
 };
 
@@ -191,7 +203,7 @@ const getRetest = () => {
 };
 
 /**
- * 退出
+ * 确认退出
 */
 const confirmExit = () => {
   proxy?.$modal.confirm("确定退出吗?").then(() => {
@@ -222,6 +234,23 @@ const getClearTimer = () => {
   }
 };
 
+/**
+ * 选择学生
+*/
+const getChooseStudent = () => {
+  if (examState.value != 41) {
+    return false;
+  }
+  chooseStudentRef.value.open();
+};
+
+/**
+ * 被选学生
+*/
+const backStudent = (data: any) => {
+  faceCheckStu.value = data;
+};
+
 onMounted(() => {
   parameter.value = route.query;
   parameter.value.examId = `${parameter.value.project}_${parameter.value.area}`; //项目+区