home-guide.tsx 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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 {px2vw,px2vwH} from '@/utils/index'
  14. import {getGuidance,setGuidance} 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(-150),
  39. left: px2vw(563),
  40. width: px2vw(734),
  41. height: px2vw(295)
  42. },
  43. btnsStyle: {
  44. bottom:px2vw(188),
  45. left: px2vw(805),
  46. },
  47. boxStyle:{
  48. border:'none',
  49. width:'0px',
  50. height:'0px',
  51. backgroundColor: 'transparent'
  52. // visibility: 'hidden'
  53. },
  54. eleRectPadding:{
  55. left:7,
  56. top:7,
  57. width:14,
  58. height:14
  59. }
  60. },
  61. // {
  62. // ele: '',
  63. // img: getImage('home2.png'),
  64. // imgStyle: {
  65. // top: '100%',
  66. // left: px2vw(-250),
  67. // width: px2vw(401),
  68. // height: px2vw(227)
  69. // },
  70. // btnsStyle: {
  71. // bottom: '30px',
  72. // left: px2vw(-90),
  73. // },
  74. // boxStyle:{
  75. // borderRadius:'25px'
  76. // },
  77. // eleRectPadding:{
  78. // left:7,
  79. // top:7,
  80. // width:14,
  81. // height:14
  82. // }
  83. // },
  84. {
  85. ele: '',
  86. img: getImage('home3.png'),
  87. handStyle: {
  88. top: '-1.39rem',
  89. left: '0.17rem',
  90. transform: 'rotate(180deg)'
  91. },
  92. imgStyle: {
  93. top: px2vw(-4),
  94. width: px2vw(454),
  95. height: px2vw(227),
  96. left:px2vw(282)
  97. },
  98. btnsStyle: {
  99. bottom: '30px',
  100. left:px2vw(445)
  101. },
  102. boxStyle:{
  103. borderRadius: '20px'
  104. },
  105. eleRectPadding:{
  106. left:44,
  107. top:44,
  108. width:88,
  109. height:88
  110. }
  111. },
  112. {
  113. ele: '',
  114. img: getImage('home4.png'),
  115. handStyle: {
  116. top: '-1.39rem',
  117. left: '1.4rem',
  118. transform: 'rotate(180deg)'
  119. },
  120. imgStyle: {
  121. top: px2vw(-4),
  122. left: px2vw(-310),
  123. width: px2vw(477),
  124. height: px2vw(227),
  125. },
  126. btnsStyle: {
  127. bottom: '30px',
  128. left:px2vw(-147)
  129. },
  130. eleRectPadding:{
  131. left:7,
  132. top:7,
  133. width:14,
  134. height:14
  135. },
  136. boxStyle:{
  137. },
  138. },
  139. {
  140. ele: '',
  141. img: getImage('home5.png'),
  142. handStyle: {
  143. top: '-1.39rem',
  144. left: '1.4rem',
  145. transform: 'rotate(180deg)'
  146. },
  147. imgStyle: {
  148. top: '0',
  149. width: px2vw(600),
  150. height: px2vw(290),
  151. left: px2vw(18)
  152. },
  153. btnsStyle: {
  154. bottom: px2vw(80),
  155. left: px2vw(185),
  156. 'justify-content': 'center',
  157. padding: 0
  158. },
  159. eleRectPadding:{
  160. left:7,
  161. top:7,
  162. width:14,
  163. height:14
  164. },
  165. type:'bottom',
  166. boxStyle:{
  167. },
  168. }
  169. ],
  170. step: 0
  171. });
  172. const tipShow = ref(false);
  173. const guideInfo = ref({} as any)
  174. const getAllGuidance = async()=>{
  175. try{
  176. const res = await getGuidance({guideTag:'teacher-guideInfo'})
  177. if(res.data){
  178. guideInfo.value = JSON.parse(res.data?.guideValue) || null
  179. }else{
  180. guideInfo.value = {}
  181. }
  182. if (guideInfo.value && guideInfo.value.homeGuide) {
  183. tipShow.value = false;
  184. } else {
  185. tipShow.value = true;
  186. }
  187. }catch(e){
  188. console.log(e)
  189. }
  190. // const guideInfo = localStorage.getItem('teacher-guideInfo');
  191. }
  192. getAllGuidance()
  193. const getStepELe = () => {
  194. const ele: HTMLElement = document.getElementById(`home-${data.step}`)!;
  195. console.log(`coai-${data.step}`,data.steps[data.step].eleRectPadding);
  196. if (ele) {
  197. const eleRect = ele.getBoundingClientRect();
  198. const left = data.steps[data.step].eleRectPadding?.left || 0;
  199. const top = data.steps[data.step].eleRectPadding?.top || 0;
  200. const width = data.steps[data.step].eleRectPadding?.width || 0;
  201. const height = data.steps[data.step].eleRectPadding?.height || 0
  202. data.box = {
  203. left: eleRect.x - left+ 'px',
  204. top: eleRect.y - top +'px',
  205. width: eleRect.width + width+'px',
  206. height: eleRect.height +height+ 'px'
  207. };
  208. }else{
  209. handleNext()
  210. }
  211. };
  212. onMounted(() => {
  213. getStepELe();
  214. window.addEventListener("resize", resetSize);
  215. });
  216. const resetSize = ()=>{
  217. getStepELe();
  218. }
  219. onUnmounted(()=>{
  220. window.removeEventListener("resize", resetSize);
  221. })
  222. const handleNext = () => {
  223. if (data.step >= 3) {
  224. endGuide();
  225. return;
  226. }
  227. data.step = data.step + 1;
  228. getStepELe();
  229. }
  230. const endGuide = async () => {
  231. // let guideInfo =
  232. // JSON.parse(localStorage.getItem('teacher-guideInfo') || '{}') || null;
  233. if (!guideInfo.value) {
  234. guideInfo.value = { homeGuide: true };
  235. } else {
  236. guideInfo.value.homeGuide = true;
  237. }
  238. try{
  239. const res = await setGuidance({guideTag:'teacher-guideInfo',guideValue:JSON.stringify(guideInfo.value)})
  240. }catch(e){
  241. console.log(e)
  242. }
  243. // localStorage.setItem('teacher-guideInfo', JSON.stringify(guideInfo));
  244. tipShow.value = false;
  245. // localStorage.setItem('endC')
  246. };
  247. return () => (
  248. <>
  249. {tipShow.value ? (
  250. <div
  251. v-model:show={tipShow.value}
  252. class={['n-modal-mask', 'n-modal-mask-guide']}>
  253. <div class={styles.content} onClick={() => handleNext()}>
  254. <div
  255. class={styles.backBtn}
  256. onClick={(e: Event) => {
  257. e.stopPropagation();
  258. endGuide();
  259. }}>
  260. 跳过
  261. </div>
  262. <div
  263. class={styles.box}
  264. style={{...data.box,...data.steps[data.step].boxStyle}}
  265. id={`modeType-${data.step}`}>
  266. {data.steps.map((item: any, index) => (
  267. <div
  268. onClick={(e: Event) => e.stopPropagation()}
  269. class={styles.item}
  270. style={ item.type=='bottom'? {
  271. display: index === data.step ? '' : 'none',
  272. left: `${item.eleRect?.left}px`,
  273. top:`-${item.imgStyle?.height}`
  274. }:{
  275. display: index === data.step ? '' : 'none',
  276. left: `${item.eleRect?.left}px`,
  277. top: `${data.box?.height}`,
  278. }}>
  279. <img
  280. class={styles.img}
  281. style={item.imgStyle}
  282. src={item.img}
  283. />
  284. {/* <img
  285. class={styles.iconHead}
  286. style={item.handStyle}
  287. src={getImage('indexDot.png')}
  288. /> */}
  289. <div class={styles.btns} style={item.btnsStyle}>
  290. {data.step + 1 == data.steps.length ? (
  291. <>
  292. <div
  293. class={[styles.endBtn]}
  294. onClick={() => endGuide()}>
  295. 完成
  296. </div>
  297. <div
  298. class={styles.nextBtn}
  299. onClick={() => {
  300. data.step = 0;
  301. getStepELe();
  302. }}>
  303. 再看一遍
  304. </div>
  305. </>
  306. ) : (
  307. <div class={styles.btn} onClick={() => handleNext()}>
  308. 下一步 ({data.step + 1}/{data.steps.length})
  309. </div>
  310. )}
  311. </div>
  312. </div>
  313. ))}
  314. </div>
  315. </div>
  316. </div>
  317. ) : null}
  318. </>
  319. );
  320. }
  321. });