Browse Source

feat: 学习本功能

huangziyang 4 hours ago
parent
commit
a96188da23

+ 12 - 1
components/Topic/QuestionsItem.vue

@@ -2,6 +2,7 @@
 import Questions from "./QuestionsItemSelect.vue";
 import uvParse from "@/uni_modules/uv-parse/components/uv-parse/uv-parse.vue";
 import { ref, watchEffect } from "vue";
+import { router } from "../../utils/router";
 
 const dataList = ref([]);
 const props = defineProps({
@@ -16,6 +17,10 @@ const props = defineProps({
   onClick: {
     type: Function,
   },
+  catalogue_id: {
+    type: Number,
+    default: 0,
+  },
 });
 const TopicMapList = ["A", "B", "C", "D", "E"];
 
@@ -53,7 +58,6 @@ watchEffect(() => {
       ind,
     };
   });
-  console.log(dataList.value);
 });
 
 const handleClick = (item) => {
@@ -61,6 +65,13 @@ const handleClick = (item) => {
     props.onClick(item);
     return;
   }
+  router.push({
+    url: "/pages/learn/rightPractice",
+    params: {
+      catalogue_id: props.catalogue_id,
+      isRight: props.isRight,
+    },
+  });
   console.log(item);
 };
 </script>

+ 0 - 2
components/Topic/TopicExam.vue

@@ -545,13 +545,11 @@ const onSafeAreaChange = (s) => {
 }
 
 .prev-btn {
-  flex: 1;
   background-color: $uni-primary-light;
   color: $uni-primary;
 }
 
 .next-btn {
-  flex: 1;
   background-color: $uni-primary;
   color: #fff;
 }

+ 0 - 2
components/Topic/TopicPractice.vue

@@ -445,13 +445,11 @@ const onSafeAreaChange = (s) => {
 }
 
 .prev-btn {
-  flex: 1;
   background-color: $uni-primary-light;
   color: $uni-primary;
 }
 
 .next-btn {
-  flex: 1;
   background-color: $uni-primary;
   color: #fff;
 }

+ 464 - 0
components/Topic/TopicPracticeEnd.vue

@@ -0,0 +1,464 @@
+<template>
+  <Container
+    :scrollX="true"
+    :scrollY="true"
+    :scroll-into-view="`item-${nowIndex}`"
+    :title="title"
+    @onSafeAreaChange="onSafeAreaChange"
+    v-bind="$attrs"
+    v-if="!open"
+  >
+    <view
+      :id="`item-${nowIndex}`"
+      class="topic-item"
+      :style="{
+        width: `${safeArea.width}px`,
+        height: `${safeArea.height}px`,
+        flexShrink: 0, // 解决宽度无效问题
+      }"
+    >
+      <!-- 头部 -->
+      <view class="topic-header">
+        <view class="topic-header-left">
+          <view class="topic-type">
+            {{ styleMap[data[nowIndex]?.style] }}题
+          </view>
+          <view class="topic-count">
+            第{{ nowIndex + 1 }}题/共{{ total }}题
+          </view>
+        </view>
+        <view class="star-icon" @tap="handleStar(data[nowIndex])">
+          <uni-icons
+            :type="data[nowIndex]?.is_favorite ? 'star-filled' : 'star'"
+            size="20"
+            color="#fe2624"
+          />
+          {{ data[nowIndex]?.is_favorite ? "已" : "" }}收藏
+        </view>
+      </view>
+      <template v-for="(item, parindex) in data" :key="parindex">
+        <template v-if="parindex === nowIndex">
+          <!-- 问题内容 -->
+          <view class="topic-content">
+            <uvParse
+              v-if="item.isImage"
+              :content="item.title"
+              class="question-text"
+            ></uvParse>
+            <rich-text
+              v-else
+              :nodes="item.title"
+              class="question-text"
+            ></rich-text>
+            <uvParse
+              :content="item.questions_ex"
+              v-if="item.style === 6 && item.isImage"
+              class="question-text"
+            ></uvParse>
+            <rich-text
+              v-else
+              :nodes="item.questions_ex"
+              class="question-text"
+            ></rich-text>
+            <questions
+              v-if="item.style !== 6"
+              v-for="(question, index) in item.questions"
+              :key="index"
+              :answerList="item.ansList"
+              :index="index"
+              :styleCount="item.style"
+              :question="question"
+              :showResult="item.showResult"
+              :parindex="parindex"
+              @select="handleSelect"
+            />
+            <view class="other" v-else>
+              <questions
+                v-for="(question, index) in item.questions"
+                :key="index"
+                :answerList="item.ansList"
+                :index="index"
+                :styleCount="item.style"
+                :question="question"
+                :showResult="item.showResult"
+                :parindex="parindex"
+                @select="handleSelect"
+              />
+            </view>
+          </view>
+
+          <!-- 答案展示 -->
+          <view v-if="item.showResult" class="answer-section">
+            <view class="answer-content">
+              <view class="answer-row">
+                <view class="answer-item border-r-primary">
+                  正确答案:
+                  <text class="answer-text">{{
+                    item.ansList.map((i) => i.label).join("")
+                  }}</text>
+                </view>
+                <view class="answer-item">
+                  我的答案:
+                  <text class="answer-text">{{
+                    item.selectAns.map((i) => i.value).join("")
+                  }}</text>
+                </view>
+                <view
+                  class="tip"
+                  :style="{
+                    color: item.isRight ? '#00be00' : '#f00',
+                  }"
+                  >{{ item.isRight ? "太棒了~" : "再接再励!" }}</view
+                >
+              </view>
+              <view class="parsing">
+                <p>解析:</p>
+                <scroll-view
+                  :show-scrollbar="false"
+                  scroll-y
+                  class="parsing-text"
+                >
+                  <rich-text :nodes="item.explain"></rich-text>
+                </scroll-view>
+              </view>
+            </view>
+          </view>
+
+          <!-- 底部按钮 -->
+          <view class="button-group">
+            <view
+              v-if="parindex >= 1 && parindex + 1 < total && item.showResult"
+              class="prev-btn button"
+              @tap="handlePage(item, parindex, 'prevPage')"
+            >
+              上一题
+            </view>
+            <view
+              v-if="parindex + 1 < total && item.showResult"
+              class="next-btn button"
+              @tap="handlePage(item, parindex, 'nextPage')"
+            >
+              下一题
+            </view>
+            <view
+              class="button"
+              v-if="parindex + 1 === total && item.showResult"
+              @click="emit('lookReport', data, submitter)"
+            >
+              完成
+            </view>
+            <button
+              :disabled="!item.selectAns.length"
+              v-if="!item.showResult"
+              @click="questionSubmit(item, parindex)"
+            >
+              提交
+            </button>
+          </view>
+        </template>
+      </template>
+    </view>
+  </Container>
+  <Modal
+    v-model:open="open"
+    title="温馨提示"
+    :submitter="submitter"
+    :onClose="onClose"
+    :onSubmit="onSubmit"
+  >
+    <view :style="{ margin: '10px 0' }">{{ submitter.context }}</view>
+  </Modal>
+</template>
+
+<script setup>
+// 答题组件
+import { ref, watchEffect } from "vue";
+import Questions from "./Questions.vue";
+import Container from "../Container/Container.vue";
+import Modal from "../Modal/Modal.vue";
+import uvParse from "@/uni_modules/uv-parse/components/uv-parse/uv-parse.vue";
+import { request } from "../../utils/request";
+const styleMap = {
+  2: "单选",
+  3: "多选",
+  6: "配伍",
+};
+
+const submitter = ref({
+  text: "提交查看",
+  closeText: "直接退出",
+  context: "您本次答题还未提交, 确定要退出答题吗?",
+  isEndQuestion: false,
+});
+
+const safeArea = ref({}); // 安全区域
+const data = ref([]); // 题目数据
+const open = ref(false); // 是否显示弹窗
+let r = null; // 异步方法
+
+// Props 定义
+const props = defineProps({
+  topics: {
+    type: Array,
+    default: () => [],
+  },
+  onStar: {
+    type: Function,
+    default: null,
+  },
+  total: {
+    type: Number,
+    default: 0,
+  },
+  title: String,
+  user_exercise_paper_id: Number,
+});
+
+watchEffect(() => {
+  data.value = props.topics;
+});
+
+// Emits 定义
+const emit = defineEmits([
+  "prevPage",
+  "nextPage",
+  "answerChange",
+  "lookReport",
+]);
+
+const onBack = () =>
+  new Promise((resolve) => {
+    if (!data.value.length) {
+      resolve(true);
+      return;
+    }
+    const isEndQuestion =
+      nowIndex.value === props.total - 1 &&
+      data.value[nowIndex.value].showResult;
+
+    if (isEndQuestion) {
+      submitter.value = {
+        ...submitter.value,
+        text: "查看报告",
+        context:
+          "您的答题报告已准备就绪!退出后将无法查看本次分析结果,且不保留本次答题记录,确定要放弃吗?",
+        isEndQuestion,
+      };
+    }
+    open.value = true;
+    r = resolve;
+  });
+
+const onClose = () => r(true);
+const onSubmit = () =>
+  new Promise((res) => {
+    emit("lookReport", data.value, submitter.value);
+    res(true);
+  });
+// 响应式数据
+const nowIndex = ref(0);
+
+// 判断答案是否正确
+const isRight = (selectAns, rightAns) => {
+  return selectAns.every((item) => rightAns.includes(item));
+};
+
+// 收藏方法
+const handleStar = (item) => {
+  if (!props.onStar) return;
+  props.onStar(item).then((res) => {
+    uni.showToast({
+      title: res ? "已加入收藏" : "已移除收藏",
+      icon: "none",
+    });
+  });
+};
+
+const handleSelect = ({ pid, checked, index, style }) => {
+  // 如果不是多选,就取消其他的选项
+  if (style !== 3) {
+    data.value[pid].questions = data.value[pid].questions.map((q) => ({
+      ...q,
+      checked: false,
+    }));
+    data.value[pid].selectAns = [];
+  }
+  // 更新选项
+  const item = data.value[pid].questions[index];
+  data.value[pid].questions[index].checked = !checked;
+  data.value[pid].questions[index].isRight = isRight(
+    [item.value],
+    data.value[pid].ansList.map((q) => q.label)
+  );
+
+  // 更新答案
+  data.value[pid].selectAns = data.value[pid].questions
+    .filter((q) => q.checked)
+    .map((q) => q.value);
+};
+
+const ansIsRight = (selectAns, rightAns) => {
+  if (selectAns.length !== rightAns.length) return false;
+  return isRight(selectAns, rightAns);
+};
+
+const questionSubmit = (item) => {
+  item.showResult = true;
+  item.selectAns = item.questions.filter((q) => q.checked);
+  item.isRight = ansIsRight(
+    item.selectAns.map((q) => q.value),
+    item.ansList.map((q) => q.label)
+  );
+
+  request("api/question_bank/question_reception/topic/answer_topic", {
+    id: item.id,
+    answer: item.selectAns.map((q) => q.value).join(","),
+    is_correct: item.isRight ? 1 : 0,
+    user_exercise_paper_id: props.user_exercise_paper_id,
+    chapter_id: item.chapter_id,
+  });
+};
+
+const handlePage = (item, index, type) => {
+  nowIndex.value = index + (type === "prevPage" ? -1 : 1);
+  emit(type, { item, index });
+};
+
+const onSafeAreaChange = (s) => {
+  safeArea.value = s;
+};
+</script>
+
+<style lang="scss" scoped>
+@import "@/uni.scss";
+.other {
+  display: flex;
+  gap: 12px;
+}
+.parsing-text {
+  height: 381rpx;
+  white-space: normal;
+}
+.answer-content {
+  display: flex;
+  flex-direction: column;
+  gap: 45rpx;
+  font-family: PingFang SC, PingFang SC;
+  font-weight: 500;
+  font-size: 32rpx;
+  color: #666666;
+}
+.topic-container {
+  width: 100vw;
+  overflow: hidden;
+  position: relative;
+}
+
+.topic-item {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+  position: relative;
+  box-sizing: border-box;
+}
+
+.topic-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+
+.topic-header-left {
+  display: flex;
+  gap: 8px;
+  align-items: center;
+}
+
+.topic-type {
+  border: 1px solid $uni-primary;
+  padding: 0 8px;
+  border-radius: 6px;
+  color: $uni-primary;
+  font-weight: 600;
+  font-size: 14px;
+}
+
+.topic-count {
+  color: #333;
+  font-size: 14px;
+}
+
+.topic-content {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+}
+
+.question-text {
+  font-weight: bold;
+  font-size: 14px;
+  white-space: normal;
+}
+
+.answer-section {
+  border-radius: 16rpx;
+  border: 1px solid #ddd;
+  padding: 24rpx;
+  display: flex;
+  flex-direction: column;
+  gap: 32rpx;
+}
+
+.answer-row {
+  font-size: 14px;
+  display: flex;
+  align-items: center;
+  gap: 12px;
+}
+
+.answer-item {
+  display: flex;
+  gap: 8px;
+  align-items: center;
+  padding-right: 12px;
+}
+
+.tip {
+  margin-left: auto;
+}
+
+.border-r-primary {
+  border-right: 2px solid $uni-primary;
+}
+
+.answer-text {
+  color: $uni-primary;
+}
+
+.button-group {
+  display: flex;
+  gap: 8px;
+  position: sticky;
+  bottom: 0;
+  margin-top: auto;
+}
+
+.prev-btn {
+  background-color: $uni-primary-light;
+  color: $uni-primary;
+}
+
+.next-btn {
+  background-color: $uni-primary;
+  color: #fff;
+}
+
+.star-icon {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  font-weight: 500;
+  font-size: 20rpx;
+  color: #000000;
+}
+</style>

+ 25 - 13
pages.json

@@ -14,6 +14,20 @@
         "navigationBarTitleText": "学习本"
       }
     },
+    {
+      "path": "pages/learn/rightPractice",
+      "style": {
+        "navigationStyle": "custom",
+        "navigationBarTitleText": "答题详情"
+      }
+    },
+    {
+      "path": "pages/learn/favorite",
+      "style": {
+        "navigationStyle": "custom",
+        "navigationBarTitleText": "收藏详情"
+      }
+    },
     {
       "path": "pages/challenge/index",
       "style": {
@@ -129,7 +143,7 @@
     {
       "path": "pages/user/settings",
       "style": {
-		"navigationStyle": "custom",
+        "navigationStyle": "custom",
         "navigationBarTitleText": "设置"
       }
     },
@@ -140,20 +154,18 @@
       }
     },
     {
-    	"path" : "pages/notice/list",
-    	"style" : 
-    	{
-			"navigationStyle": "custom",
-    		"navigationBarTitleText" : "公告列表"
-    	}
+      "path": "pages/notice/list",
+      "style": {
+        "navigationStyle": "custom",
+        "navigationBarTitleText": "公告列表"
+      }
     },
     {
-    	"path" : "pages/notice/detail",
-    	"style" : 
-    	{
-			 "navigationStyle": "custom",
-    		"navigationBarTitleText" : "公告详情"
-    	}
+      "path": "pages/notice/detail",
+      "style": {
+        "navigationStyle": "custom",
+        "navigationBarTitleText": "公告详情"
+      }
     }
   ],
   "globalStyle": {

+ 223 - 0
pages/learn/favorite.vue

@@ -0,0 +1,223 @@
+<script setup name="Exam">
+import TopicPractice from "../../components/Topic/TopicPracticeEnd.vue";
+import { ref, onMounted } from "vue";
+import { getRoute, router } from "../../utils/router";
+import { request } from "../../utils/request";
+
+const TopicMapList = ["A", "B", "C", "D", "E"];
+
+const title = ref("");
+const total = ref(0);
+
+const data = ref([]);
+const user_exercise_paper_id = ref(0);
+const getList = async (params) => {
+  const res = await request(
+    "api/question_bank/question_reception/favorite/get_user_favorite_list",
+    {
+      chapter_id: params.chapter_id,
+    }
+  );
+  total.value = res.data.total;
+  data.value.push(
+    ...res.data.data.map((item, ind) => {
+      let questions = [];
+      const ans = item.correct_answer.split(",");
+      const ansList = [];
+      for (let i = 0; i < item.question_count; i++) {
+        const current = TopicMapList[i];
+        if (ans.includes(current)) {
+          ansList.push({
+            label: current,
+            value: i,
+          });
+        }
+        const v =
+          item[`select_${current.toLowerCase()}`].replace(/<br\s*\/?>/g, "") ||
+          "";
+        questions.push({
+          label: v,
+          value: current,
+          checked: false,
+          index: i,
+        });
+      }
+
+      return {
+        ...item,
+        questions, // 题目
+        ansList, // 正确答案
+        selectAns: [], // 选择的答案
+        showResult: false, // 是否展示答案
+        isRight: false, // 是否正确
+        isImage: item.title.includes("<img"),
+        ind,
+      };
+    })
+  );
+};
+
+const lookReport = () => {
+  router.back();
+};
+
+const onStar = (item) =>
+  new Promise((resolve) => {
+    request(
+      !item.is_favorite
+        ? "api/question_bank/question_reception/topic/set_favorite"
+        : "api/question_bank/question_reception/topic/cancel_favorite",
+      {
+        id: item.id,
+        chapter_id: getRoute().params.id,
+        user_exercise_paper_id: user_exercise_paper_id.value,
+      }
+    ).then(() => {
+      item.is_favorite = item.is_favorite ? 0 : 1;
+      resolve(item.is_favorite);
+    });
+  });
+
+onMounted(() => {
+  const params = getRoute().params;
+  title.value = params.title;
+  getList(params);
+});
+</script>
+
+<template>
+  <TopicPractice
+    :title="title"
+    :total="total"
+    :topics="data"
+    :user_exercise_paper_id="user_exercise_paper_id"
+    :onStar="onStar"
+    :empty="!data.length"
+    @lookReport="lookReport"
+    text="加载中···"
+    border
+  />
+</template>
+
+<style lang="scss" scoped>
+@import "@/uni.scss";
+.template {
+  padding: 15rpx;
+  border-radius: 24rpx;
+  background-color: #f8f9fb;
+}
+.red {
+  color: #ff4444;
+}
+
+.title-r {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-weight: 500;
+  font-size: 50rpx;
+  color: #002fa7;
+}
+.card {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  gap: 63rpx;
+  padding: 40rpx 50rpx;
+  background-color: #f8f9fb;
+  border-radius: 24rpx;
+  &-time {
+    font-family: PingFang SC, PingFang SC;
+    font-weight: 500;
+    font-size: 28rpx;
+    color: #999999;
+    display: flex;
+    flex-direction: column;
+    gap: 10rpx;
+    align-items: center;
+  }
+}
+
+.reslut {
+  margin: 0 32rpx;
+  padding: 24rpx;
+  font-family: PingFang SC, PingFang SC;
+  font-weight: 500;
+  font-size: 28rpx;
+  color: #333333;
+  background: #fff;
+  border-radius: 24rpx;
+  display: flex;
+  flex-direction: column;
+  gap: 24rpx;
+  .header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+
+    .right-error {
+      display: flex;
+      gap: 20rpx;
+      font-weight: 400;
+      font-size: 20rpx;
+      color: #333333;
+      @mixin type($color) {
+        display: flex;
+        align-items: center;
+        gap: 10rpx;
+        &::before {
+          content: "";
+          width: 16rpx;
+          height: 16rpx;
+          border-radius: 50%;
+          display: block;
+          background: $color;
+        }
+      }
+      .right {
+        @include type($success);
+      }
+      .error {
+        @include type($error);
+      }
+      .not {
+        @include type($default);
+      }
+    }
+  }
+
+  .group {
+    display: grid;
+    grid-template-columns: repeat(6, 1fr);
+    gap: 20rpx;
+    margin-top: 20rpx;
+
+    .item {
+      width: 72rpx;
+      height: 72rpx;
+      border-radius: 50%;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      background: $default;
+      font-family: PingFang SC, PingFang SC;
+      font-weight: 500;
+      font-size: 28rpx;
+      color: #ffffff;
+    }
+    .item.right {
+      background: $success;
+    }
+    .item.error {
+      background: $error;
+    }
+  }
+}
+
+.footer {
+  display: flex;
+  gap: 20rpx;
+  align-items: center;
+  padding-top: 20rpx;
+}
+</style>

+ 13 - 6
pages/learn/index.vue

@@ -69,7 +69,7 @@
     </div>
     <div class="context">
       <template v-if="currentIndex === 0 && dataList.length">
-        <QuestionsItem :data="dataList" :isRight="isRight" />
+        <QuestionsItem :data="dataList" :isRight="isRight" :catalogue_id="currentTab" />
       </template>
       <template v-else-if="currentIndex === 1 && examList.length">
         <div class="card" v-for="item in examList" :key="item.catalogue_id">
@@ -89,7 +89,7 @@
       <template v-else-if="currentIndex === 2 && favoriteList.length">
         <QuestionsItem
           :data="favoriteList"
-          :isRight="isRight"
+          isRight
           :onClick="toFavorite"
         />
       </template>
@@ -118,12 +118,13 @@ const examList = ref([]);
 const favoriteList = ref([]);
 const toHistory = (item) => {
   router.push({
-    path: "/pages/real/history",
-    query: {
+    url: "/pages/real/history",
+    params: {
       id: item.catalogue_id,
     },
   });
 };
+
 const requestTopic = (is_correct, onSucess) => {
   request(
     "api/question_bank/question_reception/study_book/get_answer_topic_record",
@@ -161,8 +162,14 @@ const requestFavo = () => {
     favoriteList.value = res.data.data;
   });
 };
-const toFavorite = (item) => {
-  console.log(item);
+const toFavorite = () => {
+  router.push({
+    url: "/pages/learn/favorite",
+    params: {
+      chapter_id: currentTab.value,
+      title: '收藏'
+    },
+  });
 };
 watch(currentIndex, () => {
   switch (currentIndex.value) {

+ 226 - 0
pages/learn/rightPractice.vue

@@ -0,0 +1,226 @@
+<script setup name="Exam">
+import TopicPractice from "../../components/Topic/TopicPracticeEnd.vue";
+import { ref, onMounted } from "vue";
+import { getRoute, router } from "../../utils/router";
+import { request } from "../../utils/request";
+
+const TopicMapList = ["A", "B", "C", "D", "E"];
+
+const title = ref("");
+const total = ref(0);
+
+const data = ref([]);
+const user_exercise_paper_id = ref(0);
+const getList = async (params) => {
+  const res = await request(
+    "api/question_bank/question_reception/study_book/get_answer_topic_record",
+    {
+      chapter_id: params.catalogue_id,
+      is_correct: Number(params.isRight),
+    }
+  );
+  total.value = res.data.total;
+  data.value.push(
+    ...res.data.data.map((item, ind) => {
+      const selectAns = Number(params.isRight) ? item.answer.split(",") : [];
+      let questions = [];
+      const ans = item.correct_answer.split(",");
+      const ansList = [];
+      for (let i = 0; i < item.question_count; i++) {
+        const current = TopicMapList[i];
+        if (ans.includes(current)) {
+          ansList.push({
+            label: current,
+            value: i,
+          });
+        }
+        const v =
+          item[`select_${current.toLowerCase()}`].replace(/<br\s*\/?>/g, "") ||
+          "";
+        questions.push({
+          label: v,
+          value: current,
+          checked: selectAns.includes(current),
+          isRight: ans.includes(current),
+          index: i,
+        });
+      }
+
+      return {
+        ...item,
+        questions, // 题目
+        ansList, // 正确答案
+        selectAns: selectAns.map((i) => ({ value: i, label: i })), // 选择的答案
+        showResult: !!Number(params.isRight), // 是否展示答案
+        isRight: !!Number(params.isRight), // 是否正确
+        isImage: item.title.includes("<img"),
+        ind,
+      };
+    })
+  );
+};
+
+const lookReport = () => {
+  router.back();
+};
+
+const onStar = (item) =>
+  new Promise((resolve) => {
+    request(
+      !item.is_favorite
+        ? "api/question_bank/question_reception/topic/set_favorite"
+        : "api/question_bank/question_reception/topic/cancel_favorite",
+      {
+        id: item.id,
+        chapter_id: getRoute().params.id,
+        user_exercise_paper_id: user_exercise_paper_id.value,
+      }
+    ).then(() => {
+      item.is_favorite = item.is_favorite ? 0 : 1;
+      resolve(item.is_favorite);
+    });
+  });
+
+onMounted(() => {
+  const params = getRoute().params;
+  title.value = params.title;
+  getList(params);
+});
+</script>
+
+<template>
+  <TopicPractice
+    :title="title"
+    :total="total"
+    :topics="data"
+    :user_exercise_paper_id="user_exercise_paper_id"
+    :onStar="onStar"
+    :empty="!data.length"
+    @lookReport="lookReport"
+    text="加载中···"
+    border
+  />
+</template>
+
+<style lang="scss" scoped>
+@import "@/uni.scss";
+.template {
+  padding: 15rpx;
+  border-radius: 24rpx;
+  background-color: #f8f9fb;
+}
+.red {
+  color: #ff4444;
+}
+
+.title-r {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-weight: 500;
+  font-size: 50rpx;
+  color: #002fa7;
+}
+.card {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  gap: 63rpx;
+  padding: 40rpx 50rpx;
+  background-color: #f8f9fb;
+  border-radius: 24rpx;
+  &-time {
+    font-family: PingFang SC, PingFang SC;
+    font-weight: 500;
+    font-size: 28rpx;
+    color: #999999;
+    display: flex;
+    flex-direction: column;
+    gap: 10rpx;
+    align-items: center;
+  }
+}
+
+.reslut {
+  margin: 0 32rpx;
+  padding: 24rpx;
+  font-family: PingFang SC, PingFang SC;
+  font-weight: 500;
+  font-size: 28rpx;
+  color: #333333;
+  background: #fff;
+  border-radius: 24rpx;
+  display: flex;
+  flex-direction: column;
+  gap: 24rpx;
+  .header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+
+    .right-error {
+      display: flex;
+      gap: 20rpx;
+      font-weight: 400;
+      font-size: 20rpx;
+      color: #333333;
+      @mixin type($color) {
+        display: flex;
+        align-items: center;
+        gap: 10rpx;
+        &::before {
+          content: "";
+          width: 16rpx;
+          height: 16rpx;
+          border-radius: 50%;
+          display: block;
+          background: $color;
+        }
+      }
+      .right {
+        @include type($success);
+      }
+      .error {
+        @include type($error);
+      }
+      .not {
+        @include type($default);
+      }
+    }
+  }
+
+  .group {
+    display: grid;
+    grid-template-columns: repeat(6, 1fr);
+    gap: 20rpx;
+    margin-top: 20rpx;
+
+    .item {
+      width: 72rpx;
+      height: 72rpx;
+      border-radius: 50%;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      background: $default;
+      font-family: PingFang SC, PingFang SC;
+      font-weight: 500;
+      font-size: 28rpx;
+      color: #ffffff;
+    }
+    .item.right {
+      background: $success;
+    }
+    .item.error {
+      background: $error;
+    }
+  }
+}
+
+.footer {
+  display: flex;
+  gap: 20rpx;
+  align-items: center;
+  padding-top: 20rpx;
+}
+</style>

+ 3 - 3
pages/real/history.vue

@@ -3,12 +3,12 @@
     <view class="user">
       <image
         class="avatar"
-        :src="userInfo.userpic"
+        :src="userInfo?.userpic"
         width="40"
         height="40"
-        v-if="userInfo.userpic"
+        v-if="userInfo?.userpic"
       />
-      <view class="name">{{ userInfo.username }}</view>
+      <view class="name">{{ userInfo?.username }}</view>
     </view>
     <view class="exam-info">
       <view class="item">

+ 2 - 2
pages/regulations/learing.vue

@@ -82,8 +82,8 @@ onShow(() => {
   });
 });
 
-const onClick = (e, index) => {
-  scrollTop.value = e.currentTarget.offsetTop
+const onClick = (e) => {
+  scrollTop.value = e.currentTarget.offsetTop;
 };
 </script>
 

+ 1 - 1
utils/request.js

@@ -29,7 +29,7 @@ domain =
     : "https://openwork.dfwy.tech/";
 port = "wap";
 // #endif
-domain = "https://openwork.dfwy.tech/";
+// domain = "https://openwork.dfwy.tech/";
 // 发送网络请求的函数
 export const request = (url, data = {}, method = "GET") => {
   // 获取登录标识