123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992 |
- <template>
- <div class="class-record-container">
- <!--头部信息-->
- <div class="class-record-header">
- <span class="back-page" @click="goBack">
- <Icon type="md-arrow-round-back" />
- {{$t('cusMgt.rcd.rtn')}}
- </span>
- <span class="course-name">
- {{recordInfo.name}}
- </span>
- <div style="display:inline-block;margin-left:30px">
- <span class="label-text">
- {{$t('cusMgt.rcd.ctime')}}
- </span>
- <span class="label-value">
- {{$jsFn.timeFormat(recordInfo.startTime)}}
- </span>
- </div>
- <div class="action-wrap">
- <!-- 下载学生作品 -->
- <span v-show="taskData.length" class="e-note-tag" @click="downloadStuWork">
- <Icon type="md-download" />
- {{$t('cusMgt.rcd.dlStuWrk')}}
- </span>
- <!-- 电子笔记 -->
- <span class="e-note-tag" @click="viewENote">
- <Icon type="ios-paper" />
- {{$t('cusMgt.rcd.enote')}}
- </span>
- <!-- 表格下载 -->
- <span class="e-note-tag" @click="downloadData">
- <Icon type="md-download" />
- {{$t('cusMgt.rcd.exportData')}}
- </span>
- <!-- 数据统计 -->
- <span class="e-note-tag" v-show="hasVideo" @click="isShowVd = !isShowVd">
- <Icon :type="isShowVd ? 'md-podium' : 'logo-youtube'" />
- {{isShowVd ? $t('cusMgt.rcd.dataCount') : $t('cusMgt.rcd.videoData')}}
- </span>
- </div>
- </div>
- <Split v-model="split1">
- <div slot="left" class="rcd-split-pane">
- <!--上课内容-->
- <vuescroll>
- <!-- <div :class="isShowBar ? 'class-content mouse-over-status':'class-content mouse-over-status'" @mousemove="isShowBar = true" @mouseleave="isShowBar = false"> -->
- <div class="class-content mouse-over-status">
- <video-player2 v-if="hasVideo && playerOptions.sources.length" v-show="isShowVd" @on-vd-error="videoError" class="video-player-box" :markers="markers" ref="videoPlayer" :options="playerOptions" :playsinline="true" @getCurPage="getCurPage">
- </video-player2>
- <div v-show="!isShowVd" class="video-player-box" style="padding:15px 0px" v-if="!isGlobalSite">
- <!-- <Alert v-show="!hasVideo" class="no-video-tips" type="warning" show-icon>
- {{$t('cusMgt.rcd.noVideo')}}
- </Alert> -->
- <!-- 大陆站显示四大维度数据 -->
- <div style="width:100%;display:flex;flex-direction:column;align-items:center;justify-content:center" v-show="!isShowBase">
- <div style="display: flex;justify-content: center;font-weight: bold">
- <span style="display: flex;justify-content: center;flex-direction: column;align-items: center">
- <span :style="{ backgroundColor: getLevelColor(recordInfo.tLevel),boxShadow:'0 0 6px ' + getLevelColor(recordInfo.tLevel) }" class="level-light"></span>
- <span>{{ this.$t('lessonRecord.mgt.tLevel') }}</span>
- </span>
- <span style="display: flex;justify-content: center;flex-direction: column;align-items: center;margin-left: 40px;">
- <span :style="{ backgroundColor: getLevelColor(recordInfo.pLevel),boxShadow:'0 0 6px ' + getLevelColor(recordInfo.pLevel) }" class="level-light"></span>
- <span>{{ this.$t('lessonRecord.mgt.pLevel') }}</span>
- </span>
- </div>
- <div class="static-box">
- <div class="static-item">
- <span class="static-value">{{ recordInfo.clientInteractionAverge }}</span>
- <span class="static-label">{{ this.$t('lessonRecord.mgt.interaction') }}</span>
- </div>
- <div class="static-item">
- <span class="static-value">{{ recordInfo.hitaClientCmpCount }}</span>
- <span class="static-label">{{ this.$t('lessonRecord.mgt.cooperation') }}</span>
- </div>
- <div class="static-item">
- <span class="static-value">{{ recordInfo.examCount }}</span>
- <span class="static-label">{{ this.$t('lessonRecord.mgt.exam') }}</span>
- </div>
- <div class="static-item">
- <span class="static-value">{{ recordInfo.learningCategory.task }}</span>
- <span class="static-label">{{ this.$t('lessonRecord.mgt.task') }}</span>
- </div>
- <div class="static-item">
- <span class="static-value">{{ recordInfo.learningCategory.diffential }}</span>
- <span class="static-label">{{ this.$t('lessonRecord.mgt.diffential') }}</span>
- </div>
- </div>
- <BaseReportRadar v-if="recordInfo" :lessonInfo="recordInfo"></BaseReportRadar>
- </div>
- <DataCount :rcdInfo="baseData.report" v-if="baseData" v-show="isShowBase"></DataCount>
- <Icon type="md-swap" class="action-icon" color="#25b0c4" size="20" v-if="baseData" @click="isShowBase = !isShowBase" :title="isShowBase ? $t('lessonRecord.viewReport') : $t('lessonRecord.viewSummary')" />
- <!-- <Icon type="md-pie" class="action-icon" color="#25b0c4" size="20" @click="reportModal = true" :title="$t('lessonRecord.action1')" /> -->
- </div>
- <!-- 国际站显示统计数据 -->
- <DataCount :rcdInfo="baseData.report" v-else-if="baseData"></DataCount>
- <div class="courseware-wrap">
- <div class="custom-page-change custom-prev" @click="changePage('prev')">
- <Icon type="ios-arrow-back" />
- </div>
- <div class="custom-page-change custom-next" @click="changePage('next')">
- <Icon type="ios-arrow-forward" />
- </div>
- <img :src="curImg" alt="" class="course-cur-img">
- <div class="cus-page-wrap">
- <Page :total="pageList.length" :current.sync="curPage" :page-size="1" size="small" @on-change="getCurHTEX" />
- </div>
- </div>
- </div>
- </vuescroll>
- </div>
- <div slot="right" class="rcd-split-pane">
- <!--课堂互动记录-->
- <div class="top-wrap">
- <h2 class="content-title">
- {{$t('cusMgt.rcd.rcdLabel')}}
- </h2>
- <div style="margin-top:5px;margin-right:3px">
- <RadioGroup v-model="filterType" size="small" @on-change="handleFilter">
- <Radio v-for="item in filterInte" :key="item.value" :label="item.value" border>
- {{item.text}}
- <!-- {{item.value == 'all' ? '' : `(${item.count})`}} -->
- </Radio>
- </RadioGroup>
- </div>
- </div>
- <vuescroll ref="pagewrap">
- <div class="cus-data-wrap">
- <div class="interaction-record-wrap">
- <template v-for="(item,index) in pageListShow">
- <div v-if="item.pageData && item.pageData.length" class="page-item" :key="index" :id="'page'+(item.page)">
- <div class="page-info-wrap">
- <span class="page-tag" @click="toVideo(index+1,$event)" :ref="'page'+(index+1)">
- {{`${$t('cusMgt.rcd.cw')}${item.page}${$t('cusMgt.rcd.page')}`}}
- </span>
- <!-- 课件缩略图 -->
- <img class="page-mini-img" @click="openViewer(item.img)" :src="item.img" />
- <p class="class-time">
- <!-- <Icon size="16" type="md-time" /> -->
- <span class="class-time-value">{{item.time}}</span>
- </p>
- <!-- <Timeline style="margin-top:10px;margin-left:-5px">
- <TimelineItem v-for="(rtItem, rtIndex) in item.pageData" :key="rtIndex +''+index">
- <Icon type="md-arrow-dropright" slot="dot" />
- <p class="event-tag" @click="toEvent(rtItem)">{{rtItem.eventName}}</p>
- </TimelineItem>
- </Timeline> -->
- </div>
- <div class="record-data-wrap">
- <!-- 互动数据 -->
- <div v-for="event in item.pageData" :key="event.Time">
- <!-- 即问即答 -->
- <PopQues class="event-item" v-if="event.Event === 'PopQuesLoad' || event.Event === 'ReAtmpAnsStrt'" :evtType="event.Event" :irsData="event.data" :students="baseData.student" :recordInfo="recordInfo" :blobInfo="blobInfo"></PopQues>
- <!-- 抢权 -->
- <Buzr class="event-item student-event" v-else-if="event.Event === 'BuzrAns'" :buzrData="event.data" :students="baseData.student"></Buzr>
- <!-- 推送 -->
- <Push class="event-item" v-else-if="event.Event === 'FastPgPush'" :pushData="event.data"></Push>
- <!-- 作品收集 -->
- <Receive :recordInfo="recordInfo" class="student-event event-item" v-else-if="event.Event === 'WrkSpaceLoad'" :rcvData="event.data" :students="baseData.student" :blobInfo="blobInfo"></Receive>
- <!-- 作品回帖 -->
- <WrkCmp :recordInfo="recordInfo" class="student-event event-item" v-else-if="event.Event === 'WrkCmp'" :cmpData="event.data" :students="baseData.student" :blobInfo="blobInfo"></WrkCmp>
- <!-- 随机挑人 -->
- <Pick class="event-item student-event" :pickData="event.data" v-else-if="event.Event === 'PickupResult'" :students="baseData.student"></Pick>
- <!-- 课中评测 -->
- <Exam class="event-item" :examInfo="event.data" :recordInfo="recordInfo" v-else-if="event.Event === 'SPQStrt'"></Exam>
- <!-- 智慧评分 -->
- <SmartRating class="event-item student-event" :recordInfo="recordInfo" :smartRate="event.data" :students="baseData.student" :vote="event.vote" :blobInfo="blobInfo" v-else-if="event.Event === 'RatingStart'"></SmartRating>
- <!-- 协作 -->
- <Cowork class="event-item student-event" :recordInfo="recordInfo" :blobInfo="blobInfo" :cowork="event.data" :students="baseData.student" v-else-if="event.Event === 'CoworkLoad'"></Cowork>
- </div>
- </div>
- </div>
- </template>
- </div>
- </div>
- </vuescroll>
- </div>
- </Split>
- <div v-if="openImageViewer" class="image-viewer" @click="closeViewer()">
- <Icon type="md-close" class="close-icon" @click="closeViewer()" />
- <img :src="viewUrl" class="animated fadeIn" @click.stop />
- </div>
- <!--返回顶部-->
- <BackToTop @on-to-top="handleToTop"></BackToTop>
- <!-- 课堂报告弹窗 -->
- <!-- <Modal v-model="reportModal" transfer width="860" footer-hide class="record-research-modal">
- <div slot="header">
- <p style="text-align: center;font-weight: bold">【{{ recordInfo.name }}】 智慧课堂报告</p>
- </div>
- <div>
- <div style="display: flex;justify-content: center;font-weight: bold">
- <span style="display: flex;justify-content: center;flex-direction: column;align-items: center">
- <span :style="{ backgroundColor: getLevelColor(recordInfo.tLevel),boxShadow:'0 0 6px ' + getLevelColor(recordInfo.tLevel) }" class="level-light"></span>
- <span>技术应用</span>
- </span>
- <span style="display: flex;justify-content: center;flex-direction: column;align-items: center;margin-left: 40px;">
- <span :style="{ backgroundColor: getLevelColor(recordInfo.pLevel),boxShadow:'0 0 6px ' + getLevelColor(recordInfo.pLevel) }" class="level-light"></span>
- <span>教法应用</span>
- </span>
- </div>
- <div class="static-box">
- <div class="static-item">
- <span class="static-value">{{ recordInfo.attendCount }}</span>
- <span class="static-label">出席人数</span>
- </div>
- <div class="split-line"></div>
- <div class="static-item">
- <span class="static-value">{{ recordInfo.groupCount }}</span>
- <span class="static-label">小组数</span>
- </div>
- <div class="split-line"></div>
- <div class="static-item">
- <span class="static-value">{{ recordInfo.collateTaskCount }}</span>
- <span class="static-label">任务总数</span>
- </div>
- <div class="split-line"></div>
- <div class="static-item">
- <span class="static-value">{{ recordInfo.collateCount }}</span>
- <span class="static-label">作品总数</span>
- </div>
- <div class="split-line"></div>
- <div class="static-item">
- <span class="static-value">{{ recordInfo.pushCount }}</span>
- <span class="static-label">推送资源数</span>
- </div>
- <div class="static-item">
- <span class="static-value">{{ recordInfo.totalPoint }}</span>
- <span class="static-label">总计分</span>
- </div>
- <div class="split-line"></div>
- <div class="static-item">
- <span class="static-value">{{ recordInfo.examCount }}</span>
- <span class="static-label">测验总数</span>
- </div>
- <div class="split-line"></div>
- <div class="static-item">
- <span class="static-value">{{ recordInfo.interactionCount }}</span>
- <span class="static-label">互动题数</span>
- </div>
- <div class="split-line"></div>
- <div class="static-item">
- <span class="static-value">{{ recordInfo.examPointRate }}%</span>
- <span class="static-label">测验得分率</span>
- </div>
- <div class="split-line"></div>
- <div class="static-item">
- <span class="static-value">{{ recordInfo.clientInteractionCount }}</span>
- <span class="static-label">学生互动总数</span>
- </div>
- </div>
- <BaseReportPie v-if="reportModal" :lessonInfo="recordInfo"></BaseReportPie>
- </div>
- </Modal> -->
- </div>
- </template>
- <script>
- import BaseReportPie from '@/view/research-center/BaseReportPie.vue'
- import BaseReportRadar from '@/view/research-center/BaseReportRadar.vue'
- import WrkCmp from './eventchart/WrkCmp.vue'
- import PopQues from './eventchart/PopQues.vue'
- import Buzr from './eventchart/Buzr.vue'
- import Pick from './eventchart/Pick.vue'
- import Push from './eventchart/Push.vue'
- import Exam from './eventchart/Exam.vue'
- import Receive from './eventchart/Receive.vue'
- import DataCount from './eventchart/DataCount.vue'
- import SmartRating from './eventchart/SmartRating.vue';
- import Cowork from './eventchart/Cowork.vue';
- import CountTo from 'vue-count-to'
- import BlobTool from '@/utils/blobTool.js'
- import FileSaver from "file-saver";
- import JSZip from "jszip";
- export default {
- components: {
- PopQues, Pick, Push, Receive, DataCount, CountTo, Buzr, Exam, WrkCmp, BaseReportPie, BaseReportRadar, SmartRating, Cowork
- },
- data() {
- return {
- filterType: 'all',
- reportModal: false,
- filterInte: [
- {
- value: 'all',
- text: this.$t('cusMgt.rcd.filter1'),
- },
- {
- value: 'Push',
- text: this.$t('cusMgt.rcd.filter2'),
- events: ['FastPgPush'],
- count: 0
- },
- {
- value: 'Task',
- text: this.$t('cusMgt.rcd.filter3'),
- events: ['WrkSpaceLoad', 'WrkCmp'],
- count: 0
- },
- {
- value: 'Interactive',
- text: this.$t('cusMgt.rcd.filter4'),
- events: ['PopQuesLoad', 'ReAtmpAnsStrt', 'BuzrLoad', 'BuzrAns'],
- count: 0
- },
- {
- value: 'SPQStrt',
- text: this.$t('cusMgt.rcd.filter5'),
- events: ['SPQStrt'],
- count: 0
- },
- {
- value: 'SmartRating',
- text: this.$t('cusMgt.rcd.filter6'),
- events: ['RatingStart'],
- count: 0
- },
- {
- value: 'CoworkLoad',
- text: this.$t('cusMgt.rcd.filter7'),
- events: ['CoworkLoad'],
- count: 0
- },
- ],
- split1: 0.4,
- backPage: undefined,
- baseData: {}, //base.json
- pushData: [],//push.json
- irsData: [],//irs.json
- taskData: [],//task.json
- smartData: [],//smartRating.json
- coworkData: [],//Cowork.json
- fnEvents: [],//功能事件
- events: [],//事件ID
- hiTeachEvent: [],//需要解析的事件信息
- isShowVd: true,
- isShowBase: false,
- hasVideo: true,
- eventClick: false,
- sokratesRecords: [],
- pageIds: [],
- pageEvents: [],
- pageList: [],
- pageListShow: [],
- videoUrl: '',
- videoPoster: '',
- recordInfo: {},
- isShowBar: false,
- markers: [],
- curPage: 1,
- viewUrl: '',
- openImageViewer: false,
- typeIndex: 'all',
- playerOptions: {
- height: "450px",
- controlBar: {
- durationDisplay: true, // 总时间
- currentTimeDisplay: true,
- },
- html5: {
- nativeControlsForTouch: true,
- },
- inactivityTimeout: 1,
- nativeVideoTracks: false,
- playbackRates: [0.7, 1.0, 1.5, 2.0], //播放速度
- autoplay: true, //如果true,浏览器准备好时开始回放。
- controls: true, //控制条
- preload: 'auto', //视频预加载
- muted: false, //默认情况下将会消除任何音频。
- loop: false, //导致视频一结束就重新开始。
- language: 'zh-CN',
- //aspectRatio: '16:9', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
- //fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
- sources: [],
- poster: '',
- // notSupportedMessage: '此视频暂无法播放,请稍后再试' //允许覆盖Video.js无法播放媒体源时显示的默认信息。
- },
- blobInfo: undefined,
- }
- },
- methods: {
- // 自定义换页功能
- changePage(type) {
- if (type == 'prev') {
- if (this.curPage > 1) this.curPage--
- } else if (type == 'next') {
- if (this.curPage < this.pageList.length) this.curPage++
- }
- },
- // 下载学生作品
- async downloadStuWork() {
- // 需要优化原始目录结构
- // const containerClient = BlobTool.CreateBlobTool(this.recordInfo.scope)
- // containerClient.downloadFolder(`records/${this.recordInfo.id}/Clients`, {
- // fileName: this.$t('cusMgt.rcd.stuWrk'),
- // exclude: 'taskList_localstorage'
- // })
- const containerClient = BlobTool.CreateBlobTool(this.recordInfo.scope)
- const zip = new JSZip()
- for (const task of this.taskData) {
- if (task.clientWorks && task.clientWorks.length) {
- for (const student of task.clientWorks) {
- if (student.blobFiles && student.blobFiles.length) {
- for (const file of student.blobFiles) {
- let blobPath = `records/${this.recordInfo.id}${file}`
- let blobClient = containerClient.containerClient.getBlockBlobClient(blobPath)
- const dwRes = await blobClient.download()
- const blobRes = await dwRes.blobBody
- const filePath = `${task.jobName}/${student.seatID}${file.substring(file.lastIndexOf("/") + 1)}`
- zip.file(filePath, blobRes, {
- binary: true
- }) // 逐个添加文件
- }
- }
- }
- }
- }
- zip.generateAsync({
- type: "blob"
- }).then(content => {
- // 生成二进制流
- FileSaver.saveAs(content, this.$t('cusMgt.rcd.stuWrk') + ".zip"); // 利用file-saver保存文件
- }).catch(err => {
- console.log(err);
- })
- },
- //下载统计表格
- downloadData() {
- // let blobInfo = this.recordInfo.scope === 'school' ? this.$store.state.user.schoolProfile : this.$store.state.user.userProfile
- let url = `${this.blobInfo.blob_uri}/records/${this.recordInfo.id}/IES/summary.xlsx${this.blobInfo.blob_sas}`
- const downloadRes = async () => {
- let response = await fetch(url); // 内容转变成blob地址
- let blob = await response.blob(); // 创建隐藏的可下载链接
- let objectUrl = window.URL.createObjectURL(blob);
- let a = document.createElement('a');
- a.href = objectUrl;
- a.download = this.recordInfo.name + '.xlsx';
- a.click()
- a.remove();
- }
- downloadRes();
- },
- videoError() {
- this.hasVideo = false
- this.isShowVd = false
- },
- //返回顶部
- handleToTop() {
- this.$refs['pagewrap'].scrollTo(
- {
- y: '0'
- },
- 300
- )
- // this.$refs['datawrap'].scrollTo(
- // {
- // y: '0'
- // },
- // 300
- // )
- },
- //跳转到对应事件
- toEvent(event) {
- console.log(event)
- this.eventClick = true
- this.curPage = event.pageIndex + 1
- this.$refs.videoPlayer.player.currentTime(event.Time)
- },
- /**
- * 处理TimeLine的异常
- * 页面重复的IRS作答
- */
- fixEventData() {
- this.pageEvents = this.pageEvents.filter((item, index) => {
- if (item.Event == 'PopQuesLoad') {
- let firstIndex = this.pageEvents.findIndex(i => i.Pgid == item.Pgid && item.Event == i.Event)
- return firstIndex == index
- } else {
- return true
- }
- })
- },
- //小于10 补0
- fullZero(n) {
- return n < 10 ? `0${n}` : `${n}`
- },
- formatTime(time) {
- let h = Math.floor(time / (60 * 60))
- time = time % (60 * 60)
- let m = Math.floor(time / 60)
- let s = Math.floor(time % 60)
- return `${this.fullZero(h)}:${this.fullZero(m)}:${this.fullZero(s)}`
- },
- //根据SokratesRecords.json处理page数据
- async getPageList() {
- this.pageList = []
- this.markers = []
- // let blobInfo = this.recordInfo.scope == 'school' ? this.$store.state.user.schoolProfile : this.$store.state.user.userProfile
- // 这里需要兼容原来没有TimeLine.json的课例(优先度读timeLine.json,没有则读SokratesRecords.json)
- let url = `${this.blobInfo.blob_uri}/records/${this.recordInfo.id}/IES/TimeLine.json${this.blobInfo.blob_sas}`
- let hasTimeLine = true
- let dataErr = false
- try {
- let res = await this.$tools.getFile(url)
- this.sokratesRecords = JSON.parse(res)
- this.pageIds = this.sokratesRecords.PgIdList || []
- this.pageEvents = this.sokratesRecords.events || []
- this.fixEventData()
- } catch (e) {
- hasTimeLine = false
- }
- //读取 timeLine.json 失败,则读取 SokratesRecords.json
- if (!hasTimeLine) {
- url = `${this.blobInfo.blob_uri}/records/${this.recordInfo.id}/Sokrates/SokratesRecords.json${this.blobInfo.blob_sas}`
- try {
- let res = await this.$tools.getFile(url)
- let resJson = JSON.parse(res)
- // 处理成timeLine数据格式
- let pageidEvent = resJson.find(item => item.Event == 'PgidList')
- this.pageIds = pageidEvent && pageidEvent.PgIdList ? pageidEvent.PgIdList : []
- this.pageEvents = resJson.filter(item => this.events.includes(item.Event))
- this.fixEventData()
- this.sokratesRecords = {
- events: this.pageEvents,
- PgIdList: this.pageIds
- }
- } catch (e) {
- //timeLine 和 SokratesRecords都没有找到
- dataErr = true
- }
- }
- // 数据异常
- if (dataErr) {
- this.$Message.error(this.$t('cusMgt.rcd.dataErr'))
- return
- }
- // 时间轴数据正常
- //获取Push.json、IRS.json、Task.json、Base.json数据 新增SmartRating.json(智慧评分) 新增Cowork.json(协作)
- try {
- let pushUrl = `${this.blobInfo.blob_uri}/records/${this.recordInfo.id}/IES/Push.json${this.blobInfo.blob_sas}`
- this.pushData = JSON.parse(await this.$tools.getFile(pushUrl) || '[]')
- this.pushData.map(item => {
- // 暂无法根据 type 区分物件化推送和图片推送,先判断是否有 .jpg 后缀
- if(item.pageMeta.indexOf('.jpg') != -1) {
- item.pageUrl = `${this.blobInfo.blob_uri}/records/${this.recordInfo.id}${item.pageMeta}${this.blobInfo.blob_sas}`
- } else {
- item.pageUrl = `${this.blobInfo.blob_uri}/records/${this.recordInfo.id}${item.pageMeta}/bg_snapshot_00001.jpg${this.blobInfo.blob_sas}`
- }
- })
- } catch (e) {
- this.pushData = []
- }
- try {
- let irsUrl = `${this.blobInfo.blob_uri}/records/${this.recordInfo.id}/IES/IRS.json${this.blobInfo.blob_sas}`
- this.irsData = JSON.parse(await this.$tools.getFile(irsUrl) || '[]')
- } catch (e) {
- this.irsData = []
- }
- try {
- let taskUrl = `${this.blobInfo.blob_uri}/records/${this.recordInfo.id}/IES/Task.json${this.blobInfo.blob_sas}`
- this.taskData = JSON.parse(await this.$tools.getFile(taskUrl) || '[]')
- } catch (e) {
- this.taskData = []
- }
- try {
- let baseUrl = `${this.blobInfo.blob_uri}/records/${this.recordInfo.id}/IES/base.json${this.blobInfo.blob_sas}`
- this.baseData = JSON.parse(await this.$tools.getFile(baseUrl) || '{}')
- } catch (e) {
- this.baseUrl = {}
- }
- try {
- let smartUrl = `${this.blobInfo.blob_uri}/records/${this.recordInfo.id}/IES/SmartRating.json${this.blobInfo.blob_sas}`
- this.smartData = JSON.parse(await this.$tools.getFile(smartUrl) || '[]')
- } catch (e) {
- this.smartData = []
- }
- try {
- let coworkUrl = `${this.blobInfo.blob_uri}/records/${this.recordInfo.id}/IES/Cowork.json${this.blobInfo.blob_sas}`
- this.coworkData = JSON.parse(await this.$tools.getFile(coworkUrl) || '[]')
- } catch (e) {
- this.coworkData = []
- }
- let pgids = this.pageIds
- //这里需要判断录制开始的pageid
- // let startInfo = this.pageEvents?.findLast(item => item.Event === 'EzsStartRecord')
- let startInfo = this._.findLast(this.pageEvents, item => item.Event === 'EzsStartRecord') //排查兼容性问题
- let startId = startInfo ? startInfo.Pgid : ''
- let startIndex = 0
- if (startId) {
- startIndex = pgids.findIndex(item => item === startId)
- //第一页视频标记
- this.markers.push({
- time: startInfo.Time,
- text: `${this.$t('cusMgt.rcd.di')}${1}${this.$t('cusMgt.rcd.page')}`,
- page: 1
- })
- }
- if (startIndex > -1) {
- pgids = pgids.slice(startIndex)
- }
- pgids.forEach((item, index) => {
- let page = {}
- page.id = item
- page.img = `${this.blobInfo.blob_uri}/records/${this.recordInfo.id}/Memo/${item}.jpg${this.blobInfo.blob_sas}`
- page.page = index + 1
- //当前页面对应的功能事件
- page.pageData = this.pageEvents.filter(record => record.Pgid === item && this.fnEvents.includes(record.Event))
- page.time = this.formatTime(page.pageData[0]?.Time)
- page.pageData.forEach(e => {
- e.pageIndex = index
- e.eventName = this.hiTeachEvent[e.Event]?.text
- let rlt = this.hiTeachEvent[e.Event]?.relation
- e.relation = rlt
- switch (rlt) {
- case 'irs':
- e.data = this.irsData.find(i => i.pageID == e.Pgid)
- this.filterInte[3].count++
- break
- case 'push':
- e.data = this.pushData.find(p => p.pageId == e.Pgid || p.pageID == e.Pgid) //数据兼容 pageId 有些大写有些小写
- this.filterInte[1].count++
- break
- case 'task':
- e.data = this.taskData.find(t => t.pageID == e.Pgid)
- this.filterInte[2].count++
- break
- case 'timeline':
- e.data = this._.cloneDeep(e)
- this.filterInte[3].count++
- break
- case 'exam':
- e.data = this._.cloneDeep(e)
- this.filterInte[4].count++
- break
- case 'smart':
- e.data = this.smartData.find(t => t.pageID == e.Pgid)
- e.data.smartRateSummary.rateInfo = {
- RatingSource: e.RatingSource,// 互评的作品类型 IRS:文字题 StudentWork:图片
- AnonyCandi: e.AnonyCandi,// 评论是否匿名
- }
- // 按照轮数返回的
- e.vote = undefined
- if(e.RatingType === 'Voting') {
- e.vote = {
- round: e.Round,
- votes: e.Votes
- }
- }
- this.filterInte[5].count++
- break
- case 'cowork':
- e.data = this.coworkData.find(t => t.pageID == e.Pgid)
- this.filterInte[6].count++
- break
- default:
- break
- }
- })
- for (let i = 1; i < page.pageData.length; i++) {
- // 星光大评分会操作几次就返回几条数据,所以需要去重只显示第一条
- if(page.pageData[i - 1].Event === 'RatingStart' && page.pageData[i].Event === 'RatingStart' && page.pageData[i].RatingType && page.pageData[i].RatingType === 'GrandRating' && page.pageData[i - 1].Pgid === page.pageData[i].Pgid) {
- page.pageData.splice(i, 1)
- i--
- }
- }
- this.pageList.push(page)
- })
- console.log(this.pageList)
- this.pageListShow = this.pageList
- console.log('互动数据', this.pageList)
- this.pageList.forEach((pageInfo, pageIndex) => {
- pageInfo.pageData.forEach(e => {
- if (e.Event == 'WrkCmp') {
- console.log(pageIndex, e)
- }
- })
- })
- let pageEvent = this.pageEvents.filter(item => item.Event === 'PgJump' || item.Event === 'PgAdd' || item.Event === 'DiscussStart')
- let page = this.markers.length
- pageEvent.forEach((item, index) => {
- if (item.JumpTo != item.JumpFrom) {
- this.markers.push({
- time: item.Time,
- text: `${this.$t('cusMgt.rcd.di')}${item.JumpTo}${this.$t('cusMgt.rcd.page')}`,
- page: item.JumpTo
- })
- }
- })
- console.log(this.markers)
- },
- //查看苏格拉底报告
- viewReport() {
- this.$router.push({
- name: 'teachCenter',
- query: { id: this.recordInfo.id, name: this.recordInfo.name }
- })
- },
- //查看电子笔记
- viewENote() {
- let eNote
- if (this.recordInfo.eNote) {
- eNote = this.recordInfo.eNote
- } else {
- let sasInfo = {}
- // let blobInfo = this.recordInfo.scope === 'school' ? this.$store.state.user.schoolProfile : this.$store.state.user.userProfile
- sasInfo.sas = this.blobInfo.blob_sas
- sasInfo.name = this.recordInfo.scope === 'school' ? this.$store.state.userInfo.schoolCode : this.$store.state.userInfo.TEAMModelId
- sasInfo.url = this.blobInfo.blob_uri.slice(0, this.blobInfo.blob_uri.lastIndexOf(sasInfo.name) - 1)
- eNote = `${sasInfo.url}/${sasInfo.name}/records/${this.recordInfo.id}/Note.pdf${sasInfo.sas}`
- }
- window.open('/web/viewer.html?file=' + encodeURIComponent(eNote))
- // if (this.recordInfo.eNote) {
- // } else {
- // this.$Message.warning(this.$t('cusMgt.rcd.noNote'))
- // }
- },
- //点击视频切片
- getCurPage(page) {
- // this.$refs["datawrap"].scrollIntoView('#page' + page, 500)
- this.$refs.videoPlayer.player.play()
- this.curPage = page
- },
- //点击课件page
- getCurHTEX(page) {
- if (this.eventClick) {
- this.eventClick = false
- return
- }
- this.$refs["pagewrap"].scrollIntoView('#page' + page, 500)
- // //视频时间定位
- // let pageInfo = this.markers.find(item => {
- // return item.page == page
- // })
- // if (pageInfo) {
- // this.$refs.videoPlayer.player.currentTime(pageInfo.time)
- // this.$refs.videoPlayer.player.play()
- // } else {
- // this.$refs["pagewrap"].scrollIntoView('#page' + page, 500)
- // }
- },
- //点击互动记录页面tag
- toVideo(page, e) {
- //页面滚动
- // let dataLoacation = this.$refs["datawrap"].getPosition()
- // let pageLocaltion = this.$refs["pagewrap"].getPosition()
- // let y = e.pageY - 665 + pageLocaltion.scrollTop + dataLoacation.scrollTop
- this.$nextTick(() => {
- // this.$refs["pagewrap"].scrollTo(
- // {
- // x: 0,
- // y: 0
- // }
- // )
- // this.$refs["datawrap"].scrollTo(
- // {
- // x: 0,
- // y: y
- // }
- // )
- })
- // 教材页面切换
- this.curPage = page
- //视频时间定位
- let pageInfo = this.markers.find(item => {
- return item.page == page
- })
- if (pageInfo) this.$refs.videoPlayer.player.currentTime(pageInfo.time)
- },
- //互动类型筛选
- handleFilter() {
- if (this.filterType == 'all') {
- this.pageListShow = this.pageList
- } else {
- let data = this._.cloneDeep(this.pageList)
- let filterInfo = this.filterInte.find(item => item.value === this.filterType)
- this.pageListShow = data.map(item => {
- if (item.pageData.length) {
- item.pageData = item.pageData.filter(event => {
- //if (this.filterType == 'Other') {
- // return !events.includes(event.Event)
- //} else {
- // return event.Event == this.filterType
- //}
- return filterInfo.events?.includes(event.Event)
- })
- }
- return item
- })
- }
- },
- //查看图片
- openViewer(url) {
- this.openImageViewer = true
- this.viewUrl = url
- },
- closeViewer() {
- this.openImageViewer = false
- },
- goBack() {
- if (this.backPage) {
- this.$router.push({
- name: this.backPage,
- record: this.recordInfo
- })
- } else {
- this.$router.go(-1)
- }
- },
- },
- computed: {
- isGlobalSite() {
- return this.$store.state.config.srvAdr !== 'China'
- },
- curImg() {
- console.log(this.curPage)
- if (this.pageList[this.curPage - 1]) {
- return this.pageList[this.curPage - 1].img
- } else {
- return ""
- }
- },
- getLevelColor() {
- return level => {
- if (level < 0) {
- return '#888999'
- } else {
- return ['#ff2d2d', '#ffc018', '#00b214'][level]
- }
- }
- }
- },
- async created() {
- this.hiTeachEvent = this.$GLOBAL.HI_TEACH_EVENT()
- //正式站先暂时不放出课中评测
- // if (this.$store.state.config.srvAdrType == 'product') {
- // this.$delete(this.hiTeachEvent, 'SPQStrt')
- // }
- this.events = Object.keys(this.hiTeachEvent)
- this.fnEvents = this.events.filter(key => this.hiTeachEvent[key].type === 'fn')
- console.log(this.events, this.fnEvents)
- this.recordInfo = this.$route.params.record || (sessionStorage.getItem('record') ? JSON.parse(sessionStorage.getItem('record')) : undefined)
- console.log(this.recordInfo)
- if (!this.recordInfo) {
- this.$router.go(-1)
- } else {
- sessionStorage.setItem('record', JSON.stringify(this.recordInfo))
- //对接Blob数据
- let blobInfos = this.recordInfo.scope == 'school' ? this.$store.state.user.schoolProfile : {...this.$store.state.user.userProfile}
- if(this.recordInfo.tmdid != this.$store.state.userInfo.TEAMModelId && this.recordInfo.scope != 'school') {
- // 其他老师创建的课堂记录
- let prvblobInfos = await this.$evTools.getBlobPrivateSasObj(this.recordInfo.tmdid)
- this.blobInfo = {
- blob_uri: prvblobInfos.url + '/' + prvblobInfos.name,
- blob_sas: prvblobInfos.sas
- }
- } else {
- this.blobInfo = {
- blob_uri: blobInfos.blob_uri,
- blob_sas: '?' + blobInfos.blob_sas
- }
- }
- console.error(this.blobInfo);
- this.videoUrl = `${this.blobInfo.blob_uri}/records/${this.recordInfo.id}/Record/CourseRecord.mp4${this.blobInfo.blob_sas}`
- this.videoPoster = `${this.blobInfo.blob_uri}/records/${this.recordInfo.id}/Record/CoverImage.jpg${this.blobInfo.blob_sas}`
- this.playerOptions.poster = this.videoPoster
- this.playerOptions.sources.push({
- src: this.videoUrl,
- type: 'video/mp4'
- })
- this.getPageList()
- }
- },
- beforeRouteEnter(to, from, next) {
- next(vm => {
- if (from.name == 'homePage') {
- vm.backPage = 'course'
- }
- console.log(arguments)
- })
- },
- watch: {
- blobInfo: {
- handler(n, o) {
- console.log(n);
- },
- deep: true,
- }
- }
- }
- </script>
- <style lang="less" scoped>
- @import "./ClassRecord.less";
- </style>
- <style lang="less">
- .courseware-wrap {
- .ivu-page-next,
- .ivu-page-prev {
- display: none;
- }
- }
- .video-player-box {
- .level-light {
- display: inline-block;
- width: 25px;
- height: 25px;
- border-radius: 50px;
- margin: 10px 0;
- }
- .reportPie {
- height: 320px;
- }
- .static-box {
- display: flex;
- justify-content: center;
- background-color: #ffffff;
- width: 80%;
- margin: 20px 0;
- .split-line {
- width: 2px;
- height: 30px;
- margin: 0 20px;
- margin-top: 35px;
- background-color: rgb(238, 238, 238);
- }
- .static-item {
- position: relative;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- width: 45%;
- &:first-child {
- padding-left: 10px;
- }
- .static-value {
- font-size: 30px;
- font-weight: bold;
- color: #00b4eb;
- }
- }
- }
- }
- .top-wrap .ivu-radio-wrapper-checked {
- color: white;
- background: #2d8cf0;
- }
- .top-wrap .ivu-radio {
- display: none;
- }
- .class-content .vjs-progress-holder {
- font-size: 10px !important;
- }
- .mouse-over-status .vjs-control-bar {
- opacity: 1 !important;
- }
- .class-content .video-js .vjs-big-play-button {
- top: 50%;
- left: 50%;
- margin-left: -40px;
- margin-top: -20px;
- }
- .class-content .vjs_video_3-dimensions.vjs-fluid {
- padding-top: 0;
- }
- .class-content .video-js.vjs-fluid,
- .class-content .video-js.vjs-16-9,
- .class-content .video-js.vjs-4-3 {
- height: 450px;
- }
- .video-player-box .vjs-volume-panel {
- display: none;
- }
- .video-player-box .ivu-alert {
- border-radius: 0px;
- }
- </style>
|