index.tsx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. import styles from "./index.module.less";
  2. import { Snackbar } from "@varlet/ui";
  3. import { closeToast, showLoadingToast, showToast, Popup } from "vant";
  4. import { defineComponent, onMounted, onUnmounted, reactive, ref, watch } from "vue";
  5. import { getLeveByScore, getLeveByScoreMeasure, IEvaluatings } from "./evaluatResult";
  6. import {
  7. cancelEvaluating,
  8. endEvaluating,
  9. endSoundCheck,
  10. getEarphone,
  11. api_proxyServiceMessage,
  12. removeResult,
  13. sendResult,
  14. startEvaluating,
  15. startSoundCheck,
  16. api_openWebView,
  17. api_startRecording,
  18. api_stopRecording,
  19. api_recordStartTime,
  20. api_remove_recordStartTime,
  21. api_startCapture,
  22. api_endCapture,
  23. api_getDeviceDelay,
  24. hideComplexButton,
  25. api_checkSocketStatus,
  26. addAccompanyError,
  27. removeAccompanyError,
  28. addSocketStatus,
  29. removeSocketStatus,
  30. api_disconnectSocket,
  31. } from "/src/helpers/communication";
  32. import state, {
  33. IPlayState,
  34. clearSelection,
  35. handleStopPlay,
  36. onPlay,
  37. resetPlaybackToStart,
  38. togglePlay,
  39. } from "/src/state";
  40. import { IPostMessage } from "/src/utils/native-message";
  41. import { usePageVisibility } from "@vant/use";
  42. import { browser } from "/src/utils";
  43. import { getAudioCurrentTime, toggleMutePlayAudio } from "../audio-list";
  44. import { handleStartTick, tickData } from "../tick";
  45. import AbnormalPop from "../abnormal-pop";
  46. import { storeData } from "../../store";
  47. import icon_bg from '../abnormal-pop/icon_bg.svg'
  48. import icon_close from '../abnormal-pop/icon_close.svg'
  49. import icon_btn from '../abnormal-pop/icon_btn.svg'
  50. import icon_success from '../abnormal-pop/icon_success.svg'
  51. const browserInfo = browser();
  52. let socketStartTime = 0
  53. export const popImgs = {
  54. icon_bg,
  55. icon_close,
  56. icon_btn,
  57. icon_success
  58. }
  59. export const evaluatingData = reactive({
  60. /** 评测数据 */
  61. contentData: {} as any,
  62. /** 评测模块是否加载完成 */
  63. rendered: false,
  64. earphone: false, // 是否插入耳机
  65. soundEffect: false, // 是否效音
  66. soundEffectFrequency: 0, // 效音频率
  67. checkStep: 0, // 执行步骤
  68. checkEnd: false, // 检测结束
  69. earphoneMode: false, // 耳机弹窗
  70. soundEffectMode: false, // 效音弹窗
  71. websocketState: false, // websocket连接状态
  72. /**是否开始播放 */
  73. startBegin: false, // 开始
  74. backtime: 0, // 延迟时间
  75. /** 已经评测的数据 */
  76. evaluatings: {} as IEvaluatings,
  77. /** 评测结果 */
  78. resultData: {} as any,
  79. /** 评测结果弹窗 */
  80. resulstMode: false,
  81. /** 是否是完整评测 */
  82. isComplete: false,
  83. /** */
  84. isDisabledPlayMusic: false,
  85. /** socket异常状态弹窗 */
  86. socketErrorPop: false,
  87. /** 异常提示 */
  88. errorContents: '',
  89. /** socket异常状态弹窗的状态值 */
  90. socketErrorStatus: 0,
  91. /** 延迟检测,socket状态异常 */
  92. delayCheckSocketError: false,
  93. /** 异常状态,不生成评测记录,不调用保存接口 */
  94. isErrorState: false,
  95. /** accompanyError,错误类型 */
  96. accompanyErrorType: '',
  97. /** app播放结束状态,重新评测需要重置为 */
  98. isAudioPlayEnd: false,
  99. });
  100. /** 点击开始评测按钮 */
  101. export const handleStartEvaluat = async () => {
  102. if (state.modeType === "evaluating") {
  103. handleCancelEvaluat();
  104. } else {
  105. if (state.platform !== 'PC') {
  106. // 评测前先检查APP端的websocket状态
  107. const res = await api_checkSocketStatus();
  108. if (res?.content?.status === "connected") {
  109. handleStopPlay();
  110. } else {
  111. // socket未连接
  112. // evaluatingData.socketErrorPop = true
  113. }
  114. } else {
  115. handleStopPlay();
  116. }
  117. }
  118. state.modeType = state.modeType === "evaluating" ? "practise" : "evaluating";
  119. if (state.modeType !== "evaluating") {
  120. // 切换到练习模式,卸载评测模块
  121. evaluatingData.rendered = false;
  122. }
  123. };
  124. /** 开始评测 & 延迟检测开始按钮 */
  125. export const startCheckDelay = async () => {
  126. // 评测前先检查APP端的websocket状态
  127. const res = await api_checkSocketStatus();
  128. if (res?.content?.status === "connected") {
  129. //
  130. return new Promise((resolve) => {
  131. resolve({checked: true})
  132. });
  133. } else {
  134. /**
  135. * socket未连接,记录此时的时间,以便于和收到socket成功链接,进行对比,对比时间小于500ms时,则连接中的状态默认显示500ms持续时间
  136. *
  137. * */
  138. socketStartTime = +new Date()
  139. evaluatingData.socketErrorPop = true
  140. evaluatingData.socketErrorStatus = 1
  141. return new Promise((resolve) => {
  142. resolve({checked: false})
  143. });
  144. }
  145. }
  146. const check_currentTime = () => {
  147. let preTime = 0;
  148. // 选段评测模式
  149. if (state.isSelectMeasureMode) {
  150. preTime = state.section[0].time * 1000;
  151. }
  152. const currentTime = getAudioCurrentTime() * 1000 - preTime;
  153. // console.log('播放进度music', currentTime, 'preTime:' + preTime)
  154. if (currentTime >= 500) {
  155. sendEvaluatingOffsetTime(500);
  156. return;
  157. }
  158. setTimeout(() => {
  159. check_currentTime();
  160. }, 10);
  161. };
  162. /** 开始播放发送延迟时间 */
  163. export const sendEvaluatingOffsetTime = async (currentTime: number) => {
  164. // 没有开始时间点, 不处理
  165. if (!evaluatingData.backtime) return;
  166. const nowTime = Date.now();
  167. const delayTime = nowTime - evaluatingData.backtime - currentTime;
  168. console.error("真正播放延迟", delayTime, "currentTime:", currentTime);
  169. await api_proxyServiceMessage({
  170. header: {
  171. commond: "audioPlayStart",
  172. type: "SOUND_COMPARE",
  173. },
  174. body: {
  175. offsetTime: delayTime < 0 ? 0 : delayTime,
  176. micDelay: 0,
  177. },
  178. });
  179. };
  180. /** 检测耳机 */
  181. export const checkUseEarphone = async () => {
  182. const res = await getEarphone();
  183. return res?.content?.checkIsWired || false;
  184. };
  185. /**
  186. * 开始录音
  187. */
  188. const handleStartSoundCheck = () => {
  189. startSoundCheck();
  190. };
  191. /** 结束录音 */
  192. export const handleEndSoundCheck = () => {
  193. endSoundCheck();
  194. };
  195. /** 连接websocket */
  196. export const connectWebsocket = async (content: any) => {
  197. evaluatingData.contentData = content;
  198. evaluatingData.websocketState = true;
  199. };
  200. /**
  201. * 执行检测
  202. */
  203. export const handlePerformDetection = async () => {
  204. // 检测完成不检测了
  205. if (evaluatingData.checkEnd) return;
  206. // 延迟检测
  207. if (evaluatingData.checkStep === 0) {
  208. evaluatingData.checkStep = 5;
  209. // 没有设备延迟数据 或 开启了效音 显示检测组件,并持续检测耳机状态
  210. if (state.setting.soundEffect) {
  211. evaluatingData.soundEffectMode = true;
  212. return;
  213. }
  214. const delayTime = await api_getDeviceDelay();
  215. console.log("🚀 ~ delayTime:", delayTime);
  216. if (!delayTime) {
  217. evaluatingData.soundEffectMode = true;
  218. return;
  219. }
  220. handlePerformDetection();
  221. return;
  222. }
  223. // 检测耳机
  224. if ((evaluatingData.checkStep = 5)) {
  225. evaluatingData.checkStep = 10;
  226. const erji = await checkUseEarphone();
  227. if (!erji) {
  228. evaluatingData.earphoneMode = true;
  229. return;
  230. }
  231. handlePerformDetection();
  232. return;
  233. }
  234. // 效音
  235. // if (evaluatingData.checkStep === 7) {
  236. // // 是否需要开启效音
  237. // evaluatingData.checkStep = 10;
  238. // if (state.setting.soundEffect && !state.isPercussion) {
  239. // evaluatingData.soundEffectMode = true;
  240. // handleStartSoundCheck();
  241. // return
  242. // }
  243. // handlePerformDetection();
  244. // return;
  245. // }
  246. // 效验完成
  247. if (evaluatingData.checkStep === 10) {
  248. evaluatingData.checkEnd = true;
  249. }
  250. };
  251. /** 记录小节分数 */
  252. export const addMeasureScore = (measureScore: any, show = true) => {
  253. // #8720 bug修复
  254. for(let idx in evaluatingData.evaluatings) {
  255. evaluatingData.evaluatings[idx].show = false
  256. }
  257. evaluatingData.evaluatings[measureScore.measureRenderIndex] = {
  258. ...measureScore,
  259. leve: getLeveByScoreMeasure(measureScore.score),
  260. show,
  261. };
  262. // console.log("🚀 ~ measureScore:", evaluatingData.evaluatings)
  263. };
  264. const handleScoreResult = (res?: IPostMessage) => {
  265. console.log('返回', res)
  266. if (res?.content) {
  267. const { header, body } = res.content;
  268. // 效音返回
  269. if (header.commond === "checking") {
  270. evaluatingData.soundEffectFrequency = body.frequency;
  271. }
  272. // 小节评分返回
  273. if (header?.commond === "measureScore") {
  274. console.log("🚀 ~ 评测返回:", res);
  275. addMeasureScore(body);
  276. }
  277. // 评测结束返回
  278. if (header?.commond === "overall") {
  279. console.log("🚀 ~ 评测返回:", res);
  280. // console.log("评测结束", body);
  281. state.isHideEvaluatReportSaveBtn = false;
  282. setTimeout(() => {
  283. evaluatingData.resulstMode = evaluatingData.isErrorState ? false : true
  284. }, 200);
  285. evaluatingData.resultData = {
  286. ...body,
  287. ...getLeveByScore(body.score),
  288. };
  289. // console.log("🚀 ~ evaluatingData.resultData:", evaluatingData.resultData)
  290. closeToast();
  291. }
  292. }
  293. };
  294. /** 开始评测 */
  295. export const handleStartBegin = async (preTimes?: number) => {
  296. evaluatingData.isComplete = false;
  297. evaluatingData.evaluatings = {};
  298. evaluatingData.resultData = {};
  299. evaluatingData.backtime = 0;
  300. resetPlaybackToStart();
  301. evaluatingData.isAudioPlayEnd = false;
  302. const res = await startEvaluating(evaluatingData.contentData);
  303. if (res?.api !== "startEvaluating") {
  304. Snackbar.error("请在APP端进行评测");
  305. evaluatingData.startBegin = false;
  306. return;
  307. }
  308. if (res?.content?.reson) {
  309. showToast(res.content?.des);
  310. evaluatingData.startBegin = false;
  311. return;
  312. }
  313. evaluatingData.startBegin = true;
  314. if (evaluatingData.isDisabledPlayMusic) {
  315. state.playState = state.playState === "paused" ? "play" : "paused";
  316. // 设置为开始播放时, 如果需要节拍,先播放节拍器
  317. if (state.playState === "play" && state.needTick) {
  318. const tickend = await handleStartTick();
  319. console.log("🚀 ~ tickend:", tickend)
  320. // 节拍器返回false, 取消播放
  321. if (!tickend) {
  322. state.playState = "paused";
  323. evaluatingData.startBegin = false;
  324. return;
  325. }
  326. }
  327. onPlay();
  328. }
  329. if (evaluatingData.isErrorState) return
  330. //开始录音
  331. await api_startRecording({
  332. accompanimentState: state.setting.enableAccompaniment ? 1 : 0,
  333. firstNoteTime: preTimes || 0,
  334. });
  335. // 如果开启了摄像头, 开启录制视频
  336. if (state.setting.camera) {
  337. console.log("开始录制视频");
  338. api_startCapture();
  339. }
  340. };
  341. /** 播放音乐 */
  342. const playMusic = async () => {
  343. const playState = await togglePlay("play");
  344. // 取消播放,停止播放
  345. if (!playState) {
  346. evaluatingData.startBegin = false;
  347. handleCancelEvaluat();
  348. return;
  349. }
  350. // 检测播放进度, 计算延迟
  351. check_currentTime();
  352. // 如果开启了摄像头, 开启录制视频
  353. if (state.setting.camera) {
  354. console.log("开始录制视频");
  355. api_startCapture();
  356. }
  357. };
  358. let _audio: HTMLAudioElement;
  359. /** 录音开始,记录开始时间点 */
  360. const recordStartTimePoint = async (res?: IPostMessage) => {
  361. console.error("开始录音");
  362. // 没有开始评测,不处理
  363. if (!evaluatingData.startBegin) return;
  364. let inteveral = res?.content?.inteveral || 0;
  365. if (browserInfo.ios) {
  366. inteveral *= 1000;
  367. }
  368. evaluatingData.backtime = inteveral || Date.now();
  369. console.log(
  370. "🚀 ~ 开始时间点:",
  371. evaluatingData.backtime,
  372. "已经录的时间:",
  373. Date.now() - inteveral,
  374. "记录时间点:",
  375. Date.now()
  376. );
  377. // 是否禁播
  378. if (evaluatingData.isDisabledPlayMusic) {
  379. return;
  380. }
  381. // 开始播放
  382. playMusic();
  383. };
  384. /**
  385. * 结束评测
  386. * @param isComplete 是否完整评测
  387. * @returns
  388. */
  389. export const handleEndEvaluat = (isComplete = false) => {
  390. // 没有开始评测 , 不是评测模式 , 不评分
  391. if (!evaluatingData.startBegin || state.modeType !== "evaluating") return;
  392. // 结束录音
  393. // api_stopRecording();
  394. // 结束评测
  395. endEvaluating({
  396. musicScoreId: state.examSongId,
  397. });
  398. showLoadingToast({
  399. message: "评分中",
  400. duration: 0,
  401. overlay: true,
  402. overlayClass: styles.scoreMode,
  403. });
  404. setTimeout(() => {
  405. evaluatingData.startBegin = false;
  406. }, 500);
  407. evaluatingData.isComplete = isComplete;
  408. // 如果开启了摄像头, 结束录制视频
  409. if (state.setting.camera) {
  410. console.log("结束录制视频");
  411. api_endCapture();
  412. }
  413. };
  414. /**
  415. * 结束评测
  416. */
  417. export const handleEndBegin = () => {
  418. handleEndEvaluat();
  419. handleStopPlay();
  420. };
  421. /**
  422. * 取消评测
  423. */
  424. export const handleCancelEvaluat = () => {
  425. evaluatingData.evaluatings = {};
  426. evaluatingData.startBegin = false;
  427. // 关闭提示
  428. closeToast();
  429. // 取消记录
  430. api_proxyServiceMessage({
  431. header: {
  432. commond: "recordCancel",
  433. type: "SOUND_COMPARE",
  434. status: 200,
  435. },
  436. });
  437. // 取消评测
  438. cancelEvaluating();
  439. // 停止播放
  440. handleStopPlay();
  441. endEvaluating({
  442. musicScoreId: state.examSongId,
  443. });
  444. // 如果开启了摄像头, 结束录制视频
  445. if (state.setting.camera) {
  446. console.log("结束录制视频");
  447. api_endCapture();
  448. }
  449. };
  450. /** 查看报告 */
  451. export const handleViewReport = (
  452. key: "recordId" | "recordIdStr",
  453. type: "gym" | "colexiu" | "orchestra" | "instrument"
  454. ) => {
  455. const id = evaluatingData.resultData?.[key] || "";
  456. let url = "";
  457. switch (type) {
  458. case "gym":
  459. url = location.origin + location.pathname + "#/report/" + id;
  460. break;
  461. case "orchestra":
  462. url = location.origin + location.pathname + "report-share.html?id=" + id;
  463. break;
  464. case "instrument":
  465. url = location.origin + location.pathname + "#/evaluat-report?id=" + id + "&musicRenderType=" + state.musicRenderType;
  466. break;
  467. default:
  468. url = location.origin + location.pathname + "report-share.html?id=" + id;
  469. break;
  470. }
  471. api_openWebView({
  472. url,
  473. orientation: 0,
  474. isHideTitle: true, // 此处兼容安卓,意思为隐藏全部头部
  475. statusBarTextColor: false,
  476. isOpenLight: true,
  477. c_orientation: 0,
  478. });
  479. };
  480. // 隐藏存演奏按钮
  481. const handleComplexButton = (res?: IPostMessage) => {
  482. console.log('监听是否隐藏保存按钮', res)
  483. if (res?.content) {
  484. const { header, body } = res.content;
  485. state.isHideEvaluatReportSaveBtn = true
  486. }
  487. };
  488. // 检测到APP发送的异常信息
  489. const handleAccompanyError = (res?: IPostMessage) => {
  490. console.log('异常信息返回', res)
  491. if (res?.content) {
  492. const { type, reson } = res.content;
  493. switch (type) {
  494. case "enterBackground":
  495. // App退到后台
  496. case "playError":
  497. // 播放异常
  498. case "socketError":
  499. // socket连接断开,评测中,则取消评测
  500. // 延迟检测中
  501. if (evaluatingData.soundEffectMode) {
  502. evaluatingData.socketErrorStatus = 0
  503. evaluatingData.delayCheckSocketError = true
  504. evaluatingData.socketErrorPop = type === "socketError" ? true : false
  505. evaluatingData.accompanyErrorType = type
  506. // api_checkSocketStatus()
  507. return
  508. }
  509. // 评测中
  510. if (state.modeType === "evaluating" && evaluatingData.startBegin) {
  511. handleCancelEvaluat();
  512. }
  513. if (tickData.show) {
  514. tickData.tickEnd = true
  515. tickData.show = false
  516. }
  517. evaluatingData.socketErrorStatus = 0
  518. evaluatingData.socketErrorPop = type === "socketError" ? true : false
  519. evaluatingData.isErrorState = true
  520. evaluatingData.accompanyErrorType = type
  521. resetPlaybackToStart();
  522. break;
  523. case "recordError":
  524. // 录音异常
  525. break;
  526. default:
  527. break;
  528. }
  529. }
  530. };
  531. // 监测socket状态,是否已经成功连接
  532. const handleSocketStatus = (res?: IPostMessage) => {
  533. if (res?.content?.status === "connected") {
  534. const currentTime = +new Date()
  535. evaluatingData.delayCheckSocketError = false
  536. const diffTime = currentTime - socketStartTime
  537. if (diffTime < 1000) {
  538. const remainingTime = 1000 - diffTime
  539. console.log(remainingTime,99999)
  540. setTimeout(() => {
  541. evaluatingData.socketErrorStatus = 2
  542. }, remainingTime);
  543. }
  544. }
  545. }
  546. // 评测出现异常,再试一次
  547. const hanldeConfirmPop = async () => {
  548. api_checkSocketStatus();
  549. evaluatingData.socketErrorStatus = 1
  550. socketStartTime = +new Date()
  551. }
  552. // 关闭异常弹窗
  553. const hanldeClosePop = () => {
  554. evaluatingData.socketErrorPop = false
  555. evaluatingData.socketErrorStatus = 0
  556. }
  557. export default defineComponent({
  558. name: "evaluating",
  559. setup() {
  560. const pageVisibility = usePageVisibility();
  561. // 需要记录的数据
  562. const record_old_data = reactive({
  563. /** 指法 */
  564. finger: false,
  565. /** 原音伴奏 */
  566. play_mode: "" as IPlayState,
  567. /** 评测是否要伴奏 */
  568. enableAccompaniment: true,
  569. });
  570. /** 记录状态 */
  571. const hanlde_record = () => {
  572. // 取消指法
  573. record_old_data.finger = state.setting.displayFingering;
  574. state.setting.displayFingering = false;
  575. // 切换为伴奏
  576. record_old_data.play_mode = state.playSource;
  577. record_old_data.enableAccompaniment = state.setting.enableAccompaniment;
  578. // 如果关闭伴奏,评测静音
  579. if (!record_old_data.enableAccompaniment) {
  580. console.log("关闭伴奏");
  581. toggleMutePlayAudio(record_old_data.play_mode === "music" ? "music" : "background", true);
  582. }
  583. };
  584. /** 还原状态 */
  585. const handle_reduction = () => {
  586. // 还原指法
  587. state.setting.displayFingering = record_old_data.finger;
  588. state.playSource = record_old_data.play_mode;
  589. // 如果关闭伴奏, 结束评测取消静音
  590. if (!record_old_data.enableAccompaniment) {
  591. toggleMutePlayAudio(record_old_data.play_mode === "music" ? "music" : "background", false);
  592. }
  593. };
  594. watch(pageVisibility, (value) => {
  595. if (value == "hidden" && evaluatingData.startBegin) {
  596. // handleEndBegin();
  597. }
  598. });
  599. watch(
  600. () => evaluatingData.socketErrorStatus,
  601. () => {
  602. if (evaluatingData.socketErrorStatus === 2) {
  603. setTimeout(() => {
  604. evaluatingData.socketErrorPop = false
  605. // evaluatingData.socketErrorStatus = 0
  606. }, 1000);
  607. }
  608. }
  609. );
  610. onMounted(() => {
  611. resetPlaybackToStart();
  612. hanlde_record();
  613. evaluatingData.resultData = {};
  614. // evaluatingData.resulstMode = true;
  615. // evaluatingData.resultData = {...getLeveByScore(10), score: 10, intonation: 10, cadence: 30, integrity: 40}
  616. // console.log("🚀 ~ evaluatingData.resultData:", evaluatingData.resultData)
  617. evaluatingData.evaluatings = {};
  618. evaluatingData.soundEffectFrequency = 0;
  619. evaluatingData.checkStep = 0;
  620. evaluatingData.rendered = true;
  621. sendResult(handleScoreResult);
  622. hideComplexButton(handleComplexButton, true);
  623. api_recordStartTime(recordStartTimePoint);
  624. addAccompanyError(handleAccompanyError);
  625. addSocketStatus(handleSocketStatus);
  626. // 不是选段模式评测, 就清空已选段
  627. if (!state.isSelectMeasureMode) {
  628. clearSelection();
  629. }
  630. console.log("加载评测模块成功");
  631. });
  632. onUnmounted(() => {
  633. evaluatingData.checkEnd = false;
  634. evaluatingData.rendered = false;
  635. resetPlaybackToStart();
  636. removeResult(handleScoreResult);
  637. hideComplexButton(() => {}, false);
  638. api_remove_recordStartTime(recordStartTimePoint);
  639. handle_reduction();
  640. removeAccompanyError(handleAccompanyError);
  641. removeSocketStatus(handleSocketStatus);
  642. api_disconnectSocket();
  643. console.log("卸载评测模块成功");
  644. });
  645. return () => (
  646. <div>
  647. {/** 预加载一下断网需要用到的图片 */}
  648. <div class={styles.hiddenPop}>
  649. <img src={popImgs.icon_bg} />
  650. <img src={popImgs.icon_btn} />
  651. <img src={popImgs.icon_success} />
  652. <img src={popImgs.icon_close} />
  653. </div>
  654. <Popup teleport="body" closeOnClickOverlay={false} class={["popup-custom", "van-scale"]} transition="van-scale" v-model:show={evaluatingData.socketErrorPop}>
  655. <AbnormalPop
  656. onConfirm={hanldeConfirmPop}
  657. onClose={hanldeClosePop}
  658. />
  659. </Popup>
  660. </div>
  661. );
  662. },
  663. });