home-guide.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. import { NButton } from 'naive-ui';
  2. import {
  3. defineComponent,
  4. nextTick,
  5. onMounted,
  6. onUnmounted,
  7. reactive,
  8. ref,
  9. watch
  10. } from 'vue';
  11. import styles from './index.module.less';
  12. import { getImage } from './images';
  13. import { eventGlobal, px2vw, px2vwH } from '@/utils/index';
  14. import { getGuidance, setGuidance, setLocalGuidance } from './api';
  15. export default defineComponent({
  16. name: 'coai-guide',
  17. emits: ['close'],
  18. setup(props, { emit }) {
  19. const data = reactive({
  20. box: {
  21. height: '0px'
  22. } as any,
  23. show: false,
  24. /**
  25. *
  26. width: px2vw(840),
  27. height: px2vw(295)
  28. */
  29. steps: [
  30. {
  31. ele: '',
  32. eleRect: {} as DOMRect,
  33. img: getImage('home1.png'),
  34. handStyle: {
  35. top: '0.91rem'
  36. },
  37. imgStyle: {
  38. top: px2vw(-400 / 2),
  39. left: px2vw(-734 / 2),
  40. width: px2vw(734),
  41. height: px2vw(295)
  42. },
  43. btnsStyle: {
  44. bottom: px2vw(240),
  45. left: px2vw(-128)
  46. },
  47. boxStyle: {
  48. border: 'none',
  49. width: 0,
  50. height: 0,
  51. backgroundColor: 'transparent',
  52. position: 'fixed',
  53. top: `50%`,
  54. left: '50%'
  55. // visibility: 'hidden'
  56. },
  57. eleRectPadding: {
  58. left: 0,
  59. top: 0,
  60. width: 0,
  61. height: 0
  62. }
  63. },
  64. {
  65. ele: '',
  66. img: getImage('home2.png'),
  67. imgStyle: {
  68. top: '100%',
  69. left: px2vw(-290),
  70. width: px2vw(401),
  71. height: px2vw(227)
  72. },
  73. btnsStyle: {
  74. bottom: '30px',
  75. left: px2vw(-130)
  76. },
  77. boxStyle: {},
  78. eleRectPadding: {
  79. left: 7,
  80. top: 7,
  81. width: 14,
  82. height: 14
  83. }
  84. },
  85. {
  86. ele: '',
  87. img: getImage('home6.png'),
  88. imgStyle: {
  89. top: '100%',
  90. left: px2vw(-310),
  91. width: px2vw(477),
  92. height: px2vw(227)
  93. },
  94. btnsStyle: {
  95. bottom: '30px',
  96. left: px2vw(-150)
  97. },
  98. boxStyle: {},
  99. eleRectPadding: {
  100. left: 7,
  101. top: 7,
  102. width: 14,
  103. height: 14
  104. }
  105. },
  106. {
  107. ele: '',
  108. img: getImage('home4.png'),
  109. imgStyle: {
  110. top: '100%',
  111. left: px2vw(-310),
  112. width: px2vw(477),
  113. height: px2vw(227)
  114. },
  115. btnsStyle: {
  116. bottom: '30px',
  117. left: px2vw(-150)
  118. },
  119. boxStyle: {},
  120. eleRectPadding: {
  121. left: 7,
  122. top: 7,
  123. width: 14,
  124. height: 14
  125. }
  126. },
  127. {
  128. ele: '',
  129. img: getImage('home3.png'),
  130. handStyle: {
  131. top: '-1.39rem',
  132. left: '0.17rem',
  133. transform: 'rotate(180deg)'
  134. },
  135. imgStyle: {
  136. top: px2vw(-4),
  137. width: px2vw(454),
  138. height: px2vw(227),
  139. left: px2vw(-150)
  140. },
  141. btnsStyle: {
  142. bottom: '30px',
  143. left: px2vw(8)
  144. },
  145. boxStyle: {
  146. borderRadius: '30px'
  147. },
  148. eleRectPadding: {
  149. left: 7,
  150. top: 9,
  151. width: 14,
  152. height: 14
  153. }
  154. },
  155. {
  156. ele: '',
  157. img: getImage('home5.png'),
  158. handStyle: {
  159. top: '-1.39rem',
  160. left: '0.17rem',
  161. transform: 'rotate(180deg)'
  162. },
  163. imgStyle: {
  164. top: px2vw(-194),
  165. width: px2vw(621),
  166. height: px2vw(223),
  167. left: px2vw(-624)
  168. },
  169. btnsStyle: {
  170. top: px2vw(-42),
  171. left: px2vw(-460)
  172. },
  173. boxStyle: {},
  174. eleRectPadding: {
  175. left: 7,
  176. top: 7,
  177. width: 14,
  178. height: 14
  179. }
  180. }
  181. ],
  182. step: 0
  183. });
  184. const tipShow = ref(false);
  185. // const res = setGuidance({guideTag:'teacher-guideInfo',guideValue:'{}'})
  186. const guideInfo = ref({} as any);
  187. const getAllGuidance = async () => {
  188. try {
  189. // const res = await getGuidance({ guideTag: 'teacher-guideInfo' });
  190. // if (res.data) {
  191. // guideInfo.value = JSON.parse(res.data?.guideValue) || null;
  192. // } else {
  193. // guideInfo.value = {};
  194. // }
  195. const res = localStorage.getItem('teacher-guideInfo');
  196. if (res) {
  197. guideInfo.value = JSON.parse(res) || null;
  198. } else {
  199. guideInfo.value = {};
  200. }
  201. if (guideInfo.value && guideInfo.value.homeGuide) {
  202. tipShow.value = false;
  203. } else {
  204. tipShow.value = true;
  205. }
  206. } catch (e) {
  207. console.log(e);
  208. }
  209. // const guideInfo = localStorage.getItem('teacher-guideInfo');
  210. };
  211. getAllGuidance();
  212. const getStepELe = () => {
  213. const ele: HTMLElement = document.getElementById(
  214. data.step === data.steps.length - 1
  215. ? 'moveNPopover'
  216. : `home-${data.step}`
  217. )!;
  218. // console.log(`coai-${data.step}`, data.steps[data.step].eleRectPadding);
  219. if (ele) {
  220. const eleRect = ele.getBoundingClientRect();
  221. const left = data.steps[data.step].eleRectPadding?.left || 0;
  222. const top = data.steps[data.step].eleRectPadding?.top || 0;
  223. const width = data.steps[data.step].eleRectPadding?.width || 0;
  224. const height = data.steps[data.step].eleRectPadding?.height || 0;
  225. console.log(eleRect, height);
  226. data.box = {
  227. left: eleRect.x - left + 'px',
  228. top: eleRect.y - top + 'px',
  229. width: eleRect.width + width + 'px',
  230. height: eleRect.height + height + 'px'
  231. };
  232. } else {
  233. handleNext();
  234. }
  235. };
  236. const onResetGuide = async (name: string) => {
  237. try {
  238. if (name !== 'Home') return;
  239. if (!guideInfo.value) {
  240. guideInfo.value = { homeGuide: false };
  241. } else {
  242. guideInfo.value.homeGuide = false;
  243. }
  244. try {
  245. setLocalGuidance({
  246. guideTag: 'teacher-guideInfo',
  247. guideValue: JSON.stringify(guideInfo.value)
  248. });
  249. } catch (e) {
  250. console.log(e);
  251. }
  252. data.step = 0;
  253. getStepELe();
  254. tipShow.value = true;
  255. } catch {
  256. //
  257. }
  258. };
  259. onMounted(() => {
  260. getStepELe();
  261. window.addEventListener('resize', resetSize);
  262. eventGlobal.on('teacher-guideInfo', onResetGuide);
  263. });
  264. const resetSize = () => {
  265. getStepELe();
  266. };
  267. onUnmounted(() => {
  268. window.removeEventListener('resize', resetSize);
  269. eventGlobal.off('teacher-guideInfo', onResetGuide);
  270. });
  271. const handleNext = () => {
  272. if (data.step >= data.steps.length - 1) {
  273. endGuide();
  274. return;
  275. }
  276. data.step = data.step + 1;
  277. getStepELe();
  278. };
  279. const endGuide = async () => {
  280. // let guideInfo =
  281. // JSON.parse(localStorage.getItem('teacher-guideInfo') || '{}') || null;
  282. if (!guideInfo.value) {
  283. guideInfo.value = { homeGuide: true };
  284. } else {
  285. guideInfo.value.homeGuide = true;
  286. }
  287. try {
  288. setLocalGuidance({
  289. guideTag: 'teacher-guideInfo',
  290. guideValue: JSON.stringify(guideInfo.value)
  291. });
  292. } catch (e) {
  293. console.log(e);
  294. }
  295. // localStorage.setItem('teacher-guideInfo', JSON.stringify(guideInfo));
  296. tipShow.value = false;
  297. // localStorage.setItem('endC')
  298. };
  299. return () => (
  300. <>
  301. {tipShow.value ? (
  302. <div
  303. v-model:show={tipShow.value}
  304. class={['n-modal-mask', 'n-modal-mask-guide']}>
  305. <div class={styles.content} onClick={() => handleNext()}>
  306. <div
  307. class={styles.backBtn}
  308. onClick={(e: Event) => {
  309. e.stopPropagation();
  310. endGuide();
  311. }}>
  312. 跳过
  313. </div>
  314. <div
  315. class={styles.box}
  316. style={{ ...data.box, ...data.steps[data.step].boxStyle }}
  317. id={`modeType-${data.step}`}>
  318. {data.steps.map((item: any, index) => (
  319. <div
  320. onClick={(e: Event) => e.stopPropagation()}
  321. class={styles.item}
  322. style={
  323. item.type == 'bottom'
  324. ? {
  325. display: index === data.step ? '' : 'none',
  326. left: `${item.eleRect?.left}px`,
  327. top: `-${item.imgStyle?.height}`
  328. }
  329. : {
  330. display: index === data.step ? '' : 'none',
  331. left: `${item.eleRect?.left}px`,
  332. top: `${data.box?.height}`
  333. }
  334. }>
  335. <img
  336. class={styles.img}
  337. style={item.imgStyle}
  338. src={item.img}
  339. />
  340. {/* <img
  341. class={styles.iconHead}
  342. style={item.handStyle}
  343. src={getImage('indexDot.png')}
  344. /> */}
  345. <div class={styles.btns} style={item.btnsStyle}>
  346. {data.step + 1 == data.steps.length ? (
  347. <>
  348. <div
  349. class={[styles.endBtn]}
  350. onClick={() => endGuide()}>
  351. 完成
  352. </div>
  353. <div
  354. class={styles.nextBtn}
  355. onClick={() => {
  356. data.step = 0;
  357. getStepELe();
  358. }}>
  359. 再看一遍
  360. </div>
  361. </>
  362. ) : (
  363. <div class={styles.btn} onClick={() => handleNext()}>
  364. {data.step !== 0
  365. ? `下一步 ${data.step}/${data.steps.length - 1}`
  366. : '开始体验'}
  367. </div>
  368. )}
  369. </div>
  370. </div>
  371. ))}
  372. </div>
  373. </div>
  374. </div>
  375. ) : null}
  376. </>
  377. );
  378. }
  379. });