index.tsx 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456
  1. import { PropType, Teleport, defineComponent, nextTick, onMounted, onUnmounted, ref } from "vue";
  2. import { Config, DriveStep, PopoverDOM, State, driver } from "driver.js";
  3. import "driver.js/dist/driver.css";
  4. import state, { IPlatform } from "/src/state";
  5. import { getGuidance, setGuidance } from "../guide-page/api";
  6. const endGuide = (guideInfo: any) => {
  7. try {
  8. // setGuidance({ guideTag: "guideInfo", guideValue: JSON.stringify(guideInfo) });
  9. localStorage.setItem("guideInfo", JSON.stringify(guideInfo));
  10. } catch (e) {
  11. console.log(e);
  12. }
  13. };
  14. /**
  15. * 按钮状态
  16. */
  17. type ButtonStatus = {
  18. /** 是否显示播放按钮 */
  19. playBtnStatus?: Boolean;
  20. /** 声部状态 */
  21. subjectStatus?: Boolean;
  22. /** 是否显示模式切换 */
  23. modelTypeStatus?: Boolean;
  24. /** 播放模式 演唱 演奏 */
  25. playType?: Boolean;
  26. /** 返回和标题 */
  27. backTitle?: Boolean;
  28. /** 返回显示的标题类型 文本 TEXT 按钮 IMG */
  29. titleType?: String;
  30. /** 原声 true 范唱 false */
  31. originPlayType?: Boolean;
  32. /** 是否显示原音 */
  33. originBtnStatus?: Boolean;
  34. /** 是否显示切换曲谱列表 */
  35. showSwitchList?: Boolean;
  36. };
  37. /** 练习模式 */
  38. export const PractiseDriver = defineComponent({
  39. name: "PractiseDriver",
  40. props: {
  41. // 按钮状态
  42. statusAll: {
  43. type: Object as PropType<ButtonStatus>,
  44. default: () => {},
  45. },
  46. },
  47. setup(props) {
  48. const driverNextStatus = ref(false);
  49. // 初始化部分引导位置
  50. const driverInitialPosition = (popover: PopoverDOM, options: { config: Config; state: State }) => {
  51. options.config.stageRadius = 5;
  52. options.config.stagePadding = 4;
  53. try {
  54. const rect = options.state.activeElement?.getBoundingClientRect();
  55. popover.wrapper.style.marginLeft = -(rect?.width || 0) / 2 + 4 + "px";
  56. } catch {}
  57. };
  58. const driverOptions = (): Config => {
  59. let length = 10;
  60. if (!props.statusAll.playBtnStatus) {
  61. length -= 1;
  62. }
  63. if (!props.statusAll.originBtnStatus) {
  64. length -= 1;
  65. }
  66. // 显示指法
  67. // if (!state.setting.displayFingering) {
  68. // length -= 1;
  69. // }
  70. // 声部
  71. if (!props.statusAll.subjectStatus) {
  72. length -= 1;
  73. }
  74. if (!props.statusAll.playType) {
  75. length -= 1;
  76. }
  77. // pc端不显示标题和模式切换引导
  78. if (state.platform === IPlatform.PC) {
  79. // length -= 2;
  80. } else {
  81. // 判断是否有标题
  82. if (!props.statusAll.backTitle || props.statusAll.titleType === "NONE") {
  83. length -= 1;
  84. }
  85. // 练习模式
  86. if (!props.statusAll.modelTypeStatus) {
  87. length -= 1;
  88. }
  89. }
  90. console.log(props.statusAll, "statusAll", length, state.setting.displayFingering);
  91. let options: Config = {
  92. showProgress: false,
  93. allowClose: false,
  94. popoverOffset: 3,
  95. disableActiveInteraction: true,
  96. onCloseClick: () => {
  97. onDriverClose();
  98. },
  99. onHighlightStarted: () => {
  100. driverNextStatus.value = true;
  101. },
  102. onHighlighted: () => {
  103. driverNextStatus.value = false;
  104. },
  105. steps: [] as DriveStep[],
  106. };
  107. if (props.statusAll.playBtnStatus) {
  108. options.steps?.push({
  109. element: ".driver-1",
  110. popover: {
  111. title: "",
  112. description: "",
  113. popoverClass: "popoverClass popoverClass1",
  114. align: "end",
  115. side: "top",
  116. nextBtnText: `下一步 (1/${length})`,
  117. showButtons: ["next"],
  118. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  119. options.config.stageRadius = 1000;
  120. options.config.stagePadding = 0;
  121. },
  122. },
  123. });
  124. }
  125. if (props.statusAll.modelTypeStatus) {
  126. options.steps?.push({
  127. element: ".driver-9",
  128. popover: {
  129. title: "",
  130. description: "",
  131. popoverClass: "popoverClass popoverClass9",
  132. align: "end",
  133. side: "bottom",
  134. nextBtnText: `下一步 (2/${length})`,
  135. showButtons: ["next"],
  136. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  137. driverInitialPosition(popover, options);
  138. },
  139. },
  140. });
  141. }
  142. if (props.statusAll.playType) {
  143. options.steps?.push({
  144. element: ".driver-2",
  145. popover: {
  146. title: "",
  147. description: "",
  148. popoverClass: "popoverClass popoverClass2",
  149. align: "start",
  150. side: "top",
  151. nextBtnText: `下一步 (${options.steps.length + 1}/${length})`,
  152. showButtons: ["next"],
  153. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  154. driverInitialPosition(popover, options);
  155. },
  156. },
  157. });
  158. }
  159. if (props.statusAll.originBtnStatus) {
  160. options.steps?.push({
  161. element: ".driver-3",
  162. popover: {
  163. title: "",
  164. description: "",
  165. popoverClass: props.statusAll.originPlayType ? "popoverClass popoverClass3" : "popoverClass popoverClass11",
  166. align: "end",
  167. side: "bottom",
  168. nextBtnText: `下一步 (${options.steps.length + 1}/${length})`,
  169. showButtons: ["next"],
  170. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  171. driverInitialPosition(popover, options);
  172. },
  173. },
  174. });
  175. }
  176. options.steps?.push(
  177. {
  178. element: ".driver-4",
  179. popover: {
  180. title: "",
  181. description: "",
  182. popoverClass: "popoverClass popoverClass4",
  183. align: "end",
  184. side: "bottom",
  185. nextBtnText: `下一步 (${options.steps.length + 1}/${length})`,
  186. showButtons: ["next"],
  187. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  188. driverInitialPosition(popover, options);
  189. },
  190. },
  191. },
  192. {
  193. element: ".driver-5",
  194. popover: {
  195. title: "",
  196. description: "",
  197. popoverClass: "popoverClass popoverClass5",
  198. align: "end",
  199. side: "bottom",
  200. nextBtnText: `下一步 (${options.steps.length + 2}/${length})`,
  201. showButtons: ["next"],
  202. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  203. driverInitialPosition(popover, options);
  204. },
  205. },
  206. }
  207. );
  208. if (props.statusAll.subjectStatus) {
  209. options.steps?.push({
  210. element: ".driver-10",
  211. popover: {
  212. title: "",
  213. description: "",
  214. popoverClass: "popoverClass popoverClass10",
  215. align: "end",
  216. side: "bottom",
  217. nextBtnText: `下一步 (${options.steps.length + 1}/${length})`,
  218. showButtons: ["next"],
  219. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  220. driverInitialPosition(popover, options);
  221. },
  222. },
  223. });
  224. }
  225. options.steps?.push({
  226. element: ".driver-5-1",
  227. popover: {
  228. title: "",
  229. description: "",
  230. popoverClass: "popoverClass popoverClass5-1",
  231. align: "end",
  232. side: "bottom",
  233. nextBtnText: `下一步 (${options.steps.length + 1}/${length})`,
  234. showButtons: ["next"],
  235. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  236. driverInitialPosition(popover, options);
  237. },
  238. },
  239. });
  240. if (state.platform === IPlatform.PC) {
  241. options.steps?.push({
  242. element: ".driver-6",
  243. popover: {
  244. title: "",
  245. description: "",
  246. popoverClass: "popoverClass popoverClass6-end popoverClose",
  247. align: "end",
  248. side: "bottom",
  249. prevBtnText: "再看一遍",
  250. doneBtnText: "完成",
  251. showButtons: ["next", "previous"],
  252. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  253. driverInitialPosition(popover, options);
  254. const rect = options.state.activeElement?.getBoundingClientRect();
  255. popover.wrapper.style.marginLeft = (rect?.width || 0) / 2 + 4 + "px";
  256. },
  257. onPrevClick: () => {
  258. driverObj.drive(0);
  259. },
  260. onNextClick: () => {
  261. onDriverClose();
  262. },
  263. },
  264. });
  265. } else {
  266. // 判断设置之后是否还有引导
  267. if (!state.setting.displayFingering && !props.statusAll.backTitle && !props.statusAll.modelTypeStatus) {
  268. options.steps?.push({
  269. element: ".driver-6",
  270. popover: {
  271. title: "",
  272. description: "",
  273. popoverClass: "popoverClass popoverClass6 popoverClose",
  274. align: "start",
  275. side: "top",
  276. prevBtnText: "再看一遍",
  277. doneBtnText: "完成",
  278. showButtons: ["next", "previous"],
  279. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  280. driverInitialPosition(popover, options);
  281. },
  282. onPrevClick: () => {
  283. driverObj.drive(0);
  284. },
  285. onNextClick: () => {
  286. onDriverClose();
  287. },
  288. },
  289. });
  290. } else if (state.setting.displayFingering && !props.statusAll.backTitle && !props.statusAll.modelTypeStatus) {
  291. options.steps?.push({
  292. element: ".driver-6",
  293. popover: {
  294. title: "",
  295. description: "",
  296. popoverClass: "popoverClass popoverClass6",
  297. align: "end",
  298. side: "bottom",
  299. nextBtnText: `下一步 (${options.steps.length + 1}/${length})`, //"下一步6/" + length,
  300. showButtons: ["next"],
  301. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  302. driverInitialPosition(popover, options);
  303. },
  304. },
  305. });
  306. } else if (props.statusAll.backTitle && !props.statusAll.modelTypeStatus) {
  307. options.steps?.push({
  308. element: ".driver-6",
  309. popover: {
  310. title: "",
  311. description: "",
  312. popoverClass: "popoverClass popoverClass6",
  313. align: "end",
  314. side: "bottom",
  315. nextBtnText: `下一步 (${options.steps.length + 1}/${length})`, //"下一步6/" + length,
  316. showButtons: ["next"],
  317. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  318. driverInitialPosition(popover, options);
  319. },
  320. },
  321. });
  322. options.steps?.push({
  323. //props.statusAll.titleType === "TEXT" ? ".driver-8 .van-notice-bar__content" :
  324. element: ".driver-8",
  325. popover: {
  326. title: "",
  327. description: "",
  328. popoverClass: "popoverClass popoverClass8 popoverClose",
  329. align: "start",
  330. side: "bottom",
  331. prevBtnText: "再看一遍",
  332. doneBtnText: "完成",
  333. showButtons: ["next", "previous"],
  334. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  335. driverInitialPosition(popover, options);
  336. const rect = options.state.activeElement?.getBoundingClientRect();
  337. popover.wrapper.style.marginLeft = (rect?.width || 0) / 2 + "px";
  338. },
  339. onPrevClick: () => {
  340. driverObj.drive(0);
  341. },
  342. onNextClick: () => {
  343. onDriverClose();
  344. },
  345. },
  346. });
  347. } else if (!props.statusAll.showSwitchList) {
  348. options.steps?.push({
  349. element: ".driver-6",
  350. popover: {
  351. title: "",
  352. description: "",
  353. popoverClass: "popoverClass popoverClass6-end popoverClose",
  354. align: "end",
  355. side: "bottom",
  356. prevBtnText: "再看一遍",
  357. doneBtnText: "完成",
  358. showButtons: ["next", "previous"],
  359. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  360. driverInitialPosition(popover, options);
  361. // const rect = options.state.activeElement?.getBoundingClientRect();
  362. // popover.wrapper.style.marginLeft = -(rect?.width || 0) / 2 + 4 + "px";
  363. },
  364. onPrevClick: () => {
  365. driverObj.drive(0);
  366. },
  367. onNextClick: () => {
  368. onDriverClose();
  369. },
  370. },
  371. });
  372. } else {
  373. options.steps?.push({
  374. element: ".driver-6",
  375. popover: {
  376. title: "",
  377. description: "",
  378. popoverClass: "popoverClass popoverClass6",
  379. align: "end",
  380. side: "bottom",
  381. nextBtnText: `下一步 (${options.steps.length + 1}/${length})`, //"下一步6/" + length,
  382. showButtons: ["next"],
  383. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  384. driverInitialPosition(popover, options);
  385. },
  386. },
  387. });
  388. if (props.statusAll.backTitle) {
  389. options.steps?.push({
  390. // .van-notice-bar__content
  391. // element: ".driver-8 .van-notice-bar__content",
  392. // props.statusAll.titleType === "TEXT" ? ".driver-8 .van-notice-bar__content" :
  393. element: ".driver-8",
  394. popover: {
  395. title: "",
  396. description: "",
  397. popoverClass: "popoverClass popoverClass8 popoverClose",
  398. align: "start",
  399. side: "bottom",
  400. prevBtnText: "再看一遍",
  401. doneBtnText: "完成",
  402. showButtons: ["next", "previous"],
  403. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  404. driverInitialPosition(popover, options);
  405. const rect = options.state.activeElement?.getBoundingClientRect();
  406. popover.wrapper.style.marginLeft = (rect?.width || 0) / 2 + "px";
  407. },
  408. onPrevClick: () => {
  409. driverObj.drive(0);
  410. },
  411. onNextClick: () => {
  412. onDriverClose();
  413. },
  414. },
  415. });
  416. }
  417. }
  418. }
  419. return options;
  420. };
  421. let driverObj: any;
  422. const handleClickOutside = (event: any) => {
  423. // 如果高亮没有结束则下进行下一步
  424. if (driverNextStatus.value) return;
  425. if (driverObj.isActive() && (event.target.nodeName === "path" || event.target.classList.contains("driver-popover") || event.target.classList.contains("driver-overlay"))) {
  426. if (driverObj.isLastStep()) {
  427. onDriverClose();
  428. } else {
  429. driverObj.moveNext(); // 跳转到下一步
  430. }
  431. }
  432. };
  433. const guideInfo = ref({} as any);
  434. const showCloseBtn = ref(false);
  435. const getAllGuidance = async () => {
  436. try {
  437. // const res = await getGuidance({ guideTag: "guideInfo" });
  438. const res = localStorage.getItem("guideInfo");
  439. if (res) {
  440. guideInfo.value = JSON.parse(res) || null;
  441. } else {
  442. guideInfo.value = {};
  443. }
  444. if (!(guideInfo.value && guideInfo.value.practiseDriver)) {
  445. document.addEventListener("click", handleClickOutside, true);
  446. driverObj = driver(driverOptions());
  447. nextTick(() => {
  448. driverObj.drive();
  449. showCloseBtn.value = true;
  450. state.hasDriverPop = true;
  451. });
  452. }
  453. } catch (e) {
  454. console.log(e);
  455. }
  456. };
  457. getAllGuidance();
  458. // 结束关闭弹窗
  459. const onDriverClose = () => {
  460. if (!guideInfo.value) {
  461. guideInfo.value = { practiseDriver: true };
  462. } else {
  463. guideInfo.value.practiseDriver = true;
  464. }
  465. endGuide(guideInfo.value);
  466. driverObj.destroy();
  467. document.querySelector(".driver-popover-close-btn-custom")?.remove();
  468. document.removeEventListener("click", handleClickOutside, true);
  469. state.hasDriverPop = false;
  470. };
  471. onUnmounted(() => {
  472. document.removeEventListener("click", handleClickOutside, true);
  473. });
  474. return () => (
  475. <Teleport to="body">
  476. {showCloseBtn.value && (
  477. <div
  478. class="driver-popover-close-btn-custom"
  479. onClick={(e: any) => {
  480. onDriverClose();
  481. }}
  482. ></div>
  483. )}
  484. </Teleport>
  485. );
  486. },
  487. });
  488. /** 跟练模式 */
  489. export const FollowDriver = defineComponent({
  490. name: "FollowDriver",
  491. props: {
  492. // 按钮状态
  493. statusAll: {
  494. type: Object as PropType<ButtonStatus>,
  495. default: () => {},
  496. },
  497. },
  498. setup(props) {
  499. const driverNextStatus = ref(false);
  500. // 初始化部分引导位置
  501. const driverInitialPosition = (popover: PopoverDOM, options: { config: Config; state: State }) => {
  502. options.config.stageRadius = 5;
  503. options.config.stagePadding = 4;
  504. try {
  505. const rect = options.state.activeElement?.getBoundingClientRect();
  506. popover.wrapper.style.marginLeft = -(rect?.width || 0) / 2 + 4 + "px";
  507. } catch {}
  508. };
  509. // 声部
  510. let length = props.statusAll.subjectStatus ? 5 : 4;
  511. const driverOptions: Config = {
  512. showProgress: false,
  513. allowClose: false,
  514. popoverOffset: 3,
  515. disableActiveInteraction: true,
  516. onCloseClick: () => {
  517. onDriverClose();
  518. },
  519. onHighlightStarted: () => {
  520. driverNextStatus.value = true;
  521. },
  522. onHighlighted: () => {
  523. driverNextStatus.value = false;
  524. },
  525. steps: [
  526. {
  527. element: ".follow-1",
  528. popover: {
  529. title: "",
  530. description: "",
  531. popoverClass: "popoverClass popoverClassF1",
  532. align: "end",
  533. side: "top",
  534. nextBtnText: `下一步 (1/${length})`,
  535. showButtons: ["next"],
  536. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  537. options.config.stageRadius = 1000;
  538. options.config.stagePadding = 0;
  539. },
  540. },
  541. },
  542. {
  543. element: ".driver-5",
  544. popover: {
  545. title: "",
  546. description: "",
  547. popoverClass: "popoverClass popoverClassF2",
  548. align: "end",
  549. side: "bottom",
  550. nextBtnText: `下一步 (2/${length})`,
  551. showButtons: ["next"],
  552. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  553. driverInitialPosition(popover, options);
  554. },
  555. },
  556. },
  557. ],
  558. };
  559. if (props.statusAll.subjectStatus) {
  560. driverOptions.steps?.push({
  561. element: ".driver-10",
  562. popover: {
  563. title: "",
  564. description: "",
  565. popoverClass: "popoverClass popoverClass10",
  566. align: "end",
  567. side: "bottom",
  568. nextBtnText: `下一步 (${driverOptions.steps.length + 1}/${length})`,
  569. showButtons: ["next"],
  570. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  571. driverInitialPosition(popover, options);
  572. },
  573. },
  574. });
  575. }
  576. driverOptions.steps?.push({
  577. element: ".driver-5-1",
  578. popover: {
  579. title: "",
  580. description: "",
  581. popoverClass: "popoverClass popoverClass5-1",
  582. align: "end",
  583. side: "bottom",
  584. nextBtnText: `下一步 (${driverOptions.steps.length + 1}/${length})`,
  585. showButtons: ["next"],
  586. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  587. driverInitialPosition(popover, options);
  588. },
  589. },
  590. });
  591. driverOptions.steps?.push({
  592. element: ".driver-6",
  593. popover: {
  594. title: "",
  595. description: "",
  596. popoverClass: "popoverClass popoverClassF3 popoverClose",
  597. align: "end",
  598. side: "bottom",
  599. prevBtnText: "再看一遍",
  600. doneBtnText: "完成",
  601. showButtons: ["next", "previous"],
  602. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  603. driverInitialPosition(popover, options);
  604. },
  605. onPrevClick: () => {
  606. driverObj.drive(0);
  607. },
  608. onNextClick: () => {
  609. onDriverClose();
  610. },
  611. },
  612. });
  613. let driverObj: any;
  614. const handleClickOutside = (event: any) => {
  615. if (driverNextStatus.value) return;
  616. console.log(driverObj.getActiveIndex(), "driverObj.getActiveIndex()");
  617. if (driverObj.isActive() && (event.target.nodeName === "path" || event.target.classList.contains("driver-popover") || event.target.classList.contains("driver-overlay"))) {
  618. if (driverObj.isLastStep()) {
  619. onDriverClose();
  620. } else {
  621. // driverObj.moveNext(); // 跳转到下一步
  622. const index = driverObj.getActiveIndex();
  623. driverObj.moveTo(index + 1);
  624. }
  625. }
  626. };
  627. const guideInfo = ref({} as any);
  628. const showCloseBtn = ref(false);
  629. const getAllGuidance = async () => {
  630. try {
  631. const res = localStorage.getItem("guideInfo");
  632. if (res) {
  633. guideInfo.value = JSON.parse(res) || null;
  634. } else {
  635. guideInfo.value = {};
  636. }
  637. if (!(guideInfo.value && guideInfo.value.followDriver)) {
  638. document.addEventListener("click", handleClickOutside, true);
  639. nextTick(() => {
  640. driverObj = driver(driverOptions);
  641. driverObj.drive(0);
  642. showCloseBtn.value = true;
  643. state.hasDriverPop = true;
  644. });
  645. }
  646. } catch (e) {
  647. console.log(e);
  648. }
  649. };
  650. getAllGuidance();
  651. // 结束关闭弹窗
  652. const onDriverClose = () => {
  653. if (!guideInfo.value) {
  654. guideInfo.value = { followDriver: true };
  655. } else {
  656. guideInfo.value.followDriver = true;
  657. }
  658. endGuide(guideInfo.value);
  659. driverObj.destroy();
  660. document.querySelector(".driver-popover-close-btn-custom")?.remove();
  661. document.removeEventListener("click", handleClickOutside, true);
  662. state.hasDriverPop = false;
  663. };
  664. onUnmounted(() => {
  665. document.removeEventListener("click", handleClickOutside, true);
  666. });
  667. return () => (
  668. <Teleport to="body">
  669. {showCloseBtn.value && (
  670. <div
  671. class="driver-popover-close-btn-custom"
  672. onClick={(e: any) => {
  673. onDriverClose();
  674. }}
  675. ></div>
  676. )}
  677. </Teleport>
  678. );
  679. },
  680. });
  681. // 评测模式
  682. export const EvaluatingDriver = defineComponent({
  683. name: "EvaluatingDriver",
  684. props: {
  685. // 按钮状态
  686. statusAll: {
  687. type: Object as PropType<ButtonStatus>,
  688. default: () => {},
  689. },
  690. },
  691. setup(props) {
  692. const driverNextStatus = ref(false);
  693. // 初始化部分引导位置
  694. const driverInitialPosition = (popover: PopoverDOM, options: { config: Config; state: State }) => {
  695. options.config.stageRadius = 5;
  696. options.config.stagePadding = 4;
  697. try {
  698. const rect = options.state.activeElement?.getBoundingClientRect();
  699. popover.wrapper.style.marginLeft = -(rect?.width || 0) / 2 + 4 + "px";
  700. } catch {}
  701. };
  702. // 声部
  703. let length = props.statusAll.subjectStatus ? 6 : 5;
  704. const driverOptions: Config = {
  705. showProgress: false,
  706. allowClose: false,
  707. popoverOffset: 3,
  708. disableActiveInteraction: true,
  709. onCloseClick: () => {
  710. onDriverClose();
  711. },
  712. onHighlightStarted: () => {
  713. driverNextStatus.value = true;
  714. },
  715. onHighlighted: () => {
  716. driverNextStatus.value = false;
  717. },
  718. steps: [
  719. {
  720. element: ".evaluting-1",
  721. popover: {
  722. title: "",
  723. description: "",
  724. popoverClass: "popoverClass popoverClassE1",
  725. align: "end",
  726. side: "top",
  727. nextBtnText: `下一步 (1/${length})`,
  728. showButtons: ["next"],
  729. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  730. options.config.stageRadius = 1000;
  731. options.config.stagePadding = 0;
  732. },
  733. },
  734. },
  735. {
  736. element: ".driver-4",
  737. popover: {
  738. title: "",
  739. description: "",
  740. popoverClass: "popoverClass popoverClassE2",
  741. align: "end",
  742. side: "bottom",
  743. nextBtnText: `下一步 (2/${length})`,
  744. showButtons: ["next"],
  745. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  746. driverInitialPosition(popover, options);
  747. },
  748. },
  749. },
  750. {
  751. element: ".driver-5",
  752. popover: {
  753. title: "",
  754. description: "",
  755. popoverClass: "popoverClass popoverClassE3",
  756. align: "end",
  757. side: "bottom",
  758. nextBtnText: `下一步 (3/${length})`,
  759. showButtons: ["next"],
  760. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  761. driverInitialPosition(popover, options);
  762. },
  763. },
  764. },
  765. ],
  766. };
  767. if (props.statusAll.subjectStatus) {
  768. driverOptions.steps?.push({
  769. element: ".driver-10",
  770. popover: {
  771. title: "",
  772. description: "",
  773. popoverClass: "popoverClass popoverClass10",
  774. align: "end",
  775. side: "bottom",
  776. nextBtnText: `下一步 (${driverOptions.steps.length + 1}/${length})`,
  777. showButtons: ["next"],
  778. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  779. driverInitialPosition(popover, options);
  780. },
  781. },
  782. });
  783. }
  784. driverOptions.steps?.push({
  785. element: ".driver-5-1",
  786. popover: {
  787. title: "",
  788. description: "",
  789. popoverClass: "popoverClass popoverClass5-1",
  790. align: "end",
  791. side: "bottom",
  792. nextBtnText: `下一步 (${driverOptions.steps.length + 1}/${length})`,
  793. showButtons: ["next"],
  794. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  795. driverInitialPosition(popover, options);
  796. },
  797. },
  798. });
  799. driverOptions.steps?.push({
  800. element: ".driver-6",
  801. popover: {
  802. title: "",
  803. description: "",
  804. popoverClass: "popoverClass popoverClassE4 popoverClose",
  805. align: "end",
  806. side: "bottom",
  807. prevBtnText: "再看一遍",
  808. doneBtnText: "完成",
  809. showButtons: ["next", "previous"],
  810. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  811. driverInitialPosition(popover, options);
  812. },
  813. onPrevClick: () => {
  814. driverObj.drive(0);
  815. },
  816. onNextClick: () => {
  817. onDriverClose();
  818. },
  819. },
  820. });
  821. let driverObj: any;
  822. const handleClickOutside = (event: any) => {
  823. if (driverNextStatus.value) return;
  824. console.log(driverObj.getActiveIndex(), "driverObj.getActiveIndex()");
  825. if (driverObj.isActive() && (event.target.nodeName === "path" || event.target.classList.contains("driver-popover") || event.target.classList.contains("driver-overlay"))) {
  826. if (driverObj.isLastStep()) {
  827. onDriverClose();
  828. } else {
  829. driverObj.moveNext(); // 跳转到下一步
  830. }
  831. }
  832. };
  833. const guideInfo = ref({} as any);
  834. const showCloseBtn = ref(false);
  835. const getAllGuidance = async () => {
  836. try {
  837. const res = localStorage.getItem("guideInfo");
  838. if (res) {
  839. guideInfo.value = JSON.parse(res) || null;
  840. } else {
  841. guideInfo.value = {};
  842. }
  843. console.log(guideInfo.value, "guideInfo.value", showCloseBtn.value);
  844. if (!(guideInfo.value && guideInfo.value.evaluatingDriver)) {
  845. document.addEventListener("click", handleClickOutside, true);
  846. nextTick(() => {
  847. driverObj = driver(driverOptions);
  848. driverObj.drive();
  849. showCloseBtn.value = true;
  850. state.hasDriverPop = true;
  851. console.log(driverOptions, "driverOptions Evaluating", showCloseBtn.value);
  852. });
  853. } else {
  854. driverObj?.destroy();
  855. }
  856. } catch (e) {
  857. console.log(e);
  858. }
  859. };
  860. getAllGuidance();
  861. // 结束关闭弹窗
  862. const onDriverClose = () => {
  863. if (!guideInfo.value) {
  864. guideInfo.value = { evaluatingDriver: true };
  865. } else {
  866. guideInfo.value.evaluatingDriver = true;
  867. }
  868. endGuide(guideInfo.value);
  869. driverObj?.destroy();
  870. document.querySelector(".driver-popover-close-btn-custom")?.remove();
  871. document.removeEventListener("click", handleClickOutside, true);
  872. state.hasDriverPop = false;
  873. };
  874. onUnmounted(() => {
  875. document.removeEventListener("click", handleClickOutside, true);
  876. });
  877. return () => (
  878. <Teleport to="body">
  879. {showCloseBtn.value && (
  880. <div
  881. class="driver-popover-close-btn-custom"
  882. onClick={(e: any) => {
  883. onDriverClose();
  884. }}
  885. ></div>
  886. )}
  887. </Teleport>
  888. );
  889. },
  890. });
  891. // 评测模式 - 结果弹窗
  892. export const EvaluatingResultDriver = defineComponent({
  893. name: "EvaluatingResultDriver",
  894. props: {
  895. // 保存按钮状态
  896. saveBtn: {
  897. type: Boolean,
  898. default: true,
  899. },
  900. },
  901. setup(props) {
  902. let length = 4;
  903. if (!props.saveBtn) {
  904. length -= 1;
  905. }
  906. console.log(props.saveBtn, "props.saveBtn");
  907. const driverNextStatus = ref(false);
  908. // 初始化部分引导位置
  909. const driverInitialPosition = (popover: PopoverDOM, options: { config: Config; state: State }, position = 1) => {
  910. options.config.stageRadius = 1000;
  911. options.config.stagePadding = 2;
  912. try {
  913. const rect = options.state.activeElement?.getBoundingClientRect();
  914. popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * position + 4 + "px";
  915. } catch {}
  916. };
  917. const driverOptionsFun = () => {
  918. const driverOptions: Config = {
  919. showProgress: false,
  920. allowClose: false,
  921. popoverOffset: 3,
  922. disableActiveInteraction: true,
  923. onCloseClick: () => {
  924. onDriverClose();
  925. },
  926. onHighlightStarted: () => {
  927. driverNextStatus.value = true;
  928. },
  929. onHighlighted: () => {
  930. driverNextStatus.value = false;
  931. },
  932. steps: [
  933. {
  934. element: ".evaluting-result-1",
  935. popover: {
  936. title: "",
  937. description: "",
  938. popoverClass: "popoverClass popoverClassER1",
  939. align: "start",
  940. side: "right",
  941. nextBtnText: `下一步 (1/${length})`,
  942. showButtons: ["next"],
  943. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  944. options.config.stageRadius = 12;
  945. options.config.stagePadding = 10;
  946. },
  947. },
  948. },
  949. {
  950. element: ".evaluting-result-2",
  951. popover: {
  952. title: "",
  953. description: "",
  954. popoverClass: "popoverClass popoverClassER2",
  955. align: "start",
  956. side: "top",
  957. nextBtnText: `下一步 (2/${length})`,
  958. showButtons: ["next"],
  959. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  960. options.config.stageRadius = 1000;
  961. options.config.stagePadding = 2;
  962. try {
  963. const rect = options.state.activeElement?.getBoundingClientRect();
  964. popover.wrapper.style.marginLeft = (rect?.width || 0) / 2 - 4 + "px";
  965. } catch {}
  966. },
  967. },
  968. },
  969. ],
  970. };
  971. if (props.saveBtn) {
  972. driverOptions.steps?.push({
  973. element: ".evaluting-result-3",
  974. popover: {
  975. title: "",
  976. description: "",
  977. popoverClass: "popoverClass popoverClassER3",
  978. align: "end",
  979. side: "top",
  980. nextBtnText: `下一步 (3/${length})`,
  981. showButtons: ["next"],
  982. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  983. driverInitialPosition(popover, options, -1);
  984. },
  985. },
  986. });
  987. }
  988. driverOptions.steps?.push({
  989. element: ".evaluting-result-4",
  990. popover: {
  991. title: "",
  992. description: "",
  993. popoverClass: "popoverClass popoverClassER4 popoverClose",
  994. align: "end",
  995. side: "top",
  996. prevBtnText: "再看一遍",
  997. doneBtnText: "完成",
  998. showButtons: ["next", "previous"],
  999. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  1000. driverInitialPosition(popover, options, -1);
  1001. },
  1002. onPrevClick: () => {
  1003. driverObj.drive();
  1004. },
  1005. onNextClick: () => {
  1006. onDriverClose();
  1007. },
  1008. },
  1009. });
  1010. return driverOptions;
  1011. };
  1012. let driverObj: any;
  1013. const handleClickOutside = (event: any) => {
  1014. if (driverNextStatus.value) return;
  1015. if (driverObj.isActive() && (event.target.nodeName === "path" || event.target.classList.contains("driver-popover") || event.target.classList.contains("driver-overlay"))) {
  1016. if (driverObj.isLastStep()) {
  1017. onDriverClose();
  1018. } else {
  1019. driverObj.moveNext(); // 跳转到下一步
  1020. }
  1021. }
  1022. };
  1023. const guideInfo = ref({} as any);
  1024. const showCloseBtn = ref(false);
  1025. const getAllGuidance = async () => {
  1026. try {
  1027. const res = localStorage.getItem("guideInfo");
  1028. if (res) {
  1029. guideInfo.value = JSON.parse(res) || null;
  1030. } else {
  1031. guideInfo.value = {};
  1032. }
  1033. if (!(guideInfo.value && guideInfo.value.evaluatingResultDriver)) {
  1034. setTimeout(() => {
  1035. document.addEventListener("click", handleClickOutside, true);
  1036. nextTick(() => {
  1037. driverObj = driver(driverOptionsFun());
  1038. driverObj.drive();
  1039. showCloseBtn.value = true;
  1040. state.hasDriverPop = true;
  1041. });
  1042. }, 100);
  1043. }
  1044. } catch (e) {
  1045. console.log(e);
  1046. }
  1047. };
  1048. onMounted(() => {
  1049. getAllGuidance();
  1050. });
  1051. // 结束关闭弹窗
  1052. const onDriverClose = () => {
  1053. if (!guideInfo.value) {
  1054. guideInfo.value = { evaluatingResultDriver: true };
  1055. } else {
  1056. guideInfo.value.evaluatingResultDriver = true;
  1057. }
  1058. endGuide(guideInfo.value);
  1059. driverObj.destroy();
  1060. document.querySelector(".driver-popover-close-btn-custom")?.remove();
  1061. document.removeEventListener("click", handleClickOutside, true);
  1062. state.hasDriverPop = false;
  1063. };
  1064. onUnmounted(() => {
  1065. document.removeEventListener("click", handleClickOutside, true);
  1066. });
  1067. return () => (
  1068. <Teleport to="body">
  1069. {showCloseBtn.value && (
  1070. <div
  1071. class="driver-popover-close-btn-custom"
  1072. onClick={(e: any) => {
  1073. onDriverClose();
  1074. }}
  1075. ></div>
  1076. )}
  1077. </Teleport>
  1078. );
  1079. },
  1080. });
  1081. // 评测报告
  1082. export const EvaluatingReportDriver = defineComponent({
  1083. name: "EvaluatingReportDriver",
  1084. props: {
  1085. /** 视屏地址 */
  1086. videoFilePath: {
  1087. type: String,
  1088. default: "",
  1089. },
  1090. },
  1091. setup(props) {
  1092. const driverNextStatus = ref(false);
  1093. // state.isPercussion 是否为打击乐
  1094. // 初始化部分引导位置
  1095. const driverInitialPosition = (popover: PopoverDOM, options: { config: Config; state: State }, position = 1) => {
  1096. options.config.stageRadius = 12;
  1097. options.config.stagePadding = 0;
  1098. try {
  1099. const rect = options.state.activeElement?.getBoundingClientRect();
  1100. popover.wrapper.style.marginLeft = -(rect?.width || 0) / 2 + 16 + "px";
  1101. } catch {}
  1102. };
  1103. // 判断是否为打击乐
  1104. let steps: DriveStep[] = [];
  1105. if (state.isPercussion) {
  1106. if (props.videoFilePath) {
  1107. steps = [
  1108. {
  1109. element: ".evaluting-report-2",
  1110. popover: {
  1111. title: "",
  1112. description: "",
  1113. popoverClass: "popoverClass popoverClassReport2",
  1114. align: "end",
  1115. side: "bottom",
  1116. nextBtnText: "下一步 (1/2)",
  1117. showButtons: ["next"],
  1118. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  1119. options.config.stageRadius = 12;
  1120. options.config.stagePadding = 0;
  1121. try {
  1122. const rect = options.state.activeElement?.getBoundingClientRect();
  1123. popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * -1 + 16 + "px";
  1124. } catch {}
  1125. },
  1126. },
  1127. },
  1128. {
  1129. element: ".evaluting-report-4",
  1130. popover: {
  1131. title: "",
  1132. description: "",
  1133. popoverClass: "popoverClass popoverClassReport4 popoverClose",
  1134. align: "end",
  1135. side: "bottom",
  1136. prevBtnText: "再看一遍",
  1137. doneBtnText: "完成",
  1138. showButtons: ["next", "previous"],
  1139. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  1140. options.config.stageRadius = 8;
  1141. options.config.stagePadding = 5;
  1142. try {
  1143. const rect = options.state.activeElement?.getBoundingClientRect();
  1144. popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * -1 + 16 + "px";
  1145. } catch {}
  1146. },
  1147. onPrevClick: () => {
  1148. driverObj.drive(0);
  1149. },
  1150. onNextClick: () => {
  1151. onDriverClose();
  1152. },
  1153. },
  1154. },
  1155. ];
  1156. } else {
  1157. steps = [
  1158. {
  1159. element: ".evaluting-report-2",
  1160. popover: {
  1161. title: "",
  1162. description: "",
  1163. popoverClass: "popoverClass popoverClassReport2 popoverClose",
  1164. align: "end",
  1165. side: "bottom",
  1166. doneBtnText: "完成",
  1167. showButtons: ["next"],
  1168. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  1169. options.config.stageRadius = 12;
  1170. options.config.stagePadding = 0;
  1171. try {
  1172. const rect = options.state.activeElement?.getBoundingClientRect();
  1173. popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * -1 + 16 + "px";
  1174. } catch {}
  1175. },
  1176. onPrevClick: () => {
  1177. driverObj.drive(0);
  1178. },
  1179. onNextClick: () => {
  1180. onDriverClose();
  1181. },
  1182. },
  1183. },
  1184. ];
  1185. }
  1186. } else {
  1187. const count = props.videoFilePath ? 4 : 3;
  1188. steps = [
  1189. {
  1190. element: ".evaluting-report-1",
  1191. popover: {
  1192. title: "",
  1193. description: "",
  1194. popoverClass: "popoverClass popoverClassReport1",
  1195. align: "end",
  1196. side: "bottom",
  1197. nextBtnText: `下一步 (1/${count})`,
  1198. showButtons: ["next"],
  1199. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  1200. driverInitialPosition(popover, options);
  1201. },
  1202. },
  1203. },
  1204. {
  1205. element: ".evaluting-report-2",
  1206. popover: {
  1207. title: "",
  1208. description: "",
  1209. popoverClass: "popoverClass popoverClassReport2",
  1210. align: "end",
  1211. side: "bottom",
  1212. nextBtnText: `下一步 (2/${count})`,
  1213. showButtons: ["next"],
  1214. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  1215. options.config.stageRadius = 12;
  1216. options.config.stagePadding = 0;
  1217. try {
  1218. const rect = options.state.activeElement?.getBoundingClientRect();
  1219. popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * -1 + 16 + "px";
  1220. } catch {}
  1221. },
  1222. },
  1223. },
  1224. ];
  1225. if (props.videoFilePath) {
  1226. steps.push(
  1227. {
  1228. element: ".evaluting-report-3",
  1229. popover: {
  1230. title: "",
  1231. description: "",
  1232. popoverClass: "popoverClass popoverClassReport3",
  1233. align: "end",
  1234. side: "bottom",
  1235. nextBtnText: "下一步 (3/4)",
  1236. showButtons: ["next"],
  1237. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  1238. // driverInitialPosition(popover, options, -1);
  1239. options.config.stageRadius = 12;
  1240. options.config.stagePadding = 0;
  1241. try {
  1242. const rect = options.state.activeElement?.getBoundingClientRect();
  1243. popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * -1 + 16 + "px";
  1244. } catch {}
  1245. },
  1246. },
  1247. },
  1248. {
  1249. element: ".evaluting-report-4",
  1250. popover: {
  1251. title: "",
  1252. description: "",
  1253. popoverClass: "popoverClass popoverClassReport4 popoverClose",
  1254. align: "end",
  1255. side: "bottom",
  1256. prevBtnText: "再看一遍",
  1257. doneBtnText: "完成",
  1258. showButtons: ["next", "previous"],
  1259. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  1260. options.config.stageRadius = 8;
  1261. options.config.stagePadding = 5;
  1262. try {
  1263. const rect = options.state.activeElement?.getBoundingClientRect();
  1264. popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * -1 + 16 + "px";
  1265. } catch {}
  1266. },
  1267. onPrevClick: () => {
  1268. driverObj.drive(0);
  1269. },
  1270. onNextClick: () => {
  1271. onDriverClose();
  1272. },
  1273. },
  1274. }
  1275. );
  1276. } else {
  1277. steps.push({
  1278. element: ".evaluting-report-3",
  1279. popover: {
  1280. title: "",
  1281. description: "",
  1282. popoverClass: "popoverClass popoverClassReport3 popoverClose",
  1283. align: "start",
  1284. side: "bottom",
  1285. prevBtnText: "再看一遍",
  1286. doneBtnText: "完成",
  1287. showButtons: ["next", "previous"],
  1288. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  1289. driverInitialPosition(popover, options);
  1290. },
  1291. onPrevClick: () => {
  1292. driverObj.drive(0);
  1293. },
  1294. onNextClick: () => {
  1295. onDriverClose();
  1296. },
  1297. },
  1298. });
  1299. }
  1300. }
  1301. const driverOptions: Config = {
  1302. showProgress: false,
  1303. allowClose: false,
  1304. popoverOffset: 3,
  1305. disableActiveInteraction: true,
  1306. onCloseClick: () => {
  1307. onDriverClose();
  1308. },
  1309. onHighlightStarted: () => {
  1310. driverNextStatus.value = true;
  1311. },
  1312. onHighlighted: () => {
  1313. driverNextStatus.value = false;
  1314. },
  1315. steps: steps,
  1316. };
  1317. let driverObj: any;
  1318. const guideInfo = ref({} as any);
  1319. const handleClickOutside = (event: any) => {
  1320. if (driverNextStatus.value) return;
  1321. if (driverObj.isActive() && (event.target.nodeName === "path" || event.target.classList.contains("driver-popover") || event.target.classList.contains("driver-overlay"))) {
  1322. if (driverObj.isLastStep()) {
  1323. onDriverClose();
  1324. } else {
  1325. driverObj.moveNext(); // 跳转到下一步
  1326. }
  1327. }
  1328. };
  1329. const showCloseBtn = ref(false);
  1330. const getAllGuidance = async () => {
  1331. try {
  1332. const res = localStorage.getItem("guideInfo");
  1333. if (res) {
  1334. guideInfo.value = JSON.parse(res) || null;
  1335. } else {
  1336. guideInfo.value = {};
  1337. }
  1338. if (!(guideInfo.value && guideInfo.value.evaluatingReportDriver)) {
  1339. // 监听点击事件以实现点击空白区域跳转到下一步
  1340. document.addEventListener("click", handleClickOutside, true);
  1341. nextTick(() => {
  1342. driverObj = driver(driverOptions);
  1343. driverObj.drive();
  1344. state.hasDriverPop = true;
  1345. showCloseBtn.value = true;
  1346. });
  1347. }
  1348. } catch (e) {
  1349. console.log(e);
  1350. }
  1351. };
  1352. getAllGuidance();
  1353. // 结束关闭弹窗
  1354. const onDriverClose = () => {
  1355. if (!guideInfo.value) {
  1356. guideInfo.value = { evaluatingReportDriver: true };
  1357. } else {
  1358. guideInfo.value.evaluatingReportDriver = true;
  1359. }
  1360. endGuide(guideInfo.value);
  1361. driverObj.destroy();
  1362. document.querySelector(".driver-popover-close-btn-custom")?.remove();
  1363. document.removeEventListener("click", handleClickOutside, true);
  1364. state.hasDriverPop = false;
  1365. };
  1366. onUnmounted(() => {
  1367. document.removeEventListener("click", handleClickOutside, true);
  1368. });
  1369. return () => (
  1370. <Teleport to="body">
  1371. {showCloseBtn.value && (
  1372. <div
  1373. class="driver-popover-close-btn-custom"
  1374. onClick={(e: any) => {
  1375. onDriverClose();
  1376. }}
  1377. ></div>
  1378. )}
  1379. </Teleport>
  1380. );
  1381. },
  1382. });