Bläddra i källkod

添加是否完成状态

shmily1213 1 månad sedan
förälder
incheckning
019a24ecc5

+ 7 - 2
src/composables/useExam.ts

@@ -77,6 +77,9 @@ export const useExam = () => {
     }
     return state;
   });
+  const isAllDone = computed(() => {
+    return questionList.value.every(q => isDone(q));
+  });
   // 当前下标
   const currentIndex = ref<number>(0);
   const totalCount = computed(() => {
@@ -99,7 +102,7 @@ export const useExam = () => {
     if (qs.subQuestions && qs.subQuestions.length > 0) {
       return qs.subQuestions.every(q => isDone(q));
     }
-    return qs.answers && qs.answers.length > 0;
+    return qs.answers && qs.answers.length > 0 || !!qs.isNotKnow;
   }
   const nextQuestion = () => {
     if (currentIndex.value >= questionList.value.length - 1) {
@@ -211,7 +214,8 @@ export const useExam = () => {
             id: index,
             isAnswer: false
           } as Study.QuestionOption
-        })
+        }),
+        isDone: false
       } as Study.Question
     }
     const arr: Study.Question[] = list.map(item => {
@@ -241,6 +245,7 @@ export const useExam = () => {
     notKnowList,
     markList,
     currentIndex,
+    isAllDone,
     totalCount,
     doneCount,
     notDoneCount,

+ 1 - 0
src/pagesStudy/pages/index/compoentns/index-banner.vue

@@ -36,6 +36,7 @@ const navigateTo = (pageUrl: string) => {
 
 const handleOpenPlan = async () => {
   const { data } = await getStudyPlan()
+  console.log(data)
   // console.log(data, directedSchool)
   if (data) {
     transferTo('/pagesStudy/pages/study-plan/study-plan');

+ 2 - 1
src/pagesStudy/pages/index/compoentns/index-menu.vue

@@ -28,7 +28,8 @@ const menus = [
   {
     label: '收藏夹',
     icon: '/menu/menu-favorite.png',
-    pageUrl: '/pagesOther/pages/personal-center/my-concerned/my-concerned'
+    // pageUrl: '/pagesOther/pages/personal-center/my-concerned/my-concerned'
+    pageUrl: '/pagesOther/pages/topic-center/topic-collection/topic-collection'
   },
   {
     label: '错题本',

+ 8 - 4
src/pagesStudy/pages/index/compoentns/index-test.vue

@@ -25,7 +25,8 @@
           </view>
         </view>
         <view class="py-60 px-46">
-          <view class="h-104 rounded-8 border border-solid border-border px-30 flex items-center justify-between" @click="handleSelectCollege">
+          <view class="h-104 rounded-8 border border-solid border-border px-30 flex items-center justify-between"
+            @click="handleSelectCollege">
             <view class="flex-1 text-30 text-fore-subtitle">{{ selectedCollege.universityName || '选择考试院校' }}</view>
             <view class="flex items-center">
               <text class="mr-8 text-30 text-[#B3B3B3]">请选择</text>
@@ -44,7 +45,7 @@
 </template>
 <script lang="ts" setup>
 import { useTransferPage } from '@/hooks/useTransferPage';
-import { SimulationTestInfo, SimulationTestOptions } from '@/types/study';
+import { SelectedUniversityMajor, SimulationTestInfo, SimulationTestOptions } from '@/types/study';
 import { getSimulationInfo } from '@/api/modules/study';
 const { transferTo } = useTransferPage();
 const tab = ref('0');
@@ -59,12 +60,15 @@ const handleSelectCollege = () => {
     data: {}
   }).then(res => {
     if (res) {
-      console.log(res)
+      const selectedUniversityMajor = res as SelectedUniversityMajor;
+      selectedCollege.value = selectedUniversityMajor;
     }
   });
 }
 const handleStartTest = () => {
-  transferTo('/pagesStudy/pages/simulation-entry/simulation-entry');
+  transferTo('/pagesStudy/pages/simulation-entry/simulation-entry', {
+    data: selectedCollege.value
+  });
 }
 const loadData = () => {
   getSimulationInfo().then(res => {

+ 12 - 5
src/pagesStudy/pages/simulation-entry/simulation-entry.vue

@@ -24,8 +24,9 @@
             </text>
           </view>
           <view class="mt-66 text-30 text-fore-light">
-            现在AI系统给您依据“<text
-              class="text-fore-title font-bold">长沙民政职业技术学院</text>”的考试大纲,通过智能扫描提取考纲要点给您生成一张职业技能模拟试卷,这样测试的成绩会更接近真实的考试结果。
+            现在AI系统给您依据“<text class="text-fore-title font-bold">
+              {{ form.selectedCollege.universityName }}
+            </text>”的考试大纲,通过智能扫描提取考纲要点给您生成一张职业技能模拟试卷,这样测试的成绩会更接近真实的考试结果。
           </view>
           <ie-button type="primary" custom-class="mt-112" @click="handleAIOutPaper">AI出卷</ie-button>
         </view>
@@ -36,12 +37,14 @@
 
 <script lang="ts" setup>
 import { useTransferPage } from '@/hooks/useTransferPage';
-const { transferTo } = useTransferPage();
+import { SimulationTestOptions } from '@/types/study';
+const { transferTo, prevData } = useTransferPage();
 const form = ref({
-  college: '长沙民政职业技术学院',
+  selectedCollege: {} as SimulationTestOptions,
   score: 240,
   score2: undefined
-})
+});
+// const form = ref({});
 const handleAIOutPaper = () => {
   uni.$ie.showLoading('AI出卷中...');
   setTimeout(() => {
@@ -49,6 +52,10 @@ const handleAIOutPaper = () => {
     transferTo('/pagesStudy/pages/simulation-start/simulation-start');
   }, 2000);
 }
+onLoad(() => {
+  form.value.selectedCollege = prevData.value as SimulationTestOptions;
+  console.log(prevData.value)
+});
 </script>
 
 <style lang="scss" scoped></style>

+ 6 - 1
src/pagesStudy/pages/start-exam/components/question-item.vue

@@ -43,9 +43,13 @@ const nextQuestion = inject(NEXT_QUESTION);
 const prevQuestion = inject(PREV_QUESTION);
 const nextQuestionQuickly = inject(NEXT_QUESTION_QUICKLY);
 const prevQuestionQuickly = inject(PREV_QUESTION_QUICKLY);
+const emit = defineEmits<{
+  (e: 'update:question', question: Study.Question): void;
+}>();
 const handleNotKnow = () => {
   // console.log('handleNotKnow')
-  props.question.isNotKnow = true;
+  props.question.isNotKnow = !props.question.isNotKnow;
+  emit('update:question', props.question);
   nextQuestion?.();
 }
 const handleSelect = (option: Study.QuestionOption) => {
@@ -68,6 +72,7 @@ const handleSelect = (option: Study.QuestionOption) => {
       props.question.answers.push(option.no);
     }
   }
+  emit('update:question', props.question);
   // props.question.answer = option.no;
 }
 const isSelected = (option: Study.QuestionOption) => {

+ 34 - 18
src/pagesStudy/pages/start-exam/start-exam.vue

@@ -21,7 +21,7 @@
           @change="handleSwiperChange" @transition="handleSwiperTransition"
           @animationfinish="handleSwiperAnimationFinish">
           <swiper-item class="h-full" v-for="(item, index) in questionList" :key="index">
-            <question-item :question="item" />
+            <question-item :question="item" @update:question="handleUpdateQuestion" />
           </swiper-item>
         </swiper>
       </view>
@@ -102,7 +102,7 @@ import { NEXT_QUESTION, PREV_QUESTION, NEXT_QUESTION_QUICKLY, PREV_QUESTION_QUIC
 import { Examinee, ExamPaper, ExamPaperSubmit } from '@/types/study';
 const { prevData, transferBack } = useTransferPage();
 const { setQuestionList, questionList, stateQuestionList, questionTypeDesc, favoriteList, notKnowList, markList, currentIndex,
-  totalCount, doneCount, notDoneCount, notKnowCount, markCount,
+  totalCount, doneCount, notDoneCount, notKnowCount, markCount, isAllDone,
   loadExamData, nextQuestion, prevQuestion, nextQuestionQuickly, prevQuestionQuickly, swiperDuration,
   formatPracticeDuration, formatExamDuration, practiceDuration, startPracticeDuration, stopPracticeDuration,
   examDuration, startExamDuration, stopExamDuration, setExamDuration, setCountDownCallback, changeIndex, reset } = useExam();
@@ -116,6 +116,8 @@ const isAnimationFinish = ref(false);
 const transitionStartX = ref(null);
 const transitionEndX = ref(null);
 const isReady = ref(false);
+// 自动提交只提醒1次
+const hasShowSubmitConfirm = ref(false);
 const examineerData = ref<Examinee>({} as Examinee);
 const paperData = ref<ExamPaper>({} as ExamPaper);
 const pageTitle = computed(() => {
@@ -137,7 +139,6 @@ const handleLeftClick = () => {
   beforeQuit();
 };
 const handleSwiperChange = (e: any) => {
-  // console.log(e)
   currentIndex.value = e.detail.current;
 };
 const beforeQuit = () => {
@@ -151,30 +152,24 @@ const beforeQuit = () => {
     content: msg,
   }).then(confirm => {
     if (confirm) {
-      handleSubmit();
+      handleSubmit(true);
     }
   });
 };
 const currentQuestion = computed(() => {
-  // console.log(questionList.value[currentIndex.value])
   return questionList.value[currentIndex.value] || {};
 });
 const hanadleNavigate = (index: number) => {
-  // console.log('hanadleNavigate', qs)
-  // const index = questionList.value.findIndex(q => q.id === qs.id);
   changeIndex(index);
 }
 const handleFavorite = () => {
-  // console.log('handleFavorite')
   currentQuestion.value.isFavorite = !currentQuestion.value.isFavorite;
 };
 const handleMark = () => {
-  // console.log('handleMark')
   currentQuestion.value.isMark = !currentQuestion.value.isMark;
 };
 const questionStatsPopupRef = ref();
 const handleCalendar = () => {
-  console.log('handleCalendar')
   questionStatsPopupRef.value.open();
 };
 
@@ -229,8 +224,7 @@ const beforeSubmit = () => {
     content: text,
   }).then(confirm => {
     if (confirm) {
-      // uni.navigateBack();
-      handleSubmit();
+      handleSubmit(false);
     } else {
       startTime();
     }
@@ -255,24 +249,46 @@ const handleReset = () => {
   });
 }
 
-const handleSubmit = () => {
+const autoSubmit = () => {
+  if (isAllDone.value) {
+    if (hasShowSubmitConfirm.value) {
+      return;
+    }
+    hasShowSubmitConfirm.value = true;
+    beforeSubmit();
+  }
+}
+
+const handleSubmit = (tempSave: boolean = false) => {
   console.log('handleSubmit', questionList.value)
-  uni.$ie.showLoading('保存中...');
+  const msg = tempSave ? '保存中...' : '提交中...';
+  uni.$ie.showLoading(msg);
   setTimeout(() => {
     uni.$ie.hideLoading();
     const params = {
       ...paperData.value,
-      questions: questionList.value,
+      questions: questionList.value.map(item => {
+        return {
+          ...item,
+          isDone: tempSave ? item.isDone : true
+        };
+      }),
       examineeId: examineerData.value.examineeId,
+      isDone: isAllDone.value
     } as ExamPaperSubmit;
     if (!isExamMode.value) {
       params.duration = practiceDuration.value;
     }
-    console.log(params);
     commitExamineePaper(params);
     uni.navigateBack();
   }, 1000);
-  console.log('handleSubmit')
+}
+
+const handleUpdateQuestion = (question: Study.Question) => {
+  // questionList.value[currentIndex.value] = question;
+  if (currentIndex.value === questionList.value.length - 1) {
+    autoSubmit();
+  }
 }
 
 const loadData = async () => {
@@ -300,7 +316,7 @@ const loadData = async () => {
   }
   isReady.value = true;
   setCountDownCallback(() => {
-    handleSubmit();
+    handleSubmit(false);
   });
   startTime();
 };

+ 1 - 1
src/pagesStudy/pages/study-plan-edit/components/course-setting.vue

@@ -1,6 +1,6 @@
 <template>
   <uv-popup ref="popup" mode="bottom" round="16" :close-on-click-overlay="false">
-    <view class="py-23 bg-white rounded-16 overflow-hidden">
+    <view class="bg-white rounded-16 overflow-hidden">
       <view class="flex items-center justify-between pt-20">
         <view class="px-46 py-20 text-28 text-fore-light" @click="handleCancel">取消</view>
         <text class="text-30 text-fore-title font-bold">课程学习</text>

+ 1 - 1
src/pagesStudy/pages/study-plan-edit/components/question-setting.vue

@@ -1,6 +1,6 @@
 <template>
   <uv-popup ref="popup" mode="bottom" round="16" :close-on-click-overlay="false">
-    <view class="py-23 bg-white rounded-16 overflow-hidden">
+    <view class="bg-white rounded-16 overflow-hidden">
       <view class="flex items-center justify-between pt-20">
         <view class="px-46 py-20 text-28 text-fore-light" @click="handleCancel">取消</view>
         <text class="text-30 text-fore-title font-bold">题库练习</text>

+ 10 - 4
src/pagesStudy/pages/study-plan-edit/study-plan-edit.vue

@@ -39,8 +39,11 @@
 </template>
 
 <script lang="ts" setup>
+import { StudyPlan } from '@/types/study';
 import CourseSetting from './components/course-setting.vue';
 import QuestionSetting from './components/question-setting.vue';
+import { saveStudyPlan } from '@/api/modules/study';
+// type SubmitStudyPlan = Omit<StudyPlan, 'id' | 'beginTime' | 'studentId' | 'status'>;
 const cellStyle = {
   padding: '30rpx 40rpx'
 }
@@ -48,8 +51,8 @@ const rightIconStyle = {
   fontSize: '14px'
 }
 const form = ref({
-  courseTime: 0,
-  questionTime: 0
+  courseTime: null as number | null,
+  questionTime: null as number | null
 })
 const courseStudySetting = ref();
 const questionStudySetting = ref();
@@ -63,13 +66,16 @@ const handleQuestionStudySetting = () => {
     form.value.questionTime = time;
   });
 }
-const handleConfirm = () => {
+const handleConfirm = async () => {
   const { courseTime, questionTime } = form.value;
-  if (!questionTime) {
+  if (questionTime == null || courseTime == null) {
     uni.$ie.showToast('请设置题库学习计划');
     return;
   }
   console.log(form.value);
+  // await saveStudyPlan(form.value);
+  uni.$ie.showToast('保存成功');
+  uni.navigateBack();
   // uni.$ie.showToast('保存成功');
   // uni.navigateBack();
 }

+ 10 - 9
src/pagesStudy/pages/study-plan/study-plan.vue

@@ -17,15 +17,7 @@ import PageCalendar from './components/page-calendar.vue';
 import { useTransferPage } from '@/hooks/useTransferPage';
 import { getStudyPlanStats } from '@/api/modules/study';
 const { transferTo } = useTransferPage();
-const loadData = async () => {
-  const { data } = await getStudyPlanStats({
-    reportMonth: '2025-10-01'
-  });
-  console.log(data)
-}
-loadData();
-onPageScroll(() => { });
-
+const today = uni.$uv.timeFormat(new Date(), 'yyyy-mm-dd');
 const handleEditPlan = () => {
   transferTo('/pagesStudy/pages/study-plan-edit/study-plan-edit', {
     data: {
@@ -33,6 +25,15 @@ const handleEditPlan = () => {
     }
   });
 }
+
+const loadData = async () => {
+  const { data } = await getStudyPlanStats({
+    reportMonth: today
+  });
+  console.log(data)
+}
+loadData();
+onPageScroll(() => { });
 </script>
 
 <style lang="scss" scoped></style>

+ 8 - 1
src/pagesStudy/pages/targeted-add/targeted-add.vue

@@ -74,7 +74,7 @@
 import { useTransferPage } from '@/hooks/useTransferPage';
 import { DirectedSchool, SelectedUniversityMajor, University, UniversityMajor } from '@/types/study';
 import { getUniversityMajorList } from '@/api/modules/university';
-const { transferTo, transferBack } = useTransferPage();
+const { prevData, transferTo, transferBack } = useTransferPage();
 const form = ref<Partial<SelectedUniversityMajor>>({});
 const keyword = ref('');
 const cellStyle = {
@@ -145,6 +145,13 @@ const handleAdd = () => {
     uni.$ie.showToast('请选择专业');
     return;
   }
+  // 检查数据是否已存在
+  const historyData = (prevData.value.historyData || []) as DirectedSchool[];
+  const isExist = historyData.some(item => item.universityId === form.value.universityId && item.majorId === form.value.majorId);
+  if (isExist) {
+    uni.$ie.showToast('该院校专业已存在');
+    return;
+  }
   transferBack(form.value);
 }
 const isActive = (item: UniversityMajor) => {

+ 5 - 3
src/pagesStudy/pages/targeted-setting/targeted-setting.vue

@@ -16,7 +16,7 @@
       </view> -->
     </view>
     <view v-if="hasDirectedSchool" class="px-30">
-      <l-drag ref="dragRef" :list="directedSchoolList" :column="1" :gridHeight="104" :touchHandle="touchHandle" ghost handle
+      <l-drag ref="dragRef" :list="directedSchoolList" :column="1" gridHeight="104px" :touchHandle="touchHandle" ghost handle
         @change="changeSort">
         <!-- // 每一项的插槽 grid 的 content 您传入的数据 -->
         <template #grid="{ active, content, index }">
@@ -37,7 +37,7 @@
                   {{ content.majorName }}
                 </view>
                 <view class="flex items-center justify-between text-20">
-                  <view class="mt-8  text-fore-light">{{ content.ancestors }}</view>
+                  <view class="mt-8  text-fore-light">{{ content.majorAncestors }}</view>
                   <view v-if="index === 0"
                     class="flex items-center gap-x-4 text-white bg-gradient-to-r from-[#FED448] to-[#F9942F] rounded-full px-12 py-4">
                     <ie-image src="/pagesStudy/static/image/icon-check-white.png" custom-class="w-24 h-24" />
@@ -84,7 +84,9 @@ const handleSetDirectedSchool = async (item: DirectedSchool, index: number) => {
 }
 const handleAdd = () => {
   transferTo('/pagesStudy/pages/targeted-add/targeted-add', {
-    data: {}
+    data: {
+      historyData: directedSchoolList.value
+    }
   }).then(async res => {
     if (res) {
       directedSchoolList.value.push({

+ 24 - 0
src/types/study.ts

@@ -55,6 +55,29 @@ export interface StudyPlan {
   status: number;
 }
 
+/**
+ * 学习计划统计数据
+ */
+export interface StudyStats {
+  questionCnt: number; // 答题数
+  videoTime: number; // 课程学习数量
+  videoTimes: number; // 学习时长
+  rightRate: number; // 正确率
+}
+export interface StudyStatsHistory {
+  date: string; // 日期 2025-10-12
+  data: StudyStats; // 数据
+}
+export interface StudyPlanStats {
+  doneDay: number; // 本月完成
+  undoneDay: number; // 本月未完成
+  videoTimes: number; // 本月课程学习时长
+  questionCnt: number; // 本月答题数
+  studyList: StudyStatsHistory[]; // 历史数据(包含今天)
+  today: StudyStats,
+  plan: StudyPlan
+}
+
 export interface Subject {
   subjectId: number;
   subjectName: string;
@@ -131,6 +154,7 @@ export interface ExamPaperSubmit {
   year: number;
   duration?: number;
   examineeId?: number;
+  isDone?: boolean;
 }
 
 export interface QuestionOption {