AnswerView.vue 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. <script setup lang="ts">
  2. import HuliApi, { AnswerItem, AnswerStart } from '@/api/huli/HuliApi';
  3. import Tiite from '@/assets/images/Answer/Tiite.png';
  4. import PageLeftTitleRightContent from '@/components/parts/PageLeftTitleRightContent.vue';
  5. import SimplePageContentLoader from '@/components/SimplePageContentLoader.vue';
  6. import Box2 from '@/components/small/Box2.vue';
  7. import { useSimpleDataLoader } from '@/composeable/SimpleDataLoader';
  8. import { RandomUtils, waitTimeOut } from '@imengyu/imengyu-utils';
  9. import { ScrollRect } from '@imengyu/vue-scroll-rect';
  10. import { message } from 'ant-design-vue';
  11. import { computed, reactive, ref } from 'vue';
  12. const userName = ref(RandomUtils.genNonDuplicateID(6));
  13. const isAnswer = ref(false);
  14. const isShowRank = ref(false);
  15. const currentDate = ref<AnswerStart>();
  16. const currentSelectIndex = ref(-1);
  17. const currentQuestion = ref<AnswerItem>();
  18. const currentState = ref(-1);
  19. const currentScore = reactive({
  20. correctCount: 0,
  21. wrongCount: 0,
  22. totalCount: 0,
  23. score: 0,
  24. finished: true,
  25. });
  26. const rankListData = useSimpleDataLoader(async () => {
  27. return (await HuliApi.getAnswerRankList());
  28. }, false);
  29. const myRank = computed(() => {
  30. if (!rankListData.content.value)
  31. return '0';
  32. const listIndex = rankListData.content.value.findIndex((item) => item.name === userName.value);
  33. if (listIndex === -1)
  34. return '99+';
  35. return (listIndex + 1).toString();
  36. })
  37. function showRank() {
  38. isShowRank.value = true;
  39. rankListData.loadData(undefined, true);
  40. }
  41. async function quitAnswer() {
  42. isAnswer.value = false;
  43. isShowRank.value = false;
  44. }
  45. async function goAnswer() {
  46. isAnswer.value = true;
  47. currentSelectIndex.value = -1;
  48. currentScore.correctCount = 0;
  49. currentScore.wrongCount = 0;
  50. currentScore.finished = false;
  51. currentDate.value = await HuliApi.answerStart();
  52. currentScore.totalCount = currentDate.value.leftCount;
  53. await nextQuestion();
  54. }
  55. async function nextQuestion() {
  56. if (currentState.value !== -1)
  57. return;
  58. if (currentSelectIndex.value === -1 && currentQuestion.value) {
  59. message.info('请选择一个答案');
  60. return;
  61. }
  62. if (currentQuestion.value) {
  63. currentState.value = await HuliApi.answerSubmit(currentSelectIndex.value) === 'answer' ? 1 : 0;
  64. if (currentState.value === 1)
  65. currentScore.correctCount++;
  66. else
  67. currentScore.wrongCount++;
  68. await waitTimeOut(1000);
  69. currentState.value = -1;
  70. }
  71. if (currentQuestion.value?.leftCount === 0) {
  72. currentScore.score = Math.floor(currentScore.correctCount * 100 / (currentScore.correctCount + currentScore.wrongCount));
  73. currentScore.finished = true;
  74. await HuliApi.answerComplete(userName.value);
  75. } else {
  76. currentSelectIndex.value = -1;
  77. currentQuestion.value = await HuliApi.answerNext();
  78. }
  79. }
  80. </script>
  81. <template>
  82. <PageLeftTitleRightContent :box="false">
  83. <template #content>
  84. <div class="d-flex flex-col align-center size-s color-text-second gap-s">
  85. <img class="w-50" :src="Tiite" />
  86. <div class="d-flex flex-row justify-content-center">
  87. 文物守护者
  88. <span class="ml-3 mr-3">保护文物</span>
  89. 留下历史
  90. </div>
  91. <span>守护者 {{ userName }} 欢迎您</span>
  92. <Box2 v-if="isShowRank" class="list w-70 mt-3">
  93. <div class="d-flex flex-col p-4 bg-light text-align-center h-100">
  94. <div class="d-flex flex-row justify-between align-center">
  95. <img class="main-image-button" src="@/assets/images/IconBack.png" tabindex="0" @click="quitAnswer"></img>
  96. <h4>排行榜</h4>
  97. <div class="main-image-button"></div>
  98. </div>
  99. <ScrollRect scroll="vertical" class="flex-one">
  100. <SimplePageContentLoader :loader="rankListData">
  101. <div class="d-flex flex-column">
  102. <div class="d-flex flex-row justify-between align-center size-ss color-text-second p-3 border-bottom-forth">
  103. <p>您的排名 {{ myRank }} 分数:{{ currentScore.score }}</p>
  104. </div>
  105. <div
  106. class="d-flex flex-row justify-between align-center size-ss color-text-second p-3 border-bottom-forth cursor-pointer"
  107. v-for="(item, key) in rankListData.content.value"
  108. :key="key"
  109. >
  110. <div class="d-flex flex-row align-center">
  111. <span class="p-2 bg-light border-all-dark mr-3">{{ key + 1 }}</span>
  112. <img class="logo" v-if="key==0" src="@/assets/images/Answer/No1.png" />
  113. <img class="logo" v-else-if="key==1" src="@/assets/images/Answer/No2.png" />
  114. <img class="logo" v-else src="@/assets/images/Answer/Logo.png" />
  115. <span class="ml-3">{{ item.name }}</span>
  116. </div>
  117. <span>
  118. <span class="size-s mr-2">{{ item.score }}分</span>
  119. <span>{{ item.costTime }}</span>
  120. </span>
  121. </div>
  122. </div>
  123. </SimplePageContentLoader>
  124. </ScrollRect>
  125. </div>
  126. </Box2>
  127. <Box2 v-else-if="isAnswer" class="mt-3">
  128. <div v-if="currentScore.finished" class="d-flex flex-col p-4 bg-light text-align-center">
  129. <h3>答题结束</h3>
  130. <hr class="w-100 mt-3 mb-3" />
  131. <h3>您的得分:{{ currentScore.score }}</h3>
  132. <p>共计{{ currentScore.totalCount }}题,您答对了 {{ currentScore.correctCount }} 道题!</p>
  133. <button class="mt-3" @click="showRank">查看排行榜</button>
  134. </div>
  135. <div v-else class="d-flex flex-col p-4 bg-light">
  136. <img class="main-image-button" src="@/assets/images/IconBack.png" tabindex="0" @click="quitAnswer"></img>
  137. <template v-if="currentQuestion">
  138. <div class="d-flex flex-row justify-content-between align-center mt-3">
  139. <span class="border-all-dark p-2 mr-3 flex-shrink-0">{{ currentQuestion.seq }} / {{ currentQuestion.leftCount }}</span>
  140. <span>{{ currentQuestion.title }}</span>
  141. </div>
  142. <hr class="w-100 mt-3 mb-3" />
  143. <div class="d-flex flex-row flex-wrap justify-content-between gap-ll">
  144. <button
  145. v-for="(item, index) in currentQuestion.optionList"
  146. :key="index"
  147. :class="[
  148. 'flex-shrink-0 m-0',
  149. currentSelectIndex === index ? 'bg-primary color-pure' : '',
  150. currentSelectIndex === index ? (currentState === 1 ? 'bg-success color-pure' : currentState === 0 ? 'bg-danger color-pure' : '') : '',
  151. ]"
  152. style="width:calc(50% - 40px);height: 15vh"
  153. @click="currentSelectIndex = index"
  154. >
  155. <span v-if="currentSelectIndex === index && currentState === 1" class="mr-2 size-l">✔</span>
  156. <span v-if="currentSelectIndex === index && currentState === 0" class="mr-2 size-l">❌</span>
  157. {{ item.label }}
  158. </button>
  159. </div>
  160. <hr class="w-100 mt-3 mb-3" />
  161. <div class="d-flex flex-row justify-content-between">
  162. <button @click="nextQuestion">下一题</button>
  163. </div>
  164. </template>
  165. </div>
  166. </Box2>
  167. <button v-else class="mt-4" @click="goAnswer">开始答题</button>
  168. </div>
  169. </template>
  170. </PageLeftTitleRightContent>
  171. </template>
  172. <style lang="scss" scoped>
  173. .list {
  174. height: 60vh;
  175. }
  176. .logo {
  177. width: 60px;
  178. height: 60px;
  179. }
  180. </style>