IntelliClass_FE/components/ResourceUploader.vue
Timothy Yin 3a8b78ea7b
feat: update course resource types and interfaces, add resource uploader component
- Expanded CourseResourceType to include "resource" and "temp".
- Renamed ICourseResource to IResource and updated its properties for consistency.
- Introduced ICreateResource type for resource creation.
- Modified ICourseSection and ICourseChapter interfaces to use the new IResource type and updated property names for camelCase.
- Implemented uploadFile function in file API for handling file uploads.
- Created ResourceUploader component for uploading resources with validation and feedback.
- Developed Card component for displaying course class details and managing student enrollment.
- Added AlertDialog components for consistent alert dialog UI.
- Enhanced table components for better data presentation and management.
- Implemented preview page for displaying various resource types based on file extension.
2025-04-08 00:04:29 +08:00

167 lines
5.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script lang="ts" setup>
import { toast } from "vue-sonner";
import { createResource } from "~/api/course";
import { uploadFile } from "~/api/file";
import type { FetchError, IResource } from "~/types";
const props = withDefaults(
defineProps<{
modelValue: boolean;
accept?: string;
}>(),
{
accept: ".docx, .pptx, .pdf, .png, .jpg, .mp4, .mp3",
}
);
const emit = defineEmits<{
"update:modelValue": [isOpen: boolean];
"on-create": [resource: IResource];
}>();
const isDialogOpen = computed({
get: () => props.modelValue,
set: (value: boolean) => emit("update:modelValue", value),
});
const loginState = useLoginState();
// const isDialogOpen = ref(false);
const loading = ref(false);
const selectedFile = ref<File | null>(null);
const onUpload = async () => {
if (!selectedFile.value) {
toast.error("请先选择文件", { id: "file-upload-error-no-file-selected" });
return;
}
loading.value = true;
toast.promise(
new Promise((resolve, reject) => {
uploadFile(selectedFile.value!, "resource")
.then((url) => {
createResource({
resourceName: selectedFile.value!.name,
resourceSize: selectedFile.value!.size,
resourceType: "resource",
resourceUrl: url,
allowDownload: true,
isRepo: false,
ownerId: loginState.user.userId,
})
.then((result) => {
if (result.code !== 200) {
reject(new Error(result.msg || "文件上传失败"));
} else {
emit("on-create", {
id: result.resourceId,
resourceName: selectedFile.value!.name,
resourceSize: selectedFile.value!.size,
resourceType: "resource",
resourceUrl: url,
allowDownload: true,
isRepo: false,
ownerId: loginState.user.userId,
});
resolve("文件上传成功");
}
})
.catch((error) => {
reject(error);
});
})
.catch((error) => {
reject(error);
});
}),
{
loading: "正在上传文件...",
success: () => {
isDialogOpen.value = false;
return "文件上传成功";
},
error: (error: FetchError) => {
return error.message || "文件上传失败,请稍后重试";
},
finally: () => {
loading.value = false;
},
}
);
};
</script>
<template>
<Dialog v-model:open="isDialogOpen">
<DialogTrigger as-child>
<slot name="trigger" />
</DialogTrigger>
<DialogContent class="sm:max-w-[520px]">
<DialogHeader>
<DialogTitle>资源上传</DialogTitle>
<DialogDescription>
<p>上传资源文件并将其添加到课程中</p>
<p>
支持的格式<span class="font-medium">{{ accept }}</span>
</p>
</DialogDescription>
</DialogHeader>
<div class="flex flex-col gap-4">
<FormField name="file">
<FormItem>
<FormLabel>选择文件</FormLabel>
<FormControl>
<Input
type="file"
:accept="accept"
@change="(e: any) => {
const files = e.target.files;
if (files && files.length > 0) {
selectedFile = files[0];
} else {
selectedFile = null;
}
}"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<input type="hidden" name="courseId" />
<div class="text-xs text-muted-foreground space-y-2">
<p>
根据国家出版管理条例网络出版服务管理规定及教育部职业教育专业教学资源库建设工作手册等相关规定上传的资源必须符合以下要求
</p>
<ul
class="list-disc list-inside space-y-1 text-[11px] text-muted-foreground/80 text-justify"
>
<li>
没有法律法规禁止出版的内容没有政治性道德性问题和科学性错误不泄露国家秘密
</li>
<li>
不含有侵犯他人著作权肖像权名誉权等权益的内容资源具有原创性引用需指明作者姓名作品名称使用他人作品应取得许可
</li>
<li>
采用法定计量单位名词术语符号等符合国家统一规定尚无统一规定的可采用习惯用法并保持一致
</li>
<li>
地图具有严肃的政治性严密的科学性和严格的法定性使用的地图应根据地图管理条例的要求已送相关部门审核并标注审图号
</li>
<li>不含有商业广告商业性宣传内容</li>
<li>不含有色情赌博迷信暴力等内容</li>
</ul>
</div>
</div>
<DialogFooter>
<Button :disabled="loading" @click="onUpload">
{{ loading ? "上传中..." : "上传" }}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</template>
<style scoped></style>