|  | @@ -20,8 +20,11 @@ import {
 | 
	
		
			
				|  |  |    onMounted,
 | 
	
		
			
				|  |  |    onUnmounted,
 | 
	
		
			
				|  |  |    reactive,
 | 
	
		
			
				|  |  | -  ref
 | 
	
		
			
				|  |  | +  ref,
 | 
	
		
			
				|  |  | +  watch
 | 
	
		
			
				|  |  |  } from 'vue';
 | 
	
		
			
				|  |  | +import TCPlayer from 'tcplayer.js';
 | 
	
		
			
				|  |  | +import 'tcplayer.js/dist/tcplayer.css';
 | 
	
		
			
				|  |  |  import qs from 'query-string';
 | 
	
		
			
				|  |  |  import {
 | 
	
		
			
				|  |  |    state as baseState,
 | 
	
	
		
			
				|  | @@ -45,15 +48,17 @@ import MDialog from '@/components/m-dialog';
 | 
	
		
			
				|  |  |  // import f3 from './images/new/f-3.png';
 | 
	
		
			
				|  |  |  // import iconTip2 from './images/new/icon-tip2.png';
 | 
	
		
			
				|  |  |  // import functionBg from './images/new/function-bg.png';
 | 
	
		
			
				|  |  | -import tuangou from './images/new/tuangou.png';
 | 
	
		
			
				|  |  | +// import tuangou from './images/new/tuangou.png';
 | 
	
		
			
				|  |  |  import icon3 from './images/new/icon-3.png';
 | 
	
		
			
				|  |  | -import icon5 from './images/new/icon-7.png';
 | 
	
		
			
				|  |  | -import icon6 from './images/new/icon-6.png';
 | 
	
		
			
				|  |  | -import giftTip from './images/new/icon-4.png';
 | 
	
		
			
				|  |  | +// import icon5 from './images/new/icon-7.png';
 | 
	
		
			
				|  |  | +// import icon6 from './images/new/icon-6.png';
 | 
	
		
			
				|  |  | +import giftTip from './images/new/icon-9.png';
 | 
	
		
			
				|  |  |  import iconGift from './images/new/icon-gift.png';
 | 
	
		
			
				|  |  | +import icon10 from './images/new/icon-n-10.png';
 | 
	
		
			
				|  |  | +import icon11 from './images/new/icon-n-11.png';
 | 
	
		
			
				|  |  |  import dayjs from 'dayjs';
 | 
	
		
			
				|  |  |  // import MMessageTip from '@/components/m-message-tip';
 | 
	
		
			
				|  |  | -import { CurrentTime, useCountDown } from '@vant/use';
 | 
	
		
			
				|  |  | +import { CurrentTime, useCountDown, usePageVisibility } from '@vant/use';
 | 
	
		
			
				|  |  |  import Payment from '../adapay/payment';
 | 
	
		
			
				|  |  |  import QrcodePayment from './qrcode-payment';
 | 
	
		
			
				|  |  |  import MImgCode from '@/components/m-img-code';
 | 
	
	
		
			
				|  | @@ -63,6 +68,7 @@ import MPopup from '@/components/m-popup';
 | 
	
		
			
				|  |  |  import UserAuth from './component/user-auth';
 | 
	
		
			
				|  |  |  import MMessageTip from '@/components/m-message-tip';
 | 
	
		
			
				|  |  |  import SelectStudent from './modal/select-student';
 | 
	
		
			
				|  |  | +import { Timer } from './timer';
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  const classList: any = [];
 | 
	
		
			
				|  |  |  for (let i = 1; i <= 40; i++) {
 | 
	
	
		
			
				|  | @@ -113,6 +119,7 @@ export default defineComponent({
 | 
	
		
			
				|  |  |    name: 'student-register',
 | 
	
		
			
				|  |  |    setup() {
 | 
	
		
			
				|  |  |      const route = useRoute();
 | 
	
		
			
				|  |  | +    const pageVisibility = usePageVisibility();
 | 
	
		
			
				|  |  |      const studentRegisterStore = useStudentRegisterStore();
 | 
	
		
			
				|  |  |      const router = useRouter();
 | 
	
		
			
				|  |  |      // 初始化学校编号
 | 
	
	
		
			
				|  | @@ -212,17 +219,6 @@ export default defineComponent({
 | 
	
		
			
				|  |  |        orderTimer: null as any
 | 
	
		
			
				|  |  |      });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    /*
 | 
	
		
			
				|  |  | -      新用户:
 | 
	
		
			
				|  |  | -      autoRegister: true
 | 
	
		
			
				|  |  | -      loginType: 'SMS'
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      已存在用户:
 | 
	
		
			
				|  |  | -      autoRegister: false
 | 
	
		
			
				|  |  | -      loginType: 'TOKEN'
 | 
	
		
			
				|  |  | -      password: xxx
 | 
	
		
			
				|  |  | -    */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      const studentInfo = reactive({
 | 
	
		
			
				|  |  |        autoRegister: true,
 | 
	
		
			
				|  |  |        multiUser: true, // 是否为多用户
 | 
	
	
		
			
				|  | @@ -241,10 +237,70 @@ export default defineComponent({
 | 
	
		
			
				|  |  |        password: '',
 | 
	
		
			
				|  |  |        username: ''
 | 
	
		
			
				|  |  |      });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const videoForms = reactive({
 | 
	
		
			
				|  |  | +      introductionVideo: '',
 | 
	
		
			
				|  |  | +      introductionVideoTime: 0, // 视频总时长
 | 
	
		
			
				|  |  | +      videoBrowsePoint: 0, // 视频最后观看点
 | 
	
		
			
				|  |  | +      player: null as any,
 | 
	
		
			
				|  |  | +      playerSpeed: 1,
 | 
	
		
			
				|  |  | +      intervalFnRef: null as any,
 | 
	
		
			
				|  |  | +      videoDetails: [] as any, // 节点列表
 | 
	
		
			
				|  |  | +      pointVideo: {} as any, // 需要处理有效的时间段
 | 
	
		
			
				|  |  | +      pointVideoTime: 0 // 有效时长
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 播放视频总时长
 | 
	
		
			
				|  |  | +    const videoIntervalRef = useInterval(1000, {
 | 
	
		
			
				|  |  | +      controls: true
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +    videoIntervalRef.pause();
 | 
	
		
			
				|  |  | +    const timer = new Timer();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      // 页面定时
 | 
	
		
			
				|  |  |      const pageTimer = useInterval(1000, { controls: true });
 | 
	
		
			
				|  |  |      pageTimer.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);
 | 
	
		
			
				|  |  | +      return res;
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /**
 | 
	
		
			
				|  |  | +     * 获取数据有效期
 | 
	
		
			
				|  |  | +     * @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 overCountDown = useCountDown({
 | 
	
		
			
				|  |  |        time: forms.activeOverTime,
 | 
	
		
			
				|  |  |        onFinish() {
 | 
	
	
		
			
				|  | @@ -544,6 +600,7 @@ export default defineComponent({
 | 
	
		
			
				|  |  |       */
 | 
	
		
			
				|  |  |      const onSubmit = async () => {
 | 
	
		
			
				|  |  |        forms.submitLoading = true;
 | 
	
		
			
				|  |  | +      forms.intervalFnRef.pause();
 | 
	
		
			
				|  |  |        try {
 | 
	
		
			
				|  |  |          if (checkForm() || checkSubmit()) {
 | 
	
		
			
				|  |  |            forms.submitLoading = false;
 | 
	
	
		
			
				|  | @@ -614,6 +671,8 @@ export default defineComponent({
 | 
	
		
			
				|  |  |            if (forms.joinType === 'tradition') {
 | 
	
		
			
				|  |  |              joinType = 'NOT_BUY_INSTRUMENT';
 | 
	
		
			
				|  |  |            }
 | 
	
		
			
				|  |  | +          // 单独存入时间,为了解决视频播放统计不全的问题
 | 
	
		
			
				|  |  | +          await updateStat(pageTimer.counter.value);
 | 
	
		
			
				|  |  |            // 更新时间
 | 
	
		
			
				|  |  |            const id = await updateStat(
 | 
	
		
			
				|  |  |              pageTimer.counter.value,
 | 
	
	
		
			
				|  | @@ -638,6 +697,7 @@ export default defineComponent({
 | 
	
		
			
				|  |  |          changeTipStatus(forms.isRegister === 'create' ? false : true, false);
 | 
	
		
			
				|  |  |        } finally {
 | 
	
		
			
				|  |  |          forms.submitLoading = false;
 | 
	
		
			
				|  |  | +        forms.intervalFnRef.resume();
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      };
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -919,7 +979,7 @@ export default defineComponent({
 | 
	
		
			
				|  |  |          });
 | 
	
		
			
				|  |  |          // 创建订单
 | 
	
		
			
				|  |  |          const updateStatus = await updateStudentInfo();
 | 
	
		
			
				|  |  | -        console.log(updateStatus, 'updateStatus');
 | 
	
		
			
				|  |  | +        // console.log(updateStatus, 'updateStatus');
 | 
	
		
			
				|  |  |          if (!updateStatus) return;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          const result = await request.post(
 | 
	
	
		
			
				|  | @@ -1132,18 +1192,56 @@ export default defineComponent({
 | 
	
		
			
				|  |  |        schoolId?: string
 | 
	
		
			
				|  |  |      ) => {
 | 
	
		
			
				|  |  |        try {
 | 
	
		
			
				|  |  | +        const videoBrowseData =
 | 
	
		
			
				|  |  | +          moreTime.value.length > 0 ? formatEffectiveTime(moreTime.value) : [];
 | 
	
		
			
				|  |  | +        const time =
 | 
	
		
			
				|  |  | +          videoBrowseData.length > 0 ? formatTimer(videoBrowseData) : 0;
 | 
	
		
			
				|  |  | +        // console.log(moreTime.value, videoBrowseData, 'video', time);
 | 
	
		
			
				|  |  | +        // const videoCountTime = videoIntervalRef?.counter.value
 | 
	
		
			
				|  |  | +        // 判断 视屏播放时间大于视屏播放有效时间则说明数据有问题,进行重置数据
 | 
	
		
			
				|  |  | +        const rate = Math.floor(
 | 
	
		
			
				|  |  | +          (time / Math.floor(videoForms.player.duration())) * 100
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        const params = {
 | 
	
		
			
				|  |  | +          id: forms.saveId,
 | 
	
		
			
				|  |  | +          useTime: pageBrowseTime, // 固定5秒
 | 
	
		
			
				|  |  | +          joinType,
 | 
	
		
			
				|  |  | +          userId,
 | 
	
		
			
				|  |  | +          schoolId
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  | +        let otherParams = {};
 | 
	
		
			
				|  |  | +        if (!userId) {
 | 
	
		
			
				|  |  | +          otherParams = {
 | 
	
		
			
				|  |  | +            videoBrowseData: JSON.stringify(videoBrowseData), // 视屏播放数据
 | 
	
		
			
				|  |  | +            videoBrowseDataTime: time || 0, // 有效的视频观看时长
 | 
	
		
			
				|  |  | +            videoBrowsePercentage: rate || 0, // 有效的视频观看时长百分比
 | 
	
		
			
				|  |  | +            videoBrowseTime: timer.getTime(), // 视频观看时长
 | 
	
		
			
				|  |  | +            videoBrowsePoint: videoForms.player.currentTime() // 视频最后观看点 - 向下取整
 | 
	
		
			
				|  |  | +          };
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // console.log(
 | 
	
		
			
				|  |  | +        //   videoIntervalRef.counter.value,
 | 
	
		
			
				|  |  | +        //   timer.getTime(),
 | 
	
		
			
				|  |  | +        //   videoForms.player.currentTime(),
 | 
	
		
			
				|  |  | +        //   videoBrowseData,
 | 
	
		
			
				|  |  | +        //   'timer count'
 | 
	
		
			
				|  |  | +        // );
 | 
	
		
			
				|  |  |          const { data } = await requestStudent.post(
 | 
	
		
			
				|  |  |            '/edu-app/open/studentRegisterPointRecord/update',
 | 
	
		
			
				|  |  |            {
 | 
	
		
			
				|  |  |              data: {
 | 
	
		
			
				|  |  | -              id: forms.saveId,
 | 
	
		
			
				|  |  | -              useTime: pageBrowseTime, // 固定10秒
 | 
	
		
			
				|  |  | -              joinType,
 | 
	
		
			
				|  |  | -              userId,
 | 
	
		
			
				|  |  | -              schoolId
 | 
	
		
			
				|  |  | +              ...params,
 | 
	
		
			
				|  |  | +              ...otherParams
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |            }
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // 不相同则说明不是一个人,数据重置
 | 
	
		
			
				|  |  | +        if (data !== forms.saveId) {
 | 
	
		
			
				|  |  | +          moreTime.value = [];
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |          forms.saveId = data;
 | 
	
		
			
				|  |  |          return data;
 | 
	
		
			
				|  |  |        } catch {
 | 
	
	
		
			
				|  | @@ -1196,6 +1294,219 @@ export default defineComponent({
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    /**
 | 
	
		
			
				|  |  | +     * 视屏累计时长
 | 
	
		
			
				|  |  | +     * 1、视屏开始播放时-开始计时
 | 
	
		
			
				|  |  | +     * 2、视频暂停时暂停-停止计时
 | 
	
		
			
				|  |  | +     * 3、视频加载时-停止计时
 | 
	
		
			
				|  |  | +     * 4、视频倍数播放时,时间正常计时
 | 
	
		
			
				|  |  | +     * 5、点击视频进度或拖动进度时,时间暂停
 | 
	
		
			
				|  |  | +     */
 | 
	
		
			
				|  |  | +    const _init = () => {
 | 
	
		
			
				|  |  | +      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="42px" height="42px" viewBox="0 0 42 42" 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"><circle stroke="#FFFFFF" stroke-width="1.0112392" fill-opacity="0.3" fill="#000000" stroke-linecap="square" cx="21" cy="21" r="20.5056196"></circle><g  transform="translate(13.000000, 12.000000)" fill="#FFFFFF"><path d="M11.7432433,3.46351367 L18.2071084,14.4520843 C18.7734418,15.4148511 18.4520691,16.6544316 17.4893024,17.2207649 C17.1784947,17.403593 16.8244584,17.5 16.4638651,17.5 L3.53613489,17.5 C2.41915092,17.5 1.51365649,16.5945056 1.51365649,15.4775216 C1.51365649,15.1169283 1.6100635,14.762892 1.79289156,14.4520843 L8.25675667,3.46351367 C8.82309003,2.50074696 10.0626705,2.17937423 11.0254373,2.74570759 C11.3218389,2.92006148 11.5688894,3.16711204 11.7432433,3.46351367 Z" id="三角形" transform="translate(10.000000, 9.000000) rotate(-270.000000) translate(-10.000000, -9.000000) "></path></g></g></svg></button>';
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        el.appendChild(
 | 
	
		
			
				|  |  | +          TCPlayer.dom.createEl('div', {
 | 
	
		
			
				|  |  | +            className: 'vjs-button-icon',
 | 
	
		
			
				|  |  | +            innerHTML: _html
 | 
	
		
			
				|  |  | +          })
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +        return el;
 | 
	
		
			
				|  |  | +      };
 | 
	
		
			
				|  |  | +      videoForms.player = TCPlayer('register-video', {
 | 
	
		
			
				|  |  | +        appID: '',
 | 
	
		
			
				|  |  | +        controls: true,
 | 
	
		
			
				|  |  | +        plugins: {}
 | 
	
		
			
				|  |  | +      }); // player-container-id 为播放器容器 ID,必须与 html 中一致
 | 
	
		
			
				|  |  | +      if (videoForms.player) {
 | 
	
		
			
				|  |  | +        videoForms.player.src(
 | 
	
		
			
				|  |  | +          videoForms.introductionVideo ||
 | 
	
		
			
				|  |  | +            'https://oss.dayaedu.com/ktyq/1715849628836a8856d6a.mp4'
 | 
	
		
			
				|  |  | +        ); // url 播放地址
 | 
	
		
			
				|  |  | +        videoForms.player.poster(
 | 
	
		
			
				|  |  | +          'https://oss.dayaedu.com/ktyq/17158281330381317fd87.png'
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        videoForms.player.on('ready', (item: any) => {
 | 
	
		
			
				|  |  | +          // console.log('ready', item);
 | 
	
		
			
				|  |  | +          // videoForms.player.pause()
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +        videoForms.player.on('loadedmetadata', () => {
 | 
	
		
			
				|  |  | +          console.log('loadedmetadata');
 | 
	
		
			
				|  |  | +          // videoForms.loading = false;
 | 
	
		
			
				|  |  | +          videoForms.player.currentTime(videoForms.videoBrowsePoint);
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // 速度变化时
 | 
	
		
			
				|  |  | +        videoForms.player.on('ratechange', () => {
 | 
	
		
			
				|  |  | +          videoForms.playerSpeed =
 | 
	
		
			
				|  |  | +            videoForms.playerSpeed < videoForms.player.playbackRate()
 | 
	
		
			
				|  |  | +              ? videoForms.player.playbackRate()
 | 
	
		
			
				|  |  | +              : videoForms.playerSpeed;
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        videoForms.player.on('seeking', () => {
 | 
	
		
			
				|  |  | +          console.log('seeking');
 | 
	
		
			
				|  |  | +          videoIntervalRef.isActive.value && videoIntervalRef.pause();
 | 
	
		
			
				|  |  | +          timer.pause();
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // // 拖动结束时
 | 
	
		
			
				|  |  | +        videoForms.player.on('seeked', () => {
 | 
	
		
			
				|  |  | +          console.log('seeked');
 | 
	
		
			
				|  |  | +          videoIntervalRef.isActive.value && videoIntervalRef.pause();
 | 
	
		
			
				|  |  | +          timer.pause();
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // 正在搜索中
 | 
	
		
			
				|  |  | +        videoForms.player.on('waiting', () => {
 | 
	
		
			
				|  |  | +          // console.log('waiting pause')
 | 
	
		
			
				|  |  | +          videoIntervalRef.isActive.value && videoIntervalRef.pause();
 | 
	
		
			
				|  |  | +          timer.pause();
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // 如何视频在缓存不会触发
 | 
	
		
			
				|  |  | +        videoForms.player.on('timeupdate', () => {
 | 
	
		
			
				|  |  | +          // console.log('timeupdate', videoForms.player.currentTime());
 | 
	
		
			
				|  |  | +          // 判断视频计时器是否暂停,如果暂停则恢复
 | 
	
		
			
				|  |  | +          // 添加 「videoForms.player.playing」 是由会跳转到上次播放时间,会触发些方法
 | 
	
		
			
				|  |  | +          if (
 | 
	
		
			
				|  |  | +            !videoIntervalRef.isActive.value &&
 | 
	
		
			
				|  |  | +            videoForms.player.currentTime() > 0 &&
 | 
	
		
			
				|  |  | +            !videoForms.player.paused()
 | 
	
		
			
				|  |  | +          ) {
 | 
	
		
			
				|  |  | +            // console.log('timeupdate play')
 | 
	
		
			
				|  |  | +            videoIntervalRef.resume();
 | 
	
		
			
				|  |  | +            timer.resume();
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // 视屏播放时暂停
 | 
	
		
			
				|  |  | +        videoForms.player.on('ended', () => {
 | 
	
		
			
				|  |  | +          videoForms.player.pause();
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // 开始播放
 | 
	
		
			
				|  |  | +        videoForms.player.on('play', () => {
 | 
	
		
			
				|  |  | +          console.log('play');
 | 
	
		
			
				|  |  | +          // 判断视频计时器是否暂停,如果暂停则恢复
 | 
	
		
			
				|  |  | +          videoIntervalRef.resume();
 | 
	
		
			
				|  |  | +          timer.resume();
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // 暂停播放
 | 
	
		
			
				|  |  | +        videoForms.player.on('pause', () => {
 | 
	
		
			
				|  |  | +          console.log('pause', videoIntervalRef.isActive.value);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          videoIntervalRef.pause();
 | 
	
		
			
				|  |  | +          timer.pause();
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        videoForms.player.on('fullscreenchange', () => {
 | 
	
		
			
				|  |  | +          if (videoForms.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', () => {
 | 
	
		
			
				|  |  | +              videoForms.player.exitFullscreen();
 | 
	
		
			
				|  |  | +            });
 | 
	
		
			
				|  |  | +            document.getElementsByClassName('video-js')[0].appendChild(i);
 | 
	
		
			
				|  |  | +          } else {
 | 
	
		
			
				|  |  | +            console.log('exitfullscreen');
 | 
	
		
			
				|  |  | +            const i = document.getElementById('fullscreen-back');
 | 
	
		
			
				|  |  | +            i && i.remove();
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 保存零时时间
 | 
	
		
			
				|  |  | +    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', videoForms.player.currentTime())
 | 
	
		
			
				|  |  | +      const initTime = deepClone(tempTime);
 | 
	
		
			
				|  |  | +      if (repeat) {
 | 
	
		
			
				|  |  | +        if (tempTime.length > 0) {
 | 
	
		
			
				|  |  | +          // console.log('join video', tempTime, 'initTime', initTime)
 | 
	
		
			
				|  |  | +          tempTime[1] =
 | 
	
		
			
				|  |  | +            Math.floor(videoForms.player.currentTime() * 1000) / 1000;
 | 
	
		
			
				|  |  | +          // tempTime[1] = videoForms.player.currentTime();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        if (newVal) {
 | 
	
		
			
				|  |  | +          // console.log(
 | 
	
		
			
				|  |  | +          //   videoForms.player.currentTime(),
 | 
	
		
			
				|  |  | +          //   'videoForms.player.currentTime()'
 | 
	
		
			
				|  |  | +          // );
 | 
	
		
			
				|  |  | +          tempTime[0] =
 | 
	
		
			
				|  |  | +            Math.floor(videoForms.player.currentTime() * 1000) / 1000;
 | 
	
		
			
				|  |  | +          // tempTime[0] = videoForms.player.currentTime();
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          tempTime[1] =
 | 
	
		
			
				|  |  | +            Math.floor(videoForms.player.currentTime() * 1000) / 1000;
 | 
	
		
			
				|  |  | +          // tempTime[1] = videoForms.player.currentTime();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // console.log(
 | 
	
		
			
				|  |  | +      //   newVal,
 | 
	
		
			
				|  |  | +      //   repeat,
 | 
	
		
			
				|  |  | +      //   tempTime,
 | 
	
		
			
				|  |  | +      //   tempTime.length,
 | 
	
		
			
				|  |  | +      //   'videoIntervalRef.isActive.value in'
 | 
	
		
			
				|  |  | +      // );
 | 
	
		
			
				|  |  | +      // console.log(videoForms.player.playbackRate(), 'speed');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      if (tempTime.length >= 2) {
 | 
	
		
			
				|  |  | +        // console.log(tempTime, 'tempTime', moreTime.value)
 | 
	
		
			
				|  |  | +        // 处理在短时间内的时间差 【视屏拖动,点击可能会导致时间差太大】
 | 
	
		
			
				|  |  | +        const diffTime =
 | 
	
		
			
				|  |  | +          tempTime[1] -
 | 
	
		
			
				|  |  | +            tempTime[0] -
 | 
	
		
			
				|  |  | +            currentTimer.counter.value * videoForms.playerSpeed >
 | 
	
		
			
				|  |  | +          2;
 | 
	
		
			
				|  |  | +        // console.log(diffTime, 'diffTime', currentTimer.counter.value, videoForms.playerSpeed, 'value')
 | 
	
		
			
				|  |  | +        // 结束时间,如果 大于开始时间则清除
 | 
	
		
			
				|  |  | +        if (tempTime[1] >= tempTime[0] && !diffTime)
 | 
	
		
			
				|  |  | +          moreTime.value.push(tempTime);
 | 
	
		
			
				|  |  | +        if (repeat) {
 | 
	
		
			
				|  |  | +          tempTime = deepClone(initTime);
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          tempTime = [];
 | 
	
		
			
				|  |  | +          currentTimer.counter.value = 0;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    watch(pageVisibility, (value: any) => {
 | 
	
		
			
				|  |  | +      if (value == 'hidden') {
 | 
	
		
			
				|  |  | +        videoForms.player.pause();
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      const pagePointInit = async () => {
 | 
	
		
			
				|  |  |        try {
 | 
	
		
			
				|  |  |          // 判断是否获取微信code码
 | 
	
	
		
			
				|  | @@ -1212,16 +1523,30 @@ export default defineComponent({
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  |          forms.saveId = data.id;
 | 
	
		
			
				|  |  |          forms.openId = data.openId;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        moreTime.value = data.videoBrowseData
 | 
	
		
			
				|  |  | +          ? JSON.parse(data.videoBrowseData)
 | 
	
		
			
				|  |  | +          : [];
 | 
	
		
			
				|  |  | +        videoForms.videoBrowsePoint = data.videoBrowsePoint || 0;
 | 
	
		
			
				|  |  | +        if (videoForms.player) {
 | 
	
		
			
				|  |  | +          videoForms.player.currentTime(data.videoBrowsePoint || 0);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          sessionStorage.setItem('active-open-id', data.openId);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          // 间隔多少时间同步数据
 | 
	
		
			
				|  |  |          forms.intervalFnRef = useIntervalFn(async () => {
 | 
	
		
			
				|  |  |            // 页面时间恢复
 | 
	
		
			
				|  |  | +          forms.intervalFnRef.pause();
 | 
	
		
			
				|  |  |            pageTimer.counter.value = 0;
 | 
	
		
			
				|  |  |            pageTimer.resume();
 | 
	
		
			
				|  |  |            // 同步数据时先进行有效时间进行保存
 | 
	
		
			
				|  |  | +          initVideoCount(false, true);
 | 
	
		
			
				|  |  | +          updateStat();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -          await updateStat();
 | 
	
		
			
				|  |  | +          timer.resetTime();
 | 
	
		
			
				|  |  | +          videoIntervalRef.counter.value = 0;
 | 
	
		
			
				|  |  | +          forms.intervalFnRef.resume();
 | 
	
		
			
				|  |  |          }, 5000);
 | 
	
		
			
				|  |  |        } catch {}
 | 
	
		
			
				|  |  |      };
 | 
	
	
		
			
				|  | @@ -1283,6 +1608,9 @@ export default defineComponent({
 | 
	
		
			
				|  |  |            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        // 初始化视频播放器
 | 
	
		
			
				|  |  | +        _init();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          await getRegisterGoods();
 | 
	
		
			
				|  |  |        } catch {}
 | 
	
		
			
				|  |  |      });
 | 
	
	
		
			
				|  | @@ -1321,15 +1649,30 @@ export default defineComponent({
 | 
	
		
			
				|  |  |              </div>
 | 
	
		
			
				|  |  |            )}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +          <div class={[styles.studentSection, styles.studentSectionForm]}>
 | 
	
		
			
				|  |  | +            <div class={styles.title4}></div>
 | 
	
		
			
				|  |  | +            <div class={styles['video-content']}>
 | 
	
		
			
				|  |  | +              <video
 | 
	
		
			
				|  |  | +                id="register-video"
 | 
	
		
			
				|  |  | +                class={styles['video']}
 | 
	
		
			
				|  |  | +                src={'https://oss.dayaedu.com/ktyq/1715849628836a8856d6a.mp4'}
 | 
	
		
			
				|  |  | +                playsinline={true}
 | 
	
		
			
				|  |  | +                poster={
 | 
	
		
			
				|  |  | +                  'https://oss.dayaedu.com/ktyq/17158281330381317fd87.png'
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                preload="auto"></video>
 | 
	
		
			
				|  |  | +            </div>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |            <div
 | 
	
		
			
				|  |  |              class={[
 | 
	
		
			
				|  |  |                styles.studentSection,
 | 
	
		
			
				|  |  |                styles.studentSectionForm,
 | 
	
		
			
				|  |  | -              styles.noSendDay
 | 
	
		
			
				|  |  | +              forms.giftVipDay <= 0 && styles.noSendDay
 | 
	
		
			
				|  |  |              ]}
 | 
	
		
			
				|  |  |              // style={{ display: 'none' }}
 | 
	
		
			
				|  |  |            >
 | 
	
		
			
				|  |  | -            <div class={styles.title3}></div>
 | 
	
		
			
				|  |  | +            <div class={styles.title1}></div>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              <Form labelAlign="left" class={styles.registerForm}>
 | 
	
		
			
				|  |  |                <Field
 | 
	
	
		
			
				|  | @@ -1400,22 +1743,8 @@ export default defineComponent({
 | 
	
		
			
				|  |  |                      )
 | 
	
		
			
				|  |  |                  }}
 | 
	
		
			
				|  |  |                </Field>
 | 
	
		
			
				|  |  | -            </Form>
 | 
	
		
			
				|  |  | -          </div>
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -          <div
 | 
	
		
			
				|  |  | -            class={[
 | 
	
		
			
				|  |  | -              styles.studentSection,
 | 
	
		
			
				|  |  | -              styles.studentSectionForm,
 | 
	
		
			
				|  |  | -              forms.giftVipDay <= 0 && styles.noSendDay
 | 
	
		
			
				|  |  | -            ]}
 | 
	
		
			
				|  |  | -            // style={{ display: 'none' }}
 | 
	
		
			
				|  |  | -          >
 | 
	
		
			
				|  |  | -            <div class={styles.title1}></div>
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            <Form labelAlign="left" class={styles.registerForm}>
 | 
	
		
			
				|  |  |                {/* 大于等于2,则可以切换学生 */}
 | 
	
		
			
				|  |  | -              {forms.studentList.length > 1 && (
 | 
	
		
			
				|  |  | +              {/* {forms.studentList.length > 1 && (
 | 
	
		
			
				|  |  |                  <div
 | 
	
		
			
				|  |  |                    class={[
 | 
	
		
			
				|  |  |                      styles.selectStudentGroup,
 | 
	
	
		
			
				|  | @@ -1433,7 +1762,7 @@ export default defineComponent({
 | 
	
		
			
				|  |  |                        : '新增学生'}
 | 
	
		
			
				|  |  |                    </span>
 | 
	
		
			
				|  |  |                  </div>
 | 
	
		
			
				|  |  | -              )}
 | 
	
		
			
				|  |  | +              )} */}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                <Field
 | 
	
		
			
				|  |  |                  clearable={false}
 | 
	
	
		
			
				|  | @@ -1443,8 +1772,24 @@ export default defineComponent({
 | 
	
		
			
				|  |  |                  placeholder="请输入学生姓名"
 | 
	
		
			
				|  |  |                  autocomplete="off"
 | 
	
		
			
				|  |  |                  maxlength={14}
 | 
	
		
			
				|  |  | -                v-model={studentInfo.extra.nickname}
 | 
	
		
			
				|  |  | -              />
 | 
	
		
			
				|  |  | +                v-model={studentInfo.extra.nickname}>
 | 
	
		
			
				|  |  | +                {{
 | 
	
		
			
				|  |  | +                  extra: () =>
 | 
	
		
			
				|  |  | +                    forms.studentList.length > 1 && (
 | 
	
		
			
				|  |  | +                      <div
 | 
	
		
			
				|  |  | +                        class={[
 | 
	
		
			
				|  |  | +                          styles.selectStudentGroup,
 | 
	
		
			
				|  |  | +                          forms.showSelectStudent &&
 | 
	
		
			
				|  |  | +                            styles.selectStudentGroupChecked
 | 
	
		
			
				|  |  | +                        ]}
 | 
	
		
			
				|  |  | +                        onClick={() => (forms.showSelectStudent = true)}>
 | 
	
		
			
				|  |  | +                        <span>
 | 
	
		
			
				|  |  | +                          {forms.studentItem.userId ? '切换' : '新增'}
 | 
	
		
			
				|  |  | +                        </span>
 | 
	
		
			
				|  |  | +                      </div>
 | 
	
		
			
				|  |  | +                    )
 | 
	
		
			
				|  |  | +                }}
 | 
	
		
			
				|  |  | +              </Field>
 | 
	
		
			
				|  |  |                <Field
 | 
	
		
			
				|  |  |                  clearable={false}
 | 
	
		
			
				|  |  |                  required
 | 
	
	
		
			
				|  | @@ -1594,9 +1939,35 @@ export default defineComponent({
 | 
	
		
			
				|  |  |                  <div class={styles.goodsInner}>传统方式</div>
 | 
	
		
			
				|  |  |                </div>
 | 
	
		
			
				|  |  |              </div>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            {forms.joinType && (
 | 
	
		
			
				|  |  | +              <div class={styles.goodsTypeGroup}>
 | 
	
		
			
				|  |  | +                {forms.joinType === 'digitalize' && (
 | 
	
		
			
				|  |  | +                  <>
 | 
	
		
			
				|  |  | +                    <img src={icon10} class={styles.showImg} />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    {forms.detailVip.membershipDays ? (
 | 
	
		
			
				|  |  | +                      <div class={styles.memberNumer}>
 | 
	
		
			
				|  |  | +                        <img src={iconGift} class={styles.iconGift} />
 | 
	
		
			
				|  |  | +                        <p>
 | 
	
		
			
				|  |  | +                          首次购买赠送乐器AI学练工具
 | 
	
		
			
				|  |  | +                          <span>{forms.detailVip.membershipDays || 0}</span>
 | 
	
		
			
				|  |  | +                          天有效期
 | 
	
		
			
				|  |  | +                        </p>
 | 
	
		
			
				|  |  | +                      </div>
 | 
	
		
			
				|  |  | +                    ) : (
 | 
	
		
			
				|  |  | +                      ''
 | 
	
		
			
				|  |  | +                    )}
 | 
	
		
			
				|  |  | +                  </>
 | 
	
		
			
				|  |  | +                )}
 | 
	
		
			
				|  |  | +                {forms.joinType === 'tradition' && (
 | 
	
		
			
				|  |  | +                  <img src={icon11} class={styles.showImg} />
 | 
	
		
			
				|  |  | +                )}
 | 
	
		
			
				|  |  | +              </div>
 | 
	
		
			
				|  |  | +            )}
 | 
	
		
			
				|  |  |            </div>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -          {forms.joinType === 'digitalize' && (
 | 
	
		
			
				|  |  | +          {/* {forms.joinType === 'digitalize' && (
 | 
	
		
			
				|  |  |              <div class={[styles.goodsExtra]}>
 | 
	
		
			
				|  |  |                <i class={styles.iconArrow}></i>
 | 
	
		
			
				|  |  |                <Cell border={false} class={styles.goodsCell}>
 | 
	
	
		
			
				|  | @@ -1611,16 +1982,13 @@ export default defineComponent({
 | 
	
		
			
				|  |  |                      <div class={styles.section}>
 | 
	
		
			
				|  |  |                        <div class={styles.sectionContent}>
 | 
	
		
			
				|  |  |                          <h2>
 | 
	
		
			
				|  |  | -                          {/* {forms.detailVip.goodsName} */}
 | 
	
		
			
				|  |  |                            <img src={icon5} class={styles.goodsName} />
 | 
	
		
			
				|  |  |                            <Tag class={styles.brandName}>
 | 
	
		
			
				|  |  | -                            {/* {forms.detailVip.brandName} */}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |                              12个月
 | 
	
		
			
				|  |  |                            </Tag>
 | 
	
		
			
				|  |  |                          </h2>
 | 
	
		
			
				|  |  |                          <p class={[styles.model]}>
 | 
	
		
			
				|  |  | -                          {/* 解决学生不会练、不知练的对错、家长无法辅导、无需再额外请老师 */}
 | 
	
		
			
				|  |  | -                          {/* {forms.detailVip.description} */}
 | 
	
		
			
				|  |  |                            <p>
 | 
	
		
			
				|  |  |                              <i></i>解决学生不会练、不知练的对错
 | 
	
		
			
				|  |  |                            </p>
 | 
	
	
		
			
				|  | @@ -1628,7 +1996,6 @@ export default defineComponent({
 | 
	
		
			
				|  |  |                              <i></i>家长无法辅导、无需再额外请老师
 | 
	
		
			
				|  |  |                            </p>
 | 
	
		
			
				|  |  |                          </p>
 | 
	
		
			
				|  |  | -                        {/* <span class={styles.sendInstrument}>赠送课堂乐器</span> */}
 | 
	
		
			
				|  |  |                          <img src={icon6} class={styles.sendInstrument} />
 | 
	
		
			
				|  |  |                        </div>
 | 
	
		
			
				|  |  |                      </div>
 | 
	
	
		
			
				|  | @@ -1688,13 +2055,12 @@ export default defineComponent({
 | 
	
		
			
				|  |  |                          'C调、木质、高音德式八孔;'}
 | 
	
		
			
				|  |  |                        {forms.instrumentCode === 'Woodwind' &&
 | 
	
		
			
				|  |  |                          'C调、红木色、树脂或木质;'}
 | 
	
		
			
				|  |  | -                      {/* 管数不限,建议20管以上C调加嘴排箫(音域宽,能演奏更多复杂乐曲,不需要重复更换),黑色,要选择单一原调(调性多学生很难掌握),价格由学生根据自身情况确定。 */}
 | 
	
		
			
				|  |  |                      </div>
 | 
	
		
			
				|  |  |                    </div>
 | 
	
		
			
				|  |  |                  )}
 | 
	
		
			
				|  |  |                </div>
 | 
	
		
			
				|  |  |              </div>
 | 
	
		
			
				|  |  | -          )}
 | 
	
		
			
				|  |  | +          )} */}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |            {forms.joinType && (
 | 
	
		
			
				|  |  |              <MSticky position="bottom" ref={mstickyRef}>
 |