camera.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  1. "use strict";
  2. const common_vendor = require("../../common/vendor.js");
  3. const api_user = require("../../api/user.js");
  4. const common_config = require("../../common/config.js");
  5. const common_assets = require("../../common/assets.js");
  6. const _sfc_main = {
  7. data() {
  8. return {
  9. cameraContext: null,
  10. devicePosition: "front",
  11. interviewStarted: true,
  12. showEndModal: false,
  13. currentQuestionIndex: 0,
  14. currentStep: 1,
  15. stepTexts: ["测试准备", "回答问题", "测试结束"],
  16. progressWidth: 50,
  17. remainingTime: "00:27",
  18. selectedOption: null,
  19. selectedOptions: [],
  20. showResult: false,
  21. isAnswerCorrect: false,
  22. questions: [],
  23. // 改为空数组,将通过API获取
  24. interviewId: null,
  25. // 存储当前面试ID
  26. useVideo: false,
  27. timerInterval: null,
  28. score: 0,
  29. totalQuestions: 0,
  30. interviewCompleted: false,
  31. digitalHumanUrl: "",
  32. // 数字人URL
  33. loading: true,
  34. // 添加加载状态
  35. loadError: false,
  36. // 添加加载错误状态
  37. errorMessage: "",
  38. // 添加错误消息
  39. answers: [],
  40. // 存储用户的所有答案
  41. currentQuestionDetail: null,
  42. // 当前题目详情
  43. isSubmitting: false,
  44. // 是否正在提交答案
  45. openQuestionAnswer: "",
  46. // 存储开放问题的答案
  47. currentAnswer: null,
  48. // 存储当前答案以便提交
  49. questionStartTime: null,
  50. // 存储问题开始时间
  51. mode: "normal",
  52. // 相机模式
  53. currentScrollId: "question-0",
  54. // 当前滚动到的问题ID
  55. questionGroups: [],
  56. // 存储分组后的题目
  57. currentGroupIndex: 0,
  58. // 当前显示的组索引
  59. showContinueButton: false,
  60. // 是否显示继续按钮
  61. scrollToBottom: false,
  62. // 新增:是否需要滚动到底部
  63. scrollTop: 0,
  64. // 控制 scroll-view 的滚动位置
  65. _clickTimer: null,
  66. _isClicking: false
  67. };
  68. },
  69. computed: {
  70. currentQuestion() {
  71. console.log(this.questions[this.currentQuestionIndex]);
  72. return this.questions[this.currentQuestionIndex];
  73. }
  74. },
  75. onLoad(options) {
  76. if (options && options.id) {
  77. this.interviewId = options.id;
  78. this.fetchInterviewData();
  79. } else {
  80. this.fetchInterviewList();
  81. }
  82. },
  83. onReady() {
  84. this.cameraContext = common_vendor.index.createCameraContext();
  85. if (this.useVideo) {
  86. this.aiVideoContext = common_vendor.index.createVideoContext("aiInterviewer");
  87. }
  88. this.initDigitalHuman();
  89. },
  90. methods: {
  91. // 获取面试列表
  92. async fetchInterviewList() {
  93. try {
  94. this.loading = true;
  95. const res2 = await api_user.getQuestions({
  96. position_id: JSON.parse(common_vendor.index.getStorageSync("selectedJob")).id,
  97. page: 1,
  98. limit: 999,
  99. tenant_id: JSON.parse(common_vendor.index.getStorageSync("userInfo")).tenant_id || 1
  100. });
  101. console.log(res2.items);
  102. this.interviewId = res2.items;
  103. this.fetchInterviewData(res2.items);
  104. } catch (error) {
  105. console.error("获取面试列表失败:", error);
  106. this.handleLoadError("获取面试列表失败");
  107. }
  108. },
  109. // 获取面试详情数据
  110. async fetchInterviewData(data) {
  111. try {
  112. this.loading = true;
  113. if (data && Array.isArray(data)) {
  114. const formattedQuestions = data.filter((q) => q.question_form !== 0).map((q, index) => ({
  115. id: q.id || index + 1,
  116. text: q.question || "未知问题",
  117. options: q.options || [],
  118. correctAnswer: q.correctAnswer || 0,
  119. isImportant: q.is_system || false,
  120. explanation: q.explanation || "",
  121. questionType: q.question_form,
  122. questionTypeName: q.question_form_name || "单选题",
  123. is_required_correct: q.is_required_correct || false,
  124. correctAnswers: q.correct_answers || [],
  125. difficulty: q.difficulty || 1,
  126. difficultyName: q.difficulty_name || "初级",
  127. imageUrl: q.question_image_url || "",
  128. // 添加图片URL字段
  129. category: q.category || 0
  130. // 添加 category 字段
  131. }));
  132. this.processQuestionGroups(formattedQuestions);
  133. } else {
  134. this.processInterviewData(res);
  135. }
  136. console.log(this.questions);
  137. this.totalQuestions = this.questions.length;
  138. } catch (error) {
  139. console.error("获取面试详情失败:", error);
  140. this.handleLoadError("获取面试详情失败");
  141. } finally {
  142. this.loading = false;
  143. }
  144. },
  145. // 处理面试数据
  146. processInterviewData(data) {
  147. this.questions = [];
  148. if (data && data.question_form !== 0) {
  149. const formattedQuestion = {
  150. id: data.id || 1,
  151. text: data.question || "未知问题",
  152. options: data.options || [],
  153. correctAnswer: data.correctAnswer || 0,
  154. isImportant: data.is_system || false,
  155. explanation: data.explanation || "",
  156. questionType: data.question_form,
  157. // 1-单选题,2-多选题,3-看图答题
  158. questionTypeName: data.question_form_name || "单选题",
  159. is_required_correct: data.is_required_correct || false,
  160. correctAnswers: data.correct_answers || [],
  161. difficulty: data.difficulty || 1,
  162. difficultyName: data.difficulty_name || "初级",
  163. imageUrl: data.question_image_url || ""
  164. // 添加图片URL字段
  165. };
  166. this.questions.push(formattedQuestion);
  167. this.totalQuestions = this.questions.length;
  168. } else {
  169. this.handleLoadError("没有可用的选择题");
  170. }
  171. },
  172. // 处理加载错误
  173. handleLoadError(message) {
  174. this.loadError = true;
  175. this.loading = false;
  176. this.errorMessage = message || "加载失败";
  177. common_vendor.index.showToast({
  178. title: message || "加载失败",
  179. icon: "none",
  180. duration: 2e3
  181. });
  182. },
  183. startTimer() {
  184. if (this.questions.length === 0)
  185. return;
  186. this.questionStartTime = /* @__PURE__ */ new Date();
  187. let seconds = 60;
  188. this.remainingTime = `01:00`;
  189. this.timerInterval = setInterval(() => {
  190. seconds--;
  191. if (seconds <= 0) {
  192. clearInterval(this.timerInterval);
  193. if (!this.showResult) {
  194. this.checkAnswer();
  195. setTimeout(() => {
  196. if (this.currentQuestionIndex < this.questions.length - 1) {
  197. this.goToNextQuestion();
  198. } else {
  199. common_vendor.index.navigateTo({
  200. url: "/pages/interview-question/interview-question"
  201. });
  202. }
  203. }, 1500);
  204. }
  205. }
  206. const min = Math.floor(seconds / 60).toString().padStart(2, "0");
  207. const sec = (seconds % 60).toString().padStart(2, "0");
  208. this.remainingTime = `${min}:${sec}`;
  209. }, 1e3);
  210. },
  211. resetTimer() {
  212. clearInterval(this.timerInterval);
  213. },
  214. selectOption(index) {
  215. if (this.currentQuestionIndex === this.questions.length - 1 && this.showContinueButton) {
  216. common_vendor.index.showToast({
  217. title: "该题目已完成,请继续下一部分",
  218. icon: "none",
  219. duration: 2e3
  220. });
  221. return;
  222. }
  223. if (this.showResult)
  224. return;
  225. console.log("selectOption", index);
  226. if (this.currentQuestion.questionType === 2) {
  227. const optionIndex = this.selectedOptions.indexOf(index);
  228. if (optionIndex > -1) {
  229. this.selectedOptions.splice(optionIndex, 1);
  230. } else {
  231. this.selectedOptions.push(index);
  232. }
  233. } else if (this.currentQuestion.questionType === 1 || this.currentQuestion.questionType === 3 || this.currentQuestion.questionType === 4) {
  234. this.selectedOption = index;
  235. this.playAiSpeaking();
  236. setTimeout(() => {
  237. this.checkAnswer();
  238. this.saveAnswer();
  239. this.submitCurrentAnswer().then(() => {
  240. setTimeout(() => {
  241. this.goToNextQuestion();
  242. }, 800);
  243. }).catch((error) => {
  244. console.error("提交答案失败:", error);
  245. setTimeout(() => {
  246. this.goToNextQuestion();
  247. }, 1e3);
  248. });
  249. }, 500);
  250. } else {
  251. this.selectedOption = index;
  252. const answer = {
  253. questionId: this.currentQuestion.id,
  254. questionType: this.currentQuestion.questionType,
  255. answer: index
  256. };
  257. const existingIndex = this.answers.findIndex((a) => a.questionId === answer.questionId);
  258. if (existingIndex > -1) {
  259. this.answers[existingIndex] = answer;
  260. } else {
  261. this.answers.push(answer);
  262. }
  263. this.playAiSpeaking();
  264. setTimeout(() => {
  265. this.checkAnswer();
  266. this.saveAnswer();
  267. this.submitCurrentAnswer().then(() => {
  268. setTimeout(() => {
  269. this.goToNextQuestion();
  270. }, 800);
  271. }).catch((error) => {
  272. console.error("提交答案失败:", error);
  273. setTimeout(() => {
  274. this.goToNextQuestion();
  275. }, 1e3);
  276. });
  277. }, 500);
  278. }
  279. },
  280. checkAnswer() {
  281. if (this.showResult)
  282. return;
  283. clearInterval(this.timerInterval);
  284. if (!this.currentQuestion) {
  285. console.error("当前问题不存在");
  286. return;
  287. }
  288. if (this.currentQuestion.questionType === 0) {
  289. this.isAnswerCorrect = true;
  290. } else if (this.currentQuestion.questionType === 2) {
  291. const sortedSelected = [...this.selectedOptions].sort();
  292. const sortedCorrect = [...this.currentQuestion.correctAnswers].sort();
  293. if (sortedSelected.length !== sortedCorrect.length) {
  294. this.isAnswerCorrect = false;
  295. } else {
  296. this.isAnswerCorrect = sortedSelected.every((value, index) => value === sortedCorrect[index]);
  297. }
  298. } else {
  299. this.isAnswerCorrect = this.selectedOption === this.currentQuestion.correctAnswer;
  300. }
  301. this.showResult = true;
  302. this.saveAnswer();
  303. if (this.currentQuestionIndex === this.questions.length - 1) {
  304. this.$nextTick(() => {
  305. this.$forceUpdate();
  306. });
  307. }
  308. },
  309. // 修改 nextQuestion 方法,只处理多选题
  310. nextQuestion() {
  311. if (this.currentQuestion.questionType !== 2)
  312. return;
  313. this.checkAnswer();
  314. this.saveAnswer();
  315. this.submitCurrentAnswer().then(() => {
  316. setTimeout(() => {
  317. if (this.currentQuestionIndex >= this.questions.length - 1) {
  318. if (this.currentGroupIndex < this.questionGroups.length - 1) {
  319. this.showContinueButton = true;
  320. setTimeout(() => {
  321. this.scrollTop = 0;
  322. this.$nextTick(() => {
  323. setTimeout(() => {
  324. this.scrollTop = 1e4;
  325. }, 100);
  326. });
  327. }, 200);
  328. } else {
  329. common_vendor.index.navigateTo({
  330. url: "/pages/interview-question/interview-question"
  331. });
  332. }
  333. } else {
  334. this.goToNextQuestion();
  335. }
  336. }, 500);
  337. }).catch((error) => {
  338. console.error("提交答案失败:", error);
  339. setTimeout(() => {
  340. if (this.currentQuestionIndex >= this.questions.length - 1) {
  341. if (this.currentGroupIndex < this.questionGroups.length - 1) {
  342. this.showContinueButton = true;
  343. setTimeout(() => {
  344. this.scrollTop = 1e4;
  345. }, 200);
  346. } else {
  347. common_vendor.index.navigateTo({
  348. url: "/pages/interview-question/interview-question"
  349. });
  350. }
  351. } else {
  352. this.goToNextQuestion();
  353. }
  354. }, 1e3);
  355. });
  356. },
  357. toggleSettings() {
  358. common_vendor.index.showToast({
  359. title: "设置功能开发中",
  360. icon: "none"
  361. });
  362. },
  363. back(target) {
  364. if (this.timerInterval) {
  365. clearInterval(this.timerInterval);
  366. }
  367. if (target) {
  368. common_vendor.index.navigateTo({
  369. url: target
  370. });
  371. return;
  372. }
  373. },
  374. error(e) {
  375. console.error(e.detail);
  376. common_vendor.index.showToast({
  377. title: "相机启动失败,请检查权限设置",
  378. icon: "none"
  379. });
  380. },
  381. playAiSpeaking() {
  382. if (this.useVideo && this.aiVideoContext) {
  383. this.aiVideoContext.play();
  384. }
  385. if (this.digitalHumanUrl) {
  386. const speakText = this.currentQuestion ? this.currentQuestion.text : "";
  387. this.interactWithDigitalHuman(speakText);
  388. }
  389. },
  390. pauseAiSpeaking() {
  391. if (this.useVideo && this.aiVideoContext) {
  392. this.aiVideoContext.pause();
  393. }
  394. },
  395. // 修改 restartTest 方法,添加可选的跳转目标
  396. restartTest(target) {
  397. this.currentQuestionIndex = 0;
  398. this.score = 0;
  399. this.showEndModal = false;
  400. this.showResult = false;
  401. this.selectedOption = null;
  402. this.selectedOptions = [];
  403. this.resetTimer();
  404. if (target) {
  405. common_vendor.index.navigateTo({
  406. url: target
  407. });
  408. }
  409. },
  410. // 在methods中添加测试方法
  411. testEndScreen() {
  412. this.interviewCompleted = true;
  413. this.showEndModal = false;
  414. },
  415. // 初始化数字人
  416. initDigitalHuman() {
  417. this.digitalHumanUrl = "";
  418. },
  419. // 与数字人交互的方法
  420. interactWithDigitalHuman(message) {
  421. const webview = this.$mp.page.$getAppWebview().children()[0];
  422. if (webview) {
  423. webview.evalJS(`receiveMessage('${message}')`);
  424. }
  425. },
  426. // 添加 navigateToInterview 方法
  427. navigateToInterview() {
  428. this.showEndModal = false;
  429. common_vendor.index.navigateTo({
  430. url: "/pages/interview/interview",
  431. success: () => {
  432. console.log("成功跳转到interview页面");
  433. },
  434. fail: (err) => {
  435. console.error("跳转失败:", err);
  436. common_vendor.index.showToast({
  437. title: "跳转失败,请手动返回首页",
  438. icon: "none"
  439. });
  440. }
  441. });
  442. },
  443. // 添加 handleCameraError 方法
  444. handleCameraError(e) {
  445. console.error("相机错误:", e.detail);
  446. common_vendor.index.showToast({
  447. title: "相机启动失败,请检查权限设置",
  448. icon: "none"
  449. });
  450. },
  451. // 修改 isOptionSelected 方法
  452. isOptionSelected(question, qIndex, optionIndex) {
  453. const answer = this.answers.find((a) => a.questionId === question.id);
  454. if (qIndex === this.currentQuestionIndex) {
  455. if (question.questionType === 1 || question.questionType === 3 || question.questionType === 4) {
  456. return this.selectedOption === optionIndex;
  457. } else if (question.questionType === 2) {
  458. return this.selectedOptions.includes(optionIndex);
  459. }
  460. } else if (answer) {
  461. if (question.questionType === 1 || question.questionType === 3 || question.questionType === 4) {
  462. return answer.answer === optionIndex;
  463. } else if (question.questionType === 2 && Array.isArray(answer.answer)) {
  464. return answer.answer.includes(optionIndex);
  465. }
  466. }
  467. return false;
  468. },
  469. // 修改 handleOptionClick 方法
  470. handleOptionClick(qIndex, index) {
  471. if (qIndex < this.currentQuestionIndex) {
  472. common_vendor.index.showToast({
  473. title: "该题目已完成,无法修改",
  474. icon: "none",
  475. duration: 2e3
  476. });
  477. return;
  478. }
  479. if (qIndex === this.questions.length - 1 && this.showContinueButton) {
  480. common_vendor.index.showToast({
  481. title: "该题目已完成,请继续下一部分",
  482. icon: "none",
  483. duration: 2e3
  484. });
  485. return;
  486. }
  487. if (qIndex > this.currentQuestionIndex) {
  488. const firstUnansweredIndex = this.currentQuestionIndex;
  489. common_vendor.index.showToast({
  490. title: `请先完成第 ${firstUnansweredIndex + 1} 题`,
  491. icon: "none",
  492. duration: 2e3
  493. });
  494. this.currentScrollId = "question-" + firstUnansweredIndex;
  495. return;
  496. }
  497. if (this._isClicking) {
  498. return;
  499. }
  500. this._isClicking = true;
  501. if (this._clickTimer) {
  502. clearTimeout(this._clickTimer);
  503. }
  504. try {
  505. this.selectOption(index);
  506. this._clickTimer = setTimeout(() => {
  507. this._isClicking = false;
  508. }, 1e3);
  509. } catch (error) {
  510. console.error("处理选项点击失败:", error);
  511. common_vendor.index.showToast({
  512. title: "操作失败,请重试",
  513. icon: "none"
  514. });
  515. this._isClicking = false;
  516. }
  517. },
  518. // 处理题目分组
  519. processQuestionGroups(questions) {
  520. const group1 = [];
  521. const group2 = [];
  522. questions.forEach((q) => {
  523. if (q.category === 5) {
  524. group1.push(q);
  525. } else {
  526. group2.push(q);
  527. }
  528. });
  529. this.questionGroups = [group2, group1].filter((group) => group.length > 0);
  530. this.questions = this.questionGroups[0] || [];
  531. },
  532. // 处理继续按钮点击
  533. handleContinue() {
  534. if (this.currentGroupIndex < this.questionGroups.length - 1) {
  535. this.currentGroupIndex++;
  536. this.questions = this.questionGroups[this.currentGroupIndex];
  537. this.currentQuestionIndex = 0;
  538. this.showContinueButton = false;
  539. this.currentScrollId = "question-0";
  540. this.scrollTop = 0;
  541. this.selectedOption = null;
  542. this.selectedOptions = [];
  543. this.showResult = false;
  544. } else {
  545. common_vendor.index.navigateTo({
  546. url: "/pages/interview-question/interview-question"
  547. });
  548. }
  549. },
  550. // 保存当前题目的答案
  551. saveAnswer() {
  552. let answer;
  553. if (this.currentQuestion.questionType === 0) {
  554. answer = {
  555. questionId: this.currentQuestion.id,
  556. questionType: this.currentQuestion.questionType,
  557. answer: this.openQuestionAnswer,
  558. answerDuration: this.getAnswerDuration()
  559. // 添加答题时长
  560. };
  561. } else if (this.currentQuestion.questionType === 1 || this.currentQuestion.questionType === 3 || this.currentQuestion.questionType === 4) {
  562. answer = {
  563. questionId: this.currentQuestion.id,
  564. questionType: this.currentQuestion.questionType,
  565. answer: this.selectedOption,
  566. answerDuration: this.getAnswerDuration()
  567. // 添加答题时长
  568. };
  569. } else {
  570. answer = {
  571. questionId: this.currentQuestion.id,
  572. questionType: this.currentQuestion.questionType,
  573. answer: this.selectedOptions,
  574. answerDuration: this.getAnswerDuration()
  575. // 添加答题时长
  576. };
  577. }
  578. const existingIndex = this.answers.findIndex((a) => a.questionId === answer.questionId);
  579. if (existingIndex > -1) {
  580. this.answers[existingIndex] = answer;
  581. } else {
  582. this.answers.push(answer);
  583. }
  584. this.currentAnswer = answer;
  585. console.log("已保存答案:", this.answers);
  586. },
  587. // 获取答题时长(秒)
  588. getAnswerDuration() {
  589. const remainingTimeArr = this.remainingTime.split(":");
  590. const remainingSeconds = parseInt(remainingTimeArr[0]) * 60 + parseInt(remainingTimeArr[1]);
  591. return 30 - remainingSeconds;
  592. },
  593. // 提交当前答案
  594. async submitCurrentAnswer() {
  595. if (!this.currentAnswer || this.isSubmitting)
  596. return;
  597. try {
  598. this.isSubmitting = true;
  599. common_vendor.index.showLoading({
  600. title: "正在提交答案..."
  601. });
  602. let answerContent = "";
  603. let answerOptions = [];
  604. if (this.currentAnswer.questionType === 0) {
  605. answerContent = this.currentAnswer.answer;
  606. answerOptions = [];
  607. } else if (this.currentAnswer.questionType === 1 || this.currentAnswer.questionType === 3 || this.currentAnswer.questionType === 4) {
  608. const selectedIndex = this.currentAnswer.answer;
  609. const selectedOption = this.currentQuestion.options[selectedIndex];
  610. console.log("selectedOption", selectedOption);
  611. const optionId = selectedOption.id ? selectedOption.id : selectedIndex;
  612. answerContent = optionId.toString();
  613. answerOptions = [optionId];
  614. } else if (this.currentAnswer.questionType === 2) {
  615. const selectedIndices = this.currentAnswer.answer;
  616. const selectedOptionIds = selectedIndices.map((index) => {
  617. const option = this.currentQuestion.options[index];
  618. return option.id ? option.id : index;
  619. });
  620. answerOptions = selectedOptionIds;
  621. }
  622. const submitData = {
  623. position_id: JSON.parse(common_vendor.index.getStorageSync("selectedJob")).id,
  624. applicant_id: JSON.parse(common_vendor.index.getStorageSync("userInfo")).id,
  625. job_position_question_id: this.currentAnswer.questionId,
  626. // answer_content: answerContent,
  627. answer_options: answerOptions,
  628. answer_duration: this.currentAnswer.answerDuration || 0,
  629. tenant_id: JSON.parse(common_vendor.index.getStorageSync("userInfo")).tenant_id || 1
  630. };
  631. console.log("提交数据:", submitData);
  632. const res2 = await this.$http.post(`${common_config.apiBaseUrl}/api/job/submit_answer`, submitData);
  633. console.log("提交答案响应:", res2);
  634. return res2;
  635. } catch (error) {
  636. console.error("提交答案失败:", error);
  637. common_vendor.index.showToast({
  638. title: "提交答案失败,请重试",
  639. icon: "none"
  640. });
  641. throw error;
  642. } finally {
  643. common_vendor.index.hideLoading();
  644. this.isSubmitting = false;
  645. }
  646. },
  647. // 修改 goToNextQuestion 方法
  648. async goToNextQuestion() {
  649. if (this.currentQuestionIndex >= this.questions.length - 1) {
  650. this.showContinueButton = true;
  651. setTimeout(() => {
  652. this.scrollTop = 0;
  653. this.$nextTick(() => {
  654. setTimeout(() => {
  655. this.scrollTop = 1e4;
  656. }, 100);
  657. });
  658. }, 200);
  659. return;
  660. }
  661. this.currentQuestionIndex++;
  662. this.currentScrollId = "question-" + this.currentQuestionIndex;
  663. this.showResult = false;
  664. this.selectedOption = null;
  665. this.selectedOptions = [];
  666. this.openQuestionAnswer = "";
  667. if (this.questions[this.currentQuestionIndex]) {
  668. this.progressWidth = (this.currentQuestionIndex + 1) / this.questions.length * 100;
  669. this.resetTimer();
  670. this.playAiSpeaking();
  671. setTimeout(() => {
  672. this.pauseAiSpeaking();
  673. }, 2e3);
  674. }
  675. }
  676. },
  677. // 添加生命周期钩子,确保在组件销毁时清除计时器
  678. beforeDestroy() {
  679. if (this.timerInterval) {
  680. clearInterval(this.timerInterval);
  681. }
  682. }
  683. };
  684. if (!Array) {
  685. const _component_uni_load_more = common_vendor.resolveComponent("uni-load-more");
  686. _component_uni_load_more();
  687. }
  688. function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  689. return common_vendor.e({
  690. a: !$data.digitalHumanUrl
  691. }, !$data.digitalHumanUrl ? {
  692. b: $data.mode,
  693. c: common_vendor.o((...args) => $options.handleCameraError && $options.handleCameraError(...args))
  694. } : $data.digitalHumanUrl ? {
  695. e: $data.digitalHumanUrl
  696. } : {
  697. f: common_assets._imports_0$1
  698. }, {
  699. d: $data.digitalHumanUrl,
  700. g: common_vendor.f($data.questions, (question, qIndex, i0) => {
  701. return common_vendor.e({
  702. a: common_vendor.t(qIndex + 1),
  703. b: common_vendor.t(question.questionTypeName),
  704. c: common_vendor.t(question.text),
  705. d: question.is_required_correct
  706. }, question.is_required_correct ? {} : {}, {
  707. e: question.questionType === 3 && question.imageUrl
  708. }, question.questionType === 3 && question.imageUrl ? {
  709. f: question.imageUrl
  710. } : {}, {
  711. g: question.questionType !== 0
  712. }, question.questionType !== 0 ? {
  713. h: common_vendor.f(question.options, (option, index, i1) => {
  714. return {
  715. a: common_vendor.t(option.option_text || (typeof option === "string" ? option : JSON.stringify(option))),
  716. b: index,
  717. c: $options.isOptionSelected(question, qIndex, index) ? 1 : "",
  718. d: common_vendor.o(($event) => $options.handleOptionClick(qIndex, index), index)
  719. };
  720. }),
  721. i: qIndex !== $data.currentQuestionIndex ? 1 : ""
  722. } : {}, {
  723. j: qIndex === $data.currentQuestionIndex && question.questionType === 2
  724. }, qIndex === $data.currentQuestionIndex && question.questionType === 2 ? {
  725. k: common_vendor.t("提交答案"),
  726. l: common_vendor.o(($event) => $options.nextQuestion(), question.id),
  727. m: $data.selectedOptions.length === 0
  728. } : {}, {
  729. n: question.id,
  730. o: "question-" + qIndex
  731. });
  732. }),
  733. h: common_vendor.t($data.questions.length),
  734. i: $data.showContinueButton
  735. }, $data.showContinueButton ? {
  736. j: common_vendor.t($data.currentGroupIndex < $data.questionGroups.length - 1 ? "继续下一部分" : "完成测试"),
  737. k: common_vendor.o((...args) => $options.handleContinue && $options.handleContinue(...args))
  738. } : {}, {
  739. l: $data.currentScrollId,
  740. m: $data.scrollTop,
  741. n: $data.showEndModal
  742. }, $data.showEndModal ? {
  743. o: common_vendor.o((...args) => $options.navigateToInterview && $options.navigateToInterview(...args))
  744. } : {}, {
  745. p: $data.interviewCompleted
  746. }, $data.interviewCompleted ? {
  747. q: common_assets._imports_0$1,
  748. r: common_vendor.o((...args) => $options.back && $options.back(...args))
  749. } : {}, {
  750. s: $data.loading
  751. }, $data.loading ? {
  752. t: common_vendor.p({
  753. status: "loading",
  754. contentText: {
  755. contentdown: "加载中..."
  756. }
  757. })
  758. } : {}, {
  759. v: !$data.loading && $data.loadError
  760. }, !$data.loading && $data.loadError ? {
  761. w: common_vendor.o((...args) => $options.fetchInterviewData && $options.fetchInterviewData(...args))
  762. } : {});
  763. }
  764. const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
  765. wx.createPage(MiniProgramPage);