提交 2168950e authored 作者: 王鹏飞's avatar 王鹏飞

chore: update

上级 cc9a93d1
......@@ -60,7 +60,7 @@ export function submitCourseWork(data: {
return httpRequest.post('/api/learn/api/v1/job/submit', data)
}
// 获取课程直播列表
// 获取课程考试列表
export function getCourseExamList(params: { course_id: string; semester_id: string }) {
return httpRequest.get('/api/learn/api/v1/question-bank/papers', { params })
}
......@@ -70,6 +70,11 @@ export function getCourseLiveList(data: { course_id: string; semester_id: string
return httpRequest.post('/api/learn/api/v1/meeting/list', data)
}
// 获取课程资料列表
export function getCourseMaterialList(params: { course_id: string; semester_id: string }) {
return httpRequest.get(`/api/learn/api/v1/course/${params.course_id}/${params.semester_id}/informations`, { params })
}
// 获取课程小节信息
export function getCourseSection(data: { section_id: string; semester_id: string }) {
return httpRequest.post('/api/learn/api/v1/chapter/section/detail', data)
......
......@@ -55,10 +55,10 @@ function toggleCollection(data: CourseResourceType) {
}
// 是否可以下载
function canDownload(type: number) {
// return [4, 10, 11].includes(type)
return [4].includes(type)
}
// function canDownload(type: number) {
// // return [4, 10, 11].includes(type)
// return [4].includes(type)
// }
// 下载资源
function downloadFile(data: CourseResourceType) {
const { url, name } = data.info
......@@ -110,7 +110,7 @@ function downloadFile(data: CourseResourceType) {
@click="toggleCollection(data)"
v-if="canCollection(data.resource_type)"
></i>
<i class="icon-download" @click="downloadFile(data)" v-if="canDownload(data.resource_type)"><Download /></i>
<i class="icon-download" @click="downloadFile(data)" v-if="!!data.can_download"><Download /></i>
</div>
</div>
</template>
......
......@@ -77,10 +77,10 @@ function toggleCollection(resource: CourseResourceType, section: CourseSectionTy
})
}
// 是否可以下载
function canDownload(type: number) {
// return [4, 10, 11].includes(type)
return [4].includes(type)
}
// function canDownload(type: number) {
// // return [4, 10, 11].includes(type)
// return [4].includes(type)
// }
// 下载资源
function downloadFile(data: CourseResourceType) {
const { url, name } = data.info
......@@ -156,7 +156,7 @@ function targetUrl(resource: CourseResourceType, section: CourseSectionType, cha
@click="toggleCollection(resource, section, item)"
v-if="canCollection(resource)"
></i>
<i class="icon-download" @click="downloadFile(resource)" v-if="canDownload(resource.resource_type)">
<i class="icon-download" @click="downloadFile(resource)" v-if="!!resource.can_download">
<Download />
</i>
</div>
......
<!-- 直播 -->
<script setup lang="ts">
import type { LiveType } from '@/types'
import CourseViewMaterialListItem from './CourseViewMaterialListItem.vue'
import { getCourseMaterialList } from '../api'
const { query } = useRoute()
const courseId = $ref(query.course_id as string)
const semesterId = $ref(query.semester_id as string)
let list = $ref<LiveType[]>([])
function fetchList() {
getCourseMaterialList({ course_id: courseId, semester_id: semesterId }).then(res => {
list = res.data.items
})
}
onMounted(() => {
fetchList()
})
</script>
<template>
<div class="course-live">
<template v-if="list.length">
<CourseViewMaterialListItem v-for="item in list" :data="item" :key="item.id"></CourseViewMaterialListItem>
</template>
<el-empty description="暂无数据" v-else />
</div>
</template>
<script setup lang="ts">
import type { CourseResourceType } from '../types'
import ResourceIcon from '@/components/ResourceIcon.vue'
import { Download } from '@element-plus/icons-vue'
import { saveAs } from 'file-saver'
import { collectionResource } from '../api'
import { useLog } from '@/composables/useLog'
const log = useLog()
const { query } = useRoute()
const courseId = $ref(query.course_id as string)
const chapterId = $ref(query.chapter_id as string)
const semesterId = $ref(query.semester_id as string)
const sectionId = $ref(query.section_id as string)
interface Props {
data: CourseResourceType
}
const props = defineProps<Props>()
// 跳转链接
const targetUrl = computed(() => {
const info = props.data.info || {}
if (props.data.resource_type === 3 || props.data.resource_type === 9) {
return `/course/exam?course_id=${courseId}&semester_id=${semesterId}&paper_id=${props.data.resource_id}&type=2&paper_title=${props.data.name}`
} else if (props.data.resource_type === 6) {
return info.join_url
} else {
return `/preview?course_id=${courseId}&semester_id=${semesterId}&resource_id=${props.data.resource_id}&resource_type=${props.data.resource_type}&url=${info.url}`
}
})
// 是否可以收藏
function canCollection(type: number) {
return [3, 4, 9, 10, 11].includes(type)
}
// 收藏/取消收藏
function toggleCollection(data: CourseResourceType) {
// 资源类型: 1章节,2视频,3作业,4其他,6腾讯会议,9考试,10课件,11教案
// 收藏类型: 1其他, 2视频,3课件,4教案,5作业,6帖子
const typeMap: Record<number, number> = { 4: 1, 2: 2, 10: 3, 11: 4, 3: 5, 9: 5 }
collectionResource({
course_id: courseId,
semester_id: semesterId,
chapter_id: chapterId,
section_id: sectionId,
source_id: data.resource_id,
type: typeMap[data.resource_type],
status: data.collection_count ? 0 : 1
}).then(() => {
data.collection_count = data.collection_count ? 0 : 1
})
}
// 是否可以下载
// function canDownload(type: number) {
// // return [4, 10, 11].includes(type)
// return [4].includes(type)
// }
// 下载资源
function downloadFile(data: CourseResourceType) {
const { url, name } = data.info
const urlExtensionName = url?.split('.').pop()
const nameExtensionName = name?.split('.').pop()
const filename = nameExtensionName === urlExtensionName ? name : `${name}.${urlExtensionName}`
url && saveAs(url, filename)
// 日志上送
log.upload({
event: 'file_event',
action: 'stu_download_file_action',
data: {
course_id: courseId,
resource_id: data.info.id,
resource_type: data.resource_type,
download_time: Math.floor(Date.now() / 1000),
download_name: name,
download_size: data.info.size
}
})
}
</script>
<template>
<div class="course-resource-item">
<p>
<a :href="targetUrl" target="_blank">
<ResourceIcon :resourceType="data.resource_type" :info="data.info" />
{{ data.info.name }}
</a>
</p>
<div class="actions">
<i
class="icon-star"
:class="!!data.collection_count ? 'is-active' : ''"
@click="toggleCollection(data)"
v-if="canCollection(data.resource_type)"
></i>
<i class="icon-download" @click="downloadFile(data)" v-if="!!data.can_download"><Download /></i>
</div>
</div>
</template>
<style lang="scss" scoped>
.course-resource-item {
display: flex;
align-items: center;
height: 48px;
padding: 0 20px;
border-bottom: 1px solid #e6e6e6;
p {
flex: 1;
line-height: 48px;
}
&:hover {
color: var(--main-color);
}
.actions {
min-width: 60px;
display: flex;
align-items: center;
justify-content: space-between;
&:empty {
min-width: auto;
}
}
}
.icon-star {
display: inline-block;
width: 16px;
height: 16px;
background: url(@/assets/images/icon_star.png) no-repeat;
background-size: contain;
cursor: pointer;
&.is-active {
background: url(@/assets/images/icon_star_hover.png) no-repeat;
background-size: contain;
}
}
.icon-download {
display: inline-block;
width: 20px;
height: 20px;
cursor: pointer;
}
</style>
......@@ -51,6 +51,7 @@ export interface CourseResourceType {
depth: number
is_finished?: number
paper_status?: number
can_download: number
}
export interface VideoRecordType {
......
......@@ -9,6 +9,7 @@ const CourseViewWork = defineAsyncComponent(() => import('../components/CourseVi
const CourseViewExam = defineAsyncComponent(() => import('../components/CourseViewExam.vue'))
const CourseViewAssess = defineAsyncComponent(() => import('../components/CourseViewAssess.vue'))
const CourseViewLive = defineAsyncComponent(() => import('../components/CourseViewLive.vue'))
const CourseViewMaterial = defineAsyncComponent(() => import('../components/CourseViewMaterial.vue'))
const { query } = useRoute()
const courseId = $ref<string | null>(query.course_id as string)
......@@ -133,6 +134,9 @@ function showInfo(title: string, content: string) {
<el-tab-pane label="直播" lazy>
<CourseViewLive />
</el-tab-pane>
<el-tab-pane label="资料" lazy>
<CourseViewMaterial />
</el-tab-pane>
</el-tabs>
</div>
</div>
......
import type { CourseType, ResourceType } from '@/types'
import type { CourseType, ChapterType, ResourceType } from '@/types'
export interface CollectionType {
chapter_id: string
......@@ -12,6 +12,9 @@ export interface CollectionType {
status: number
type: number
resource_type: number
can_download: number
course: Pick<CourseType, 'id' | 'name' | 'course_id'>
chapter: Pick<ChapterType, 'id' | 'name'>
}
export interface CollectionSemesterType {
......
......@@ -74,10 +74,10 @@ function toggleCollection(data: CollectionType) {
})
}
// 是否可以下载
function canDownload(type: number) {
// return [1, 3, 4].includes(type)
return [1].includes(type)
}
// function canDownload(type: number) {
// // return [1, 3, 4].includes(type)
// return [1].includes(type)
// }
// 下载资源
function downloadFile(data: CollectionType) {
const { url, name } = data.info
......@@ -124,12 +124,15 @@ function targetUrl(item: CollectionType) {
{{ item.info.name || item.info.paper_title }}
</router-link>
</p>
<p>{{ item.course.name }}/{{ item.chapter.name }}</p>
<div class="collection-item-aside">
<div class="video-duration" v-if="item.type === 2">
{{ formatDuration(item.info.length) }}
</div>
<div class="actions">
<i class="icon-star" :class="!!item.status ? 'is-active' : ''" @click="toggleCollection(item)"></i>
<i class="icon-download" @click="downloadFile(item)" v-if="canDownload(item.type)"><Download /></i>
<i class="icon-download" @click="downloadFile(item)" v-if="!!item.can_download"><Download /></i>
</div>
</div>
</li>
</ul>
......@@ -146,6 +149,12 @@ function targetUrl(item: CollectionType) {
p {
flex: 1;
line-height: 48px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
p + p {
margin-left: 20px;
}
&:hover {
color: var(--main-color);
......@@ -163,6 +172,12 @@ function targetUrl(item: CollectionType) {
line-height: 1;
}
}
.collection-item-aside {
min-width: 200px;
display: flex;
align-items: center;
justify-content: flex-end;
}
.icon-star {
display: inline-block;
width: 16px;
......
......@@ -84,6 +84,7 @@ export interface FileType {
size: number
source_id: string
ppt_arr?: PptType[]
can_download: number
}
export interface PptType {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论