Bladeren bron

同步对口升学模拟考试代码

shmily1213 16 uur geleden
bovenliggende
commit
b597ad483c
36 gewijzigde bestanden met toevoegingen van 1137 en 336 verwijderingen
  1. 9 1
      src/api/modules/study.ts
  2. 4 1
      src/components/ie-page/ie-page.vue
  3. 71 66
      src/components/ie-table/ie-table.vue
  4. 0 2
      src/pagesMain/pages/index/index.vue
  5. 59 0
      src/pagesStudy/components/ie-exam-record-item.vue
  6. 2 2
      src/pagesStudy/components/knowledge-table.vue
  7. 10 8
      src/pagesStudy/components/paper-work-item.vue
  8. 1 1
      src/pagesStudy/components/practice-table.vue
  9. 95 0
      src/pagesStudy/components/vhs-exam-item.vue
  10. 69 0
      src/pagesStudy/components/vhs-exam-record-item.vue
  11. 23 4
      src/pagesStudy/pages/exam-start/components/exam-subtitle.vue
  12. 76 11
      src/pagesStudy/pages/exam-start/exam-start.vue
  13. 38 0
      src/pagesStudy/pages/index/compoentns/ie-exam.vue
  14. 9 3
      src/pagesStudy/pages/index/compoentns/index-banner.vue
  15. 3 8
      src/pagesStudy/pages/index/compoentns/index-menu.vue
  16. 146 0
      src/pagesStudy/pages/index/compoentns/index-practice-entry.vue
  17. 69 0
      src/pagesStudy/pages/index/compoentns/vhs-exam.vue
  18. 19 101
      src/pagesStudy/pages/index/index.vue
  19. 30 31
      src/pagesStudy/pages/simulation-analysis/simulation-analysis.vue
  20. 11 59
      src/pagesStudy/pages/study-history/components/exam-history.vue
  21. 57 0
      src/pagesStudy/pages/study-history/components/ie-exam-history-student.vue
  22. 18 0
      src/pagesStudy/pages/study-history/components/ie-exam-history-teacher.vue
  23. 66 0
      src/pagesStudy/pages/study-history/components/ie-exam-history.vue
  24. 3 1
      src/pagesStudy/pages/study-history/components/knowledge-history-student.vue
  25. 1 1
      src/pagesStudy/pages/study-history/components/knowledge-history.vue
  26. 1 1
      src/pagesStudy/pages/study-history/components/practice-history.vue
  27. 32 0
      src/pagesStudy/pages/study-history/components/vhs-exam-history-student.vue
  28. 93 0
      src/pagesStudy/pages/study-history/components/vhs-exam-history-teacher.vue
  29. 44 0
      src/pagesStudy/pages/study-history/components/vhs-exam-history.vue
  30. 8 5
      src/pagesStudy/pages/study-history/study-history.vue
  31. 8 8
      src/pagesSystem/pages/bind-profile/bind-profile.vue
  32. 9 9
      src/pagesSystem/pages/bind-teacher-profile/bind-teacher-profile.vue
  33. 1 1
      src/pagesSystem/pages/edit-profile/edit-profile.vue
  34. 3 0
      src/store/userStore.ts
  35. 43 3
      src/types/study.ts
  36. 6 9
      src/types/transfer.ts

+ 9 - 1
src/api/modules/study.ts

@@ -1,6 +1,6 @@
 import { ApiResponse, ApiResponseList } from "@/types";
 import flyio from "../flyio";
-import type { Batch, ClassKnowledgeRecord, DirectedSchool, Examinee, ExamPaper, ExamPaperSubmit, FavoriteQuestion, FavoriteQuestionListRequestDTO, GetExamPaperRequestDTO, Knowledge, KnowledgeListRequestDTO, KnowledgeRecord, OpenExamineeRequestDTO, PaperWork, PaperWorkRecord, PaperWorkRecordDetail, PaperWorkRecordQuery, PracticeHistory, PracticeRecord, SimulatedRecord, SimulationExamSubject, SimulationTestInfo, StudentExamRecord, StudentPlanStudyRecord, StudentSubject, StudentVideoRecord, StudyPlan, Subject, SubjectListRequestDTO, TeachClass, VideoCourse, VideoCourseKnowledge, VideoCoursePlayInfo, VideoCourseRecordDTO, VideoCourseRequestDTO, VideoCourseSubject, VideoCourseSubjectRequestDTO, VideoStudy, WrongBookQuestion, WrongBookQuestionRequestDTO } from "@/types/study";
+import type { Batch, ClassKnowledgeRecord, DirectedSchool, Examinee, ExamPaper, ExamPaperSubmit, FavoriteQuestion, FavoriteQuestionListRequestDTO, GetExamPaperRequestDTO, Knowledge, KnowledgeListRequestDTO, KnowledgeRecord, OpenExamineeRequestDTO, PaperWork, PaperWorkRecord, PaperWorkRecordDetail, PaperWorkRecordQuery, PracticeHistory, PracticeRecord, SimulatedRecord, SimulationExamSubject, SimulationTestInfo, StudentExamRecord, StudentPlanStudyRecord, StudentSubject, StudentVideoRecord, StudyPlan, Subject, SubjectListRequestDTO, TeachClass, VHSPaper, VHSPaperListRequestDTO, VideoCourse, VideoCourseKnowledge, VideoCoursePlayInfo, VideoCourseRecordDTO, VideoCourseRequestDTO, VideoCourseSubject, VideoCourseSubjectRequestDTO, VideoStudy, WrongBookQuestion, WrongBookQuestionRequestDTO } from "@/types/study";
 import { EnumPaperWorkState } from "@/common/enum";
 
 /**
@@ -116,6 +116,14 @@ export function getExamineeResult(examineeId: number) {
   return flyio.get('/front/exam/loadExaminee', { examineeId }) as Promise<ApiResponse<Examinee>>;
 }
 
+/**
+ * 对口升学-获取真题&模拟试卷
+ * @param params 
+ * @returns 
+ */
+export function getVHSPaperList(params: VHSPaperListRequestDTO) {
+  return flyio.get('/front/paper/list', params) as Promise<ApiResponse<VHSPaper[]>>;
+}
 
 /**
  * 获取模拟考试信息

+ 4 - 1
src/components/ie-page/ie-page.vue

@@ -111,7 +111,10 @@ onUnload(() => {
 }
 
 .is-fixed {
-  height: 1px;
+  height: 100vh;
+  .ie-page-content {
+    height: 100%;
+  }
 }
 
 .ie-fixed-bottom {

+ 71 - 66
src/components/ie-table/ie-table.vue

@@ -1,119 +1,124 @@
 <template>
-    <view class="">
-        <view class="table-header">
-            <view class="table-header-cell" v-for="item in tableColumns" :key="item.prop" :style="getHeaderStyle(item)">
-                {{ item.label }}
-            </view>
-        </view>
-        <view class="table-body">
-            <block v-if="data.length">
-                <view class="table-row" :class="{ 'sibling-border-top': getTableConfig.border }"
-                      v-for="(row, index) in data"
-                      :key="getRowKey(row, index)" @click="handleRowClick(row)">
-                    <view class="table-row-cell" v-for="item in tableColumns" :key="item.prop"
-                          :style="getCellStyle(item)">
-                        <view v-if="item.type === 'index'">
-                            {{ index + 1 }}
-                        </view>
-                        <template v-else-if="item.slot">
-                            <slot :name="item.slot" :item="row" :index="index"></slot>
-                        </template>
-                        <text v-else>{{ getCellValue(row, item.prop) }}</text>
-                    </view>
-                </view>
-            </block>
-            <view v-else class="no-data">{{ getTableConfig.emptyText }}</view>
-        </view>
+  <view class="w-full" :class="{ 'h-full flex flex-col': headerFixed }">
+    <view class="table-header">
+      <view class="table-header-cell" v-for="item in tableColumns" :key="item.prop" :style="getHeaderStyle(item)">
+        {{ item.label }}
+      </view>
     </view>
+    <scroll-view :class="{ 'flex-1 min-h-1': headerFixed }" scroll-y>
+      <view class="table-body">
+        <block v-if="data.length">
+          <view class="table-row" :class="{ 'sibling-border-top': getTableConfig.border }" v-for="(row, index) in data"
+            :key="getRowKey(row, index)" @click="handleRowClick(row)">
+            <view class="table-row-cell" v-for="item in tableColumns" :key="item.prop" :style="getCellStyle(item)">
+              <view v-if="item.type === 'index'">
+                {{ index + 1 }}
+              </view>
+              <template v-else-if="item.slot">
+                <slot :name="item.slot" :item="row" :index="index"></slot>
+              </template>
+              <text v-else>{{ getCellValue(row, item.prop) }}</text>
+            </view>
+          </view>
+        </block>
+        <view v-else class="no-data">{{ getTableConfig.emptyText }}</view>
+      </view>
+    </scroll-view>
+  </view>
 </template>
 
 <script lang="ts" setup generic="T extends Record<string, any>">
-import {TableColumnConfig, TableConfig} from '@/types';
-import {CSSProperties} from 'vue';
+import { TableColumnConfig, TableConfig } from '@/types';
+import { CSSProperties } from 'vue';
 
 // 使用泛型定义props
 interface Props<T> {
-    tableConfig: TableConfig;
-    tableColumns: TableColumnConfig[];
-    data: T[];
-    cellStyle: CSSProperties;
-    headerStyle: CSSProperties;
+  tableConfig: TableConfig;
+  tableColumns: TableColumnConfig[];
+  data: T[];
+  cellStyle: CSSProperties;
+  headerStyle: CSSProperties;
+  headerFixed?: boolean;
 }
 
 const props = defineProps<Props<any>>();
 
 // 使用泛型定义emits
 const emit = defineEmits<{
-    rowClick: [row: T]
+  rowClick: [row: T]
 }>();
 
 const getTableConfig = computed(() => {
-    return {
-        ...{
-            border: true,
-            stripe: false,
-            emptyText: '暂无数据',
-            loading: false,
-            rowKey: 'id'
-        },
-        ...props.tableConfig
-    };
+  return {
+    ...{
+      border: true,
+      stripe: false,
+      emptyText: '暂无数据',
+      loading: false,
+      rowKey: 'id'
+    },
+    ...props.tableConfig
+  };
 });
 
 const getHeaderStyle = (item: TableColumnConfig) => {
-    return {
-        flex: item.flex ? item.flex : 1,
-        minWidth: '1px',
-        textAlign: item.headerAlign ? item.headerAlign : 'center',
-        ...props.headerStyle
-    };
+  return {
+    flex: item.flex ? item.flex : 1,
+    minWidth: '1px',
+    textAlign: item.headerAlign ? item.headerAlign : 'center',
+    ...props.headerStyle
+  };
 };
 
 const getCellStyle = (item: TableColumnConfig) => {
-    return {
-        flex: item.flex ? item.flex : 1,
-        minWidth: '1px',
-        flexShrink: 0,
-        width: '100%',
-        textAlign: item.align ? item.align : 'center',
-        ...props.cellStyle
-    };
+  return {
+    flex: item.flex ? item.flex : 1,
+    minWidth: '1px',
+    flexShrink: 0,
+    width: '100%',
+    textAlign: item.align ? item.align : 'center',
+    ...props.cellStyle
+  };
 };
 
 const handleRowClick = (row: any) => {
-    emit('rowClick', row);
+  emit('rowClick', row);
 };
 
 // 安全地获取行key
 const getRowKey = (row: any, index: number) => {
-    const rowKey = getTableConfig.value.rowKey;
-    return row[rowKey] || index;
+  const rowKey = getTableConfig.value.rowKey;
+  return row[rowKey] || index;
 };
 
 // 安全地获取单元格值
 const getCellValue = (row: any, prop: string) => {
-    return row[prop] || props.tableConfig.defaultValue || '';
+  return row[prop] || props.tableConfig.defaultValue || '';
 };
 </script>
 
 <style lang="scss" scoped>
 .table-header {
-    @apply flex items-center bg-[#EBF9FF] rounded-5 overflow-hidden;
+  @apply w-full flex items-center bg-[#EBF9FF] rounded-5 overflow-hidden;
 }
 
 .table-header-cell {
-    @apply flex-1 px-20 py-20 text-30 text-fore-light;
+  @apply flex-1 px-20 py-20 text-30 text-fore-light;
 }
 
 .table-row {
-    @apply flex items-center;
+  @apply flex items-center;
 }
 
 .table-row-cell {
-    @apply px-20 py-20 text-28 text-fore-title;
+  @apply px-20 py-20 text-28 text-fore-title;
 }
 
 .no-data {
-    @apply mt-16 bg-[#F6F8FA] text-center py-50 text-26 text-fore-light rounded-5;
+  @apply mt-16 bg-[#F6F8FA] text-center py-50 text-26 text-fore-light rounded-5;
+}
+
+.fixed {
+  @apply sticky top-0 z-1;
 }
 </style>

+ 0 - 2
src/pagesMain/pages/index/index.vue

@@ -4,8 +4,6 @@
       <template #headerLeft>
         <view class="flex items-center gap-7 text-fore-title">
           <view class="text-38 font-bold">{{ orgName }}</view>
-          <text>·</text>
-          <view class="text-30 font-medium">升学备考好帮手</view>
         </view>
       </template>
       <template #headerRight="{ isTransparent }">

+ 59 - 0
src/pagesStudy/components/ie-exam-record-item.vue

@@ -0,0 +1,59 @@
+<template>
+  <view class="bg-white">
+    <view class="text-30 text-fore-title">{{ data.name }}</view>
+    <view class="mt-32 flex items-center justify-between">
+      <view class="text-24 text-fore-light">提交时间: {{ data.date || '-' }}</view>
+      <view class="text-28 text-primary flex items-center gap-x-4" @click="handleDetail">
+        <text>{{ isFinished ? '查看分析' : '继续考试' }}</text>
+        <uv-icon name="arrow-right" size="14" color="var(--primary-color)" />
+      </view>
+    </view>
+    <view
+      class="mt-20 border border-solid border-[#FEF6DA] bg-[#FFFBEB] rounded-5 py-20 px-16 flex items-center justify-between">
+      <view class="text-24 text-[#F59E0B]">考试科目:{{ data.subjectName }}</view>
+      <view class="text-24 text-[#F59E0B]">卷面得分:{{ getScore }}</view>
+    </view>
+  </view>
+</template>
+<script lang="ts" setup>
+import { Study, Transfer } from '@/types';
+import { useTransferPage } from '@/hooks/useTransferPage';
+import { EnumPaperType, EnumSimulatedRecordStatus } from '@/common/enum';
+import { beginExaminee } from '@/api/modules/study';
+const { transferTo } = useTransferPage<any, Transfer.SimulationAnalysisPageOptions | Transfer.ExamAnalysisPageOptions>();
+const props = defineProps<{
+  data: Study.SimulatedRecord;
+}>();
+const isFinished = computed(() => {
+  return props.data.state === EnumSimulatedRecordStatus.SUBMIT;
+});
+const getScore = computed(() => {
+  if (props.data.score === undefined || props.data.score === null) {
+    return '-';
+  }
+  return props.data.score;
+})
+const handleDetail = () => {
+  if (isFinished.value) {
+    transferTo('/pagesStudy/pages/simulation-analysis/simulation-analysis', {
+      data: {
+        examineeId: props.data.id,
+        paperType: EnumPaperType.SIMULATED
+      }
+    });
+  } else {
+    transferTo('/pagesStudy/pages/exam-start/exam-start', {
+      data: {
+        // name: '模拟考试-' + props.data.subjectName,
+        paperType: EnumPaperType.SIMULATED,
+        readonly: false,
+        simulationInfo: {
+          examineeId: props.data.id,
+          name: props.data.subjectName,
+        }
+      }
+    });
+  }
+};
+</script>
+<style lang="scss" scoped></style>

+ 2 - 2
src/pagesStudy/components/knowledge-table.vue

@@ -1,6 +1,6 @@
 <template>
-  <view class="p-30">
-    <ie-table :table-columns="tableColumns" :table-config="tableConfig" :data="data">
+  <view class="h-full p-30 box-border">
+    <ie-table :table-columns="tableColumns" :table-config="tableConfig" :data="data" :header-fixed="true">
       <template #name="{ item }">
         <view class="">
           <text class="leading-38">{{ item.name }}</text>

+ 10 - 8
src/pagesStudy/components/paper-work-item.vue

@@ -3,7 +3,7 @@
     <view class="border-bottom flex items-center justify-between py-32 px-25 leading-27">
       <view class="text-28 text-fore-light flex items-center">
         <view class="w-12 h-12 rounded-full bg-[#E5E5E5]"></view>
-        <view class="ml-10">{{ publishTime }}{{  `${data.publishUser ? `-${data.publishUser}` : ''}` }}</view>
+        <view class="ml-10">{{ publishTime }}{{ `${data.publishUser ? `-${data.publishUser}` : ''}` }}</view>
       </view>
       <view :class="['text-28', data.state === EnumPaperWorkState.NOT_COMPLETED ? 'text-warning' : 'text-success']">
         {{ data.state === EnumPaperWorkState.NOT_COMPLETED ? '未完成' : '已完成' }}
@@ -93,14 +93,16 @@ const handleStart = () => {
     relateId: props.data.id,
     directed: props.data.directed
   }).then(res => {
+    const pageOptions: Transfer.ExamAnalysisPageOptions = {
+      paperType: EnumPaperType.TEST,
+      readonly: false,
+      simulationInfo: {
+        examineeId: res.data.examineeId,
+        name: batchName.value
+      },
+    }
     transferTo('/pagesStudy/pages/exam-start/exam-start', {
-      data: {
-        name: '组卷作业-' + batchName.value,
-        paperType: EnumPaperType.TEST,
-        simulationInfo: {
-          examineeId: res.data.examineeId
-        },
-      } as Transfer.ExamAnalysisPageOptions,
+      data: pageOptions,
     });
   }).catch(err => {
     console.error(err);

+ 1 - 1
src/pagesStudy/components/practice-table.vue

@@ -61,7 +61,7 @@
       </ie-table>
     </view>
     <ie-popup ref="calendarPopupRef" :showToolbar="false" v-if="canOpenCalendar">
-      <view class="h-[480px]">
+      <view class="h-[420px]">
         <view class="h-108 flex items-center justify-center border-0 border-b border-solid border-border">
           <view :class="['w-38 h-38 rounded-full flex items-center justify-center transition-all duration-200', prevButtonClass]" @click="canGoPrev && !loading ? handlePrev() : null">
             <uv-icon name="arrow-left" size="12" :color="canGoPrev && !loading ? '#808080' : '#CCCCCC'" />

+ 95 - 0
src/pagesStudy/components/vhs-exam-item.vue

@@ -0,0 +1,95 @@
+<template>
+  <view class="bg-white rounded-5">
+    <view class="px-30 pt-32 pb-20">
+      <view class="text-28 text-fore-title font-bold ellipsis-2">{{ data.paperName }}</view>
+      <view class="flex items-center gap-16 mt-20">
+        <view class="tag-item bg-[#FFFBEB] text-[#F97316]">{{ data.subjectName }}</view>
+        <view class="tag-item bg-back text-fore-light">{{ type === 0 ? '公共课' : '专业课' }}</view>
+      </view>
+    </view>
+    <uv-line color="#F6F8FA" />
+    <view class="px-30 py-20 flex items-center justify-between">
+      <view class="text-24 text-fore-light">
+        <text>共</text>
+        <text class="text-primary">{{ data.number }}</text>
+        <text>道题,总分</text>
+        <text class="text-primary">{{ data.fenshu }}</text>
+        <text>分</text>
+      </view>
+      <view class="px-20 py-8 border border-solid rounded-full text-24 text-white"
+        :class="[isFinished ? 'bg-success border-success' : 'bg-primary border-primary']" @click="handleStartExam">
+        <text>{{ isFinished ? '查看分析' : '开始考试' }}</text>
+      </view>
+    </view>
+  </view>
+</template>
+<script lang="ts" setup>
+import { EnumPaperType, EnumSimulatedRecordStatus, EnumUserRole } from '@/common/enum';
+import { Study, Transfer } from '@/types';
+import { useTransferPage } from '@/hooks/useTransferPage';
+import { useAuth } from '@/hooks/useAuth';
+import { getOpenExaminee } from '@/api/modules/study';
+
+const { hasPermission } = useAuth();
+const { transferTo } = useTransferPage();
+const props = defineProps<{
+  data: Study.VHSPaper;
+  type?: number
+}>();
+const isFinished = computed(() => {
+  return props.data.status === EnumSimulatedRecordStatus.SUBMIT;
+});
+
+const handleStartExam = () => {
+  const hasAuth = hasPermission([EnumUserRole.VIP]);
+  if (hasAuth) {
+    if (isFinished.value) {
+      transferTo('/pagesStudy/pages/simulation-analysis/simulation-analysis', {
+        data: {
+          examineeId: props.data.examineeId,
+          paperType: EnumPaperType.SIMULATED
+        }
+      });
+    } else {
+      console.log(props.data)
+      // return
+      // const pageOptions: Transfer.ExamAnalysisPageOptions = {
+      //   paperType: EnumPaperType.SIMULATED,
+      //   readonly: false,
+      //   simulationInfo: {
+      //     name: props.data.paperName,
+      //     // 难受
+      //     examineeId: props.data.id,
+      //   }
+      // }
+      // transferTo('/pagesStudy/pages/exam-start/exam-start', {
+      //   data: pageOptions,
+      // });
+      getOpenExaminee({
+        paperType: EnumPaperType.SIMULATED,
+        relateId: props.data.id
+      }).then(res => {
+        const pageOptions: Transfer.ExamAnalysisPageOptions = {
+          paperType: EnumPaperType.SIMULATED,
+          readonly: false,
+          simulationInfo: {
+            examineeId: res.data.examineeId,
+            name: props.data.paperName,
+          },
+        }
+        transferTo('/pagesStudy/pages/exam-start/exam-start', {
+          data: pageOptions,
+        });
+      }).catch(err => {
+        console.error(err);
+      });
+    }
+  }
+}
+
+</script>
+<style lang="scss" scoped>
+.tag-item {
+  @apply text-24 rounded-4 px-10 py-6 w-fit;
+}
+</style>

+ 69 - 0
src/pagesStudy/components/vhs-exam-record-item.vue

@@ -0,0 +1,69 @@
+<template>
+  <view class="bg-white rounded-5">
+    <view class="px-30 pt-32 pb-20">
+      <view class="text-28 text-fore-title font-bold ellipsis-2">{{ data.name }}</view>
+      <view class="flex items-center gap-16 mt-20">
+        <view class="tag-item bg-[#FFFBEB] text-[#F97316]">{{ data.subjectName }}</view>
+        <view class="tag-item bg-back text-fore-light">{{ data.subjectGroup }}</view>
+      </view>
+    </view>
+    <uv-line color="#F6F8FA" />
+    <view class="px-30 py-20 flex items-center justify-between">
+      <view class="text-24 text-fore-light">
+        <template v-if="data.score !== null">
+          <text>得分:</text>
+          <text class="text-primary">{{ data.score }}</text>
+          <text>分</text>
+        </template>
+      </view>
+      <view class="px-20 py-8 border border-solid rounded-full text-24 text-white"
+        :class="[isFinished ? 'bg-success border-success' : 'bg-primary border-primary']" @click="handleStartExam">
+        <text>{{ isFinished ? '查看分析' : '继续考试' }}</text>
+      </view>
+    </view>
+  </view>
+</template>
+<script lang="ts" setup>
+import { EnumPaperType, EnumSimulatedRecordStatus } from '@/common/enum';
+import { Study, Transfer } from '@/types';
+import { useTransferPage } from '@/hooks/useTransferPage';
+
+const { transferTo } = useTransferPage();
+const props = defineProps<{
+  data: Study.SimulatedRecord;
+  type?: number
+}>();
+const isFinished = computed(() => {
+  return props.data.state === EnumSimulatedRecordStatus.SUBMIT;
+});
+
+const handleStartExam = () => {
+  if (isFinished.value) {
+    transferTo('/pagesStudy/pages/simulation-analysis/simulation-analysis', {
+      data: {
+        examineeId: props.data.id,
+        paperType: EnumPaperType.SIMULATED
+      }
+    });
+  } else {
+    const pageOptions: Transfer.ExamAnalysisPageOptions = {
+      paperType: EnumPaperType.SIMULATED,
+      readonly: false,
+      simulationInfo: {
+        name: props.data.name,
+        // 难受
+        examineeId: props.data.id,
+      }
+    }
+    transferTo('/pagesStudy/pages/exam-start/exam-start', {
+      data: pageOptions,
+    });
+  }
+}
+
+</script>
+<style lang="scss" scoped>
+.tag-item {
+  @apply text-24 rounded-4 px-10 py-6 w-fit;
+}
+</style>

+ 23 - 4
src/pagesStudy/pages/exam-start/components/exam-subtitle.vue

@@ -8,20 +8,39 @@
   </view>
 </template>
 <script lang="ts" setup>
+import { useUserStore } from '@/store/userStore';
 import { Transfer } from '@/types';
 import { EXAM_PAGE_OPTIONS, EXAM_DATA } from '@/types/injectionSymbols';
 import { useExam } from '@/composables/useExam';
 
+const userStore = useUserStore();
 const examPageOptions = inject(EXAM_PAGE_OPTIONS) || {} as Transfer.ExamAnalysisPageOptions;
 const examData = inject(EXAM_DATA) || {} as ReturnType<typeof useExam>;
 const { virtualCurrentIndex, virtualTotalCount } = examData;
 
 const pageSubtitle = computed(() => {
-  if (examPageOptions) {
-    const { name } = examPageOptions;
-    return name;
+  if (examPageOptions && examPageOptions.practiceInfo) {
+    const { practiceInfo: { directed, questionType, name } } = examPageOptions;
+    let titlePrefix = '';
+    if (userStore.isVHS) {
+      if (questionType === 0) {
+        titlePrefix = '知识点练习';
+      } else if (questionType === 2) {
+        titlePrefix = '必刷题';
+      }
+    } else {
+      if (directed) {
+        titlePrefix = '定向刷题';
+      } else {
+        titlePrefix = '全量刷题';
+      }
+    }
+    return titlePrefix + '-' + name;
+  } else if (examPageOptions && examPageOptions.simulationInfo) {
+    const { simulationInfo: { name } } = examPageOptions;
+    return '模拟考试' + '-' + name || '模拟考试';
   }
-  return '';
+  return '知识点练习';
 });
 </script>
 <style lang="scss" scoped></style>

+ 76 - 11
src/pagesStudy/pages/exam-start/exam-start.vue

@@ -2,7 +2,7 @@
   <ie-page :fix-height="true" :safe-area-inset-bottom="false">
     <block v-if="isReady">
       <exam-navbar :total-exam-time="totalExamTime" @left-click="handleLeftClick" @right-click="handleRightClick" />
-      <exam-subtitle :total-exam-time="totalExamTime" />
+      <exam-subtitle />
       <exam-swiper @submit="beforeSubmit" />
       <exam-toolbar ref="examToolbarRef" @submit="beforeSubmit" />
     </block>
@@ -78,7 +78,9 @@ const totalExamTime = ref<number>(0);
 const hasShowSubmitConfirm = ref(false);
 const examineeId = ref<number | undefined>(undefined);
 const paperData = ref<Study.ExamPaper>({} as Study.ExamPaper);
-const examToolbarRef = ref();
+// 是否确认退出
+const confirmQuit = ref(false);
+const confirmShowing = ref(false);
 /**
  * 自动提交
  */
@@ -111,6 +113,7 @@ const isReadOnly = computed(() => {
 });
 const handleLeftClick = () => {
   if (!isReady.value || isReadOnly.value) {
+    confirmQuit.value = true;
     transferBack();
     return;
   }
@@ -133,6 +136,7 @@ const beforeQuit = () => {
   }
   stopTime();
   const msg = paperType === EnumPaperType.PRACTICE ? '当前练习未完成,确认退出?' : '当前考试未完成,确认退出?';
+  confirmShowing.value = true;
   uni.$ie.showModal({
     title: '提示',
     content: msg,
@@ -140,6 +144,8 @@ const beforeQuit = () => {
     if (confirm) {
       handleSubmit(true);
     } else {
+      confirmQuit.value = false;
+      confirmShowing.value = false;
       startTime();
     }
   });
@@ -180,7 +186,7 @@ const handleSubmit = (tempSave: boolean = false) => {
   const msg = tempSave ? '保存中...' : '提交中...';
   uni.$ie.showLoading(msg);
   setTimeout(async () => {
-    const params = {
+    const params: Study.ExamPaperSubmit = {
       ...paperData.value,
       questions: questionList.value.map(item => {
         return {
@@ -199,7 +205,7 @@ const handleSubmit = (tempSave: boolean = false) => {
       // examineeId: examineerData.value.examineeId,
       isDone: tempSave ? isAllDone.value : true,
       duration: practiceDuration.value
-    } as Study.ExamPaperSubmit;
+    };
     console.log('提交试卷参数', params)
     await commitExamineePaper(params);
     if (isSimulationExam.value || isTestExam.value) {
@@ -207,6 +213,8 @@ const handleSubmit = (tempSave: boolean = false) => {
         setTimeout(async () => {
           uni.$ie.hideLoading();
           await nextTick();
+          confirmQuit.value = true;
+          confirmShowing.value = false;
           transferTo('/pagesStudy/pages/simulation-analysis/simulation-analysis', {
             data: {
               examineeId: examineeId.value,
@@ -217,6 +225,8 @@ const handleSubmit = (tempSave: boolean = false) => {
         }, 2500);
       } else {
         uni.$ie.hideLoading();
+        confirmQuit.value = true;
+        confirmShowing.value = false;
         nextTick(() => {
           transferBack();
         });
@@ -226,18 +236,23 @@ const handleSubmit = (tempSave: boolean = false) => {
         setTimeout(async () => {
           uni.$ie.hideLoading();
           await nextTick();
+          confirmQuit.value = true;
+          confirmShowing.value = false;
           transferTo('/pagesStudy/pages/knowledge-practice-detail/knowledge-practice-detail', {
             data: {
               paperType: prevData.value.paperType,
               examineeId: examineeId.value,
               name: prevData.value.practiceInfo?.name,
-              directed: prevData.value.practiceInfo?.directed
+              directed: prevData.value.practiceInfo?.directed,
+              questionType: prevData.value.practiceInfo?.questionType
             } as Transfer.PracticeResultPageOptions,
             type: 'redirectTo'
           });
         }, 2500);
       } else {
         uni.$ie.hideLoading();
+        confirmQuit.value = true;
+        confirmShowing.value = false;
         nextTick(() => {
           transferBack();
         });
@@ -276,6 +291,7 @@ const restoreQuestion = (savedQuestion: Study.ExamineeQuestion[], fullQuestion:
   }
   return fullQuestion;
 }
+// 1、加载知识点练习数据
 const loadPracticeData = async () => {
   const { paperType, readonly, practiceInfo } = prevData.value;
   let data: Study.Examinee | null = null;
@@ -285,11 +301,16 @@ const loadPracticeData = async () => {
       data = res.data;
     }
   } else {
-    const res = await getOpenExaminee({
+    const params = {
       paperType: paperType,
       relateId: practiceInfo?.relateId,
-      directed: practiceInfo?.directed || false
-    });
+    } as Study.OpenExamineeRequestDTO;
+    if (userStore.isVHS) {
+      params.questionType = practiceInfo?.questionType;
+    } else {
+      params.directed = practiceInfo?.directed || false;
+    }
+    const res = await getOpenExaminee(params);
     data = res.data || {};
   }
 
@@ -302,6 +323,7 @@ const loadPracticeData = async () => {
   totalExamTime.value = Number.MAX_SAFE_INTEGER;
   combinePaperData(data, paperType);
 }
+// 2、加载模拟考试数据
 const loadExamData = async () => {
   const { paperType, readonly, simulationInfo } = prevData.value;
   let data: Study.Examinee;
@@ -322,6 +344,31 @@ const loadExamData = async () => {
     combinePaperData(data, paperType);
   }
 }
+// 3、加载对口升学试卷数据
+// const loadVHSPaperData = async () => {
+//   const { paperType, readonly, simulationInfo } = prevData.value;
+//   let data: Study.Examinee;
+//   if (simulationInfo?.examineeId) {
+//     if (readonly) {
+//       const res = await getExamineeResult(simulationInfo.examineeId);
+//       data = res.data;
+//     } else {
+//       const params = {
+//         paperType: paperType,
+//         relateId: simulationInfo?.examineeId,
+//       } as Study.OpenExamineeRequestDTO;
+//       const res = await getOpenExaminee(params);
+//       data = res.data || {};
+//     }
+//     if (!data) {
+//       uni.$ie.hideLoading();
+//       transferBack();
+//       return;
+//     }
+//     totalExamTime.value = data.paperInfo?.time || Number.MAX_SAFE_INTEGER;
+//     combinePaperData(data, paperType);
+//   }
+// }
 const combinePaperData = async (examinee: Study.Examinee, paperType: EnumPaperType) => {
   examineeId.value = examinee.examineeId;
   if (examinee.paperId) {
@@ -373,9 +420,7 @@ const handleSwiperTipNext = () => {
 }
 const handleGuideClose = () => {
   userStore.isExamGuideShow = true;
-  if (!isReadOnly.value) {
-    startTime();
-  }
+  startTime();
 }
 const loadData = async () => {
   uni.$ie.showLoading();
@@ -383,12 +428,32 @@ const loadData = async () => {
   if (paperType === EnumPaperType.PRACTICE || paperType === EnumPaperType.COURSE) {
     loadPracticeData();
   } else if (paperType === EnumPaperType.SIMULATED || paperType === EnumPaperType.TEST) {
+    // if (paperType === EnumPaperType.SIMULATED && userStore.isVHS) {
+    //   loadVHSPaperData();
+    // } else {
+    //   loadExamData();
+    // }
     loadExamData();
   }
 };
 onLoad(() => {
   console.log(prevData.value)
   loadData();
+  uni.addInterceptor('navigateBack', {
+    invoke: (e) => {
+      if (confirmShowing.value) {
+        return false;
+      }
+      if (confirmQuit.value) {
+        return e;
+      }
+      handleLeftClick();
+      return false;
+    }
+  })
+});
+onUnload(() => {
+  uni.removeInterceptor('navigateBack');
 });
 </script>
 

+ 38 - 0
src/pagesStudy/pages/index/compoentns/ie-exam.vue

@@ -0,0 +1,38 @@
+<template>
+  <view>
+    <view class="h-16 bg-back my-32"></view>
+    <index-test :directed-school="directedSchool" />
+    <view v-if="list.length > 0" class="px-30 pb-30 bg-back">
+      <view class="h-94 flex items-center justify-center">
+        <view class="h-0 w-160 border-0 border-b border-dashed border-border"></view>
+        <ie-image src="/pagesStudy/static/image/icon-ear-left.png" customClass="w-20 h-26 ml-26 mr-30" />
+        <view class="text-30 text-fore-title font-bold">考试记录</view>
+        <ie-image src="/pagesStudy/static/image/icon-ear-right.png" customClass="w-20 h-26 ml-26 mr-30" />
+        <view class="h-0 w-160 border-0 border-b border-dashed border-border"></view>
+      </view>
+      <view v-for="value in list" :key="value.id" class="rounded-10 mb-20 bg-white px-20 py-38">
+        <ie-exam-record-item :data="value" />
+      </view>
+    </view>
+  </view>
+</template>
+<script lang="ts" setup>
+import IndexTest from './index-test.vue';
+import IeExamRecordItem from '@/pagesStudy/components/ie-exam-record-item.vue';
+import { getSimulatedRecord } from '@/api/modules/study';
+import { Study } from '@/types';
+
+const props = defineProps<{
+  directedSchool: Study.DirectedSchool;
+}>();
+
+const list = ref<Study.SimulatedRecord[]>([]);
+const loadData = async () => {
+  const { data } = await getSimulatedRecord();
+  list.value = data || [];
+}
+onShow(() => {
+  loadData();
+});
+</script>
+<style lang="scss" scoped></style>

+ 9 - 3
src/pagesStudy/pages/index/compoentns/index-banner.vue

@@ -1,8 +1,8 @@
 <template>
   <view class="mx-30 mt-40">
     <!-- <ie-image :is-oss="true" src="/banner/index-banner-4.png" :round="10" customClass="w-full h-178" mode="widthFix" /> -->
-    <view class="flex gap-x-30">
-      <view class="flex-1 rounded-12 bg-[#F0FFF2] py-40 pl-22 pr-8 flex items-center" @click="handleOpenPlan">
+    <view class="grid grid-cols-2 gap-x-30">
+      <view class="rounded-12 bg-[#F0FFF2] py-40 pl-22 pr-8 flex items-center" @click="handleOpenPlan">
         <!-- /pagesStudy/pages/study-plan-edit/study-plan-edit -->
         <view class="flex-1">
           <view class="text-30 text-fore-title font-bold flex items-center">
@@ -13,7 +13,7 @@
         </view>
         <ie-image :is-oss="true" src="/study-bg3.png" customClass="w-92 h-92" />
       </view>
-      <view class="flex-1 rounded-12 bg-[#FFF6F0] py-40 pl-22 pr-8 flex items-center" @click="handleTest">
+      <view v-if="showCoursePractice" class="rounded-12 bg-[#FFF6F0] py-40 pl-22 pr-8 flex items-center" @click="handleTest">
         <view class="flex-1">
           <view class="text-30 text-fore-title font-bold flex items-center">
             <text class="mr-2">教材同步练习</text>
@@ -31,10 +31,16 @@ import { useTransferPage } from '@/hooks/useTransferPage';
 import { getStudyPlan, getDirectedSchool } from '@/api/modules/study';
 import { OPEN_VIP_POPUP } from '@/types/injectionSymbols';
 import { useUserStore } from '@/store/userStore';
+import { EnumExamType } from '@/common/enum';
 
 const { transferTo } = useTransferPage();
 const userStore = useUserStore();
 const openVipPopup = inject(OPEN_VIP_POPUP);
+
+const showCoursePractice = computed(() => {
+  return userStore.getExamType !== EnumExamType.VHS;
+});
+
 const handleOpenPlan = async () => {
   const { data } = await getStudyPlan();
   if (data) {

+ 3 - 8
src/pagesStudy/pages/index/compoentns/index-menu.vue

@@ -11,6 +11,7 @@
 <script lang="ts" setup>
 import { useUserStore } from '@/store/userStore';
 import { useTransferPage } from '@/hooks/useTransferPage';
+import { EnumExamType } from '@/common/enum';
 
 const { transferTo, routes } = useTransferPage();
 const userStore = useUserStore();
@@ -30,7 +31,7 @@ const menus = computed(() => [
     label: '组卷作业',
     icon: '/menu/menu-exam.png',
     pageUrl: routes.pageHomework,
-    visible: userStore.isStudent
+    visible: userStore.isStudent && (userStore.getExamType !== EnumExamType.VHS)
   },
   {
     label: '收藏夹',
@@ -52,13 +53,7 @@ const menus = computed(() => [
   }
 ])
 const navigateTo = (menu: MenuItem) => {
-  if (menu.label === '错题本') {
-    transferTo(routes.pageWrongBook, {
-      data: {}
-    });
-  } else {
-    transferTo(menu.pageUrl);
-  }
+  transferTo(menu.pageUrl);
 }
 </script>
 <style lang="scss" scoped>

+ 146 - 0
src/pagesStudy/pages/index/compoentns/index-practice-entry.vue

@@ -0,0 +1,146 @@
+<template>
+  <view>
+    <view v-if="!isVHS" class="mx-30 mt-20 flex items-center bg-[#E3F4FA] rounded-8 py-16 px-16 gap-x-40">
+      <view class="text-24 text-[#34B0D7] flex-1">
+        <text v-if="!hasDirectedSchool">你还未开启定向学习,快来设置吧!</text>
+        <view v-else class="flex items-center">
+          <text class="flex-shrink-0">定向:</text>
+          <text class="min-w-1 ellipsis-1">{{ firstDirectedSchool.universityName }}</text>
+          <uv-icon name="arrow-right" size="14" color="#0DACF5"></uv-icon>
+          <text class="flex-shrink-0">{{ firstDirectedSchool.majorName }}</text>
+        </view>
+      </view>
+      <view class="text-24 text-white bg-gradient-to-r from-[#26C5F7] to-[#0DACF5] rounded-full px-18 py-6"
+        @click="handleSetting">{{ hasDirectedSchool ? '已开启' : '去开启' }}</view>
+    </view>
+    <view class="mx-30 mt-20">
+      <view class="grid grid-cols-2 items-center gap-x-28">
+        <template v-if="isVHS">
+          <view class="bg-gradient-to-r from-[#0088FE] to-[#31A0FC] flex-1 rounded-15 relative overflow-hidden">
+            <view class="mt-30 p-30 z-1 relative">
+              <view class="text-30 text-white font-bold">知识点练习</view>
+              <view class="mt-8 text-24 text-white">考点专攻,精准提分</view>
+              <view class="mt-32 w-200 h-56 flex items-center justify-center rounded-full text-26 text-primary bg-white"
+                @click="handlePracticeKnowledge">
+                开始练习
+              </view>
+            </view>
+            <ie-image :is-oss="true" src="/study-bg13.png" custom-class="absolute bottom-0 left-0 w-full h-full z-0"
+              mode="aspectFill" />
+          </view>
+          <!-- <view class="bg-gradient-to-r from-[#32B5FD] to-[#79DCFD] flex-1 rounded-15 relative overflow-hidden">
+            <view class="mt-30 p-30 z-1 relative">
+              <view class="text-30 text-white font-bold">必刷题</view>
+              <view class="mt-8 text-24 text-white">高频考题,一网打尽</view>
+              <view class="mt-32 w-200 h-56 flex items-center justify-center rounded-full text-26 text-primary bg-white"
+                @click="handlePracticeMustDo">
+                开始练习
+              </view>
+            </view>
+            <ie-image :is-oss="true" src="/study-bg13.png" custom-class="absolute bottom-0 left-0 w-full h-full z-0"
+              mode="aspectFill" />
+          </view> -->
+        </template>
+        <template v-else>
+          <view class="bg-gradient-to-r from-[#0088FE] to-[#31A0FC] flex-1 rounded-15 relative overflow-hidden">
+            <view class="mt-30 p-30 z-1 relative">
+              <view class="text-30 text-white font-bold">全量刷题</view>
+              <view class="mt-8 text-24 text-white">全面刷题,高效备考</view>
+              <view class="mt-32 w-200 h-56 flex items-center justify-center rounded-full text-26 text-primary bg-white"
+                @click="handlePracticeAll">
+                开始练习
+              </view>
+            </view>
+            <ie-image :is-oss="true" src="/study-bg13.png" custom-class="absolute bottom-0 left-0 w-full h-full z-0"
+              mode="aspectFill" />
+          </view>
+          <view class="bg-gradient-to-r from-[#32B5FD] to-[#79DCFD] flex-1 rounded-15 relative overflow-hidden">
+            <view class="mt-30 p-30 z-1 relative">
+              <view class="text-30 text-white font-bold">定向刷题</view>
+              <view class="mt-8 text-24 text-white">紧扣考纲,精准练习</view>
+              <view class="mt-32 w-200 h-56 flex items-center justify-center rounded-full text-26 text-primary bg-white"
+                @click="handlePracticeDirected">
+                开始练习
+              </view>
+            </view>
+            <ie-image :is-oss="true" src="/study-bg13.png" custom-class="absolute bottom-0 left-0 w-full h-full z-0"
+              mode="aspectFill" />
+          </view>
+        </template>
+      </view>
+    </view>
+  </view>
+</template>
+<script lang="ts" setup>
+import { useTransferPage } from '@/hooks/useTransferPage';
+import { useUserStore } from '@/store/userStore';
+const { transferTo } = useTransferPage();
+const userStore = useUserStore();
+
+const { hasDirectedSchool, directedSchoolList, getExamType, isVHS } = storeToRefs(userStore);
+const firstDirectedSchool = computed(() => directedSchoolList.value[0] || {});
+
+const handlePracticeDirected = async () => {
+  if (!hasDirectedSchool.value) {
+    addTarget();
+    return;
+  }
+  const notice = firstDirectedSchool.value.notice;
+  if (notice) {
+    await uni.$ie.showModal({
+      title: '提示',
+      content: notice,
+      showCancel: false,
+      confirmText: '知道了'
+    });
+  } else {
+    transferTo('/pagesStudy/pages/knowledge-practice/knowledge-practice', {
+      data: {
+        isVHS: false,
+        directed: true
+      }
+    });
+  }
+}
+
+const handlePracticeAll = () => {
+  transferTo('/pagesStudy/pages/knowledge-practice/knowledge-practice', {
+    data: {
+      isVHS: false,
+      directed: false
+    }
+  });
+}
+
+const handlePracticeKnowledge = () => {
+  transferTo('/pagesStudy/pages/knowledge-practice/knowledge-practice', {
+    data: {
+      isVHS: true,
+      directed: false,
+      questionType: 0
+    }
+  });
+}
+
+const handlePracticeMustDo = () => {
+  transferTo('/pagesStudy/pages/knowledge-practice/knowledge-practice', {
+    data: {
+      isVHS: true,
+      directed: false,
+      questionType: 2
+    }
+  });
+}
+
+const handleSetting = async () => {
+  if (hasDirectedSchool.value) {
+    transferTo('/pagesStudy/pages/targeted-setting/targeted-setting');
+  } else {
+    addTarget();
+  }
+}
+const addTarget = () => {
+  transferTo('/pagesStudy/pages/targeted-add/targeted-add');
+}
+</script>
+<style lang="scss" scoped></style>

+ 69 - 0
src/pagesStudy/pages/index/compoentns/vhs-exam.vue

@@ -0,0 +1,69 @@
+<template>
+  <view>
+    <view class="h-16 bg-back my-32"></view>
+    <view class="px-30 pt-13 pb-24 text-32 text-fore-title font-bold">真题&模拟</view>
+    <view class="">
+      <view class="overflow-hidden bg-white sticky z-2" :style="{ top: baseStickyTop + 'px' }">
+        <view class="px-30 pt-24 pb-30 text-32 text-fore-title font-bold flex items-center gap-44 bg-back rounded-t-15">
+          <view :class="['relative text-fore-light', { 'is-active': current === 0 }]" @click="handleChange(0)">公共课
+          </view>
+          <view :class="['relative text-fore-light', { 'is-active': current === 1 }]" @click="handleChange(1)">专业课
+          </view>
+        </view>
+      </view>
+
+      <view v-if="list.length > 0" class="px-30 pb-24 bg-back flex flex-col gap-20 sticky z-1 "
+        :style="{ top: baseStickyTop + 20 + 'px' }">
+        <vhs-exam-item v-for="(item, index) in list" :key="index" :data="item" :type="current" />
+      </view>
+      <view v-else class="bg-white">
+        <z-paging-empty-view :empty-view-fixed="false" />
+      </view>
+    </view>
+  </view>
+</template>
+<script lang="ts" setup>
+import VhsExamItem from '@/pagesStudy/components/vhs-exam-item.vue';
+import { useTransferPage } from '@/hooks/useTransferPage';
+import { useNavbar } from '@/hooks/useNavbar';
+import { getVHSPaperList } from '@/api/modules/study';
+import { Study, Transfer } from '@/types';
+
+const { transferTo } = useTransferPage();
+const { baseStickyTop } = useNavbar();
+const list = ref<Study.VHSPaper[]>([]);
+const current = ref(0);
+const handleChange = (index: number) => {
+  current.value = index;
+  loadData();
+}
+const loadData = async () => {
+  list.value = [];
+  const { data } = await getVHSPaperList({
+    subjectId: current.value
+  });
+  list.value = data;
+}
+onShow(() => {
+  loadData();
+});
+</script>
+<style lang="scss" scoped>
+.is-active {
+  @apply text-fore-title;
+
+  &::after {
+    content: '';
+    display: block;
+    width: 20px;
+    height: 4px;
+    background: radial-gradient(0% 0% at 0% 0%, #31A0FC 0%, #70C8FD 100%);
+    position: absolute;
+    bottom: 0;
+    border-radius: 4rpx;
+    left: 50%;
+    transform: translateX(-50%);
+    bottom: -8rpx;
+  }
+}
+</style>

+ 19 - 101
src/pagesStudy/pages/index/index.vue

@@ -1,75 +1,31 @@
 <template>
   <ie-page ref="iePageRef" bg-color="#FFFFFF" safe-area-inset-bottom-color="#f2f3f7">
-    <view>
-      <ie-navbar>
-        <template #headerLeft>
-          <view class="flex items-center">
-            <uv-icon name="arrow-left" size="20px" color="#333" bold></uv-icon>
-            <ie-image :is-oss="true" src="/study-title.png" custom-class="ml-8 w-148 h-36" mode="heightFix" />
-            <view class="w-6 h-6 rounded-2 bg-black mx-12"></view>
-            <view>
-              <ie-dict :dict-name="EnumDictName.EXAM_TYPE" :dict-value="userStore.getExamType || '--'" />
-            </view>
-          </view>
-        </template>
-      </ie-navbar>
-      <view class="mx-30 mt-20 flex items-center bg-[#E3F4FA] rounded-8 py-16 px-16 gap-x-40">
-        <view class="text-24 text-[#34B0D7] flex-1">
-          <text v-if="!hasDirectedSchool">你还未开启定向学习,快来设置吧!</text>
-          <view v-else class="flex items-center">
-            <text class="flex-shrink-0">定向:</text>
-            <text class="min-w-1 ellipsis-1">{{ firstDirectedSchool.universityName }}</text>
-            <uv-icon name="arrow-right" size="14" color="#0DACF5"></uv-icon>
-            <text class="flex-shrink-0">{{ firstDirectedSchool.majorName }}</text>
-          </view>
-        </view>
-        <view class="text-24 text-white bg-gradient-to-r from-[#26C5F7] to-[#0DACF5] rounded-full px-18 py-6"
-          @click="handleSetting">{{ hasDirectedSchool ? '已开启' : '去开启' }}</view>
-      </view>
-      <view class="mx-30 mt-20">
-        <view class="flex items-center gap-x-28">
-          <view class="bg-gradient-to-r from-[#0088FE] to-[#31A0FC] flex-1 rounded-15 relative overflow-hidden">
-            <view class="mt-30 p-30 z-1 relative">
-              <view class="text-30 text-white font-bold">全量刷题</view>
-              <view class="mt-8 text-24 text-white">全面刷题,高效备考</view>
-              <view class="mt-32 w-200 h-56 flex items-center justify-center rounded-full text-26 text-primary bg-white"
-                @click="handlePracticeAll">
-                开始练习
-              </view>
-            </view>
-            <ie-image :is-oss="true" src="/study-bg13.png" custom-class="absolute bottom-0 left-0 w-full h-full z-0"
-              mode="aspectFill" />
-          </view>
-          <view class="bg-gradient-to-r from-[#32B5FD] to-[#79DCFD] flex-1 rounded-15 relative overflow-hidden">
-            <view class="mt-30 p-30 z-1 relative">
-              <view class="text-30 text-white font-bold">定向刷题</view>
-              <view class="mt-8 text-24 text-white">紧扣考纲,精准练习</view>
-              <view class="mt-32 w-200 h-56 flex items-center justify-center rounded-full text-26 text-primary bg-white"
-                @click="handlePracticeDirected">
-                开始练习
-              </view>
-            </view>
-            <ie-image :is-oss="true" src="/study-bg13.png" custom-class="absolute bottom-0 left-0 w-full h-full z-0"
-              mode="aspectFill" />
+    <ie-navbar>
+      <template #headerLeft>
+        <view class="flex items-center">
+          <uv-icon name="arrow-left" size="20px" color="#333"></uv-icon>
+          <ie-image :is-oss="true" src="/study-title.png" custom-class="ml-8 w-148 h-36" mode="heightFix" />
+          <view class="w-6 h-6 rounded-2 bg-black mx-12"></view>
+          <view>
+            <ie-dict :dict-name="EnumDictName.EXAM_TYPE" :dict-value="userStore.getExamType || '--'" />
           </view>
         </view>
-      </view>
-      <index-menu />
-      <index-banner />
-      <block v-if="hasTestAndRecord">
-        <view class="h-16 bg-back my-32"></view>
-        <index-test :directed-school="firstDirectedSchool" />
-        <index-exam-record />
-      </block>
-    </view>
+      </template>
+    </ie-navbar>
+    <index-practice-entry />
+    <index-menu />
+    <index-banner />
+    <vhs-exam v-if="isVHS" :directed-school="firstDirectedSchool" />
+    <ie-exam v-else :directed-school="firstDirectedSchool" />
   </ie-page>
 </template>
 
 <script lang="ts" setup>
 import IndexMenu from './compoentns/index-menu.vue';
 import IndexBanner from './compoentns/index-banner.vue';
-import IndexTest from './compoentns/index-test.vue';
-import IndexExamRecord from './compoentns/index-exam-record.vue';
+import IeExam from './compoentns/ie-exam.vue';
+import VhsExam from './compoentns/vhs-exam.vue';
+import IndexPracticeEntry from './compoentns/index-practice-entry.vue';
 import { EnumDictName, EnumExamType, EnumUserRole } from '@/common/enum';
 import { useUserStore } from '@/store/userStore';
 import { useTransferPage } from '@/hooks/useTransferPage';
@@ -82,47 +38,9 @@ const { hasPermission } = useAuth();
 
 // 通过 ref 获取 ie-page 组件实例
 const iePageRef = ref<InstanceType<typeof IePage>>();
-const { hasDirectedSchool, directedSchoolList, hasTestAndRecord } = toRefs(userStore);
+const { hasDirectedSchool, directedSchoolList, getExamType, isVHS } = storeToRefs(userStore);
 const firstDirectedSchool = computed(() => directedSchoolList.value[0] || {});
 
-const handlePracticeAll = () => {
-  transferTo('/pagesStudy/pages/knowledge-practice/knowledge-practice', {
-    data: {
-      directed: false
-    }
-  });
-}
-const handlePracticeDirected = async () => {
-  if (!hasDirectedSchool.value) {
-    addTarget();
-    return;
-  }
-  const notice = firstDirectedSchool.value.notice;
-  if (notice) {
-    await uni.$ie.showModal({
-      title: '提示',
-      content: notice,
-      showCancel: false,
-      confirmText: '知道了'
-    });
-  } else {
-    transferTo('/pagesStudy/pages/knowledge-practice/knowledge-practice', {
-      data: {
-        directed: true
-      }
-    });
-  }
-}
-const handleSetting = async () => {
-  if (hasDirectedSchool.value) {
-    transferTo('/pagesStudy/pages/targeted-setting/targeted-setting');
-  } else {
-    addTarget();
-  }
-}
-const addTarget = () => {
-  transferTo('/pagesStudy/pages/targeted-add/targeted-add');
-}
 const loadData = async () => {
   await userStore.getDirectedSchoolList();
 }

+ 30 - 31
src/pagesStudy/pages/simulation-analysis/simulation-analysis.vue

@@ -10,16 +10,18 @@
           <rate-chart :value="rightRate" />
           <view class="h-1 bg-[#E6E6E6] my-20"></view>
           <view>
-            <view class="my-20 flex items-center justify-between text-24">
-              <ie-image src="/pagesStudy/static/image/icon-house.png" custom-class="w-24 h-24" mode="aspectFill" />
-              <text class="ml-10 text-fore-light flex-1">考试院校</text>
-              <text class="text-fore-title">{{ examineeData.collegeName }}-{{ examineeData.majorName }}</text>
-            </view>
-            <view class="my-20 flex items-center justify-between text-24">
-              <ie-image src="/pagesStudy/static/image/icon-group.png" custom-class="w-24 h-24" mode="aspectFill" />
-              <text class="ml-10 text-fore-light flex-1">考试科目</text>
-              <text class="text-fore-title">{{ examineeData.subjectName }}</text>
-            </view>
+            <template v-if="!userStore.isVHS">
+              <view class="my-20 flex items-center justify-between text-24">
+                <ie-image src="/pagesStudy/static/image/icon-house.png" custom-class="w-24 h-24" mode="aspectFill" />
+                <text class="ml-10 text-fore-light flex-1">考试院校</text>
+                <text class="text-fore-title">{{ examineeData.collegeName }}-{{ examineeData.majorName }}</text>
+              </view>
+              <view class="my-20 flex items-center justify-between text-24">
+                <ie-image src="/pagesStudy/static/image/icon-group.png" custom-class="w-24 h-24" mode="aspectFill" />
+                <text class="ml-10 text-fore-light flex-1">考试科目</text>
+                <text class="text-fore-title">{{ examineeData.subjectName }}</text>
+              </view>
+            </template>
             <view class="my-20 flex items-center justify-between text-24">
               <ie-image src="/pagesStudy/static/image/icon-clock.png" custom-class="w-24 h-24" mode="aspectFill" />
               <text class="ml-10 text-fore-light flex-1">考试时长</text>
@@ -40,6 +42,7 @@ import ExamStat from './components/exam-stat.vue';
 import ScoreStat from './components/score-stat.vue';
 import { getExamineeResult } from '@/api/modules/study';
 import { useTransferPage } from '@/hooks/useTransferPage';
+import { useUserStore } from '@/store/userStore';
 import { useAppStore } from '@/store/appStore';
 import { Study, Transfer } from '@/types';
 import { EnumPaperType, EnumQuestionType } from '@/common/enum';
@@ -47,19 +50,14 @@ import { EnumPaperType, EnumQuestionType } from '@/common/enum';
 const appStore = useAppStore();
 const { prevData, transferTo } = useTransferPage<Transfer.SimulationAnalysisPageOptions, Transfer.ExamAnalysisPageOptions>();
 const examineeData = ref<Study.Examinee>();
-  const titleMap = {
-  [EnumPaperType.PRACTICE]: '知识点练习',
-  [EnumPaperType.SIMULATED]: '模拟考试',
-  [EnumPaperType.TEST]: '组卷作业',
-}
-const readonlyTitleMap = {
-  [EnumPaperType.PRACTICE]: '练习解析',
-  [EnumPaperType.SIMULATED]: '考试解析',
-  [EnumPaperType.TEST]: '作业解析',
-}
+const userStore = useUserStore();
 
 const paperName = computed(() => {
-  return titleMap[prevData.value.paperType as keyof typeof titleMap] + '-' + examineeData.value?.subjectName;
+  if (userStore.isVHS) {
+    return examineeData.value?.name || examineeData.value?.subjectName || '';
+  } else {
+    return examineeData.value?.name || examineeData.value?.subjectName || '';
+  }
 });
 const rightRate = computed(() => {
   const { totalCount = 0, wrongCount = 0 } = examineeData.value || {};
@@ -83,17 +81,18 @@ const formatTime = (time: number) => {
 const handleDetail = (item: Study.Question) => {
   if (!examineeData.value) {
     return;
-  }  
-  transferTo('/pagesStudy/pages/exam-start/exam-start', {
-    data: {
+  }
+  const pageOptions: Transfer.ExamAnalysisPageOptions = {
+    readonly: true,
+    questionId: item.id,
+    paperType: prevData.value.paperType,
+    simulationInfo: {
       name: paperName.value,
-      readonly: true,
-      questionId: item.id,
-      paperType: prevData.value.paperType,
-      simulationInfo: {
-        examineeId: examineeData.value.examineeId
-      }
+      examineeId: examineeData.value.examineeId
     }
+  }
+  transferTo('/pagesStudy/pages/exam-start/exam-start', {
+    data: pageOptions,
   });
 };
 const loadData = async () => {
@@ -108,4 +107,4 @@ onLoad(() => {
 onPageScroll(() => { })
 </script>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped></style>

+ 11 - 59
src/pagesStudy/pages/study-history/components/exam-history.vue

@@ -1,66 +1,18 @@
 <template>
-  <view class="flex-1 min-h-1 bg-white">
-    <view class="px-30 py-30 flex gap-x-20">
-      <view class="exam-type-item" :class="{ 'is-active': examType === EnumExamRecordType.SIMULATED }"
-        @click="handleChangeExamType(EnumExamRecordType.SIMULATED)">
-        <ie-image src="/pagesStudy/static/image/icon-exam-test.png" custom-class="w-64 h-60" />
-        <view class="exam-type-text">模拟仿真</view>
-      </view>
-      <view class="exam-type-item" :class="{ 'is-active': examType === EnumExamRecordType.HOMEWORK }"
-        @click="handleChangeExamType(EnumExamRecordType.HOMEWORK)">
-        <ie-image src="/pagesStudy/static/image/icon-exam-homework.png" custom-class="w-64 h-60" />
-        <view class="exam-type-text">组卷作业</view>
-      </view>
-    </view>
-    <exam-history-student v-if="isStudent" :exam-type="examType" />
-    <exam-history-teacher v-else :exam-type="examType" />
+  <view class="h-full relative bg-back">
+    <ie-exam-history v-if="getLocation === '湖南'" />
+    <vhs-exam-history v-if="getLocation === '河南'" />
   </view>
 </template>
 <script lang="ts" setup>
-defineOptions({
-  options: {
-    virtualHost: true
-  }
-});
-import { EnumExamRecordType } from '@/common/enum';
-import examHistoryStudent from './exam-history-student.vue';
-import examHistoryTeacher from './exam-history-teacher.vue';
+import IeExamHistory from './ie-exam-history.vue'
+import VhsExamHistory from './vhs-exam-history.vue'
 import { useUserStore } from '@/store/userStore';
-const { isStudent } = storeToRefs(useUserStore());
-const examType = ref(EnumExamRecordType.SIMULATED);
+const userStore = useUserStore();
+const { getLocation } = storeToRefs(userStore);
 
-const handleChangeExamType = (type: EnumExamRecordType) => {
-  examType.value = type;
-}
+onShow(() => {
+  console.log(2)
+});
 </script>
-<style lang="scss" scoped>
-.exam-type-item {
-  @apply flex-1 h-175 rounded-15 bg-[#F5F5F5] flex flex-col items-center justify-center gap-y-10;
-}
-
-.exam-type-text {
-  @apply text-28 text-fore-title font-bold;
-}
-
-.is-active {
-  @apply bg-[#E6F7FF] relative;
-
-  &::after {
-    content: "";
-    display: block;
-    position: absolute;
-    bottom: -9px;
-    left: 50%;
-    transform: translateX(-50%);
-    width: 0;
-    height: 0;
-    border-left: 14px solid transparent;
-    border-right: 14px solid transparent;
-    border-top: 10px solid #E6F7FF;
-  }
-
-  .exam-type-text {
-    @apply text-primary;
-  }
-}
-</style>
+<style lang="scss" scoped></style>

+ 57 - 0
src/pagesStudy/pages/study-history/components/ie-exam-history-student.vue

@@ -0,0 +1,57 @@
+<template>
+  <view class="pb-30">
+    <view v-if="examType === EnumExamRecordType.SIMULATED" class="px-30">
+      <view class="sibling-border-top px-20 py-30" v-for="(item, index) in simulatedRecordList" :key="index">
+        <ie-exam-record-item :data="item" />
+      </view>
+    </view>
+    <template v-else>
+      <template v-if="paperWorkRecordList.length > 0">
+        <view class="sibling-border-top" v-for="(item, index) in paperWorkRecordList" :key="index">
+          <paper-work-item :data="item" />
+        </view>
+      </template>
+      <view v-else class="mt-50 mx-30 bg-[#F6F8FA] text-center py-50 text-26 text-fore-light rounded-5">暂无数据</view>
+    </template>
+  </view>
+</template>
+<script lang="ts" setup>
+import { getSimulatedRecord, getPaperWorkList } from '@/api/modules/study';
+import { EnumExamRecordType, EnumPaperWorkState } from '@/common/enum';
+import IeExamRecordItem from '@/pagesStudy/components/ie-exam-record-item.vue';
+import { Study } from '@/types';
+import PaperWorkItem from '@/pagesStudy/components/paper-work-item.vue';
+const props = defineProps({
+  examType: {
+    type: String,
+    default: 'test'
+  }
+});
+const simulatedRecordList = ref<Study.SimulatedRecord[]>([]);
+const paperWorkRecordList = ref<Study.PaperWork[]>([]);
+const loadData = async (type: string) => {
+  simulatedRecordList.value = [];
+  paperWorkRecordList.value = [];
+  if (type === EnumExamRecordType.SIMULATED) {
+    const { data } = await getSimulatedRecord();
+    simulatedRecordList.value = data;
+  } else {
+    const { rows } = await getPaperWorkList({ state: EnumPaperWorkState.COMPLETED });
+    paperWorkRecordList.value = rows;
+  }
+}
+
+watch(() => props.examType, (newVal) => {
+  loadData(newVal);
+}, {
+  immediate: false
+});
+onShow(() => {
+  console.log(44)
+});
+onMounted(() => {
+  console.log(4)
+  loadData(props.examType);
+});
+</script>
+<style lang="scss" scoped></style>

+ 18 - 0
src/pagesStudy/pages/study-history/components/ie-exam-history-teacher.vue

@@ -0,0 +1,18 @@
+<template>
+  <view class="p-30 pt-50">
+    <exam-history-simulated v-if="examType === 'simulated'" />
+    <exam-history-paperwork v-else />
+  </view>
+</template>
+<script lang="ts" setup>
+import examHistorySimulated from './exam-history-simulated.vue';
+import examHistoryPaperwork from './exam-history-paperwork.vue';
+
+const props = defineProps({
+  examType: {
+    type: String,
+    default: 'test'
+  }
+});
+</script>
+<style lang="scss" scoped></style>

+ 66 - 0
src/pagesStudy/pages/study-history/components/ie-exam-history.vue

@@ -0,0 +1,66 @@
+<template>
+  <view class="h-full bg-white flex flex-col">
+    <view class="px-30 py-20 flex gap-x-20">
+      <view class="exam-type-item" :class="{ 'is-active': examType === EnumExamRecordType.SIMULATED }"
+        @click="handleChangeExamType(EnumExamRecordType.SIMULATED)">
+        <ie-image src="/pagesStudy/static/image/icon-exam-test.png" custom-class="w-64 h-60" />
+        <view class="exam-type-text">模拟仿真</view>
+      </view>
+      <view class="exam-type-item" :class="{ 'is-active': examType === EnumExamRecordType.HOMEWORK }"
+        @click="handleChangeExamType(EnumExamRecordType.HOMEWORK)">
+        <ie-image src="/pagesStudy/static/image/icon-exam-homework.png" custom-class="w-64 h-60" />
+        <view class="exam-type-text">组卷作业</view>
+      </view>
+    </view>
+    <scroll-view class="flex-1 min-h-1" scroll-y>
+      <ie-exam-history-student v-if="isStudent" :exam-type="examType" />
+      <ie-exam-history-teacher v-else :exam-type="examType" />
+    </scroll-view>
+  </view>
+</template>
+<script lang="ts" setup>
+import { EnumExamRecordType } from '@/common/enum';
+import IeExamHistoryStudent from './ie-exam-history-student.vue';
+import IeExamHistoryTeacher from './ie-exam-history-teacher.vue';
+import { useUserStore } from '@/store/userStore';
+const { isStudent } = storeToRefs(useUserStore());
+const examType = ref(EnumExamRecordType.SIMULATED);
+
+const handleChangeExamType = (type: EnumExamRecordType) => {
+  examType.value = type;
+}
+onShow(() => {
+  console.log(3)
+});
+</script>
+<style lang="scss" scoped>
+.exam-type-item {
+  @apply flex-1 h-175 rounded-15 bg-[#F5F5F5] flex flex-col items-center justify-center gap-y-10;
+}
+
+.exam-type-text {
+  @apply text-28 text-fore-title font-bold;
+}
+
+.is-active {
+  @apply bg-[#E6F7FF] relative;
+
+  &::after {
+    content: "";
+    display: block;
+    position: absolute;
+    bottom: -9px;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 0;
+    height: 0;
+    border-left: 14px solid transparent;
+    border-right: 14px solid transparent;
+    border-top: 10px solid #E6F7FF;
+  }
+
+  .exam-type-text {
+    @apply text-primary;
+  }
+}
+</style>

+ 3 - 1
src/pagesStudy/pages/study-history/components/knowledge-history-student.vue

@@ -1,5 +1,7 @@
 <template>
-  <knowledge-table :data="dataList" />
+  <view class="h-full">
+    <knowledge-table :data="dataList" />
+  </view>
 </template>
 <script lang="ts" setup>
 import { getKnowledgeRecord } from '@/api/modules/study';

+ 1 - 1
src/pagesStudy/pages/study-history/components/knowledge-history.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="bg-white">
+  <view class="bg-white h-full">
     <knowledge-history-student v-if="isStudent" />
     <teacher-class-view v-else>
       <template #default="{ teachClass }">

+ 1 - 1
src/pagesStudy/pages/study-history/components/practice-history.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="flex-1 min-h-1 bg-white">
+  <view class="h-full bg-white">
     <practice-history-student v-if="isStudent" />
     <teacher-class-view v-else>
       <template #default="{ teachClass }">

+ 32 - 0
src/pagesStudy/pages/study-history/components/vhs-exam-history-student.vue

@@ -0,0 +1,32 @@
+<template>
+  <view class="flex flex-col gap-20 px-30 pb-20 bg-back h-fit">
+    <template v-if="simulatedRecordList.length > 0">
+      <view class="" v-for="(item, index) in simulatedRecordList" :key="index">
+        <vhs-exam-record-item :data="item" />
+      </view>
+    </template>
+    <view v-else class="mt-200">
+      <z-paging-empty-view :empty-view-fixed="false" />
+    </view>
+  </view>
+</template>
+<script lang="ts" setup>
+import { getSimulatedRecord } from '@/api/modules/study';
+import VhsExamRecordItem from '@/pagesStudy/components/vhs-exam-record-item.vue';
+import { Study } from '@/types';
+
+const simulatedRecordList = ref<Study.SimulatedRecord[]>([]);
+const paperWorkRecordList = ref<Study.PaperWork[]>([]);
+const loadData = async () => {
+  simulatedRecordList.value = [];
+  paperWorkRecordList.value = [];
+  const { data } = await getSimulatedRecord();
+  simulatedRecordList.value = data;
+  console.log(data, 123)
+}
+
+onShow(() => {
+  loadData();
+});
+</script>
+<style lang="scss" scoped></style>

+ 93 - 0
src/pagesStudy/pages/study-history/components/vhs-exam-history-teacher.vue

@@ -0,0 +1,93 @@
+<template>
+  <view class="h-full bg-white">
+    <teacher-class-view>
+      <template #default="{ teachClass }">
+        <view class="">
+          <ie-table :tableColumns="tableColumns" :data="tableData" :cellStyle="cellStyle" :headerFixed="true">
+            <template #name="{ item }">
+              <text class="font-bold">{{ item.name }}</text>
+            </template>
+            <template #total="{ item }">
+              <text class="font-bold">{{ item.value }}/{{ item.total }}</text>
+            </template>
+            <template #action="{ item }">
+              <text class="text-30 text-primary font-bold" @click="handleRowClick(item)">查看</text>
+            </template>
+          </ie-table>
+        </view>
+      </template>
+    </teacher-class-view>
+  </view>
+</template>
+<script lang="ts" setup>
+import teacherClassView from '@/pagesStudy/components/teacher-class-view.vue';
+import examHistorySimulated from './exam-history-simulated.vue';
+import examHistoryPaperwork from './exam-history-paperwork.vue';
+import { Study } from '@/types';
+import { TableColumnConfig } from '@/types';
+import { CSSProperties } from 'vue';
+import { useTransferPage } from '@/hooks/useTransferPage';
+import { getClassExamRecord } from '@/api/modules/study';
+const { transferTo } = useTransferPage();
+
+const props = defineProps({
+  examType: {
+    type: String,
+    default: 'test'
+  }
+});
+const cellStyle: CSSProperties = {
+  padding: '30rpx 20rpx'
+}
+const mockData = {
+  name: '1班',
+  total: 100,
+  value: 100,
+  rate: 100,
+}
+const tableData = ref<Study.StudentExamRecord[]>(new Array(20).fill(mockData));
+const tableColumns: TableColumnConfig[] = [
+  {
+    prop: 'name',
+    label: '班级',
+    flex: 1,
+    slot: 'name',
+    headerAlign: 'center',
+    align: 'center'
+  },
+  {
+    prop: 'total',
+    label: '做卷情况',
+    flex: 1,
+    slot: 'total'
+  },
+  {
+    prop: 'action',
+    label: '操作',
+    flex: 1,
+    slot: 'action'
+  }
+];
+
+const handleRowClick = (row: Study.StudentExamRecord) => {
+  transferTo('/pagesStudy/pages/study-exam-simulated-class/study-exam-simulated-class', {
+    data: {
+      classId: row.id,
+      name: row.name
+    }
+  });
+}
+
+const loadData = async () => {
+  uni.$ie.showLoading();
+  await getClassExamRecord({}).then(res => {
+    tableData.value = res.data;
+  });
+  uni.$ie.hideLoading();
+}
+
+onMounted(() => {
+  // loadData();
+})
+</script>
+<style lang="scss" scoped></style>

+ 44 - 0
src/pagesStudy/pages/study-history/components/vhs-exam-history.vue

@@ -0,0 +1,44 @@
+<template>
+  <view class="h-full">
+    <vhs-exam-history-student v-if="isStudent" />
+    <vhs-exam-history-teacher v-else />
+  </view>
+</template>
+<script lang="ts" setup>
+import VhsExamHistoryStudent from './vhs-exam-history-student.vue';
+import VhsExamHistoryTeacher from './vhs-exam-history-teacher.vue';
+import { useUserStore } from '@/store/userStore';
+
+const { isStudent } = storeToRefs(useUserStore());
+</script>
+<style lang="scss" scoped>
+.exam-type-item {
+  @apply flex-1 h-175 rounded-15 bg-[#F5F5F5] flex flex-col items-center justify-center gap-y-10;
+}
+
+.exam-type-text {
+  @apply text-28 text-fore-title font-bold;
+}
+
+.is-active {
+  @apply bg-[#E6F7FF] relative;
+
+  &::after {
+    content: "";
+    display: block;
+    position: absolute;
+    bottom: -9px;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 0;
+    height: 0;
+    border-left: 14px solid transparent;
+    border-right: 14px solid transparent;
+    border-top: 10px solid #E6F7FF;
+  }
+
+  .exam-type-text {
+    @apply text-primary;
+  }
+}
+</style>

+ 8 - 5
src/pagesStudy/pages/study-history/study-history.vue

@@ -1,15 +1,17 @@
 <template>
   <ie-page bg-color="#FFFFFF" :fix-height="true">
     <ie-navbar title="学习记录" />
-    <view class="bg-white sticky z-1" :style="{ top: baseStickyTop + 'px' }">
+    <view class="bg-white" :style="{ top: baseStickyTop + 'px' }">
       <uv-tabs :list="list" :current="current" :activeStyle="activeStyle" :inactiveStyle="inactiveStyle"
         :scrollable="false" @change="handleTabChange"></uv-tabs>
     </view>
     <view class="h-20 bg-[#F6F8FA]"></view>
-    <knowledge-history v-if="current === 0" />
-    <exam-history v-if="current === 1" />
-    <practice-history v-if="current === 2" />
-    <video-history v-if="current === 3" />
+    <scroll-view class="flex-1 min-h-1 box-border" scroll-y>
+      <knowledge-history v-if="current === 0" />
+      <exam-history v-if="current === 1" />
+      <practice-history v-if="current === 2" />
+      <video-history v-if="current === 3" />
+    </scroll-view>
   </ie-page>
 </template>
 
@@ -37,6 +39,7 @@ const inactiveStyle = {
 const handleTabChange = (e: any) => {
   current.value = e.index;
 }
+onShow(() => { });
 </script>
 
 <style lang="scss" scoped></style>

+ 8 - 8
src/pagesSystem/pages/bind-profile/bind-profile.vue

@@ -5,7 +5,7 @@
       <content-card title="个人信息">
         <uv-form-item label="姓名" prop="name" borderBottom required>
           <uv-input v-model="form.nickName" border="none" placeholder="请输入姓名" placeholderClass="text-[15px]"
-            font-size="30rpx" :custom-style="customStyle">
+            font-size="15px" :custom-style="customStyle">
           </uv-input>
         </uv-form-item>
         <uv-form-item label="所在省份" prop="location" borderBottom required>
@@ -31,7 +31,7 @@
             :disabled="!examTypeForm.examType" :placeholder="pickerPlaceholder" :custom-style="customStyle"
             key-label="dictLabel" key-value="dictValue"></ie-picker>
         </uv-form-item>
-        <uv-form-item label="单招年份" prop="year" required>
+        <uv-form-item label="毕业年份" prop="year" required>
           <ie-picker ref="pickerRef" v-model="examTypeForm.endYear" :list="endYearList"
             :disabled="!examTypeForm.examType" :placeholder="pickerPlaceholder" :custom-style="customStyle"
             key-label="dictLabel" key-value="dictValue" @click="handlePreCheck('endYear')"></ie-picker>
@@ -40,7 +40,7 @@
       </content-card>
       <content-card title="邀请信息">
         <uv-form-item label="邀请码" prop="form.inviteCode">
-          <uv-input v-model="form.inviteCode" border="none" placeholder="请输入邀请码(非必填)" font-size="30rpx"
+          <uv-input v-model="form.inviteCode" border="none" placeholder="请输入邀请码(非必填)" font-size="15px"
             :custom-style="customStyle">
           </uv-input>
         </uv-form-item>
@@ -49,27 +49,27 @@
       <content-card v-if="showCulture" title="文化素质">
         <uv-form-item label="语文" prop="form.scores.chinese" borderBottom :required="isScoreRequired">
           <uv-input v-model.number="scoresForm.chinese" border="none" type="number" :placeholder="inputPlaceholder"
-            font-size="30rpx" :custom-style="customStyle">
+            font-size="15px" :custom-style="customStyle">
           </uv-input>
         </uv-form-item>
         <uv-form-item label="数学" prop="form.score.mathematics" borderBottom :required="isScoreRequired">
           <uv-input v-model.number="scoresForm.mathematics" border="none" type="number" :placeholder="inputPlaceholder"
-            font-size="30rpx" :custom-style="customStyle">
+            font-size="15px" :custom-style="customStyle">
           </uv-input>
         </uv-form-item>
         <uv-form-item label="外语" prop="form.scores.foreign" borderBottom :required="isScoreRequired">
           <uv-input v-model.number="scoresForm.foreign" border="none" type="number" :placeholder="inputPlaceholder"
-            font-size="30rpx" :custom-style="customStyle">
+            font-size="15px" :custom-style="customStyle">
           </uv-input>
         </uv-form-item>
         <uv-form-item label="物理" prop="form.scores.physics" borderBottom :required="isScoreRequired">
           <uv-input v-model.number="scoresForm.physics" border="none" type="number" :placeholder="inputPlaceholder"
-            font-size="30rpx" :custom-style="customStyle">
+            font-size="15px" :custom-style="customStyle">
           </uv-input>
         </uv-form-item>
         <uv-form-item label="政治" prop="form.scores.political" :required="isScoreRequired">
           <uv-input v-model.number="scoresForm.political" border="none" type="number" :placeholder="inputPlaceholder"
-            font-size="30rpx" :custom-style="customStyle">
+            font-size="15px" :custom-style="customStyle">
           </uv-input>
         </uv-form-item>
       </content-card>

+ 9 - 9
src/pagesSystem/pages/bind-teacher-profile/bind-teacher-profile.vue

@@ -5,7 +5,7 @@
       <content-card title="个人信息">
         <uv-form-item label="姓名" prop="name" borderBottom required>
           <uv-input v-model="form.nickName" border="none" placeholder="请输入姓名" placeholderClass="text-30"
-            font-size="30rpx" :custom-style="customStyle">
+            font-size="15px" :custom-style="customStyle">
           </uv-input>
         </uv-form-item>
         <uv-form-item label="所在省份" prop="location" borderBottom required>
@@ -33,7 +33,7 @@
               <ie-image src="/static/image/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
             </template></ie-picker>
         </uv-form-item>
-        <uv-form-item label="单招年份" prop="year" required>
+        <uv-form-item label="毕业年份" prop="year" required>
           <ie-picker ref="pickerRef" v-model="examTypeForm.endYear" :list="endYearList"
             :disabled="!examTypeForm.examType || disabledEdit" :placeholder="pickerPlaceholder"
             :custom-style="customStyle" key-label="dictLabel" key-value="dictValue">
@@ -46,33 +46,33 @@
       <content-card v-if="showCulture" title="文化素质">
         <uv-form-item label="语文" prop="form.scores.chinese" borderBottom :required="isScoreRequired">
           <uv-input v-model.number="scoresForm.chinese" border="none" type="number" :placeholder="inputPlaceholder"
-            font-size="30rpx" :custom-style="customStyle" :readonly="disabledEdit">
+            font-size="15px" :custom-style="customStyle" :readonly="disabledEdit">
           </uv-input>
         </uv-form-item>
         <uv-form-item label="数学" prop="form.score.mathematics" borderBottom :required="isScoreRequired">
           <uv-input v-model.number="scoresForm.mathematics" border="none" type="number" :placeholder="inputPlaceholder"
-            font-size="30rpx" :custom-style="customStyle" :readonly="disabledEdit">
+            font-size="15px" :custom-style="customStyle" :readonly="disabledEdit">
           </uv-input>
           <ie-image v-if="disabledEdit" slot="right" src="/static/image/icon-lock.png" custom-class="w-24 h-30"
             mode="aspectFill" />
         </uv-form-item>
         <uv-form-item label="外语" prop="form.scores.foreign" borderBottom :required="isScoreRequired">
           <uv-input v-model.number="scoresForm.foreign" border="none" type="number" :placeholder="inputPlaceholder"
-            font-size="30rpx" :custom-style="customStyle" :readonly="disabledEdit">
+            font-size="15px" :custom-style="customStyle" :readonly="disabledEdit">
           </uv-input>
           <ie-image v-if="disabledEdit" slot="right" src="/static/image/icon-lock.png" custom-class="w-24 h-30"
             mode="aspectFill" />
         </uv-form-item>
         <uv-form-item label="物理" prop="form.scores.physics" borderBottom :required="isScoreRequired">
           <uv-input v-model.number="scoresForm.physics" border="none" type="number" :placeholder="inputPlaceholder"
-            font-size="30rpx" :custom-style="customStyle" :readonly="disabledEdit">
+            font-size="15px" :custom-style="customStyle" :readonly="disabledEdit">
           </uv-input>
           <ie-image v-if="disabledEdit" slot="right" src="/static/image/icon-lock.png" custom-class="w-24 h-30"
             mode="aspectFill" />
         </uv-form-item>
         <uv-form-item label="政治" prop="form.scores.political" :required="isScoreRequired">
           <uv-input v-model.number="scoresForm.political" border="none" type="number" :placeholder="inputPlaceholder"
-            font-size="30rpx" :custom-style="customStyle" :readonly="disabledEdit">
+            font-size="15px" :custom-style="customStyle" :readonly="disabledEdit">
           </uv-input>
           <ie-image v-if="disabledEdit" slot="right" src="/static/image/icon-lock.png" custom-class="w-24 h-30"
             mode="aspectFill" />
@@ -81,14 +81,14 @@
 
       <content-card v-if="showSchoolInfo" title="学校信息">
         <uv-form-item label="学校名称" prop="form.campusName" borderBottom>
-          <uv-input v-model="form.campusName" border="none" placeholder="" placeholderClass="text-30" font-size="30rpx"
+          <uv-input v-model="form.campusName" border="none" placeholder="" placeholderClass="text-30" font-size="15px"
             :custom-style="customStyle" readonly>
           </uv-input>
           <ie-image slot="right" src="/static/image/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
         </uv-form-item>
         <uv-form-item label="所在班级" prop="form.campusClassName">
           <uv-input v-model="form.campusClassName" border="none" placeholder="" placeholderClass="text-30"
-            font-size="30rpx" :custom-style="customStyle" readonly>
+            font-size="15px" :custom-style="customStyle" readonly>
           </uv-input>
           <ie-image slot="right" src="/static/image/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
         </uv-form-item>

+ 1 - 1
src/pagesSystem/pages/edit-profile/edit-profile.vue

@@ -33,7 +33,7 @@
             </view>
             <ie-image slot="right" src="/static/image/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
           </uv-form-item>
-          <uv-form-item label="单招年份" prop="name">
+          <uv-form-item label="毕业年份" prop="name">
             <uv-input v-model="form.endYear" border="none" placeholder="" placeholderClass="text-[15px]" font-size="15px"
               :custom-style="customStyle" readonly>
             </uv-input>

+ 3 - 0
src/store/userStore.ts

@@ -128,6 +128,9 @@ export const useUserStore = defineStore('ie-user', {
     },
     isHN(): boolean {
       return this.getLocation == '湖南'
+    },
+    isVHS(): boolean {
+      return this.getExamType === EnumExamType.VHS;
     }
   },
   actions: {

+ 43 - 3
src/types/study.ts

@@ -185,6 +185,7 @@ export interface ExamineeQuestion {
   subQuestions: ExamineeQuestion[];
   parse?: string;
   totalScore: number;
+  // 原始题型名称
   typeTitle?: string;
 }
 export interface Examinee {
@@ -297,11 +298,14 @@ export interface Question extends QuestionState {
   duration: number;
   // 是否有子题
   hasSubQuestions: boolean;
+  // 原始题型名称
   typeTitle?: string;
 }
 
 export interface SubjectListRequestDTO {
-  directed: boolean;
+  directed?: boolean;
+  questionType?: number;
+  subjectType?: number;
 }
 
 export interface KnowledgeListRequestDTO {
@@ -312,9 +316,10 @@ export interface KnowledgeListRequestDTO {
 export interface OpenExamineeRequestDTO {
   paperType: string,
   relateId?: number,
-  directed: boolean,
+  directed?: boolean,
   subjectId?: number,
-  testType?: string
+  testType?: string;
+  questionType?: number;
 }
 
 export interface GetExamPaperRequestDTO {
@@ -387,6 +392,8 @@ export interface SimulatedRecord {
   // 
   subjectName: string;
   state: EnumSimulatedRecordStatus;
+  //
+  subjectGroup: string;
 }
 
 /**
@@ -433,6 +440,7 @@ export interface PracticeHistory {
   endTime: string;
   examineeId: number;
   paperName: string;
+  questionType?: number;
 }
 
 /**
@@ -459,6 +467,38 @@ export interface PaperWork {
   batchName: string;
 }
 
+export interface VHSPaperListRequestDTO {
+  subjectId: number;
+}
+
+export interface VHSPaper {
+  collect: boolean;
+  createBy: string | null;
+  createTime: string;
+  directKey: string;
+  examineeId: string | null;
+  examineeTypes: string;
+  fenshu: number;
+  filename: string;
+  id: number;
+  locations: string;
+  number: string | null;
+  ospath: string | null;
+  paperInfo: string | null;
+  paperName: string;
+  paperSource: number;
+  paperType: string;
+  relateId: number;
+  remark: string | null;
+  status: number;
+  subjectId: number;
+  subjectName: string;
+  tiid: string;
+  updateBy: string | null;
+  updateTime: string | null;
+  year: string | null;
+}
+
 
 /**
  * 收藏题目列表请求参数

+ 6 - 9
src/types/transfer.ts

@@ -10,6 +10,8 @@ export interface PracticeResultPageOptions {
   name: string;
   directed: boolean;
   paperType: EnumPaperType;
+  isVHS?: boolean; // 是否是对口升学
+  questionType?: number; // 对口升学用来区分是知识点还是必刷题
 }
 
 /**
@@ -18,12 +20,13 @@ export interface PracticeResultPageOptions {
  */
 export interface ExamAnalysisPageOptions {
   paperType: EnumPaperType;
-  name: string;
+  // name: string;
   questionId?: number;
-  readonly?: boolean;
+  readonly: boolean;
   // 模拟考试
   simulationInfo?: {
     examineeId: number;
+    name: string;
   };
   // 知识点练习、教材同步练、组卷作业
   practiceInfo?: {
@@ -31,6 +34,7 @@ export interface ExamAnalysisPageOptions {
     relateId: number;
     directed: boolean; // 知识点 id
     examineeId?: number;
+    questionType?: number; // 对口升学用来区分是知识点还是必刷题
   };
 }
 
@@ -40,11 +44,4 @@ export interface ExamAnalysisPageOptions {
 export interface SimulationAnalysisPageOptions {
   examineeId: number;
   paperType: EnumPaperType;
-}
-
-export interface UniversityPickerPageOptions {
-  title?: string;
-  fromVoluntary?: boolean;
-  selectedUniversityId?: string|number;
-  selectedMajorId?: string|number;
 }