feat: 前端增加提交功能
This commit is contained in:
@@ -8,19 +8,7 @@
|
||||
{{ mode === "create" ? "新建实验" : "编辑实验" }}
|
||||
</h2>
|
||||
<button @click="close" class="btn btn-sm btn-circle btn-ghost">
|
||||
<svg
|
||||
class="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<XIcon class="w-6 h-6" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -417,11 +405,13 @@ import {
|
||||
BinaryIcon,
|
||||
FileArchiveIcon,
|
||||
FileJsonIcon,
|
||||
XIcon,
|
||||
} from "lucide-vue-next";
|
||||
import {
|
||||
ExamClient,
|
||||
ExamDto,
|
||||
ResourceClient,
|
||||
ResourcePurpose,
|
||||
type FileParameter,
|
||||
} from "@/APIClient";
|
||||
import { useAlertStore } from "@/components/Alert";
|
||||
@@ -685,7 +675,12 @@ async function uploadExamResources(examId: string) {
|
||||
data: uploadFiles.value.mdFile,
|
||||
fileName: uploadFiles.value.mdFile.name,
|
||||
};
|
||||
await client.addResource("doc", "template", examId, mdFileParam);
|
||||
await client.addResource(
|
||||
"doc",
|
||||
ResourcePurpose.Template,
|
||||
examId,
|
||||
mdFileParam,
|
||||
);
|
||||
console.log("MD文档上传成功");
|
||||
}
|
||||
|
||||
@@ -695,7 +690,12 @@ async function uploadExamResources(examId: string) {
|
||||
data: imageFile,
|
||||
fileName: imageFile.name,
|
||||
};
|
||||
await client.addResource("image", "template", examId, imageFileParam);
|
||||
await client.addResource(
|
||||
"image",
|
||||
ResourcePurpose.Template,
|
||||
examId,
|
||||
imageFileParam,
|
||||
);
|
||||
console.log("图片上传成功:", imageFile.name);
|
||||
}
|
||||
|
||||
@@ -707,7 +707,7 @@ async function uploadExamResources(examId: string) {
|
||||
};
|
||||
await client.addResource(
|
||||
"bitstream",
|
||||
"template",
|
||||
ResourcePurpose.Template,
|
||||
examId,
|
||||
bitstreamFileParam,
|
||||
);
|
||||
@@ -720,7 +720,12 @@ async function uploadExamResources(examId: string) {
|
||||
data: canvasFile,
|
||||
fileName: canvasFile.name,
|
||||
};
|
||||
await client.addResource("canvas", "template", examId, canvasFileParam);
|
||||
await client.addResource(
|
||||
"canvas",
|
||||
ResourcePurpose.Template,
|
||||
examId,
|
||||
canvasFileParam,
|
||||
);
|
||||
console.log("画布模板上传成功:", canvasFile.name);
|
||||
}
|
||||
|
||||
@@ -732,7 +737,7 @@ async function uploadExamResources(examId: string) {
|
||||
};
|
||||
await client.addResource(
|
||||
"resource",
|
||||
"template",
|
||||
ResourcePurpose.Template,
|
||||
examId,
|
||||
resourceFileParam,
|
||||
);
|
||||
@@ -775,6 +780,7 @@ defineExpose({
|
||||
show,
|
||||
close,
|
||||
editExam,
|
||||
editExamInfo,
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -13,19 +13,7 @@
|
||||
@click="closeExamDetail"
|
||||
class="btn btn-sm btn-circle btn-ghost"
|
||||
>
|
||||
<svg
|
||||
class="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<XIcon class="w-6 h-6" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -147,17 +135,18 @@
|
||||
<div class="space-y-4">
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-base-content/70">当前状态</span>
|
||||
<div class="badge badge-error">未完成</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-base-content/70">批阅状态</span>
|
||||
<div class="badge badge-ghost">待提交</div>
|
||||
<div class="badge badge-error">
|
||||
{{
|
||||
isUndefined(commitsList) || commitsList.length === 0
|
||||
? "未提交"
|
||||
: "已提交"
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-base-content/70">成绩</span>
|
||||
<span class="text-base-content/50">未评分</span>
|
||||
<div class="badge badge-ghost">未评分</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -167,17 +156,22 @@
|
||||
<div class="space-y-3">
|
||||
<h4 class="font-medium text-base-content">提交历史</h4>
|
||||
<div
|
||||
v-if="isUndefined(commitsList)"
|
||||
v-if="isUndefined(commitsList) || commitsList.length === 0"
|
||||
class="text-sm text-base-content/50 text-center py-4"
|
||||
>
|
||||
暂无提交记录
|
||||
</div>
|
||||
<div v-else class="overflow-y-auto">
|
||||
<ul class="steps steps-vertical">
|
||||
<li class="step step-primary">Register</li>
|
||||
<li class="step step-primary">Choose plan</li>
|
||||
<li class="step">Purchase</li>
|
||||
<li class="step">Receive Product</li>
|
||||
<li
|
||||
class="step"
|
||||
:class="{ 'step-primary': _idx === 1 }"
|
||||
v-for="(commit, _idx) in commitsList.slice(0, 3)"
|
||||
>
|
||||
{{ commit.id }} ---
|
||||
{{ commit.uploadTime.toDateString() }}
|
||||
</li>
|
||||
<li class="step" v-if="commitsList.length > 3">......</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -187,58 +181,27 @@
|
||||
<!-- 操作按钮 -->
|
||||
<div class="space-y-3">
|
||||
<button @click="startExam" class="btn btn-primary w-full">
|
||||
<svg
|
||||
class="w-5 h-5 mr-2"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M14.828 14.828a4 4 0 01-5.656 0M9 10h1m4 0h1m-6 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<Smile class="w-5 h-5" />
|
||||
开始实验
|
||||
</button>
|
||||
|
||||
<button @click="uploadModal?.show" class="btn btn-info w-full">
|
||||
<Upload class="w-5 h-5" />
|
||||
提交实验
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="downloadResources"
|
||||
class="btn btn-outline w-full"
|
||||
:disabled="downloadingResources"
|
||||
>
|
||||
<svg
|
||||
class="w-5 h-5 mr-2"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
||||
/>
|
||||
</svg>
|
||||
<Download class="w-5 h-5" />
|
||||
<span v-if="downloadingResources">下载中...</span>
|
||||
<span v-else>下载资源包</span>
|
||||
</button>
|
||||
|
||||
<button class="btn btn-outline w-full">
|
||||
<svg
|
||||
class="w-5 h-5 mr-2"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
||||
/>
|
||||
</svg>
|
||||
<GitGraph class="w-5 h-5" />
|
||||
查看记录
|
||||
</button>
|
||||
</div>
|
||||
@@ -247,6 +210,12 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-backdrop" @click="closeExamDetail"></div>
|
||||
<UploadModal
|
||||
ref="uploadModal"
|
||||
class="fixed z-auto"
|
||||
:auto-upload="true"
|
||||
:callback="submitExam"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
@@ -266,10 +235,16 @@ import { formatDate } from "@/utils/Common";
|
||||
import { computed } from "vue";
|
||||
import { watch } from "vue";
|
||||
import { isNull, isUndefined } from "lodash";
|
||||
import { Download, GitGraph, Smile, Upload, XIcon } from "lucide-vue-next";
|
||||
import UploadModal from "@/components/UploadModal.vue";
|
||||
import { templateRef } from "@vueuse/core";
|
||||
import { toFileParameter } from "@/utils/Common";
|
||||
|
||||
const alertStore = useRequiredInjection(useAlertStore);
|
||||
const router = useRouter();
|
||||
|
||||
const uploadModal = templateRef("uploadModal");
|
||||
|
||||
const show = defineModel<boolean>("show", {
|
||||
default: false,
|
||||
});
|
||||
@@ -350,6 +325,24 @@ const startExam = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const submitExam = (files: File[]) => {
|
||||
try {
|
||||
const client = AuthManager.createClient(ResourceClient);
|
||||
|
||||
for (const file of files) {
|
||||
client.addResource(
|
||||
"compression",
|
||||
ResourcePurpose.Homework,
|
||||
props.selectedExam.id,
|
||||
toFileParameter(file),
|
||||
);
|
||||
}
|
||||
} catch (err: any) {
|
||||
alertStore.error(err.message || "上传资料失败");
|
||||
console.error("上传资料失败:", err);
|
||||
}
|
||||
};
|
||||
|
||||
const closeExamDetail = () => {
|
||||
show.value = false;
|
||||
};
|
||||
|
||||
@@ -191,6 +191,7 @@ import { templateRef } from "@vueuse/core";
|
||||
import { isArray, isNull } from "lodash";
|
||||
import { watch } from "vue";
|
||||
import { watchEffect } from "vue";
|
||||
import { nextTick } from "vue";
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
@@ -218,13 +219,18 @@ watch(
|
||||
},
|
||||
);
|
||||
|
||||
watchEffect(() => {
|
||||
if (showEditModal.value) {
|
||||
router.replace({ path: `/exam/edit` });
|
||||
} else {
|
||||
router.replace({ path: `/exam` });
|
||||
}
|
||||
});
|
||||
watch(
|
||||
() => showEditModal.value,
|
||||
() => {
|
||||
if (showEditModal.value) {
|
||||
router.replace({
|
||||
path: `/exam/edit/${examEditModalRef.value?.editExamInfo.id}`,
|
||||
});
|
||||
} else {
|
||||
router.replace({ path: `/exam` });
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
async function refreshExams() {
|
||||
loading.value = true;
|
||||
@@ -263,7 +269,8 @@ async function handleCardClicked(event: MouseEvent, examId: string) {
|
||||
}
|
||||
|
||||
async function handleEditExamClicked(event: MouseEvent, examId: string) {
|
||||
examEditModalRef?.value?.editExam(examId);
|
||||
await examEditModalRef?.value?.editExam(examId);
|
||||
router.replace(`/exam/edit/${examId}`);
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
@@ -278,17 +285,28 @@ onMounted(async () => {
|
||||
await refreshExams();
|
||||
});
|
||||
|
||||
async function loadBasicPage(page: string) {
|
||||
if (page === "") return;
|
||||
else if (page === "edit") showEditModal.value = true;
|
||||
else if (page) await viewExam(page);
|
||||
else router.push("/exam");
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
// 处理路由参数,如果有examId则自动打开该实验的详情模态框
|
||||
const examId = route.params.examId as string;
|
||||
if (examId === "") return;
|
||||
const page = route.params.page;
|
||||
|
||||
if (isArray(examId)) return;
|
||||
|
||||
if (examId === "edit") showEditModal.value = true;
|
||||
|
||||
if (examId) {
|
||||
await viewExam(examId);
|
||||
if (Array.isArray(page)) {
|
||||
if (page.length == 1) await loadBasicPage(page[0]);
|
||||
else if (page.length == 2) {
|
||||
if (page[0] === "edit") {
|
||||
await examEditModalRef.value?.editExam(page[1]);
|
||||
} else {
|
||||
router.push("/exam");
|
||||
}
|
||||
} else router.push("/exam");
|
||||
} else {
|
||||
await loadBasicPage(page);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user