<template>
|
<div class="classManagePage-box">
|
<div class="classManagePage-nav" v-if="classInfo">
|
<el-breadcrumb :separator-icon="ArrowRight">
|
<el-breadcrumb-item>我的班级</el-breadcrumb-item>
|
<el-breadcrumb-item>{{ classInfo?.name }}</el-breadcrumb-item>
|
<el-breadcrumb-item>班级首页</el-breadcrumb-item>
|
</el-breadcrumb>
|
</div>
|
<div class="classManagePage-content">
|
<div class="content-left fl">
|
<div class="classOverview mainBorder">
|
<div class="">
|
<div class="title mainbg">班级概览</div>
|
</div>
|
<div class="bodyBox" v-if="currentClass?.name && !classLoading">
|
<div class="classInfo">
|
<div class="name">{{ currentClass?.name }}</div>
|
<!-- <div class="time">报名时间:2024.7.30--2024-8.03</div> -->
|
<div class="time">开课时间: {{ currentClass?.classTime }}</div>
|
</div>
|
<div class="line"></div>
|
<div class="classInfoBox">
|
<div class="iconBox">
|
<img :src="currentClass?.bookIcon ? currentClass?.bookIcon : defaultImg" />
|
</div>
|
<div class="infoBox">
|
<div class="main">{{ currentClass?.bookName }}</div>
|
<div class="job">作者:{{ classInfo?.author ?? '-' }}</div>
|
<div class="job">ISBN:{{ classInfo?.isbn ?? '-' }}</div>
|
</div>
|
</div>
|
<div class="line"></div>
|
<div class="classInfo">
|
<div class="name">班级人数</div>
|
<div class="con">
|
<span class="main">{{ currentClass?.memberCount }}</span
|
>/{{ currentClass?.maxUserCount }}
|
</div>
|
</div>
|
<div class="line"></div>
|
<div class="classInfo">
|
<div class="name">作业次数</div>
|
<div class="con">
|
<span class="main">{{ homeworkCount }}</span>
|
</div>
|
</div>
|
<!-- <div class="line"></div>
|
<div class="classInfo">
|
<div class="name">教学进度</div>
|
<div class="con"><span class="main">0</span>/0</div>
|
</div> -->
|
</div>
|
<div
|
class="bodyBox"
|
style="display: flex; justify-content: center; align-items: center"
|
v-if="classLoading"
|
>
|
<div v-loading="classLoading"></div>
|
</div>
|
<div v-if="!currentClass && !classLoading">
|
<el-empty style="padding: 0" :image-size="100" />
|
</div>
|
</div>
|
<div class="classNotice">
|
<div class="titleBox">
|
<div class="border mainbg"></div>
|
<div class="title">
|
<span>班级通知</span>
|
<el-icon
|
style="cursor: pointer"
|
color="#019e58"
|
v-if="noticeList.length > 0 && userInfo.role == 'Teacher'"
|
@click="toInfo"
|
>
|
<ArrowRightBold />
|
</el-icon>
|
</div>
|
</div>
|
<div class="noticeList" v-if="noticeList.length > 0 && !noticeLoading">
|
<div class="noticeItem" v-for="(item, index) in noticeList" :key="index">
|
<div class="noticeContent">
|
<span class="title">{{ item.name }}:</span>
|
<div class="contentText">{{ item.content }}</div>
|
</div>
|
<span class="time">{{ item.createDate }}</span>
|
</div>
|
</div>
|
<div v-if="noticeLoading" v-loading="noticeLoading"></div>
|
<div v-if="noticeList.length == 0 && !noticeLoading" class="notBox">
|
<el-empty :image-size="100" />
|
</div>
|
</div>
|
<div class="classTalk">
|
<div class="titleBox">
|
<div class="border mainbg"></div>
|
<div class="title">
|
<span>班组话题</span>
|
<el-icon
|
style="cursor: pointer"
|
color="#019e58"
|
v-if="messageList.length > 0"
|
@click="toTalk"
|
>
|
<ArrowRightBold />
|
</el-icon>
|
</div>
|
</div>
|
<div class="noticeList" v-if="messageList.length > 0 && !messageLoading">
|
<div class="noticeItem" v-for="(item, index) in messageList" :key="index">
|
<div class="noticeContent">
|
<span class="title">{{ item.name }}</span>
|
<div class="content" v-if="item.publicText">
|
<span>{{ item.publicText.publishRole }}:</span>
|
<span>{{ item.publicText.publisher }}</span>
|
</div>
|
<span>最近回复:{{ item.updateDate }}</span>
|
</div>
|
<span class="time">{{ item.createDate }}</span>
|
</div>
|
</div>
|
<div v-if="messageLoading" v-loading="messageLoading"></div>
|
<div v-if="messageList.length == 0 && !messageLoading" class="notBox">
|
<el-empty :image-size="100" />
|
</div>
|
</div>
|
<div class="classTask">
|
<div class="titleBox" style="margin-bottom: 5px">
|
<div class="border mainbg"></div>
|
<div class="title">
|
<span>班级作业概览</span>
|
<!-- <el-icon
|
style="cursor: pointer"
|
color="#019e58"
|
v-if="tableData.length > 0"
|
@click="toWorkList"
|
>
|
<ArrowRightBold />
|
</el-icon> -->
|
</div>
|
</div>
|
<div class="tableWall">
|
<el-table :data="tableData" border style="width: 100%; font-size: 14px" size="small">
|
<el-table-column prop="name" label="名称" />
|
<el-table-column prop="beginDate" label="开始时间" />
|
<el-table-column prop="endDate" label="截止时间" />
|
<el-table-column prop="submitCount" label="完成情况(提交人数)" width="180" />
|
</el-table>
|
</div>
|
</div>
|
<!-- <div class="classTask">
|
<div class="titleBox" style="margin-bottom: 5px">
|
<div class="border mainbg"></div>
|
<div class="title">
|
<span>教学互动</span>
|
<el-icon
|
style="cursor: pointer"
|
color="#019e58"
|
v-if="tableData.length > 0"
|
@click="toTeaching"
|
>
|
<ArrowRightBold />
|
</el-icon>
|
</div>
|
</div>
|
<div class="tableWall">
|
<el-table :data="[]" border style="width: 100%; font-size: 14px" size="small">
|
<el-table-column prop="index" label="序号" />
|
<el-table-column prop="name" label="标题" />
|
<el-table-column prop="beginDate" label="互动学生数(已互动/全部学生)" />
|
<el-table-column prop="endDate" label="最后提交时间" />
|
</el-table>
|
</div>
|
</div> -->
|
</div>
|
<div class="content-right fr">
|
<div class="assistant">
|
<div class="titleBox">
|
<div class="border mainbg"></div>
|
<div class="title">助教列表</div>
|
<div class="options">
|
<!-- <div class="optionsItem">移除</div> -->
|
<div class="copyIdBtn" @click="copy(currentClass)">复制邀请码</div>
|
</div>
|
</div>
|
<div class="avatarList" style="max-height: 147px; overflow-y: auto">
|
<div class="avatarItem" v-for="(item, index) in teacherList" :key="index">
|
<el-avatar v-if="item.appUser?.icon" :size="35" :src="item.appUser?.icon" />
|
<el-avatar v-else :size="35" :icon="UserFilled" />
|
<el-tooltip :content="item.appUser?.name" placement="top" effect="light">
|
<span class="userName">{{ item.appUser?.name }}</span>
|
</el-tooltip>
|
</div>
|
<div class="nullBox" v-if="!Sloading && teacherList.length == 0">
|
<el-empty :image-size="100" />
|
</div>
|
</div>
|
</div>
|
<div class="student">
|
<div class="titleBox">
|
<div class="border mainbg"></div>
|
<div class="title">学生列表</div>
|
<div class="options">
|
<div class="copyIdBtn" @click="copy(currentClass)">复制邀请码</div>
|
</div>
|
</div>
|
<div class="avatarList" style="max-height: 570px; overflow-y: auto">
|
<div class="avatarItem02" v-for="(item, index) in studentList" :key="index">
|
<el-avatar v-if="item.appUser?.icon" :size="35" :src="item.appUser?.icon" />
|
<el-avatar v-else :size="35" :icon="UserFilled" />
|
<el-tooltip :content="item.appUser?.name" placement="top" effect="light">
|
<span class="userName">{{ item.appUser?.name }}</span>
|
</el-tooltip>
|
</div>
|
<div class="nullBox" v-if="!Sloading && studentList.length == 0">
|
<el-empty :image-size="100" />
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script setup lang="ts">
|
import { useRoute, useRouter } from 'vue-router'
|
import { getPublicImage } from '@/assets/js/middleGround/tool.js'
|
import useClipboard from 'vue-clipboard3'
|
import { inject, onMounted, ref } from 'vue'
|
import moment from 'moment'
|
import { ElMessage } from 'element-plus'
|
import { ArrowRight, UserFilled } from '@element-plus/icons-vue'
|
import defaultImg from '@/assets/images/default-book-img.png'
|
|
const { toClipboard } = useClipboard()
|
const route: any = useRoute()
|
const router: any = useRouter()
|
const classInfo = JSON.parse(route.query.classInfo)
|
const MG: any = inject('MG')
|
const config: any = inject('config')
|
const userInfo: any = ref()
|
|
const currentClass = ref()
|
const classLoading = ref(true)
|
const messageTopicInfo = ref()
|
const talkTopicInfo = ref()
|
const noticeList: any = ref([])
|
const noticeLoading = ref(true)
|
const messageList: any = ref([])
|
const messageLoading = ref(true)
|
const tableData: any = ref([])
|
const homeworkCount = ref(0)
|
const studentList: any = ref([])
|
const teacherList: any = ref([])
|
const Sloading = ref(false)
|
|
onMounted(() => {
|
const userCache: any = localStorage.getItem(config.userInfoKey)
|
if (userCache) {
|
userInfo.value = JSON.parse(userCache)
|
}
|
getData()
|
getStudentList()
|
getTaskList()
|
})
|
|
// 复制
|
const copy = async (val: any) => {
|
try {
|
await toClipboard(val.refCode)
|
ElMessage({
|
message: '复制成功',
|
type: 'success',
|
})
|
} catch (e) {
|
console.error(e)
|
}
|
}
|
|
// 获取班级
|
const getData = () => {
|
MG.edu
|
.getCourseClass({
|
ClassIdOrRefCode: String(classInfo.id),
|
})
|
.then((res: any) => {
|
if (res) {
|
res.bookName = res.linkProductDto.product.name
|
res.bookIcon = getPublicImage(res.linkProductDto.product.icon, 100)
|
res.classTime =
|
moment(res.beginDate).format('YYYY.MM.DD') +
|
'--' +
|
moment(res.endDate).format('YYYY.MM.DD')
|
}
|
currentClass.value = res
|
classLoading.value = false
|
getTopicInfo()
|
})
|
}
|
|
// 获取topic
|
const getTopicInfo = () => {
|
const pramas = {
|
classId: classInfo.id,
|
refCodes: [config.refCode.message, config.refCode.talk],
|
}
|
MG.edu.getClassTopic(pramas).then((res: any) => {
|
const list = res
|
messageTopicInfo.value = list.find((item: any) => item.refCode == config.refCode.message)
|
if (messageTopicInfo.value.id) {
|
sessionStorage.messageId = messageTopicInfo.value.id
|
noticeLoading.value = true
|
getNotice()
|
}
|
talkTopicInfo.value = list.find((item: any) => item.refCode == config.refCode.talk)
|
if (talkTopicInfo.value.id) {
|
sessionStorage.talkId = talkTopicInfo.value.id
|
messageLoading.value = true
|
getMessage()
|
}
|
})
|
}
|
|
// 获取班级通知
|
const getNotice = () => {
|
const data = {
|
start: 0,
|
size: 3,
|
appRefCode: config.appRefCode,
|
topicIdOrRefCode: String(messageTopicInfo.value.id),
|
sort: {
|
type: 'Desc',
|
field: 'CreateDate',
|
subSorts: [],
|
},
|
}
|
MG.ugc.getTopicMessageList(data).then((res: any) => {
|
noticeLoading.value = false
|
const list = res.datas
|
noticeList.value = list.map((item: any) => {
|
return {
|
...item,
|
createDate: moment(item.createDate).format('YYYY-MM-DD'),
|
}
|
})
|
})
|
}
|
|
// 获取班级话题
|
const getMessage = () => {
|
const data = {
|
start: 0,
|
size: 3,
|
appRefCode: config.appRefCode,
|
topicIdOrRefCode: String(talkTopicInfo.value.id),
|
sort: {
|
type: 'Desc',
|
field: 'CreateDate',
|
subSorts: [],
|
},
|
}
|
MG.ugc.getTopicMessageList(data).then((res: any) => {
|
messageLoading.value = false
|
const list = res.datas
|
messageList.value = list.map((item: any, i: number) => {
|
const str = item.content.indexOf('publisher')
|
if (str > -1) {
|
item.publicText = JSON.parse(item.content)
|
if (item.publicText && item.publicText.publishRole) {
|
item.publicText.publishRole = item.publicText.publishRole == 'Teacher' ? '助教' : '学生'
|
}
|
}
|
return {
|
...item,
|
index: i + 1,
|
createDate: moment(item.createDate).format('YYYY-MM-DD HH:mm:ss'),
|
updateDate: moment(item.updateDate).format('YYYY-MM-DD HH:mm:ss'),
|
}
|
})
|
})
|
}
|
|
// 获取教师/学生列表
|
const getStudentList = () => {
|
Sloading.value = true
|
const data = {
|
start: 0,
|
size: 999,
|
groupId: classInfo.id,
|
filterList: [
|
{
|
value: 'Normal',
|
field: 'State',
|
subFilters: [],
|
},
|
],
|
}
|
MG.identity.getGroupUserList(data).then((res: any) => {
|
const { datas } = res
|
Sloading.value = false
|
let list: any = []
|
if (datas.length > 0) {
|
list = datas.map((item: any, index: number) => {
|
if (item.linkType == 'Creator') {
|
const userInfo = item.appUser?.infoList?.find((citem: any) => citem.type == 'teacherInfo')
|
item.appUser.name = userInfo.name
|
item.appUser.icon = userInfo.icon
|
if (userInfo?.data) {
|
const iconData = JSON.parse(userInfo.data)
|
item.appUser.icon = getPublicImage(iconData?.relevantCertificates[0]?.md5, 100) ?? ''
|
}
|
}
|
if (item.linkType == 'RefCode' || item.linkType == 'Teacher') {
|
let userInfo = null
|
const wechatData = item.appUser?.infoList?.find((citem: any) => citem.type == 'WeChat')
|
const defaultData = item.appUser?.infoList?.find((citem: any) => citem.type == 'Default')
|
userInfo = defaultData
|
if (wechatData?.name) {
|
userInfo = wechatData
|
}
|
item.appUser.name = userInfo.name
|
item.appUser.icon = userInfo.icon
|
}
|
return {
|
...item,
|
index: index + 1,
|
createDate: moment(item.createDate).format('YYYY-MM-DD'),
|
}
|
})
|
}
|
teacherList.value = list.filter((item: any) => item.linkType != 'RefCode')
|
studentList.value = list.filter((item: any) => item.linkType == 'RefCode')
|
})
|
}
|
|
// 前往话题
|
const toTalk = () => {
|
classInfo.index = 5
|
if (userInfo.value?.role != 'Teacher') {
|
classInfo.index = 3
|
}
|
router.push({
|
path: '/talkingPoint',
|
query: {
|
classInfo: JSON.stringify(classInfo),
|
},
|
})
|
}
|
|
// 前往通知
|
const toInfo = () => {
|
classInfo.index = 0
|
router.push({
|
path: '/info',
|
query: {
|
classInfo: JSON.stringify(classInfo),
|
},
|
})
|
}
|
|
// 教学互动
|
const toTeaching = () => {}
|
|
// 班级作业概览
|
const getTaskList = () => {
|
const data = {
|
start: 0,
|
size: 3,
|
sort: {
|
type: 'Desc',
|
field: 'CreateDate',
|
subSorts: [],
|
},
|
filterList: [
|
// {
|
// value: 'Normal',
|
// field: 'State',
|
// subFilters: []
|
// },
|
{
|
value: config.taskType.homeWork,
|
field: 'Type',
|
subFilters: [],
|
},
|
],
|
groupId: classInfo?.id,
|
}
|
MG.edu
|
.getTaskList(data)
|
.then((res: any) => {
|
let list: any = []
|
if (res.datas.length > 0) {
|
list = res.datas
|
?.map((item: any) => {
|
return {
|
...item,
|
beginDate: moment(item.beginDate).format('YYYY-MM-DD'),
|
endDate: moment(item.endDate).format('YYYY-MM-DD'),
|
}
|
})
|
.slice(0, 3)
|
}
|
tableData.value = list
|
homeworkCount.value = res.totalSize
|
})
|
.catch((e: any) => {
|
console.log(e)
|
})
|
}
|
</script>
|
|
<style lang="less" scoped>
|
.nullBox {
|
width: 100%;
|
display: flex;
|
justify-content: center;
|
}
|
.classManagePage-box {
|
padding: 20px;
|
box-sizing: border-box;
|
.classManagePage-nav {
|
padding-bottom: 20px;
|
border-bottom: 1px solid #e6e8ed;
|
}
|
.classManagePage-content {
|
display: flex;
|
justify-content: space-between;
|
.content-left {
|
width: 70%;
|
min-width: 950px;
|
.classOverview {
|
height: 190px;
|
margin-top: 30px;
|
border-radius: 10px;
|
.title {
|
width: 80px;
|
text-align: center;
|
padding: 7px;
|
border-radius: 8px 0 8px 0;
|
}
|
.bodyBox {
|
display: flex;
|
justify-content: space-between;
|
margin-top: 20px;
|
padding: 0 20px;
|
.classInfoBox {
|
padding: 0 20px;
|
display: flex;
|
.iconBox {
|
width: 90px;
|
height: 120px;
|
img {
|
width: 100%;
|
height: 100%;
|
object-fit: contain;
|
}
|
}
|
.infoBox {
|
flex: 1;
|
padding-left: 10px;
|
.main {
|
font-size: 16px;
|
line-height: 20px;
|
}
|
.job {
|
// padding:10px;
|
margin-top: 20px;
|
}
|
}
|
}
|
.line {
|
width: 1px;
|
height: 130px;
|
background: linear-gradient(
|
180deg,
|
rgba(255, 255, 255, 0) 0%,
|
#b7b7b7 51%,
|
rgba(255, 255, 255, 0) 100%
|
);
|
}
|
.classInfo {
|
padding: 0 20px;
|
font-size: 16px;
|
min-width: 120px;
|
.name {
|
font-weight: bold;
|
margin-bottom: 20px;
|
text-align: center;
|
}
|
.con {
|
margin-top: 40px;
|
font-size: 22px;
|
text-align: center;
|
}
|
.time {
|
line-height: 30px;
|
}
|
}
|
}
|
}
|
.classNotice {
|
height: 200px;
|
margin-top: 20px;
|
border-radius: 20px;
|
background: linear-gradient(180deg, #fffcf1 0%, #ffffff 100%);
|
border: 1px solid rgba(249, 200, 35, 0.2);
|
}
|
.classTalk {
|
height: 200px;
|
margin-top: 20px;
|
border-radius: 20px;
|
background: linear-gradient(180deg, #edf0ff 0%, #ffffff 100%);
|
border: 1px solid rgba(154, 171, 251, 0.2);
|
}
|
.classTask {
|
min-height: 200px;
|
margin-top: 20px;
|
border-radius: 20px;
|
border: 1px solid #e8ebf5;
|
.tableWall {
|
width: 100%;
|
padding: 10px 5px;
|
box-sizing: border-box;
|
}
|
}
|
.titleBox {
|
display: flex;
|
align-items: center;
|
margin: 10px 0;
|
font-size: 16px;
|
.title {
|
width: 100%;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding-right: 10px;
|
}
|
.border {
|
width: 4px;
|
height: 23px;
|
border-radius: 0px 10px 10px 0px;
|
margin-right: 10px;
|
}
|
}
|
}
|
.content-right {
|
width: 28%;
|
margin-left: 20px;
|
min-width: 270px;
|
|
.assistant {
|
min-height: 160px;
|
margin-top: 30px;
|
border-radius: 10px;
|
border: 1px solid #e8ebf5;
|
overflow: hidden;
|
}
|
.student {
|
height: 640px;
|
margin-top: 20px;
|
border-radius: 10px;
|
border: 1px solid #e8ebf5;
|
overflow: hidden;
|
}
|
.titleBox {
|
display: flex;
|
align-items: center;
|
margin: 10px 0;
|
.border {
|
width: 4px;
|
height: 23px;
|
border-radius: 0px 10px 10px 0px;
|
margin-right: 10px;
|
}
|
}
|
}
|
.notBox {
|
width: 100%;
|
height: 100px;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
}
|
}
|
.options {
|
flex: 1;
|
display: flex;
|
align-items: center;
|
justify-content: flex-end;
|
padding-right: 10px;
|
.optionsItem {
|
color: #999;
|
margin-right: 10px;
|
cursor: pointer;
|
}
|
.copyIdBtn {
|
background-color: #fff;
|
padding: 10px;
|
border-radius: 50px;
|
overflow: hidden;
|
cursor: pointer;
|
font-size: 14px;
|
}
|
}
|
.avatarList {
|
display: flex;
|
flex-wrap: wrap;
|
width: 100%;
|
padding: 0 20px;
|
box-sizing: border-box;
|
.avatarItem,
|
.avatarItem02 {
|
width: 68px;
|
max-height: 88px;
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
padding: 6px 4px;
|
position: relative;
|
margin-left: 1px;
|
|
.userName {
|
width: 100%;
|
margin: 3px 0;
|
white-space: nowrap;
|
text-overflow: ellipsis;
|
overflow: hidden;
|
text-align: center;
|
min-height: 30px;
|
line-height: 30px;
|
font-size: 12px;
|
}
|
}
|
// .avatarItem:hover {
|
// background-image: url('@/assets/images/class/avabg.png');
|
// background-size: 100% 100%;
|
// background-position: center;
|
// background-repeat: no-repeat;
|
// cursor: pointer;
|
// }
|
.avatarItem:hover,
|
.avatarItem02:hover {
|
background: #eee;
|
}
|
}
|
.noticeList {
|
width: 100%;
|
height: calc(100% - 63px);
|
padding: 5px 25px;
|
overflow: auto;
|
.noticeItem {
|
display: flex;
|
justify-content: space-between;
|
font-family: PingFang SC;
|
font-weight: 400;
|
font-size: 14px;
|
line-height: 32px;
|
.noticeContent {
|
display: flex;
|
justify-content: space-between;
|
color: #000000;
|
max-width: 800px;
|
white-space: nowrap;
|
text-overflow: ellipsis;
|
overflow: hidden;
|
.title {
|
margin-right: 30px;
|
}
|
.content {
|
margin-right: 30px;
|
}
|
}
|
.time {
|
color: #b7b7b7;
|
}
|
}
|
}
|
}
|
</style>
|