IntelliClass_FE/components/course/Resource.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

145 lines
3.6 KiB
Vue

<script lang="ts" setup>
import { toast } from "vue-sonner";
import { editResource } from "~/api/course";
import type { IResource } from "~/types";
const props = defineProps<{
resource: IResource;
}>();
const emit = defineEmits<{
refresh: [];
"delete-resource": [resourceId: number];
}>();
const resourceIcon = computed(() => {
switch (props.resource.resourceName?.split(".").pop()) {
case "mp4":
case "avi":
case "mov":
return "tabler:video";
case "jpg":
case "jpeg":
case "png":
case "gif":
case "webp":
return "tabler:photo";
case "ppt":
case "pptx":
return "tabler:file-type-ppt";
case "doc":
case "docx":
case "txt":
case "pdf":
case "xls":
case "xlsx":
case "csv":
return "tabler:file-type-doc";
default:
return "tabler:file";
}
});
const onAllowDownloadSwitch = () => {
toast.promise(
editResource({
...props.resource,
allowDownload: !props.resource.allowDownload,
}),
{
loading: "正在修改资源下载权限...",
success: () => {
return `${props.resource.allowDownload ? "禁止" : "允许"}下载资源`;
},
error: () => {
return "修改资源下载权限失败";
},
finally: () => {
emit("refresh");
},
}
);
};
const onDeleteResource = () => {
const confirmDelete = confirm(
"将从课程中移除该资源,文件仍可在资源库中找到,是否继续?"
);
if (!confirmDelete) return;
emit("delete-resource", props.resource.id);
};
const onPreviewResource = (url: string) => {
window.open(`/preview/${btoa(url)}`, "xmts_resource_preview");
};
</script>
<template>
<div
class="px-4 pl-8 py-1 flex justify-between group/resource hover:bg-muted/50"
>
<div class="flex items-center gap-2 relative text-muted-foreground">
<div
class="absolute inset-y-0 top-3 left-1.5 w-4 h-[1px] bg-gray-300 dark:bg-gray-700 z-0"
/>
<div class="w-[7px] h-[7px] rounded-full bg-foreground/50 z-10" />
<Icon :name="resourceIcon" class="ml-6" size="20px" />
<span class="text-ellipsis line-clamp-1 text-xs font-medium">
{{ resource.resourceName }}
</span>
</div>
<div
class="flex items-center gap-2 mr-8 opacity-0 group-hover/resource:opacity-100"
>
<Button
variant="link"
size="xs"
class="flex items-center gap-1 text-muted-foreground"
@click="onPreviewResource(resource.resourceUrl)"
>
<Icon name="tabler:eye" size="16px" />
<span>预览</span>
</Button>
<Button
variant="link"
size="xs"
class="flex items-center gap-1 text-muted-foreground"
:class="{
'text-amber-500': resource.allowDownload,
}"
@click="onAllowDownloadSwitch"
>
<Icon
:name="
resource.allowDownload ? 'tabler:download-off' : 'tabler:download'
"
size="16px"
/>
<span>
{{ resource.allowDownload ? "关闭下载" : "开启下载" }}
</span>
</Button>
<!-- <Tooltip :delay-duration="0">
<TooltipTrigger>
</TooltipTrigger>
<TooltipContent>
{{ `当前${resource.allow_download ? "允许" : "禁止"}下载` }}
</TooltipContent>
</Tooltip> -->
<Button
variant="link"
size="xs"
class="flex items-center gap-1 text-red-500"
@click="onDeleteResource"
>
<Icon name="tabler:trash" size="16px" />
<span>删除</span>
</Button>
</div>
</div>
</template>
<style scoped></style>