Commit a4867188 authored by 罗超's avatar 罗超

教室管理

parent 9de1fefc
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
"cos-js-sdk-v5": "^1.1.5", "cos-js-sdk-v5": "^1.1.5",
"echarts": "^5.1.2", "echarts": "^5.1.2",
"element-ui": "^2.14.1", "element-ui": "^2.14.1",
"flv.js": "^1.6.2",
"html2canvas": "^1.3.2", "html2canvas": "^1.3.2",
"js-md5": "^0.7.3", "js-md5": "^0.7.3",
"jsencrypt": "^3.2.1", "jsencrypt": "^3.2.1",
...@@ -36,6 +37,8 @@ ...@@ -36,6 +37,8 @@
"quasar": "^1.0.0", "quasar": "^1.0.0",
"relation-graph": "^1.0.8", "relation-graph": "^1.0.8",
"v-viewer": "^1.5.1", "v-viewer": "^1.5.1",
"videojs-flash": "^2.2.1",
"videojs-swf": "^5.4.2",
"vue-amap": "^0.5.10", "vue-amap": "^0.5.10",
"vue-apexcharts": "^1.6.2", "vue-apexcharts": "^1.6.2",
"vue-draggable-resizable": "^1.7.2", "vue-draggable-resizable": "^1.7.2",
......
...@@ -51,11 +51,14 @@ module.exports = function (ctx) { ...@@ -51,11 +51,14 @@ module.exports = function (ctx) {
// API: 'http://192.168.10.46:8300/api', // API: 'http://192.168.10.46:8300/api',
// API: 'https://eduapi.oytour.com/api', // API: 'https://eduapi.oytour.com/api',
API_ZC: 'http://192.168.10.17:8087/api', API_ZC: 'http://192.168.10.17:8087/api',
API_SK: 'ws:192.168.10.214:' API_SK: 'ws:192.168.10.214:',
API_SIG: 'http://localhost:5001/messagecenter'
} : { } : {
API: 'https://eduapi.oytour.com/api', API: 'https://eduapi.oytour.com/api',
API_ZC: 'http://propertyedu.oytour.com/api', API_ZC: 'http://propertyedu.oytour.com/api',
API_SK: 'ws://47.96.23.199:' API_SK: 'ws://47.96.23.199:',
API_SK_WSS: 'wss://sk.kookaku.com',
API_SIG: 'http://eduapi.oytour.com/messagecenter'
}, },
// transpile: false, // transpile: false,
...@@ -75,12 +78,11 @@ module.exports = function (ctx) { ...@@ -75,12 +78,11 @@ module.exports = function (ctx) {
// https://quasar.dev/quasar-cli/handling-webpack // https://quasar.dev/quasar-cli/handling-webpack
extendWebpack(cfg) { extendWebpack(cfg) {
// cfg.module.rules.push({ cfg.module.rules.push({
// enforce: 'pre', enforce: 'pre',
// test: /\.(js|vue)$/, test: /\.swf$/,
// loader: 'eslint-loader', loader: 'url-loader'
// exclude: /node_modules/ })
// })
} }
}, },
...@@ -252,7 +254,7 @@ module.exports = function (ctx) { ...@@ -252,7 +254,7 @@ module.exports = function (ctx) {
// More info: https://quasar.dev/quasar-cli/developing-electron-apps/node-integration // More info: https://quasar.dev/quasar-cli/developing-electron-apps/node-integration
nodeIntegration: true, nodeIntegration: true,
extendWebpack( /* cfg */ ) { extendWebpack( /* cfg */) {
// do something with Electron main process Webpack cfg // do something with Electron main process Webpack cfg
// chainWebpack also available besides this extendWebpack // chainWebpack also available besides this extendWebpack
} }
......
...@@ -25,7 +25,7 @@ export default { ...@@ -25,7 +25,7 @@ export default {
</script> </script>
<style> <style>
@import url("//at.alicdn.com/t/font_2077629_0n6sqaodu4f.css"); @import url("//at.alicdn.com/t/font_2077629_s183916p0bb.css");
@font-face { @font-face {
font-family: "din"; font-family: "din";
src: url("./assets/font/DIN-Bold.otf") format("opentype"); src: url("./assets/font/DIN-Bold.otf") format("opentype");
......
...@@ -2,7 +2,12 @@ ...@@ -2,7 +2,12 @@
font-family: 'perfectFont'; font-family: 'perfectFont';
src: url('../font/MicrosoftYaHeiLight.woff') format('woff'); src: url('../font/MicrosoftYaHeiLight.woff') format('woff');
} }
@font-face { @font-face {
font-family: 'pingfang'; font-family: 'pingfang';
src: url('../font/PingFang2.ttf'); src: url('../font/PingFang2.ttf');
} }
.perfectFont {
font-family: 'perfectFont' !important;
}
...@@ -389,7 +389,7 @@ export default { ...@@ -389,7 +389,7 @@ export default {
that.injectTCCC( that.injectTCCC(
r.Data.Token, r.Data.Token,
1400617921, 1400617921,
this.userInfo.Email, that.userInfo.Email,
r.Data.SdkURL r.Data.SdkURL
); );
} }
......
<template> <template>
<div class="page-body room-list" v-loading="loading"> <div class="page-body room-list" v-loading="loading">
<div v-for="item in classdata" :key="item.Key" class="school-item"> <div v-for="(item, i) in classdata" :key="item.Key">
<div class="school-name">{{item.SchoolName}}</div> <template
<div class="classroom-box"> v-if="
<div v-for="(_item,_index) in item.RoomList" :key="item.RoomId" > item.SchoolName.indexOf('武侯') == -1 &&
<div class="classroom-item q-mr-lg q-mb-lg" :class="{'classroom-item-noUse':_item.UserRate==0}" > item.SchoolName.indexOf('眉山') == -1
"
<div @click="goUrl(item,_item)"> >
<div class="divCalssRoom"> <el-image class="classroom-img" :src="_item.RoomPicList[0]" fit="cover" > <div class="row items-center">
<div slot="error" class="image-slot"> <div class="text-h6 col">{{ item.SchoolName }}</div>
<img src="../../assets/images/classroom/bg-img.jpg" alt="" srcset="" style=" opacity: 0.8;"> <div v-if="i == 0" class="f12">只看在线:</div>
<div v-if="i == 0">
<el-switch
v-model="queryStatus"
@change="changeViewStatusHandler"
></el-switch>
</div> </div>
</el-image></div>
</div> </div>
<div class="q-mt-md q-mb-lg row">
<template v-for="(x, xi) in item.RoomList">
<div class="classroom-name" >{{_item.RoomName}} <div
<!-- <img src="../../assets/images/classroom/warning.png" class="q-ml-sm" v-if="_item.warn"> class="class-room"
<img src="../../assets/images/classroom/normal.png" class="q-ml-sm" v-if="!_item.warn"> --> style="width:calc(20% - 10px);margin-right:10px;margin-bottom:10px;"
</div> v-if="queryStatus == 0 || (queryStatus == 1 && x.StatusInfo)"
<q-knob :key="xi"
show-value >
font-size="0.1rem" <div class="img-box">
v-model="_item.user" <q-img
size="50px" :src="x.RoomPicList[0]"
:thickness="0.1" height="100%"
color="primary" fit="fill"
track-color="grey-3" spinner-color="primary"
class="q-ma-md classroom-user" spinner-size="30px"
readonly v-if="x.RoomPicList && x.RoomPicList.length > 0"
style="text-align: center" />
<q-img
src="../../assets/images/classroom/bg-img.jpg"
fit="fill"
height="100%"
spinner-color="primary"
spinner-size="30px"
v-else
/>
</div>
<div class="xuhua"></div>
<div class="q-pa-md">
<div class="row items-end">
<div style="font-size:18px;" class="col">
{{ x.RoomName }}
</div>
<div class="f12 q-ml-md text-grey-5">
<div class="text-right">时段</div>
<div class="text-dark">
{{ x.StartTime }} - {{ x.EndTime }}
</div>
</div>
</div>
<div class="q-mt-lg f12 row items-center">
<div class="text-grey-6 f12 col">
<span
class="q-px-xs text-white q-mr-md inline-block text-weight-bold"
style="border-radius:4px;font-size:15;"
:class="{
'bg-grey-3': !x.StatusInfo,
'bg-negative': x.StatusInfo
}"
>
LIVE
</span>
<span class="text-grey-6" v-if="!x.StatusInfo"
>设备离线</span
> >
{{ _item.UserRate}}% <span
<br/> class="text-grey-6"
使用率 v-else-if="x.StatusInfo.UnLockUserName == 'lock'"
</q-knob> >设备在线,未解锁</span
<div class="classroom-info"> >
<div v-if="_item.TimeList.length>0"> <span class="text-grey-6" v-else
<q-carousel >{{ x.StatusInfo.UnLockUserName }}正在使用</span
v-model="_item.slide"
animated
:navigation="false"
height="75px"
class=" text-white shadow-1 rounded-borders"
arrows
control-color="grey-1"
control-text-color="primary"
control-type="unelevated"
> >
<q-carousel-slide v-for="(slide,slideIndex) in _item.TimeList" :key="slideIndex" :name="slideIndex" >
<div class="info-box">
<div class="time">{{ slide.StartTime }}</div>
<div class="info">{{slide.TeacherName}}{{slide.ClassName}}</div>
</div> </div>
</q-carousel-slide> <div v-if="x.StatusInfo">
</q-carousel> <q-btn
color="primary"
dense
class="f12"
flat
label="链接"
@click="openVideo(x)"
/>
</div> </div>
<div v-if="_item.TimeList.length===0" class="no-data">
暂无课程安排
</div> </div>
</div> </div>
</div> </div>
</template>
</div> </div>
</template>
</div> </div>
<q-dialog v-model="showVideo" @hide="clearVideo">
<q-card
class="my-card"
style="width:60vw !important;max-width:60vw !important;max-height:unset !important;"
flat
>
<!-- <q-card-section>
<div class="text-h6" v-if="currentRoom">
{{ currentRoom.RoomName }}
</div> </div>
</q-card-section> -->
<q-card-section>
<video
id="my_video"
class="video-js vjs-default-skin"
controls
preload
v-if="showVideo"
></video>
</q-card-section>
</q-card>
</q-dialog>
</div> </div>
</template> </template>
<script> <script>
import { import { getUseClassRoomList } from "../../api/classroom/index";
getUseClassRoomList import * as signalR from "@aspnet/signalr";
} from '../../api/classroom/index'; import videojs from "video.js";
export default { import "videojs-contrib-hls";
export default {
meta: { meta: {
title: "教室状态" title: "教室状态"
}, },
data() { data() {
return { return {
classdata:[ classdata: [],
{ loading: true,
SchoolName:"锦江校区一", showVideo: false,
list:[ videoObj: null,
{ currentRoom: null,
slide:0, queryStatus: 0,
img:"", connection: "", //signalr连接
classroom:'樱花教室', roomStatusList: [] //返回消息
user:80, };
warn:0,
course:[]
}, },
]
}
], created() {
loading: true, let thisVue = this;
console.log(process.env.API_SIG);
this.connection = new signalR.HubConnectionBuilder()
.withUrl(process.env.API_SIG, {
skipNegotiation: true,
transport: signalR.HttpTransportType.WebSockets
})
.configureLogging(signalR.LogLevel.Information)
.build();
this.connection.on("RoomStatusChange", function(message) {
thisVue.roomStatusList = JSON.parse(message);
console.log(thisVue.roomStatusList);
thisVue.changeStatus();
});
this.connection.onclose(async () => {
setTimeout(() => {
thisVue.linkHub();
}, 3000);
});
}; this.linkHub();
}, },
mounted(){ mounted() {
this.getList(); this.getList();
//this.openVideo();
}, },
methods:{ methods: {
goUrl(x,y){ changeViewStatusHandler() {},
this.$router.push({ clearVideo() {
path:"/classroom/useRecord", this.videoObj.dispose();
query:{ this.showVideo = false;
key:x.Key, },
roomId:y.RoomId openVideo(item) {
this.showVideo = true;
this.currentRoom = item;
this.$nextTick(() => {
this.videoObj = videojs("my_video", {
controls: true, //是否显示播放器控件
autoplay: true, //是否自动播放
sources: [
{
type: "application/x-mpegURL",
src: `http://47.96.12.235:5000/live/${item.RoomId}.m3u8`
} }
]
});
this.videoObj.play();
setTimeout(() => {
document
.getElementById("my_video_html5_api")
.setAttribute("controls", "controls");
}, 2000);
});
},
changeStatus() {
this.initStatus();
if (this.roomStatusList && this.roomStatusList.length > 0) {
this.roomStatusList.forEach(x => {
this.classdata.forEach(y => {
y.RoomList.forEach(z => {
if (z.RoomId == x.RoomId) {
z.StatusInfo = x;
}
});
});
});
}
this.$forceUpdate();
},
initStatus() {
this.classdata.forEach(y => {
y.RoomList.forEach(z => {
this.classdata.forEach(y => {
y.RoomList.forEach(z => {
z.StatusInfo = null;
});
});
});
});
this.$forceUpdate();
},
linkHub() {
let thatVue = this;
this.connection
.start()
.then(() => {
console.log("linke success");
thatVue.connection.invoke("RegistErp", "IMERP");
}) })
.catch(e => {
console.log(e);
setTimeout(() => {
thatVue.linkHub();
}, 3000);
});
},
goUrl(x, y) {
this.$router.push({
path: "/classroom/useRecord",
query: {
key: x.Key,
roomId: y.RoomId
}
});
}, },
getList() { getList() {
getUseClassRoomList({}).then(res => { getUseClassRoomList({})
this.loading = false .then(res => {
if(res.Code===1){ this.loading = false;
if (res.Code === 1) {
res.Data.forEach(e => { res.Data.forEach(e => {
e.RoomList.forEach(_e=>{ e.RoomList.forEach(_e => {
_e.slide=0 _e.slide = 0;
}) });
}); });
this.classdata=res.Data this.classdata = res.Data;
this.changeStatus();
} }
}).catch(() => {
this.loading = false;
}) })
}, .catch(() => {
this.loading = false;
});
} }
};
</script>
<style lang="scss" scoped>
.school-item{
margin-bottom: 10px;
.school-name{
font-size: 16px;
font-family: Microsoft YaHei;
font-weight: bold;
color: #000000;
margin-bottom: 30px;
} }
.classroom-box{ };
width: 1680px; </script>
display: flex; <style>
// justify-content: space-between; .class-room {
flex-wrap: wrap; border: 1px solid #f5f5f5;
.classroom-item-noUse{ border-radius: 10px;
opacity:0.8;
}
.classroom-item{
width: 390px;
height: 235px;
background: #FFFFFF;
border: 1px solid #EBEBEB;
box-shadow: 0px 1px 1px 0px #E4E7FB;
border-radius: 16px;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
}
.classroom-img{ .class-room .img-box {
display: block; height: 80px;
width: 390px; }
// height: 160px; .class-room .xuhua {
// border-radius: 16px;
background-color: #333;
overflow: hidden;
}
.divCalssRoom{
height: 160px;
border-radius: 16px;
overflow: hidden;
}
.classroom-name{
position: absolute;
top: 20px;
left: 20px;
z-index: 5999;
font-size: 20px;
font-family: PingFang SC;
font-weight: 800;
color: #FFFFFF;
display: flex;
align-items: center;
}
.classroom-user{
position: absolute; position: absolute;
top: 10px; top: 0;
right: 10px; height: 80px;
z-index: 5999; left: 0;
color: #FFFFFF; right: 0;
} backdrop-filter: blur(4px);
.classroom-info{
width: 390px;
height: 75px;
// background-color: tomato;
.info-box{
height: 43px;
display: flex;
align-items: center;
justify-content: flex-start;
box-sizing: border-box;
padding: 0 40px;
.time{
font-size: 14px;
font-family: PingFang SC;
font-weight: bold;
color: #6D97FF;
margin-right: 10px;
}
.info{
// width: 225px;
height: 100%;
font-size: 14px;
font-family: PingFang SC;
display: flex;
align-items: center;
color: #000000;
}
}
}
}
}
} }
.no-data{ .class-room:hover .xuhua {
backdrop-filter: none;
}
.no-data {
height: 75px; height: 75px;
font-size: 14px; font-size: 14px;
color: #000000; color: #000000;
...@@ -239,7 +300,23 @@ import { ...@@ -239,7 +300,23 @@ import {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.room-list{ .video-js div,
overflow: scroll; .video-js button {
display: none !important;
}
.video-js {
width: 100%;
}
.video-js video {
width: 100%;
}
.video-js .no-video {
display: flex;
height: 100%;
font-size: 14px;
text-align: center;
justify-content: center;
align-items: center;
background: #000;
} }
</style> </style>
...@@ -191,6 +191,11 @@ export default { ...@@ -191,6 +191,11 @@ export default {
immediate: true immediate: true
} }
}, },
mounted() {
if (tccc && tccc.Agent) {
tccc.Agent.offline();
}
},
methods: { methods: {
callBackUserInfo(code) { callBackUserInfo(code) {
setUserCodeCallBack({ setUserCodeCallBack({
...@@ -228,7 +233,7 @@ export default { ...@@ -228,7 +233,7 @@ export default {
const s = document.createElement("script"); const s = document.createElement("script");
s.type = "text/javascript"; s.type = "text/javascript";
s.src = s.src =
"http://wwcdn.weixin.qq.com/node/wework/wwopen/js/wwLogin-1.2.5.js"; "https://wwcdn.weixin.qq.com/node/wework/wwopen/js/wwLogin-1.2.5.js";
const wxElement = document.body.appendChild(s); const wxElement = document.body.appendChild(s);
// 调用企业微信二维码方法 // 调用企业微信二维码方法
wxElement.onload = function() { wxElement.onload = function() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment