<template>
|
<div class="coursePage">
|
<div class="personalPage-title">我的课程</div>
|
<div class="headerBox">
|
<div class="searchBox">
|
<el-input
|
v-model="searchKey"
|
clearable
|
@clear="getData"
|
placeholder="请输入关键字"
|
>
|
<template #append>
|
<el-button type="primary" class="searchBtn" :icon="Search" @click="getData" />
|
</template>
|
</el-input>
|
</div>
|
<el-button type="primary" class="applyStartClasses" @click="applyCourse"
|
>申请开课</el-button
|
>
|
</div>
|
<div class="courseListBox" v-loading="pages.loading">
|
<div
|
class="courseItem"
|
v-for="(item, index) in courseList"
|
:key="index"
|
@click="gotoDetail(item)"
|
>
|
<div class="itemHeader">
|
<div class="title" :title="item.name">{{ item.name }}</div>
|
</div>
|
<div class="reasonBox">
|
<el-tooltip placement="right-end" effect="light" class="box-item">
|
<template #content>
|
<div style="width: 300px" v-html="item.reason"></div>
|
</template>
|
<span v-if="item.applyState == 'Reject'" style="color: red">
|
拒绝原因:{{ item.reason != "" ? item.reason : "-" }}
|
</span>
|
</el-tooltip>
|
<el-button
|
v-if="item.applyState == 'Reject'"
|
type="primary"
|
size="small"
|
style="margin-left: 20px"
|
@click="reapplyCourse(item)"
|
>重新申请</el-button
|
>
|
</div>
|
|
<div class="itemInfo">
|
<div class="imgBox autoImgBox">
|
<div
|
class="stateIcon"
|
v-if="item.applyState == 'Normal'"
|
style="background-color: #1dbd11"
|
>
|
使用中
|
</div>
|
<div
|
class="stateIcon"
|
v-if="item.applyState == 'WaitAudit'"
|
style="background-color: #ef9f29"
|
>
|
审核中
|
</div>
|
<div
|
class="stateIcon"
|
v-if="item.applyState == 'Reject'"
|
style="background-color: red"
|
>
|
未通过
|
</div>
|
<img v-if="item.icon" :src="item.icon" />
|
<img v-else :src="defaultImg" alt="" />
|
</div>
|
<div class="infoBox">
|
<p class="id">ID:{{ item.id }}</p>
|
<div class="introduction" :title="item.introduction">
|
{{ item.introduction }}
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
<div class="pagination-box" v-if="courseList.length > 0">
|
<el-pagination
|
v-model:current-page="pages.page"
|
v-model:page-size="pages.pageSize"
|
:background="false"
|
layout="total, prev, pager, next"
|
:total="pages.count"
|
@current-change="pageChange"
|
/>
|
</div>
|
<div class="nullBox" v-if="!pages.loading && courseList.length == 0">
|
<el-empty />
|
</div>
|
<!-- 申请开课弹框 -->
|
<el-dialog v-model="applyCourseDialog" width="750" align-center>
|
<template #title>{{ editData ? "重新申请" : "申请开课" }}</template>
|
<el-form
|
:model="formData"
|
label-position="left"
|
ref="dialogFormRef"
|
label-width="80px"
|
>
|
<el-form-item
|
label="课程名称"
|
prop="name"
|
:rules="[{ required: true, message: '请输入课程名称' }]"
|
>
|
<el-input v-model="formData.name" placeholder="请输入课程名称" />
|
</el-form-item>
|
<el-form-item
|
v-if="!editData"
|
label="关联教材"
|
prop="bookName"
|
:rules="[{ required: true, message: '请选择教材' }]"
|
>
|
<div style="display: flex">
|
<el-input v-model="formData.bookName" disabled="true" style="width: 300px" />
|
<el-button style="margin-left: 10px" @click="selectBook">选择教材</el-button>
|
</div>
|
</el-form-item>
|
<el-form-item label="课程介绍">
|
<el-input
|
v-model="formData.desc"
|
type="textarea"
|
autocomplete="off"
|
maxlength="300"
|
show-word-limit
|
rows="7"
|
placeholder="请输入课程介绍"
|
/>
|
</el-form-item>
|
</el-form>
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button @click="applyCourseDialog = false">取消</el-button>
|
<el-button type="primary" @click="submit" :loading="submitLoading"
|
>提交</el-button
|
>
|
</div>
|
</template>
|
</el-dialog>
|
<!-- 选择教材弹框 -->
|
<el-dialog v-model="selectTextBookDialog" width="1000" align-center>
|
<template #title>选择教材</template>
|
<div class="textBookList" v-loading="textBookPages.loading">
|
<div class="headerBox" style="padding: 10px">
|
<div class="searchBox" style="float: right">
|
<el-input
|
v-model="selectName"
|
@clear="getTextBook"
|
clearable
|
placeholder="请输入关键字"
|
>
|
<template #append>
|
<el-button
|
type="primary"
|
class="searchBtn"
|
:icon="Search"
|
@click="getTextBook"
|
/>
|
</template>
|
</el-input>
|
</div>
|
</div>
|
<div style="min-height: 370px" v-if="textBookListData.length > 0">
|
<div
|
v-for="(item, index) in textBookListData"
|
:key="index"
|
class="textBookItem"
|
>
|
<el-checkbox
|
class="checkBox"
|
v-model="item.check"
|
@change="selectChange(item)"
|
/>
|
<div class="imgBox autoImgBox">
|
<img :src="item.img" />
|
</div>
|
<p>{{ item.product.name }}</p>
|
</div>
|
</div>
|
<div
|
class="nullBox"
|
v-if="!textBookPages.loading && textBookListData.length == 0"
|
>
|
<el-empty />
|
</div>
|
</div>
|
<div class="pagination-box" v-if="textBookListData.length > 0">
|
<el-pagination
|
v-model:current-page="textBookPages.page"
|
v-model:page-size="textBookPages.pageSize"
|
:background="false"
|
layout="total, prev, pager, next"
|
:total="textBookPages.count"
|
@current-change="handleCurrentChange"
|
/>
|
</div>
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button @click="selectTextBookDialog = false">取消</el-button>
|
<el-button type="primary" @click="selectTextBookSubmit">确定</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script setup lang="ts">
|
import { reactive, ref, onMounted, inject, watch } from "vue";
|
import { Search } from "@element-plus/icons-vue";
|
import { useRouter, useRoute } from "vue-router";
|
import { ElMessage } from "element-plus";
|
// eslint-disable-next-line
|
import { getPublicImage } from "@/assets/js/middleGround/tool.js";
|
// eslint-disable-next-line
|
import defaultImg from "@/assets/images/default-book-img.png";
|
|
const router: any = useRouter();
|
const route: any = useRoute();
|
const MG: any = inject("MG");
|
const selectName = ref("");
|
|
// 申请开课防抖loading
|
const submitLoading = ref(false);
|
|
const courseList: any = ref([]);
|
|
onMounted(() => {
|
getData();
|
});
|
|
const searchKey = ref("");
|
const pages = reactive({
|
page: 1,
|
pageSize: 6,
|
count: 0,
|
loading: true,
|
});
|
|
// 获取课程
|
const getData = () => {
|
pages.loading = true;
|
MG.edu
|
.getAppCourseList({
|
size: pages.pageSize,
|
start: pages.pageSize * pages.page - pages.pageSize,
|
sort: {
|
type: "Desc",
|
field: "CreateDate",
|
},
|
filterList: [],
|
searchList: searchKey.value
|
? [
|
{
|
keywords: searchKey.value,
|
field: "Name",
|
compareType: "Contains",
|
},
|
]
|
: [],
|
})
|
.then((res: any) => {
|
pages.loading = false;
|
pages.count = res.totalSize;
|
courseList.value = res.datas.map((item: any) => {
|
return {
|
...item,
|
name: item.name,
|
id: item.id,
|
icon: item.icon != "default" ? getPublicImage(item.icon, 80) : defaultImg,
|
introduction: item.description,
|
reason: item.applyReturnMsg ? JSON.parse(item.applyReturnMsg).reason : "",
|
};
|
});
|
});
|
};
|
|
// 申请开课
|
const applyCourse = () => {
|
editData.value = null;
|
formData.value = {
|
name: "",
|
bookName: "",
|
bookId: "",
|
selectData: "",
|
desc: "",
|
};
|
applyCourseDialog.value = true;
|
};
|
|
const editData: any = ref(null);
|
const reapplyCourse = (data: any) => {
|
editData.value = data;
|
formData.value = {
|
name: data.name,
|
bookName: data.linkProduct.name,
|
bookId: data.linkProduct.id,
|
selectData: "",
|
desc: data.description,
|
};
|
applyCourseDialog.value = true;
|
};
|
|
// 申请教材弹框
|
const applyCourseDialog = ref(false);
|
const selectTextBookDialog = ref(false);
|
const formData = ref({
|
name: "",
|
bookName: "",
|
bookId: "",
|
selectData: "",
|
desc: "",
|
});
|
|
const selectChange = (select: any) => {
|
for (let i = 0; i < textBookListData.value.length; i++) {
|
const item: any = textBookListData.value[i];
|
if (item.id == select.id) {
|
item.check = true;
|
} else {
|
item.check = false;
|
}
|
}
|
};
|
|
const selectTextBookSubmit = () => {
|
const selectData: any = textBookListData.value.filter((item: any) => item.check)[0];
|
if (!selectData?.product?.id) {
|
ElMessage.warning("请选择开课教材!");
|
return false;
|
}
|
formData.value.bookId = selectData.product.id;
|
formData.value.bookName = selectData.product.name;
|
formData.value.selectData = selectData;
|
selectTextBookDialog.value = false;
|
};
|
|
const submit = () => {
|
submitLoading.value = true;
|
if (editData.value) {
|
MG.edu
|
.updateCourse({
|
courseId: editData.value.id,
|
name: formData.value.name,
|
description: formData.value.desc,
|
})
|
.then((res: any) => {
|
MG.edu
|
.updateCourseApply({
|
courseId: editData.value.id,
|
applyData: JSON.stringify({
|
textBookId: formData.value.bookId,
|
textBookName: formData.value.bookName,
|
}),
|
})
|
.then((ares: any) => {
|
ElMessage.success("课程已重新申请,等待管理员审核。");
|
applyCourseDialog.value = false;
|
getData();
|
});
|
});
|
} else {
|
if (formData.value.name == "") {
|
ElMessage({
|
type: "warning",
|
message: "请填写课程名称",
|
});
|
submitLoading.value = false;
|
return false;
|
}
|
if (!formData.value.bookId) {
|
ElMessage({
|
type: "warning",
|
message: "请选择关联教材",
|
});
|
submitLoading.value = false;
|
return false;
|
}
|
MG.edu
|
.applyNewCourse({
|
name: formData.value.name,
|
description: formData.value.desc,
|
content: "",
|
icon: formData.value.selectData.product.icon ?? "default",
|
type: "course",
|
config: "",
|
applyData: JSON.stringify({
|
textBookId: formData.value.bookId,
|
textBookName: formData.value.bookName,
|
}),
|
linkProductId: formData.value.bookId,
|
maxClassCount: 999,
|
payPrice: 0,
|
})
|
.then((res: any) => {
|
if (res) {
|
ElMessage.success("课程已申请,等待管理员审核。");
|
applyCourseDialog.value = false;
|
getData();
|
}
|
});
|
}
|
formData.value.selectData = "";
|
setTimeout(() => {
|
submitLoading.value = false;
|
}, 1000);
|
};
|
|
// 获取已购买的教材列表
|
const textBookPages = reactive({
|
page: 1,
|
pageSize: 12,
|
count: 0,
|
loading: false,
|
});
|
const textBookListData = ref([]);
|
|
const getTextBook = () => {
|
textBookPages.loading = true;
|
const searchData = [
|
{
|
keywords: "digitalTextbooks",
|
field: "ProductType",
|
},
|
{
|
keywords: "mediaBook",
|
field: "ProductType",
|
},
|
{
|
keywords: selectName.value,
|
field: "ProductName",
|
},
|
];
|
const data = {
|
Size: textBookPages.pageSize,
|
Start: textBookPages.pageSize * textBookPages.page - textBookPages.pageSize,
|
sort: {
|
type: "Desc",
|
field: "CreateDate",
|
},
|
searchList: searchData,
|
};
|
MG.store
|
.getPurchasedProductList(data)
|
.then((res: any) => {
|
textBookPages.count = res.totalSize;
|
textBookListData.value = res.datas.map((item: any) => {
|
return {
|
...item,
|
img: item.product.icon ? getPublicImage(item.product.icon, 80) : defaultImg,
|
};
|
});
|
textBookPages.loading = false;
|
})
|
.catch(() => {
|
textBookPages.loading = false;
|
});
|
};
|
|
// 选择教材
|
const selectBook = () => {
|
selectTextBookDialog.value = true;
|
textBookListData.value = [];
|
getTextBook();
|
};
|
|
const pageChange = (val: any) => {
|
pages.page = val;
|
getData();
|
};
|
const handleCurrentChange = (val: any) => {
|
textBookPages.page = val;
|
getTextBook();
|
};
|
|
const gotoDetail = (data: any) => {
|
if (data.applyState == "Normal") {
|
router.push({
|
name: "courseDetail",
|
query: {
|
courseId: data.id,
|
},
|
});
|
}
|
};
|
</script>
|
|
<style lang="less" scoped>
|
.coursePage {
|
.headerBox {
|
padding: 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;
|
min-height: 200px;
|
|
.courseItem {
|
float: left;
|
width: 46%;
|
height: 210px;
|
margin: 0 2% 20px;
|
border-radius: 8px;
|
border: 1px solid #efefef;
|
overflow: hidden;
|
cursor: pointer;
|
|
.itemHeader {
|
height: 40px;
|
line-height: 40px;
|
padding: 0 20px;
|
background-color: #f8f8f8;
|
.title {
|
font-weight: 600;
|
}
|
|
div {
|
width: 100%;
|
white-space: nowrap;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
word-break: break-all;
|
}
|
}
|
|
.reasonBox {
|
display: flex;
|
padding: 5px 20px;
|
cursor: default;
|
span {
|
font-size: 12px;
|
line-height: 24px;
|
white-space: nowrap;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
}
|
}
|
|
.itemInfo {
|
padding: 10px 20px;
|
flex: 1;
|
display: flex;
|
.imgBox {
|
width: 90px;
|
height: 120px;
|
margin-right: 20px;
|
}
|
.infoBox {
|
flex: 1;
|
font-size: 14px;
|
p {
|
margin-bottom: 10px;
|
}
|
.introduction {
|
height: 88px;
|
line-height: 22px;
|
display: -webkit-box;
|
-webkit-box-orient: vertical;
|
-webkit-line-clamp: 4;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
word-break: break-all;
|
}
|
}
|
.stateIcon {
|
position: absolute;
|
right: -6px;
|
top: -4px;
|
padding: 5px 8px;
|
color: #fff;
|
border-top-left-radius: 30px;
|
border-bottom-right-radius: 30px;
|
border-top-right-radius: 30px;
|
z-index: 99;
|
}
|
}
|
}
|
}
|
}
|
|
.textBookList {
|
overflow: hidden;
|
margin-bottom: 20px;
|
.textBookItem {
|
float: left;
|
width: 160px;
|
height: 220px;
|
margin: 10px;
|
position: relative;
|
border: 1px solid #eee;
|
padding: 20px;
|
box-sizing: border-box;
|
.checkBox {
|
position: absolute;
|
right: 0;
|
top: 0;
|
height: 14px;
|
::v-deep {
|
.el-checkbox__inner {
|
border-color: #888;
|
}
|
}
|
}
|
|
p {
|
line-height: 1.2;
|
display: -webkit-box;
|
-webkit-line-clamp: 2;
|
-webkit-box-orient: vertical;
|
overflow: hidden;
|
}
|
}
|
}
|
|
.autoImgBox {
|
width: 120px;
|
height: 130px;
|
margin-bottom: 10px;
|
position: relative;
|
img {
|
width: auto;
|
height: auto;
|
max-width: 100%;
|
max-height: 100%;
|
position: absolute;
|
top: 0;
|
right: 0;
|
bottom: 0;
|
left: 0;
|
margin: auto;
|
}
|
}
|
|
.pagination-box {
|
display: flex;
|
justify-content: center;
|
padding: 10px 0;
|
}
|
|
.nullBox {
|
text-align: center;
|
margin-top: 30px;
|
font-size: 20px;
|
color: #ccc;
|
}
|
</style>
|