|
@@ -114,14 +114,37 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div class="layout-content-right" v-show="type == '1'">
|
|
|
+ <div class="layout-content-right" v-show="type == '1'" :class="{ collapsed: workPanelCollapsed }">
|
|
|
<div class="thumbnails">
|
|
|
- <div class="viewer-header">
|
|
|
- <h3>作业区</h3>
|
|
|
+ <div class="viewer-header homework-header">
|
|
|
+ <h3 v-show="!workPanelCollapsed">作业区</h3>
|
|
|
+ <button class="collapse-btn" @click="workPanelCollapsed = !workPanelCollapsed" :title="workPanelCollapsed ? '展开' : '收起'">
|
|
|
+ <span v-if="workPanelCollapsed">›</span>
|
|
|
+ <span v-else>‹</span>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ <div v-show="!workPanelCollapsed">
|
|
|
+ <div class="homework-title">已提交</div>
|
|
|
+ <div v-if="workLoading" class="homework-loading">正在加载作业...</div>
|
|
|
+ <div v-else>
|
|
|
+ <div v-if="workArray && workArray.length" class="homework-grid">
|
|
|
+ <button class="homework-btn" v-for="(work, idx) in workArray" :key="work.id ?? idx" :title="work.name" @click="openWorkModal(work)">
|
|
|
+ <span class="homework-btn__text">{{ work.name }}</span>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ <div class="homework-empty" v-else>
|
|
|
+ 暂无作业提交
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
+ <ShotWorkModal v-model:visible="visibleShot" :work="selectedWork" />
|
|
|
+ <QAWorkModal v-model:visible="visibleQA" :work="selectedWork" />
|
|
|
+ <ChoiceWorkModal v-model:visible="visibleChoice" :work="selectedWork" />
|
|
|
+ <AIWorkModal v-model:visible="visibleAI" :work="selectedWork" />
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts" setup>
|
|
@@ -140,6 +163,10 @@ import useSlideBackgroundStyle from '@/hooks/useSlideBackgroundStyle'
|
|
|
import useImport from '@/hooks/useImport'
|
|
|
import message from '@/utils/message'
|
|
|
import api from '@/services/course'
|
|
|
+import ShotWorkModal from './components/ShotWorkModal.vue'
|
|
|
+import QAWorkModal from './components/QAWorkModal.vue'
|
|
|
+import ChoiceWorkModal from './components/ChoiceWorkModal.vue'
|
|
|
+import AIWorkModal from './components/AIWorkModal.vue'
|
|
|
|
|
|
// 定义组件props
|
|
|
interface Props {
|
|
@@ -191,9 +218,68 @@ const slideHeight = ref(0)
|
|
|
|
|
|
// 添加loading状态
|
|
|
const isLoading = ref(false)
|
|
|
+const workLoading = ref(false)
|
|
|
|
|
|
// 作业数组
|
|
|
-const workArray = ref([])
|
|
|
+type WorkItem = {
|
|
|
+ id?: string | number
|
|
|
+ name: string
|
|
|
+ type: number | string
|
|
|
+ [key: string]: any
|
|
|
+}
|
|
|
+const workArray = ref<WorkItem[]>([])
|
|
|
+
|
|
|
+// 作业弹窗相关
|
|
|
+const selectedWork = ref<any>(null)
|
|
|
+const visibleShot = ref(false)
|
|
|
+const visibleQA = ref(false)
|
|
|
+const visibleChoice = ref(false)
|
|
|
+const visibleAI = ref(false)
|
|
|
+
|
|
|
+// 作业区收缩状态
|
|
|
+const workPanelCollapsed = ref(false)
|
|
|
+
|
|
|
+// 收缩/展开后重新计算中间画布尺寸(在 DOM 更新并完成过渡后)
|
|
|
+watch(() => workPanelCollapsed.value, async () => {
|
|
|
+ // 等待本次 DOM 更新
|
|
|
+ await nextTick()
|
|
|
+ // 先在下一帧计算一次,确保初步布局就绪
|
|
|
+ requestAnimationFrame(() => {
|
|
|
+ calculateScale()
|
|
|
+ })
|
|
|
+ // 再在过渡结束后(与右栏 width .2s 过渡一致)复算一次,确保最终尺寸
|
|
|
+ setTimeout(() => {
|
|
|
+ calculateScale()
|
|
|
+ }, 220)
|
|
|
+}, { flush: 'post' })
|
|
|
+
|
|
|
+const openWorkModal = (work: WorkItem) => {
|
|
|
+ selectedWork.value = work
|
|
|
+ const t = Number(work?.type)
|
|
|
+ if (t !== 1) {
|
|
|
+ message.warning('暂未开发完成')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ visibleShot.value = false
|
|
|
+ visibleQA.value = false
|
|
|
+ visibleChoice.value = false
|
|
|
+ visibleAI.value = false
|
|
|
+ if (t === 1) {
|
|
|
+ visibleShot.value = true
|
|
|
+ }
|
|
|
+ else if (t === 3) {
|
|
|
+ visibleQA.value = true
|
|
|
+ }
|
|
|
+ else if (t === 8) {
|
|
|
+ visibleChoice.value = true
|
|
|
+ }
|
|
|
+ else if (t === 20) {
|
|
|
+ visibleAI.value = true
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ message.info('暂不支持的作业类型')
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
// 计算幻灯片尺寸的函数
|
|
|
const calculateSlideSize = () => {
|
|
@@ -317,7 +403,7 @@ const nextSlide = () => {
|
|
|
// 监听slideIndex变化,调用getWork
|
|
|
watch(() => slideIndex.value, (newIndex, oldIndex) => {
|
|
|
console.log('slideIndex变化,调用getWork', { newIndex, oldIndex })
|
|
|
- if (newIndex !== oldIndex && typeof newIndex === 'number') {
|
|
|
+ if (newIndex !== oldIndex && typeof newIndex === 'number' && currentSlideHasIframe.value) {
|
|
|
console.log('触发getWork,当前幻灯片索引:', newIndex)
|
|
|
getWork()
|
|
|
}
|
|
@@ -590,6 +676,7 @@ const submitWork = async (slideIndex: number, atool: string, content: string, ty
|
|
|
content: content,
|
|
|
type: type
|
|
|
})
|
|
|
+ getWork()
|
|
|
console.log(res)
|
|
|
}
|
|
|
// 文件上传到AWS S3的函数
|
|
@@ -817,11 +904,13 @@ const handleHomeworkSubmit = async () => {
|
|
|
|
|
|
if (!hasSubmitWork) {
|
|
|
message.info('未找到可用的作业提交功能')
|
|
|
+ isSubmitting.value = false
|
|
|
}
|
|
|
}
|
|
|
catch (error) {
|
|
|
console.error('作业提交过程中出错:', error)
|
|
|
message.error('作业提交失败')
|
|
|
+ isSubmitting.value = false
|
|
|
}
|
|
|
finally {
|
|
|
isSubmitting.value = false
|
|
@@ -834,7 +923,8 @@ const getHomeworkButtonRight = () => {
|
|
|
return 30 // 全屏时按钮在右侧30px
|
|
|
}
|
|
|
if (props.type === '1') {
|
|
|
- return 230 // type=1时(有左侧导航栏)按钮在右侧230px
|
|
|
+ // 展开作业区:按钮更靠左;收起时:按钮更靠右侧
|
|
|
+ return workPanelCollapsed.value ? 60 : 430
|
|
|
}
|
|
|
return 30 // type=2时按钮在右侧30px
|
|
|
}
|
|
@@ -940,6 +1030,7 @@ const getCourseDetail = async () => {
|
|
|
|
|
|
const getWork = async () => {
|
|
|
try {
|
|
|
+ workLoading.value = true
|
|
|
console.log('getWork 开始执行,参数:', {
|
|
|
courseid: props.courseid,
|
|
|
slideIndex: slideIndex.value,
|
|
@@ -948,14 +1039,18 @@ const getWork = async () => {
|
|
|
|
|
|
if (!props.courseid) {
|
|
|
console.warn('getWork: courseid 未提供,跳过执行')
|
|
|
+ workLoading.value = false
|
|
|
return
|
|
|
}
|
|
|
|
|
|
const res = await api.selectSWorks(props.courseid, '0', slideIndex.value.toString())
|
|
|
console.log('getWork 执行成功,结果:', res)
|
|
|
+ const frame = elementList.value.find(element => element.type === ElementTypes.FRAME)
|
|
|
+ console.log('frame:', frame)
|
|
|
+ const toolType = frame?.toolType ?? ''
|
|
|
workArray.value = props.cid
|
|
|
? res[0].filter((work: any) => {
|
|
|
- return work.type === 1 || (work.type === 2 && work.classid.includes(props.cid))
|
|
|
+ return work.type === 1 || (work.type === 2 && work.classid.includes(props.cid)) && (work.atool === toolType || !toolType)
|
|
|
})
|
|
|
: res[0]
|
|
|
console.log('getWork 执行成功,结果:', workArray.value)
|
|
@@ -964,6 +1059,9 @@ const getWork = async () => {
|
|
|
console.error('getWork 执行失败:', error)
|
|
|
message.error('获取作业信息失败')
|
|
|
}
|
|
|
+ finally {
|
|
|
+ workLoading.value = false
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
onMounted(() => {
|
|
@@ -1085,11 +1183,93 @@ onUnmounted(() => {
|
|
|
}
|
|
|
|
|
|
.layout-content-right {
|
|
|
- width: 200px;
|
|
|
+ width: 400px;
|
|
|
height: 100%;
|
|
|
background-color: #fff;
|
|
|
border-left: 1px solid #e0e0e0;
|
|
|
overflow-y: auto;
|
|
|
+ transition: width .2s ease;
|
|
|
+}
|
|
|
+.layout-content-right.collapsed {
|
|
|
+ width: 48px;
|
|
|
+}
|
|
|
+.homework-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+}
|
|
|
+/* 收缩时头部仅显示按钮,并保持按钮在可用宽度内水平居中 */
|
|
|
+.layout-content-right.collapsed .homework-header {
|
|
|
+ justify-content: center;
|
|
|
+ padding: 8px;
|
|
|
+}
|
|
|
+.collapse-btn {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 32px;
|
|
|
+ height: 32px;
|
|
|
+ border: 1px solid #d9d9d9;
|
|
|
+ border-radius: 8px;
|
|
|
+ background: #fff;
|
|
|
+ color: #333;
|
|
|
+ cursor: pointer;
|
|
|
+ line-height: 1;
|
|
|
+ font-weight: 700;
|
|
|
+}
|
|
|
+.collapse-btn:hover {
|
|
|
+ border-color: #1890ff;
|
|
|
+ color: #1890ff;
|
|
|
+}
|
|
|
+
|
|
|
+.homework-title {
|
|
|
+ padding: 12px 12px 0 12px;
|
|
|
+ color: #333;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+.homework-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(4, 1fr);
|
|
|
+ gap: 16px;
|
|
|
+ padding: 12px;
|
|
|
+}
|
|
|
+.homework-btn {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 100%;
|
|
|
+ min-width: 0;
|
|
|
+ height: 35px;
|
|
|
+ border: 1px solid #2f80ed;
|
|
|
+ color: #2f80ed;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ cursor: pointer;
|
|
|
+ font-weight: 600;
|
|
|
+ overflow: hidden;
|
|
|
+ padding: 0 10px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+.homework-btn__text {
|
|
|
+ display: block;
|
|
|
+ max-width: 100%;
|
|
|
+ overflow: hidden;
|
|
|
+ white-space: nowrap;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+}
|
|
|
+.homework-btn:hover {
|
|
|
+ box-shadow: 0 2px 10px rgba(0,0,0,0.08);
|
|
|
+}
|
|
|
+.homework-loading {
|
|
|
+ padding: 12px;
|
|
|
+ color: #666;
|
|
|
+ font-size: 13px;
|
|
|
+}
|
|
|
+.homework-empty {
|
|
|
+ padding: 12px;
|
|
|
+ color: #999;
|
|
|
+ font-size: 13px;
|
|
|
}
|
|
|
|
|
|
.thumbnails {
|