index.tsx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. import { defineComponent, nextTick, ref } from "vue";
  2. import { Config, DriveStep, PopoverDOM, State, driver } from "driver.js";
  3. import "driver.js/dist/driver.css";
  4. import state 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. } catch (e) {
  10. console.log(e);
  11. }
  12. };
  13. /** 练习模式 */
  14. export const PractiseDriver = defineComponent({
  15. name: "PractiseDriver",
  16. setup() {
  17. // 初始化部分引导位置
  18. const driverInitialPosition = (popover: PopoverDOM, options: { config: Config; state: State }) => {
  19. options.config.stageRadius = 5;
  20. options.config.stagePadding = 8;
  21. try {
  22. const rect = options.state.activeElement?.getBoundingClientRect();
  23. popover.wrapper.style.marginLeft = (rect?.width || 0) / 2 + 4 + "px";
  24. } catch {}
  25. };
  26. // 乐器方向不一样引导位置不一样
  27. const instrumentDirection: DriveStep = {
  28. element: ".driver-7",
  29. popover: {
  30. title: "",
  31. description: "",
  32. popoverClass: `popoverClass ${state.fingeringInfo.direction === "transverse" ? "popoverClass7" : "popoverClass7-1"}`,
  33. align: state.fingeringInfo.direction === "transverse" ? "start" : "center",
  34. side: state.fingeringInfo.direction === "transverse" ? "top" : "left",
  35. nextBtnText: "下一步7/9",
  36. showButtons: ["next", "close"],
  37. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  38. if (state.fingeringInfo.direction === "transverse") driverInitialPosition(popover, options);
  39. },
  40. onCloseClick: () => {
  41. onDriverClose();
  42. },
  43. },
  44. };
  45. const driverOptions: Config = {
  46. showProgress: false,
  47. allowClose: false,
  48. popoverOffset: 3,
  49. disableActiveInteraction: true,
  50. onCloseClick: () => {
  51. onDriverClose();
  52. },
  53. steps: [
  54. {
  55. element: ".driver-1",
  56. popover: {
  57. title: "",
  58. description: "",
  59. popoverClass: "popoverClass popoverClass1",
  60. align: "end",
  61. side: "top",
  62. nextBtnText: "下一步1/9",
  63. showButtons: ["next", "close"],
  64. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  65. // console.log(popover, "popover", popover.wrapper, options.state.activeElement, options.state.__overlaySvg);
  66. options.config.stageRadius = 1000;
  67. options.config.stagePadding = 0;
  68. // popover.wrapper.addEventListener("click", (e) => {
  69. // e.stopPropagation;
  70. // console.log("12121212");
  71. // // driverObj.drive(1);
  72. // });
  73. // document.querySelector(".popoverClass1")?.addEventListener("click", () => {
  74. // console.log("11111");
  75. // });
  76. },
  77. },
  78. },
  79. {
  80. element: ".driver-2",
  81. popover: {
  82. title: "",
  83. description: "",
  84. popoverClass: "popoverClass popoverClass2",
  85. align: "start",
  86. side: "top",
  87. nextBtnText: "下一步2/9",
  88. showButtons: ["next", "close"],
  89. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  90. driverInitialPosition(popover, options);
  91. },
  92. },
  93. },
  94. {
  95. element: ".driver-3",
  96. popover: {
  97. title: "",
  98. description: "",
  99. popoverClass: "popoverClass popoverClass3",
  100. align: "start",
  101. side: "top",
  102. nextBtnText: "下一步3/9",
  103. showButtons: ["next", "close"],
  104. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  105. driverInitialPosition(popover, options);
  106. },
  107. },
  108. },
  109. {
  110. element: ".driver-4",
  111. popover: {
  112. title: "",
  113. description: "",
  114. popoverClass: "popoverClass popoverClass4",
  115. align: "start",
  116. side: "top",
  117. nextBtnText: "下一步4/9",
  118. showButtons: ["next", "close"],
  119. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  120. driverInitialPosition(popover, options);
  121. },
  122. },
  123. },
  124. {
  125. element: ".driver-5",
  126. popover: {
  127. title: "",
  128. description: "",
  129. popoverClass: "popoverClass popoverClass5",
  130. align: "start",
  131. side: "top",
  132. nextBtnText: "下一步5/9",
  133. showButtons: ["next", "close"],
  134. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  135. driverInitialPosition(popover, options);
  136. },
  137. },
  138. },
  139. {
  140. element: ".driver-6",
  141. popover: {
  142. title: "",
  143. description: "",
  144. popoverClass: "popoverClass popoverClass6",
  145. align: "start",
  146. side: "top",
  147. nextBtnText: "下一步6/9",
  148. showButtons: ["next", "close"],
  149. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  150. driverInitialPosition(popover, options);
  151. },
  152. },
  153. },
  154. instrumentDirection,
  155. {
  156. element: ".driver-8",
  157. popover: {
  158. title: "",
  159. description: "",
  160. popoverClass: "popoverClass popoverClass8",
  161. align: "start",
  162. side: "bottom",
  163. nextBtnText: "下一步8/9",
  164. showButtons: ["next", "close"],
  165. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  166. options.config.stageRadius = 1000;
  167. options.config.stagePadding = 0;
  168. try {
  169. const rect = options.state.activeElement?.getBoundingClientRect();
  170. popover.wrapper.style.marginLeft = (rect?.width || 0) / 2 - 4 + "px";
  171. } catch {}
  172. },
  173. },
  174. },
  175. {
  176. element: ".driver-9",
  177. popover: {
  178. title: "",
  179. description: "",
  180. popoverClass: "popoverClass popoverClass9 popoverClose",
  181. align: "end",
  182. side: "bottom",
  183. prevBtnText: "再看一遍",
  184. doneBtnText: "完成",
  185. showButtons: ["next", "previous", "close"],
  186. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  187. options.config.stageRadius = 1000;
  188. options.config.stagePadding = 0;
  189. try {
  190. const rect = options.state.activeElement?.getBoundingClientRect();
  191. popover.wrapper.style.marginLeft = -((rect?.width || 0) / 2 - 8) + "px";
  192. } catch {}
  193. },
  194. onPrevClick: () => {
  195. driverObj.drive(0);
  196. },
  197. onNextClick: () => {
  198. onDriverClose();
  199. },
  200. },
  201. },
  202. ],
  203. };
  204. let driverObj: any;
  205. const guideInfo = ref({} as any);
  206. const getAllGuidance = async () => {
  207. try {
  208. if (state.guideInfo) {
  209. guideInfo.value = state.guideInfo;
  210. } else {
  211. const res = await getGuidance({ guideTag: "guideInfo" });
  212. if (res.data) {
  213. guideInfo.value = JSON.parse(res.data?.guideValue) || null;
  214. } else {
  215. guideInfo.value = {};
  216. }
  217. }
  218. if (!(guideInfo.value && guideInfo.value.practiseDriver)) {
  219. driverObj = driver(driverOptions);
  220. nextTick(() => {
  221. driverObj.drive(0);
  222. });
  223. }
  224. } catch (e) {
  225. console.log(e);
  226. }
  227. };
  228. getAllGuidance();
  229. // 结束关闭弹窗
  230. const onDriverClose = () => {
  231. if (!guideInfo.value) {
  232. guideInfo.value = { practiseDriver: true };
  233. } else {
  234. guideInfo.value.practiseDriver = true;
  235. }
  236. endGuide(guideInfo.value);
  237. driverObj.destroy();
  238. };
  239. return () => <div></div>;
  240. },
  241. });
  242. /** 跟练模式 */
  243. export const FollowDriver = defineComponent({
  244. name: "FollowDriver",
  245. setup() {
  246. // 初始化部分引导位置
  247. const driverInitialPosition = (popover: PopoverDOM, options: { config: Config; state: State }) => {
  248. options.config.stageRadius = 5;
  249. options.config.stagePadding = 8;
  250. try {
  251. const rect = options.state.activeElement?.getBoundingClientRect();
  252. popover.wrapper.style.marginLeft = (rect?.width || 0) / 2 + 4 + "px";
  253. } catch {}
  254. };
  255. const driverOptions: Config = {
  256. showProgress: false,
  257. allowClose: false,
  258. popoverOffset: 3,
  259. disableActiveInteraction: true,
  260. steps: [
  261. {
  262. element: ".follow-1",
  263. popover: {
  264. title: "",
  265. description: "",
  266. popoverClass: "popoverClass popoverClassF1",
  267. align: "end",
  268. side: "top",
  269. nextBtnText: "下一步1/3",
  270. showButtons: ["next", "close"],
  271. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  272. options.config.stageRadius = 1000;
  273. options.config.stagePadding = 0;
  274. },
  275. onCloseClick: () => {
  276. onDriverClose();
  277. },
  278. },
  279. },
  280. {
  281. element: ".driver-5",
  282. popover: {
  283. title: "",
  284. description: "",
  285. popoverClass: "popoverClass popoverClass5",
  286. align: "start",
  287. side: "top",
  288. nextBtnText: "下一步2/3",
  289. showButtons: ["next", "close"],
  290. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  291. driverInitialPosition(popover, options);
  292. },
  293. onCloseClick: () => {
  294. onDriverClose();
  295. },
  296. },
  297. },
  298. {
  299. element: ".driver-6",
  300. popover: {
  301. title: "",
  302. description: "",
  303. popoverClass: "popoverClass popoverClass6 popoverClose",
  304. align: "start",
  305. side: "top",
  306. prevBtnText: "再看一遍",
  307. doneBtnText: "完成",
  308. showButtons: ["next", "previous", "close"],
  309. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  310. driverInitialPosition(popover, options);
  311. },
  312. onPrevClick: () => {
  313. driverObj.drive(0);
  314. },
  315. onNextClick: () => {
  316. onDriverClose();
  317. },
  318. onCloseClick: () => {
  319. onDriverClose();
  320. },
  321. },
  322. },
  323. ],
  324. };
  325. let driverObj: any;
  326. const guideInfo = ref({} as any);
  327. const getAllGuidance = async () => {
  328. try {
  329. if (state.guideInfo) {
  330. guideInfo.value = state.guideInfo;
  331. } else {
  332. const res = await getGuidance({ guideTag: "guideInfo" });
  333. if (res.data) {
  334. guideInfo.value = JSON.parse(res.data?.guideValue) || null;
  335. } else {
  336. guideInfo.value = {};
  337. }
  338. }
  339. if (!(guideInfo.value && guideInfo.value.followDriver)) {
  340. driverObj = driver(driverOptions);
  341. nextTick(() => {
  342. driverObj.drive(0);
  343. });
  344. }
  345. } catch (e) {
  346. console.log(e);
  347. }
  348. };
  349. getAllGuidance();
  350. // 结束关闭弹窗
  351. const onDriverClose = () => {
  352. if (!guideInfo.value) {
  353. guideInfo.value = { followDriver: true };
  354. } else {
  355. guideInfo.value.followDriver = true;
  356. }
  357. endGuide(guideInfo.value);
  358. driverObj.destroy();
  359. };
  360. return () => <div></div>;
  361. },
  362. });
  363. // 评测模式
  364. export const EvaluatingDriver = defineComponent({
  365. name: "EvaluatingDriver",
  366. setup() {
  367. // 初始化部分引导位置
  368. const driverInitialPosition = (popover: PopoverDOM, options: { config: Config; state: State }) => {
  369. options.config.stageRadius = 5;
  370. options.config.stagePadding = 8;
  371. try {
  372. const rect = options.state.activeElement?.getBoundingClientRect();
  373. popover.wrapper.style.marginLeft = (rect?.width || 0) / 2 + 4 + "px";
  374. } catch {}
  375. };
  376. const driverOptions: Config = {
  377. showProgress: false,
  378. allowClose: false,
  379. popoverOffset: 3,
  380. disableActiveInteraction: true,
  381. steps: [
  382. {
  383. element: ".evaluting-1",
  384. popover: {
  385. title: "",
  386. description: "",
  387. popoverClass: "popoverClass popoverClassE1",
  388. align: "end",
  389. side: "top",
  390. nextBtnText: "下一步1/3",
  391. showButtons: ["next", "close"],
  392. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  393. options.config.stageRadius = 1000;
  394. options.config.stagePadding = 0;
  395. },
  396. onCloseClick: () => {
  397. onDriverClose();
  398. },
  399. },
  400. },
  401. {
  402. element: ".driver-5",
  403. popover: {
  404. title: "",
  405. description: "",
  406. popoverClass: "popoverClass popoverClass5",
  407. align: "start",
  408. side: "top",
  409. nextBtnText: "下一步2/3",
  410. showButtons: ["next", "close"],
  411. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  412. driverInitialPosition(popover, options);
  413. },
  414. onCloseClick: () => {
  415. onDriverClose();
  416. },
  417. },
  418. },
  419. {
  420. element: ".driver-6",
  421. popover: {
  422. title: "",
  423. description: "",
  424. popoverClass: "popoverClass popoverClass6 popoverClose",
  425. align: "start",
  426. side: "top",
  427. prevBtnText: "再看一遍",
  428. doneBtnText: "完成",
  429. showButtons: ["next", "previous", "close"],
  430. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  431. driverInitialPosition(popover, options);
  432. },
  433. onPrevClick: () => {
  434. driverObj.drive(0);
  435. },
  436. onNextClick: () => {
  437. onDriverClose();
  438. },
  439. onCloseClick: () => {
  440. onDriverClose();
  441. },
  442. },
  443. },
  444. ],
  445. };
  446. let driverObj: any;
  447. const guideInfo = ref({} as any);
  448. const getAllGuidance = async () => {
  449. try {
  450. if (state.guideInfo) {
  451. guideInfo.value = state.guideInfo;
  452. } else {
  453. const res = await getGuidance({ guideTag: "guideInfo" });
  454. if (res.data) {
  455. guideInfo.value = JSON.parse(res.data?.guideValue) || null;
  456. } else {
  457. guideInfo.value = {};
  458. }
  459. }
  460. if (!(guideInfo.value && guideInfo.value.evaluatingDriver)) {
  461. driverObj = driver(driverOptions);
  462. nextTick(() => {
  463. driverObj.drive(0);
  464. });
  465. } else {
  466. driverObj.destroy();
  467. }
  468. } catch (e) {
  469. console.log(e);
  470. }
  471. };
  472. getAllGuidance();
  473. // 结束关闭弹窗
  474. const onDriverClose = () => {
  475. if (!guideInfo.value) {
  476. guideInfo.value = { evaluatingDriver: true };
  477. } else {
  478. guideInfo.value.evaluatingDriver = true;
  479. }
  480. endGuide(guideInfo.value);
  481. driverObj?.destroy();
  482. };
  483. return () => <div></div>;
  484. },
  485. });
  486. // 评测模式 - 结果弹窗
  487. export const EvaluatingResultDriver = defineComponent({
  488. name: "EvaluatingResultDriver",
  489. setup() {
  490. // 初始化部分引导位置
  491. const driverInitialPosition = (popover: PopoverDOM, options: { config: Config; state: State }, position = 1) => {
  492. options.config.stageRadius = 1000;
  493. options.config.stagePadding = 0;
  494. try {
  495. const rect = options.state.activeElement?.getBoundingClientRect();
  496. popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * position + 4 + "px";
  497. } catch {}
  498. };
  499. const driverOptions: Config = {
  500. showProgress: false,
  501. allowClose: false,
  502. popoverOffset: 3,
  503. disableActiveInteraction: true,
  504. steps: [
  505. {
  506. element: ".evaluting-result-1",
  507. popover: {
  508. title: "",
  509. description: "",
  510. popoverClass: "popoverClass popoverClassER1",
  511. align: "start",
  512. side: "right",
  513. nextBtnText: "下一步1/4",
  514. showButtons: ["next", "close"],
  515. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  516. options.config.stageRadius = 12;
  517. options.config.stagePadding = 10;
  518. },
  519. onCloseClick: () => {
  520. onDriverClose();
  521. },
  522. },
  523. },
  524. {
  525. element: ".evaluting-result-2",
  526. popover: {
  527. title: "",
  528. description: "",
  529. popoverClass: "popoverClass popoverClassER2",
  530. align: "start",
  531. side: "top",
  532. nextBtnText: "下一步2/4",
  533. showButtons: ["next", "close"],
  534. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  535. options.config.stageRadius = 1000;
  536. options.config.stagePadding = 0;
  537. try {
  538. const rect = options.state.activeElement?.getBoundingClientRect();
  539. popover.wrapper.style.marginLeft = (rect?.width || 0) / 2 - 4 + "px";
  540. } catch {}
  541. },
  542. onCloseClick: () => {
  543. onDriverClose();
  544. },
  545. },
  546. },
  547. {
  548. element: ".evaluting-result-3",
  549. popover: {
  550. title: "",
  551. description: "",
  552. popoverClass: "popoverClass popoverClassER3",
  553. align: "end",
  554. side: "top",
  555. nextBtnText: "下一步3/4",
  556. showButtons: ["next", "close"],
  557. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  558. driverInitialPosition(popover, options, -1);
  559. },
  560. onCloseClick: () => {
  561. onDriverClose();
  562. },
  563. },
  564. },
  565. {
  566. element: ".evaluting-result-4",
  567. popover: {
  568. title: "",
  569. description: "",
  570. popoverClass: "popoverClass popoverClassER4 popoverClose",
  571. align: "end",
  572. side: "top",
  573. prevBtnText: "再看一遍",
  574. doneBtnText: "完成",
  575. showButtons: ["next", "previous", "close"],
  576. onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
  577. driverInitialPosition(popover, options, -1);
  578. },
  579. onPrevClick: () => {
  580. driverObj.drive(0);
  581. },
  582. onNextClick: () => {
  583. onDriverClose();
  584. },
  585. onCloseClick: () => {
  586. onDriverClose();
  587. },
  588. },
  589. },
  590. ],
  591. };
  592. let driverObj: any;
  593. const guideInfo = ref({} as any);
  594. const getAllGuidance = async () => {
  595. try {
  596. if (state.guideInfo) {
  597. guideInfo.value = state.guideInfo;
  598. } else {
  599. const res = await getGuidance({ guideTag: "guideInfo" });
  600. if (res.data) {
  601. guideInfo.value = JSON.parse(res.data?.guideValue) || null;
  602. } else {
  603. guideInfo.value = {};
  604. }
  605. }
  606. if (!(guideInfo.value && guideInfo.value.evaluatingResultDriver)) {
  607. driverObj = driver(driverOptions);
  608. nextTick(() => {
  609. driverObj.drive(0);
  610. });
  611. }
  612. } catch (e) {
  613. console.log(e);
  614. }
  615. };
  616. getAllGuidance();
  617. // 结束关闭弹窗
  618. const onDriverClose = () => {
  619. if (!guideInfo.value) {
  620. guideInfo.value = { evaluatingResultDriver: true };
  621. } else {
  622. guideInfo.value.evaluatingResultDriver = true;
  623. }
  624. endGuide(guideInfo.value);
  625. driverObj.destroy();
  626. };
  627. return () => <div></div>;
  628. },
  629. });