175 lines
5.4 KiB
Vue
175 lines
5.4 KiB
Vue
<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>
|