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

chore: update

上级 d4e70689
......@@ -4,7 +4,7 @@ import httpRequest from '@/utils/axios'
// 获取Key
export function getPageKey() {
return httpRequest.get('/api/log/api/v1/client/page-key')
return httpRequest.get('/api/meta/api/v1/client/page-key')
}
/**
......@@ -15,5 +15,5 @@ export function getPageKey() {
*/
export function setMetaInfo(data: { event: string; action: string; data: string }) {
return httpRequest.post('/api/log/api/v1/client/set-meta-info', data)
return httpRequest.post('/api/meta/api/v1/client/set-meta-info', data)
}
src/assets/images/icon_chapter.png

479 Bytes | W: | H:

src/assets/images/icon_chapter.png

586 Bytes | W: | H:

src/assets/images/icon_chapter.png
src/assets/images/icon_chapter.png
src/assets/images/icon_chapter.png
src/assets/images/icon_chapter.png
  • 2-up
  • Swipe
  • Onion skin
src/assets/images/icon_doc.png

1.8 KB | W: | H:

src/assets/images/icon_doc.png

913 Bytes | W: | H:

src/assets/images/icon_doc.png
src/assets/images/icon_doc.png
src/assets/images/icon_doc.png
src/assets/images/icon_doc.png
  • 2-up
  • Swipe
  • Onion skin
src/assets/images/icon_exam.png

441 Bytes | W: | H:

src/assets/images/icon_exam.png

548 Bytes | W: | H:

src/assets/images/icon_exam.png
src/assets/images/icon_exam.png
src/assets/images/icon_exam.png
src/assets/images/icon_exam.png
  • 2-up
  • Swipe
  • Onion skin
src/assets/images/icon_live.png

707 Bytes | W: | H:

src/assets/images/icon_live.png

850 Bytes | W: | H:

src/assets/images/icon_live.png
src/assets/images/icon_live.png
src/assets/images/icon_live.png
src/assets/images/icon_live.png
  • 2-up
  • Swipe
  • Onion skin
src/assets/images/icon_mp3.png

1.7 KB | W: | H:

src/assets/images/icon_mp3.png

938 Bytes | W: | H:

src/assets/images/icon_mp3.png
src/assets/images/icon_mp3.png
src/assets/images/icon_mp3.png
src/assets/images/icon_mp3.png
  • 2-up
  • Swipe
  • Onion skin
src/assets/images/icon_mp4.png

1.7 KB | W: | H:

src/assets/images/icon_mp4.png

809 Bytes | W: | H:

src/assets/images/icon_mp4.png
src/assets/images/icon_mp4.png
src/assets/images/icon_mp4.png
src/assets/images/icon_mp4.png
  • 2-up
  • Swipe
  • Onion skin
src/assets/images/icon_pdf.png

1.7 KB | W: | H:

src/assets/images/icon_pdf.png

774 Bytes | W: | H:

src/assets/images/icon_pdf.png
src/assets/images/icon_pdf.png
src/assets/images/icon_pdf.png
src/assets/images/icon_pdf.png
  • 2-up
  • Swipe
  • Onion skin
src/assets/images/icon_png.png

1.6 KB | W: | H:

src/assets/images/icon_png.png

774 Bytes | W: | H:

src/assets/images/icon_png.png
src/assets/images/icon_png.png
src/assets/images/icon_png.png
src/assets/images/icon_png.png
  • 2-up
  • Swipe
  • Onion skin
src/assets/images/icon_ppt.png

1.7 KB | W: | H:

src/assets/images/icon_ppt.png

862 Bytes | W: | H:

src/assets/images/icon_ppt.png
src/assets/images/icon_ppt.png
src/assets/images/icon_ppt.png
src/assets/images/icon_ppt.png
  • 2-up
  • Swipe
  • Onion skin
src/assets/images/icon_rar.png

657 Bytes | W: | H:

src/assets/images/icon_rar.png

788 Bytes | W: | H:

src/assets/images/icon_rar.png
src/assets/images/icon_rar.png
src/assets/images/icon_rar.png
src/assets/images/icon_rar.png
  • 2-up
  • Swipe
  • Onion skin
src/assets/images/icon_work.png

684 Bytes | W: | H:

src/assets/images/icon_work.png

751 Bytes | W: | H:

src/assets/images/icon_work.png
src/assets/images/icon_work.png
src/assets/images/icon_work.png
src/assets/images/icon_work.png
  • 2-up
  • Swipe
  • Onion skin
src/assets/images/icon_xls.png

1.5 KB | W: | H:

src/assets/images/icon_xls.png

895 Bytes | W: | H:

src/assets/images/icon_xls.png
src/assets/images/icon_xls.png
src/assets/images/icon_xls.png
src/assets/images/icon_xls.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -79,3 +79,21 @@ textarea:focus {
:root {
--main-color: #aa1941;
}
.el-tabs__item {
--el-font-size-base: 16px;
padding: 0 20px !important;
min-width: 60px;
font-weight: 400;
text-align: center;
}
.el-tabs__item.is-active {
font-weight: 500;
}
.el-tabs__active-bar {
padding: 0 20px;
margin-left: -20px;
}
.el-tabs__nav-wrap::after {
height: 1px !important;
}
......@@ -31,7 +31,7 @@ function show(fileType: string) {
display: inline-block;
img {
margin-right: 10px;
width: 14px;
width: 16px;
}
}
</style>
......@@ -18,7 +18,7 @@ export default { name: 'AppMain' }
overflow: hidden;
}
.app-main-inner {
max-width: 1440px;
/* max-width: 1440px; */
height: 100%;
margin: 0 auto;
}
......
......@@ -49,7 +49,7 @@ function handleTop(data: CourseListItemType) {
</script>
<template>
<div class="course-item" :class="{ 'is-active': isActive }">
<div class="course-item" :class="{ 'is-active': isActive, 'is-top': !!data.is_top }">
<el-tooltip :content="!!data.is_top ? '取消置顶' : '置顶'">
<div class="course-item__top" :class="{ 'is-active': !!data.is_top }" @click="handleTop(data)"></div>
</el-tooltip>
......@@ -60,13 +60,17 @@ function handleTop(data: CourseListItemType) {
</div>
<div class="course-item-main">
<h2 class="course-item__name">{{ data.name }}</h2>
<div class="course-item-progress">总进度<el-progress :percentage="parseFloat(data.schedule)" /></div>
</div>
</div>
<div class="course-item-progress">
总进度<el-progress :stroke-width="4" :percentage="parseFloat(data.schedule)" />
</div>
</router-link>
<div class="course-item-ft">
<div class="course-item-playlist" v-if="data.section?.watch_video_length">
<p class="t1">{{ data.section.name }}</p>
<p class="t1">
<el-tooltip :content="data.section.name">{{ data.section.name }}</el-tooltip>
</p>
<p class="t2">已观看{{ data.section.schedule }}%</p>
<router-link :to="`/course/player?${targetUrlQuery}`" target="_blank">
<el-button type="primary" round>点击观看</el-button>
......@@ -83,9 +87,13 @@ function handleTop(data: CourseListItemType) {
padding: 12px;
margin: 20px 0;
border: 1px solid #e6e6e6;
box-shadow: 0px 3px 10px rgba(0, 0, 0, 0.12);
border-radius: 6px;
&.is-top {
background: rgba(247, 248, 250, 0.39);
}
&:hover,
&.is-active {
box-shadow: 0px 3px 10px rgba(0, 0, 0, 0.12);
background: rgba(247, 248, 250, 1);
}
}
......@@ -110,8 +118,8 @@ function handleTop(data: CourseListItemType) {
}
.course-item-pic {
position: relative;
width: 90px;
height: 90px;
width: 108px;
height: 72px;
border-radius: 4px;
overflow: hidden;
img {
......@@ -123,9 +131,9 @@ function handleTop(data: CourseListItemType) {
position: absolute;
top: 0;
right: 0;
padding: 0 2px;
padding: 0 4px;
font-size: 10px;
line-height: 16px;
line-height: 18px;
color: #dbdbdb;
background: rgba(0, 0, 0, 0.39);
border-radius: 0px 4px 0px 4px;
......@@ -149,7 +157,7 @@ function handleTop(data: CourseListItemType) {
}
}
.course-item-progress {
margin-top: 10px;
margin-top: 8px;
display: flex;
align-items: center;
color: #999;
......@@ -157,10 +165,13 @@ function handleTop(data: CourseListItemType) {
:deep(.el-progress) {
flex: 1;
margin-left: 5px;
.el-progress__text {
font-size: 12px !important;
}
}
}
.course-item-ft {
margin-top: 10px;
margin-top: 8px;
font-size: 12px;
line-height: 20px;
color: #535353;
......
......@@ -192,12 +192,18 @@ const filterList = computed(() => {
}
.el-checkbox-button {
margin-bottom: 10px;
--el-checkbox-button-checked-text-color: var(--el-color-primary);
--el-checkbox-button-checked-bg-color: #f7e9ec;
--el-checkbox-button-checked-border-color: var(--el-color-primary);
--el-checkbox-button-border-color: #adadad;
}
.el-checkbox-button__inner {
padding: 10px 20px;
border: 1px solid #adadad !important;
border-left: var(--el-border);
border-radius: 18px !important;
box-shadow: none !important;
&:hover {
border-color: var(--el-checkbox-button-checked-border-color);
}
}
}
</style>
......@@ -41,7 +41,7 @@ function formatDuration(duration: number | undefined) {
<template>
<div class="course-player-chapter">
<el-tabs v-model="activeTab">
<el-tabs v-model="activeTab" stretch>
<el-tab-pane label="章节" name="chapter">
<dl v-for="(item, index) in chapterList" :key="item.id">
<dt>
......@@ -84,15 +84,16 @@ function formatDuration(duration: number | undefined) {
float: none;
display: flex;
}
:deep(.el-tabs__active-bar) {
display: none;
}
:deep(.el-tabs__item) {
flex: 1;
height: 40px;
font-size: 16px;
line-height: 40px;
color: #fff;
text-align: center;
color: #89898b;
&.is-active {
color: var(--main-color);
color: #fff;
}
}
dl {
......
......@@ -56,7 +56,8 @@ function toggleCollection(data: CourseResourceType) {
// 是否可以下载
function canDownload(type: number) {
return [4, 10, 11].includes(type)
// return [4, 10, 11].includes(type)
return [4].includes(type)
}
// 下载资源
function downloadFile(data: CourseResourceType) {
......
......@@ -4,7 +4,9 @@ import type { VideoJsPlayer, VideoJsPlayerOptions } from 'video.js'
import { throttle } from 'lodash'
import { useStorage, useElementVisibility } from '@vueuse/core'
import { Swiper, SwiperSlide } from 'swiper/vue'
import { Navigation } from 'swiper'
import 'swiper/css'
import 'swiper/css/navigation'
import AppVideoPlayer from '@/components/base/AppVideoPlayer.vue'
import { getCoursePlayInfo, getVideoRecords, uploadVideoRecords } from '../api'
import { useLog } from '@/composables/useLog'
......@@ -266,6 +268,7 @@ onUnmounted(() => {
</script>
<template>
<div class="course-player-wrapper">
<div ref="playerWrapperRef" :style="resource ? `height: 510px` : ''">
<div class="player-box" :class="{ 'is-pinned': !playerIsVisible }">
<AppVideoPlayer
......@@ -312,7 +315,7 @@ onUnmounted(() => {
</ul>
</el-popover>
</teleport>
<swiper :slidesPerView="'auto'" :spaceBetween="30">
<swiper :slidesPerView="'auto'" :spaceBetween="30" navigation :modules="[Navigation]">
<swiper-slide
v-for="item in sectionVideoList"
:key="item.id"
......@@ -320,13 +323,20 @@ onUnmounted(() => {
:class="{ 'is-active': item.resource_id === resourceId }"
@click="changeResource(item)"
>
<div class="video-item-pic">
<img :src="item.info?.cover" />
</div>
<p>{{ item.info.name }}</p>
</swiper-slide>
</swiper>
</div>
</template>
<style lang="scss" scoped>
.course-player-wrapper {
margin-bottom: 40px;
border-bottom: 1px solid #e2e2e2;
}
.player-box {
width: 100%;
height: 100%;
......@@ -355,36 +365,43 @@ onUnmounted(() => {
.video-item {
position: relative;
margin: 20px 0;
width: 200px;
height: 100px;
border-radius: 5px;
width: 238px;
cursor: pointer;
overflow: hidden;
box-sizing: border-box;
p {
position: absolute;
left: 0;
right: 0;
bottom: 0;
padding: 0 10px;
padding: 0 8px;
font-size: 14px;
line-height: 30px;
color: #fff;
background-color: rgba(0, 0, 0, 0.5);
text-align: center;
color: #333;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
&:hover,
&.is-active {
img {
transform: scale(1.05);
}
p {
color: var(--main-color);
}
}
}
.video-item-pic {
width: 100%;
height: 148px;
border-radius: 10px;
box-sizing: border-box;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
&.is-active {
border: 2px solid var(--main-color);
transition: all 0.25s ease-in-out;
}
}
.video-definition {
font-size: 12px;
li {
......@@ -422,4 +439,14 @@ onUnmounted(() => {
padding: 0;
margin-bottom: -12px !important;
}
:deep(.swiper-button-next),
:deep(.swiper-button-prev) {
margin-top: -30px;
--swiper-navigation-size: 14px;
width: 34px;
height: 34px;
color: #fff;
background: #303133;
border-radius: 50%;
}
</style>
......@@ -78,7 +78,8 @@ function toggleCollection(resource: CourseResourceType, section: CourseSectionTy
}
// 是否可以下载
function canDownload(type: number) {
return [4, 10, 11].includes(type)
// return [4, 10, 11].includes(type)
return [4].includes(type)
}
// 下载资源
function downloadFile(data: CourseResourceType) {
......@@ -113,10 +114,16 @@ function targetUrl(resource: CourseResourceType, section: CourseSectionType, cha
<template>
<el-collapse class="course-chapters" v-model="chapterIds" v-if="chapterList.length">
<el-collapse-item :name="item.id" v-for="item in chapterList" :key="item.id">
<template #title><i class="icon-chapter"></i>{{ item.name }}</template>
<template #title
><i class="icon-chapter"></i>
<p class="chapter-title">{{ item.name }}</p></template
>
<el-collapse class="course-sections" v-model="sectionIds">
<el-collapse-item :name="section.id" v-for="section in item.sections" :key="section.id">
<template #title><i class="icon-chapter"></i>{{ section.name }}</template>
<template #title
><i class="icon-chapter"></i>
<p class="section-title">{{ section.name }}</p></template
>
<ul>
<li class="course-resource-item" v-for="resource in section.resources" :key="resource.id">
<p>
......@@ -175,6 +182,7 @@ function targetUrl(resource: CourseResourceType, section: CourseSectionType, cha
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
color: #666;
}
a {
&:hover {
......@@ -217,8 +225,8 @@ function targetUrl(resource: CourseResourceType, section: CourseSectionType, cha
.icon-chapter {
margin-right: 10px;
display: inline-block;
width: 12px;
height: 14px;
width: 16px;
height: 20px;
background: url(@/assets/images/icon_chapter.png) no-repeat;
background-size: contain;
}
......@@ -237,6 +245,16 @@ function targetUrl(resource: CourseResourceType, section: CourseSectionType, cha
border-bottom: none;
}
}
.chapter-title {
font-size: 16px;
font-weight: 500;
color: #333333;
}
.section-title {
font-size: 14px;
font-weight: 400;
color: #333333;
}
.el-collapse {
border-top: none;
border-bottom: none;
......
......@@ -4,6 +4,8 @@ import CourseListItem from '../components/CourseListItem.vue'
import type { CourseListParamsType, CourseListItemType } from '../types'
import { getCourseList } from '../api'
const router = useRouter()
const route = useRoute()
// 列表参数
const listParams = reactive<CourseListParamsType>({ id: '', semester_ids: [], elective_types: [] })
let courseList = $ref<CourseListItemType[]>([])
......@@ -15,6 +17,11 @@ function fetchList() {
})
getCourseList(params).then(res => {
courseList = res.data.data
const [first] = courseList
// 进入第一个课程详情页
if (first && route.path === '/course') {
router.push({ path: '/course/view', query: { course_id: first.course_id, semester_id: first.semester_id } })
}
})
}
// 筛选
......
......@@ -160,10 +160,12 @@ function toggleSidebar() {
.course-player-aside {
position: relative;
width: 258px;
margin-left: 20px;
background-color: #1f1e24;
transition: width 0.3s ease-in-out;
transition: width 0.1s;
&.is-hidden {
width: 0;
margin-left: 0;
}
}
.course-player-aside__inner {
......@@ -173,10 +175,10 @@ function toggleSidebar() {
}
.toggle-button {
position: absolute;
top: 238px;
left: -17px;
width: 34px;
height: 34px;
top: 235px;
left: -20px;
width: 40px;
height: 40px;
font-size: 14px;
border-radius: 50%;
background: #303133;
......@@ -187,13 +189,27 @@ function toggleSidebar() {
align-items: center;
justify-content: flex-end;
// 右半圆
clip: rect(0px 34px 34px 17px);
clip: rect(0px 40px 40px 20px);
box-sizing: border-box;
cursor: pointer;
&.is-hidden {
// 左半圆
clip: rect(0px 17px 34px 0px);
clip: rect(0px 20px 40px 0px);
justify-content: flex-start;
}
}
:deep(.el-tabs__item) {
--el-font-size-base: 16px;
padding: 0 20px !important;
min-width: 60px;
font-weight: 400;
text-align: center;
&.is-active {
font-weight: 500;
}
}
:deep(.el-tabs__active-bar) {
padding: 0 20px;
margin-left: -20px;
}
</style>
......@@ -76,11 +76,16 @@ function showInfo(title: string, content: string) {
<li>{{ detail.credit }}学分</li>
<li v-if="detail.semester">{{ detail.semester.name }}</li>
</ul>
<el-button round @click="showInfo('课程简介', detail.represent)" v-if="detail.represent">课程简介</el-button>
<el-button round @click="showInfo('预备知识', detail.previous_preparation)" v-if="detail.previous_preparation"
<el-button round @click="showInfo('课程简介', detail.represent)" :disabled="!detail.represent"
>课程简介</el-button
>
<el-button
round
@click="showInfo('预备知识', detail.previous_preparation)"
:disabled="!detail.previous_preparation"
>预备知识</el-button
>
<el-button round @click="showInfo('授课目标', detail.target)" v-if="detail.target">授课目标</el-button>
<el-button round @click="showInfo('授课目标', detail.target)" :disabled="!detail.target">授课目标</el-button>
</div>
<div class="course-lecturers" v-if="detail.lecturers?.length">
<el-carousel
......@@ -95,9 +100,13 @@ function showInfo(title: string, content: string) {
<h2>{{ item.name }}</h2>
<el-popover :width="400" trigger="hover" v-if="item.summarize">
<template #reference>
<div v-html="item.summarize" style="height: 66px; overflow: hidden"></div>
<div
class="lecturer-item__content"
v-html="item.summarize"
style="height: 66px; overflow: hidden"
></div>
</template>
<div v-html="item.summarize"></div>
<div class="lecturer-item__content" v-html="item.summarize"></div>
</el-popover>
</div>
</el-carousel-item>
......@@ -209,7 +218,17 @@ function showInfo(title: string, content: string) {
font-size: 16px;
font-weight: 500;
line-height: 27px;
color: #333333;
color: #333;
}
.lecturer-item__content {
font-size: 14px !important;
font-weight: 400;
line-height: 24px !important;
color: #666666;
:deep(p) {
font-size: 14px !important;
line-height: 24px !important;
}
}
}
......
......@@ -75,7 +75,8 @@ function toggleCollection(data: CollectionType) {
}
// 是否可以下载
function canDownload(type: number) {
return [1, 3, 4].includes(type)
// return [1, 3, 4].includes(type)
return [1].includes(type)
}
// 下载资源
function downloadFile(data: CollectionType) {
......
......@@ -40,10 +40,10 @@ function handleUpdate() {
<el-tab-pane label="待处理" name="1" lazy></el-tab-pane>
<el-tab-pane label="已处理" name="2" lazy></el-tab-pane>
</el-tabs>
<el-collapse v-if="dataset.list.length">
<el-collapse v-if="dataset.list.length" style="border-top: 0">
<el-collapse-item v-for="item in dataset.list" :name="item.id" :key="item.id">
<template #title>
<el-button type="primary" size="small" round style="margin-right: 10px" v-if="item.status === 1"
<el-button type="primary" size="small" plain round style="margin-right: 10px" v-if="item.status === 1"
>待处理</el-button
>
<el-button color="#E8E8E8" size="small" round style="margin-right: 10px" v-if="item.status === 2"
......
......@@ -15,7 +15,7 @@ httpRequest.interceptors.request.use(
function (config) {
// 权限接口单独签名
// https://gitlab.ezijing.com/root/api-documents/-/blob/master/ezijing_permissions/%E7%AD%BE%E5%90%8D%E9%AA%8C%E8%AF%81.md
if (config.url && /^\/api\/learn|^\/api\/log/.test(config.url)) {
if (config.url && /^\/api\/learn|^\/api\/meta/.test(config.url)) {
// 默认参数
const defaultHeaders = {
timestamp: Date.now(),
......
......@@ -30,11 +30,6 @@ export default defineConfig(({ mode }) => ({
cert: fs.readFileSync(path.join(__dirname, './https/dev.ezijing.com.pem'))
},
proxy: {
'/api/log': {
target: 'http://api.ezijing.com:9501',
changeOrigin: true,
rewrite: path => path.replace(/^\/api\/log/, '')
},
'/api': 'https://saas-learn.ezijing.com'
}
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论