Browse Source

挪动家长签到

lex-xin 5 months ago
parent
commit
a09c782fa1
31 changed files with 2370 additions and 0 deletions
  1. 24 0
      src/router/router-root.ts
  2. 110 0
      src/views/pre-register-active/compontent-show/active-show.tsx
  3. 227 0
      src/views/pre-register-active/compontent-show/register-show.module.less
  4. 210 0
      src/views/pre-register-active/compontent-show/register-show.tsx
  5. 260 0
      src/views/pre-register-active/compontent-show/video-show.tsx
  6. BIN
      src/views/pre-register-active/images/banner.png
  7. BIN
      src/views/pre-register-active/images/flow-path-bg.png
  8. BIN
      src/views/pre-register-active/images/flow-path-title.png
  9. BIN
      src/views/pre-register-active/images/icon-connect.png
  10. BIN
      src/views/pre-register-active/images/message-bg.png
  11. BIN
      src/views/pre-register-active/images/pre-btn.png
  12. BIN
      src/views/pre-register-active/images/preRegister/banner.png
  13. BIN
      src/views/pre-register-active/images/preRegister/btn.png
  14. BIN
      src/views/pre-register-active/images/preRegister/p-popup-banner.png
  15. BIN
      src/views/pre-register-active/images/preRegister/p-popup-btn.png
  16. BIN
      src/views/pre-register-active/images/preRegister/tips.png
  17. BIN
      src/views/pre-register-active/images/signin-bg.png
  18. BIN
      src/views/pre-register-active/images/signin-btn.png
  19. BIN
      src/views/pre-register-active/images/signin-tips.png
  20. BIN
      src/views/pre-register-active/images/top_title.png
  21. BIN
      src/views/pre-register-active/images/video-bg.png
  22. BIN
      src/views/pre-register-active/images/video-count.png
  23. BIN
      src/views/pre-register-active/images/video-path-title.png
  24. BIN
      src/views/pre-register-active/images/video-speed.png
  25. BIN
      src/views/pre-register-active/images/video-speed1.png
  26. BIN
      src/views/pre-register-active/images/video_bg.png
  27. 166 0
      src/views/pre-register-active/index.module.less
  28. 383 0
      src/views/pre-register-active/index.tsx
  29. 36 0
      src/views/pre-register-active/show.tsx
  30. 250 0
      src/views/pre-register-active/video.module.less
  31. 704 0
      src/views/pre-register-active/video.tsx

+ 24 - 0
src/router/router-root.ts

@@ -280,6 +280,30 @@ export default [
     }
   },
   {
+    path: '/pre-register-active',
+    name: 'pre-register-active',
+    component: () => import('@/views/pre-register-active/index'),
+    meta: {
+      title: '管乐团组建家长会'
+    }
+  },
+  {
+    path: '/pre-register-video',
+    name: 'pre-register-video',
+    component: () => import('@/views/pre-register-active/video'),
+    meta: {
+      title: '管乐团组建家长会'
+    }
+  },
+  {
+    path: '/pre-register-show',
+    name: 'pre-register-show',
+    component: () => import('@/views/pre-register-active/show'),
+    meta: {
+      title: '管乐团组建家长会'
+    }
+  },
+  {
     path: '/:pathMatch(.*)*',
     component: () => import('@/views/404'),
     meta: {

+ 110 - 0
src/views/pre-register-active/compontent-show/active-show.tsx

@@ -0,0 +1,110 @@
+import { defineComponent, nextTick, onMounted, onUnmounted, ref } from 'vue'
+import styles from '../index.module.less'
+import signinTips from '../images/signin-tips.png'
+import { Button, CellGroup, Field } from 'vant'
+
+export default defineComponent({
+  name: 'pre-register',
+  emits: ['tabChange'],
+  setup(props, { emit }) {
+    const messageContent = ref('')
+    const onSubmit = () => {
+      // emit('tabChange', 2)
+    }
+
+    const getMessage = (ev: any) => {
+      if (ev.data.api === 'parent-agenda') {
+        messageContent.value = ev.data.message || ''
+      }
+    }
+
+    onMounted(() => {
+      nextTick(() => {
+        // 是否加载完成
+        window.parent &&
+          window.parent.postMessage(
+            {
+              api: 'onLoad',
+              status: true
+            },
+            '*'
+          )
+      })
+
+      window.addEventListener('message', getMessage)
+    })
+
+    onUnmounted(() => {
+      window.removeEventListener('message', getMessage)
+    })
+    return () => (
+      <div class={styles['per-register-active']}>
+        <div class={styles.flowPath}>
+          <i class={styles.flowPathTitle}></i>
+          <div class={styles.flowPathContent} v-html={messageContent.value}>
+            {/* 一、请所有家长进行<span>签到</span>
+            <br />
+            二、<span>观看</span>管乐团家长会议
+            <br />
+            1、学校领导讲话(5分钟)
+            <br />
+            2、基金会老师介绍乐团事项(20分钟)
+            <br />
+            <p
+              style={{
+                'padding-left': '1em'
+              }}
+            >
+              *乐团组建背景及政策
+              <br />
+              *乐团发展规划与乐器知识讲解
+              <br />
+              *学校/基金会/家长各方职责与投入
+              <br />
+              *入团流程讲解
+            </p>
+            三、请
+            <span>“有意向”</span>让孩子加入乐团的家长点击
+            <span>“乐团报名”</span>完成信息填报 */}
+          </div>
+        </div>
+
+        <div class={styles.signin}>
+          <div class={styles.tips}>
+            <img src={signinTips} class={styles.signinTips} />
+            <p>
+              请先进行<span>签到</span>,再观看<span>管乐团家长会视频</span>
+            </p>
+          </div>
+
+          <CellGroup class={styles.cellGroup} border={false}>
+            <Field
+              label="学生姓名"
+              labelAlign="top"
+              placeholder="请输入学生姓名"
+              autocomplete="off"
+            />
+            <Field
+              label="年级"
+              labelAlign="top"
+              placeholder="请选择年级"
+              isLink
+              readonly
+              clickable={false}
+            />
+            <Field
+              label="班级"
+              labelAlign="top"
+              placeholder="请选择班级"
+              isLink
+              readonly
+              clickable={false}
+            />
+
+            <Button class={styles.submitBtn} onClick={onSubmit}></Button>
+          </CellGroup>
+        </div>
+      </div>
+    )
+  }
+})

+ 227 - 0
src/views/pre-register-active/compontent-show/register-show.module.less

@@ -0,0 +1,227 @@
+.registerShow {
+  background: url('../images/preRegister/banner.png') no-repeat top center #C7F4FF;
+  background-size: contain;
+  max-width: 750px;
+  margin: 0 auto;
+  min-height: 100vh;
+  overflow: hidden;
+  position: relative;
+
+
+  :global {
+    .van-cell {
+      flex-direction: column;
+      font-size: 16px;
+      padding: 14px 13px;
+    }
+
+    .van-field__label {
+      width: 100%;
+      margin-right: 0;
+      color: #333;
+      font-size: 16px;
+      font-weight: 500;
+    }
+
+    .van-field--disabled .van-field__label {
+      color: #333;
+    }
+
+    .van-cell--required::before {
+      left: 15px;
+    }
+
+    .van-field__body {
+      margin-top: 10px;
+    }
+
+    .cell-group {
+      margin: 0 13px 12px;
+      border-radius: 10px;
+      padding-bottom: 20px;
+    }
+
+    .van-form {
+      overflow: hidden;
+    }
+  }
+}
+
+.banner,
+.banner img {
+  width: 100%;
+  font-size: 0;
+}
+
+
+.btn-submit {
+  width: 90%;
+  margin: 20px auto;
+  background: url('../images/preRegister/btn.png') no-repeat center;
+  background-size: contain;
+  height: 52px;
+  border: none;
+}
+
+.system h2 {
+  font-size: 18px;
+  font-weight: 500;
+  margin: 10px 24px;
+  color: #444444;
+}
+
+.system .van-cell--required::before {
+  left: 25px;
+}
+
+.top-tips {
+  position: relative;
+  margin: 20px 12px 20px;
+  padding: 40px 18px 20px;
+  background: #FFFFFF;
+  border-radius: 10px;
+  font-size: 12px;
+  color: #777777;
+  line-height: 20px;
+}
+
+.top-tips::before {
+  position: absolute;
+  top: -6px;
+  left: 50%;
+  content: ' ';
+  margin-left: -62.5px;
+  width: 125px;
+  height: 32px;
+  background: url('../images/preRegister/tips.png') no-repeat center;
+  background-size: contain;
+}
+
+.title {
+  font-size: 22px;
+  line-height: 32px;
+  color: #ffffff;
+  width: 57%;
+  padding-left: 24px;
+  height: 148px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 1;
+}
+
+
+.radioSection {
+  position: relative;
+  font-size: 14px;
+  min-width: 32px;
+  justify-content: center;
+}
+
+.radioItem {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  opacity: 0;
+}
+
+.radioSection+.radioSection {
+  margin-left: 12px;
+}
+
+.van-picker__confirm {
+  color: #57ABF8;
+}
+
+.otherSubject {
+  font-size: 12px;
+  font-weight: 500;
+  color: #AAAAAA;
+  line-height: 17px;
+  padding-bottom: 13px;
+}
+
+/* 弹窗 */
+.submit-container {
+  position: relative;
+  text-align: center;
+  margin: 0 auto;
+  background: url('../images/preRegister/p-popup-banner.png') no-repeat top center;
+  background-size: contain;
+  width: 7.5rem;
+  height: 8.87rem;
+}
+
+.submit-title {
+  padding-top: 4.2rem;
+  padding-bottom: 10px;
+  font-size: 18px;
+  font-weight: 500;
+  color: #000000;
+}
+
+.submit-tips {
+  font-size: 15px;
+  color: #777777;
+  line-height: 20px;
+  padding-bottom: 12px;
+}
+
+.submit-btn {
+  background: url('../images/preRegister/p-popup-btn.png') no-repeat center center;
+  background-size: contain;
+  width: 3.547rem;
+  height: 1rem;
+  margin: 0 auto;
+}
+
+.submit-container .van-button {
+  font-size: 18px;
+  font-weight: 500;
+}
+
+
+
+.wxPopupDialog {
+  overflow: initial;
+}
+
+.wxPopupDialog::before {
+  position: absolute;
+  content: ' ';
+  top: -73px;
+  left: 50%;
+  margin-left: -86px;
+  display: inline-block;
+  background: url('../images/initiation/wx-no-top.png') no-repeat top center;
+  background-size: contain;
+  width: 172px;
+  height: 154px;
+}
+
+.popupContainer {
+  background: url('../images/initiation/wx-no-bg.png') no-repeat top center;
+  background-size: cover;
+  border-radius: 20px;
+  overflow: hidden;
+
+}
+
+.popupContainer .title1 {
+  padding-top: 57px;
+  text-align: center;
+  font-size: 18px;
+  font-weight: 500;
+  color: #3b2300;
+}
+
+.popupContainer .popupTips {
+  padding-top: 12px;
+  padding-bottom: 47px;
+  text-align: center;
+  font-size: 15px;
+  color: #777777;
+  line-height: 21px;
+}

+ 210 - 0
src/views/pre-register-active/compontent-show/register-show.tsx

@@ -0,0 +1,210 @@
+import { defineComponent, reactive } from 'vue'
+import styles from './register-show.module.less'
+import { Button, CellGroup, Field, Form, Icon, Radio, RadioGroup, Tag } from 'vant'
+import { useRoute } from 'vue-router'
+
+export default defineComponent({
+  name: 'register-show',
+  setup() {
+    const route = useRoute()
+    const forms = reactive({
+      instrumentPriceImg: route.query.instrumentPriceImg,
+      name: route.query.name
+    })
+    return () => (
+      <div class={styles.registerShow}>
+        <div class={styles.title}>{forms.name}管乐团报名申请</div>
+
+        <Form validateFirst scrollToError ref="form" class={styles.form}>
+          <div class={styles['top-tips']}>
+            1、为了保障乐团顺利组建,避免名额浪费;请家长与孩子以自愿为原则,在确认意向后填写相关信息;专业老师将根据家长的相关填报,确认孩子是否能够加入乐团;
+            <br />
+            2、自用乐器及课后练习,家长自愿选择准备方式。
+          </div>
+          <CellGroup inset class={styles['cell-group']}>
+            <Field labelAlign="top" label="性别" name="sex">
+              {{
+                input: () => (
+                  <RadioGroup checkedColor="#57ABF8" direction="horizontal">
+                    <Tag
+                      size="large"
+                      type="primary"
+                      color={'#57ABF8'}
+                      textColor="#FFF"
+                      class={styles['radioSection']}
+                    >
+                      <Radio class={styles['radioItem']} name={1} />
+                      男生
+                    </Tag>
+
+                    <Tag
+                      size="large"
+                      type="primary"
+                      color={'#EAEAEA'}
+                      textColor="#AAA"
+                      class={styles['radioSection']}
+                    >
+                      <Radio class={styles['radioItem']} name={0} />
+                      女生
+                    </Tag>
+                  </RadioGroup>
+                )
+              }}
+            </Field>
+            <Field
+              labelAlign="top"
+              label="孩子是否有学习过的乐器(有请备注)"
+              name="learningSubjectName"
+              placeholder="请输入学习过的乐器"
+            ></Field>
+
+            <Field
+              labelAlign="top"
+              label="选报声部1"
+              readonly
+              name="registerSubjectId"
+              placeholder="请选择选报声部1"
+            >
+              {{
+                'right-icon': () => <Icon name="arrow" color="#323233" size="16"></Icon>
+              }}
+            </Field>
+            <Field
+              labelAlign="top"
+              label="选报声部2"
+              readonly
+              name="standbyRegisterSubjectId"
+              placeholder="请选择选报声部2"
+            >
+              {{
+                'right-icon': () => <Icon name="arrow" color="#323233" size="16"></Icon>
+              }}
+            </Field>
+
+            <Field labelAlign="top" label="是否服从调配" name="adjust">
+              {{
+                input: () => (
+                  <div>
+                    <p class={styles.otherSubject}>
+                      (如果自选声部名额已满,是否愿意接受安排其他声部?)
+                    </p>
+
+                    <RadioGroup checked-color="#57ABF8" direction="horizontal">
+                      <Tag
+                        size="large"
+                        type="primary"
+                        color={'#57ABF8'}
+                        textColor="#FFF"
+                        class={styles['radioSection']}
+                      >
+                        <Radio class={styles['radioItem']} name={1} />
+                        愿意
+                      </Tag>
+                      <Tag
+                        size="large"
+                        type="primary"
+                        color={'#EAEAEA'}
+                        textColor="#AAA"
+                        class={styles['radioSection']}
+                      >
+                        <Radio class={styles['radioItem']} name={0} />
+                        不愿意
+                      </Tag>
+                    </RadioGroup>
+                  </div>
+                )
+              }}
+            </Field>
+          </CellGroup>
+
+          <CellGroup inset class={styles['cell-group']}>
+            <Field
+              labelAlign="top"
+              label="乐器参考表&Ai练习参考表"
+              border={false}
+              style="padding-bottom: 0;"
+            >
+              {{
+                input: () => <img src={forms.instrumentPriceImg as any} style="width: 100%" />
+              }}
+            </Field>
+
+            <Field labelAlign="top" label="乐器准备方式" name="instrumentsPrepareMode">
+              {{
+                input: () => (
+                  <RadioGroup checked-color="#57ABF8" direction="horizontal">
+                    <Tag
+                      size="large"
+                      type="primary"
+                      color={'#57ABF8'}
+                      textColor="#FFF"
+                      class={styles['radioSection']}
+                    >
+                      <Radio class={styles['radioItem']} name={1} />
+                      自行购置
+                    </Tag>
+                    <Tag
+                      size="large"
+                      type="primary"
+                      color={'#EAEAEA'}
+                      textColor="#AAA"
+                      class={styles['radioSection']}
+                    >
+                      <Radio class={styles['radioItem']} name={0} />
+                      希望基金会提供渠道购置
+                    </Tag>
+                  </RadioGroup>
+                )
+              }}
+            </Field>
+
+            <Field labelAlign="top" label="乐团学习系统准备方式" name="learningSystemPrepareMode">
+              {{
+                input: () => (
+                  <RadioGroup checked-color="#57ABF8" direction="horizontal">
+                    <Tag
+                      size="large"
+                      type="primary"
+                      color={'#57ABF8'}
+                      textColor="#FFF"
+                      class={styles['radioSection']}
+                    >
+                      <Radio class={styles['radioItem']} name={1} />
+                      自行购置
+                    </Tag>
+                    <Tag
+                      size="large"
+                      type="primary"
+                      color={'#EAEAEA'}
+                      textColor="#AAA"
+                      class={styles['radioSection']}
+                    >
+                      <Radio class={styles['radioItem']} name={0} />
+                      希望基金会提供渠道购置
+                    </Tag>
+                  </RadioGroup>
+                )
+              }}
+            </Field>
+
+            <Field
+              labelAlign="top"
+              type="tel"
+              label="联系电话(直接监护人)"
+              name="phone"
+              placeholder="请输入监护人手机号码"
+            ></Field>
+          </CellGroup>
+
+          <Button
+            size="large"
+            block
+            round
+            class={styles['btn-submit']}
+            native-type="submit"
+          ></Button>
+        </Form>
+      </div>
+    )
+  }
+})

+ 260 - 0
src/views/pre-register-active/compontent-show/video-show.tsx

@@ -0,0 +1,260 @@
+import { defineComponent, nextTick, onMounted, onUnmounted, reactive, ref, watch } from 'vue'
+import styles from '../video.module.less'
+import { Button } from 'vant'
+import { browser } from '@/helpers/utils'
+// import Plyr from 'plyr'
+// import 'plyr/dist/plyr.css'
+import { useRoute } from 'vue-router'
+import deepClone from '@/helpers/deep-clone'
+import TCPlayer from 'tcplayer.js'
+import 'tcplayer.js/dist/tcplayer.css'
+
+export default defineComponent({
+  name: 'pre-register',
+  emits: ['tabChange'],
+  setup(props, { emit }) {
+    const route = useRoute()
+    const video = route.query.v ? JSON.parse(route.query.v as any) : []
+    console.log(route.query, 'query')
+    const forms = reactive({
+      coverImg: route.query.coverImg,
+      videoID: 'video' + Date.now() + Math.floor(Math.random() * 100),
+      introductionVideo: route.query.introductionVideo as any,
+      id: null as any,
+      videoDetails: deepClone(video),
+      player: null as any,
+      currentTime: 0
+    })
+
+    /**
+     * 视屏累计时长
+     * 1、视屏开始播放时-开始计时
+     * 2、视频暂停时暂停-停止计时
+     * 3、视频加载时-停止计时
+     * 4、视频倍数播放时,时间正常计时
+     * 5、点击视频进度或拖动进度时,时间暂停
+     */
+    const _init = () => {
+      // const controls = [
+      //   'play-large',
+      //   'play',
+      //   'progress',
+      //   'captions',
+      //   'current-time',
+      //   'duration',
+      //   'settings',
+      //   'fullscreen'
+      // ]
+      // const params: any = {
+      //   controls: controls,
+      //   settings: ['speed'],
+      //   speed: { selected: 1, options: [0.5, 1, 1.5, 2] },
+      //   i18n: {
+      //     speed: '速度',
+      //     normal: '默认'
+      //   },
+      //   invertTime: false
+      // }
+
+      // if (browser().iPhone) {
+      //   params.fullscreen = {
+      //     enabled: true,
+      //     fallback: 'force',
+      //     iosNative: true
+      //   }
+      // }
+
+      // const times: any = []
+      // deepClone(forms.videoDetails).forEach((item: any) => {
+      //   times.push({
+      //     time: item.startNode,
+      //     label: item.desc
+      //   })
+      // })
+      // params.markers = { enabled: true, points: times }
+
+      // forms.player = new Plyr('#register-video', params)
+
+      // forms.player.on('loadedmetadata', () => {
+      //   checkVideoDetails(forms.player.currentTime)
+      // })
+
+      // // 如何视频在缓存不会触发
+      // forms.player.on('timeupdate', (e: any) => {
+      //   // 时间变化时更新每一段的状态
+      //   console.log(forms.player.currentTime, 'forms.player.currentTime', e)
+      //   checkVideoDetails(forms.player.currentTime)
+      // })
+
+      // forms.player.on('enterfullscreen', () => {
+      //   console.log('fullscreen')
+      //   const i = document.createElement('i')
+      //   i.id = 'fullscreen-back'
+      //   i.className = 'van-icon van-icon-arrow-left video-back'
+      //   i.addEventListener('click', () => {
+      //     forms.player.fullscreen.exit()
+      //   })
+      //   console.log(document.getElementsByClassName('plyr'))
+      //   document.getElementsByClassName('plyr')[0].appendChild(i)
+      // })
+
+      // forms.player.on('exitfullscreen', () => {
+      //   console.log('exitfullscreen')
+      //   const i = document.getElementById('fullscreen-back')
+      //   i && i.remove()
+      // })
+      const Button = TCPlayer.getComponent('Button')
+      const BigPlayButton = TCPlayer.getComponent('BigPlayButton')
+      BigPlayButton.prototype.createEl = function () {
+        const el = Button.prototype.createEl.call(this)
+        const _html =
+          '<button><svg width="41px"height="41px"viewBox="0 0 41 41"version="1.1"xmlns="http://www.w3.org/2000/svg"xmlns:xlink="http://www.w3.org/1999/xlink"><g stroke="none"stroke-width="1"fill="none"fill-rule="evenodd"><g transform="translate(-167.000000, -155.000000)"><g transform="translate(0.000000, 85.000000)"><g transform="translate(158.000000, 70.000000)"><g transform="translate(9.000000, 0.000000)"><circle id="椭圆形"stroke="#FFFFFF"fill-opacity="0.1"fill="#D8D8D8"cx="20.5"cy="20.5"r="20"></circle><path d="M14.5483871,27.6859997 L14.5483871,13.4342349 C14.5480523,12.8729571 14.8729597,12.356555 15.3949624,12.0887034 C15.9169651,11.8208518 16.5522696,11.8445472 17.0503046,12.1504437 L28.6530473,19.2778563 C29.1119763,19.5602271 29.3887725,20.0426422 29.3887725,20.5601173 C29.3887725,21.0775924 29.1119763,21.5600075 28.6530473,21.8423783 L17.0503046,28.9697909 C16.5522696,29.2756874 15.9169651,29.2993828 15.3949624,29.0315312 C14.8729597,28.7636796 14.5480523,28.2472775 14.5483871,27.6859997 Z"id="路径"fill="#FFFFFF"fill-rule="nonzero"></path></g></g></g></g></g></svg></button>'
+
+        el.appendChild(
+          TCPlayer.dom.createEl('div', {
+            className: 'vjs-button-icon',
+            innerHTML: _html
+          })
+        )
+        return el
+      }
+      forms.player = TCPlayer('register-video', {
+        appID: '',
+        controls: true,
+        plugins: {
+          ProgressMarker: true
+        }
+      }) // player-container-id 为播放器容器 ID,必须与 html 中一致
+      if (forms.player) {
+        forms.player.src(forms.introductionVideo) // url 播放地址
+        forms.player.poster(forms.coverImg || '')
+
+        forms.player.on('loadedmetadata', () => {
+          checkVideoDetails(forms.player.currentTime())
+        })
+
+        // 如何视频在缓存不会触发
+        forms.player.on('timeupdate', (e: any) => {
+          // 时间变化时更新每一段的状态
+          console.log(forms.player.currentTime(), 'forms.player.currentTime()', e)
+          checkVideoDetails(forms.player.currentTime())
+        })
+
+        forms.player.on('fullscreenchange', () => {
+          if (forms.player.isFullscreen()) {
+            console.log('fullscreen')
+            const i = document.createElement('i')
+            i.id = 'fullscreen-back'
+            i.className = 'van-icon van-icon-arrow-left video-back'
+            i.addEventListener('click', () => {
+              forms.player.exitFullscreen()
+            })
+            document.getElementsByClassName('video-js')[0].appendChild(i)
+          } else {
+            console.log('exitfullscreen')
+            const i = document.getElementById('fullscreen-back')
+            i && i.remove()
+          }
+        })
+      }
+    }
+
+    const checkVideoDetails = (time: number) => {
+      forms.videoDetails.forEach((item: any) => {
+        if (item.startNode <= time && time <= item.endNode) {
+          forms.id = item.id
+        }
+      })
+    }
+    onMounted(() => {
+      nextTick(() => {
+        _init()
+      })
+    })
+
+    const onSubmit = () => {
+      // emit('tabChange', 3)
+    }
+
+    const messageContent = ref('')
+    const registerDisplay = ref()
+
+    const getMessage = (ev: any) => {
+      if (ev.data.api === 'parent-notes') {
+        console.log(ev.data, 'data')
+        messageContent.value = ev.data.message || ''
+        registerDisplay.value = ev.data.registerDisplay || false
+      }
+    }
+    onMounted(() => {
+      nextTick(() => {
+        // 是否加载完成
+        window.parent &&
+          window.parent.postMessage(
+            {
+              api: 'onLoad',
+              status: true
+            },
+            '*'
+          )
+      })
+
+      window.addEventListener('message', getMessage)
+    })
+
+    onUnmounted(() => {
+      window.removeEventListener('message', getMessage)
+    })
+    return () => (
+      <div class={styles['pre-register-video']}>
+        <div class={styles.videoContainer}>
+          <div class={styles['video-content']}>
+            {/* <video
+              id="register-video"
+              class={styles['video']}
+              src={forms.introductionVideo}
+              playsinline={true}
+              poster={forms.coverImg as any}
+              preload="auto"
+            ></video> */}
+            <img src={forms.coverImg as any} class={styles.coverImg} />
+          </div>
+        </div>
+        <div class={styles.videoCount}>
+          <div class={styles.videoTitle}></div>
+          <div class={styles.videoCountContent}>
+            {forms.videoDetails.map((item: any) => (
+              <span
+                class={[item.id === forms.id ? styles.active : '']}
+                onClick={() => {
+                  forms.player.currentTime(item.startNode)
+                }}
+              >
+                {item.desc}
+              </span>
+            ))}
+          </div>
+        </div>
+        <div class={styles.messageContainer}>
+          <div class={styles.messageContent}>
+            {/* <p>家长您好!</p>
+            <p class={styles.c1}>
+              请家长们合理安排时间,<span>认真观看</span>家长会内容。在<span>详细了解</span>
+              所有要求后,有意向让孩子加入乐团的家长,请在<span>明晚20:00前</span>,为孩子完成
+              <span>乐团报名</span>
+            </p>
+            <p class={styles.c1}>
+              下周,专业老师将针对意向入团学员进行身体条件确认。谢谢各位的支持!
+            </p>
+            <p class={styles.bottom}>
+              注:乐团于下学期正式开始训练,训练时间下 学期开学前另行通知,训练时间会与学校其他
+              社团错开,家长无需担心时间冲突问题。
+            </p> */}
+            <div v-html={messageContent.value}></div>
+            {registerDisplay.value && <Button class={styles.submitBtn} onClick={onSubmit}></Button>}
+          </div>
+        </div>
+      </div>
+    )
+  }
+})

BIN
src/views/pre-register-active/images/banner.png


BIN
src/views/pre-register-active/images/flow-path-bg.png


BIN
src/views/pre-register-active/images/flow-path-title.png


BIN
src/views/pre-register-active/images/icon-connect.png


BIN
src/views/pre-register-active/images/message-bg.png


BIN
src/views/pre-register-active/images/pre-btn.png


BIN
src/views/pre-register-active/images/preRegister/banner.png


BIN
src/views/pre-register-active/images/preRegister/btn.png


BIN
src/views/pre-register-active/images/preRegister/p-popup-banner.png


BIN
src/views/pre-register-active/images/preRegister/p-popup-btn.png


BIN
src/views/pre-register-active/images/preRegister/tips.png


BIN
src/views/pre-register-active/images/signin-bg.png


BIN
src/views/pre-register-active/images/signin-btn.png


BIN
src/views/pre-register-active/images/signin-tips.png


BIN
src/views/pre-register-active/images/top_title.png


BIN
src/views/pre-register-active/images/video-bg.png


BIN
src/views/pre-register-active/images/video-count.png


BIN
src/views/pre-register-active/images/video-path-title.png


BIN
src/views/pre-register-active/images/video-speed.png


BIN
src/views/pre-register-active/images/video-speed1.png


BIN
src/views/pre-register-active/images/video_bg.png


+ 166 - 0
src/views/pre-register-active/index.module.less

@@ -0,0 +1,166 @@
+.per-register-active {
+  min-height: 100vh;
+  background: url('./images/banner.png') no-repeat top center #C7F4FF;
+  background-size: contain;
+  padding-top: 176px;
+  overflow: hidden;
+}
+
+.flowPath {
+  position: relative;
+  margin: 0 14px 12px;
+  background: linear-gradient(180deg, #BFF4FF 0%, #80D3E1 100%);
+  box-shadow: 0 2px 4px 0 rgba(23, 89, 202, 0.92), inset 0 -9px 6px 0 #64BDFF, inset 0 3px 4px 0 #FFFFFF;
+  border-radius: 25px;
+  padding: 12px 10px 11px;
+
+  .flowPathTitle {
+    display: block;
+    position: absolute;
+    top: -4px;
+    left: 50%;
+    margin-left: -72px;
+    width: 144px;
+    height: 42px;
+    background: url('./images/flow-path-title.png') no-repeat center;
+    background-size: contain;
+  }
+
+  .flowPathContent {
+    padding: 31px 20px 14px;
+    font-size: 14px;
+    color: #2D1A18;
+    line-height: 26px;
+
+    background: linear-gradient(180deg, #FFFFFA 0%, rgba(255, 255, 253, 0.87) 90%, rgba(255, 255, 255, 0.52) 100%);
+    box-shadow: 0 1px 6px 0 #D9EFF8;
+    border-radius: 18px;
+    border: 5px solid #139CF1;
+    :global {
+      img {
+        width: 100% !important;
+      }
+    }
+  }
+}
+
+.signin {
+  position: relative;
+  margin: 0 10px 20px;
+  background: url('./images/signin-bg.png') no-repeat center;
+  background-size: contain;
+  min-height: 419px;
+  overflow: hidden;
+
+  .tips {
+    margin: 27px 35px 0;
+    display: flex;
+    align-items: center;
+    background: #F1F1F1;
+    border-radius: 6px;
+    font-size: 13px;
+    color: #DC2A00;
+    line-height: 18px;
+
+    p {
+      padding-top: 2px;
+    }
+
+    span {
+      font-weight: bold;
+    }
+
+    .signinTips {
+      margin: 0 2px 0 4px;
+      width: 34px;
+      height: 28px;
+      object-fit: contain;
+    }
+  }
+}
+
+.cellGroup {
+  margin: 0 40px;
+  background-color: transparent;
+
+  :global {
+    .van-cell {
+      padding-top: 18px;
+      padding-left: 0;
+      padding-right: 0;
+      background-color: transparent;
+    }
+
+    .van-field__label {
+      font-size: 16px;
+      font-weight: 500;
+      color: #333333;
+      line-height: 22px;
+      margin-bottom: 10px;
+    }
+
+    input {
+      color: #666;
+      font-size: 16px;
+
+      &::placeholder {
+        color: #dcdcdc;
+      }
+    }
+  }
+
+  .submitBtn {
+    width: 190px;
+    height: 53px;
+    background: url('./images/signin-btn.png') no-repeat center;
+    background-size: contain;
+    border: none;
+    display: block;
+    margin: 18px auto 0;
+    border-radius: 50px;
+  }
+}
+
+.wxPopupDialog {
+  // position: relative;
+  overflow: initial;
+  // margin-top: -160px;
+
+  &::before {
+    position: absolute;
+    content: ' ';
+    top: -73px;
+    left: 50%;
+    margin-left: -86px;
+    display: inline-block;
+    background: url('../music-group/pre-apply/images/wx-no-top.png') no-repeat top center;
+    background-size: contain;
+    width: 172px;
+    height: 154px;
+  }
+}
+
+.popupContainer {
+  background: url('../music-group/pre-apply/images/wx-no-bg.png') no-repeat top center;
+  background-size: cover;
+  border-radius: 20px;
+  overflow: hidden;
+  padding: 0 20px;
+
+  .title {
+    padding-top: 57px;
+    text-align: center;
+    font-size: 18px;
+    font-weight: 500;
+    color: #3b2300;
+  }
+
+  .popupTips {
+    padding-top: 12px;
+    padding-bottom: 47px;
+    text-align: center;
+    font-size: 15px;
+    color: #777777;
+    line-height: 21px;
+  }
+}

+ 383 - 0
src/views/pre-register-active/index.tsx

@@ -0,0 +1,383 @@
+import { defineComponent, onMounted, onUnmounted, reactive, ref } from 'vue'
+import styles from './index.module.less'
+import signinTips from './images/signin-tips.png'
+import { Button, CellGroup, Field, Picker, Popup, closeToast, showToast } from 'vant'
+import { useRoute, useRouter } from 'vue-router'
+import OWxTip from '@/components/m-wx-tip'
+import { browser, getUrlCode } from '@/helpers/utils'
+import qs from 'query-string'
+import request from '@/helpers/request'
+import { goWechatAuth } from '@/state'
+import { useInterval, useIntervalFn } from '@vueuse/core'
+const classList: any[] = []
+for (let i = 1; i <= 40; i++) {
+  classList.push({ text: i + '班', value: i })
+}
+export default defineComponent({
+  name: 'pre-register',
+  setup() {
+    // 页面定时
+    const pageTimer = useInterval(1000, { controls: true })
+    pageTimer.pause()
+    const router = useRouter()
+    const route = useRoute()
+    const forms = reactive({
+      loading: true,
+      orchestraId: route.query.id,
+      code: null,
+      currentGradeList: [
+        { text: '一年级', value: 1 },
+        { text: '二年级', value: 2 },
+        { text: '三年级', value: 3 },
+        { text: '四年级', value: 4 },
+        { text: '五年级', value: 5 },
+        { text: '六年级', value: 6 },
+        { text: '七年级', value: 7 },
+        { text: '八年级', value: 8 },
+        { text: '九年级', value: 9 }
+      ], // 年级数组列表
+      showPicker: false,
+      classPicker: false,
+      nameReg: /^[\u4E00-\u9FA5]+$/,
+      openId: '' as any,
+      id: null,
+      videoBrowseData: null,
+      videoBrowsePoint: null,
+      username: '',
+      currentGrade: '', // 年级
+      currentClass: '', // 班级
+      intervalFnRef: null as any,
+      applyStatus: false,
+      isPageHide: false,
+      parentConferencesAgenda: ''
+    })
+
+    const showPopup = ref(false)
+    const showPopupMessage = ref('')
+
+    const message = (value: string) => {
+      if (!value) {
+        return '请填写学生真实姓名'
+      } else if (!forms.nameReg.test(value)) {
+        return '学员姓名必须为中文'
+      } else if (value.length < 2 || value.length > 15) {
+        return '学员姓名必须为2~15个字'
+      }
+    }
+
+    const onSubmit = async () => {
+      try {
+        if (forms.applyStatus) {
+          showToast('家长会调查问卷已结束')
+          return
+        }
+
+        if (message(forms.username)) {
+          showToast(message(forms.username))
+          return
+        }
+
+        if (!forms.currentGrade) {
+          showToast('请选择年级')
+          return
+        }
+
+        if (!forms.currentClass) {
+          showToast('请选择班级')
+          return
+        }
+        // 暂停回调
+        forms.intervalFnRef?.pause()
+        // 页面计时暂停
+        pageTimer.pause()
+        await request.post('/api-student/open/studentBrowseRecord/updateStat', {
+          data: {
+            id: forms.id,
+            pageBrowseTime: pageTimer.counter.value,
+            username: forms.username,
+            currentGrade: forms.currentGrade,
+            currentClass: forms.currentClass ? Number(forms.currentClass) : null
+          }
+        })
+
+        router.push({
+          path: '/pre-register-video',
+          query: {
+            saveId: forms.id,
+            id: forms.orchestraId, // 乐团编号
+            openId: forms.openId //
+          }
+        })
+      } catch {
+        // 还原
+        forms.intervalFnRef?.resume()
+        pageTimer.resume()
+      }
+      // router.push('/pre-register-video')
+    }
+
+    const formatterClass = (value: any, list: any[]) => {
+      let txt = ''
+      list.forEach((listItem: any) => {
+        if (listItem.value == value) {
+          txt = listItem.text
+        }
+      })
+      return txt
+    }
+
+    // 更新时间
+    const updateStat = async (pageBrowseTime = 10) => {
+      try {
+        await request.post('/api-student/open/studentBrowseRecord/updateStat', {
+          data: {
+            id: forms.id,
+            pageBrowseTime // 固定10秒
+          }
+        })
+      } catch {
+        //
+      }
+    }
+
+    onMounted(async () => {
+      try {
+        if (!forms.orchestraId) {
+          showToast('信息获取失败,请联系老师')
+        }
+        const { data } = await request.get(
+          '/api-student/open/orchestra/detail/' + forms.orchestraId
+        )
+        forms.parentConferencesAgenda = data.parentConferencesAgenda
+
+        // 判断是否获取微信code码
+        if (!forms.code) return
+
+        // 乐团注册
+        if (data.orchestraRegisterType === 'ORCHESTRA' && data.status !== 'PRE_REGISTER') {
+          showToast('家长会调查问卷已结束')
+          forms.applyStatus = true
+          return
+        }
+
+        // 家长会注册
+        // 'DOING' | 'DONE'
+        if (
+          data.orchestraRegisterType === 'PARENT_CONFERENCES' &&
+          data.status !== 'PARENT_TEACHER_REGISTRATION' &&
+          data.status !== 'DOING' &&
+          data.status !== 'DONE'
+        ) {
+          showToast('家长会调查问卷已结束')
+          forms.applyStatus = true
+          return
+        }
+
+        if (forms.orchestraId) {
+          // 提示乐团报名失败
+          showPopupMessage.value = '二维码已过期'
+          showPopup.value = true
+          return
+        }
+
+        const recordAdd = await request.post('/api-student/open/studentBrowseRecord/add', {
+          data: {
+            orchestraId: forms.orchestraId,
+            code: forms.code,
+            openId: forms.openId
+          }
+        })
+        const recordObj = recordAdd.data
+        forms.currentClass = recordObj.currentClass
+        forms.currentGrade = recordObj.currentGrade
+        forms.openId = recordObj.openId
+        forms.username = recordObj.username
+        forms.videoBrowseData = recordObj.videoBrowseData
+        forms.videoBrowsePoint = recordObj.videoBrowsePoint
+        forms.id = recordObj.id
+
+        sessionStorage.setItem('active-open-id', recordObj.openId)
+
+        pageTimer.resume()
+        // 间隔10秒更新停留时间
+        forms.intervalFnRef = useIntervalFn(() => {
+          // 页面时间恢复
+          pageTimer.counter.value = 0
+          pageTimer.resume()
+          updateStat()
+        }, 10000)
+      } catch {
+        //
+      }
+    })
+
+    const getAppIdAndCode = async (url?: string) => {
+      try {
+        const { data } = await request.get('/api-school/open/paramConfig/wechatAppId')
+        // 判断是否有微信appId
+        if (data) {
+          closeToast()
+          goWechatAuth(data, url)
+        }
+      } catch {
+        //
+      }
+    }
+
+    if (browser().weixin) {
+      //授权
+      const openId = sessionStorage.getItem('active-open-id')
+      forms.openId = openId
+      const code = getUrlCode()
+      if (!code) {
+        const newUrl =
+          window.location.origin +
+          window.location.pathname +
+          '#' +
+          route.path +
+          '?' +
+          qs.stringify({
+            ...route.query
+          })
+        getAppIdAndCode(newUrl)
+        return ''
+      } else {
+        forms.code = code
+      }
+    }
+
+    const onPageShow = () => {
+      console.log(forms.isPageHide, 'showInfo')
+      if (forms.isPageHide) {
+        window.location.reload()
+      }
+    }
+    // 处理监听页面返回不刷新的问题
+    window.addEventListener('pageshow', onPageShow)
+
+    const onPageHide = () => {
+      console.log(forms.isPageHide, 'showInfo')
+      forms.isPageHide = true
+    }
+    window.addEventListener('pagehide', onPageHide)
+
+    onUnmounted(() => {
+      window.removeEventListener('pageshow', onPageShow)
+      window.removeEventListener('pagehide', onPageHide)
+    })
+    return () => (
+      <div class={styles['per-register-active']}>
+        <div class={styles.flowPath}>
+          <i class={styles.flowPathTitle}></i>
+          <div class={styles.flowPathContent} v-html={forms.parentConferencesAgenda}>
+            {/* 一、请所有家长进行<span>签到</span>
+            <br />
+            二、<span>观看</span>管乐团家长会议
+            <br />
+            1、学校领导讲话(5分钟)
+            <br />
+            2、基金会老师介绍乐团事项(20分钟)
+            <br />
+            <p
+              style={{
+                'padding-left': '1em'
+              }}
+            >
+              *乐团组建背景及政策
+              <br />
+              *乐团发展规划与乐器知识讲解
+              <br />
+              *学校/基金会/家长各方职责与投入
+              <br />
+              *入团流程讲解
+            </p>
+            三、请
+            <span>“有意向”</span>让孩子加入乐团的家长点击
+            <span>“乐团报名”</span>完成信息填报 */}
+          </div>
+        </div>
+
+        <div class={styles.signin}>
+          <div class={styles.tips}>
+            <img src={signinTips} class={styles.signinTips} />
+            <p>
+              请先进行<span>签到</span>,再观看<span>管乐团家长会视频</span>
+            </p>
+          </div>
+
+          <CellGroup class={styles.cellGroup} border={false}>
+            <Field
+              label="学生姓名"
+              labelAlign="top"
+              placeholder="请输入学生姓名"
+              autocomplete="off"
+              v-model={forms.username}
+            />
+            <Field
+              label="年级"
+              labelAlign="top"
+              placeholder="请选择年级"
+              isLink
+              readonly
+              modelValue={formatterClass(forms.currentGrade, forms.currentGradeList)}
+              clickable={false}
+              onClick={() => (forms.showPicker = true)}
+            />
+            <Field
+              label="班级"
+              labelAlign="top"
+              placeholder="请选择班级"
+              isLink
+              readonly
+              modelValue={formatterClass(forms.currentClass, classList)}
+              clickable={false}
+              onClick={() => (forms.classPicker = true)}
+            />
+
+            <Button class={styles.submitBtn} onClick={onSubmit}></Button>
+          </CellGroup>
+        </div>
+
+        {/* 是否在微信中打开 */}
+        {/* <OWxTip /> */}
+
+        {/* 年级 */}
+        <Popup v-model:show={forms.showPicker} position="bottom" round>
+          <Picker
+            columns={forms.currentGradeList}
+            onCancel={() => (forms.showPicker = false)}
+            onConfirm={({ selectedValues }) => {
+              forms.currentGrade = selectedValues[0]
+              forms.showPicker = false
+            }}
+          />
+        </Popup>
+
+        {/* 班级 */}
+        <Popup v-model:show={forms.classPicker} position="bottom" round>
+          <Picker
+            columns={classList}
+            onCancel={() => (forms.classPicker = false)}
+            onConfirm={({ selectedValues }) => {
+              forms.currentClass = selectedValues[0]
+              forms.classPicker = false
+            }}
+          />
+        </Popup>
+
+        <Popup
+          v-model:show={showPopup.value}
+          round
+          style={{ width: '88%' }}
+          closeOnClickOverlay={false}
+          class={styles.wxPopupDialog}
+        >
+          <div class={styles.popupContainer}>
+            <p class={styles.title}>温馨提示</p>
+            <p class={styles.popupTips} v-html={showPopupMessage.value}></p>
+          </div>
+        </Popup>
+      </div>
+    )
+  }
+})

+ 36 - 0
src/views/pre-register-active/show.tsx

@@ -0,0 +1,36 @@
+import { defineComponent, reactive } from 'vue'
+import ActiveShow from './compontent-show/active-show'
+import VideoShow from './compontent-show/video-show'
+import RegisterShow from './compontent-show/register-show'
+import { useRoute } from 'vue-router'
+
+export default defineComponent({
+  name: 'show-page',
+  setup() {
+    const route = useRoute()
+    console.log(route.query, 'query')
+    const index = route.query.index ? Number(route.query.index) : 1
+    const forms = reactive({
+      tabIndex: index || 1
+    })
+    return () => (
+      <>
+        {forms.tabIndex === 1 && (
+          <ActiveShow
+            onTabChange={(index: number) => {
+              forms.tabIndex = index
+            }}
+          />
+        )}
+        {forms.tabIndex === 2 && (
+          <VideoShow
+            onTabChange={(index: number) => {
+              forms.tabIndex = index
+            }}
+          />
+        )}
+        {forms.tabIndex === 3 && <RegisterShow />}
+      </>
+    )
+  }
+})

+ 250 - 0
src/views/pre-register-active/video.module.less

@@ -0,0 +1,250 @@
+.pre-register-video {
+  min-height: calc(100vh - 176px);
+  background: url('./images/banner.png') no-repeat top center #C7F4FF;
+  background-size: contain;
+  padding-top: 160px;
+  overflow: hidden;
+}
+
+.videoContainer {
+  position: relative;
+  margin: 0 6px;
+  background: url('./images/video-bg.png') no-repeat center;
+  background-size: contain;
+  min-height: 265px;
+}
+
+.video-content {
+  position: relative;
+  width: 100%;
+  --plyr-color-main: #FF8057;
+  width: 303px;
+  height: 171px;
+  border-radius: 18px;
+  padding-top: 34px;
+  padding-bottom: 28px;
+  margin: 0 auto;
+
+  .coverImg {
+    width: 100%;
+    height: 100%;
+    border-radius: 30px;
+  }
+
+  video {
+    width: 100%;
+  }
+
+  :global {
+    .video-back {
+      position: absolute;
+      left: 20px;
+      top: 20px;
+      color: #fff;
+      z-index: 99;
+      font-size: 24px;
+      width: 30px;
+      height: 30px;
+      background-color: rgba(0, 0, 0, 0.5);
+      border-radius: 50%;
+      padding: 4px 5px 4px 3px;
+    }
+
+
+    .video-js {
+      width: 100%;
+      height: 100%;
+      border-radius: 30px;
+      overflow: hidden;
+    }
+
+
+    .plyr__poster {
+      background-size: cover;
+    }
+
+    .plyr__control--overlaid {
+      border: 1px solid #fff;
+      background-color: rgba(0, 0, 0, 0.2) !important;
+    }
+
+    .plyr--video .plyr__control:hover {
+      background-color: transparent !important;
+    }
+
+    .video-js {
+      width: 100%;
+      height: 100%;
+    }
+
+    .tcp-skin .vjs-play-progress {
+      background-color: var(--van-primary) !important;
+    }
+
+    .vjs-slider:focus {
+      box-shadow: none !important;
+    }
+
+    .video-js .vjs-progress-control:hover .vjs-progress-holder {
+      font-size: 1em !important;
+    }
+
+  }
+
+  .video {
+    position: relative;
+    border-radius: 18px;
+  }
+}
+
+.videoCount {
+  // position: relative;
+  // margin-top: 5px;
+  // background: url('./images/video-count.png') no-repeat center;
+  // background-size: contain;
+  // min-height: 82px;
+  // box-sizing: content-box;
+  // padding: 60px 36px 0;
+  position: relative;
+  margin: 8px 14px 12px;
+  // background: url('./images/flow-path-bg.png') no-repeat center;
+  // background-size: contain;
+  background: linear-gradient(180deg, #BFF4FF 0%, #80D3E1 100%);
+  box-shadow: 0px 2px 4px 0px rgba(23, 89, 202, 0.92), inset 0px -9px 6px 0px #64BDFF, inset 0px 3px 4px 0px #FFFFFF;
+  border-radius: 25px;
+  padding: 12px 10px 11px;
+
+  .videoTitle {
+    display: block;
+    position: absolute;
+    top: -6px;
+    left: 50%;
+    margin-left: -93px;
+    width: 186px;
+    height: 32px;
+    background: url('./images/video-path-title.png') no-repeat center;
+    background-size: contain;
+  }
+
+  &::before,
+  &::after {
+    content: ' ';
+    position: absolute;
+    top: -33px;
+    width: 11px;
+    height: 44px;
+    background: url('./images/icon-connect.png') no-repeat center;
+    background-size: contain;
+  }
+
+  &::before {
+    left: 34px;
+  }
+
+  &::after {
+    right: 34px;
+  }
+
+
+  .videoCountContent {
+    padding: 31px 20px 14px;
+    font-size: 14px;
+    color: #2D1A18;
+    line-height: 26px;
+
+    background: linear-gradient(180deg, #FFFFFA 0%, rgba(255, 255, 253, 0.87) 90%, rgba(255, 255, 255, 0.52) 100%);
+    box-shadow: 0px 1px 6px 0px #D9EFF8;
+    border-radius: 18px;
+    border: 5px solid #139CF1;
+
+    span {
+      font-size: 13px;
+      color: #000000;
+      line-height: 18px;
+      background: #E8EBEE;
+      border-radius: 14px;
+      padding: 4px 9px;
+      display: inline-block;
+      margin-right: 8px;
+      margin-bottom: 6px;
+
+      &.active {
+        font-weight: 600;
+        color: #FFFFFF;
+        background: #198CFE;
+      }
+
+      // &+span {
+      //   margin-left: 8px;
+      // }
+    }
+
+    &::-webkit-scrollbar {
+      display: none;
+    }
+  }
+}
+
+.loadingVideo {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+  background: rgba(0, 0, 0, 0.9);
+  z-index: 10;
+}
+
+.messageContainer {
+  margin: 0 10px 20px;
+  // background: url('./images/message-bg.png') no-repeat center;
+  // background-size: contain;
+  // min-height: 440px;
+  background: linear-gradient(180deg, #BFF4FF 0%, #80D3E1 100%);
+  box-shadow: 0px 2px 4px 0px rgba(23, 89, 202, 0.92), inset 0px -9px 6px 0px #64BDFF, inset 0px 3px 4px 0px #FFFFFF;
+  border-radius: 25px;
+  padding: 12px 10px 11px;
+
+  .messageContent {
+    padding: 12px 20px 12px;
+    font-size: 14px;
+    color: #2D1A18;
+    line-height: 26px;
+
+    background: linear-gradient(180deg, #FFFFFA 0%, rgba(255, 255, 253, 0.87) 90%, rgba(255, 255, 255, 0.52) 100%);
+    box-shadow: 0px 1px 6px 0px #D9EFF8;
+    border-radius: 18px;
+    border: 5px solid #139CF1;
+
+    &>div {
+      text-align: justify;
+    }
+
+    // p {
+    //   text-align: justify;
+    // }
+
+    // .c1 {
+    //   text-indent: 2em;
+
+    //   span {
+    //     color: #DD3210;
+    //   }
+    // }
+  }
+
+  .bottom {
+    padding-top: 30px;
+  }
+}
+
+.submitBtn {
+  width: 190px;
+  height: 53px;
+  background: url('./images/pre-btn.png') no-repeat center;
+  background-size: contain;
+  border: none;
+  display: block;
+  margin: 20px auto 0;
+  border-radius: 50px;
+}

+ 704 - 0
src/views/pre-register-active/video.tsx

@@ -0,0 +1,704 @@
+import { defineComponent, onMounted, onUnmounted, reactive, ref, watch } from 'vue'
+import styles from './video.module.less'
+import { Button, Loading } from 'vant'
+import { browser } from '@/helpers/utils'
+// import Plyr from 'plyr'
+// import 'plyr/dist/plyr.css'
+import TCPlayer from 'tcplayer.js'
+import 'tcplayer.js/dist/tcplayer.css'
+import { useInterval, useIntervalFn } from '@vueuse/core'
+import { useRoute, useRouter } from 'vue-router'
+import request from '@/helpers/request'
+import { usePageVisibility } from '@vant/use'
+import deepClone from '@/helpers/deep-clone'
+
+export default defineComponent({
+  name: 'pre-register',
+  setup() {
+    const route = useRoute()
+    const router = useRouter()
+    const pageVisibility = usePageVisibility()
+    const openId = sessionStorage.getItem('active-open-id')
+    // 页面定时
+    const pageTimer = useInterval(1000, { controls: true })
+    pageTimer.pause()
+
+    const forms = reactive({
+      videoID: 'video' + Date.now() + Math.floor(Math.random() * 100),
+      coverImg: '',
+      introductionVideo: '',
+      introductionVideoTime: 0, // 视频总时长
+      videoBrowsePoint: 0, // 视频最后观看点
+      saveId: route.query.saveId,
+      orchestraId: route.query.id,
+      openId: route.query.openId || openId,
+      loading: false,
+      player: null as any,
+      playerSpeed: 1,
+      intervalFnRef: null as any,
+      videoDetails: [] as any, // 节点列表
+      pointVideo: {} as any, // 需要处理有效的时间段
+      pointVideoTime: 0, // 有效时长
+      videoSelectId: null, // 选中的编号
+      isPageHide: false, // 处理页面返回没有刷新的问题
+      parentConferencesNotes: '',
+      orchestraRegisterType: '',
+      status: '',
+      registerDisplay: true
+    })
+
+    // 播放视频总时长
+    const videoIntervalRef = useInterval(1000, { controls: true })
+    videoIntervalRef.pause()
+
+    /**
+     * 格式化视屏播放有效时间 - 合并区间
+     * @param intervals [[], []]
+     * @example [[4, 8],[0, 4],[10, 30]]
+     * @returns [[0, 8], [10, 30]]
+     */
+    const formatEffectiveTime = (intervals: any[]) => {
+      const res: any = []
+      intervals.sort((a, b) => a[0] - b[0])
+      let prev = intervals[0]
+      for (let i = 1; i < intervals.length; i++) {
+        const cur = intervals[i]
+        if (prev[1] >= cur[0]) {
+          // 有重合
+          prev[1] = Math.max(cur[1], prev[1])
+        } else {
+          // 不重合,prev推入res数组
+          res.push(prev)
+          prev = cur // 更新 prev
+        }
+      }
+      res.push(prev)
+      // console.log(res, 'formatEffectiveTime')
+
+      return formatEffectiveTimeToAfter(res)
+    }
+
+    const formatEffectiveTimeToAfter = (res: any[]) => {
+      // 格式化有效时间
+      const effective: any = []
+      const startNode = forms.pointVideo.startNode
+      const endNode = forms.pointVideo.endNode
+      // console.log(startNode, endNode, 'startNode')
+      res.forEach((item: any) => {
+        // 开始时间大于 设置时间
+        if (item[1] >= item[0]) {
+          /**
+           * 1、开始时间
+           */
+          if (item[0] >= startNode && item[0] <= endNode && item[1] <= endNode) {
+            // console.log(1)
+            effective.push(item)
+          }
+          if (item[0] >= startNode && item[0] <= endNode && item[1] > endNode) {
+            // console.log(3)
+            effective.push([item[0], endNode])
+          }
+          if (item[0] < startNode && item[1] > startNode && item[1] <= endNode) {
+            // console.log(4)
+            effective.push([startNode, item[1]])
+          }
+
+          if (item[0] < startNode && item[1] > startNode && item[1] > endNode) {
+            // console.log(4)
+            effective.push([startNode, endNode])
+          }
+        }
+      })
+
+      // console.log(effective, 'effective')
+      return effective
+    }
+
+    /**
+     * 获取数据有效期
+     * @param intervals [[], []]
+     * @returns 0s
+     */
+    const formatTimer = (intervals: any[]) => {
+      const afterIntervals = formatEffectiveTime(intervals)
+      // console.log(afterIntervals, 'afterIntervals')
+      let time = 0
+      afterIntervals.forEach((t: any) => {
+        time += t[1] - t[0]
+      })
+      return time
+    }
+
+    const checkVideoDetails = (time: number) => {
+      forms.videoDetails.forEach((item: any) => {
+        if (item.startNode <= time && time <= item.endNode) {
+          forms.videoSelectId = item.id
+        }
+      })
+    }
+
+    /**
+     * 视屏累计时长
+     * 1、视屏开始播放时-开始计时
+     * 2、视频暂停时暂停-停止计时
+     * 3、视频加载时-停止计时
+     * 4、视频倍数播放时,时间正常计时
+     * 5、点击视频进度或拖动进度时,时间暂停
+     */
+    const _init = () => {
+      // const controls = [
+      //   'play-large',
+      //   'play',
+      //   'progress',
+      //   'captions',
+      //   'current-time',
+      //   'duration',
+      //   'settings',
+      //   'fullscreen'
+      // ]
+      // const params: any = {
+      //   controls: controls,
+      //   settings: ['speed'],
+      //   speed: { selected: 1, options: [0.5, 1, 1.5, 2] },
+      //   i18n: {
+      //     speed: '速度',
+      //     normal: '默认'
+      //   },
+      //   autoplay: false,
+      //   invertTime: false
+      // }
+
+      // if (browser().iPhone) {
+      //   params.fullscreen = {
+      //     enabled: true,
+      //     fallback: 'force',
+      //     iosNative: true
+      //   }
+      // }
+      // const times: any = []
+      // forms.videoDetails.forEach((item: any) => {
+      //   times.push({
+      //     time: item.startNode,
+      //     label: item.desc
+      //   })
+      // })
+      // params.markers = { enabled: true, points: times }
+
+      // forms.player = new Plyr('#register-video', params)
+
+      // forms.player.on('ready', (item: any) => {
+      //   console.log('ready', item)
+
+      //   // forms.player.pause()
+      // })
+      // forms.player.on('loadedmetadata', () => {
+      //   console.log('loadedmetadata')
+      //   forms.loading = false
+      //   forms.player.currentTime() = forms.videoBrowsePoint
+      //   checkVideoDetails(forms.player.currentTime())
+      // })
+
+      // // 速度变化时
+      // forms.player.on('ratechange', () => {
+      //   forms.playerSpeed =
+      //     forms.playerSpeed < forms.player.speed ? forms.player.speed : forms.playerSpeed
+      // })
+
+      // forms.player.on('seeking', () => {
+      //   console.log('seeking')
+      //   videoIntervalRef.isActive.value && videoIntervalRef.pause()
+      // })
+
+      // // // 拖动结束时
+      // forms.player.on('seeked', () => {
+      //   console.log('seeked')
+      //   videoIntervalRef.isActive.value && videoIntervalRef.pause()
+      // })
+
+      // // 正在搜索中
+      // forms.player.on('waiting', () => {
+      //   // console.log('waiting pause')
+      //   videoIntervalRef.isActive.value && videoIntervalRef.pause()
+      // })
+
+      // // 如何视频在缓存不会触发
+      // forms.player.on('timeupdate', () => {
+      //   console.log('timeupdate', forms.player.currentTime())
+      //   // 时间变化时更新每一段的状态
+      //   checkVideoDetails(forms.player.currentTime())
+      //   // 判断视频计时器是否暂停,如果暂停则恢复
+      //   // 添加 「forms.player.playing」 是由会跳转到上次播放时间,会触发些方法
+      //   if (
+      //     !videoIntervalRef.isActive.value &&
+      //     forms.player.currentTime() > 0 &&
+      //     forms.player.playing
+      //   ) {
+      //     // console.log('timeupdate play')
+      //     videoIntervalRef.resume()
+      //   }
+      // })
+
+      // // 视屏播放时暂停
+      // forms.player.on('ended', () => {
+      //   forms.player.pause()
+      // })
+
+      // // 开始播放
+      // forms.player.on('play', () => {
+      //   console.log('play')
+      //   // 判断视频计时器是否暂停,如果暂停则恢复
+      //   videoIntervalRef.resume()
+      // })
+
+      // // 暂停播放
+      // forms.player.on('pause', () => {
+      //   console.log('pause', videoIntervalRef.isActive.value)
+
+      //   videoIntervalRef.pause()
+      // })
+
+      // forms.player.on('enterfullscreen', () => {
+      //   console.log('fullscreen')
+      //   const i = document.createElement('i')
+      //   i.id = 'fullscreen-back'
+      //   i.className = 'van-icon van-icon-arrow-left video-back'
+      //   i.addEventListener('click', () => {
+      //     forms.player.fullscreen.exit()
+      //   })
+      //   console.log(document.getElementsByClassName('plyr'))
+      //   document.getElementsByClassName('plyr')[0].appendChild(i)
+      // })
+
+      // forms.player.on('exitfullscreen', () => {
+      //   console.log('exitfullscreen')
+      //   const i = document.getElementById('fullscreen-back')
+      //   i && i.remove()
+      // })
+      const Button = TCPlayer.getComponent('Button')
+      const BigPlayButton = TCPlayer.getComponent('BigPlayButton')
+      BigPlayButton.prototype.createEl = function () {
+        const el = Button.prototype.createEl.call(this)
+        const _html =
+          '<button><svg width="41px"height="41px"viewBox="0 0 41 41"version="1.1"xmlns="http://www.w3.org/2000/svg"xmlns:xlink="http://www.w3.org/1999/xlink"><g stroke="none"stroke-width="1"fill="none"fill-rule="evenodd"><g transform="translate(-167.000000, -155.000000)"><g transform="translate(0.000000, 85.000000)"><g transform="translate(158.000000, 70.000000)"><g transform="translate(9.000000, 0.000000)"><circle id="椭圆形"stroke="#FFFFFF"fill-opacity="0.1"fill="#D8D8D8"cx="20.5"cy="20.5"r="20"></circle><path d="M14.5483871,27.6859997 L14.5483871,13.4342349 C14.5480523,12.8729571 14.8729597,12.356555 15.3949624,12.0887034 C15.9169651,11.8208518 16.5522696,11.8445472 17.0503046,12.1504437 L28.6530473,19.2778563 C29.1119763,19.5602271 29.3887725,20.0426422 29.3887725,20.5601173 C29.3887725,21.0775924 29.1119763,21.5600075 28.6530473,21.8423783 L17.0503046,28.9697909 C16.5522696,29.2756874 15.9169651,29.2993828 15.3949624,29.0315312 C14.8729597,28.7636796 14.5480523,28.2472775 14.5483871,27.6859997 Z"id="路径"fill="#FFFFFF"fill-rule="nonzero"></path></g></g></g></g></g></svg></button>'
+
+        el.appendChild(
+          TCPlayer.dom.createEl('div', {
+            className: 'vjs-button-icon',
+            innerHTML: _html
+          })
+        )
+        return el
+      }
+      forms.player = TCPlayer('register-video', {
+        appID: '',
+        controls: true,
+        plugins: {
+          // ProgressMarker: {
+          //   markers: [
+          //     {
+          //       content: '1111',
+          //       timeOffset: 1000
+          //     }
+          //   ]
+          // }
+        }
+      }) // player-container-id 为播放器容器 ID,必须与 html 中一致
+      if (forms.player) {
+        forms.player.src(forms.introductionVideo) // url 播放地址
+        forms.player.poster(forms.coverImg || '')
+
+        // forms.player.on('loadstart', () => {})
+        forms.player.on('ready', (item: any) => {
+          console.log('ready', item)
+
+          // forms.player.pause()
+        })
+        forms.player.on('loadedmetadata', () => {
+          console.log('loadedmetadata')
+          forms.loading = false
+          forms.player.currentTime(forms.videoBrowsePoint)
+          checkVideoDetails(forms.player.currentTime())
+        })
+
+        // 速度变化时
+        forms.player.on('ratechange', () => {
+          forms.playerSpeed =
+            forms.playerSpeed < forms.player.playbackRate()
+              ? forms.player.playbackRate()
+              : forms.playerSpeed
+        })
+
+        forms.player.on('seeking', () => {
+          console.log('seeking')
+          videoIntervalRef.isActive.value && videoIntervalRef.pause()
+        })
+
+        // // 拖动结束时
+        forms.player.on('seeked', () => {
+          console.log('seeked')
+          videoIntervalRef.isActive.value && videoIntervalRef.pause()
+        })
+
+        // 正在搜索中
+        forms.player.on('waiting', () => {
+          // console.log('waiting pause')
+          videoIntervalRef.isActive.value && videoIntervalRef.pause()
+        })
+
+        // 如何视频在缓存不会触发
+        forms.player.on('timeupdate', () => {
+          console.log('timeupdate', forms.player.currentTime())
+          // 时间变化时更新每一段的状态
+          checkVideoDetails(forms.player.currentTime())
+          // 判断视频计时器是否暂停,如果暂停则恢复
+          // 添加 「forms.player.playing」 是由会跳转到上次播放时间,会触发些方法
+          if (
+            !videoIntervalRef.isActive.value &&
+            forms.player.currentTime() > 0 &&
+            !forms.player.paused()
+          ) {
+            // console.log('timeupdate play')
+            videoIntervalRef.resume()
+          }
+        })
+
+        // 视屏播放时暂停
+        forms.player.on('ended', () => {
+          forms.player.pause()
+        })
+
+        // 开始播放
+        forms.player.on('play', () => {
+          console.log('play')
+          // 判断视频计时器是否暂停,如果暂停则恢复
+          videoIntervalRef.resume()
+        })
+
+        // 暂停播放
+        forms.player.on('pause', () => {
+          console.log('pause', videoIntervalRef.isActive.value)
+
+          videoIntervalRef.pause()
+        })
+
+        forms.player.on('fullscreenchange', () => {
+          if (forms.player.isFullscreen()) {
+            console.log('fullscreen')
+            const i = document.createElement('i')
+            i.id = 'fullscreen-back'
+            i.className = 'van-icon van-icon-arrow-left video-back'
+            i.addEventListener('click', () => {
+              forms.player.exitFullscreen()
+            })
+            document.getElementsByClassName('video-js')[0].appendChild(i)
+          } else {
+            console.log('exitfullscreen')
+            const i = document.getElementById('fullscreen-back')
+            i && i.remove()
+          }
+        })
+      }
+      checkVideoDetails(0)
+    }
+
+    // 保存零时时间
+    const moreTime: any = ref([]) // 多个观看时间段
+    let tempTime: any = [] // 临时存储时间
+
+    const currentTimer = useInterval(1000, { controls: true })
+    // 监听播放状态,
+    watch(
+      () => videoIntervalRef.isActive.value,
+      (newVal: boolean) => {
+        console.log(videoIntervalRef.isActive.value, 'videoIntervalRef')
+        initVideoCount(newVal)
+      }
+    )
+
+    /**
+     * 初始化视频时长
+     * @param newVal 播放状态
+     * @param repeat 是否为定时发送的
+     */
+    const initVideoCount = (newVal: any, repeat = false) => {
+      // console.log('watch', forms.player.currentTime)
+      const initTime = deepClone(tempTime)
+      if (repeat) {
+        if (tempTime.length > 0) {
+          // console.log('join video', tempTime, 'initTime', initTime)
+          tempTime[1] = Math.floor(forms.player.currentTime())
+        }
+      } else {
+        if (newVal) {
+          tempTime[0] = Math.floor(forms.player.currentTime())
+        } else {
+          tempTime[1] = Math.floor(forms.player.currentTime())
+        }
+      }
+
+      // console.log(newVal, repeat, tempTime, tempTime.length, 'videoIntervalRef.isActive.value in')
+      // console.log(forms.player.speed, 'speed')
+
+      if (tempTime.length >= 2) {
+        // console.log(tempTime, 'tempTime', moreTime.value)
+        // 处理在短时间内的时间差 【视屏拖动,点击可能会导致时间差太大】
+        const diffTime =
+          tempTime[1] - tempTime[0] - currentTimer.counter.value * forms.playerSpeed > 2
+        // console.log(diffTime, 'diffTime', currentTimer.counter.value, forms.playerSpeed, 'value')
+        // 结束时间,如果 大于开始时间则清除
+        if (tempTime[1] >= tempTime[0] && !diffTime) moreTime.value.push(tempTime)
+        if (repeat) {
+          tempTime = deepClone(initTime)
+        } else {
+          tempTime = []
+          currentTimer.counter.value = 0
+        }
+      }
+
+      // console.log('观看的时间', moreTime)
+    }
+
+    watch(pageVisibility, (value: any) => {
+      console.log('watch', value)
+      if (value == 'hidden') {
+        forms.player.pause()
+      }
+    })
+
+    // 更新时间
+    const updateStat = async (pageBrowseTime = 10) => {
+      try {
+        const videoBrowseData = moreTime.value.length > 0 ? formatEffectiveTime(moreTime.value) : []
+        // console.log(moreTime.value, videoBrowseData, 'video')
+        const time = videoBrowseData.length > 0 ? formatTimer(videoBrowseData) : 0
+        // const videoCountTime = videoIntervalRef?.counter.value
+        // 判断如何视屏播放时间大于视屏播放有效时间则说明数据有问题,进行重置数据
+        const rate = Math.floor((time / Math.floor(forms.pointVideoTime)) * 100)
+        // console.log('videoIntervalRef?.counter.value', videoIntervalRef?.counter.value)
+        await request.post('/api-student/open/studentBrowseRecord/updateStat', {
+          data: {
+            id: forms.saveId,
+            pageBrowseTime, // 固定10秒
+            videoBrowseData: JSON.stringify(videoBrowseData), // 视屏播放数据
+            videoBrowseDataTime: time || 0, // 有效的视频观看时长
+            videoBrowsePercentage: rate || 0, // 有效的视频观看时长百分比
+            videoBrowseTime: videoIntervalRef?.counter.value, // 视频观看时长
+            videoBrowsePoint: Math.floor(forms.player.currentTime() || 0) // 视频最后观看点 - 向下取整
+          }
+        })
+      } catch {
+        //
+      }
+    }
+
+    // 提交
+    const onSubmit = async () => {
+      try {
+        forms.player.pause() // 视屏
+        forms.intervalFnRef?.pause() // 页面订时器
+        currentTimer.pause()
+        videoIntervalRef.pause()
+        // 页面计时暂停
+        pageTimer.pause()
+        initVideoCount(videoIntervalRef.isActive.value)
+
+        await updateStat()
+
+        console.log(forms.orchestraRegisterType)
+        // if (forms.orchestraRegisterType === 'PARENT_CONFERENCES') {
+        //   window.location.href =
+        //     window.location.origin +
+        //     window.location.pathname +
+        //     `/#/preApply?id=${forms.orchestraId}`
+        // } else if (forms.orchestraRegisterType === 'GROUP_BUY') {
+        //   window.location.href =
+        //     window.location.origin +
+        //     window.location.pathname +
+        //     `/#/preGoodsApply?id=${forms.orchestraId}`
+        // } else {
+        //   window.location.href =
+        //     window.location.origin +
+        //     window.location.pathname +
+        //     '/project/preRegister.html?' +
+        //     qs.stringify({
+        //       orchestraId: forms.orchestraId,
+        //       openId: forms.openId
+        //     })
+        // }
+      } catch (e) {
+        console.log(e, 'e')
+        // 还原
+        forms.intervalFnRef?.resume()
+        pageTimer.resume()
+        currentTimer.resume()
+      }
+    }
+
+    onMounted(async () => {
+      try {
+        const { data } = await request.get('/api-student/open/studentBrowseRecord/query', {
+          params: {
+            openId: forms.openId,
+            orchestraId: forms.orchestraId
+          }
+        })
+        forms.videoBrowsePoint = data.videoBrowsePoint || 0
+        if (forms.player) {
+          forms.player.currentTime(data.videoBrowsePoint || 0)
+        }
+        forms.introductionVideo = data.introductionVideo
+        forms.introductionVideoTime = data.introductionVideoTime
+        forms.coverImg = data.coverImg
+        moreTime.value = data.videoBrowseData ? JSON.parse(data.videoBrowseData) : []
+        forms.parentConferencesNotes = data.parentConferencesNotes
+        forms.orchestraRegisterType = data.orchestraRegisterType
+        forms.registerDisplay = data.registerDisplay
+
+        const videoDetails = data.videoDetails || []
+        videoDetails.forEach((video: any) => {
+          forms.videoDetails.push({
+            startNode: video.startNode,
+            endNode: video.endNode,
+            desc: video.desc,
+            id: video.id
+          })
+          if (video.pointFlag) {
+            forms.pointVideo = video
+            forms.pointVideoTime = video.endNode - video.startNode
+          }
+        })
+
+        _init()
+        // 间隔多少时间同步数据
+        forms.intervalFnRef = useIntervalFn(async () => {
+          // 页面时间恢复
+          pageTimer.counter.value = 0
+          pageTimer.resume()
+          // 同步数据时先进行有效时间进行保存
+          initVideoCount(false, true)
+
+          await updateStat()
+          videoIntervalRef.counter.value = 0
+        }, 10000)
+
+        // const arr = [
+        //   [10, 10],
+        //   [53, 53],
+        //   [64, 64],
+        //   [74, 74],
+        //   [155, 155],
+        //   [173, 173],
+        //   [183, 183],
+        //   [191, 201]
+        // ]
+        // console.log(formatEffectiveTime(arr))
+      } catch {
+        //
+      }
+    })
+
+    onUnmounted(() => {
+      forms.player?.fullscreen.exit()
+      forms.intervalFnRef?.pause()
+      currentTimer.pause()
+      // 页面计时暂停
+      pageTimer.pause()
+    })
+
+    // 判断是否有openId
+    if (!forms.openId) {
+      router.replace({
+        path: '/pre-register-video',
+        query: {
+          id: forms.orchestraId
+        }
+      })
+    }
+
+    const onPageShow = () => {
+      // console.log(forms.isPageHide, 'showInfo')
+      if (forms.isPageHide) {
+        window.location.reload()
+      }
+    }
+    // 处理监听页面返回不刷新的问题
+    window.addEventListener('pageshow', onPageShow)
+
+    const onPageHide = () => {
+      // console.log(forms.isPageHide, 'showInfo')
+      forms.isPageHide = true
+    }
+    window.addEventListener('pagehide', onPageHide)
+
+    onUnmounted(() => {
+      window.removeEventListener('pageshow', onPageShow)
+      window.removeEventListener('pagehide', onPageHide)
+    })
+    return () => (
+      <div class={styles['pre-register-video']}>
+        <div class={styles.videoContainer}>
+          <div class={styles['video-content']}>
+            <video
+              id="register-video"
+              class={styles['video']}
+              src={forms.introductionVideo}
+              playsinline={true}
+              poster={forms.coverImg}
+              preload="auto"
+            ></video>
+            {/* 加载视频使用 */}
+            {forms.loading && (
+              <div class={styles.loadingVideo}>
+                <Loading
+                  size={36}
+                  color="#FF8057"
+                  vertical
+                  style={{ height: '100%', justifyContent: 'center' }}
+                >
+                  加载中...
+                </Loading>
+              </div>
+            )}
+          </div>
+        </div>
+        <div class={styles.videoCount}>
+          <div class={styles.videoTitle}></div>
+          <div class={styles.videoCountContent}>
+            {forms.videoDetails.map((item: any) => (
+              <span
+                class={[item.id === forms.videoSelectId ? styles.active : '']}
+                onClick={() => {
+                  forms.player.currentTime(item.startNode)
+                  forms.player.play()
+                  forms.videoBrowsePoint = item.startNode
+                  checkVideoDetails(forms.player.currentTime())
+                }}
+              >
+                {item.desc}
+              </span>
+            ))}
+          </div>
+        </div>
+        <div class={styles.messageContainer}>
+          <div class={styles.messageContent}>
+            {/* <p>家长您好!</p>
+            <p class={styles.c1}>
+              请家长们合理安排时间,<span>认真观看</span>家长会内容。在<span>详细了解</span>
+              所有要求后,有意向让孩子加入乐团的家长,请在<span>明晚20:00前</span>,为孩子完成
+              <span>乐团报名</span>。
+            </p>
+            <p class={styles.c1}>
+              下周,专业老师将针对意向入团学员进行身体条件确认。谢谢各位的支持!
+            </p>
+            <p class={styles.bottom}>
+              注:乐团于下学期正式开始训练,训练时间下学期开学前另行通知,训练时间会与学校其他社团错开,家长无需担心时间冲突问题。
+            </p> */}
+            <div v-html={forms.parentConferencesNotes}></div>
+
+            {forms.registerDisplay && <Button class={styles.submitBtn} onClick={onSubmit}></Button>}
+          </div>
+        </div>
+      </div>
+    )
+  }
+})