Przeglądaj źródła

管乐团后台选择小节

liushengqiang 2 lat temu
rodzic
commit
c0d7cdeb2b

BIN
src/page-orchestra/custom-plugins/guide-page/images/icon-hand2.png


BIN
src/page-orchestra/custom-plugins/guide-page/images/icon-header.png


+ 5 - 0
src/page-orchestra/custom-plugins/guide-page/images/index.ts

@@ -0,0 +1,5 @@
+const modules = (import.meta as any).globEager(`../images/**`)
+export const getImage = (name: string) => {
+    // console.log("🚀 ~ modules", modules[`../images/${name}`]?.default)
+    return modules[`../images/${name}`]?.default || ''
+}

BIN
src/page-orchestra/custom-plugins/guide-page/images/m1.png


BIN
src/page-orchestra/custom-plugins/guide-page/images/m2.png


BIN
src/page-orchestra/custom-plugins/guide-page/images/m3.png


BIN
src/page-orchestra/custom-plugins/guide-page/images/m4.png


BIN
src/page-orchestra/custom-plugins/guide-page/images/m5.png


BIN
src/page-orchestra/custom-plugins/guide-page/images/step0.png


BIN
src/page-orchestra/custom-plugins/guide-page/images/step1.png


BIN
src/page-orchestra/custom-plugins/guide-page/images/step2.png


+ 75 - 0
src/page-orchestra/custom-plugins/guide-page/index.module.less

@@ -0,0 +1,75 @@
+.tipsContainer {
+  background: transparent;
+  width: 100vw;
+  height: 100vh;
+  margin-left: 0;
+}
+.backBtn {
+  position: absolute;
+  left: 24px;
+  top: 12px;
+  padding: 4px 10px;
+  border-radius: 20px;
+  border: 1px solid #ffffff;
+  font-size: 6px;
+  color: #fff;
+  text-align: center;
+  &:active {
+    opacity: 0.8;
+  }
+}
+.content {
+  position: relative;
+  width: 100%;
+  height: 100%;
+}
+
+.parent {
+  position: absolute;
+  padding: 4px;
+  background: rgba(248, 249, 237, 1);
+  border-radius: 20px;
+  animation: myscale 1.5s infinite;
+  img {
+    width: 100%;
+    height: 100%;
+  }
+}
+.item {
+  position: absolute;
+  width: 128px;
+  z-index: 10;
+  .img {
+    position: absolute;
+    width: 100%;
+  }
+  .iconHead {
+    position: absolute;
+    left: 30px;
+    width: 15px;
+    height: 21px;
+  }
+  .btns {
+    position: absolute;
+    display: flex;
+    width: 100%;
+    padding: 0 12px;
+    .btn {
+      width: 51px;
+      height: 16px;
+      line-height: 16px;
+      padding: 0;
+    }
+  }
+}
+@keyframes myscale {
+  0% {
+    transform: scale(0.9);
+  }
+  50% {
+    transform: scale(1);
+  }
+  100% {
+    transform: scale(0.9);
+  }
+}

+ 67 - 0
src/page-orchestra/custom-plugins/guide-page/index.tsx

@@ -0,0 +1,67 @@
+import { Button, Popup } from 'vant'
+import {} from 'vant'
+import { defineComponent, nextTick, onMounted, reactive, ref, watch } from 'vue'
+import styles from './index.module.less'
+import Tip1 from './tip1'
+import Tip2 from './tip2'
+import { modelType } from '../buttons'
+import { useOriginSearch } from '../uses'
+
+export default defineComponent({
+  name: 'tips-step',
+  setup(props, ctx) {
+    const tipShow = ref(false)
+    const guide = reactive({
+      tipStep: 1,
+      tip1: false,
+      tip2: false,
+    })
+    watch(modelType, () => {
+      if (modelType.value !== 'practice') return
+      handleChange()
+    })
+    const setLocalData = (key: string) => {
+      localStorage.setItem(key, 'ok')
+    }
+    /** 触发器 */
+    const handleChange = () => {
+      const search = useOriginSearch()
+      // 如果为课后作业 和 单元测验 不引导
+      if (search.questionId || search.lessonTrainingId) {
+        return
+      }
+      const isFirstTip = localStorage.getItem('isFirstTip')
+      const isFirstModel = localStorage.getItem('isFirstModel')
+      if (modelType.value == 'init' && !isFirstTip) {
+        tipShow.value = true
+        guide.tipStep = 1
+      } else if (modelType.value == 'practice' && !isFirstModel) {
+        tipShow.value = true
+        guide.tipStep = 2
+      }
+    }
+    onMounted(() => {
+      handleChange()
+    })
+    return () => (
+      <Popup teleport="body" closeOnClickOverlay={false} class={styles.tipsContainer} v-model:show={tipShow.value}>
+        {guide.tipStep == 1 && (
+          <Tip1
+            onHanldeStop={() => {
+              tipShow.value = false
+              setLocalData('isFirstTip')
+            }}
+          />
+        )}
+        {guide.tipStep == 2 && (
+          <Tip2
+            onHanldeStop={() => {
+              tipShow.value = false
+              setLocalData('isFirstModel')
+            }}
+          />
+        )}
+      </Popup>
+    )
+  },
+})

+ 152 - 0
src/page-orchestra/custom-plugins/guide-page/tip1.tsx

@@ -0,0 +1,152 @@
+import { Button } from 'vant'
+import {} from 'vant'
+import { defineComponent, nextTick, onMounted, reactive, ref, watch } from 'vue'
+import styles from './index.module.less'
+import { getImage } from './images'
+
+export default defineComponent({
+  name: 'tips-tip1',
+  emits: ['hanldeStop'],
+  setup(props, { emit }) {
+    const contentRef = ref<HTMLElement>()
+    const data = reactive({
+      show: false,
+      steps: [
+        {
+          ele: '',
+          eleRect: {} as DOMRect,
+          img: getImage('step0.png'),
+          btnsStyle: {
+            top: '-2.13333rem',
+          },
+          handStyle: {
+            top: '-0.42667rem',
+          },
+          imgStyle: {
+            top: '-2.4rem',
+          },
+        },
+        {
+          ele: '',
+          img: getImage('step1.png'),
+          btnsStyle: {
+            top: '-2.2rem',
+          },
+          handStyle: {
+            top: '-0.42667rem',
+          },
+          imgStyle: {
+            top: '-2.4rem',
+          },
+        },
+        {
+          ele: '',
+          img: getImage('step2.png'),
+          btnsStyle: {
+            top: '-0.7rem',
+            left: '-2.5rem',
+            'justify-content': 'space-evenly',
+            padding: 0,
+          },
+          handStyle: {
+            top: '-0.42667rem',
+          },
+          imgStyle: {
+            top: '-2.7rem',
+            left: '-2.3rem',
+          },
+        },
+      ],
+      step: 0,
+    })
+
+    const getStepELe = () => {
+      for (let i = 0; i < data.steps.length; i++) {
+        const ele: HTMLElement = document.querySelector(`[data-step='step${i}']`)!
+        if (ele) {
+          const eleNode: any = ele.cloneNode(true)
+          const eleRect = ele.getBoundingClientRect()
+          const parentElement = document.createElement('div')
+          parentElement.classList.add(styles.parent)
+          parentElement.style.left = eleRect?.left - 10 + 'px'
+          parentElement.style.top = eleRect?.top - 10 + 'px'
+          parentElement.style.width = eleRect?.width + 20 + 'px'
+          parentElement.style.height = eleRect?.height + 20 + 'px'
+          parentElement.appendChild(eleNode)
+          data.steps[i].ele = parentElement.outerHTML
+          data.steps[i].eleRect = eleRect
+        }
+      }
+      // console.log(data.steps)
+    }
+    onMounted(() => {
+      getStepELe()
+    })
+
+    const handleNext = (step?: number) => {
+      if (step !== undefined) {
+        data.step = step
+      } else {
+        if (data.step + 1 >= data.steps.length) {
+          handleStop()
+          return
+        }
+        data.step += 1
+      }
+    }
+    const handleStop = () => {
+      emit('hanldeStop')
+    }
+    return () => (
+      <div class={styles.content} ref={contentRef} onClick={() => handleNext()}>
+        <div
+          class={styles.backBtn}
+          onClick={(e: Event) => {
+            e.stopPropagation()
+            handleStop()
+          }}
+        >
+          跳过引导
+        </div>
+        {data.steps.map((item: any, index) => (
+          <div style={{ display: index === data.step ? 'block' : 'none' }} onClick={(e: Event) => e.stopPropagation()}>
+            <div
+              class={styles.item}
+              style={{
+                left: `${item.eleRect?.left}px`,
+                top: `${item.eleRect?.top}px`,
+              }}
+            >
+              <img class={styles.img} style={item.imgStyle} src={item.img} />
+              <img class={styles.iconHead} style={item.handStyle} src={getImage('icon-header.png')} />
+              <div class={styles.btns} style={item.btnsStyle}>
+                {data.step + 1 == data.steps.length ? (
+                  <>
+                    <Button
+                      class={styles.btn}
+                      round
+                      color="transparent"
+                      style={{ 'border-color': '#fff' }}
+                      type="primary"
+                      onClick={() => handleNext(0)}
+                    >
+                      再看一遍
+                    </Button>
+                    <Button class={styles.btn} round type="primary" onClick={() => handleStop()}>
+                      完成
+                    </Button>
+                  </>
+                ) : (
+                  <Button class={styles.btn} round type="primary" onClick={() => handleNext()}>
+                    下一步 ({data.step + 1}/{data.steps.length})
+                  </Button>
+                )}
+              </div>
+            </div>
+            <div innerHTML={item.ele}></div>
+          </div>
+        ))}
+      </div>
+    )
+  },
+})

+ 199 - 0
src/page-orchestra/custom-plugins/guide-page/tip2.tsx

@@ -0,0 +1,199 @@
+import { Button, Popup } from 'vant'
+import {} from 'vant'
+import { defineComponent, nextTick, onMounted, reactive, ref, watch } from 'vue'
+import styles from './index.module.less'
+import { getImage } from './images'
+
+export default defineComponent({
+  name: 'tips-tip1',
+  emits: ['hanldeStop'],
+  setup(props, { emit }) {
+    const contentRef = ref<HTMLElement>()
+    const data = reactive({
+      show: false,
+      step: 0,
+      steps: [
+        {
+          ele: '',
+          eleRect: {} as DOMRect,
+          img: getImage('m1.png'),
+          btnsStyle: {
+            top: '2.4rem',
+            left: '-0.1rem'
+          },
+          handStyle: {
+            top: '0.6rem',
+            left: '0.1rem',
+          },
+          imgStyle: {
+            top: '0.6rem',
+            left: '-0.2rem',
+          },
+        },
+        {
+          ele: '',
+          eleRect: {} as DOMRect,
+          img: getImage('m2.png'),
+          btnsStyle: {
+            top: '2.2rem',
+          },
+          handStyle: {
+            top: '0.6rem',
+            left: '0.1rem',
+          },
+          imgStyle: {
+            width: '2.6rem',
+            top: '0.6rem',
+            left: '-0.2rem',
+          },
+        },
+        {
+          img: getImage('m3.png'),
+          btnsStyle: {
+            top: '2.6rem',
+          },
+          handStyle: {
+            top: '0.6rem',
+            left: '0.1rem',
+          },
+          imgStyle: {
+            width: '2.45333rem',
+            top: '0.6rem',
+            left: '-0.2rem',
+          },
+        },
+        {
+          ele: '',
+          eleRect: {} as DOMRect,
+          img: getImage('m4.png'),
+          btnsStyle: {
+            top: '2.5rem',
+            left: '-1.5rem',
+          },
+          handStyle: {
+            top: '0.6rem',
+            left: '0.1rem',
+          },
+          imgStyle: {
+            width: '2.45333rem',
+            top: '0.6rem',
+            left: '-1.7rem',
+          },
+        },
+        {
+          ele: '',
+          eleRect: {} as DOMRect,
+          img: getImage('m5.png'),
+          btnsStyle: {
+            top: '2.2rem',
+            left: '-2rem',
+            width: '2.93333rem',
+            'justify-content': 'space-evenly',
+            padding: 0,
+          },
+          handStyle: {
+            top: '0.6rem',
+            left: '0.1rem',
+          },
+          imgStyle: {
+            top: '0.4rem',
+            left: '-2rem',
+            width: '2.93333rem',
+          },
+        },
+      ],
+    })
+    const getStepELe = () => {
+      for (let i = 0; i < data.steps.length; i++) {
+        const ele: HTMLElement = document.querySelector(`[data-step='m${i}']`)!
+        if (ele) {
+          const eleNode: any = ele.cloneNode(true)
+          const eleRect = ele.getBoundingClientRect()
+          const parentElement = document.createElement('div')
+          parentElement.classList.add(styles.parent)
+          parentElement.style.left = eleRect?.left - 10 + 'px'
+          parentElement.style.top = '0'
+          parentElement.style.borderRadius = '0.1rem'
+          parentElement.appendChild(eleNode)
+          data.steps[i].ele = parentElement.outerHTML
+          data.steps[i].eleRect = eleRect
+        }
+      }
+    }
+    onMounted(() => {
+      getStepELe()
+    })
+
+    const handleNext = (step?: number) => {
+      if (step !== undefined) {
+        data.step = step
+      } else {
+        if (data.step + 1 >= data.steps.length) {
+          handleStop()
+          return
+        }
+        data.step += 1
+      }
+    }
+    const handleStop = () => {
+      emit('hanldeStop')
+    }
+    return () => {
+      return (
+        <div class={styles.content} ref={contentRef} onClick={() => handleNext()}>
+          <div
+            class={styles.backBtn}
+            onClick={(e: Event) => {
+              e.stopPropagation()
+              handleStop()
+            }}
+          >
+            跳过引导
+          </div>
+          {data.steps.map((item: any, index: number) => (
+            <div
+              style={{ display: index === data.step ? 'block' : 'none' }}
+              onClick={(e: Event) => e.stopPropagation()}
+            >
+              <div
+                onClick={(e: Event) => e.stopPropagation()}
+                class={styles.item}
+                style={{
+                  width: '2.18667rem',
+                  left: `${item.eleRect?.left}px`,
+                }}
+              >
+                <img class={styles.img} style={item.imgStyle} src={item.img} />
+                <img class={styles.iconHead} style={item.handStyle} src={getImage('icon-hand2.png')} />
+                <div class={styles.btns} style={item.btnsStyle}>
+                  {data.step + 1 == data.steps.length ? (
+                    <>
+                      <Button
+                        class={styles.btn}
+                        round
+                        color="transparent"
+                        style={{ 'border-color': '#fff' }}
+                        type="primary"
+                        onClick={() => handleNext(0)}
+                      >
+                        再看一遍
+                      </Button>
+                      <Button class={styles.btn} round type="primary" onClick={() => handleStop()}>
+                        完成
+                      </Button>
+                    </>
+                  ) : (
+                    <Button class={styles.btn} round type="primary" onClick={() => handleNext()}>
+                      下一步 ({data.step + 1}/{data.steps.length})
+                    </Button>
+                  )}
+                </div>
+              </div>
+              <div innerHTML={item.ele}></div>
+            </div>
+          ))}
+        </div>
+      )
+    }
+  },
+})