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

chore: update

上级 7649fdcd
......@@ -115,4 +115,7 @@ export interface GroupItem {
student_num: number
updated_operator: string
updated_time: string
experiment_name?: string
course_name?: string
class_name?: string
}
......@@ -64,10 +64,10 @@ function handleRemoveStudent(row: StudentItem) {
<template>
<AppCard title="实验管理">
<el-descriptions :column="2" v-if="detail">
<el-descriptions-item label="实验名称:">{{ detail.name }}</el-descriptions-item>
<el-descriptions-item label="实验课程:">{{ detail.name }}</el-descriptions-item>
<el-descriptions-item label="实验名称:">{{ detail.experiment_name }}</el-descriptions-item>
<el-descriptions-item label="实验课程:">{{ detail.course_name }}</el-descriptions-item>
<el-descriptions-item label="小组名称:">{{ detail.name }}</el-descriptions-item>
<el-descriptions-item label="班级名称:">{{ detail.name }}</el-descriptions-item>
<el-descriptions-item label="班级名称:">{{ detail.class_name }}</el-descriptions-item>
</el-descriptions>
<AppList v-bind="listOptions" ref="appList">
<template #header-buttons>
......
import httpRequest from '@/utils/axios'
// 获取课程列表
export function getCourseList() {
return httpRequest.get('/api/student/v1/student/course/all')
}
// 获取实验指导书
export function getExperimentBook(params: { experiment_id: string }) {
return httpRequest.get('/api/student/v1/student/experiment-book/detail', { params })
}
// 获取实验视频
export function getExperimentVideoList(params: { experiment_id: string }) {
return httpRequest.get('/api/student/v1/student/experiment-video/all', { params })
}
// 获取实验视频播放信息
export function getExperimentVideoPlayInfo(params: { source_id: string }) {
return httpRequest.get('/api/student/v1/student/experiment-video/replay-list', { params })
}
// 获取实验讨论交流
export function getExperimentDiscussList(params: {
experiment_id: string
tag: string
page?: number
'per-page'?: number
}) {
return httpRequest.get('/api/student/v1/student/experiment-topic/list', { params })
}
// 发表新话题
export function addExperimentDiscuss(data: { experiment_id: string; title: string; content: string }) {
return httpRequest.post('/api/student/v1/student/experiment-topic/issue', data)
}
// 发表回复
export function addExperimentDiscussComment(data: { discussion_id: string; content: string }) {
return httpRequest.post('/api/student/v1/student/experiment-topic/comment', data)
}
<script setup lang="ts"></script>
<script setup lang="ts">
import type { ExperimentBookType } from '../types'
import { getExperimentBook } from '../api'
interface Props {
experiment_id?: string
}
const props = defineProps<Props>()
let detail = $ref<ExperimentBookType>()
function fetchInfo() {
if (!props.experiment_id) return
getExperimentBook({ experiment_id: props.experiment_id }).then(res => {
detail = res.data.detail
})
}
watchEffect(() => {
fetchInfo()
})
const isEmpty = $computed(() => {
return !props.experiment_id || !detail?.id
})
// 文件扩展名
const fileExtensionName = $computed(() => {
return detail?.url?.split('.').pop() || ''
})
// office文件
const officeUrl = $computed(() => {
return ['pptx', 'doc', 'docx', 'xls', 'xlsx'].includes(fileExtensionName)
? `https://view.officeapps.live.com/op/view.aspx?src=${detail.url}`
: ''
})
</script>
<template>
<div>book</div>
<el-empty description="暂无数据" v-if="isEmpty" />
<template v-else>
<iframe :src="officeUrl" frameborder="0" style="width: 100%; height: 100%" v-if="officeUrl"></iframe>
<object :data="detail.url" style="width: 100%; height: 100%; object-fit: none" v-else></object>
</template>
</template>
<style lang="scss" scoped></style>
<script setup lang="ts">
import DiscussAddDialog from './DiscussAddDialog.vue'
import DiscussCommentAddDialog from './DiscussCommentAddDialog.vue'
import type { ExperimentDiscussType } from '../types'
import { getExperimentDiscussList } from '../api'
import DiscussItem from './DiscussItem.vue'
const DiscussAddDialog = defineAsyncComponent(() => import('./DiscussAddDialog.vue'))
interface Props {
experiment_id?: string
}
const props = defineProps<Props>()
const discussTag = $ref('1')
let list = $ref<ExperimentDiscussType[]>([])
function fetchInfo() {
if (!props.experiment_id) return
getExperimentDiscussList({ experiment_id: props.experiment_id, tag: discussTag }).then(res => {
list = res.data.list
})
}
watchEffect(() => {
fetchInfo()
})
const isEmpty = $computed(() => {
return !props.experiment_id || !list.length
})
const dialogVisible = $ref(false)
const commentDialogVisible = $ref(false)
</script>
<template>
<el-radio-group>
<el-radio-group v-model="discussTag">
<el-radio :label="1">我发起的</el-radio>
<el-radio :label="2">我回复的</el-radio>
<el-radio :label="3">我的小组</el-radio>
......@@ -16,12 +37,13 @@ const commentDialogVisible = $ref(false)
<el-row justify="end">
<el-button round type="primary" @click="dialogVisible = true">发表新话题</el-button>
</el-row>
<div>discuss</div>
<el-row justify="end">
<el-button round type="primary" @click="commentDialogVisible = true">我要评论</el-button>
</el-row>
<DiscussAddDialog v-model="dialogVisible"></DiscussAddDialog>
<DiscussCommentAddDialog v-model="commentDialogVisible"></DiscussCommentAddDialog>
<el-empty description="暂无数据" v-if="isEmpty" />
<template v-else>
<DiscussItem v-for="item in list" :key="item.id" :data="item"></DiscussItem>
</template>
<!-- 发表新话题 -->
<DiscussAddDialog v-model="dialogVisible" v-if="dialogVisible"></DiscussAddDialog>
</template>
<style lang="scss" scoped></style>
<script setup lang="ts">
import type { ExperimentDiscussType } from '../types'
const DiscussCommentAddDialog = defineAsyncComponent(() => import('./DiscussCommentAddDialog.vue'))
interface Props {
data: ExperimentDiscussType
}
defineProps<Props>()
const commentDialogVisible = $ref(false)
</script>
<template>
<div class="discuss-item">
<div class="discuss-item-user">
<img src="" />
<p></p>
</div>
<div class="discuss-item-main"></div>
</div>
<el-row justify="end">
<el-button round type="primary" @click="commentDialogVisible = true">我要评论</el-button>
</el-row>
<!-- 我要评论 -->
<DiscussCommentAddDialog v-model="commentDialogVisible" v-if="commentDialogVisible"></DiscussCommentAddDialog>
</template>
<style lang="scss" scoped>
.video-item {
h2 {
font-size: 16px;
color: #333;
margin-bottom: 10px;
text-align: center;
}
img {
width: 100%;
height: 200px;
object-fit: cover;
}
}
</style>
<script setup lang="ts"></script>
<script setup lang="ts">
interface Props {
experiment_id?: string
}
defineProps<Props>()
</script>
<template>
<div>result</div>
......
<script setup lang="ts"></script>
<script setup lang="ts">
import type { ExperimentVideoType } from '../types'
import VideoItem from './VideoItem.vue'
import { getExperimentVideoList } from '../api'
interface Props {
experiment_id?: string
}
const props = defineProps<Props>()
let list = $ref<ExperimentVideoType[]>([])
function fetchInfo() {
if (!props.experiment_id) return
getExperimentVideoList({ experiment_id: props.experiment_id }).then(res => {
list = res.data.list
})
}
watchEffect(() => {
fetchInfo()
})
const isEmpty = $computed(() => {
return !props.experiment_id || !list.length
})
</script>
<template>
<div>video</div>
<el-empty description="暂无数据" v-if="isEmpty" />
<template v-else>
<VideoItem v-for="item in list" :key="item.id" :data="item"></VideoItem>
</template>
</template>
<style lang="scss" scoped></style>
<script setup lang="ts">
import type { ExperimentVideoType, PlayInfo } from '../types'
import { getExperimentVideoPlayInfo } from '../api'
interface Props {
data: ExperimentVideoType
}
const props = defineProps<Props>()
let playList = $ref<PlayInfo[]>([])
function fetchInfo() {
getExperimentVideoPlayInfo({ source_id: props.data.source_id }).then(res => {
playList = res.data.play_info_list
})
}
console.log(playList)
onMounted(() => {
fetchInfo()
})
</script>
<template>
<div class="video-item">
<h2>{{ data.name }}</h2>
<img :src="data.cover" />
</div>
</template>
<style lang="scss" scoped>
.video-item {
h2 {
font-size: 16px;
color: #333;
margin-bottom: 10px;
text-align: center;
}
img {
width: 100%;
height: 200px;
object-fit: cover;
}
}
</style>
import type { CourseType } from '../types'
import { getCourseList } from '../api'
const courses = ref<CourseType[]>([])
export function useGetCourseList() {
!courses.value.length &&
getCourseList().then((res: any) => {
courses.value = res.data.list
})
return { courses }
}
export interface CourseType {
id: string
name: string
cover: string
experiments: ExperimentType[]
}
export interface ExperimentType {
id: string
name: string
course_id: string
organ_id: string
}
export interface ExperimentBookType {
id: string
name: string
size: string
type: string
url: string
}
export interface ExperimentVideoType {
id: string
name: string
size: string
type: string
source_id: string
length: number
cover: string
}
export interface PlayInfo {
BitDepth: number
Bitrate: string
CreationTime: string
Definition: string
Duration: string
Encrypt: number
Format: string
Fps: string
HDRType: string
Height: number
JobId: string
ModificationTime: string
NarrowBandType: string
PlayURL: string
PreprocessStatus: string
Size: number
Specification: string
Status: string
StreamType: string
Width: number
}
export interface ExperimentDiscussType {
content: string
created_operator: string
created_time: string
id: string
is_reply: string
replies: ExperimentDiscussCommentType[]
reply_count: number
sso_user: UserType
student_id: string
title: string
updated_time: string
}
export interface ExperimentDiscussCommentType {
content: string
created_time: string
discussion_id: string
id: string
role: string
sso_id: string
sso_user: UserType
}
export interface UserType {
avatar: string
id: string
nickname: string
real_name: string
username: string
}
<script setup lang="ts">
import type { CourseType } from '../types'
import { HomeFilled, Select, UploadFilled, FullScreen } from '@element-plus/icons-vue'
import type { FormInstance, FormRules } from 'element-plus'
import ReportDialog from '../components/ReportDialog.vue'
import { useGetCourseList } from '../composables/useGetCourseList'
const Book = defineAsyncComponent(() => import('../components/Book.vue'))
const Video = defineAsyncComponent(() => import('../components/Video.vue'))
const Discuss = defineAsyncComponent(() => import('../components/Discuss.vue'))
const Result = defineAsyncComponent(() => import('../components/Result.vue'))
const ReportDialog = defineAsyncComponent(() => import('../components/ReportDialog.vue'))
// 左侧
const formRef = $ref<FormInstance>()
const form = reactive({ course_id: '', e_id: 1 })
const rules = ref<FormRules>({
course_id: [{ required: true, message: '请选择课程', trigger: 'change' }],
e_id: [{ required: true, message: '请选择实验', trigger: 'change' }]
const form = reactive<{ course?: CourseType; experiment_id: string }>({
course: undefined,
experiment_id: '6965149866569760768'
})
// 课程列表
const { courses } = useGetCourseList()
// 实验列表
const experimentList = $computed(() => {
return form.course?.experiments || []
})
// 右侧
const LAB_URL = import.meta.env.VITE_LAB_URL
......@@ -61,33 +66,30 @@ onUnmounted(() => {
<template>
<section class="lab">
<div class="lab-left">
<el-form
:model="form"
:rules="rules"
label-suffix=":"
hide-required-asterisk
ref="formRef"
style="--el-text-color-regular: #fff"
>
<el-form-item label="请选择课程" prop="course_id">
<el-select style="width: 100%"></el-select>
<el-form :model="form" label-suffix=":" hide-required-asterisk>
<el-form-item label="请选择课程">
<el-select value-key="id" v-model="form.course" style="width: 100%">
<el-option v-for="item in courses" :key="item.id" :label="item.name" :value="item"></el-option>
</el-select>
</el-form-item>
<el-form-item label="请选择实验" prop="e_id">
<el-select style="width: 100%"></el-select>
<el-form-item label="请选择实验" prop="experiment_id">
<el-select v-model="form.experiment_id" style="width: 100%">
<el-option v-for="item in experimentList" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-form>
<el-tabs type="border-card">
<el-tab-pane label="实训指导" name="first">
<Book></Book>
<el-tabs type="border-card" stretch>
<el-tab-pane label="实训指导" lazy>
<Book :experiment_id="form.experiment_id"></Book>
</el-tab-pane>
<el-tab-pane label="操作视频" name="second">
<Video></Video>
<el-tab-pane label="操作视频" lazy>
<Video :experiment_id="form.experiment_id"></Video>
</el-tab-pane>
<el-tab-pane label="讨论交流" name="third">
<Discuss></Discuss>
<el-tab-pane label="讨论交流" lazy>
<Discuss :experiment_id="form.experiment_id"></Discuss>
</el-tab-pane>
<el-tab-pane label="过程与结果" name="fourth">
<Result></Result>
<el-tab-pane label="过程与结果" lazy>
<Result :experiment_id="form.experiment_id"></Result>
</el-tab-pane>
</el-tabs>
</div>
......@@ -119,8 +121,8 @@ onUnmounted(() => {
</div>
</div>
</section>
<ReportDialog v-model="reportDialogVisible"></ReportDialog>
<!-- 上传报告 -->
<ReportDialog v-model="reportDialogVisible" v-if="reportDialogVisible"></ReportDialog>
</template>
<style lang="scss" scoped>
......@@ -129,11 +131,23 @@ onUnmounted(() => {
height: 100%;
}
.lab-left {
display: flex;
flex-direction: column;
width: 500px;
padding: 20px;
color: #fff;
background-color: rgba(45, 48, 55, 1);
border-radius: 6px;
.el-tabs {
flex: 1;
}
:deep(.el-tabs__content) {
height: calc(100% - 40px);
box-sizing: border-box;
}
:deep(.el-tab-pane) {
height: 100%;
overflow-y: auto;
}
}
.lab-right {
margin-left: 20px;
......
......@@ -26,8 +26,12 @@ export default defineConfig(({ mode }) => ({
cert: fs.readFileSync(path.join(__dirname, './https/dev.ezijing.com.pem'))
},
proxy: {
'/api': 'https://resource-center.ezijing.com',
'/lab': 'https://dev.ezijing.com'
'/api/student': {
target: 'http://test-resource-api.ezijing.com:8001',
changeOrigin: true,
rewrite: path => path.replace(/^\/api\/student/, '')
},
'/api': 'https://resource-center.ezijing.com'
}
},
resolve: {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论