|
|
@@ -0,0 +1,468 @@
|
|
|
+<template>
|
|
|
+
|
|
|
+ <div class="course_page">
|
|
|
+ <img src="../../assets/img/topl.png" alt="" class="top_img">
|
|
|
+
|
|
|
+ <div class="grandTitle2">
|
|
|
+ 信息与通信学院-人工智能系列课程
|
|
|
+ </div>
|
|
|
+ <div class="course_select_title">
|
|
|
+ <div class="course_select_button_container">
|
|
|
+ <span class="grandTitle">课程名称:</span>
|
|
|
+ <div class="course_select_button course_select_button_active">
|
|
|
+ <span class="course_select_button_text">人工智能应用基础</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="course_select_button_container">
|
|
|
+ <span class="grandTitle">课程模块:</span>
|
|
|
+ <div class="course_select_button"
|
|
|
+ v-for="item in yearList"
|
|
|
+ :key="item.value"
|
|
|
+ :class="activeyear == item.value ? 'course_select_button_active' : ''"
|
|
|
+ @click="clickYear(item.value)"
|
|
|
+ >
|
|
|
+ <span class="course_select_button_text">{{ item.label }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ class="course_select"
|
|
|
+ v-for="project in projectList"
|
|
|
+ :key="project.grade"
|
|
|
+ >
|
|
|
+ <span class="project_title">
|
|
|
+ <div class="cell_line"></div>
|
|
|
+ {{ project.title }}
|
|
|
+ </span>
|
|
|
+ <div v-loading="courseLoading">
|
|
|
+ <div v-if="getCoursesByGrade(project.grade).length > 0" class="listcor">
|
|
|
+ <div class="course_item" v-for="item in getCoursesByGrade(project.grade)" :key="item.id">
|
|
|
+ <div class="grid-content ep-bg-purple">
|
|
|
+ <img class="course_item_img" :src="getImageUrl(item.json.url)" alt="">
|
|
|
+ <div class="course_content">
|
|
|
+ <div class="div_title">
|
|
|
+ <el-tooltip class="item" effect="dark" :content="item.json.title" placement="top">
|
|
|
+ <div class="div_title_text">{{ item.json.title }}</div>
|
|
|
+ </el-tooltip>
|
|
|
+ </div>
|
|
|
+ <div class="begin_course_container">
|
|
|
+ <!-- <div class="begin_coursel" @click="downloadcoupage(item.json.dataList)">
|
|
|
+ <img class="begin_course_img" src="../../assets/img/coursedl.png" alt="">
|
|
|
+ 下载课件
|
|
|
+ </div> -->
|
|
|
+ <div class="begin_course" @click="openCourseDetail(item.json.id)">
|
|
|
+ <img class="begin_course_img" src="../../assets/img/begl.png" alt="">
|
|
|
+ 开始上课
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-else>
|
|
|
+ <el-empty :description="lang.ssNoCrsGrdTip" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <selectTeachingClassDialog ref="DialogRef" @openCourse="openCourseIframe" />
|
|
|
+ </div>
|
|
|
+
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { addOp3 } from '@/mixins/mixin'
|
|
|
+import { ref, onMounted, watchEffect, inject } from 'vue'
|
|
|
+import { useRoute } from 'vue-router'
|
|
|
+import { userCurrentRole, userInfoStore, pageGotype } from '../../stores/counter'
|
|
|
+import DownloadImg from '@/assets/img/download.png'
|
|
|
+import selectTeachingClassDialog from '../dialog/selectTeachingClassDialog.vue'
|
|
|
+import axios from 'axios'
|
|
|
+import { openCourseIframe } from '@/composables/useCourseIframe'
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
+
|
|
|
+const lang = inject('lang')
|
|
|
+const route = useRoute()
|
|
|
+
|
|
|
+
|
|
|
+const user = userInfoStore()
|
|
|
+const CurrentRole = userCurrentRole()
|
|
|
+
|
|
|
+const isupdateCourse = ref(false)
|
|
|
+const DialogRef = ref(null)
|
|
|
+const courseLoading = ref(false)
|
|
|
+const activeyear = ref(route.query.yea || 'cszy1')
|
|
|
+const activeCurrentData = ref([])
|
|
|
+const projectList = ref([
|
|
|
+ { title: '项目一:AI初始与数据认知', grade: 0 },
|
|
|
+ { title: '项目二:人机协同多模态表达', grade: 1 },
|
|
|
+ { title: '项目三:AI输出核验与独立思辨', grade: 2 },
|
|
|
+ { title: '项目四:数据安全与算法责任', grade: 3 },
|
|
|
+ { title: '项目五:专业场景综合创新', grade: 4 },
|
|
|
+ { title: '项目六:岗位智能体与职业发展', grade: 5 }
|
|
|
+])
|
|
|
+
|
|
|
+const getCoursesByGrade = (grade) => {
|
|
|
+ return activeCurrentData.value.filter(item => item.grade == grade)
|
|
|
+}
|
|
|
+
|
|
|
+const yearList = ref([
|
|
|
+ { value: 'cszy1', label: '通用基础模块' },
|
|
|
+ // { value: 'cszy2', label: '专业进阶模块' }
|
|
|
+])
|
|
|
+
|
|
|
+const clickYear = (val) => {
|
|
|
+ activeyear.value = val
|
|
|
+ getCourseList()
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+// getTimeCourse(1, { title: 'AI课程' })
|
|
|
+ getCourseList()
|
|
|
+})
|
|
|
+
|
|
|
+const getCourseList = () => {
|
|
|
+ courseLoading.value = true
|
|
|
+ const params = {
|
|
|
+ ter: 0,
|
|
|
+ gra: '',
|
|
|
+ ar: lang.lang,
|
|
|
+ typ: 0,
|
|
|
+ yea: activeyear.value
|
|
|
+ }
|
|
|
+ axios.get('https://pbl.cocorobo.cn/api/pbl/selectaisixCourse', { params })
|
|
|
+ .then(res => {
|
|
|
+ const data = res.data[0]
|
|
|
+ console.log(data)
|
|
|
+ data.forEach(item => {
|
|
|
+ item.json = JSON.parse(item.json)
|
|
|
+ })
|
|
|
+ activeCurrentData.value = data
|
|
|
+ courseLoading.value = false
|
|
|
+ })
|
|
|
+ .catch(err => {
|
|
|
+ console.error(err)
|
|
|
+ courseLoading.value = false
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const getImageUrl = (url) => new URL(url, import.meta.url).href
|
|
|
+
|
|
|
+const getPblBaseUrl = () => {
|
|
|
+ if (lang.lang == 'hk') return 'https://pbl.cocorobo.hk'
|
|
|
+ if (lang.lang == 'en') return 'https://pbl.cocorobo.com'
|
|
|
+ return 'https://pbl.cocorobo.cn'
|
|
|
+}
|
|
|
+
|
|
|
+const buildCourseDetailUrl = (courseId) => {
|
|
|
+ const baseUrl = getPblBaseUrl()
|
|
|
+ return `${baseUrl}/pbl-student-table/dist/#/courseDetail?userid=${user.user.userid}&oid=${user.user.organizeid}&org=${user.user.org}&courseId=${courseId}&tType=1&cid=&screenType=2`
|
|
|
+}
|
|
|
+
|
|
|
+const getCourseModeType = (state) => {
|
|
|
+ const modeMap = {
|
|
|
+ 1: 'course_stageMode_open',
|
|
|
+ 2: 'course_taskMode_open',
|
|
|
+ 3: 'course_easyMode_open',
|
|
|
+ 5: 'course_aiMode_open',
|
|
|
+ 6: 'course_aiEasyMode_open',
|
|
|
+ 7: 'course_pptMode_open'
|
|
|
+ }
|
|
|
+ return modeMap[state] || ''
|
|
|
+}
|
|
|
+
|
|
|
+const checkClass = async () => {
|
|
|
+ if (user.user.org == '16ace517-b5c7-4168-a9bb-a9e0035df840') {
|
|
|
+ try {
|
|
|
+ const res = await axios.get('https://pbl.cocorobo.cn/api/pbl/checkClass', {
|
|
|
+ params: { userid: user.user.userid }
|
|
|
+ })
|
|
|
+ return res.data[0][0].result
|
|
|
+ } catch (err) {
|
|
|
+ console.error(err)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 2
|
|
|
+}
|
|
|
+
|
|
|
+const getCourseid = (id) => {
|
|
|
+ axios.post('https://pbl.cocorobo.cn/api/pbl/getcopyCourseByUseridSz', { id: id + ',' + user.user.userid }, {
|
|
|
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
|
+ withCredentials: true
|
|
|
+ })
|
|
|
+ .then(async res => {
|
|
|
+ if (res.data[0].length > 0) {
|
|
|
+ DialogRef.value.getClasslist(res.data[0][0])
|
|
|
+ } else {
|
|
|
+ const classResult = await checkClass()
|
|
|
+ if (classResult == 1) {
|
|
|
+ ElMessage({ message: lang.ssCreateCourseLimit, type: 'warning' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ getCourseid2(id)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch(err => console.log(err))
|
|
|
+}
|
|
|
+
|
|
|
+const getCourseid2 = (id) => {
|
|
|
+ axios.post('https://pbl.cocorobo.cn/api/pbl/copyCourseSz', { id: id + ',' + user.user.userid }, {
|
|
|
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
|
+ withCredentials: true
|
|
|
+ })
|
|
|
+ .then(res => DialogRef.value.getClasslist(res.data[0][0]))
|
|
|
+ .catch(err => console.log(err))
|
|
|
+}
|
|
|
+const downloadCheckedFiles = async (urls) => {
|
|
|
+ for (let i = 0; i < urls.length; i++) {
|
|
|
+ fetch(urls[i].url)
|
|
|
+ .then(response => response.blob())
|
|
|
+ .then(blob => {
|
|
|
+ const url = window.URL.createObjectURL(blob)
|
|
|
+ const a = document.createElement('a')
|
|
|
+ a.href = url
|
|
|
+ a.download = urls[i].name
|
|
|
+ a.style.display = 'none'
|
|
|
+ document.body.appendChild(a)
|
|
|
+ a.click()
|
|
|
+ document.body.removeChild(a)
|
|
|
+ window.URL.revokeObjectURL(url)
|
|
|
+ })
|
|
|
+ .catch(console.error)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const downloadcoupage = async (dataList) => {
|
|
|
+ if (!Array.isArray(dataList) || !dataList.length) {
|
|
|
+ ElMessage({ message: lang.ssNoData || '暂无可下载文件', type: 'warning' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ await downloadCheckedFiles(dataList)
|
|
|
+}
|
|
|
+
|
|
|
+const openCourseDetail = (id) => {
|
|
|
+ axios.post('https://pbl.cocorobo.cn/api/pbl/getcopyCourseByUseridSz', { id: id + ',' + user.user.userid }, {
|
|
|
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
|
+ withCredentials: true
|
|
|
+ })
|
|
|
+ .then(async res => {
|
|
|
+ if (res.data[0].length > 0) {
|
|
|
+ getCourseUrl(res.data[0][0])
|
|
|
+ } else {
|
|
|
+ const classResult = await checkClass()
|
|
|
+ if (classResult == 1) {
|
|
|
+ ElMessage({ message: lang.ssCreateCourseLimit, type: 'warning' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ updateCourseId(id)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch(err => console.log(err))
|
|
|
+}
|
|
|
+
|
|
|
+const getCourseUrl = (item) => {
|
|
|
+ addOp3('1', '', { courseid: item.courseId, type: getCourseModeType(item.state) }, 'success')
|
|
|
+ openCourseIframe(buildCourseDetailUrl(item.courseId))
|
|
|
+}
|
|
|
+
|
|
|
+const updateCourseId = (id) => {
|
|
|
+ axios.post('https://pbl.cocorobo.cn/api/pbl/copyCourseSz', { id: id + ',' + user.user.userid }, {
|
|
|
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
|
+ withCredentials: true
|
|
|
+ })
|
|
|
+ .then(res => {
|
|
|
+ const course = res.data[0][0]
|
|
|
+ if (course.courseId != '') {
|
|
|
+ addOp3('1', '', { courseid: course.courseId, type: getCourseModeType(course.state) }, 'success')
|
|
|
+ openCourseIframe(buildCourseDetailUrl(course.courseId))
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch(err => console.log(err))
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+watchEffect(() => {
|
|
|
+ if (JSON.stringify(user.user) != '{}') {
|
|
|
+ if (
|
|
|
+ CurrentRole.currentRole == 'edupersonnel' ||
|
|
|
+ CurrentRole.currentRole == 'areaAdministrator' ||
|
|
|
+ CurrentRole.currentRole == 'userAdministrator' ||
|
|
|
+ CurrentRole.currentRole == 'securityAuditor' ||
|
|
|
+ CurrentRole.currentRole == 'schoolAdministrator' ||
|
|
|
+ CurrentRole.currentRole == 'schoolSecurityAuditor' ||
|
|
|
+ CurrentRole.currentRole == 'teacher' ||
|
|
|
+ user.type != 2
|
|
|
+ ) {
|
|
|
+ isupdateCourse.value = true
|
|
|
+ }
|
|
|
+ }
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.course_page {
|
|
|
+ max-width: 1400px;
|
|
|
+ margin: 0 auto;
|
|
|
+ margin-bottom: 100px;
|
|
|
+ .top_img {
|
|
|
+ width: 100%;
|
|
|
+ height: auto;
|
|
|
+ display: block;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.course_select {
|
|
|
+ margin-top: 45px;
|
|
|
+ .grid-content {
|
|
|
+ border-radius: 4px;
|
|
|
+ min-height: 36px;
|
|
|
+ background: #fff;
|
|
|
+ cursor: pointer;
|
|
|
+ border-radius: 8px;
|
|
|
+ overflow: hidden;
|
|
|
+ .course_item_img {
|
|
|
+ width: 100%;
|
|
|
+ aspect-ratio: 16 / 9;
|
|
|
+ object-fit: cover;
|
|
|
+ display: block;
|
|
|
+ }
|
|
|
+ .course_content {
|
|
|
+ padding: 15px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ .div_title {
|
|
|
+ margin-bottom: 10px;
|
|
|
+ .div_title_text {
|
|
|
+ color: #000002;
|
|
|
+ overflow: hidden;
|
|
|
+ font-size: 14px;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+.begin_course_container {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ justify-content: space-between;
|
|
|
+}
|
|
|
+.begin_coursel {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 5px;
|
|
|
+ justify-content: center;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #5080F6;
|
|
|
+ background: #F0F4FF;
|
|
|
+ padding: 5px 0px;
|
|
|
+ border-radius: 5px;
|
|
|
+}
|
|
|
+.begin_course {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 5px;
|
|
|
+ justify-content: center;
|
|
|
+ font-size: 14px;
|
|
|
+ color: rgba(255, 255, 255, 1);
|
|
|
+ background: #548CFF;
|
|
|
+ padding: 5px 0px;
|
|
|
+ border-radius: 5px;
|
|
|
+}
|
|
|
+
|
|
|
+.begin_course_img {
|
|
|
+ width: 12px !important;
|
|
|
+ height: 12px;
|
|
|
+}
|
|
|
+.Levelone {
|
|
|
+ background: #E0EAFB;
|
|
|
+ border-radius: 5px;
|
|
|
+ color: rgba(26, 37, 64, 1);
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ height: 33px;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+.grandTitle2 {
|
|
|
+ font-size: 16px;
|
|
|
+ line-height: 28px;
|
|
|
+ margin-top: 20px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ color: #1F2329;
|
|
|
+}
|
|
|
+
|
|
|
+.cell_line {
|
|
|
+ width: 4px;
|
|
|
+ height: 20px;
|
|
|
+ border-radius: 2px;
|
|
|
+ background: rgba(74, 124, 246, 1);
|
|
|
+}
|
|
|
+
|
|
|
+.project_title {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ font-weight: 500;
|
|
|
+ font-size: 16px;
|
|
|
+ color: rgba(26, 37, 64, 1);
|
|
|
+}
|
|
|
+
|
|
|
+.listcor {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 20px;
|
|
|
+ margin-top: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.course_item {
|
|
|
+ box-sizing: border-box;
|
|
|
+ flex: 0 0 calc((100% - 80px) / 4);
|
|
|
+ min-width: min(100%, 280px);
|
|
|
+}
|
|
|
+.course_select_title {
|
|
|
+ background: rgba(255, 255, 255, 1);
|
|
|
+ padding: 15px 20px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 15px;
|
|
|
+ border-radius: 10px;
|
|
|
+}
|
|
|
+.course_select_button_container {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+}
|
|
|
+.grandTitle {
|
|
|
+ font-size: 14px;
|
|
|
+ color: rgba(90, 103, 133, 1);
|
|
|
+}
|
|
|
+
|
|
|
+ .course_select_button {
|
|
|
+ background: rgba(255, 255, 255, 1);
|
|
|
+ padding: 2px 6px;
|
|
|
+ border-radius: 5px;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 400;
|
|
|
+ color: rgba(54, 129, 252, 1);
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ .course_select_button_active {
|
|
|
+ background: rgba(54, 129, 252, 1);
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+</style>
|