|
@@ -0,0 +1,3146 @@
|
|
|
+<template>
|
|
|
+ <div>
|
|
|
+ <el-dialog
|
|
|
+ :title="examId"
|
|
|
+ center
|
|
|
+ width="68%"
|
|
|
+ top="8vh"
|
|
|
+ height="60%"
|
|
|
+ destroy-on-close
|
|
|
+ fullscreen
|
|
|
+ :visible.sync="showPlayer"
|
|
|
+ :modal="false"
|
|
|
+ :before-close="handlBeforeClose"
|
|
|
+ custom-class="el-dialog-body"
|
|
|
+ @close="handlePlayerClose"
|
|
|
+ >
|
|
|
+ <p>播放源地址:{{ viewCamurl }}</p>
|
|
|
+ <div v-show="anchorFlag && !caliFlag" style="display: flex; margin-top: 10px;">
|
|
|
+ <el-button type="primary" size="mini" style="" @click="startAnchor()">开始布点</el-button>
|
|
|
+
|
|
|
+ <el-button type="primary" size="mini" style="margin-left:5px;" :disabled="btnDis" :loading="btnDis" @click="lastAnchor()"
|
|
|
+ >上次布点
|
|
|
+ </el-button>
|
|
|
+ <el-upload action="#" :before-upload="loadAnchorFile" accept=".json" :show-file-list="false" style="margin-left:5px;">
|
|
|
+ <el-button size="mini" type="primary">加载布点</el-button>
|
|
|
+ </el-upload>
|
|
|
+ <!-- <el-button @onclick="" size="mini" type="primary" style="margin-left: 5px;">重置布点</el-button> -->
|
|
|
+ <el-button type="primary" size="mini" style="margin-left: 5px;" @click="saveAnchor()"> 保存 </el-button>
|
|
|
+ </div>
|
|
|
+ <br />
|
|
|
+ <canvas id="canvas" width="0" height="0" style="background-color:black;" />
|
|
|
+ <div
|
|
|
+ v-loading="!anchorFlag"
|
|
|
+ element-loading-text="请稍等几秒"
|
|
|
+ element-loading-spinner="el-icon-loading"
|
|
|
+ element-loading-background="rgba(0, 0, 0, 0.8)"
|
|
|
+ >
|
|
|
+ <video id="videoflv" muted style="height:720px;background-color:black;" controls autoplay />
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <el-dialog :key="snapTime" :title="picTitle" center fullscreen destroy-on-close :visible.sync="showSnapPics">
|
|
|
+ <p>
|
|
|
+ 布点图最后更新:<b> {{ snapTime }}</b>
|
|
|
+ <!-- 布点文件最后更新:<b>{{anchorUptime[camIndex+'_error'] || anchorUptime[camIndex]}}</b> -->
|
|
|
+ <!-- 矫正文件最后更新:<b>{{camparamUptime[camIndex + '_error']|| camparamUptime[camIndex] || '未上传' }} </b> -->
|
|
|
+ </p>
|
|
|
+ <div style="display:flex; margin-top:5px;">
|
|
|
+ <el-image id="snapPic" :src="snapPic" style="width:100%;" class="sanPicShowDia" lazy>
|
|
|
+ <div slot="error" class="image-slot">
|
|
|
+ <i class="el-icon-picture-outline" />
|
|
|
+ <p>抱歉,布点文件生成失败,请稍后点击右侧刷新按钮重试。</p>
|
|
|
+ </div>
|
|
|
+ </el-image>
|
|
|
+ <div style="display: flex; flex-direction: column; align-items: flex-end; margin-left: 1px;">
|
|
|
+ <el-button type="success" size="mini" style="" @click="showSnap(0, camIndex, 'snapshot')"> 刷新布点 </el-button>
|
|
|
+ <el-button type="primary" size="mini" style="margin-top: 5px;" @click="upAndDownPFile(camIndex, 'json')">下载布点 </el-button>
|
|
|
+ <el-button v-if="camparamUptime[camIndex]" type="primary" size="mini" style="margin-top: 5px;" @click="upAndDownPFile(camIndex, 'yml')"
|
|
|
+ >下载矫正
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+ <el-container style="background: #ecf3f9;">
|
|
|
+ <el-header class="navbar">
|
|
|
+ <div class="nav1">
|
|
|
+ <div style="font-size: 20px; bold; font-weight: bold;">
|
|
|
+ <div @click="$router.push('/set/config')">返回</div>
|
|
|
+
|
|
|
+ </div>
|
|
|
+ <h3 style="font-weight:bold;">{{ examCN }}</h3>
|
|
|
+ <div>
|
|
|
+ <el-button type="primary" size="small" @click="submitForm('ruleForm', 0)">保存</el-button>
|
|
|
+ <!-- <el-button type="primary" @click="submitForm('ruleForm', 1)">保存并重启</el-button> -->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-header>
|
|
|
+ <el-main class="container-main">
|
|
|
+ <div class="">
|
|
|
+ <el-form
|
|
|
+ ref="ruleForm"
|
|
|
+ :model="ruleForm"
|
|
|
+ :rules="rules"
|
|
|
+ label-width="122px"
|
|
|
+ style="font-size:18px;letter-spacing:0;word-spacing:0"
|
|
|
+ label-position="left"
|
|
|
+ size="small"
|
|
|
+ >
|
|
|
+ <el-collapse v-model="activeNames">
|
|
|
+ <el-collapse-item style="margin-left:-4px; color:#0067E1; font-size: 14px; " name="1">
|
|
|
+ <template slot="title">
|
|
|
+ 基础设置
|
|
|
+ <!-- <i class="header-icon el-icon-info"></i> -->
|
|
|
+ </template>
|
|
|
+ <template v-for="value, item in ruleForm">
|
|
|
+ <template v-if="item in examFormConf['required']">
|
|
|
+ <template v-if="item === 'cam_path'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <span slot="label">
|
|
|
+ {{ anchorLabelObj[item] }}
|
|
|
+ <el-popover placement="right" width="width:30%" trigger="hover">
|
|
|
+ <div style="height:100px; font-size:12px; margin-bottom: 20px;line-height:20px;">
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ 大华摄像头示例: <br />
|
|
|
+ rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ 大华摄像头示例-h265: <br />
|
|
|
+ rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0,coder=h265
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0,coder=h265', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ 海康摄像头示例: <br />
|
|
|
+ rtsp://admin:tropsedu123@192.168.3.77:554/h265/ch1/main/av_stream,coder=h265
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('rtsp://admin:tropsedu123@192.168.3.77:554/h265/ch1/main/av_stream,coder=h265', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ USB摄像头示例: <br />
|
|
|
+ /dev/video0,width=1280,height=720,framerate=30
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('/dev/video0,width=1280,height=720,framerate=30', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <i slot="reference" class="el-icon-question" />
|
|
|
+ </el-popover>
|
|
|
+ </span>
|
|
|
+
|
|
|
+ <el-input v-model="ruleForm.cam_path" clearable style="width:45%; margin-right:5px;" />
|
|
|
+ <span style="margin-right:4px;font-size:10px;">帧率</span>
|
|
|
+ <el-input v-model.number="ruleForm.cam_fps" style="width:9.66%;margin-right:5px;" />
|
|
|
+ <el-button icon="el-icon-video-camera" type="primary" size="small" @click.prevent="viewCam(1, 0, ruleForm.cam_fps, 1)"
|
|
|
+ >远程布点</el-button
|
|
|
+ >
|
|
|
+ <el-button
|
|
|
+ icon="el-icon-video-camera"
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ style="margin-left:5px;"
|
|
|
+ :disabled="!hasLocSRS"
|
|
|
+ @click.prevent="viewCam(1, 0, ruleForm.cam_fps, 3)"
|
|
|
+ >本地布点</el-button
|
|
|
+ >
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+ <template v-if="item === 'anchor_path'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input v-model="ruleForm.anchor_path" disabled class="input45" clearable />
|
|
|
+ <el-button type="primary" size="small" plain @click.prevent="showSnap(0, 1)">预览</el-button>
|
|
|
+ <el-button type="primary" size="small" plain style="margin-left:5px;" @click.prevent="checkAnchorUrl('', 1)">刷新</el-button>
|
|
|
+ <el-upload
|
|
|
+ name="upload_file"
|
|
|
+ style="display: inline-block; margin-left: 5px; margin-right:5px;"
|
|
|
+ action="#"
|
|
|
+ :show-file-list="false"
|
|
|
+ :data="{exam_id: examId, cindex: 1, school_id: schoolId}"
|
|
|
+ :action="uploadUrl"
|
|
|
+ :headers="headers"
|
|
|
+ :on-success="handleUpload"
|
|
|
+ >
|
|
|
+ <el-button type="primary" size="small" plain>上传布点</el-button>
|
|
|
+ </el-upload>
|
|
|
+ <el-button type="primary" size="small" plain @click.prevent="upAndDownPFile(1, 'json')">下载布点</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="item === 'flag_calibrate'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-switch v-model="ruleForm.flag_calibrate" :active-value="1" :inactive-value="0" />
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="item == 'cam_param_path'">
|
|
|
+ <el-collapse-transition>
|
|
|
+ <div v-show="ruleForm.flag_calibrate">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input v-model="ruleForm.cam_param_path" disabled class="input45" />
|
|
|
+ <!-- <el-button @click.prevent="viewCam(1, 1, ruleForm.cam_fps, 1)" type="primary" size="small" plain>预览</el-button> -->
|
|
|
+ <el-button type="primary" size="small" style="" @click.prevent="checkAnchorUrl('', 1, 'yml')">刷新</el-button>
|
|
|
+ <el-upload
|
|
|
+ name="upload_file"
|
|
|
+ style="display:inline-block; margin-left: 5px;margin-right:5px;"
|
|
|
+ action="#"
|
|
|
+ :show-file-list="false"
|
|
|
+ :data="{exam_id: examId, cindex: 1, school_id: schoolId, up_type:'yml'}"
|
|
|
+ :action="uploadUrl"
|
|
|
+ :headers="headers"
|
|
|
+ :on-success="handleUpload"
|
|
|
+ ><el-button type="primary" size="small">上传矫正</el-button>
|
|
|
+ </el-upload>
|
|
|
+ <el-button type="primary" size="mini" @click="upAndDownPFile(1, 'yml')">下载矫正 </el-button>
|
|
|
+ <el-button type="primary" size="small" @click.prevent="viewCam(1, 2, ruleForm.cam_fps, 1)">远程矫正</el-button>
|
|
|
+ <el-button type="primary" size="small" :disabled="!hasLocSRS" @click.prevent="viewCam(1, 2, ruleForm.cam_fps, 4)"
|
|
|
+ >本地矫正</el-button
|
|
|
+ >
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ </el-collapse-transition>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="item == 'cam_0_path'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <span slot="label">
|
|
|
+ {{ anchorLabelObj[item] }}
|
|
|
+ <el-popover placement="right" width="width:30%" trigger="hover">
|
|
|
+ <div style="height:100px; font-size:12px; margin-bottom: 20px;line-height:20px;">
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ 大华摄像头示例: <br />
|
|
|
+ rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ 海康摄像头示例: <br />
|
|
|
+ rtsp://admin:tropsedu123@192.168.3.77:554/h265/ch1/main/av_stream
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('rtsp://admin:tropsedu123@192.168.3.77:554/h265/ch1/main/av_stream', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ USB摄像头示例: <br />
|
|
|
+ /dev/video0,width=1280,height=720,framerate=30
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('/dev/video0,width=1280,height=720,framerate=30')"
|
|
|
+ >
|
|
|
+ 复制</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <i slot="reference" class="el-icon-question" />
|
|
|
+ </el-popover>
|
|
|
+ </span>
|
|
|
+ <el-input v-model="ruleForm.cam_0_path" style="width:45%; margin-right:5px;" />
|
|
|
+ <span style="margin-right:4px; font-size:10px;">帧率</span>
|
|
|
+ <el-input v-model.number="ruleForm.cam_fps" style="width:9.66%;margin-right:5px;" />
|
|
|
+ <el-button icon="el-icon-video-camera" type="primary" size="small" @click.prevent="viewCam(2, 0, ruleForm.cam_fps, 1)"
|
|
|
+ >远程布点</el-button
|
|
|
+ >
|
|
|
+ <el-button
|
|
|
+ icon="el-icon-video-camera"
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ style="margin-left:5px;"
|
|
|
+ :disabled="!hasLocSRS"
|
|
|
+ @click.prevent="viewCam(2, 0, ruleForm.cam_fps, 3)"
|
|
|
+ >本地布点</el-button
|
|
|
+ >
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="item == 'anchor_0_path'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input v-model="ruleForm.anchor_0_path" disabled class="input45" />
|
|
|
+ <el-button type="primary" size="small" plain @click.prevent="showSnap(0, 2)">预览</el-button>
|
|
|
+ <!-- <el-button @click.prevent="handleDown(2)" type="primary">下载布点</el-button> -->
|
|
|
+ <el-button type="primary" size="small" plain style="margin-left:5px;" @click.prevent="checkAnchorUrl('', 2)">刷新</el-button>
|
|
|
+ <el-upload
|
|
|
+ name="upload_file"
|
|
|
+ style="display: inline; margin-left: 5px;"
|
|
|
+ action="#"
|
|
|
+ :data="{exam_id: examId, cindex: 2, school_id: schoolId}"
|
|
|
+ :show-file-list="false"
|
|
|
+ :action="uploadUrl"
|
|
|
+ :headers="headers"
|
|
|
+ :on-success="handleUpload"
|
|
|
+ >
|
|
|
+ <el-button type="primary" size="small" plain>上传布点</el-button>
|
|
|
+ </el-upload>
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="item == 'cam_face_path'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <span slot="label">
|
|
|
+ {{ anchorLabelObj[item] }}
|
|
|
+ <el-popover placement="right" width="width:30%" trigger="hover">
|
|
|
+ <div style="height:100px; font-size:12px; margin-bottom: 20px;line-height:20px;">
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ 大华摄像头示例: <br />
|
|
|
+ rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ 海康摄像头示例: <br />
|
|
|
+ rtsp://admin:tropsedu123@192.168.3.77:554/h265/ch1/main/av_stream
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('rtsp://admin:tropsedu123@192.168.3.77:554/h265/ch1/main/av_stream', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ USB摄像头示例: <br />
|
|
|
+ /dev/video0,width=1280,height=720,framerate=30
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('/dev/video0,width=1280,height=720,framerate=30')"
|
|
|
+ >
|
|
|
+ 复制</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <i slot="reference" class="el-icon-question" />
|
|
|
+ </el-popover>
|
|
|
+ </span>
|
|
|
+ <el-input v-model="ruleForm.cam_face_path" style="width:45% ;margin-right:5px;" clearable />
|
|
|
+ <span style="margin-right:4px; font-size:10px;">帧率</span>
|
|
|
+ <el-input v-model.number="ruleForm.cam_face_fps" style="width:9.66%;margin-right:5px;" />
|
|
|
+ <el-button icon="el-icon-video-camera" type="primary" size="small" @click.prevent="viewCam(0, 0, ruleForm.cam_face_fps, 1)"
|
|
|
+ >远程布点</el-button
|
|
|
+ >
|
|
|
+ <el-button
|
|
|
+ icon="el-icon-video-camera"
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ style="margin-left:5px;"
|
|
|
+ :disabled="!hasLocSRS"
|
|
|
+ @click.prevent="viewCam(0, 0, ruleForm.cam_face_fps, 3)"
|
|
|
+ >本地布点</el-button
|
|
|
+ >
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+ <template v-if="item == 'anchor_face_path'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input v-model="ruleForm.anchor_face_path" disabled class="input45" />
|
|
|
+ <el-button type="primary" size="small" plain @click.prevent="showSnap(0, 0)">预览</el-button>
|
|
|
+ <el-button type="primary" size="small" plain style="margin-left:5px;" @click.prevent="checkAnchorUrl('', 0)">刷新</el-button>
|
|
|
+ <el-upload
|
|
|
+ name="upload_file"
|
|
|
+ style="display: inline-block; margin-left: 5px;"
|
|
|
+ action="#"
|
|
|
+ :show-file-list="false"
|
|
|
+ :data="{ exam_id: examId, cindex: 0, school_id: schoolId}"
|
|
|
+ :action="uploadUrl"
|
|
|
+ :headers="headers"
|
|
|
+ :on-success="handleUpload"
|
|
|
+ >
|
|
|
+ <el-button type="primary" size="small" plain>上传布点</el-button>
|
|
|
+ </el-upload>
|
|
|
+ <el-button type="primary" size="small" plain @click.prevent="upAndDownPFile(0, 'json')">下载布点 </el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template
|
|
|
+ v-if="['flag_check_stline', 'flag_check_back',
|
|
|
+ 'flag_check_hip', 'flag_check_knee', 'flag_check_stline', 'flag_check_hand', 'flag_check_elbow', 'flag_save',
|
|
|
+ 'flag_display', 'flag_check_person', 'flag_check_singleleg_jump'].includes(item)"
|
|
|
+ >
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-switch v-model="ruleForm[item]" :active-value="1" :inactive-value="0" />
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template
|
|
|
+ v-if="['distance_ground', 'distance_maximum', 'height_maximum','length_air_line',
|
|
|
+ 'distance_ground_between_lines', 'length_ground_line',
|
|
|
+ 'distance_air_between_lines', 'distance_per_round',
|
|
|
+ 'num_of_tracks', 'num_of_tracks_startline', 'num_of_tracks_endline', 'delay_cam_second', 'delay_cmd_second'
|
|
|
+ ].includes(item) "
|
|
|
+ >
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input-number v-model="ruleForm[item]" style="width:30%" /><span
|
|
|
+ style="margin-right:4px; padding-left:10px; font-size:18px;"
|
|
|
+ >cm</span
|
|
|
+ >
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="item == 'difficulty'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input-number v-model="ruleForm.difficulty" :min="0" :max="5" style="width:30%" />
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+ <template v-if="item == 'test_time'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input-number v-model="ruleForm.test_time" :min="1" :max="1000" style="width:30%" />
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </el-collapse-item>
|
|
|
+ <el-collapse-item style="margin-left:-4px; color:#0067E1; font-size: 14px;">
|
|
|
+ <template slot="title">
|
|
|
+ 高级设置
|
|
|
+ <!-- <i class="header-icon el-icon-info"></i> -->
|
|
|
+ </template>
|
|
|
+ <template v-for="value, item in ruleForm">
|
|
|
+ <template v-if="item in examFormConf['advanced']">
|
|
|
+ <template v-if="item === 'cam_path'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <span slot="label">
|
|
|
+ {{ anchorLabelObj[item] }}
|
|
|
+ <el-popover placement="right" width="width:30%" trigger="hover">
|
|
|
+ <div style="height:100px; font-size:12px; margin-bottom: 20px;line-height:20px;">
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ 大华摄像头示例: <br />
|
|
|
+ rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ 海康摄像头示例: <br />
|
|
|
+ rtsp://admin:tropsedu123@192.168.3.77:554/h265/ch1/main/av_stream
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('rtsp://admin:tropsedu123@192.168.3.77:554/h265/ch1/main/av_stream', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ USB摄像头示例: <br />
|
|
|
+ /dev/video0,width=1280,height=720,framerate=30
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('/dev/video0,width=1280,height=720,framerate=30', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <i slot="reference" class="el-icon-question" />
|
|
|
+ </el-popover>
|
|
|
+ </span>
|
|
|
+
|
|
|
+ <el-input v-model="ruleForm.cam_path" clearable style="width:45%; margin-right:5px;" />
|
|
|
+ <span style="margin-right:4px;font-size:10px;">帧率</span>
|
|
|
+ <el-input v-model.number="ruleForm.cam_fps" style="width:9.66%;margin-right:5px;" />
|
|
|
+ <el-button icon="el-icon-video-camera" type="primary" size="small" @click.prevent="viewCam(1, 0, ruleForm.cam_fps, 1)"
|
|
|
+ >远程布点</el-button
|
|
|
+ >
|
|
|
+ <el-button
|
|
|
+ icon="el-icon-video-camera"
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ style="margin-left:5px;"
|
|
|
+ :disabled="!hasLocSRS"
|
|
|
+ @click.prevent="viewCam(1, 0, ruleForm.cam_fps, 3)"
|
|
|
+ >本地布点</el-button
|
|
|
+ >
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+ <template v-if="item === 'anchor_path'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input v-model="ruleForm.anchor_path" disabled class="input45" />
|
|
|
+ <el-button type="primary" size="small" plain @click.prevent="showSnap(0, 1)">预览</el-button>
|
|
|
+ <el-button type="primary" size="small" plain style="margin-left:5px;" @click.prevent="checkAnchorUrl('', 1)">刷新</el-button>
|
|
|
+ <el-upload
|
|
|
+ name="upload_file"
|
|
|
+ style="display: inline; margin-left: 5px;"
|
|
|
+ action="#"
|
|
|
+ :show-file-list="false"
|
|
|
+ :data="{exam_id: examId, cindex: 1, school_id: schoolId}"
|
|
|
+ :action="uploadUrl"
|
|
|
+ :headers="headers"
|
|
|
+ :on-success="handleUpload"
|
|
|
+ >
|
|
|
+ <el-button type="primary" size="small" plain>上传布点</el-button>
|
|
|
+ </el-upload>
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="item === 'flag_calibrate'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-switch v-model="ruleForm.flag_calibrate" :active-value="1" :inactive-value="0" />
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="item == 'cam_param_path'">
|
|
|
+ <el-collapse-transition>
|
|
|
+ <div v-show="ruleForm.flag_calibrate">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input v-model="ruleForm.cam_param_path" disabled class="input45" />
|
|
|
+ <!-- <el-button @click.prevent="viewCam(1, 1, ruleForm.cam_fps, 1)" type="primary" size="small" plain>预览</el-button> -->
|
|
|
+ <el-button type="primary" size="small" plain style="margin-left:5px;" @click.prevent="checkAnchorUrl('', 1, 'yml')"
|
|
|
+ >刷新</el-button
|
|
|
+ >
|
|
|
+
|
|
|
+ <el-upload
|
|
|
+ name="upload_file"
|
|
|
+ style="display: inline-block; margin-left: 5px;"
|
|
|
+ action="#"
|
|
|
+ :show-file-list="false"
|
|
|
+ :data="{exam_id: examId, cindex: 1, school_id: schoolId, up_type:'yml'}"
|
|
|
+ :action="uploadUrl"
|
|
|
+ :headers="headers"
|
|
|
+ :on-success="handleUpload"
|
|
|
+ ><el-button type="primary" size="small" plain>上传矫正</el-button>
|
|
|
+ </el-upload>
|
|
|
+
|
|
|
+ <el-button type="primary" size="small" plain style="margin-left: 5px;" @click="upAndDownPFile(1, 'yml')"
|
|
|
+ >下载矫正
|
|
|
+ </el-button>
|
|
|
+
|
|
|
+ <el-button type="primary" size="small" plain style="margin-left:5px;" @click.prevent="viewCam(1, 2, ruleForm.cam_fps, 1)"
|
|
|
+ >远程矫正</el-button
|
|
|
+ >
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ plain
|
|
|
+ style="margin-left:5px;"
|
|
|
+ :disabled="!hasLocSRS"
|
|
|
+ @click.prevent="viewCam(1, 2, ruleForm.cam_fps, 4)"
|
|
|
+ >本地矫正</el-button
|
|
|
+ >
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ </el-collapse-transition>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="item == 'cam_0_path'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <span slot="label">
|
|
|
+ {{ anchorLabelObj[item] }}
|
|
|
+ <el-popover placement="right" width="width:30%" trigger="hover">
|
|
|
+ <div style="height:100px; font-size:12px; margin-bottom: 20px;line-height:20px;">
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ 大华摄像头示例: <br />
|
|
|
+ rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ 海康摄像头示例: <br />
|
|
|
+ rtsp://admin:tropsedu123@192.168.3.77:554/h265/ch1/main/av_stream
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('rtsp://admin:tropsedu123@192.168.3.77:554/h265/ch1/main/av_stream', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ USB摄像头示例: <br />
|
|
|
+ /dev/video0,width=1280,height=720,framerate=30
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('/dev/video0,width=1280,height=720,framerate=30')"
|
|
|
+ >
|
|
|
+ 复制</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <i slot="reference" class="el-icon-question" />
|
|
|
+ </el-popover>
|
|
|
+ </span>
|
|
|
+ <el-input v-model="ruleForm.cam_0_path" style="width:45%; margin-right:5px;" />
|
|
|
+ <span style="margin-right:4px; font-size:10px;">帧率</span>
|
|
|
+ <el-input v-model.number="ruleForm.cam_fps" style="width:9.66%;margin-right:5px;" />
|
|
|
+ <el-button icon="el-icon-video-camera" type="primary" size="small" @click.prevent="viewCam(2, 0, ruleForm.cam_fps, 1)"
|
|
|
+ >远程布点</el-button
|
|
|
+ >
|
|
|
+ <el-button
|
|
|
+ icon="el-icon-video-camera"
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ style="margin-left:5px;"
|
|
|
+ :disabled="!hasLocSRS"
|
|
|
+ @click.prevent="viewCam(2, 0, ruleForm.cam_fps, 3)"
|
|
|
+ >本地布点</el-button
|
|
|
+ >
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="item == 'anchor_0_path'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input v-model="ruleForm.anchor_0_path" disabled class="input45" />
|
|
|
+ <el-button type="primary" size="small" plain @click.prevent="showSnap(0, 2)">预览</el-button>
|
|
|
+ <el-button type="primary" size="small" plain style="margin-left:5px;" @click.prevent="checkAnchorUrl('', 2)">刷新</el-button>
|
|
|
+ <el-upload
|
|
|
+ name="upload_file"
|
|
|
+ style="display: inline; margin-left: 5px;"
|
|
|
+ action="#"
|
|
|
+ :show-file-list="false"
|
|
|
+ :data="{exam_id: examId, cindex: 2, school_id: schoolId}"
|
|
|
+ :action="uploadUrl"
|
|
|
+ :headers="headers"
|
|
|
+ :on-success="handleUpload"
|
|
|
+ >
|
|
|
+ <el-button type="primary" size="small" plain>上传布点</el-button>
|
|
|
+ </el-upload>
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="item == 'cam_face_path'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <span slot="label">
|
|
|
+ {{ anchorLabelObj[item] }}
|
|
|
+ <el-popover placement="right" width="width:30%" trigger="hover">
|
|
|
+ <div style="height:100px; font-size:12px; margin-bottom: 20px;line-height:20px;">
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ 大华摄像头示例: <br />
|
|
|
+ rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ 海康摄像头示例: <br />
|
|
|
+ rtsp://admin:tropsedu123@192.168.3.77:554/h265/ch1/main/av_stream
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('rtsp://admin:tropsedu123@192.168.3.77:554/h265/ch1/main/av_stream', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ USB摄像头示例: <br />
|
|
|
+ /dev/video0,width=1280,height=720,framerate=30
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('/dev/video0,width=1280,height=720,framerate=30')"
|
|
|
+ >
|
|
|
+ 复制</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <i slot="reference" class="el-icon-question" />
|
|
|
+ </el-popover>
|
|
|
+ </span>
|
|
|
+ <el-input v-model="ruleForm.cam_face_path" style="width:45% ;margin-right:5px;" clearable />
|
|
|
+ <span style="margin-right:4px; font-size:10px;">帧率</span>
|
|
|
+ <el-input v-model.number="ruleForm.cam_face_fps" style="width:9.66%;margin-right:5px;" />
|
|
|
+ <el-button icon="el-icon-video-camera" type="primary" size="small" @click.prevent="viewCam(0, 0, ruleForm.cam_face_fps, 1)"
|
|
|
+ >远程布点</el-button
|
|
|
+ >
|
|
|
+ <el-button
|
|
|
+ icon="el-icon-video-camera"
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ style="margin-left:5px;"
|
|
|
+ :disabled="!hasLocSRS"
|
|
|
+ @click.prevent="viewCam(0, 0, ruleForm.cam_face_fps, 3)"
|
|
|
+ >本地布点</el-button
|
|
|
+ >
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+ <template v-if="item == 'anchor_face_path'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input v-model="ruleForm.anchor_face_path" disabled class="input45" />
|
|
|
+ <el-button type="primary" size="small" plain @click.prevent="showSnap(0, 0)">预览</el-button>
|
|
|
+ <el-button type="primary" size="small" plain style="margin-left:5px;" @click.prevent="checkAnchorUrl('', 0)">刷新</el-button>
|
|
|
+ <el-upload
|
|
|
+ name="upload_file"
|
|
|
+ style="display: inline; margin-left: 5px;"
|
|
|
+ action="#"
|
|
|
+ :show-file-list="false"
|
|
|
+ :data="{ exam_id: examId, cindex: 0, school_id: schoolId}"
|
|
|
+ :action="uploadUrl"
|
|
|
+ :headers="headers"
|
|
|
+ :on-success="handleUpload"
|
|
|
+ >
|
|
|
+ <el-button type="primary" size="small" plain>上传布点</el-button>
|
|
|
+ </el-upload>
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template
|
|
|
+ v-if="['flag_check_stline', 'flag_check_back',
|
|
|
+ 'flag_check_hip', 'flag_check_knee', 'flag_check_stline', 'flag_check_hand', 'flag_check_elbow', 'flag_save',
|
|
|
+ 'flag_display', 'flag_check_person', 'flag_check_singleleg_jump'].includes(item)"
|
|
|
+ >
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-switch v-model="ruleForm[item]" :active-value="1" :inactive-value="0" />
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template
|
|
|
+ v-if="['distance_ground', 'length_air_line',
|
|
|
+ 'distance_ground_between_lines', 'length_ground_line',
|
|
|
+ 'distance_air_between_lines', 'distance_per_round',
|
|
|
+ 'num_of_tracks', 'num_of_tracks_startline', 'num_of_tracks_endline', 'delay_cam_second', 'delay_cmd_second'
|
|
|
+ ].includes(item) "
|
|
|
+ >
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input-number v-model="ruleForm[item]" style="width:30%" /><span
|
|
|
+ style="margin-right:4px; padding-left:10px; font-size:18px;"
|
|
|
+ >cm</span
|
|
|
+ >
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="item == 'difficulty'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input-number v-model="ruleForm.difficulty" :min="0" :max="5" style="width:30%" />
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+ <template v-if="item == 'test_time'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input-number v-model="ruleForm.test_time" :min="1" :max="1000" style="width:30%" />
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </el-collapse-item>
|
|
|
+ <el-collapse-item style="margin-left:-4px; color:#0067E1; font-size: 14px; ">
|
|
|
+ <template slot="title">
|
|
|
+ 保留参数
|
|
|
+ <!-- <i class="header-icon el-icon-info"></i> -->
|
|
|
+ </template>
|
|
|
+ <template v-for="value, item in ruleForm">
|
|
|
+ <template v-if="item in examFormConf['reserved']">
|
|
|
+ <template v-if="item === 'cam_path'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <span slot="label">
|
|
|
+ {{ anchorLabelObj[item] }}
|
|
|
+ <el-popover placement="right" width="width:30%" trigger="hover">
|
|
|
+ <div style="height:100px; font-size:12px; margin-bottom: 20px;line-height:20px;">
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ 大华摄像头示例: <br />
|
|
|
+ rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ 海康摄像头示例: <br />
|
|
|
+ rtsp://admin:tropsedu123@192.168.3.77:554/h265/ch1/main/av_stream
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('rtsp://admin:tropsedu123@192.168.3.77:554/h265/ch1/main/av_stream', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ USB摄像头示例: <br />
|
|
|
+ /dev/video0,width=1280,height=720,framerate=30
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('/dev/video0,width=1280,height=720,framerate=30', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <i slot="reference" class="el-icon-question" />
|
|
|
+ </el-popover>
|
|
|
+ </span>
|
|
|
+
|
|
|
+ <el-input v-model="ruleForm.cam_path" clearable style="width:45%; margin-right:5px;" />
|
|
|
+ <span style="margin-right:4px;font-size:10px;">帧率</span>
|
|
|
+ <el-input v-model.number="ruleForm.cam_fps" style="width:9.66%;margin-right:5px;" />
|
|
|
+ <el-button icon="el-icon-video-camera" type="primary" size="small" @click.prevent="viewCam(1, 0, ruleForm.cam_fps, 1)"
|
|
|
+ >远程布点</el-button
|
|
|
+ >
|
|
|
+ <el-button
|
|
|
+ icon="el-icon-video-camera"
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ style="margin-left:5px;"
|
|
|
+ :disabled="!hasLocSRS"
|
|
|
+ @click.prevent="viewCam(1, 0, ruleForm.cam_fps, 3)"
|
|
|
+ >本地布点</el-button
|
|
|
+ >
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+ <template v-if="item === 'anchor_path'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input v-model="ruleForm.anchor_path" disabled class="input45" />
|
|
|
+ <el-button type="primary" size="small" plain @click.prevent="showSnap(0, 1)">预览</el-button>
|
|
|
+ <el-button type="primary" size="small" plain style="margin-left:5px;" @click.prevent="checkAnchorUrl('', 1)">刷新</el-button>
|
|
|
+ <el-upload
|
|
|
+ name="upload_file"
|
|
|
+ style="display: inline; margin-left: 5px;"
|
|
|
+ action="#"
|
|
|
+ :show-file-list="false"
|
|
|
+ :data="{exam_id: examId, cindex: 1, school_id: schoolId}"
|
|
|
+ :action="uploadUrl"
|
|
|
+ :headers="headers"
|
|
|
+ :on-success="handleUpload"
|
|
|
+ >
|
|
|
+ <el-button type="primary" size="small" plain>上传布点</el-button>
|
|
|
+ </el-upload>
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="item === 'flag_calibrate'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-switch v-model="ruleForm.flag_calibrate" :active-value="1" :inactive-value="0" />
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="item == 'cam_param_path'">
|
|
|
+ <el-collapse-transition>
|
|
|
+ <div v-show="ruleForm.flag_calibrate">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input v-model="ruleForm.cam_param_path" disabled class="input45" />
|
|
|
+ <!-- <el-button @click.prevent="viewCam(1, 1, ruleForm.cam_fps, 1)" type="primary" size="small" plain>预览</el-button -->>
|
|
|
+ <el-button type="primary" size="small" plain style="margin-left:5px;" @click.prevent="checkAnchorUrl('', 1, 'yml')"
|
|
|
+ >刷新</el-button
|
|
|
+ >
|
|
|
+ <el-upload
|
|
|
+ name="upload_file"
|
|
|
+ style="display: inline-block; margin-left: 5px;"
|
|
|
+ action="#"
|
|
|
+ :show-file-list="false"
|
|
|
+ :data="{exam_id: examId, cindex: 1, school_id: schoolId, up_type:'yml'}"
|
|
|
+ :action="uploadUrl"
|
|
|
+ :headers="headers"
|
|
|
+ :on-success="handleUpload"
|
|
|
+ ><el-button type="primary" size="small" plain>上传矫正</el-button>
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ plain
|
|
|
+ style="margin-left:5px;"
|
|
|
+ @click.prevent="viewCam(1, 2, ruleForm.cam_fps, 1)"
|
|
|
+ >远程矫正</el-button
|
|
|
+ >
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ plain
|
|
|
+ style="margin-left:5px;"
|
|
|
+ :disabled="!hasLocSRS"
|
|
|
+ @click.prevent="viewCam(1, 2, ruleForm.cam_fps, 4)"
|
|
|
+ >本地矫正</el-button
|
|
|
+ >
|
|
|
+ </el-upload>
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ </el-collapse-transition>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="item == 'cam_0_path'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <span slot="label">
|
|
|
+ {{ anchorLabelObj[item] }}
|
|
|
+ <el-popover placement="right" width="width:30%" trigger="hover">
|
|
|
+ <div style="height:100px; font-size:12px; margin-bottom: 20px;line-height:20px;">
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ 大华摄像头示例: <br />
|
|
|
+ rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ 海康摄像头示例: <br />
|
|
|
+ rtsp://admin:tropsedu123@192.168.3.77:554/h265/ch1/main/av_stream
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('rtsp://admin:tropsedu123@192.168.3.77:554/h265/ch1/main/av_stream', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ USB摄像头示例: <br />
|
|
|
+ /dev/video0,width=1280,height=720,framerate=30
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('/dev/video0,width=1280,height=720,framerate=30')"
|
|
|
+ >
|
|
|
+ 复制</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <i slot="reference" class="el-icon-question" />
|
|
|
+ </el-popover>
|
|
|
+ </span>
|
|
|
+ <el-input v-model="ruleForm.cam_0_path" style="width:45%; margin-right:5px;" />
|
|
|
+ <span style="margin-right:4px; font-size:10px;">帧率</span>
|
|
|
+ <el-input v-model.number="ruleForm.cam_fps" style="width:9.66%;margin-right:5px;" />
|
|
|
+ <el-button icon="el-icon-video-camera" type="primary" size="small" @click.prevent="viewCam(2, 0, ruleForm.cam_fps, 1)"
|
|
|
+ >远程布点</el-button
|
|
|
+ >
|
|
|
+ <el-button
|
|
|
+ icon="el-icon-video-camera"
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ style="margin-left:5px;"
|
|
|
+ :disabled="!hasLocSRS"
|
|
|
+ @click.prevent="viewCam(2, 0, ruleForm.cam_fps, 3)"
|
|
|
+ >本地布点</el-button
|
|
|
+ >
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="item == 'anchor_0_path'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input v-model="ruleForm.anchor_0_path" disabled class="input45" />
|
|
|
+ <el-button type="primary" size="small" plain @click.prevent="showSnap(0, 2)">预览</el-button>
|
|
|
+ <el-button type="primary" size="small" plain style="margin-left:5px;" @click.prevent="checkAnchorUrl('', 2)">刷新</el-button>
|
|
|
+ <el-upload
|
|
|
+ name="upload_file"
|
|
|
+ style="display: inline; margin-left: 5px;"
|
|
|
+ action="#"
|
|
|
+ :show-file-list="false"
|
|
|
+ :data="{exam_id: examId, cindex: 2, school_id: schoolId}"
|
|
|
+ :action="uploadUrl"
|
|
|
+ :headers="headers"
|
|
|
+ :on-success="handleUpload"
|
|
|
+ >
|
|
|
+ <el-button type="primary" size="small" plain>上传布点</el-button>
|
|
|
+ </el-upload>
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="item == 'cam_face_path'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <span slot="label">
|
|
|
+ {{ anchorLabelObj[item] }}
|
|
|
+ <el-popover placement="right" width="width:30%" trigger="hover">
|
|
|
+ <div style="height:100px; font-size:12px; margin-bottom: 20px;line-height:20px;">
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ 大华摄像头示例: <br />
|
|
|
+ rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('rtsp://admin:tropsedu123@192.168.3.106:554/cam/realmonitor?channel=1&subtype=0', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ 海康摄像头示例: <br />
|
|
|
+ rtsp://admin:tropsedu123@192.168.3.77:554/h265/ch1/main/av_stream
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('rtsp://admin:tropsedu123@192.168.3.77:554/h265/ch1/main/av_stream', item)"
|
|
|
+ >选择</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <p style="font-size:10px;">
|
|
|
+ USB摄像头示例: <br />
|
|
|
+ /dev/video0,width=1280,height=720,framerate=30
|
|
|
+ <el-link
|
|
|
+ type="primary"
|
|
|
+ style="font-size:10px;"
|
|
|
+ @click.prevent="copyContent('/dev/video0,width=1280,height=720,framerate=30')"
|
|
|
+ >
|
|
|
+ 复制</el-link
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <i slot="reference" class="el-icon-question" />
|
|
|
+ </el-popover>
|
|
|
+ </span>
|
|
|
+ <el-input v-model="ruleForm.cam_face_path" style="width:45% ;margin-right:5px;" clearable />
|
|
|
+ <span style="margin-right:4px; font-size:10px;">帧率</span>
|
|
|
+ <el-input v-model.number="ruleForm.cam_face_fps" style="width:9.66%;margin-right:5px;" />
|
|
|
+ <el-button icon="el-icon-video-camera" type="primary" size="small" @click.prevent="viewCam(0, 0, ruleForm.cam_face_fps, 1)"
|
|
|
+ >远程布点</el-button
|
|
|
+ >
|
|
|
+ <el-button
|
|
|
+ icon="el-icon-video-camera"
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ style="margin-left:5px;"
|
|
|
+ :disabled="!hasLocSRS"
|
|
|
+ @click.prevent="viewCam(0, 0, ruleForm.cam_face_fps, 3)"
|
|
|
+ >本地布点</el-button
|
|
|
+ >
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+ <template v-if="item == 'anchor_face_path'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input v-model="ruleForm.anchor_face_path" disabled class="input45" />
|
|
|
+ <el-button type="primary" size="small" plain @click.prevent="showSnap(0, 0)">预览</el-button>
|
|
|
+ <el-button type="primary" size="small" plain style="margin-left:5px;" @click.prevent="checkAnchorUrl('', 0)">刷新</el-button>
|
|
|
+ <el-upload
|
|
|
+ name="upload_file"
|
|
|
+ style="display: inline; margin-left: 5px;"
|
|
|
+ action="#"
|
|
|
+ :show-file-list="false"
|
|
|
+ :data="{ exam_id: examId, cindex: 0, school_id: schoolId}"
|
|
|
+ :action="uploadUrl"
|
|
|
+ :headers="headers"
|
|
|
+ :on-success="handleUpload"
|
|
|
+ >
|
|
|
+ <el-button type="primary" size="small" plain>上传布点</el-button>
|
|
|
+ </el-upload>
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template
|
|
|
+ v-if="['flag_check_stline', 'flag_check_back',
|
|
|
+ 'flag_check_hip', 'flag_check_knee', 'flag_check_stline', 'flag_check_hand', 'flag_check_elbow', 'flag_save',
|
|
|
+ 'flag_display', 'flag_check_person', 'flag_check_singleleg_jump'].includes(item)"
|
|
|
+ >
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-switch v-model="ruleForm[item]" :active-value="1" :inactive-value="0" />
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template
|
|
|
+ v-if="['distance_ground', 'length_air_line',
|
|
|
+ 'distance_ground_between_lines', 'length_ground_line',
|
|
|
+ 'distance_air_between_lines', 'distance_per_round',
|
|
|
+ 'num_of_tracks', 'num_of_tracks_startline', 'num_of_tracks_endline', 'delay_cam_second', 'delay_cmd_second'
|
|
|
+ ].includes(item) "
|
|
|
+ >
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input-number v-model="ruleForm[item]" style="width:30%" /><span
|
|
|
+ style="margin-right:4px; padding-left:10px; font-size:18px;"
|
|
|
+ >cm</span
|
|
|
+ >
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="item == 'difficulty'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input-number v-model="ruleForm.difficulty" :min="0" :max="5" style="width:30%" />
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+ <template v-if="item == 'test_time'">
|
|
|
+ <el-form-item :key="item" :prop="item" :label="anchorLabelObj[item]">
|
|
|
+ <el-input-number v-model="ruleForm.test_time" :min="1" :max="1000" style="width:30%" />
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </el-collapse-item>
|
|
|
+ </el-collapse>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ </el-main>
|
|
|
+ </el-container>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import dataDictionary from '@/utils/dataDictionary';
|
|
|
+import axios from 'axios';
|
|
|
+export default {
|
|
|
+ name: 'SchoolExamConf',
|
|
|
+ components: {},
|
|
|
+ data() {
|
|
|
+ const Authorization = 'JWT ' + localStorage.getItem('token') || '';
|
|
|
+ return {
|
|
|
+ userinfo: {},
|
|
|
+ project: dataDictionary.project,
|
|
|
+ anchorSetsObj: dataDictionary.anchorSetsObj,
|
|
|
+ anchorLabelObj: dataDictionary.anchorLabelObj,
|
|
|
+ ruleForm: {
|
|
|
+ cam_path: '',
|
|
|
+ anchor_path: '',
|
|
|
+
|
|
|
+ flag_calibrate: 0,
|
|
|
+ cam_param_path: '',
|
|
|
+ cam_fps: 25,
|
|
|
+
|
|
|
+ cam_face_path: '',
|
|
|
+ cam_face_fps: 25,
|
|
|
+ anchor_face_path: '',
|
|
|
+
|
|
|
+ cam_0_path: '',
|
|
|
+ anchor_0_path: '',
|
|
|
+
|
|
|
+ flag_check_person: 1,
|
|
|
+ flag_check_singleleg_jump: 0,
|
|
|
+ distance_maximum: 800,
|
|
|
+ height_maximum: 300,
|
|
|
+ flag_check_stline: 0,
|
|
|
+ flag_check_back: 0,
|
|
|
+ flag_check_hip: 0,
|
|
|
+ flag_check_knee: 0,
|
|
|
+ flag_check_hand: 0,
|
|
|
+ flag_check_elbow: 0,
|
|
|
+
|
|
|
+ test_time: 60,
|
|
|
+ difficulty: 1,
|
|
|
+
|
|
|
+ distance_per_round: 400,
|
|
|
+ num_of_tracks: 1,
|
|
|
+ num_of_tracks_startline: 1,
|
|
|
+ num_of_tracks_endline: 1,
|
|
|
+ delay_cam_second: 0.45,
|
|
|
+ delay_cmd_second: 0.2,
|
|
|
+
|
|
|
+ distance_ground_between_lines: 50,
|
|
|
+ distance_ground: 1200,
|
|
|
+ distance_air_between_lines: 50,
|
|
|
+ length_ground_line: 80,
|
|
|
+ length_air_line: 50,
|
|
|
+ flag_save: 1,
|
|
|
+ flag_display: 0
|
|
|
+ },
|
|
|
+ camData: [],
|
|
|
+
|
|
|
+ rawImags: {},
|
|
|
+ jFiles: {},
|
|
|
+ uploadUrl: import.meta.env.VITE_APP_BASE_API + '/exam/gpu_anchor_update',
|
|
|
+ headers: { Authorization: Authorization },
|
|
|
+ disExams: ['jump', 'solidball', 'trijump', 'shotput', 'verticaljump'],
|
|
|
+ countExams: ['situp', 'pullup', 'sidepullup', 'jumprope'],
|
|
|
+ secResExams: ['football', 'basketball', 'badminton', 'pingpang', 'volleyball'],
|
|
|
+ examId: '',
|
|
|
+ exam_name: '',
|
|
|
+ schoolId: '',
|
|
|
+ examCN: '',
|
|
|
+ showSnapPics: false,
|
|
|
+ snapPic: '',
|
|
|
+ playUrl: '',
|
|
|
+ rtmpPlayUrl: '',
|
|
|
+ rtcPlayUrl: '',
|
|
|
+ flvUrl: '',
|
|
|
+ showPlayer: false,
|
|
|
+ anchorFlag: false,
|
|
|
+ caliFlag: false,
|
|
|
+ viewCamurl: '',
|
|
|
+ picTitle: '测试区布点图',
|
|
|
+ camIndex: 1,
|
|
|
+ snapUptime: {},
|
|
|
+ anchorUptime: {},
|
|
|
+ camparamUptime: {},
|
|
|
+ stdAnchObj: null,
|
|
|
+ cIntervalId: null,
|
|
|
+ lstAnchorIvalId: null,
|
|
|
+ imgSize: [1280, 720],
|
|
|
+ lines: null,
|
|
|
+ points: [],
|
|
|
+ rawPoints: '[]',
|
|
|
+ names: null,
|
|
|
+ scaleRate: 1,
|
|
|
+ windowHeight: parseInt(window.innerHeight),
|
|
|
+ windowWidth: parseInt(window.innerWidth * 0.96),
|
|
|
+ xPos: 0,
|
|
|
+ scaledWidth: 1080,
|
|
|
+ yPos: 0,
|
|
|
+ scaledHeight: 720,
|
|
|
+ anchorNum: 1,
|
|
|
+ video: null,
|
|
|
+ dragStartX: 0,
|
|
|
+ dragStartY: 0,
|
|
|
+ flvPlayer: null,
|
|
|
+ rtcPlayer: null,
|
|
|
+ srsHost: 'srs.tropsx.com',
|
|
|
+ lsrsHost: '',
|
|
|
+ playHost: '',
|
|
|
+ isLocStream: false,
|
|
|
+ checkPSTO: null,
|
|
|
+ checkCBFD: null,
|
|
|
+ checkUpFID: null,
|
|
|
+ // showRequire: true,
|
|
|
+ // showAdvance: false,
|
|
|
+ // showReserve: false,
|
|
|
+ activeNames: ['1'],
|
|
|
+ examFormConf: {},
|
|
|
+ rawFormData: '{}',
|
|
|
+ uutoken: '',
|
|
|
+ achorUrlChkId: null,
|
|
|
+ hasLocSRS: false,
|
|
|
+ btnDis: false,
|
|
|
+ zoomRatio: 1,
|
|
|
+ lastZoom: 1,
|
|
|
+ startDistance: 0,
|
|
|
+ rules: {
|
|
|
+ // cam_path: [
|
|
|
+ // { required: true, message: '请输入摄像头地址', trigger: 'blur' },
|
|
|
+ // // { min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' }
|
|
|
+ // ],
|
|
|
+ cam_path: [{ required: true, message: '请输入摄像头地址' }],
|
|
|
+ anchor_path: [{ required: true, message: '请上传布点文件' }],
|
|
|
+ cam_fps: [{ required: true, message: '请输入摄像头帧率' }]
|
|
|
+ }
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ isDisExams() {
|
|
|
+ return this.disExams.includes(this.exam_name);
|
|
|
+ },
|
|
|
+ isSitup() {
|
|
|
+ return this.exam_name === 'situp';
|
|
|
+ },
|
|
|
+ isJumpRope() {
|
|
|
+ return this.exam_name === 'jumprope';
|
|
|
+ },
|
|
|
+ isJumps() {
|
|
|
+ return this.exam_name === 'jump' || this.exam_name === 'trijump';
|
|
|
+ },
|
|
|
+ isRun() {
|
|
|
+ return this.exam_name.indexOf('run') === 0;
|
|
|
+ },
|
|
|
+ isBackRun() {
|
|
|
+ return this.exam_name.indexOf('run') == 0 && this.exam_name.indexOf('x') != -1;
|
|
|
+ },
|
|
|
+ isShortRun() {
|
|
|
+ let c1 = this.exam_name.indexOf('run') == 0;
|
|
|
+ let c2 = this.exam_name.indexOf('x') == -1;
|
|
|
+ if (c1 && c2) {
|
|
|
+ if (this.exam_name.replace('run', '') < 799) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ },
|
|
|
+ isLongRun() {
|
|
|
+ let c1 = this.exam_name.indexOf('run') == 0;
|
|
|
+ let c2 = this.exam_name.indexOf('x') == -1;
|
|
|
+ if (c1 && c2) {
|
|
|
+ if (this.exam_name.replace('run', '') > 799) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ },
|
|
|
+ isBasicFace() {
|
|
|
+ return ['volleyball', 'pingpang', 'badminton'].includes(this.exam_name);
|
|
|
+ },
|
|
|
+ snapTime() {
|
|
|
+ return this.snapUptime[this.camIndex + '_error'] || this.snapUptime[this.camIndex] || '';
|
|
|
+ }
|
|
|
+ },
|
|
|
+ watch: {},
|
|
|
+ created() {
|
|
|
+ this.examId = this.$route.query.examId;
|
|
|
+ console.log(this.examId, 'this.examId');
|
|
|
+ let myInfo = localStorage.getItem('userInfo');
|
|
|
+ this.userinfo = JSON.parse(myInfo);
|
|
|
+ this.schoolId = this.userinfo.school_id;
|
|
|
+ this.exam_name = this.examId.split('_')[0];
|
|
|
+ this.examIndex = this.examId.split('_')[1];
|
|
|
+ this.examCN = this.project[this.exam_name] + '_' + this.examIndex;
|
|
|
+ this.isSolidBall = this.exam_name === 'solidball';
|
|
|
+ this.isPushBall = ['solidball', 'shotput'].includes(this.exam_name);
|
|
|
+ this.isSidepullup = this.exam_name === 'sidepullup';
|
|
|
+ this.examFormConf['required'] = JSON.parse(JSON.stringify(this.anchorSetsObj['basic']['required']));
|
|
|
+ this.examFormConf['advanced'] = JSON.parse(JSON.stringify(this.anchorSetsObj['basic']['advanced']));
|
|
|
+ this.examFormConf['reserved'] = JSON.parse(JSON.stringify(this.anchorSetsObj['basic']['reserved']));
|
|
|
+ console.log(this.examFormConf, 'this.examFormConf111');
|
|
|
+ let ename;
|
|
|
+ if (this.isLongRun) {
|
|
|
+ ename = 'longrun';
|
|
|
+ } else if (this.isShortRun) {
|
|
|
+ ename = 'shortrun';
|
|
|
+ } else if (this.isBackRun) {
|
|
|
+ ename = 'backrun';
|
|
|
+ } else if (this.isBasicFace) {
|
|
|
+ ename = 'basicface';
|
|
|
+ } else {
|
|
|
+ ename = this.exam_name;
|
|
|
+ }
|
|
|
+ console.log('ename:', ename, 'examId:', this.examId, 'schoolId:', this.schoolId);
|
|
|
+ Object.assign(this.examFormConf['required'], this.anchorSetsObj[ename]['required']);
|
|
|
+ Object.assign(this.examFormConf['advanced'], this.anchorSetsObj[ename]['advanced']);
|
|
|
+ Object.assign(this.examFormConf['reserved'], this.anchorSetsObj[ename]['reserved']);
|
|
|
+ for (let i in this.examFormConf['required']) {
|
|
|
+ if (!this.rules[i]) {
|
|
|
+ let message = `${this.anchorLabelObj[i]}必填`;
|
|
|
+ this.rules[i] = [{ required: true, message: message }];
|
|
|
+ }
|
|
|
+ this.ruleForm[i]=this.examFormConf['required'][i];
|
|
|
+ }
|
|
|
+ for (let i in this.examFormConf['advanced']) {
|
|
|
+ if (i in this.examFormConf['required']) {
|
|
|
+ delete this.examFormConf['advanced'][i];
|
|
|
+ } else {
|
|
|
+ this.ruleForm[i] = this.examFormConf['advanced'][i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for (let i in this.examFormConf['reserved']) {
|
|
|
+ if (i in this.examFormConf['required'] || i in this.examFormConf['advanced']) {
|
|
|
+ delete this.examFormConf['reserved'][i];
|
|
|
+ } else {
|
|
|
+ this.ruleForm[i] = this.examFormConf['reserved'][i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.getExamConf(); // 获取布点配置
|
|
|
+ },
|
|
|
+
|
|
|
+ beforeRouteLeave(to, from, next) {
|
|
|
+ if (this.showSnapPics) {
|
|
|
+ next(false);
|
|
|
+ this.showSnapPics = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (this.showPlayer) {
|
|
|
+ next(false);
|
|
|
+ if (this.rawPoints != JSON.stringify(this.points)) {
|
|
|
+ setTimeout(() => {
|
|
|
+ this.$confirm('检测到有点位移动没有保存', '确认退出?', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ this.handlePlayerClose();
|
|
|
+ return false;
|
|
|
+ })
|
|
|
+ .catch((err) => {
|
|
|
+ console.log(1111, err);
|
|
|
+ return false;
|
|
|
+ });
|
|
|
+ }, 200);
|
|
|
+ } else {
|
|
|
+ this.handlePlayerClose();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (this.rawFormData != JSON.stringify(this.ruleForm)) {
|
|
|
+ setTimeout(() => {
|
|
|
+ this.$confirm('检测到改动未保存', '退出后编辑过的内容将丢失', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ next();
|
|
|
+ })
|
|
|
+ .catch((err) => {
|
|
|
+ next(false);
|
|
|
+ });
|
|
|
+ }, 200);
|
|
|
+ } else {
|
|
|
+ next();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ let tmparr = [this.checkPSTO, this.cIntervalId, this.lstAnchorIvalId, this.checkCBFD, this.achorUrlChkId];
|
|
|
+ tmparr.forEach((i) => {
|
|
|
+ clearInterval(i);
|
|
|
+ });
|
|
|
+
|
|
|
+ this.$http.deploy.closeLocalStream({ exam_id: this.examId, school_id: this.schoolId });
|
|
|
+ this.$http.deploy.closeCaliStream({ exam_id: this.examId, school_id: this.schoolId });
|
|
|
+ if (this.flvPlayer) {
|
|
|
+ if (this.flvPlayer.destroy) {
|
|
|
+ try {
|
|
|
+ this.flvPlayer.destroy();
|
|
|
+ } catch {
|
|
|
+ this.flvPlayer = null;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.flvPlayer.unsubscribe();
|
|
|
+ this.flvPlayer = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (this.rtcPlayer) {
|
|
|
+ try {
|
|
|
+ this.rtcPlayer.close();
|
|
|
+ } catch {
|
|
|
+ this.rtcPlayer = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.anchorFlag = false;
|
|
|
+ this.examFormConf = {};
|
|
|
+ },
|
|
|
+
|
|
|
+ mounted() {
|
|
|
+ // this.$nextTick(() => {
|
|
|
+ // window.addEventListener('resize', this.onResize);
|
|
|
+ // })
|
|
|
+ },
|
|
|
+
|
|
|
+ methods: {
|
|
|
+ // onResize() {
|
|
|
+ // this.windowHeight = window.innerHeight * 0.9
|
|
|
+ // this.windowWidth = window.innerWidth * 0.9
|
|
|
+ // },
|
|
|
+ validateIP(str) {
|
|
|
+ const re = /^(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|[0-9])\.((1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.){2}(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)$/;
|
|
|
+ return re.test(str);
|
|
|
+ },
|
|
|
+
|
|
|
+ checkHTTPPageExists(url, callback) {
|
|
|
+ let xhttp = new XMLHttpRequest();
|
|
|
+ xhttp.onreadystatechange = function () {
|
|
|
+ if (this.readyState === 4) {
|
|
|
+ if (this.status === 200) {
|
|
|
+ callback(true);
|
|
|
+ } else {
|
|
|
+ callback(false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ xhttp.open('HEAD', url, true);
|
|
|
+ xhttp.send();
|
|
|
+ },
|
|
|
+
|
|
|
+ checkLocRSR() {
|
|
|
+ if (this.lsrsHost) {
|
|
|
+ let ourl = ['http:/', this.lsrsHost + ':8081', 'players/anchor/index.html'].join('/');
|
|
|
+ var vm = this;
|
|
|
+ this.checkHTTPPageExists(ourl, function (exists) {
|
|
|
+ console.log(exists, 'checkHTTPPageExists');
|
|
|
+ if (exists) {
|
|
|
+ console.log('HTTP page exists.');
|
|
|
+ vm.hasLocSRS = true;
|
|
|
+ } else {
|
|
|
+ vm.hasLocSRS = false;
|
|
|
+ console.log('HTTP page does not exist or is inaccessible.');
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.hasLocSRS = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ localView(webrtc) {
|
|
|
+ let action = 'anchor_config';
|
|
|
+ let ftype = 'json';
|
|
|
+ if (webrtc == 4) {
|
|
|
+ action = 'camera_param';
|
|
|
+ ftype = 'yml';
|
|
|
+ clearInterval(this.checkCBFD);
|
|
|
+ this.checkCBFD = setInterval(this.checkCalibFshd, 5000, 1);
|
|
|
+ } else {
|
|
|
+ clearInterval(this.achorUrlChkId);
|
|
|
+ this.achorUrlChkId = setInterval(this.checkAnchorUrl, 5000, lsturl, this.camIndex, ftype, 1);
|
|
|
+ }
|
|
|
+ let ourl = ['http:/', this.lsrsHost + ':8081', 'players/anchor/index.html'].join('/');
|
|
|
+ let lsturl =
|
|
|
+ '//aiexam-data.oss-cn-shenzhen.aliyuncs.com/midexam/uploaded_files/settings/' +
|
|
|
+ this.uutoken +
|
|
|
+ '/' +
|
|
|
+ this.examId +
|
|
|
+ '_' +
|
|
|
+ this.camIndex +
|
|
|
+ '.' +
|
|
|
+ ftype;
|
|
|
+ let ename_str = this.getEName().join('_');
|
|
|
+ console.log(ename_str, 'eNameeNameeName');
|
|
|
+ let params_str = [
|
|
|
+ 'camUrl=' + this.viewCamurl,
|
|
|
+ 'examId=' + this.examId,
|
|
|
+ 'camIndex=' + this.camIndex,
|
|
|
+ 'playUrl=' + this.rtcPlayUrl,
|
|
|
+ 'lastAchUrl=' + lsturl,
|
|
|
+ 'eName=' + ename_str,
|
|
|
+ 'token=' + Authorization,
|
|
|
+ 'baseUrl=' + process.env.VUE_APP_BASE_API2,
|
|
|
+ 'action=' + action
|
|
|
+ ].join('&');
|
|
|
+ ourl = ourl + '?' + params_str;
|
|
|
+ if (window && window.navigator) {
|
|
|
+ window.open(ourl, '_blank');
|
|
|
+ } else {
|
|
|
+ window.location.href = ourl;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ checkStreamClosed() {
|
|
|
+ this.$http.deploy.checkStreamClosd({ dest_uri: this.rtcPlayUrl }).then((res) => {
|
|
|
+ console.log('checkStreamClosed', res);
|
|
|
+ if (res.status == 200) {
|
|
|
+ if (res.data) {
|
|
|
+ if (res.data >= '0') {
|
|
|
+ // if (this.ruleForm.)
|
|
|
+ // this.$message.error(
|
|
|
+ // '布点结束,如您已完成布点,请点刷新按钮')
|
|
|
+ this.$message.warning('推流结束,如您已布点成功且未检测到布点文件请点击刷新按钮');
|
|
|
+ clearInterval(this.achorUrlChkId);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.$message.info('正在推流,请继续布点');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ clearInterval(this.achorUrlChkId);
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ checkCaliClosed() {
|
|
|
+ this.$http.deploy.checkCaliStreamClosd({ exam_id: this.examId }).then((res) => {
|
|
|
+ if (res.status == 200) {
|
|
|
+ if (res.data) {
|
|
|
+ if (res.data >= '0') {
|
|
|
+ // if (this.ruleForm.)
|
|
|
+ // this.$message.error(
|
|
|
+ // '布点结束,如您已完成布点,请点刷新按钮')
|
|
|
+ this.$message.warning('推流结束,如您矫正成功且未检测到矫正文件请点击刷新按钮');
|
|
|
+ clearInterval(this.checkCBFD);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.$message.info('正在推流,请继续矫正');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ clearInterval(this.checkCBFD);
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ checkAnchorUrl(url = '', camIndex = this.camIndex, ftype = 'json', chType = 0) {
|
|
|
+ if (!url) {
|
|
|
+ url =
|
|
|
+ '//aiexam-data.oss-cn-shenzhen.aliyuncs.com/midexam/uploaded_files/settings/' +
|
|
|
+ this.uutoken +
|
|
|
+ '/' +
|
|
|
+ this.examId +
|
|
|
+ '_' +
|
|
|
+ camIndex +
|
|
|
+ '.' +
|
|
|
+ ftype;
|
|
|
+ }
|
|
|
+ axios
|
|
|
+ .get(url)
|
|
|
+ .then((response) => {
|
|
|
+ let anchorPath = 'settings/anchor_files/' + this.examId + '_' + camIndex + '.' + ftype;
|
|
|
+ if (camIndex == 1) {
|
|
|
+ if (ftype == 'json') {
|
|
|
+ if (!this.ruleForm.anchor_path) {
|
|
|
+ this.ruleForm.anchor_path = anchorPath;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (!this.ruleForm.cam_param_path) {
|
|
|
+ anchorPath = 'settings/cam_param_files/' + this.examId + '_' + camIndex + '.' + ftype;
|
|
|
+ this.ruleForm.cam_param_path = anchorPath;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (camIndex == 0 && !this.ruleForm.anchor_face_path) {
|
|
|
+ this.ruleForm.anchor_face_path = anchorPath;
|
|
|
+ } else if (camIndex == 2 && !this.ruleForm.anchor_0_path) {
|
|
|
+ this.ruleForm.anchor_0_path = anchorPath;
|
|
|
+ }
|
|
|
+ this.$message({
|
|
|
+ message: '检测到云文件,读取成功',
|
|
|
+ type: 'success'
|
|
|
+ });
|
|
|
+ if (this.achorUrlChkId) {
|
|
|
+ clearInterval(this.achorUrlChkId);
|
|
|
+ }
|
|
|
+ clearInterval(this.achorUrlChkId);
|
|
|
+ })
|
|
|
+ .catch((error) => {
|
|
|
+ if (ftype == 'json') {
|
|
|
+ if (chType) {
|
|
|
+ this.checkStreamClosed();
|
|
|
+ } else {
|
|
|
+ clearInterval(this.achorUrlChkId);
|
|
|
+ this.$message({
|
|
|
+ message: '未检测到云文件,读取失败',
|
|
|
+ type: 'error'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (chType) {
|
|
|
+ this.checkCaliClosed();
|
|
|
+ } else {
|
|
|
+ this.$message({
|
|
|
+ message: '矫正未完成,读取失败',
|
|
|
+ type: 'error'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ async viewCam(cindex, cali = 0, cam_fps = 0, webrtc = 0) {
|
|
|
+ if (!cam_fps) {
|
|
|
+ this.$message({
|
|
|
+ message: '请输入摄像头帧率',
|
|
|
+ type: 'error'
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (cindex == 0) {
|
|
|
+ this.viewCamurl = this.ruleForm.cam_face_path;
|
|
|
+ } else if (cindex == 1) {
|
|
|
+ this.viewCamurl = this.ruleForm.cam_path;
|
|
|
+ } else if (cindex == 2) {
|
|
|
+ this.viewCamurl = this.ruleForm.cam_0_path;
|
|
|
+ }
|
|
|
+ if (!this.viewCamurl) {
|
|
|
+ this.$message({
|
|
|
+ message: '请输入摄像头地址',
|
|
|
+ type: 'error'
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (webrtc == 2 && !this.validateIP(this.playHost)) {
|
|
|
+ this.$message({
|
|
|
+ message: '请输入正确局域网srs IP',
|
|
|
+ type: 'error'
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.camIndex = cindex;
|
|
|
+ let src_uri = this.viewCamurl;
|
|
|
+ if (cali == 1) {
|
|
|
+ if (!this.ruleForm.cam_param_path) {
|
|
|
+ this.$message({
|
|
|
+ message: '请先生成矫正文件',
|
|
|
+ type: 'error'
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.isLocStream = false;
|
|
|
+ var pushHost = 'alilive-push.tropsx.com';
|
|
|
+ var playHost;
|
|
|
+ let port = 443;
|
|
|
+ let schema = window.location.protocol;
|
|
|
+ if (webrtc == 1) {
|
|
|
+ pushHost = this.srsHost;
|
|
|
+ port = 8088;
|
|
|
+ playHost = this.srsHost;
|
|
|
+ schema = 'https:';
|
|
|
+ } else if (webrtc == 2) {
|
|
|
+ pushHost = this.playHost;
|
|
|
+ port = 8080;
|
|
|
+ playHost = this.playHost;
|
|
|
+ schema = 'http:';
|
|
|
+ } else if (webrtc == 3 || webrtc == 4) {
|
|
|
+ playHost = this.lsrsHost;
|
|
|
+ port = 8081;
|
|
|
+ pushHost = this.lsrsHost;
|
|
|
+ schema = 'http:';
|
|
|
+ } else {
|
|
|
+ if (schema == 'http:') {
|
|
|
+ port = 80;
|
|
|
+ }
|
|
|
+ playHost = 'alilive-play.tropsx.com';
|
|
|
+ }
|
|
|
+ let baseUrl = [pushHost, this.schoolId, this.examId + '_' + cindex + '_' + cali].join('/');
|
|
|
+ let dest_uri = ['rtmp:/', baseUrl].join('/');
|
|
|
+ await this.$http.deploy.closeLocalStream({ exam_id: this.examId, school_id: this.schoolId });
|
|
|
+ await this.$http.deploy.closeCaliStream({ exam_id: this.examId, school_id: this.schoolId });
|
|
|
+ if (port != 80) {
|
|
|
+ this.flvUrl = [schema + '/', baseUrl + '.flv'].join('/');
|
|
|
+ this.playUrl = ['artc:' + '/', baseUrl].join('/');
|
|
|
+ } else {
|
|
|
+ this.flvUrl = [schema + '/', baseUrl + '.flv'].join('/');
|
|
|
+ this.playUrl = ['artc:' + '/', baseUrl].join('/');
|
|
|
+ }
|
|
|
+
|
|
|
+ this.rtmpPlayUrl = ['rtmp:/', baseUrl].join('/');
|
|
|
+ this.rtcPlayUrl = ['webrtc:/', baseUrl].join('/'); // 'webrtc://srs.xmtel.com:443/live/3/jump_76_1_0'
|
|
|
+ let params = { exam_id: this.examId, src_uri: src_uri, dest_uri: dest_uri, school_id: this.schoolId, cam_fps, cali };
|
|
|
+ if (this.ruleForm.flag_calibrate && this.camIndex == 1 && cali != 2) {
|
|
|
+ if (!this.ruleForm.cam_param_path) {
|
|
|
+ this.$message.warning('您已开启矫正,请配置矫正文件');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ params['cam_param_path'] = this.ruleForm.cam_param_path;
|
|
|
+ }
|
|
|
+
|
|
|
+ await this.$http.deploy.pushLocalStream(params).then((res) => {
|
|
|
+ if (webrtc == 3 || webrtc == 4) {
|
|
|
+ this.localView(webrtc);
|
|
|
+ } else {
|
|
|
+ this.showPlayer = true;
|
|
|
+ if (webrtc) {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.flvPlayer = null;
|
|
|
+ this.playRtc();
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ }
|
|
|
+ clearInterval(this.checkPSTO);
|
|
|
+ this.checkPSTO = setInterval(this.checkPushStream, 3500);
|
|
|
+ if (cali === 2) {
|
|
|
+ this.caliFlag = true;
|
|
|
+ clearInterval(this.checkCBFD);
|
|
|
+ this.checkCBFD = setInterval(this.checkCalibFshd, 5000);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ initSuccess() {
|
|
|
+ let aspectRatio = this.video.videoWidth / this.video.videoHeight;
|
|
|
+ this.scaledWidth = this.windowWidth;
|
|
|
+ this.scaledHeight = this.windowWidth / aspectRatio;
|
|
|
+ if (this.scaledHeight > this.windowHeight) {
|
|
|
+ this.scaledHeight = this.windowHeight;
|
|
|
+ this.scaledWidth = this.windowHeight * aspectRatio;
|
|
|
+ }
|
|
|
+ this.xPos = (this.windowWidth - this.scaledWidth) / 2;
|
|
|
+ this.yPos = (this.windowHeight - this.scaledHeight) / 2;
|
|
|
+ this.anchorFlag = true;
|
|
|
+ this.imgSize = [this.video.videoWidth, this.video.videoHeight];
|
|
|
+ setTimeout(function () {
|
|
|
+ console.log(this.flvPlayer);
|
|
|
+ if (this.flvPlayer) {
|
|
|
+ this.flvPlayer.play();
|
|
|
+ }
|
|
|
+ }, 100);
|
|
|
+ },
|
|
|
+
|
|
|
+ playLocStream() {
|
|
|
+ this.video = document.getElementById('videoflv');
|
|
|
+ var vm = this;
|
|
|
+ let videoSelect = document.querySelector('select#videoSource');
|
|
|
+ console.log('playLocStream', this.video);
|
|
|
+ this.video.width = this.windowWidth;
|
|
|
+ this.video.height = this.windowHeight;
|
|
|
+ function getDevices() {
|
|
|
+ return navigator.mediaDevices.enumerateDevices();
|
|
|
+ }
|
|
|
+ function gotDevices(deviceInfos) {
|
|
|
+ console.log('Available input and output devices:', deviceInfos);
|
|
|
+ for (const deviceInfo of deviceInfos) {
|
|
|
+ if (deviceInfo.deviceId) {
|
|
|
+ const option = document.createElement('option');
|
|
|
+ option.value = deviceInfo.deviceId;
|
|
|
+ if (deviceInfo.kind === 'videoinput' && deviceInfo.deviceId !== '') {
|
|
|
+ option.text = deviceInfo.label || `Camera ${videoSelect.length + 1}`;
|
|
|
+ videoSelect.appendChild(option);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ function getStream() {
|
|
|
+ if (vm.video.srcObject) {
|
|
|
+ vm.video.srcObject.getTracks().forEach((track) => {
|
|
|
+ track.stop();
|
|
|
+ });
|
|
|
+ }
|
|
|
+ const videoSource = videoSelect.value;
|
|
|
+ const constraints = {
|
|
|
+ video: { deviceId: videoSource ? { exact: videoSource } : undefined }
|
|
|
+ };
|
|
|
+ return navigator.mediaDevices
|
|
|
+ .getUserMedia(constraints)
|
|
|
+ .then(gotStream)
|
|
|
+ .catch((error) => {
|
|
|
+ console.error('Error: ', error);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ function gotStream(stream) {
|
|
|
+ // window.stream = stream; // make stream available to console
|
|
|
+ videoSelect.selectedIndex = [...videoSelect.options].findIndex((option) => option.text === stream.getVideoTracks()[0].label);
|
|
|
+ vm.video.srcObject = stream;
|
|
|
+ }
|
|
|
+ videoSelect.onchange = getStream;
|
|
|
+ getStream().then(getDevices).then(gotDevices);
|
|
|
+
|
|
|
+ // navigator.mediaDevices.getUserMedia({video: true})
|
|
|
+ // .then(stream => {
|
|
|
+ // // Set video source and play
|
|
|
+ // this.video.srcObject = stream;
|
|
|
+ // this.video.play();
|
|
|
+ // })
|
|
|
+ // .catch(err => {
|
|
|
+ // console.error(err);
|
|
|
+ // });
|
|
|
+ this.video.addEventListener('loadedmetadata', this.initSuccess);
|
|
|
+ },
|
|
|
+ checkCalibFshd(isLocal = 0) {
|
|
|
+ this.$http.deploy.checkCaliRes({ exam_id: this.examId }).then((res) => {
|
|
|
+ console.log(res, res.data, 'checkCaliRes');
|
|
|
+ if (res.data.error_message) {
|
|
|
+ if (res.data.error_code == '0') {
|
|
|
+ this.$message({
|
|
|
+ message: '矫正已完成',
|
|
|
+ type: 'success'
|
|
|
+ });
|
|
|
+ // this.ruleForm.cam_param_path = "settings/cam_param_files/"+this.examId+"_"+this.camIndex+".yml"
|
|
|
+ if (!this.ruleForm.cam_param_path) {
|
|
|
+ this.ruleForm.cam_param_path = res.data.cam_param_path;
|
|
|
+ }
|
|
|
+ this.caliFlag = false;
|
|
|
+ } else {
|
|
|
+ this.$message({
|
|
|
+ message: '矫正失败,原因:' + res.data.error_message,
|
|
|
+ type: 'error'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (isLocal >= 1) {
|
|
|
+ clearInterval(this.checkCBFD);
|
|
|
+ }
|
|
|
+ // if (this.checkCBFD) {
|
|
|
+ // clearInterval(this.checkCBFD)
|
|
|
+ // }
|
|
|
+ } else {
|
|
|
+ if (isLocal == 1) {
|
|
|
+ this.$message.info('矫正未完成,检测中');
|
|
|
+ } else if (isLocal == 2) {
|
|
|
+ this.$message.info('未找到矫正记录');
|
|
|
+ } else {
|
|
|
+ this.$message({
|
|
|
+ message: '请将棋盘放到摄像头前进行矫正',
|
|
|
+ type: 'info'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ checkPushStream() {
|
|
|
+ this.$http.deploy
|
|
|
+ .checkPushStream({
|
|
|
+ dest_uri: this.rtmpPlayUrl
|
|
|
+ })
|
|
|
+ .then((res) => {
|
|
|
+ console.log('ressts', res);
|
|
|
+ if (res == -1) {
|
|
|
+ this.$message({
|
|
|
+ message: '开启推流中,请稍等',
|
|
|
+ type: 'info'
|
|
|
+ });
|
|
|
+ } else if (res == '推流成功') {
|
|
|
+ this.$message({
|
|
|
+ message: '推流成功',
|
|
|
+ type: 'success'
|
|
|
+ });
|
|
|
+ if (this.checkPSTO) {
|
|
|
+ clearInterval(this.checkPSTO);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.$message({
|
|
|
+ message: '推流失败,原因:' + res,
|
|
|
+ type: 'error'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ playRtc() {
|
|
|
+ if (this.rtcPlayer) {
|
|
|
+ this.rtcPlayer.close();
|
|
|
+ }
|
|
|
+ var vm = this;
|
|
|
+ this.video = document.getElementById('videoflv');
|
|
|
+ this.video.width = this.windowWidth;
|
|
|
+ this.video.height = this.windowHeight;
|
|
|
+ this.rtcPlayer = new this.SrsRtcPlayerAsync();
|
|
|
+ this.video.srcObject = this.rtcPlayer.stream;
|
|
|
+ // $('#videoflv').prop('srcObject', this.rtcPlayer.stream);
|
|
|
+ this.rtcPlayer
|
|
|
+ .play(this.rtcPlayUrl)
|
|
|
+ .then(function (session) {
|
|
|
+ // vm.anchorFlag = true
|
|
|
+ vm.video.play();
|
|
|
+ vm.initSuccess();
|
|
|
+ })
|
|
|
+ .catch(function (reason) {
|
|
|
+ if (vm.rtcPlayer) {
|
|
|
+ vm.rtcPlayer.close();
|
|
|
+ }
|
|
|
+ console.error(reason);
|
|
|
+ });
|
|
|
+ this.video.addEventListener('loadedmetadata', this.initSuccess);
|
|
|
+ // this.video.addEventListener('canplay', this.initSuccess);
|
|
|
+ },
|
|
|
+
|
|
|
+ handlBeforeClose(done = null) {
|
|
|
+ if (this.rawPoints != JSON.stringify(this.points)) {
|
|
|
+ this.$confirm('检测到有点位移动没有保存', '确认退出?', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ if (done) done();
|
|
|
+ return true;
|
|
|
+ })
|
|
|
+ .catch((err) => {
|
|
|
+ console.log(1111, err);
|
|
|
+ return false;
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ if (done) done();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ handlePlayerClose() {
|
|
|
+ if (this.isLocStream) {
|
|
|
+ this.video.srcObject.getTracks().forEach((track) => {
|
|
|
+ track.stop();
|
|
|
+ });
|
|
|
+ // this.video.stop()
|
|
|
+ } else {
|
|
|
+ if (this.checkPSTO) {
|
|
|
+ this.$http.deploy.closeLocalStream({ exam_id: this.examId, school_id: this.schoolId });
|
|
|
+ }
|
|
|
+ if (this.checkCBFD) {
|
|
|
+ this.$http.deploy.closeCaliStream({ exam_id: this.examId, school_id: this.schoolId });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.flvPlayer) {
|
|
|
+ if (this.flvPlayer.destroy) {
|
|
|
+ this.flvPlayer.destroy();
|
|
|
+ } else {
|
|
|
+ this.flvPlayer.unsubscribe();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (this.rtcPlayer) {
|
|
|
+ this.rtcPlayer.close();
|
|
|
+ this.video.pause();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.showPlayer = false;
|
|
|
+ this.anchorFlag = false;
|
|
|
+ this.caliFlag = false;
|
|
|
+ console.log('closed!!');
|
|
|
+ let tmparr = [this.checkPSTO, this.cIntervalId, this.lstAnchorIvalId, this.checkCBFD];
|
|
|
+ tmparr.forEach((item) => {
|
|
|
+ if (item) clearInterval(item);
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ upSnapShotInfos(onlyShow, up_type = 'all') {
|
|
|
+ let params = { exam_id: this.examId, no_req: onlyShow, qindex: this.camIndex, school_id: this.schoolId, up_type: up_type };
|
|
|
+ if (this.camIndex == 1) {
|
|
|
+ params['cam_path'] = this.ruleForm.cam_path;
|
|
|
+ params['anchor_path'] = this.ruleForm.anchor_path;
|
|
|
+ params['cam_param_path'] = this.ruleForm.cam_param_path;
|
|
|
+ } else if (this.camIndex == 0) {
|
|
|
+ params['cam_path'] = this.ruleForm.cam_face_path;
|
|
|
+ params['anchor_path'] = this.ruleForm.anchor_face_path;
|
|
|
+ } else if (this.camIndex == 2) {
|
|
|
+ params['cam_path'] = this.ruleForm.cam_0_path;
|
|
|
+ params['anchor_path'] = this.ruleForm.anchor_0_path;
|
|
|
+ }
|
|
|
+ // if (!params['cam_path'] || !params['anchor_path']) {
|
|
|
+ // this.$message.error("请先配置摄像头地址和布点文件")
|
|
|
+ // return
|
|
|
+ // }
|
|
|
+ this.$http.deploy.getExamSnapShot(params).then((res) => {
|
|
|
+ console.log(res, 'getExamSnapShot');
|
|
|
+ // res.data.exam_imgs.forEach(img => {
|
|
|
+ // this.snapPics.push(img + "?" + Math.random())
|
|
|
+ // })
|
|
|
+ setTimeout(() => {
|
|
|
+ if (res.data.exam_imgs.length == 1) {
|
|
|
+ this.snapPic = res.data.exam_imgs[0] + '?' + Math.random();
|
|
|
+ } else {
|
|
|
+ this.snapPic = res.data.exam_imgs[this.camIndex] + '?' + Math.random();
|
|
|
+ }
|
|
|
+ // $('#snapPic').attr('src', this.snapPic)
|
|
|
+ this.rawImags = res.data.raw_imgs;
|
|
|
+ this.jFiles = res.data.j_files;
|
|
|
+ this.snapUptime = res.data.snappic_uptime;
|
|
|
+ this.anchorUptime = res.data.anchor_uptime;
|
|
|
+ this.camparamUptime = res.data.camparam_uptime;
|
|
|
+ }, 1500);
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ showSnap(onlyShow = 0, camIndex = 1, up_type = 'snapshot') {
|
|
|
+ this.camIndex = camIndex;
|
|
|
+ if (camIndex == 0) {
|
|
|
+ this.picTitle = this.examCN + '人脸区布点图';
|
|
|
+ if (!this.ruleForm.cam_face_path || !this.ruleForm.anchor_face_path) {
|
|
|
+ this.$message.error('请配置人脸摄像头和人脸布点文件');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ } else if (camIndex == 1) {
|
|
|
+ if (!this.ruleForm.cam_path || !this.ruleForm.anchor_path) {
|
|
|
+ this.$message.error('请配置测试摄像头和测试布点文件');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.picTitle = this.examCN + '测试区布点图';
|
|
|
+ } else if (camIndex == 2) {
|
|
|
+ if (!this.ruleForm.cam_0_path || !this.ruleForm.anchor_0_path) {
|
|
|
+ this.$message.error('请配置辅助摄像头和辅助布点文件');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.picTitle = this.examCN + '辅助区布点图';
|
|
|
+ }
|
|
|
+
|
|
|
+ // this.snapPics = []
|
|
|
+ this.upSnapShotInfos(onlyShow, up_type);
|
|
|
+ if (!this.showSnapPics) {
|
|
|
+ this.showSnapPics = true;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // getGExamConfs() {
|
|
|
+ // getGPUExamconfs(
|
|
|
+ // { exam_id: this.examId }
|
|
|
+ // ).then(res => {
|
|
|
+ // this.camData = res
|
|
|
+ // })
|
|
|
+ // },
|
|
|
+
|
|
|
+ onlyDownFile(url) {
|
|
|
+ const iframe = document.createElement('iframe');
|
|
|
+ iframe.style.display = 'none';
|
|
|
+ iframe.style.height = 0;
|
|
|
+ iframe.src = url + '?response-content-type=application/octet-stream';
|
|
|
+ console.log(url, 'Url onlyDownFile');
|
|
|
+ document.body.appendChild(iframe);
|
|
|
+ // 不能马上将iframe进行删除,否者会出现马上取消的情况
|
|
|
+ setTimeout(() => {
|
|
|
+ iframe.remove();
|
|
|
+ }, 5000);
|
|
|
+ // this.$message.success('文件下载成功')
|
|
|
+ },
|
|
|
+
|
|
|
+ checkPermission(fileUrl, fname) {
|
|
|
+ // let permissions = cordova.plugins.permissions
|
|
|
+ // permissions.checkPermission(permissions.READ_EXTERNAL_STORAGE, checkPermissionCallback, null)
|
|
|
+
|
|
|
+ // Checking for permissions
|
|
|
+ // function checkPermissionCallback(status) {
|
|
|
+ // console.log('checking permissions')
|
|
|
+ // console.log(status)
|
|
|
+ // if (!status.hasPermission) {
|
|
|
+ // var errorCallback = function () {
|
|
|
+ // console.warn('Storage permission is not turned on')
|
|
|
+ // }
|
|
|
+ // // Asking permission to the user
|
|
|
+ // permissions.requestPermission(
|
|
|
+ // permissions.READ_EXTERNAL_STORAGE,
|
|
|
+ // function (status) {
|
|
|
+ // if (!status.hasPermission) {
|
|
|
+ // errorCallback()
|
|
|
+ // } else {
|
|
|
+ // // proceed with downloading
|
|
|
+ // downloadFile()
|
|
|
+ // }
|
|
|
+ // },
|
|
|
+ // errorCallback)
|
|
|
+ // } else {
|
|
|
+ // downloadFile() }
|
|
|
+ // }
|
|
|
+ // fileUrl = "https:" + fileUrl
|
|
|
+ function downloadFile(fileUrl, fname) {
|
|
|
+ try {
|
|
|
+ let filePath = cordova.file.externalApplicationStorageDirectory + fname;
|
|
|
+ let fileTransfer = new FileTransfer();
|
|
|
+ let uri = encodeURI(fileUrl);
|
|
|
+ // alert(uri)
|
|
|
+ // alert(filePath)
|
|
|
+ // Downloading the file
|
|
|
+ fileTransfer.download(
|
|
|
+ uri,
|
|
|
+ filePath,
|
|
|
+ function (entry) {
|
|
|
+ // alert('Successfully downloaded file, full path is ' + entry.fullPath)
|
|
|
+ this.$message.success('文件存储于:' + entry.fullPath);
|
|
|
+ },
|
|
|
+ function (error) {
|
|
|
+ alert('error' + error.code);
|
|
|
+ alert('error' + error);
|
|
|
+ },
|
|
|
+ false
|
|
|
+ );
|
|
|
+ } catch (e) {
|
|
|
+ alert(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ downloadFile(fileUrl, fname);
|
|
|
+ },
|
|
|
+
|
|
|
+ getSampleFile(url, fname) {
|
|
|
+ var xhr = new XMLHttpRequest();
|
|
|
+ xhr.open('get', url, false);
|
|
|
+ // xhr.responseType = 'blob'
|
|
|
+ xhr.send(null);
|
|
|
+ if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
|
|
|
+ // console.log(xhr.response);
|
|
|
+ alert(xhr.response);
|
|
|
+ let dataObj = xhr.response;
|
|
|
+ // let dataObj = new Blob([xhr.response], { type: 'text/plain' })
|
|
|
+ this.cordovaDownFile(dataObj, fname);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ cordovaDownFile(blob, fname) {
|
|
|
+ function writeFile(fileEntry, dataObj) {
|
|
|
+ fileEntry.createWriter(function (fileWriter) {
|
|
|
+ fileWriter.onwriteend = function () {
|
|
|
+ alert('Successful file write...');
|
|
|
+ alert(fileEntry.fullPath);
|
|
|
+ };
|
|
|
+
|
|
|
+ fileWriter.onerror = function (e) {
|
|
|
+ alert('Failed file write: ' + e.toString());
|
|
|
+ };
|
|
|
+
|
|
|
+ fileWriter.write(dataObj);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ const onError = function (msg) {
|
|
|
+ alert('error:' + msg.code);
|
|
|
+ alert(Object.keys(msg) + '');
|
|
|
+ alert('error:' + msg.toString());
|
|
|
+ };
|
|
|
+
|
|
|
+ let downDir = cordova.file.externalRootDirectory + 'Download/';
|
|
|
+ // alert(downDir)
|
|
|
+ window.resolveLocalFileSystemURL(
|
|
|
+ downDir,
|
|
|
+ function (fdir) {
|
|
|
+ alert(fdir);
|
|
|
+ fdir.getFile(
|
|
|
+ fname,
|
|
|
+ { create: true },
|
|
|
+ function (file) {
|
|
|
+ file.createWriter(function (fileWriter) {
|
|
|
+ alert('Writing content to file');
|
|
|
+ fileWriter.onwriteend = function () {
|
|
|
+ alert('Successful file write...');
|
|
|
+ };
|
|
|
+
|
|
|
+ fileWriter.onerror = function (e) {
|
|
|
+ alert('Failed file write: ' + e.toString());
|
|
|
+ };
|
|
|
+ fileWriter.write(blob);
|
|
|
+ }, onError);
|
|
|
+ },
|
|
|
+ onError
|
|
|
+ );
|
|
|
+ },
|
|
|
+ onError
|
|
|
+ );
|
|
|
+ // window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
|
|
|
+ // // Make sure you add the domain name to the Content-Security-Policy <meta> element.
|
|
|
+ // alert('file system open: ' + fs.name)
|
|
|
+ // fs.root.getFile(fname, { create: true, exclusive: false },
|
|
|
+ // function (fileEntry) {
|
|
|
+ // alert("fileEntry is file?" + fileEntry.isFile.toString())
|
|
|
+ // writeFile(fileEntry, blob);
|
|
|
+ // }, onError);
|
|
|
+ // },onError);
|
|
|
+ },
|
|
|
+
|
|
|
+ downloadFile(url) {
|
|
|
+ const fileUrl = url + '?response-content-type=application/octet-stream'; // Replace with your file URL
|
|
|
+ let urspll = url.split('/');
|
|
|
+ let fname = urspll[urspll.length - 1];
|
|
|
+ if (window.cordova) {
|
|
|
+ try {
|
|
|
+ this.checkPermission(url, fname);
|
|
|
+ } catch (e) {
|
|
|
+ alert(e);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.onlyDownFile(url);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ handleDown(row) {
|
|
|
+ let rawImg = this.rawImags[row];
|
|
|
+ let jFile = this.jFiles[row];
|
|
|
+ if (!jFile) {
|
|
|
+ this.$message({
|
|
|
+ message: '链接获取失败,建议在预览页面查看矫正文件是否上传',
|
|
|
+ type: 'error'
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let files = [
|
|
|
+ { url: jFile, name: '布点文件' },
|
|
|
+ { url: rawImg, name: '原图' }
|
|
|
+ ];
|
|
|
+ files.forEach((url) => {
|
|
|
+ const iframe = document.createElement('iframe');
|
|
|
+ iframe.style.display = 'none';
|
|
|
+ iframe.style.height = 0;
|
|
|
+ iframe.src = url.url;
|
|
|
+ document.body.appendChild(iframe);
|
|
|
+ // 不能马上将iframe进行删除,否者会出现马上取消的情况
|
|
|
+ setTimeout(() => {
|
|
|
+ iframe.remove();
|
|
|
+ }, 3 * 1000);
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ downCamParamFile() {
|
|
|
+ let jfile = this.jFiles[1];
|
|
|
+ if (!jfile) {
|
|
|
+ this.$message({
|
|
|
+ message: '请先预览布点文件再下载',
|
|
|
+ type: 'error'
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ } else if (!this.camparamUptime[1]) {
|
|
|
+ this.$message({
|
|
|
+ message: '该摄像头未矫正',
|
|
|
+ type: 'error'
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let cpfile = jfile.substring(0, jfile.length - 4) + 'yml';
|
|
|
+ const iframe = document.createElement('iframe');
|
|
|
+ iframe.style.display = 'none';
|
|
|
+ iframe.style.height = 0;
|
|
|
+ iframe.src = cpfile;
|
|
|
+ document.body.appendChild(iframe);
|
|
|
+ // 不能马上将iframe进行删除,否者会出现马上取消的情况
|
|
|
+ setTimeout(() => {
|
|
|
+ iframe.remove();
|
|
|
+ }, 3 * 1000);
|
|
|
+ },
|
|
|
+
|
|
|
+ checkUpFIrr(up_type, cindex, loading) {
|
|
|
+ this.$http.deploy
|
|
|
+ .getExamSnapShot({
|
|
|
+ exam_id: this.examId,
|
|
|
+ no_req: 1,
|
|
|
+ qindex: cindex,
|
|
|
+ school_id: this.schoolId,
|
|
|
+ cam_path: this.ruleForm.cam_path,
|
|
|
+ anchor_path: this.ruleForm.anchor_path,
|
|
|
+ cam_param_path: this.ruleForm.cam_param_path,
|
|
|
+ up_type: up_type
|
|
|
+ })
|
|
|
+ .then((res) => {
|
|
|
+ console.log(res, 'checkUpFIrr');
|
|
|
+ if (up_type == 'json') {
|
|
|
+ let ach_err = res.data.anchor_uptime[cindex + '_error'];
|
|
|
+ if (ach_err == '文件校验中,请稍等') {
|
|
|
+ this.$message.info(ach_err);
|
|
|
+ } else {
|
|
|
+ if (loading) {
|
|
|
+ setTimeout(() => {
|
|
|
+ loading.close();
|
|
|
+ loading = null;
|
|
|
+ }, 1000);
|
|
|
+ }
|
|
|
+ if (this.checkUpFID) clearInterval(this.checkUpFID);
|
|
|
+ if (ach_err) {
|
|
|
+ this.$message.error('布点文件校验失败,原因:' + ach_err);
|
|
|
+ } else {
|
|
|
+ this.$message.success('布点文件上传成功!');
|
|
|
+ this.setFormPath(cindex, up_type);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (up_type == 'yml') {
|
|
|
+ let camP_err = res.data.camparam_uptime[cindex + '_error'];
|
|
|
+ if (camP_err == '上传文件校验中,请稍等') {
|
|
|
+ this.$message.info(ach_err);
|
|
|
+ } else {
|
|
|
+ if (loading) {
|
|
|
+ setTimeout(() => {
|
|
|
+ loading.close();
|
|
|
+ loading = null;
|
|
|
+ }, 1000);
|
|
|
+ }
|
|
|
+ if (this.checkUpFID) clearInterval(this.checkUpFID);
|
|
|
+ if (camP_err) {
|
|
|
+ this.$message.error('矫正文件校验失败,原因:' + camP_err);
|
|
|
+ } else {
|
|
|
+ clearInterval(this.checkUpFID);
|
|
|
+ this.$message.success('矫正文件上传成功!');
|
|
|
+ this.setFormPath(cindex, up_type);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ setFormPath(cindex, up_type) {
|
|
|
+ this.showPlayer = false;
|
|
|
+ if (up_type == 'yml') {
|
|
|
+ if (cindex == 1 && !this.ruleForm.cam_param_path) {
|
|
|
+ this.ruleForm.cam_param_path = 'settings/cam_param_files/' + this.examId + '_' + cindex + '.yml';
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (cindex == 1 && !this.ruleForm.anchor_path) {
|
|
|
+ this.ruleForm.anchor_path = 'settings/anchor_files/' + this.examId + '_' + cindex + '.json';
|
|
|
+ } else if (cindex == 0 && !this.ruleForm.anchor_face_path) {
|
|
|
+ this.ruleForm.anchor_face_path = 'settings/anchor_files/' + this.examId + '_' + cindex + '.json';
|
|
|
+ } else if (cindex == 2 && !this.ruleForm.anchor_0_path) {
|
|
|
+ this.ruleForm.anchor_0_path = 'settings/anchor_files/' + this.examId + '_' + cindex + '.json';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ handleUpload(res, f, flist, loading = null) {
|
|
|
+ if (this.checkUpFID) {
|
|
|
+ clearInterval(this.checkUpFID);
|
|
|
+ }
|
|
|
+ if (res.status != 200) {
|
|
|
+ this.message.error(res.message);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let cindex = Number(res.cindex);
|
|
|
+ let up_type = res.up_type;
|
|
|
+ console.log(res, 'handleUploadhandleUpload');
|
|
|
+ clearInterval(this.checkUpFID);
|
|
|
+ this.checkUpFID = setInterval(this.checkUpFIrr, 2000, up_type, cindex, loading);
|
|
|
+ },
|
|
|
+
|
|
|
+ async getExamConf() {
|
|
|
+ await this.$http.deploy.getExamSettings({ school_id: this.schoolId, exam_id: this.examId }).then((res) => {
|
|
|
+ // this.ruleForm = Object.assign({}, res.data)
|
|
|
+ if (res.status != 200) {
|
|
|
+ this.$message({
|
|
|
+ message: res.message,
|
|
|
+ type: 'error'
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.uutoken = res.uutoken;
|
|
|
+ if (res.localip) {
|
|
|
+ this.lsrsHost = res.localip;
|
|
|
+ }
|
|
|
+ if (res.haslocalsrs) {
|
|
|
+ if (res.haslocalsrs == '0') {
|
|
|
+ this.hasLocSRS = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ let version = 0;
|
|
|
+ if (res.version) {
|
|
|
+ version = res.version;
|
|
|
+ console.log('version: ', version);
|
|
|
+ }
|
|
|
+
|
|
|
+ Object.keys(this.ruleForm).forEach((key) => {
|
|
|
+ // console.log(key, res.data[key], "11112222333")
|
|
|
+ if (key in res.data) {
|
|
|
+ this.ruleForm[key] = res.data[key];
|
|
|
+ } else if (!(key in this.examFormConf['required'] || key in this.examFormConf['advanced'] || key in this.examFormConf['reserved'])) {
|
|
|
+ delete this.ruleForm[key];
|
|
|
+ }
|
|
|
+ if (version < 2.5) {
|
|
|
+ delete this.ruleForm['flag_check_singleleg_jump'];
|
|
|
+ if (this.exam_name == 'situp') {
|
|
|
+ delete this.ruleForm['flag_check_elbow'];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ this.rawFormData = JSON.stringify(this.ruleForm);
|
|
|
+ console.log(res, 'finalformres');
|
|
|
+ if (!this.hasLocSRS) {
|
|
|
+ this.checkLocRSR();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ submitForm(formName, restart) {
|
|
|
+ this.$refs[formName].validate((valid) => {
|
|
|
+ if (valid) {
|
|
|
+ let tmpFdata = JSON.stringify(this.ruleForm);
|
|
|
+ this.$http.deploy.upExamSettings({ school_id: this.schoolId, exam_id: this.examId, js_data: tmpFdata, restart }).then((res) => {
|
|
|
+ this.rawFormData = tmpFdata;
|
|
|
+ if (res.message == 'ok') {
|
|
|
+ this.$message({
|
|
|
+ message: '更新成功',
|
|
|
+ type: 'success'
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.$message({
|
|
|
+ message: res.message,
|
|
|
+ type: 'error'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ console.log(res);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ console.log('error submit!!');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ clearFormValue(field) {
|
|
|
+ this.ruleForm[field] = '';
|
|
|
+ },
|
|
|
+ resetForm(formName) {
|
|
|
+ this.$refs[formName].resetFields();
|
|
|
+ },
|
|
|
+ back() {
|
|
|
+ this.$router.go(-1);
|
|
|
+ // this.$router.back()
|
|
|
+ },
|
|
|
+ getEName() {
|
|
|
+ let ename = this.exam_name;
|
|
|
+ let posi = '';
|
|
|
+ if (this.isShortRun) {
|
|
|
+ ename = 'shortrun';
|
|
|
+ } else if (this.isLongRun) {
|
|
|
+ ename = 'longrun';
|
|
|
+ } else if (this.isBackRun) {
|
|
|
+ ename = 'backrun';
|
|
|
+ }
|
|
|
+ if (this.camIndex == 0) {
|
|
|
+ if (ename.indexOf('run') > -1) {
|
|
|
+ ename += '_st';
|
|
|
+ } else {
|
|
|
+ ename = 'face';
|
|
|
+ }
|
|
|
+ } else if (this.camIndex === 1) {
|
|
|
+ if (this.isDisExams) {
|
|
|
+ posi = 'left';
|
|
|
+ }
|
|
|
+ } else if (this.camIndex === 2) {
|
|
|
+ posi = '2';
|
|
|
+ }
|
|
|
+ return [ename, posi];
|
|
|
+ },
|
|
|
+ loadAnchorFile(file) {
|
|
|
+ let reader = new FileReader(); // 新建一个FileReader
|
|
|
+ reader.readAsText(file, 'UTF-8'); // 读取文件
|
|
|
+ reader.onload = (evt) => {
|
|
|
+ // 读取文件完毕执行此函数
|
|
|
+ console.log(evt.target.result, 'evt.target.result');
|
|
|
+ const dataJson = JSON.parse(evt.target.result);
|
|
|
+ console.log(dataJson, 'dataJson');
|
|
|
+ this.anchorNum = dataJson.num || 1;
|
|
|
+ this.runStartAnchor(dataJson.names, dataJson.connects, dataJson.keypoints, dataJson.imagesize);
|
|
|
+ };
|
|
|
+ return false;
|
|
|
+ },
|
|
|
+
|
|
|
+ saveAnchor() {
|
|
|
+ if (!this.names) {
|
|
|
+ this.$message({ message: '请进入布点或加载布点文件', type: 'error' });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let keypoints = [];
|
|
|
+ const loading = this.$loading({
|
|
|
+ lock: true,
|
|
|
+ text: '正在保存中...',
|
|
|
+ spinner: 'el-icon-loading'
|
|
|
+ // background: 'rgba(0, 0, 0, 0.7)'
|
|
|
+ });
|
|
|
+ this.points.forEach((point) => {
|
|
|
+ keypoints.push(parseInt((point.x - this.xPos) * (this.imgSize[0] / this.scaledWidth)));
|
|
|
+ keypoints.push(parseInt((point.y - this.yPos) * (this.imgSize[1] / this.scaledHeight)));
|
|
|
+ });
|
|
|
+ let jsData = { names: this.names, imagesize: this.imgSize, connects: this.connects, keypoints: keypoints, num: this.anchorNum };
|
|
|
+ this.$http.deploy.saveAnchorPt({ exam_id: this.examId, cindex: this.camIndex, school_id: this.schoolId, js_data: jsData }).then((res) => {
|
|
|
+ if (res.status == 200) {
|
|
|
+ this.handleUpload(res, null, [], loading);
|
|
|
+ this.rawPoints = JSON.stringify(this.points);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ lastAnchor() {
|
|
|
+ this.btnDis = true;
|
|
|
+ let url =
|
|
|
+ '//aiexam-data.oss-cn-shenzhen.aliyuncs.com/midexam/uploaded_files/settings/' +
|
|
|
+ this.uutoken +
|
|
|
+ '/' +
|
|
|
+ this.examId +
|
|
|
+ '_' +
|
|
|
+ this.camIndex +
|
|
|
+ '.json' +
|
|
|
+ '?' +
|
|
|
+ Math.random();
|
|
|
+ this.downAnchorFile(url, 'load', 'anchor_config', this.camIndex);
|
|
|
+ },
|
|
|
+
|
|
|
+ upAndDownPFile(cindex, ftype = 'json') {
|
|
|
+ let url =
|
|
|
+ '//aiexam-data.oss-cn-shenzhen.aliyuncs.com/midexam/uploaded_files/settings/' + this.uutoken + '/' + this.examId + '_' + cindex + '.' + ftype;
|
|
|
+ console.log(url, 'upAndDownPFile');
|
|
|
+ let upType = 'anchor_config';
|
|
|
+ if (ftype == 'yml') {
|
|
|
+ upType = 'camera_param';
|
|
|
+ }
|
|
|
+ this.downAnchorFile(url, 'down', upType, cindex);
|
|
|
+ },
|
|
|
+
|
|
|
+ downAnchorFile(url, _type = 'load', upType = 'anchor_config', cindex = 1) {
|
|
|
+ this.upSnapShotInfos(0, upType);
|
|
|
+ this.$message({
|
|
|
+ message: '正在获取文件,请稍等',
|
|
|
+ type: 'warning'
|
|
|
+ });
|
|
|
+ setTimeout(() => {
|
|
|
+ axios
|
|
|
+ .get(url)
|
|
|
+ .then((response) => {
|
|
|
+ console.log(response);
|
|
|
+ let anchorErr;
|
|
|
+ if (upType == 'anchor_config') {
|
|
|
+ anchorErr = this.anchorUptime['error'] || this.anchorUptime[cindex + '_error'];
|
|
|
+ } else {
|
|
|
+ anchorErr = this.camparamUptime[cindex + '_error'];
|
|
|
+ }
|
|
|
+ this.btnDis = false;
|
|
|
+ if (anchorErr) {
|
|
|
+ clearInterval(this.lstAnchorIvalId);
|
|
|
+ this.$message({
|
|
|
+ message: anchorErr + ',无法获取文件',
|
|
|
+ type: 'error'
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (this.lstAnchorIvalId) {
|
|
|
+ clearInterval(this.lstAnchorIvalId);
|
|
|
+ }
|
|
|
+ if (_type == 'load') {
|
|
|
+ this.stdAnchObj = response.data;
|
|
|
+ this.$message({
|
|
|
+ message: '上次布点加载成功。',
|
|
|
+ type: 'success'
|
|
|
+ });
|
|
|
+ this.runStartAnchor(this.stdAnchObj.names, this.stdAnchObj.connects, this.stdAnchObj.keypoints, this.stdAnchObj.imagesize);
|
|
|
+ } else if (_type == 'down') {
|
|
|
+ this.downloadFile(url);
|
|
|
+ } else {
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((error) => {
|
|
|
+ if (upType == 'anchor_config') {
|
|
|
+ this.btnDis = false;
|
|
|
+ let anchorErr = this.anchorUptime['error'] || this.anchorUptime[this.camIndex + '_error'];
|
|
|
+ if (anchorErr) {
|
|
|
+ if (this.lstAnchorIvalId) {
|
|
|
+ clearInterval(this.lstAnchorIvalId);
|
|
|
+ this.btnDis = false;
|
|
|
+ }
|
|
|
+ this.$message({
|
|
|
+ message: anchorErr + ',无法获取上次布点',
|
|
|
+ type: 'error'
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // this.lstAnchorIvalId = setInterval(
|
|
|
+ // this.downAnchorFile, 3000, url, 'down', upType)
|
|
|
+ } else {
|
|
|
+ let anchorErr = this.camparamUptime['error'] || this.camparamUptime[this.camIndex + '_error'];
|
|
|
+ if (anchorErr) {
|
|
|
+ this.$message({
|
|
|
+ message: anchorErr + ',无法获取矫正文件',
|
|
|
+ type: 'error'
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }, 3500);
|
|
|
+ },
|
|
|
+ startAnchor(lsturl = '') {
|
|
|
+ let ep = this.getEName();
|
|
|
+ let ename = ep[0];
|
|
|
+ let posi = ep[1];
|
|
|
+ let url = `https://aiexam-data.oss-cn-shenzhen.aliyuncs.com/midexam/uploaded_files/std_anchors/${ename}_${posi}.json`;
|
|
|
+ axios
|
|
|
+ .get(url)
|
|
|
+ .then((response) => {
|
|
|
+ console.log(response);
|
|
|
+ this.stdAnchObj = response.data;
|
|
|
+ this.runStartAnchor(this.stdAnchObj.names, this.stdAnchObj.connects, this.stdAnchObj.keypoints, this.stdAnchObj.imagesize);
|
|
|
+ })
|
|
|
+ .catch((error) => {
|
|
|
+ if (ename in this.anchorSetsObj) {
|
|
|
+ this.stdAnchObj = this.anchorSetsObj[ename];
|
|
|
+ } else {
|
|
|
+ this.stdAnchObj = this.anchorSetsObj['basic'];
|
|
|
+ }
|
|
|
+ this.runStartAnchor(this.stdAnchObj.names, this.stdAnchObj.connects);
|
|
|
+ console.log(this.stdAnchObj, 'this.stdAnchObj');
|
|
|
+ return null;
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ calculateDistance(touch1, touch2) {
|
|
|
+ const dx = touch1.clientX - touch2.clientX;
|
|
|
+ const dy = touch1.clientY - touch2.clientY;
|
|
|
+ return Math.sqrt(dx * dx + dy * dy);
|
|
|
+ },
|
|
|
+
|
|
|
+ runStartAnchor(names = null, connects = null, kPoints = null, imagesize = null) {
|
|
|
+ var vm = this;
|
|
|
+ let video = this.video;
|
|
|
+ this.video.style.display = 'none';
|
|
|
+ const canvas = document.getElementById('canvas');
|
|
|
+ const ctx = canvas.getContext('2d');
|
|
|
+ // const aliplayer = this.$refs['playerRef'];
|
|
|
+ // aliplayer.pause()
|
|
|
+ canvas.height = this.windowHeight;
|
|
|
+ canvas.width = this.windowWidth;
|
|
|
+ if (this.cIntervalId) {
|
|
|
+ clearInterval(this.cIntervalId);
|
|
|
+ }
|
|
|
+ this.lines = [];
|
|
|
+ let anchorObj = this.stdAnchObj;
|
|
|
+ if (!connects) {
|
|
|
+ this.connects = [];
|
|
|
+ this.lines = anchorObj['lines'];
|
|
|
+ this.lines.forEach((line) => {
|
|
|
+ this.connects.push(line[0]);
|
|
|
+ this.connects.push(line[1]);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.connects = connects;
|
|
|
+ for (let l = 0; l < connects.length / 2; l++) {
|
|
|
+ this.lines.push([connects[2 * l], connects[2 * l + 1]]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!names) {
|
|
|
+ this.names = anchorObj['names'];
|
|
|
+ } else this.names = names;
|
|
|
+ if (!imagesize) {
|
|
|
+ imagesize = this.imgSize;
|
|
|
+ }
|
|
|
+ this.points = [];
|
|
|
+
|
|
|
+ if (!kPoints) {
|
|
|
+ this.names.forEach((name, idx) => {
|
|
|
+ let ix = idx % 16;
|
|
|
+ let iy = parseInt(idx / 16);
|
|
|
+ let x = (10 + 40 * ix) / (imagesize[0] / this.scaledWidth) + this.xPos;
|
|
|
+ let y = (40 + 40 * iy) / (imagesize[1] / this.scaledHeight) + this.yPos;
|
|
|
+ this.points.push({ x: x, y: y, name: name });
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ console.log(imagesize, 'imagesize', this.scaledWidth, this.xPos);
|
|
|
+ this.names.forEach((name, idx) => {
|
|
|
+ let x = kPoints[idx * 2] / (imagesize[0] / this.scaledWidth) + this.xPos;
|
|
|
+ let y = kPoints[idx * 2 + 1] / (imagesize[1] / this.scaledHeight) + this.yPos;
|
|
|
+ this.points.push({ x: x, y: y, name: name });
|
|
|
+ });
|
|
|
+ }
|
|
|
+ this.rawPoints = JSON.stringify(this.points);
|
|
|
+ // Define dragging variables
|
|
|
+ var isDragging = false;
|
|
|
+ var dragIndex = -1;
|
|
|
+ var isZoom = false;
|
|
|
+ // var xRate = vm.scaledWidth/this.video.videoWidth
|
|
|
+ // var yRate = vm.scaledHeight/this.video.videoHeight
|
|
|
+ console.log(vm.yPos, vm.xPos, vm.scaledWidth, vm.scaledHeight);
|
|
|
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
|
+ run();
|
|
|
+
|
|
|
+ function scaledX(xal) {
|
|
|
+ return (xal - vm.xPos) * vm.zoomRatio + vm.xPos;
|
|
|
+ }
|
|
|
+ function scaledY(yval) {
|
|
|
+ return (yval - vm.yPos) * vm.zoomRatio + vm.yPos;
|
|
|
+ }
|
|
|
+
|
|
|
+ function pointSelect(e) {
|
|
|
+ if (isDragging || isZoom) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const touchPoints = e.touches;
|
|
|
+ // if (!touchPoints) {
|
|
|
+ // return
|
|
|
+ // }
|
|
|
+ if (touchPoints && touchPoints.length === 2) {
|
|
|
+ const touch1 = touchPoints[0];
|
|
|
+ const touch2 = touchPoints[1];
|
|
|
+ vm.startDistance = vm.calculateDistance(touch1, touch2);
|
|
|
+ this.lastZoom = vm.zoomRatio;
|
|
|
+ isZoom = true;
|
|
|
+ } else {
|
|
|
+ const rect = canvas.getBoundingClientRect();
|
|
|
+ if (e.touches) {
|
|
|
+ let tcl = e.touches.length;
|
|
|
+ let tctx = 0;
|
|
|
+ let tcty = 0;
|
|
|
+ console.log(typeof e.touches);
|
|
|
+ Object.keys(e.touches).forEach((key) => {
|
|
|
+ let touch = e.touches[key];
|
|
|
+ tctx += touch.clientX;
|
|
|
+ tcty += touch.clientY;
|
|
|
+ });
|
|
|
+ e.clientX = tctx / tcl;
|
|
|
+ e.clientY = tcty / tcl;
|
|
|
+ }
|
|
|
+ console.log(e, rect.left, rect.top, '!!!');
|
|
|
+ const mouseX = e.clientX - rect.left;
|
|
|
+ const mouseY = e.clientY - rect.top;
|
|
|
+ // Check if mouse is over a point
|
|
|
+
|
|
|
+ dragIndex = vm.points.findIndex((point) => {
|
|
|
+ return Math.abs(scaledX(point.x) - mouseX) <= 18 && Math.abs(scaledY(point.y) - mouseY) <= 18;
|
|
|
+ });
|
|
|
+ // Set dragging variables
|
|
|
+ if (dragIndex !== -1) {
|
|
|
+ isDragging = true;
|
|
|
+ this.dragStartX = scaledX(vm.points[dragIndex].x);
|
|
|
+ this.dragStartY = scaledY(vm.points[dragIndex].y);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function drag(e) {
|
|
|
+ if (isDragging) {
|
|
|
+ e.preventDefault();
|
|
|
+ const rect = canvas.getBoundingClientRect();
|
|
|
+ if (e.touches) {
|
|
|
+ let tcl = e.touches.length;
|
|
|
+ console.log(tcl, 'tcl');
|
|
|
+ let tctx = 0;
|
|
|
+ let tcty = 0;
|
|
|
+ Object.keys(e.touches).forEach((key) => {
|
|
|
+ let touch = e.touches[key];
|
|
|
+ tctx += touch.clientX;
|
|
|
+ tcty += touch.clientY;
|
|
|
+ });
|
|
|
+ e.clientX = tctx / tcl;
|
|
|
+ e.clientY = tcty / tcl;
|
|
|
+ }
|
|
|
+ let currentx;
|
|
|
+ let currenty;
|
|
|
+ console.log(vm.xPos, e.clientX, rect.left, 'Dragdrag...');
|
|
|
+ if (e.clientX > vm.scaledWidth * vm.zoomRatio + vm.xPos + rect.left) {
|
|
|
+ currentx = vm.scaledWidth * vm.zoomRatio + vm.xPos + rect.left;
|
|
|
+ } else if (e.clientX < vm.xPos + rect.left) {
|
|
|
+ currentx = vm.xPos + rect.left;
|
|
|
+ } else {
|
|
|
+ currentx = e.clientX;
|
|
|
+ }
|
|
|
+ if (e.clientY > vm.scaledHeight * vm.zoomRatio + vm.yPos + rect.top) {
|
|
|
+ currenty = vm.scaledHeight * vm.zoomRatio + vm.yPos + rect.top;
|
|
|
+ // e.clientY = currenty
|
|
|
+ } else if (e.clientY < vm.yPos + rect.top) {
|
|
|
+ currenty = vm.yPos + rect.top;
|
|
|
+ } else {
|
|
|
+ currenty = e.clientY;
|
|
|
+ }
|
|
|
+
|
|
|
+ // console.log("dragged111", rect.left, rect.top, e)
|
|
|
+ // const mouseX = e.clientX - rect.left;
|
|
|
+ // const mouseY = e.clientY - rect.top;
|
|
|
+ const mouseX = currentx - rect.left;
|
|
|
+ const mouseY = currenty - rect.top;
|
|
|
+ // Calculate distance dragged
|
|
|
+ const deltaX = mouseX - this.dragStartX;
|
|
|
+ const deltaY = mouseY - this.dragStartY;
|
|
|
+ this.dragStartX = mouseX;
|
|
|
+ this.dragStartY = mouseY;
|
|
|
+ // Update dragged point
|
|
|
+ vm.points[dragIndex].y += deltaY / vm.zoomRatio;
|
|
|
+ // vm.points[dragIndex].y + deltaY
|
|
|
+ vm.points[dragIndex].x += deltaX / vm.zoomRatio;
|
|
|
+ // Redraw points and lines
|
|
|
+ drawPointsAndLines();
|
|
|
+ } else if (isZoom) {
|
|
|
+ const touchPoints = e.touches;
|
|
|
+ if (touchPoints && touchPoints.length === 2) {
|
|
|
+ const touch1 = touchPoints[0];
|
|
|
+ const touch2 = touchPoints[1];
|
|
|
+ vm.currentDistance = vm.calculateDistance(touch1, touch2);
|
|
|
+ if ((vm.currentDistance * this.lastZoom) / vm.startDistance < 1) {
|
|
|
+ vm.zoomRatio = 1;
|
|
|
+ } else {
|
|
|
+ vm.zoomRatio = (this.lastZoom * vm.currentDistance) / vm.startDistance;
|
|
|
+ }
|
|
|
+ canvas.width = vm.windowWidth * vm.zoomRatio;
|
|
|
+ canvas.height = vm.windowHeight * vm.zoomRatio;
|
|
|
+ drawPointsAndLines();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ function stopDrag(e) {
|
|
|
+ isDragging = false;
|
|
|
+ dragIndex = -1;
|
|
|
+ isZoom = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ function drawPointsAndLines() {
|
|
|
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
|
+ ctx.drawImage(vm.video, vm.xPos, vm.yPos, vm.scaledWidth * vm.zoomRatio, vm.scaledHeight * vm.zoomRatio);
|
|
|
+
|
|
|
+ // Draw lines
|
|
|
+ ctx.strokeStyle = 'red';
|
|
|
+ ctx.lineWidth = 0.6 * vm.zoomRatio;
|
|
|
+ vm.lines.forEach((line) => {
|
|
|
+ const [startIndex, endIndex] = line;
|
|
|
+ const startPoint = vm.points[startIndex];
|
|
|
+ const endPoint = vm.points[endIndex];
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.moveTo(scaledX(startPoint.x), scaledY(startPoint.y));
|
|
|
+ ctx.lineTo(scaledX(endPoint.x), scaledY(endPoint.y));
|
|
|
+ ctx.stroke();
|
|
|
+ });
|
|
|
+
|
|
|
+ vm.points.forEach((point, index) => {
|
|
|
+ ctx.beginPath();
|
|
|
+ // let scaledPx = scaledX(point.x)
|
|
|
+ // let scaledPy = scaledY(point.y)
|
|
|
+ ctx.arc(scaledX(point.x), scaledY(point.y), 3.5 * vm.zoomRatio, 0, 2 * Math.PI);
|
|
|
+ ctx.fillStyle = 'red';
|
|
|
+ ctx.fillText(point.name, scaledX(point.x), scaledY(point.y) - 5);
|
|
|
+ ctx.fill();
|
|
|
+ ctx.stroke();
|
|
|
+ // Draw label for dragged point
|
|
|
+ if (index === dragIndex) {
|
|
|
+ ctx.fillStyle = 'origin';
|
|
|
+ // ctx.fillText(
|
|
|
+ // `(Math.f${point.x}, ${point.y})`, point.x + 5, point.y - 5);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // function wheelAction(event) {
|
|
|
+ // event.preventDefault();
|
|
|
+ // }
|
|
|
+
|
|
|
+ function run() {
|
|
|
+ if (vm.cIntervalId) {
|
|
|
+ clearInterval(vm.cIntervalId);
|
|
|
+ }
|
|
|
+ vm.cIntervalId = setInterval(drawPointsAndLines, 50);
|
|
|
+ canvas.addEventListener('mousedown', pointSelect);
|
|
|
+ canvas.addEventListener('touchstart', pointSelect);
|
|
|
+ canvas.addEventListener('mousemove', drag);
|
|
|
+ canvas.addEventListener('touchmove', drag, { passive: false });
|
|
|
+ canvas.addEventListener('mouseup', stopDrag);
|
|
|
+ canvas.addEventListener('mouseleave', stopDrag);
|
|
|
+ canvas.addEventListener('touchend', stopDrag);
|
|
|
+ // canvas.addEventListener('wheel', wheelAction);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ copyContent(content, item) {
|
|
|
+ this.$copyText(content).then(
|
|
|
+ (e) => {
|
|
|
+ this.ruleForm[item] = content;
|
|
|
+ this.$message({
|
|
|
+ message: '复制成功',
|
|
|
+ type: 'success'
|
|
|
+ });
|
|
|
+ // this.showCamUrl = false
|
|
|
+ },
|
|
|
+ function (e) {
|
|
|
+ this.$message({
|
|
|
+ message: '复制失败,请手动复制',
|
|
|
+ type: 'error'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ );
|
|
|
+ },
|
|
|
+
|
|
|
+ SrsRtcPlayerAsync() {
|
|
|
+ var self = {};
|
|
|
+ self.play = async function (url) {
|
|
|
+ var conf = self.__internal.prepareUrl(url);
|
|
|
+ self.pc.addTransceiver('audio', { direction: 'recvonly' });
|
|
|
+ self.pc.addTransceiver('video', { direction: 'recvonly' });
|
|
|
+
|
|
|
+ var offer = await self.pc.createOffer();
|
|
|
+ await self.pc.setLocalDescription(offer);
|
|
|
+ var session = await new Promise(function (resolve, reject) {
|
|
|
+ // @see https://github.com/rtcdn/rtcdn-draft
|
|
|
+ var data = {
|
|
|
+ api: conf.apiUrl,
|
|
|
+ tid: conf.tid,
|
|
|
+ streamurl: conf.streamUrl,
|
|
|
+ clientip: null,
|
|
|
+ sdp: offer.sdp
|
|
|
+ };
|
|
|
+ console.log('Generated offer: ', data);
|
|
|
+
|
|
|
+ $.ajax({
|
|
|
+ type: 'POST',
|
|
|
+ url: conf.apiUrl,
|
|
|
+ data: JSON.stringify(data),
|
|
|
+ contentType: 'application/json',
|
|
|
+ dataType: 'json'
|
|
|
+ })
|
|
|
+ .done(function (data) {
|
|
|
+ console.log('Got answer: ', data);
|
|
|
+ if (data.code) {
|
|
|
+ reject(data);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ resolve(data);
|
|
|
+ })
|
|
|
+ .fail(function (reason) {
|
|
|
+ reject(reason);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ await self.pc.setRemoteDescription(new RTCSessionDescription({ type: 'answer', sdp: session.sdp }));
|
|
|
+ session.simulator = conf.schema + '//' + conf.urlObject.server + ':' + conf.port + '/rtc/v1/nack/';
|
|
|
+ return session;
|
|
|
+ };
|
|
|
+ // Close the player.
|
|
|
+ self.close = function () {
|
|
|
+ self.pc && self.pc.close();
|
|
|
+ self.pc = null;
|
|
|
+ };
|
|
|
+ self.ontrack = function (event) {
|
|
|
+ // https://webrtc.org/getting-started/remote-streams
|
|
|
+ self.stream.addTrack(event.track);
|
|
|
+ };
|
|
|
+ // Internal APIs.
|
|
|
+ self.__internal = {
|
|
|
+ defaultPath: '/rtc/v1/play/',
|
|
|
+ prepareUrl: function (webrtcUrl) {
|
|
|
+ var urlObject = self.__internal.parse(webrtcUrl);
|
|
|
+ // If user specifies the schema, use it as API schema.
|
|
|
+ var schema = urlObject.user_query.schema;
|
|
|
+ schema = schema ? schema + ':' : window.location.protocol;
|
|
|
+ var port = urlObject.port || 1985;
|
|
|
+ if (schema === 'https:') {
|
|
|
+ port = urlObject.port || 1990;
|
|
|
+ }
|
|
|
+ // @see https://github.com/rtcdn/rtcdn-draft
|
|
|
+ var api = urlObject.user_query.play || self.__internal.defaultPath;
|
|
|
+ if (api.lastIndexOf('/') !== api.length - 1) {
|
|
|
+ api += '/';
|
|
|
+ }
|
|
|
+ apiUrl = schema + '//' + urlObject.server + ':' + port + api;
|
|
|
+ for (var key in urlObject.user_query) {
|
|
|
+ if (key !== 'api' && key !== 'play') {
|
|
|
+ apiUrl += '&' + key + '=' + urlObject.user_query[key];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // Replace /rtc/v1/play/&k=v to /rtc/v1/play/?k=v
|
|
|
+ var apiUrl = apiUrl.replace(api + '&', api + '?');
|
|
|
+ var streamUrl = urlObject.url;
|
|
|
+
|
|
|
+ return {
|
|
|
+ apiUrl: apiUrl,
|
|
|
+ streamUrl: streamUrl,
|
|
|
+ schema: schema,
|
|
|
+ urlObject: urlObject,
|
|
|
+ port: port,
|
|
|
+ tid: Number(parseInt(new Date().getTime() * Math.random() * 100))
|
|
|
+ .toString(16)
|
|
|
+ .substr(0, 7)
|
|
|
+ };
|
|
|
+ },
|
|
|
+ parse: function (url) {
|
|
|
+ // @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri
|
|
|
+ var a = document.createElement('a');
|
|
|
+ a.href = url.replace('rtmp://', 'http://').replace('webrtc://', 'http://').replace('rtc://', 'http://');
|
|
|
+
|
|
|
+ var vhost = a.hostname;
|
|
|
+ var app = a.pathname.substr(1, a.pathname.lastIndexOf('/') - 1);
|
|
|
+ var stream = a.pathname.substr(a.pathname.lastIndexOf('/') + 1);
|
|
|
+
|
|
|
+ // parse the vhost in the params of app, that srs supports.
|
|
|
+ app = app.replace('...vhost...', '?vhost=');
|
|
|
+ if (app.indexOf('?') >= 0) {
|
|
|
+ var params = app.substr(app.indexOf('?'));
|
|
|
+ app = app.substr(0, app.indexOf('?'));
|
|
|
+
|
|
|
+ if (params.indexOf('vhost=') > 0) {
|
|
|
+ vhost = params.substr(params.indexOf('vhost=') + 'vhost='.length);
|
|
|
+ if (vhost.indexOf('&') > 0) {
|
|
|
+ vhost = vhost.substr(0, vhost.indexOf('&'));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (a.hostname === vhost) {
|
|
|
+ var re = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
|
|
|
+ if (re.test(a.hostname)) {
|
|
|
+ vhost = '__defaultVhost__';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // parse the schema
|
|
|
+ var schema = 'rtmp';
|
|
|
+ if (url.indexOf('://') > 0) {
|
|
|
+ schema = url.substr(0, url.indexOf('://'));
|
|
|
+ }
|
|
|
+ var port = a.port;
|
|
|
+ if (!port) {
|
|
|
+ // Finger out by webrtc url, if contains http or https port, to overwrite default 1985.
|
|
|
+ if (schema === 'webrtc' && url.indexOf(`webrtc://${a.host}:`) === 0) {
|
|
|
+ port = url.indexOf(`webrtc://${a.host}:80`) === 0 ? 80 : 1990;
|
|
|
+ }
|
|
|
+ // Guess by schema.
|
|
|
+ if (schema === 'http') {
|
|
|
+ port = 80;
|
|
|
+ } else if (schema === 'https') {
|
|
|
+ port = 1990;
|
|
|
+ } else if (schema === 'rtmp') {
|
|
|
+ port = 1935;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var ret = {
|
|
|
+ url: url,
|
|
|
+ schema: schema,
|
|
|
+ server: a.hostname,
|
|
|
+ port: port,
|
|
|
+ vhost: vhost,
|
|
|
+ app: app,
|
|
|
+ stream: stream
|
|
|
+ };
|
|
|
+ self.__internal.fill_query(a.search, ret);
|
|
|
+
|
|
|
+ if (!ret.port) {
|
|
|
+ if (schema === 'webrtc' || schema === 'rtc') {
|
|
|
+ if (ret.user_query.schema === 'https') {
|
|
|
+ ret.port = 1990;
|
|
|
+ } else if (window.location.href.indexOf('https://') === 0) {
|
|
|
+ ret.port = 1990;
|
|
|
+ } else {
|
|
|
+ // For WebRTC, SRS use 1985 as default API port.
|
|
|
+ ret.port = 1985;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+ },
|
|
|
+ fill_query: function (query_string, obj) {
|
|
|
+ // pure user query object.
|
|
|
+ obj.user_query = {};
|
|
|
+ if (query_string.length === 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // split again for angularjs.
|
|
|
+ if (query_string.indexOf('?') >= 0) {
|
|
|
+ query_string = query_string.split('?')[1];
|
|
|
+ }
|
|
|
+ var queries = query_string.split('&');
|
|
|
+ for (var i = 0; i < queries.length; i++) {
|
|
|
+ var elem = queries[i];
|
|
|
+ var query = elem.split('=');
|
|
|
+ obj[query[0]] = query[1];
|
|
|
+ obj.user_query[query[0]] = query[1];
|
|
|
+ }
|
|
|
+
|
|
|
+ // alias domain for vhost.
|
|
|
+ if (obj.domain) {
|
|
|
+ obj.vhost = obj.domain;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ self.pc = new RTCPeerConnection(null);
|
|
|
+ self.stream = new MediaStream();
|
|
|
+
|
|
|
+ // https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/ontrack
|
|
|
+ self.pc.ontrack = function (event) {
|
|
|
+ if (self.ontrack) {
|
|
|
+ self.ontrack(event);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ return self;
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style type="text/css">
|
|
|
+.el-dialog__body {
|
|
|
+ padding: 20px !important;
|
|
|
+ max-height: 99vh;
|
|
|
+}
|
|
|
+.el-form-item__label {
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.el-form-item--small.el-form-item {
|
|
|
+ margin-bottom: 12px;
|
|
|
+}
|
|
|
+.el-collapse {
|
|
|
+ border-top: 1px solid #ebeef5;
|
|
|
+ border-bottom: 0;
|
|
|
+}
|
|
|
+</style>
|
|
|
+<style lang="scss" scoped>
|
|
|
+@import '@/assets/styles/func.scss';
|
|
|
+
|
|
|
+.dashboard {
|
|
|
+ &-container {
|
|
|
+ min-height: calc(100vh - 80px);
|
|
|
+ padding: 24px;
|
|
|
+ background: #f3f6fa;
|
|
|
+ }
|
|
|
+ &-text {
|
|
|
+ font-size: 30px;
|
|
|
+ line-height: 46px;
|
|
|
+ }
|
|
|
+}
|
|
|
+.input45 {
|
|
|
+ width: 40%;
|
|
|
+ margin-right: 5px;
|
|
|
+}
|
|
|
+
|
|
|
+.column {
|
|
|
+ float: left;
|
|
|
+ width: 90%;
|
|
|
+ padding: 2px;
|
|
|
+}
|
|
|
+
|
|
|
+/* Clearfix (clear floats) */
|
|
|
+.row::after {
|
|
|
+ content: '';
|
|
|
+ clear: both;
|
|
|
+ display: table;
|
|
|
+}
|
|
|
+
|
|
|
+.container-main {
|
|
|
+ // background:#FFFFFF;
|
|
|
+ width: 99%;
|
|
|
+ padding: auto;
|
|
|
+ margin: 5px auto;
|
|
|
+ background: #fff;
|
|
|
+ height: calc(100vh - 50px - 30px);
|
|
|
+ overflow-y: scroll;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+
|
|
|
+.el-header {
|
|
|
+ // height: getvh(80);
|
|
|
+ margin-bottom: 5px;
|
|
|
+}
|
|
|
+
|
|
|
+.nav1 {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 15px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.navbar {
|
|
|
+ // padding-top: getvh(25);
|
|
|
+ overflow: hidden;
|
|
|
+ position: relative;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 4px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ box-shadow: 0px 2px 4px 0px rgb(0 92 220 / 10%);
|
|
|
+}
|
|
|
+</style>
|