Răsfoiți Sursa

添加app端评价任务展示页

lm 2 săptămâni în urmă
părinte
comite
c5ce00c36b

+ 0 - 483
src/components/ReviewManagementDetailSideBar.vue

@@ -1,483 +0,0 @@
-<template>
-    <!-- 左侧导航栏 -->
-    <div class="left_nav">
-      <div class="exam_title">
-        <div class="exam_page_title" :title="store.state.evaluationManageStepData.evaluationManageDetailName">
-          {{ store.state.evaluationManageStepData.evaluationManageDetailName }}
-        </div>
-      </div>
-      <div class="exam_back">
-        <el-button class="back_button" @click="$router.push('/main/reviewManagement')">
-          <img :src="backIcon" alt="">返回
-        </el-button>
-      </div>
-      
-      <div class="nav_list">
-        <!-- 步骤列表 -->
-        <template v-for="(stepItm, index) in stepMsgs" :key="stepItm.stepName">
-          <div 
-            v-if="stepItm.show"
-            class="nav_item"
-            :class="{
-              'active_item': store.state.evaluationManageStepData.currentActiveStepName == stepItm.stepName,
-              'success': stepItm.isFinish
-            }"
-            @click="HandleChangeStep(stepItm)"
-          >
-            <div class="step_box">
-              <div class="step_header_title">
-                <div class="num_box">
-                  <el-icon v-if="stepItm.isFinish" class="el-icon-success"><SuccessFilled /></el-icon>
-                  <span v-else class="step_num">{{ stepItm.stepNum || (index + 1) }}</span>
-                </div>
-                <span class="step_title" :title="stepItm.title">{{ stepItm.title }}</span>
-              </div>
-
-              <div class="step_content">
-                <div class="left_line "></div>
-                <div>
-                  {{ stepItm.desc }}
-                </div>
-              </div>
-
-            </div>
-          </div>
-        </template>
-      </div>
-    </div>
-</template>
-
-
-<script setup lang="ts">
-import { onMounted, ref, computed } from 'vue';
-import { useRoute } from 'vue-router';
-import { useStore } from 'vuex';
-import backIcon from '@/assets/icon/left_back_arrow_.png'
-import router from '@/router';
-
-const route = useRoute()
-const store = useStore()  //store.state.evaluationManageStepData.evaluationType,   // 评价方式  0-线上匿名,1-线下答卷,2-线上导入,3-线上实名
-
-const stepMsgs = computed(()=>[
-  {
-    stepNum:1,
-    stepName:'evaluationData',
-    title:'评价数据',
-    desc:'评价覆盖的年级、班级、对应科目基础信息',
-    route:'evaluationData',
-    show:true,
-    isFinish:store.state.evaluationManageStepData.isFinishEvaluationData,
-
-  },
-  {
-    stepNum:2,
-    stepName:'teachingRelationship',
-    title:'授课关系',
-    desc:'年级、班级、科目匹配对应的任课教师',
-    route:'teachingRelationship',
-    show:true,
-    isFinish:store.state.evaluationManageStepData.isFinishTeachingRelationship,
-
-  },
-
-// ==================================
-  // 线下答卷的内容 >>>>>  evaluationType === 1
-  {
-    stepNum:3,
-    stepName: 'numberMapping', 
-    title: '编号对应',
-    desc: '绑定年级、班级与专属编号',
-    route: 'numberMapping',
-    show:store.state.evaluationManageStepData.evaluationType === 1 ? true : false,
-    isFinish:null,
-  },
-  {
-    stepNum:4,
-    stepName: 'templateSetting',  
-    title: '模板设置',
-    desc: '框选问卷各答题区域完成线上模板配置',
-    route: 'templateSetting',
-    show:store.state.evaluationManageStepData.evaluationType === 1 ? true : false,
-    isFinish:null,
-  },
-  {
-      stepNum:5,
-      stepName: 'scoreSetting',
-      title: '分数设置',
-      desc: '设置每道题及各个选项对应得分',
-      route: 'scoreSetting',
-      show:store.state.evaluationManageStepData.evaluationType === 1 ? true : false,
-      isFinish:null,
-  },
-  {
-      stepNum:6,
-      stepName: 'scanQuestionnaire',  // 对应“扫描问卷”
-      title: '扫描问卷',
-      desc: '批量扫描学生纸质问卷,处理异常',
-      route: 'scanQuestionnaire',
-      show:store.state.evaluationManageStepData.evaluationType === 1 ? true : false,
-      isFinish:null,
-  },
-  // =================================
-  
-  // ============================
-  // 线上匿名 的内容 >>>  evaluationType === 0
-  {
-    stepNum:3,
-    stepName:'questionnaireTemplate',
-    title:'问卷模版',
-    desc:'为不同科目选定适配的评价问卷模板',
-    route:'questionnaireTemplate',
-    show:store.state.evaluationManageStepData.evaluationType === 0 ? true : false,
-    isFinish:store.state.evaluationManageStepData.isFinishQuestionnaireTemplate,
-
-  },
-  {
-    stepNum:4,
-    stepName:'reviewAccount',
-    title:'评价账号',
-    desc:'批量生成对应数量的学生评价登录账号',
-    route:'reviewAccount',
-    show:store.state.evaluationManageStepData.evaluationType === 0 ? true : false,
-    childrenRoute:[
-      'generateReviewCode',
-    ],
-    isFinish:store.state.evaluationManageStepData.isFinishReviewAccount,
-    isGenerateReviewCode:store.state.evaluationManageStepData.isGenerateReviewCode,  //是否已生成评价码
-  },
-  // ^^^^^ =========================
-
-  
-  {
-    stepNum: store.state.evaluationManageStepData.evaluationType === 1  ? 7 : (store.state.evaluationManageStepData.evaluationType === 0 ?  5 : '') ,  // 线上匿名 5   线下答卷 7
-    stepName:'parameterSetting',
-    title:'参数设置',
-    desc:'统一配置本次评价任务的评分分值规则',
-    route:'parameterSetting',
-    show:true,
-    isFinish:store.state.evaluationManageStepData.isFinishParameterSetting,
-  },
-  {
-    // 线上匿名的内容
-    stepNum:6,
-    stepName:'evaluationProgress',
-    title:'评价进度',
-    desc:'实时查看学生完成评价的填报进度',
-    route:'evaluationProgress',
-    show:store.state.evaluationManageStepData.evaluationType === 0 ? true : false,
-    isFinish:store.state.evaluationManageStepData.isFinishEvaluationProgress,
-
-  },
-
-  {
-    stepNum:store.state.evaluationManageStepData.evaluationType === 1 ? 8 : (store.state.evaluationManageStepData.evaluationType === 0 ? 7 : '' ),   // 线上匿名 7   线下答卷 8
-    stepName:'generateAnalysis',
-    title:'生成分析',
-    desc:'汇总数据并生成、发布评价分析报告',
-    route:'generateAnalysis',
-    show:true,
-    isFinish:store.state.evaluationManageStepData.isFinsihGenerateAnalysis,
-
-  },
-])
-
-const HandleChangeStep=(currentStep)=>{
-  store.commit('updateEvaluationManageStepData',
-                {currentActiveStepName:currentStep.stepName})
-  if(currentStep.stepName  == 'reviewAccount'){
-    if(currentStep.isGenerateReviewCode){
-      // 已经生成评价码,跳转到评价码生成页面
-      router.push(`generateReviewCode?id=${route.query.id}`)
-    }else{
-      router.push(`${currentStep.route}?id=${route.query.id}`)
-    }
-  }else{
-    router.push(`${currentStep.route}?id=${route.query.id}`)
-  }
-}
-
-
-onMounted(()=>{
-  let stepRoute = route.params.stepRoute
-  let matchRes = stepMsgs.value.find(item=>{
-    return item.route === stepRoute || item.childrenRoute?.includes(stepRoute)
-  })
-  if(matchRes){
-    store.commit('updateEvaluationManageStepData',
-                {currentActiveStepName: matchRes.stepName})
-  }
-})
-</script>
-
-
-<style lang="scss" scoped>
-/* 左侧导航样式 */
-.left_nav {
-  min-width: 160px;
-  width: 160px;
-  height: 100%;
-  background-color: #ffffff;
-  display: flex;
-  flex-direction: column;
-
-  > *{
-    flex-shrink: 0;
-  }
-
-  .exam_title {
-    font-weight: 500;
-    color: #ffffff;
-    text-align: center;
-    background-color: #2e64fa;
-    padding: 5px 5px;
-
-    .exam_page_title {
-      font-size: 16px;
-      line-height: 25px;
-      overflow: hidden;
-      text-overflow: ellipsis;
-      display: -webkit-box;
-      -webkit-line-clamp: 5;
-      -webkit-box-orient: vertical;
-      white-space: normal;
-      word-break: break-all;
-      word-wrap: break-word;
-      text-align: center;
-      cursor: pointer;
-    }
-  }
-
-  .exam_back {
-    width: 100%;
-    height: 56px;
-    display: flex;
-    justify-content: center;
-
-    .back_button {
-      width: calc(100% - 24px);
-      margin: auto;
-      height: 36px;
-      line-height: 36px;
-      background: #ffffff;
-      border-radius: 4px;
-      border: 1px solid #dcdfe6;
-      text-align: center;
-      cursor: pointer;
-      font-weight: 500;
-      font-size: 14px;
-      color: #666666;
-      display: flex;
-      justify-content: center;
-      align-items: center;
-
-      img {
-        width: 20px;
-        height: 20px;
-        margin-right: 5px;
-      }
-    }
-  }
-
-  .nav_list {
-    margin-bottom: 15px;
-    flex:1 1;
-    position: relative;
-    width: 100%;
-    overflow-y: auto;
-
-    display: flex;
-    flex-direction: column;
-    > *{
-      flex-shrink: 0;
-    }
-
-    /* 菜单节点样式 (完全还原第一段 step_item) */
-    .nav_item {
-      width: 100%;
-      position: relative;
-      z-index: 7;
-
-      .step_box{
-        border-top-left-radius: 10px;
-        border-bottom-left-radius: 10px;
-      }
-
-      
-      cursor: pointer;
-
-     
-
-      /* 标题区域 */
-      .step_header_title {
-        display: flex;
-        align-items: center;
-        justify-content: flex-start;
-        width: 100%;
-        height: 34px;
-        font-size: 16px;
-        color: #333333;
-        line-height: 34px;
-        font-weight: 600;
-        border-top-left-radius: 10px;
-
-        .step_title {
-          white-space: nowrap;
-          overflow: hidden;
-          text-overflow: ellipsis;
-        }
-
-        /* 图标/序号容器 */
-        .num_box {
-          width: 30px;
-          height: 100%;
-          display: flex;
-          justify-content: center;
-          align-items: center;
-          flex-shrink: 0;
-
-          /* 完成状态打勾图标 (兼顾 iconfont / element-ui 两种类名) */
-          .hjx-dui,
-          .el-icon-success {
-            font-size: 19px;
-
-            &::before {
-              font-size: 19px;
-            }
-          }
-        }
-
-        /* 序号圆圈 */
-        .step_num {
-          display: block;
-          width: 17px;
-          height: 17px;
-          font-size: 12px;
-          text-align: center;
-          font-weight: 500;
-          line-height: 17px;
-          border-radius: 50%;
-          background-color: #B0B2B7;
-          color: #ffffff;
-        }
-      }
-
-      /* 描述文字区域 */
-      .step_content {
-        padding: 0px 5px 6px 20px;
-        font-size: 12px;
-        line-height: 16px;
-        color: #999999;
-      }
-
-      .left_line {
-        position: absolute;
-        top: 28px;
-        left: 15.55px;
-        z-index: 6;
-        height: 100%;
-        width: 0;
-        border-left: 1px dashed #C0C4CC;
-      }
-
-       &:last-child{
-        flex:1 1;
-        margin-bottom: 0;
-
-        .left_line {
-          height: calc(100% - 28px);
-        }
-      }
-
-      /* 完成状态 (success) */
-      &.success {
-        border-color: #ffffff;
-
-        .num_box > i,
-        .num_box > span {
-          color: #15BC83;
-        }
-      }
-
-      /* 激活高亮状态 (active_item) - 完美还原原蓝色阴影与卡片样式 */
-      &.active_item {
-        .step_box{
-          border-color: #2E64FA;
-          background-color: rgba(46, 100, 250, 0.1);
-          box-shadow: inset 1px -1px 0px 1.5px #2E64FA;
-        }
-
-        .step_header_title {
-          background-color: #2E64FA;
-          color: #ffffff;
-        }
-
-        .step_num {
-          background-color: #ffffff;
-          color: #2E64FA;
-        }
-
-        .step_content {
-          background-color: rgba(46, 100, 250, 0.1);
-        }
-      }
-    }
-
-    /* ------------------- 响应式适配 (100% 还原第一段媒体查询) ------------------- */
-
-    /* 小屏幕笔记本:常见分辨率 1366x768 及以下 */
-    @media (max-height: 768px) {
-      .nav_item {
-        margin-bottom: 0px;
-
-        .step_header_title {
-          font-size: 14px;
-          line-height: 30px;
-          font-weight: 700;
-        }
-
-        .step_content {
-          padding: 0px 5px 6px 20px;
-          font-size: 10px;
-          line-height: 15px;
-        }
-      }
-    }
-
-    /* 中等屏幕笔记本:1600x900, 1920x1080 */
-    @media (min-height: 769px) and (max-height: 1080px) {
-      .nav_item {
-        margin-bottom: 15px;
-
-        .step_header_title {
-          font-size: 16px;
-          line-height: 30px;
-        }
-
-        .step_content {
-          padding: 0px 5px 6px 20px;
-          font-size: 12px;
-          line-height: 15px;
-        }
-      }
-    }
-
-    /* 大屏幕/高分辨率设备:2560x1440 及以上 */
-    @media screen and (min-height: 1081px) {
-      .nav_item {
-        margin-bottom: 25px;
-
-        .step_header_title {
-          font-size: 17px;
-          line-height: 30px;
-        }
-
-        .step_content {
-          padding: 10px 5px 10px 20px;
-          font-size: 14px;
-          line-height: 15px;
-        }
-      }
-    }
-  }
-}
-</style>

+ 25 - 0
src/layout/components/AppHeader.vue

@@ -0,0 +1,25 @@
+<template>
+    <div class="app_header">
+        智能教学评价系统
+    </div>
+</template>
+
+
+<script setup lang="ts"></script>
+
+
+<style lang="scss" scoped>
+.app_header{
+    flex-shrink: 0;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    width: 100%;
+    height: calc(44 * var(--app-rpx));
+    border-bottom:1px solid #F3F3F3;;
+    background-color: white;
+    font-weight: 600;
+    font-size: calc(16 * var(--app-rpx));
+    color: #333;
+}
+</style>

+ 2 - 35
src/layout/components/AppMain.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="container">
-    <component :menuItems="menuItems" :is="finalSideBar"></component>
+    <SiderBar v-if="menuItems?.length  > 0" :menuItems="menuItems"  />
     <!-- <el-main class="main_container"> -->
     <router-view></router-view>
     <!-- </el-main> -->
@@ -9,50 +9,17 @@
 
 <script>
 import SiderBar from './SiderBar.vue'
-import ReviewManagementDetailSideBar from '@/components/ReviewManagementDetailSideBar.vue'
+
 export default {
   components: {
     SiderBar,
-    ReviewManagementDetailSideBar
   },
   props:{
     menuItems:Array
   },
-  computed: {
-    finalSideBar() {
-      return this.$route.path.startsWith('/main/reviewManagementDetail') ? 
-              ReviewManagementDetailSideBar : 
-              (this.menuItems?.length  > 0 ?  SiderBar : null)
-    }
-  }
 }
 </script>
 
-<script setup>
-  import {  reactive } from 'vue';
-
-  // 评价管理 的 步骤公共信息 下发
-  const evaluationManageStepData  = reactive({
-    evaluationManageDetailName:'',  // 评价管理任务名称
-    
-    evaluationType:null,   // 评价方式  0-线上匿名,1-线下答卷,2-线上导入,3-线上实名
-
-
-    isHeadTeacherInvolved:null,    //班主任是否参与评价
-    isGenerateAccountByGender:null,  // 是否按男女生成评价账号
-    isGenerateReviewCode:null,  //是否已生成评价码
-    // 各个步骤的完成状态
-    isFinishEvaluationData:null,  // 评价数据是否完成
-    isFinishTeachingRelationship:null, // 授课关系是否完成
-    isFinishQuestionnaireTemplate:null,  //问卷模板是否完成
-    isFinishReviewAccount:null,  //评价账号是否完成
-    isFinishParameterSetting:null,   //参数设置是否完成
-    isFinishEvaluationProgress:null, //评价进度是否完成
-    isFinsihGenerateAnalysis:null,  //生成分析是否完成
-  })
-
-</script>
-
 <style scoped lang="scss">
 .container {
     /* border:solid blue 2px; */

+ 13 - 4
src/layout/index.vue

@@ -1,9 +1,7 @@
 <template>
   <div class="layout">
-    <Header 
-      v-if="!route.path.startsWith('/main/reviewManagementDetail')" 
-      :horizontalNavList="horizontalNavList"/>
-    <AppMain :menuItems="menuList" />
+    <component :is="finalHeader" :horizontalNavList="horizontalNavList" />
+    <AppMain :menuItems="menuList"/>
   </div>
 </template>
 
@@ -11,6 +9,7 @@
 <script setup lang="ts">
 import {computed,ref} from 'vue'
 import Header from './components/header.vue'
+import AppHeader from './components/AppHeader.vue'
 import AppMain from './components/AppMain.vue'
 import { useStore } from 'vuex'
 import { useRoute } from 'vue-router'
@@ -27,4 +26,14 @@ const horizontalNavList = computed(()=>{
   return []
 })
 
+const finalHeader = computed(()=>{
+  if(route.path.startsWith('/main')){
+    return Header
+  }else if(route.path.startsWith('/app') && 
+           route.path !== '/app' && 
+           route.path !== '/app/' ){
+    return AppHeader
+  }
+})
+
 </script>

+ 6 - 1
src/router/index.ts

@@ -48,14 +48,19 @@ const routes: Array<RouteRecordRaw> = [
   {
     path: '/app',
     name: 'app',
+    component: Layout,
     children: [
       {
         path: '',
         name: 'appStudentEntry',    //学生入口
         component: () => import('@/views/appView/StudentEntry.vue')
       },
+      {
+        path: 'questionnaireTaskListPage',
+        name: 'appQuestionnaireTaskListPage',    //问卷任务页
+        component: () => import('@/views/appView/QuestionnaireTaskListPage.vue')
+      },
     ]
-
   },
 
 

+ 126 - 0
src/views/appView/QuestionnaireTaskListPage.vue

@@ -0,0 +1,126 @@
+<template>
+    <div class="main_container">
+        <div class="questionnaire_card">
+            <div class="title">{{ questionnaire.evaluationName }}</div>
+            <div class="time_group">
+                <span class="time">开始时间:{{ questionnaire.evaluationStartDatetime }}</span>
+                <span class="time">结束时间:{{ questionnaire.evaluationEndDatetime }}</span>
+            </div>
+            <div class="operation">
+                <el-button class="button_border" @click="GoEnter(questionnaire)">进入</el-button>
+            </div>
+        </div>
+        <SubjectAndClassChooseDialog 
+            v-if="formVisible"
+            v-model:formVisible="formVisible"
+            @confirm="ConfirmFormDialog"
+        ></SubjectAndClassChooseDialog>
+    </div>
+</template>   
+
+<script setup lang="ts">
+import { onMounted, ref } from 'vue';
+
+import { useRouter } from 'vue-router';
+import SubjectAndClassChooseDialog from '@/components/subjectAndClassChooseDialog/SubjectAndClassChooseDialog.vue';
+
+const router = useRouter()
+
+interface QuestionnaireData {
+    id:string
+    evaluationName:string   //任务名称
+    evaluationStartDatetime:string  //任务开始时间
+    evaluationEndDatetime:string   //任务结束时间
+}
+// 问卷列表
+const questionnaire = ref<QuestionnaireData|{}>({})
+
+
+// 处理进入问卷逻辑
+const GoEnter = (row)=>{
+    console.log(row.id)
+    if(row.showSelectSubject){
+        // 需要调用弹窗接口
+        OpenFormDialog()
+    }else{
+        router.push('/main/selfQuestionnaireProcess')
+    }
+}
+
+
+// 选择科目/班级弹窗
+const formVisible = ref(false)
+const OpenFormDialog = ()=>{
+    formVisible.value = true
+}
+const ConfirmFormDialog = (params)=>{
+    router.push('/main/selfQuestionnaireProcess')
+}
+
+onMounted(()=>{
+    let userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}')
+    questionnaire.value = userInfo.evaluationBO
+})
+</script>
+
+
+
+<style lang="scss" scoped>
+.main_container{
+    flex-shrink: 0;
+    align-items: center;
+    overflow: auto;
+    background-color: #ffffff !important;
+
+    .questionnaire_card{
+        margin-top: calc(92 * var(--app-rpx));
+        flex-shrink: 0;
+        display: flex;
+        flex-direction: column;
+        align-items: flex-start;
+        width: calc(300 * var(--app-rpx));
+        height: calc(400 * var(--app-rpx));
+        padding:calc(40 * var(--app-rpx)) calc(20 * var(--app-rpx));
+        background-image: url('@/assets/studentQuestionnaire/questionnaire_bg.png');
+        background-repeat: no-repeat;
+        background-size: 100% 100%; 
+
+        .title{
+            font-weight: 600;
+            font-size: calc(20 * var(--app-rpx));
+            color: #FFFFFF;
+            margin-bottom:  calc(20 * var(--app-rpx));
+        }
+
+        .time_group{
+            display: flex;
+            flex-direction: column;
+            gap: calc(10 * var(--app-rpx));
+            font-weight: 400;
+            font-size: calc(14 * var(--app-rpx));
+            color: rgba(255,255,255,0.8);
+        }
+
+        .operation{
+            flex: 1 1 ;
+            width: 100%;
+            display: flex;
+            flex-direction: column;
+            justify-content: flex-end;
+            .button_border{ 
+                :deep(>span){
+                    display: flex;
+                    align-items: center;
+                    justify-content: center;
+                }
+                width: 100%;
+                height: calc(52 * var(--app-rpx));
+                font-weight: 600;
+                font-size:  calc(18 * var(--app-rpx)); 
+                color: #2E64FA;
+            }
+        }
+    }
+}
+
+</style>

+ 2 - 1
src/views/appView/StudentEntry.vue

@@ -41,13 +41,14 @@ const handleEnter = async() => {
   if(res?.code == 200){
     localStorage.setItem('userInfo', JSON.stringify(res.data))
     localStorage.setItem('token', res.data.tokenValue)
-    router.push('/main/questionnaireTaskListPage')
+    router.push('/app/questionnaireTaskListPage')
   }
 };
 </script>
 
 <style lang="scss" scoped>
 .main_container {
+    padding:0 !important;
     overflow: auto;
     height: 100%;
     background-color: #ffffff !important;