|
|
@@ -62,6 +62,13 @@
|
|
|
<el-icon><Download /></el-icon>
|
|
|
下载文本作业
|
|
|
</el-button>
|
|
|
+ <el-button
|
|
|
+ class="download-doc-button"
|
|
|
+ @click="openBehaviorDownloadDialog"
|
|
|
+ >
|
|
|
+ <el-icon><Download /></el-icon>
|
|
|
+ 下载行为数据
|
|
|
+ </el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
@@ -353,6 +360,68 @@
|
|
|
</el-button>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
+
|
|
|
+ <el-dialog
|
|
|
+ v-model="behaviorDownloadDialogVisible"
|
|
|
+ title="下载行为数据"
|
|
|
+ width="520px"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ >
|
|
|
+ <el-form label-position="top" class="download-form">
|
|
|
+ <el-form-item label="作业名称">
|
|
|
+ <el-select
|
|
|
+ v-model="behaviorDownloadForm.assignmentIds"
|
|
|
+ multiple
|
|
|
+ collapse-tags
|
|
|
+ collapse-tags-tooltip
|
|
|
+ filterable
|
|
|
+ placeholder="请选择作业名称"
|
|
|
+ class="download-form-select"
|
|
|
+ @change="handleBehaviorDownloadAssignmentChange"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="assignment in downloadableAssignments"
|
|
|
+ :key="assignment.assignmentId"
|
|
|
+ :label="assignment.assignmentName"
|
|
|
+ :value="assignment.assignmentId"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="班级名称">
|
|
|
+ <el-select
|
|
|
+ v-model="behaviorDownloadForm.classIds"
|
|
|
+ multiple
|
|
|
+ collapse-tags
|
|
|
+ collapse-tags-tooltip
|
|
|
+ filterable
|
|
|
+ :placeholder="behaviorDownloadClassPlaceholder"
|
|
|
+ class="download-form-select"
|
|
|
+ :disabled="behaviorDownloadForm.assignmentIds.length === 0"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="classItem in downloadableBehaviorClasses"
|
|
|
+ :key="classItem.classId"
|
|
|
+ :label="classItem.className"
|
|
|
+ :value="classItem.classId"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <div class="download-form-tip">
|
|
|
+ 将按“作业 x 班级”组合逐个下载 Excel 文件。
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="closeBehaviorDownloadDialog">取消</el-button>
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ :loading="behaviorDownloadSubmitting"
|
|
|
+ @click="handleBehaviorBatchDownload"
|
|
|
+ >
|
|
|
+ 开始下载
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
@@ -374,10 +443,16 @@
|
|
|
const selectedAssignment = ref(null)
|
|
|
const downloadDialogVisible = ref(false)
|
|
|
const downloadSubmitting = ref(false)
|
|
|
+ const behaviorDownloadDialogVisible = ref(false)
|
|
|
+ const behaviorDownloadSubmitting = ref(false)
|
|
|
const downloadForm = reactive({
|
|
|
assignmentIds: [] as number[],
|
|
|
classIds: [] as number[]
|
|
|
})
|
|
|
+ const behaviorDownloadForm = reactive({
|
|
|
+ assignmentIds: [] as number[],
|
|
|
+ classIds: [] as number[]
|
|
|
+ })
|
|
|
const downloadClassCache = reactive<Record<number, ClassDTO[]>>({})
|
|
|
|
|
|
// 定义课程和作业的数据结构
|
|
|
@@ -412,6 +487,10 @@
|
|
|
return downloadableAssignments.value.filter(assignment => downloadForm.assignmentIds.includes(assignment.assignmentId))
|
|
|
})
|
|
|
|
|
|
+ const selectedBehaviorDownloadAssignments = computed(() => {
|
|
|
+ return downloadableAssignments.value.filter(assignment => behaviorDownloadForm.assignmentIds.includes(assignment.assignmentId))
|
|
|
+ })
|
|
|
+
|
|
|
const downloadableClasses = computed(() => {
|
|
|
const classMap = new Map<number, ClassDTO>()
|
|
|
|
|
|
@@ -425,6 +504,19 @@
|
|
|
return Array.from(classMap.values())
|
|
|
})
|
|
|
|
|
|
+ const downloadableBehaviorClasses = computed(() => {
|
|
|
+ const classMap = new Map<number, ClassDTO>()
|
|
|
+
|
|
|
+ selectedBehaviorDownloadAssignments.value.forEach(assignment => {
|
|
|
+ const classes = downloadClassCache[assignment.courseId] || []
|
|
|
+ classes.forEach(classItem => {
|
|
|
+ classMap.set(classItem.classId, classItem)
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ return Array.from(classMap.values())
|
|
|
+ })
|
|
|
+
|
|
|
const downloadClassPlaceholder = computed(() => {
|
|
|
if (downloadForm.assignmentIds.length === 0) {
|
|
|
return '请先选择作业'
|
|
|
@@ -436,6 +528,18 @@
|
|
|
|
|
|
return '请选择班级名称'
|
|
|
})
|
|
|
+
|
|
|
+ const behaviorDownloadClassPlaceholder = computed(() => {
|
|
|
+ if (behaviorDownloadForm.assignmentIds.length === 0) {
|
|
|
+ return '请先选择作业'
|
|
|
+ }
|
|
|
+
|
|
|
+ if (downloadableBehaviorClasses.value.length === 0) {
|
|
|
+ return '当前所选作业暂无可选班级'
|
|
|
+ }
|
|
|
+
|
|
|
+ return '请选择班级名称'
|
|
|
+ })
|
|
|
|
|
|
// 加载状态
|
|
|
const loading = ref(false)
|
|
|
@@ -912,6 +1016,20 @@
|
|
|
downloadForm.classIds = []
|
|
|
}
|
|
|
|
|
|
+ const openBehaviorDownloadDialog = () => {
|
|
|
+ if (downloadableAssignments.value.length === 0) {
|
|
|
+ ElMessage.warning('暂无可下载的写作作业')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ behaviorDownloadDialogVisible.value = true
|
|
|
+ }
|
|
|
+
|
|
|
+ const closeBehaviorDownloadDialog = () => {
|
|
|
+ behaviorDownloadDialogVisible.value = false
|
|
|
+ behaviorDownloadForm.assignmentIds = []
|
|
|
+ behaviorDownloadForm.classIds = []
|
|
|
+ }
|
|
|
+
|
|
|
const handleDownloadAssignmentChange = async () => {
|
|
|
const selectedCourseIds = Array.from(new Set(selectedDownloadAssignments.value.map(item => item.courseId)))
|
|
|
|
|
|
@@ -923,6 +1041,17 @@
|
|
|
downloadForm.classIds = downloadForm.classIds.filter(classId => validClassIds.has(classId))
|
|
|
}
|
|
|
|
|
|
+ const handleBehaviorDownloadAssignmentChange = async () => {
|
|
|
+ const selectedCourseIds = Array.from(new Set(selectedBehaviorDownloadAssignments.value.map(item => item.courseId)))
|
|
|
+
|
|
|
+ for (const courseId of selectedCourseIds) {
|
|
|
+ await loadClassesForDownload(courseId)
|
|
|
+ }
|
|
|
+
|
|
|
+ const validClassIds = new Set(downloadableBehaviorClasses.value.map(item => item.classId))
|
|
|
+ behaviorDownloadForm.classIds = behaviorDownloadForm.classIds.filter(classId => validClassIds.has(classId))
|
|
|
+ }
|
|
|
+
|
|
|
const getHeaderValue = (headers: Record<string, any>, key: string) => {
|
|
|
const value = headers[key] ?? headers[key.toLowerCase()] ?? headers[key.toUpperCase()]
|
|
|
return typeof value === 'string' ? value : (value != null ? String(value) : '')
|
|
|
@@ -1022,6 +1151,61 @@
|
|
|
downloadSubmitting.value = false
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ const handleBehaviorBatchDownload = async () => {
|
|
|
+ if (behaviorDownloadForm.assignmentIds.length === 0) {
|
|
|
+ ElMessage.warning('请先选择作业')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (behaviorDownloadForm.classIds.length === 0) {
|
|
|
+ ElMessage.warning('请选择班级')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const selectedClasses = downloadableBehaviorClasses.value.filter(classItem => behaviorDownloadForm.classIds.includes(classItem.classId))
|
|
|
+ const downloadTasks = selectedBehaviorDownloadAssignments.value.flatMap(assignment => {
|
|
|
+ return selectedClasses
|
|
|
+ .filter(classItem => classItem.courseId === assignment.courseId)
|
|
|
+ .map(classItem => ({ assignment, classItem }))
|
|
|
+ })
|
|
|
+
|
|
|
+ if (downloadTasks.length === 0) {
|
|
|
+ ElMessage.warning('所选作业与班级没有可下载的对应关系')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ behaviorDownloadSubmitting.value = true
|
|
|
+
|
|
|
+ try {
|
|
|
+ for (const task of downloadTasks) {
|
|
|
+ console.log('下载行为数据参数:', {
|
|
|
+ classId: task.classItem.classId,
|
|
|
+ assignmentId: task.assignment.assignmentId,
|
|
|
+ className: task.classItem.className,
|
|
|
+ assignmentName: task.assignment.assignmentName
|
|
|
+ })
|
|
|
+ const response = await apis.downLoadAllBehaviorDataByClass(task.classItem.classId, task.assignment.assignmentId)
|
|
|
+ const contentType = getHeaderValue(response.headers as Record<string, any>, 'content-type')
|
|
|
+
|
|
|
+ if (contentType.includes('application/json')) {
|
|
|
+ throw new Error(await parseBlobErrorMessage(response.data))
|
|
|
+ }
|
|
|
+
|
|
|
+ const fallbackName = `${task.classItem.className}_${task.assignment.assignmentName}_行为数据.xlsx`
|
|
|
+ const fileName = getDownloadFilename(response.headers as Record<string, any>, fallbackName)
|
|
|
+ triggerBrowserDownload(response.data, fileName)
|
|
|
+ }
|
|
|
+
|
|
|
+ ElMessage.success(`已开始下载 ${downloadTasks.length} 个行为数据文件`)
|
|
|
+ closeBehaviorDownloadDialog()
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error('批量下载行为数据失败:', error)
|
|
|
+ ElMessage.error(error?.message || '批量下载失败,请稍后重试')
|
|
|
+ } finally {
|
|
|
+ behaviorDownloadSubmitting.value = false
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
// 加载学生作业状态
|
|
|
const loadStudentAssignmentStatus = async (classId: string, assignmentId: string) => {
|
|
|
@@ -1437,11 +1621,15 @@ export default {
|
|
|
.download-section {
|
|
|
padding: 1rem 1.25rem 1.25rem;
|
|
|
border-top: 1px solid rgba(255, 255, 255, 0.18);
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 12px;
|
|
|
}
|
|
|
|
|
|
.download-doc-button {
|
|
|
width: 100%;
|
|
|
height: 40px;
|
|
|
+ margin-left: 0;
|
|
|
border: 1px solid rgba(255, 255, 255, 0.35);
|
|
|
background: rgba(255, 255, 255, 0.16);
|
|
|
color: white;
|