<template>
|
<div class="coursePage">
|
<div class="personalPage-title">我的班级</div>
|
<div class="tabs">
|
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
|
<el-tab-pane
|
:label="'当前班级(' + calssList.length + ')'"
|
name="1"
|
></el-tab-pane>
|
<!-- <el-tab-pane label="历史班级(5)" name="2"></el-tab-pane> -->
|
</el-tabs>
|
</div>
|
<div class="headerBox">
|
<div class="searchBox">
|
<el-input
|
v-model="searchKey"
|
clearable
|
@clear="searchList()"
|
placeholder="请输入关键字"
|
>
|
<template #append>
|
<el-button
|
type="primary"
|
class="searchBtn"
|
@click="searchList()"
|
:icon="Search"
|
/>
|
</template>
|
</el-input>
|
</div>
|
<el-button type="primary" class="applyStartClasses" @click="openJoin()"
|
>加入班级</el-button
|
>
|
<el-dialog v-model="dialogVisible" title="加入班级" width="500">
|
<div class="codeContent">
|
<span>邀请码:</span>
|
<el-input style="width: 330px" v-model="codeText" placeholder="请输入邀请码" />
|
<el-button type="primary" @click="getClassDetail">确认</el-button>
|
</div>
|
<div class="classInfo" v-if="classDetail?.name">
|
<div class="itemCon">
|
<span>班级名称:</span>
|
<span>{{ classDetail.name }}</span>
|
</div>
|
<div class="itemCon">
|
<span>班级人数:</span>
|
<span>{{ classDetail.memberCount }} / {{ classDetail.maxUserCount }}</span>
|
</div>
|
<div class="itemCon">
|
<span>开课时间:</span>
|
<span
|
>{{ moment(classDetail.beginDate).format("YYYY-MM-DD") }} -
|
{{ moment(classDetail.endDate).format("YYYY-MM-DD") }}</span
|
>
|
</div>
|
</div>
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button @click="dialogVisible = false"> 取消 </el-button>
|
<el-button type="primary" @click="joinClass()"> 确认 </el-button>
|
</div>
|
</template>
|
</el-dialog>
|
</div>
|
<div class="courseListBox" v-if="calssList.length > 0 && !isLoading">
|
<div class="courseItem" v-for="(item, index) in calssList" :key="index">
|
<div class="itemHeader">
|
<div class="title">{{ item.name }}</div>
|
<div class="courseId">(ID:{{ item.id }})</div>
|
<!-- <div class="copyIdBtn" @click="copy(item.refCode)">复制邀请码</div> -->
|
</div>
|
<div class="itemInfo" @click="goClassManage(item)">
|
<div class="infoBox">
|
<p>
|
状态:<span v-if="item.userState == 'WaitValid'" style="color: #ef9f29">
|
审核中 </span
|
><span v-if="item.userState == 'Normal'" style="color: #1dbd11">
|
进行中 </span
|
><span v-if="item.userState == 'Reject'" style="color: red"> 未通过 </span>
|
</p>
|
<p>班级人数:{{ item.memberCount }} / {{ item.maxUserCount }}</p>
|
<p>有效期:{{ item.classTime }}</p>
|
</div>
|
</div>
|
</div>
|
</div>
|
<el-empty description="暂无数据" v-if="calssList.length == 0 && !isLoading" />
|
<div style="min-height: 200px" v-if="isLoading" v-loading="isLoading"></div>
|
<div class="pageBox">
|
<el-pagination
|
v-model:current-page="pages.currentPage"
|
:page-size="pages.pageSize"
|
:size="'small'"
|
:disabled="pages.count <= 1"
|
layout="total, prev, pager, next"
|
:total="pages.count"
|
@size-change="handleSizeChange"
|
@current-change="handleCurrentChange"
|
/>
|
</div>
|
</div>
|
</template>
|
|
<script setup lang="ts">
|
import { reactive, ref, onMounted, inject, watch } from "vue";
|
import { Search } from "@element-plus/icons-vue";
|
import { useRouter } from "vue-router";
|
import { ElMessage } from "element-plus";
|
import { getPublicImage } from "@/assets/js/middleGround/tool.js";
|
import moment from "moment";
|
import useClipboard from "vue-clipboard3";
|
|
const { toClipboard } = useClipboard();
|
const MG: any = inject("MG");
|
const config: any = inject("config");
|
const router = useRouter();
|
const activeName = ref("1");
|
|
interface ClassItem {
|
id: string;
|
name: string;
|
memberCount: number;
|
maxUserCount: number;
|
userState: string;
|
beginDate: string;
|
endDate: string;
|
classTime: string;
|
linkProductDto: {
|
product: {
|
name: string;
|
icon: string;
|
};
|
};
|
}
|
|
const calssList = ref<ClassItem[]>([]);
|
const searchKey = ref("");
|
const codeText = ref("");
|
const dialogVisible = ref(false);
|
const classDetail = ref();
|
const isLoading = ref(true);
|
|
let pages = reactive({
|
currentPage: 1,
|
page: 1,
|
pageSize: 6,
|
count: 0,
|
loading: false,
|
});
|
|
onMounted(() => {
|
getCurrentClassList();
|
});
|
|
// 分页
|
const handleSizeChange = (val: number) => {
|
pages.pageSize = val;
|
getCurrentClassList();
|
};
|
|
const handleCurrentChange = (val: number) => {
|
pages.page = val;
|
pages.currentPage = val;
|
getCurrentClassList();
|
};
|
|
const handleClick = (val: any) => {
|
activeName.value = val;
|
};
|
|
const openJoin = () => {
|
dialogVisible.value = true;
|
classDetail.value = null;
|
codeText.value = "";
|
};
|
|
// 搜索
|
const searchList = () => {
|
pages.page = 1;
|
pages.currentPage = 1;
|
getCurrentClassList();
|
};
|
|
// 复制
|
const copy = async (text: string) => {
|
try {
|
await toClipboard(text);
|
ElMessage({
|
message: "复制成功",
|
type: "success",
|
});
|
} catch (e) {
|
console.error(e);
|
}
|
};
|
|
// 加入班级
|
const joinClass = () => {
|
if (!codeText.value) {
|
ElMessage({
|
message: "无效的邀请码",
|
type: "error",
|
});
|
return false;
|
}
|
const data = { refCode: codeText.value };
|
MG.identity.joinGroupByRefCode(data).then((res: any) => {
|
if (res == "组不存在") {
|
ElMessage({
|
message: "无效的班级",
|
type: "error",
|
});
|
}
|
if (res == "组成员数量已最大,不能加入") {
|
ElMessage({
|
message: "班级成员数量已最大,不能加入",
|
type: "error",
|
});
|
}
|
if (res == "已经申请过加入此组") {
|
ElMessage({
|
message: "已经申请过加入此班级",
|
type: "error",
|
});
|
}
|
dialogVisible.value = false;
|
getCurrentClassList();
|
});
|
};
|
|
// 获取当前班级列表
|
const getCurrentClassList = () => {
|
isLoading.value = true;
|
const data = {
|
start: (pages.page - 1) * pages.pageSize,
|
size: pages.pageSize,
|
sort: {
|
type: "Desc",
|
field: "CreateDate",
|
subSorts: [],
|
},
|
filterList: [],
|
searchList: searchKey.value
|
? [
|
{
|
keywords: searchKey.value,
|
field: "Name",
|
compareType: "Contains",
|
},
|
]
|
: [],
|
};
|
MG.identity.joinedGroupByList(data).then((res: any) => {
|
isLoading.value = false;
|
pages.count = res.totalSize;
|
if (res.datas) {
|
calssList.value = res.datas.map((item: any) => {
|
return {
|
...item,
|
classTime:
|
moment(item.beginDate).format("YYYY.MM.DD") +
|
"--" +
|
moment(item.endDate).format("YYYY.MM.DD"),
|
bookName: item.linkProductDto.product.name,
|
bookIcon: getPublicImage(item.linkProductDto.product.icon, 100),
|
};
|
});
|
}
|
});
|
};
|
|
// 跳转班级管理
|
const goClassManage = async (item: any) => {
|
if (item.userState == "WaitValid") {
|
ElMessage({
|
message: "正在审核中....",
|
type: "warning",
|
});
|
return false;
|
}
|
if (item.userState == "Reject") {
|
ElMessage({
|
message: "审核未通过",
|
type: "warning",
|
});
|
return false;
|
}
|
const bookInfo = await getBookDetail(item.linkProductDto?.product);
|
let info = {
|
id: item.id,
|
name: item.name,
|
icon: bookInfo.icon,
|
rootCmsItemId: bookInfo.rootCmsItemId,
|
bookId: bookInfo.id,
|
author: bookInfo.author,
|
isbn: bookInfo.isbn,
|
bookRefCode: bookInfo.refCode,
|
};
|
let page = router.resolve({
|
path: "/classManage",
|
query: {
|
classInfo: JSON.stringify(info),
|
},
|
});
|
window.open(page.href, "_blank");
|
// router.push({
|
// path: '/classManage',
|
// query: {
|
// classInfo: JSON.stringify(info)
|
// }
|
// })
|
};
|
|
// 获取教材详情
|
const getBookDetail = async (item: any) => {
|
const path = item.refCode ? "jsek_digitalTextbooks" : config.goodsStore;
|
let query = {
|
path,
|
queryType: "*",
|
productId: String(item.id),
|
storeInfo: path,
|
coverSize: {
|
height: 300,
|
width: 210,
|
},
|
fields: {
|
author: [],
|
isbn: [],
|
},
|
};
|
const res = await MG.store.getProductDetail(query);
|
return res.datas ?? null;
|
};
|
|
// 通过code查询班级
|
const getClassDetail = () => {
|
if (codeText.value == "") {
|
ElMessage({
|
message: "请输入邀请码",
|
type: "warning",
|
});
|
return false;
|
}
|
const data = {
|
classIdOrRefCode: codeText.value,
|
};
|
MG.edu
|
.getCourseClass(data)
|
.then((res: any) => {
|
classDetail.value = res;
|
})
|
.catch((err: any) => {
|
console.log(err);
|
});
|
};
|
</script>
|
|
<style lang="less" scoped>
|
.coursePage {
|
.tabs {
|
padding: 0 20px;
|
}
|
.headerBox {
|
padding: 5px 20px;
|
margin-bottom: 10px;
|
overflow: hidden;
|
.searchBox {
|
width: 300px;
|
float: left;
|
.searchBtn {
|
background-color: var(--el-color-primary);
|
color: #fff;
|
border-top-left-radius: 0;
|
border-bottom-left-radius: 0;
|
}
|
}
|
.applyStartClasses {
|
float: right;
|
}
|
}
|
.courseListBox {
|
overflow: hidden;
|
.courseItem {
|
float: left;
|
width: 46%;
|
margin: 0 2% 20px;
|
border-radius: 8px;
|
border: 1px solid #efefef;
|
overflow: hidden;
|
.itemHeader {
|
height: 40px;
|
line-height: 40px;
|
padding: 0 20px;
|
// color: #fff;
|
background-color: #f8f8f8;
|
.title {
|
font-weight: 600;
|
}
|
div {
|
display: inline-block;
|
}
|
.courseId {
|
margin-left: 6px;
|
font-size: 12px;
|
color: #999;
|
}
|
.copyIdBtn {
|
float: right;
|
height: 20px;
|
line-height: 20px;
|
margin-top: 10px;
|
font-size: 12px;
|
background-color: #fff;
|
color: #3b93fe;
|
padding: 0 6px;
|
border-radius: 50px;
|
overflow: hidden;
|
cursor: pointer;
|
}
|
}
|
.itemInfo {
|
padding: 20px;
|
flex: 1;
|
display: flex;
|
cursor: pointer;
|
.imgBox {
|
width: 90px;
|
height: 120px;
|
margin-right: 20px;
|
}
|
.infoBox {
|
flex: 1;
|
font-size: 12px;
|
p {
|
margin-bottom: 10px;
|
}
|
}
|
}
|
}
|
}
|
.codeContent {
|
width: 100%;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding-bottom: 30px;
|
}
|
.classInfo {
|
padding: 30px 0;
|
border-top: 2px dashed #ccc;
|
|
.itemCon {
|
margin-bottom: 20px;
|
}
|
}
|
.pageBox {
|
padding: 10px 0;
|
display: flex;
|
justify-content: center;
|
}
|
}
|
</style>
|