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

chore: 新增数字教材

上级 0c77c29c
差异被折叠。
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
"typescript": "~4.7.4", "typescript": "~4.7.4",
"unplugin-auto-import": "^0.11.3", "unplugin-auto-import": "^0.11.3",
"vite": "^3.1.8", "vite": "^3.1.8",
"vite-plugin-mkcert": "^1.17.6",
"vue-tsc": "^1.0.9" "vue-tsc": "^1.0.9"
} }
} }
...@@ -145,3 +145,9 @@ export function submitPaper(data: { ...@@ -145,3 +145,9 @@ export function submitPaper(data: {
* *
* 考试、测验end * 考试、测验end
*/ */
export function getCourseBook(data: { id: string }) {
return httpRequest.post('/api/ebook/open/teacher/book/getInfoById', data, {
headers: { 'Content-Type': 'application/json' }
})
}
...@@ -28,6 +28,8 @@ const targetUrl = computed(() => { ...@@ -28,6 +28,8 @@ const targetUrl = computed(() => {
return `/course/exam?course_id=${courseId}&semester_id=${semesterId}&paper_id=${props.data.resource_id}&type=2&paper_title=${props.data.name}` 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) { } else if (props.data.resource_type === 6) {
return info.join_url return info.join_url
} else if (props.data.resource_type === 13) {
return `https://zijingebook.ezijing.com/student/book?book_id=${info.book_id}`
} else { } else {
return `/preview?course_id=${courseId}&semester_id=${semesterId}&resource_id=${props.data.resource_id}&resource_type=${props.data.resource_type}&url=${info.url}` return `/preview?course_id=${courseId}&semester_id=${semesterId}&resource_id=${props.data.resource_id}&resource_type=${props.data.resource_type}&url=${info.url}`
} }
...@@ -95,8 +97,7 @@ function downloadFile(data: CourseResourceType) { ...@@ -95,8 +97,7 @@ function downloadFile(data: CourseResourceType) {
:to="`/course/exam/result?course_id=${courseId}&semester_id=${semesterId}&paper_id=${data.resource_id}&type=2&paper_title=${data.name}`" :to="`/course/exam/result?course_id=${courseId}&semester_id=${semesterId}&paper_id=${data.resource_id}&type=2&paper_title=${data.name}`"
target="_blank" target="_blank"
style="margin: 0 20px" style="margin: 0 20px"
v-if="data.paper_status === 2 || data.paper_status === 3" v-if="data.paper_status === 2 || data.paper_status === 3">
>
<el-button round size="small">查看报告</el-button> <el-button round size="small">查看报告</el-button>
</router-link> </router-link>
<template v-if="data.resource_type === 6 && data.info"> <template v-if="data.resource_type === 6 && data.info">
...@@ -108,8 +109,7 @@ function downloadFile(data: CourseResourceType) { ...@@ -108,8 +109,7 @@ function downloadFile(data: CourseResourceType) {
class="icon-star" class="icon-star"
:class="!!data.collection_count ? 'is-active' : ''" :class="!!data.collection_count ? 'is-active' : ''"
@click="toggleCollection(data)" @click="toggleCollection(data)"
v-if="canCollection(data.resource_type)" v-if="canCollection(data.resource_type)"></i>
></i>
<i class="icon-download" @click="downloadFile(data)" v-if="!!data.can_download"><Download /></i> <i class="icon-download" @click="downloadFile(data)" v-if="!!data.can_download"><Download /></i>
</div> </div>
</div> </div>
......
<!-- 直播 -->
<script setup lang="ts">
import CoursePlayerResourceListItem from './CoursePlayerResourceListItem.vue'
import { getCourseBook } from '../api'
const props = defineProps<{ bookId: string }>()
const list = ref([])
function fetchInfo() {
if (!props.bookId) return
getCourseBook({ id: props.bookId }).then(res => {
const book = res.data
const resource = {
id: book.id,
name: book.name,
resource_id: book.id,
resource_type: 13,
info: { book_id: book.id, name: book.name }
}
list.value = [resource]
})
}
onMounted(() => {
fetchInfo()
})
</script>
<template>
<div class="list">
<template v-if="list.length">
<CoursePlayerResourceListItem v-for="item in list" :data="item" :key="item.id" />
</template>
<el-empty description="暂无数据" v-else />
</div>
</template>
...@@ -111,6 +111,8 @@ function targetUrl(resource: CourseResourceType, section: CourseSectionType, cha ...@@ -111,6 +111,8 @@ function targetUrl(resource: CourseResourceType, section: CourseSectionType, cha
return `/course/player?course_id=${courseId}&chapter_id=${chapter.id}&section_id=${section.id}&resource_id=${resource.resource_id}&semester_id=${semesterId}&paper_title=${resource.name}` return `/course/player?course_id=${courseId}&chapter_id=${chapter.id}&section_id=${section.id}&resource_id=${resource.resource_id}&semester_id=${semesterId}&paper_title=${resource.name}`
} else if (resource.resource_type === 6) { } else if (resource.resource_type === 6) {
return resource.info.join_url return resource.info.join_url
} else if (resource.resource_type === 13) {
return `https://zijingebook.ezijing.com/student/book?book_id=${resource.info.book_id}&chapter_id=${resource.info.chapter_id}`
} else { } else {
return `/preview?course_id=${courseId}&semester_id=${semesterId}&resource_id=${resource.resource_id}&resource_type=${resource.resource_type}&url=${resource.info?.url}` return `/preview?course_id=${courseId}&semester_id=${semesterId}&resource_id=${resource.resource_id}&resource_type=${resource.resource_type}&url=${resource.info?.url}`
} }
......
<script setup lang="ts"> <script setup lang="ts">
import type { CourseResourceType, CourseChapterType } from '../types' import type { CourseResourceType, CourseChapterType } from '../types'
import { getCourseSection, getChapterTreeList } from '../api' import { getCourse, getCourseSection, getChapterTreeList } from '../api'
import CoursePlayerResourceList from '../components/CoursePlayerResourceList.vue' import CoursePlayerResourceList from '../components/CoursePlayerResourceList.vue'
import { ArrowLeftBold, ArrowRightBold } from '@element-plus/icons-vue' import { ArrowLeftBold, ArrowRightBold } from '@element-plus/icons-vue'
import type { VideoJsPlayer } from 'video.js' import type { VideoJsPlayer } from 'video.js'
...@@ -10,6 +10,7 @@ const { mobile } = useDevice() ...@@ -10,6 +10,7 @@ const { mobile } = useDevice()
const CoursePlayerVideo = defineAsyncComponent(() => import('../components/CoursePlayerVideo.vue')) const CoursePlayerVideo = defineAsyncComponent(() => import('../components/CoursePlayerVideo.vue'))
const CoursePlayerChapter = defineAsyncComponent(() => import('../components/CoursePlayerChapter.vue')) const CoursePlayerChapter = defineAsyncComponent(() => import('../components/CoursePlayerChapter.vue'))
const CourseViewBook = defineAsyncComponent(() => import('../components/CourseViewBook.vue'))
const route = useRoute() const route = useRoute()
let courseId = $ref<string>('') let courseId = $ref<string>('')
...@@ -53,6 +54,19 @@ function fetchInfo() { ...@@ -53,6 +54,19 @@ function fetchInfo() {
watchEffect(() => { watchEffect(() => {
fetchInfo() fetchInfo()
}) })
// 获取课程详情信息
const course = ref({ name: '', ebook_id: '' })
function fetchCourseInfo() {
if (!courseId || !semesterId) return
getCourse({ course_id: courseId, semester_id: semesterId }).then(res => {
course.value = res.data.detail
})
}
watchEffect(() => {
fetchCourseInfo()
})
let chapterList = $ref<CourseChapterType[]>([]) let chapterList = $ref<CourseChapterType[]>([])
// 获取章节列表 // 获取章节列表
function fetchList() { function fetchList() {
...@@ -97,7 +111,11 @@ function toggleSidebar() { ...@@ -97,7 +111,11 @@ function toggleSidebar() {
</div> </div>
<div class="course-player-bd"> <div class="course-player-bd">
<div class="course-player-main" v-loading="loading"> <div class="course-player-main" v-loading="loading">
<CoursePlayerVideo :chapterList="chapterList" :key="sectionId" @updateResource="onUpdateResource" @timeupdate="onTimeUpdate" /> <CoursePlayerVideo
:chapterList="chapterList"
:key="sectionId"
@updateResource="onUpdateResource"
@timeupdate="onTimeUpdate" />
<el-tabs :stretch="mobile"> <el-tabs :stretch="mobile">
<el-tab-pane label="课件"> <el-tab-pane label="课件">
<CoursePlayerResourceList :list="detail.coursewares" /> <CoursePlayerResourceList :list="detail.coursewares" />
...@@ -117,11 +135,18 @@ function toggleSidebar() { ...@@ -117,11 +135,18 @@ function toggleSidebar() {
<el-tab-pane label="直播" lazy> <el-tab-pane label="直播" lazy>
<CoursePlayerResourceList :list="detail.meetings" /> <CoursePlayerResourceList :list="detail.meetings" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="数字教材" lazy>
<CourseViewBook :bookId="course.ebook_id"></CourseViewBook>
</el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
<div class="course-player-aside" :class="{ 'is-hidden': !sidebarVisible }"> <div class="course-player-aside" :class="{ 'is-hidden': !sidebarVisible }">
<div class="course-player-aside__inner"> <div class="course-player-aside__inner">
<CoursePlayerChapter :chapterList="chapterList" :pptList="pptList" :pptIndex="pptIndex" @clickPPT="onClickPPT" /> <CoursePlayerChapter
:chapterList="chapterList"
:pptList="pptList"
:pptIndex="pptIndex"
@clickPPT="onClickPPT" />
</div> </div>
<div class="toggle-button" :class="{ 'is-hidden': !sidebarVisible }" @click="toggleSidebar"> <div class="toggle-button" :class="{ 'is-hidden': !sidebarVisible }" @click="toggleSidebar">
<el-icon> <el-icon>
......
...@@ -14,6 +14,7 @@ const CourseViewExam = defineAsyncComponent(() => import('../components/CourseVi ...@@ -14,6 +14,7 @@ const CourseViewExam = defineAsyncComponent(() => import('../components/CourseVi
const CourseViewAssess = defineAsyncComponent(() => import('../components/CourseViewAssess.vue')) const CourseViewAssess = defineAsyncComponent(() => import('../components/CourseViewAssess.vue'))
const CourseViewLive = defineAsyncComponent(() => import('../components/CourseViewLive.vue')) const CourseViewLive = defineAsyncComponent(() => import('../components/CourseViewLive.vue'))
const CourseViewMaterial = defineAsyncComponent(() => import('../components/CourseViewMaterial.vue')) const CourseViewMaterial = defineAsyncComponent(() => import('../components/CourseViewMaterial.vue'))
const CourseViewBook = defineAsyncComponent(() => import('../components/CourseViewBook.vue'))
const { query } = useRoute() const { query } = useRoute()
const courseId = $ref<string | null>(query.course_id as string) const courseId = $ref<string | null>(query.course_id as string)
...@@ -117,8 +118,7 @@ const handleDetail = function () { ...@@ -117,8 +118,7 @@ const handleDetail = function () {
<div <div
:class="infoIndex === 1 ? 'btn active' : 'btn'" :class="infoIndex === 1 ? 'btn active' : 'btn'"
@click="showInfo(props.data?.previous_preparation, 1)" @click="showInfo(props.data?.previous_preparation, 1)"
v-if="false" v-if="false">
>
预备知识 预备知识
</div> </div>
<div :class="infoIndex === 2 ? 'btn active' : 'btn'" @click="showInfo(props.data?.target, 2)"> <div :class="infoIndex === 2 ? 'btn active' : 'btn'" @click="showInfo(props.data?.target, 2)">
...@@ -177,6 +177,9 @@ const handleDetail = function () { ...@@ -177,6 +177,9 @@ const handleDetail = function () {
<el-tab-pane label="资料" lazy> <el-tab-pane label="资料" lazy>
<CourseViewMaterial /> <CourseViewMaterial />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="数字教材" lazy>
<CourseViewBook :bookId="detail.ebook_id"></CourseViewBook>
</el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
<template v-if="props.data?.length !== 1"> <template v-if="props.data?.length !== 1">
......
...@@ -58,7 +58,7 @@ httpRequest.interceptors.response.use( ...@@ -58,7 +58,7 @@ httpRequest.interceptors.response.use(
return Promise.reject(data) return Promise.reject(data)
} }
if (Object.hasOwnProperty.call(data, 'code') && data.code !== 0) { if (Object.hasOwnProperty.call(data, 'code') && data.code !== 0 && data.code !== 200) {
ElMessage.error(data.message || data.msg) ElMessage.error(data.message || data.msg)
return Promise.reject(data) return Promise.reject(data)
} }
......
import fs from 'fs' // import fs from 'fs'
import path from 'path' // import path from 'path'
import { fileURLToPath, URL } from 'url' import { fileURLToPath, URL } from 'url'
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue' import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite' import AutoImport from 'unplugin-auto-import/vite'
import mkcert from 'vite-plugin-mkcert'
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({ export default defineConfig(({ mode }) => ({
base: mode === 'prod' ? 'https://webapp-pub.ezijing.com/website/prod/saas-learn/' : '/', base: mode === 'prod' ? 'https://webapp-pub.ezijing.com/website/prod/saas-learn/' : '/',
plugins: [ plugins: [
mkcert(),
vue({ reactivityTransform: true }), vue({ reactivityTransform: true }),
AutoImport({ AutoImport({
imports: ['vue', 'vue/macros', 'vue-router'], imports: ['vue', 'vue/macros', 'vue-router'],
...@@ -25,10 +27,10 @@ export default defineConfig(({ mode }) => ({ ...@@ -25,10 +27,10 @@ export default defineConfig(({ mode }) => ({
server: { server: {
open: true, open: true,
host: 'dev.ezijing.com', host: 'dev.ezijing.com',
https: { // https: {
key: fs.readFileSync(path.join(__dirname, './https/dev.ezijing.com.key')), // key: fs.readFileSync(path.join(__dirname, './https/dev.ezijing.com.key')),
cert: fs.readFileSync(path.join(__dirname, './https/dev.ezijing.com.pem')) // cert: fs.readFileSync(path.join(__dirname, './https/dev.ezijing.com.pem'))
}, // },
proxy: { proxy: {
'/api': 'https://saas-learn.ezijing.com' '/api': 'https://saas-learn.ezijing.com'
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论