add: 添加实验列表界面,实验增删完全依赖数据库实现
This commit is contained in:
@@ -1,21 +1,64 @@
|
||||
<template>
|
||||
<div class="flex flex-col bg-base-100 justify-center items-center">
|
||||
<div class="flex flex-col bg-base-100 justify-center items-center gap-4">
|
||||
<!-- Title -->
|
||||
<h1 class="font-bold text-2xl">上传比特流文件</h1>
|
||||
<h1 class="font-bold text-2xl">比特流文件</h1>
|
||||
|
||||
<!-- 示例比特流下载区域 (仅在有examId时显示) -->
|
||||
<div v-if="examId && availableBitstreams.length > 0" class="w-full">
|
||||
<fieldset class="fieldset w-full">
|
||||
<legend class="fieldset-legend text-sm">示例比特流文件</legend>
|
||||
<div class="space-y-2">
|
||||
<div v-for="bitstream in availableBitstreams" :key="bitstream.id" class="flex items-center justify-between p-2 bg-base-200 rounded">
|
||||
<span class="text-sm">{{ bitstream.name }}</span>
|
||||
<div class="flex gap-2">
|
||||
<button
|
||||
@click="downloadExampleBitstream(bitstream)"
|
||||
class="btn btn-sm btn-secondary"
|
||||
:disabled="isDownloading || isProgramming"
|
||||
>
|
||||
<div v-if="isDownloading">
|
||||
<span class="loading loading-spinner loading-xs"></span>
|
||||
下载中...
|
||||
</div>
|
||||
<div v-else>
|
||||
下载示例
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
@click="programExampleBitstream(bitstream)"
|
||||
class="btn btn-sm btn-primary"
|
||||
:disabled="isDownloading || isProgramming || !uploadEvent"
|
||||
>
|
||||
<div v-if="isProgramming">
|
||||
<span class="loading loading-spinner loading-xs"></span>
|
||||
烧录中...
|
||||
</div>
|
||||
<div v-else>
|
||||
直接烧录
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<!-- 分割线 -->
|
||||
<div v-if="examId && availableBitstreams.length > 0" class="divider">或</div>
|
||||
|
||||
<!-- Input File -->
|
||||
<fieldset class="fieldset w-full">
|
||||
<legend class="fieldset-legend text-sm">选择或拖拽上传文件</legend>
|
||||
<legend class="fieldset-legend text-sm">上传自定义比特流文件</legend>
|
||||
<input type="file" ref="fileInput" class="file-input w-full" @change="handleFileChange" />
|
||||
<label class="fieldset-label">文件最大容量: {{ maxMemory }}MB</label>
|
||||
</fieldset>
|
||||
|
||||
<!-- Upload Button -->
|
||||
<div class="card-actions w-full">
|
||||
<button @click="handleClick" class="btn btn-primary grow" :disabled="isUploading">
|
||||
<button @click="handleClick" class="btn btn-primary grow" :disabled="isUploading || isProgramming">
|
||||
<div v-if="isUploading">
|
||||
<span class="loading loading-spinner"></span>
|
||||
下载中...
|
||||
上传中...
|
||||
</div>
|
||||
<div v-else>
|
||||
{{ buttonText }}
|
||||
@@ -27,6 +70,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, useTemplateRef, onMounted } from "vue";
|
||||
import { AuthManager } from "@/utils/AuthManager"; // Adjust the path based on your project structure
|
||||
import { useDialogStore } from "@/stores/dialog";
|
||||
import { isNull, isUndefined } from "lodash";
|
||||
|
||||
@@ -34,10 +78,12 @@ interface Props {
|
||||
uploadEvent?: (file: File) => Promise<boolean>;
|
||||
downloadEvent?: () => Promise<boolean>;
|
||||
maxMemory?: number;
|
||||
examId?: string; // 新增examId属性
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
maxMemory: 4,
|
||||
examId: '',
|
||||
});
|
||||
|
||||
const emits = defineEmits<{
|
||||
@@ -47,6 +93,10 @@ const emits = defineEmits<{
|
||||
const dialog = useDialogStore();
|
||||
|
||||
const isUploading = ref(false);
|
||||
const isDownloading = ref(false);
|
||||
const isProgramming = ref(false);
|
||||
const availableBitstreams = ref<{id: number, name: string}[]>([]);
|
||||
|
||||
const buttonText = computed(() => {
|
||||
return isUndefined(props.downloadEvent) ? "上传" : "上传并下载";
|
||||
});
|
||||
@@ -56,14 +106,113 @@ const bitstream = defineModel("bitstreamFile", {
|
||||
type: File,
|
||||
default: undefined,
|
||||
});
|
||||
onMounted(() => {
|
||||
|
||||
// 初始化时加载示例比特流
|
||||
onMounted(async () => {
|
||||
if (!isUndefined(bitstream.value) && !isNull(fileInput.value)) {
|
||||
let fileList = new DataTransfer();
|
||||
fileList.items.add(bitstream.value);
|
||||
fileInput.value.files = fileList.files;
|
||||
}
|
||||
|
||||
await loadAvailableBitstreams();
|
||||
});
|
||||
|
||||
// 加载可用的比特流文件列表
|
||||
async function loadAvailableBitstreams() {
|
||||
console.log('加载可用比特流文件,examId:', props.examId);
|
||||
if (!props.examId) {
|
||||
availableBitstreams.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const examClient = AuthManager.createAuthenticatedExamClient();
|
||||
// 使用新的API获取比特流资源列表
|
||||
const resources = await examClient.getExamResourceList(props.examId, 'bitstream');
|
||||
availableBitstreams.value = resources.map(r => ({ id: r.id, name: r.name })) || [];
|
||||
} catch (error) {
|
||||
console.error('加载比特流列表失败:', error);
|
||||
availableBitstreams.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
// 下载示例比特流
|
||||
async function downloadExampleBitstream(bitstream: {id: number, name: string}) {
|
||||
if (isDownloading.value) return;
|
||||
|
||||
isDownloading.value = true;
|
||||
try {
|
||||
const examClient = AuthManager.createAuthenticatedExamClient();
|
||||
|
||||
// 使用动态API获取资源文件
|
||||
const response = await examClient.getExamResourceById(bitstream.id);
|
||||
|
||||
if (response && response.data) {
|
||||
// 创建下载链接
|
||||
const url = URL.createObjectURL(response.data);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = response.fileName || bitstream.name;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
dialog.info("示例比特流下载成功");
|
||||
} else {
|
||||
dialog.error("下载失败:响应数据为空");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('下载示例比特流失败:', error);
|
||||
dialog.error("下载示例比特流失败");
|
||||
} finally {
|
||||
isDownloading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 直接烧录示例比特流
|
||||
async function programExampleBitstream(bitstream: {id: number, name: string}) {
|
||||
if (isProgramming.value || !props.uploadEvent) return;
|
||||
|
||||
isProgramming.value = true;
|
||||
try {
|
||||
const examClient = AuthManager.createAuthenticatedExamClient();
|
||||
|
||||
// 使用动态API获取比特流文件数据
|
||||
const response = await examClient.getExamResourceById(bitstream.id);
|
||||
|
||||
if (!response || !response.data) {
|
||||
throw new Error('获取比特流文件失败');
|
||||
}
|
||||
|
||||
const file = new File([response.data], response.fileName || bitstream.name, { type: response.data.type });
|
||||
|
||||
// 调用上传事件
|
||||
const uploadSuccess = await props.uploadEvent(file);
|
||||
if (uploadSuccess) {
|
||||
// 如果有下载事件(烧录),则执行
|
||||
if (props.downloadEvent) {
|
||||
const downloadSuccess = await props.downloadEvent();
|
||||
if (downloadSuccess) {
|
||||
dialog.info("示例比特流烧录成功");
|
||||
} else {
|
||||
dialog.error("烧录失败");
|
||||
}
|
||||
} else {
|
||||
dialog.info("示例比特流上传成功");
|
||||
}
|
||||
} else {
|
||||
dialog.error("上传失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('烧录示例比特流失败:', error);
|
||||
dialog.error("烧录示例比特流失败");
|
||||
} finally {
|
||||
isProgramming.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleFileChange(event: Event): void {
|
||||
const target = event.target as HTMLInputElement;
|
||||
const file = target.files?.[0]; // 获取选中的第一个文件
|
||||
|
||||
Reference in New Issue
Block a user