mirror of
https://codeup.aliyun.com/67762337eccfc218f6110e0e/vue/fe-manage.git
synced 2025-12-10 19:36:46 +08:00
feat(course): 新增音视频与图文组件支持
- 新增 AudioComp.vue 组件,支持音频播放与设置 - 新增 EditorComp.vue 组件,集成富文本编辑器用于图文内容 - 修改 chooseFileList.vue,增加文件上传功能与类型适配 - 更新 createCourse.vue,完善课程章节内容管理逻辑 - 升级 useCourseData.js 和 useCreateCourseMaps.js,增强类型映射与数据结构 - 优化 BasicTable.vue,移除调试日志并调整样式 - 引入 quill 及相关插件依赖以支持富文本编辑功能
This commit is contained in:
@@ -30,6 +30,10 @@
|
|||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"qrcode.vue": "^3.3.3",
|
"qrcode.vue": "^3.3.3",
|
||||||
"qs": "^6.11.0",
|
"qs": "^6.11.0",
|
||||||
|
"quill": "^2.0.3",
|
||||||
|
"quill-blot-formatter": "^1.0.5",
|
||||||
|
"quill-image-drop-module": "^1.0.3",
|
||||||
|
"quill-image-resize-module": "^3.0.0",
|
||||||
"sortablejs": "^1.15.0",
|
"sortablejs": "^1.15.0",
|
||||||
"vue": "^3.2.13",
|
"vue": "^3.2.13",
|
||||||
"vue-cookies": "^1.8.2",
|
"vue-cookies": "^1.8.2",
|
||||||
|
|||||||
@@ -25,8 +25,6 @@ const props = defineProps({
|
|||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
console.log(props);
|
|
||||||
|
|
||||||
const paginationCopy = computed(() => {
|
const paginationCopy = computed(() => {
|
||||||
return {
|
return {
|
||||||
pageSize: props.pagination.pageSize,
|
pageSize: props.pagination.pageSize,
|
||||||
|
|||||||
@@ -1,24 +1,21 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { reactive, onMounted, ref, h, watch } from "vue";
|
import { reactive, onMounted, ref, h, watch } from "vue";
|
||||||
import {
|
import { ElButton, ElInput, ElUpload } from "element-plus";
|
||||||
ElButton,
|
|
||||||
ElInput,
|
|
||||||
ElDialog,
|
|
||||||
ElForm,
|
|
||||||
ElFormItem,
|
|
||||||
ElRadioGroup,
|
|
||||||
ElRadio,
|
|
||||||
ElInputNumber,
|
|
||||||
} from "element-plus";
|
|
||||||
import BasicTable from "@/components/BasicElTable/BasicTable.vue";
|
import BasicTable from "@/components/BasicElTable/BasicTable.vue";
|
||||||
import { getPageListByType } from "@/hooks/useCreateCourseMaps";
|
import { getPageListByType } from "@/hooks/useCreateCourseMaps";
|
||||||
|
import { getType, getMapsItem } from "@/hooks/useCreateCourseMaps";
|
||||||
const props = defineProps({});
|
import Cookies from "vue-cookies";
|
||||||
|
const props = defineProps({
|
||||||
|
resType: {
|
||||||
|
type: Number,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const tableData = ref([]);
|
const tableData = ref([]);
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
name: "",
|
name: "",
|
||||||
resType: 10,
|
resType: props.resType,
|
||||||
});
|
});
|
||||||
let pagination = reactive({
|
let pagination = reactive({
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
@@ -74,7 +71,7 @@ const columns = [
|
|||||||
isDrag: false,
|
isDrag: false,
|
||||||
completeSetup: 0,
|
completeSetup: 0,
|
||||||
setupTage: "",
|
setupTage: "",
|
||||||
resType: 10,
|
resType: props.resType,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -108,25 +105,31 @@ const chooseItem = (type) => {
|
|||||||
showDialog.value = false;
|
showDialog.value = false;
|
||||||
emit("chooseItem", {
|
emit("chooseItem", {
|
||||||
...dialogVideoForm,
|
...dialogVideoForm,
|
||||||
type: 10,
|
type: props.resType,
|
||||||
});
|
});
|
||||||
// postData.content=this.cware.content;
|
};
|
||||||
// this.cwareChange.content = deepClone(this.cware.content)
|
|
||||||
// if(this.cware.content.contentType==52){
|
const uploadData = reactive({
|
||||||
// if(this.cware.linkInfo.url==''){
|
headers: {
|
||||||
// this.$message.error("请填写外连URL地址");
|
"XBOE-Access-Token": Cookies.get("token"),
|
||||||
// return;
|
},
|
||||||
// }
|
data: {
|
||||||
// postData.content.content=JSON.stringify(this.cware.linkInfo);
|
dir: "course",
|
||||||
// this.cwareChange.linkInfo = deepClone(this.cware.linkInfo)
|
},
|
||||||
// }else if(this.cware.content.contentType==10 || this.cware.content.contentType==20){
|
actionUrl: process.env.VUE_APP_SYS_API + "/xboe/sys/xuploader/file/upload",
|
||||||
// if(this.cware.curriculumData.url==''){
|
});
|
||||||
// this.$message.error("请选择课件");
|
|
||||||
// return;
|
const fileList = ref([]);
|
||||||
// }
|
const uploadSuccess = (result) => {
|
||||||
// postData.content.content=JSON.stringify(this.cware.curriculumData);
|
if (result.status === 200) {
|
||||||
// this.cwareChange.curriculumData = deepClone(this.cware.curriculumData)
|
emit("chooseItem", {
|
||||||
// }
|
...dialogVideoForm,
|
||||||
|
name: result.result.displayName,
|
||||||
|
resType: props.resType,
|
||||||
|
...result.result,
|
||||||
|
});
|
||||||
|
fileList.value = [];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -135,20 +138,36 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="add-video" v-if="!isPreview && !isSetting">
|
<div class="add-video">
|
||||||
<div class="add-vide-header">
|
<div class="add-vide-header">
|
||||||
<div>
|
<div style="display: flex; align-items: center">
|
||||||
<el-button>上传新视频</el-button>
|
<el-upload
|
||||||
<span class="desc ml10">文件大小限制:1G,支持的文件类型:mp4 </span>
|
:action="uploadData.actionUrl"
|
||||||
|
:headers="uploadData.headers"
|
||||||
|
:data="uploadData.data"
|
||||||
|
:on-success="uploadSuccess"
|
||||||
|
:file-list="fileList"
|
||||||
|
>
|
||||||
|
<el-button v-if="[10, 20].includes(props.resType)" type="primary"
|
||||||
|
>上传新{{ getType(props.resType) }}</el-button
|
||||||
|
>
|
||||||
|
</el-upload>
|
||||||
|
<span class="desc ml10"
|
||||||
|
>文件大小限制:{{
|
||||||
|
getMapsItem(props.resType).uploadSizeName
|
||||||
|
}},支持的文件类型:{{ getMapsItem(props.resType).fileType.join(",") }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<el-input
|
<el-input
|
||||||
style="width: 150px"
|
style="width: 150px"
|
||||||
placeholder="请输入视频名称"
|
:placeholder="`请输入${getType(props.resType)}名称`"
|
||||||
v-model="form.name"
|
v-model="form.name"
|
||||||
clearable
|
clearable
|
||||||
></el-input>
|
></el-input>
|
||||||
<el-button class="ml10" @click="getVideoList">查询</el-button>
|
<el-button class="ml10" @click="getVideoList" type="primary"
|
||||||
|
>查询</el-button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt10">
|
<div class="mt10">
|
||||||
|
|||||||
106
src/components/CreatedCourse/preview/AudioComp.vue
Normal file
106
src/components/CreatedCourse/preview/AudioComp.vue
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
ElForm,
|
||||||
|
ElFormItem,
|
||||||
|
ElInput,
|
||||||
|
ElInputNumber,
|
||||||
|
ElRadio,
|
||||||
|
ElRadioGroup,
|
||||||
|
} from "element-plus";
|
||||||
|
defineOptions({
|
||||||
|
resType: 20,
|
||||||
|
});
|
||||||
|
const props = defineProps({
|
||||||
|
dialogVideoForm: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({
|
||||||
|
name: "",
|
||||||
|
filePath: "",
|
||||||
|
isDrag: true,
|
||||||
|
completeSetup: 0,
|
||||||
|
setupTage: 0,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
isPreview: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
import { ref, watch } from "vue";
|
||||||
|
// Create a reactive copy of the prop for local modifications
|
||||||
|
const localDialogVideoForm = ref({ ...props.dialogVideoForm });
|
||||||
|
|
||||||
|
// Watch for changes in the prop and update the local copy
|
||||||
|
watch(
|
||||||
|
() => props.dialogVideoForm,
|
||||||
|
(newVal) => {
|
||||||
|
Object.assign(localDialogVideoForm.value, newVal);
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Emit updates to parent component
|
||||||
|
const emit = defineEmits(["update:dialogVideoForm"]);
|
||||||
|
|
||||||
|
// Update form values and emit changes
|
||||||
|
const updateFormValue = (field, value) => {
|
||||||
|
localDialogVideoForm.value[field] = value;
|
||||||
|
emit("update:dialogVideoForm", { ...localDialogVideoForm.value });
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-form>
|
||||||
|
<el-form-item label="视频名称" v-if="!isPreview">
|
||||||
|
<el-input
|
||||||
|
v-model="localDialogVideoForm.name"
|
||||||
|
@update:modelValue="(val) => updateFormValue('name', val)"
|
||||||
|
></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<!-- Added video type prop -->
|
||||||
|
<audio
|
||||||
|
controls
|
||||||
|
style="width: 100%; max-height: 400px"
|
||||||
|
class="mb10"
|
||||||
|
:key="localDialogVideoForm.filePath"
|
||||||
|
:src="'http://home.hzer.xyz:9960/upload/' + localDialogVideoForm.filePath"
|
||||||
|
>
|
||||||
|
您的浏览器不支持video
|
||||||
|
</audio>
|
||||||
|
<el-form-item label="是否允许拖拽" v-if="!isPreview">
|
||||||
|
<el-radio-group
|
||||||
|
:model-value="localDialogVideoForm.isDrag"
|
||||||
|
@update:modelValue="(val) => updateFormValue('isDrag', val)"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<el-radio :label="true" border>是</el-radio>
|
||||||
|
<el-radio :label="false" border>否</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="完成规则设置" v-if="!isPreview">
|
||||||
|
<el-radio-group
|
||||||
|
:model-value="localDialogVideoForm.completeSetup"
|
||||||
|
@update:modelValue="(val) => updateFormValue('completeSetup', val)"
|
||||||
|
>
|
||||||
|
<el-radio :label="0">默认(系统自动控制)</el-radio>
|
||||||
|
<el-radio :label="1">
|
||||||
|
按进度
|
||||||
|
<el-input-number
|
||||||
|
:disabled="localDialogVideoForm.completeSetup === 0"
|
||||||
|
:model-value="localDialogVideoForm.setupTage"
|
||||||
|
@update:modelValue="(val) => updateFormValue('setupTage', val)"
|
||||||
|
size="mini"
|
||||||
|
:min="0"
|
||||||
|
:max="100"
|
||||||
|
label="描述文字"
|
||||||
|
controls-position="right"
|
||||||
|
></el-input-number>
|
||||||
|
%
|
||||||
|
</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss"></style>
|
||||||
160
src/components/CreatedCourse/preview/EditorComp.vue
Normal file
160
src/components/CreatedCourse/preview/EditorComp.vue
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ElForm, ElFormItem, ElInput } from "element-plus";
|
||||||
|
import Quill from "quill";
|
||||||
|
import "quill/dist/quill.core.css";
|
||||||
|
import "quill/dist/quill.snow.css";
|
||||||
|
import "quill/dist/quill.bubble.css";
|
||||||
|
import { ImageDrop } from "quill-image-drop-module";
|
||||||
|
import BlotFormatter from "quill-blot-formatter";
|
||||||
|
import { ref, onMounted, onBeforeUnmount, watch, nextTick } from "vue";
|
||||||
|
|
||||||
|
// 注册Quill模块
|
||||||
|
Quill.register("modules/imageDrop", ImageDrop);
|
||||||
|
Quill.register("modules/blotFormatter", BlotFormatter);
|
||||||
|
|
||||||
|
const Size = Quill.import("attributors/style/size");
|
||||||
|
Size.whitelist = ["15px", "18px"];
|
||||||
|
Quill.register(Size, true);
|
||||||
|
|
||||||
|
// 只有在Parchment存在时才创建lineHeightAttributor
|
||||||
|
let lineHeightStyle = null;
|
||||||
|
try {
|
||||||
|
const Parchment = Quill.import("parchment");
|
||||||
|
if (Parchment && Parchment.Attributor && Parchment.Attributor.Style) {
|
||||||
|
class lineHeightAttributor extends Parchment.Attributor.Style {}
|
||||||
|
lineHeightStyle = new lineHeightAttributor("lineHeight", "line-height", {
|
||||||
|
scope: Parchment.Scope.INLINE,
|
||||||
|
whitelist: ["1", "1.5", "2", "3", "4"],
|
||||||
|
});
|
||||||
|
Quill.register({ "formats/lineHeight": lineHeightStyle }, true);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Failed to register lineHeight formatter:", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
const toolbarOptions = [
|
||||||
|
["bold", "italic", "underline", "strike"],
|
||||||
|
["blockquote", "code-block"],
|
||||||
|
[{ list: "ordered" }, { list: "bullet" }],
|
||||||
|
[{ indent: "-1" }, { indent: "+1" }],
|
||||||
|
[{ size: [false, "18px"] }],
|
||||||
|
[{ header: [1, 2, 3, 4, 5, 6, false] }],
|
||||||
|
[{ color: [] }, { background: [] }],
|
||||||
|
[{ align: [] }],
|
||||||
|
[{ lineheight: ["initial", "1", "1.5", "2", "3", "4"] }],
|
||||||
|
["clean"],
|
||||||
|
["link", "image"],
|
||||||
|
["selectPicture"],
|
||||||
|
];
|
||||||
|
|
||||||
|
// 随机数 八位
|
||||||
|
function uuid() {
|
||||||
|
return Math.random().toString(36).substring(2, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
const quillClass = "editor_" + uuid();
|
||||||
|
let quill = null;
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
resType: 41,
|
||||||
|
});
|
||||||
|
const props = defineProps({
|
||||||
|
dialogVideoForm: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({
|
||||||
|
name: "",
|
||||||
|
filePath: "",
|
||||||
|
isDrag: true,
|
||||||
|
completeSetup: 0,
|
||||||
|
setupTage: 0,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
isPreview: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create a reactive copy of the prop for local modifications
|
||||||
|
const localDialogVideoForm = ref({ ...props.dialogVideoForm });
|
||||||
|
|
||||||
|
// Watch for changes in the prop and update the local copy
|
||||||
|
watch(
|
||||||
|
() => props.dialogVideoForm,
|
||||||
|
(newVal) => {
|
||||||
|
Object.assign(localDialogVideoForm.value, newVal);
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Emit updates to parent component
|
||||||
|
const emit = defineEmits(["update:dialogVideoForm"]);
|
||||||
|
|
||||||
|
// Update form values and emit changes
|
||||||
|
const updateFormValue = (field, value) => {
|
||||||
|
localDialogVideoForm.value[field] = value;
|
||||||
|
emit("update:dialogVideoForm", { ...localDialogVideoForm.value });
|
||||||
|
};
|
||||||
|
|
||||||
|
const editor = ref(null);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
nextTick(() => {
|
||||||
|
if (editor.value) {
|
||||||
|
quill = new Quill(`.${quillClass}`, {
|
||||||
|
modules: {
|
||||||
|
toolbar: toolbarOptions,
|
||||||
|
imageDrop: true,
|
||||||
|
blotFormatter: {
|
||||||
|
overlay: {
|
||||||
|
// 自定义图片调整大小的样式
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
theme: "snow",
|
||||||
|
});
|
||||||
|
|
||||||
|
// 如果有内容,设置内容
|
||||||
|
if (props.dialogVideoForm.filePath) {
|
||||||
|
quill.root.innerHTML = props.dialogVideoForm.filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听文本变化
|
||||||
|
quill.on("text-change", () => {
|
||||||
|
const content = quill.root.innerHTML;
|
||||||
|
updateFormValue("filePath", content);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (quill) {
|
||||||
|
quill = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听内容变化
|
||||||
|
watch(
|
||||||
|
() => props.dialogVideoForm.filePath,
|
||||||
|
(newContent) => {
|
||||||
|
if (quill && newContent !== quill.root.innerHTML) {
|
||||||
|
quill.root.innerHTML = newContent || "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-form>
|
||||||
|
<el-form-item label="名称" v-if="!isPreview">
|
||||||
|
<el-input
|
||||||
|
v-model="localDialogVideoForm.name"
|
||||||
|
@update:model-value="(val) => updateFormValue('name', val)"
|
||||||
|
></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<div :class="quillClass" ref="editor" style="min-height: 300px"></div>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss"></style>
|
||||||
@@ -8,6 +8,9 @@ import {
|
|||||||
ElRadioGroup,
|
ElRadioGroup,
|
||||||
} from "element-plus";
|
} from "element-plus";
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
resType: 10,
|
||||||
|
});
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
dialogVideoForm: {
|
dialogVideoForm: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ export function useCourseData() {
|
|||||||
createTime: "",
|
createTime: "",
|
||||||
chooseIndex: "",
|
chooseIndex: "",
|
||||||
sectionIndex: "",
|
sectionIndex: "",
|
||||||
|
resType: "",
|
||||||
});
|
});
|
||||||
const tableColumns = [
|
const tableColumns = [
|
||||||
{
|
{
|
||||||
@@ -350,6 +351,13 @@ export function useCourseData() {
|
|||||||
fun: "addAssessment",
|
fun: "addAssessment",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
// 添加章
|
||||||
|
const addChapter = () => {
|
||||||
|
courseList.value.push({
|
||||||
|
title: "视频课程名称",
|
||||||
|
data: [],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
courseMetadata,
|
courseMetadata,
|
||||||
@@ -357,5 +365,6 @@ export function useCourseData() {
|
|||||||
courseActionButtons,
|
courseActionButtons,
|
||||||
executeCourseOperation,
|
executeCourseOperation,
|
||||||
tableColumns,
|
tableColumns,
|
||||||
|
addChapter,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,138 @@
|
|||||||
import apiCourseFile from "@/api/modules/courseFile";
|
import apiCourseFile from "@/api/modules/courseFile";
|
||||||
|
|
||||||
const contentTypeMaps = {
|
// const contentTypeMaps = {
|
||||||
10: "视频",
|
// 10: "视频",
|
||||||
20: "音频",
|
// 20: "音频",
|
||||||
30: "图片",
|
// 30: "图片",
|
||||||
40: "文档",
|
// 40: "文档",
|
||||||
41: "图文",
|
// 41: "图文",
|
||||||
50: "scorm",
|
// 50: "scorm",
|
||||||
52: "外链",
|
// 52: "外链",
|
||||||
60: "作业",
|
// 60: "作业",
|
||||||
61: "考试",
|
// 61: "考试",
|
||||||
62: "评估",
|
// 62: "评估",
|
||||||
90: "其它",
|
// 90: "其它",
|
||||||
};
|
// };
|
||||||
|
|
||||||
|
const contentTypeMaps = [
|
||||||
|
{
|
||||||
|
type: 10,
|
||||||
|
name: "视频",
|
||||||
|
icon: "icon-video",
|
||||||
|
// 1G B
|
||||||
|
uploadSize: 1024 * 1024 * 1024,
|
||||||
|
uploadSizeName: "1G",
|
||||||
|
// 文件类型
|
||||||
|
fileType: ["mp4"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 20,
|
||||||
|
name: "音频",
|
||||||
|
icon: "icon-audio",
|
||||||
|
// 1G B
|
||||||
|
uploadSize: 1024 * 1024 * 1024,
|
||||||
|
uploadSizeName: "1G",
|
||||||
|
// 文件类型
|
||||||
|
fileType: ["mp3"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 30,
|
||||||
|
name: "图片",
|
||||||
|
icon: "icon-image",
|
||||||
|
// 1G B
|
||||||
|
uploadSize: 1024 * 1024 * 1024,
|
||||||
|
uploadSizeName: "1G",
|
||||||
|
// 文件类型
|
||||||
|
fileType: ["png", "jpg", "jpeg", "gif"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 40,
|
||||||
|
name: "文档",
|
||||||
|
icon: "icon-file",
|
||||||
|
// 1G B
|
||||||
|
uploadSize: 1024 * 1024 * 1024,
|
||||||
|
uploadSizeName: "1G",
|
||||||
|
// 文件类型
|
||||||
|
fileType: ["doc", "docx", "xls", "xlsx", "ppt", "pptx", "pdf"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 41,
|
||||||
|
name: "图文",
|
||||||
|
icon: "icon-file",
|
||||||
|
// 1G B
|
||||||
|
uploadSize: 1024 * 1024 * 1024,
|
||||||
|
uploadSizeName: "1G",
|
||||||
|
// 文件类型
|
||||||
|
fileType: ["doc", "docx", "xls", "xlsx", "ppt", "pptx", "pdf"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 50,
|
||||||
|
name: "scorm",
|
||||||
|
icon: "icon-file",
|
||||||
|
// 1G B
|
||||||
|
uploadSize: 1024 * 1024 * 1024,
|
||||||
|
uploadSizeName: "1G",
|
||||||
|
// 文件类型
|
||||||
|
fileType: ["zip"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 52,
|
||||||
|
name: "外链",
|
||||||
|
icon: "icon-file",
|
||||||
|
// 1G B
|
||||||
|
uploadSize: 1024 * 1024 * 1024,
|
||||||
|
uploadSizeName: "1G",
|
||||||
|
// 文件类型
|
||||||
|
fileType: ["zip"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 60,
|
||||||
|
name: "作业",
|
||||||
|
icon: "icon-file",
|
||||||
|
// 1G B
|
||||||
|
uploadSize: 1024 * 1024 * 1024,
|
||||||
|
uploadSizeName: "1G",
|
||||||
|
// 文件类型
|
||||||
|
fileType: ["zip"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 61,
|
||||||
|
name: "考试",
|
||||||
|
icon: "icon-file",
|
||||||
|
// 1G B
|
||||||
|
uploadSize: 1024 * 1024 * 1024,
|
||||||
|
uploadSizeName: "1G",
|
||||||
|
// 文件类型
|
||||||
|
fileType: ["zip"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 62,
|
||||||
|
name: "评估",
|
||||||
|
icon: "icon-file",
|
||||||
|
// 1G B
|
||||||
|
uploadSize: 1024 * 1024 * 1024,
|
||||||
|
uploadSizeName: "1G",
|
||||||
|
// 文件类型
|
||||||
|
fileType: ["zip"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 90,
|
||||||
|
name: "其它",
|
||||||
|
icon: "icon-file",
|
||||||
|
// 1G B
|
||||||
|
uploadSize: 1024 * 1024 * 1024,
|
||||||
|
uploadSizeName: "1G",
|
||||||
|
// 文件类型
|
||||||
|
fileType: ["zip"],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export function getType(type) {
|
export function getType(type) {
|
||||||
return contentTypeMaps[type];
|
const item = contentTypeMaps.filter((item) => item.type === type)[0];
|
||||||
|
return item ? item.name : "";
|
||||||
|
}
|
||||||
|
export function getMapsItem(type) {
|
||||||
|
return contentTypeMaps.filter((item) => item.type === type)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据不同type 类型查询 媒体 视频等列表
|
// 根据不同type 类型查询 媒体 视频等列表
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import dragCollapse from "./dragCollapse.vue";
|
import dragCollapse from "./dragCollapse.vue";
|
||||||
import { ElButton, ElCheckbox, ElDialog } from "element-plus";
|
import { ElButton, ElCheckbox, ElDialog, ElMessageBox } from "element-plus";
|
||||||
import dragTable from "./dragTable.vue";
|
import dragTable from "./dragTable.vue";
|
||||||
import { ref, reactive } from "vue";
|
import { ref, reactive } from "vue";
|
||||||
defineOptions({
|
defineOptions({
|
||||||
@@ -9,42 +9,34 @@ defineOptions({
|
|||||||
import { useCourseData } from "@/hooks/useCourseData";
|
import { useCourseData } from "@/hooks/useCourseData";
|
||||||
import chooseFileList from "@/components/CreatedCourse/chooseFileList.vue";
|
import chooseFileList from "@/components/CreatedCourse/chooseFileList.vue";
|
||||||
import VideoComp from "@/components/CreatedCourse/preview/VideoComp.vue";
|
import VideoComp from "@/components/CreatedCourse/preview/VideoComp.vue";
|
||||||
|
import AudioComp from "@/components/CreatedCourse/preview/AudioComp.vue";
|
||||||
const mapComponents = {
|
import EditorComp from "@/components/CreatedCourse/preview/EditorComp.vue";
|
||||||
VideoComp,
|
import { getType } from "@/hooks/useCreateCourseMaps";
|
||||||
};
|
const mapComponents = [VideoComp, AudioComp, EditorComp];
|
||||||
|
|
||||||
// 使用课程数据hook
|
// 使用课程数据hook
|
||||||
const { courseMetadata, courseList, courseActionButtons } = useCourseData();
|
const { courseMetadata, courseList, courseActionButtons, addChapter } =
|
||||||
const isSetting = ref(false);
|
useCourseData();
|
||||||
const isPreview = ref(false);
|
const isPreview = ref(false);
|
||||||
const chooseItemData = ref({});
|
const chooseItemData = ref({});
|
||||||
const showSettingDialog = ref(false);
|
const showSettingDialog = ref(false);
|
||||||
// 定义表格列
|
// 定义表格列
|
||||||
|
|
||||||
// 添加章
|
|
||||||
const addChapter = () => {
|
|
||||||
courseList.value.push({
|
|
||||||
title: "视频课程名称",
|
|
||||||
data: [],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const showDialog = ref(false);
|
const showDialog = ref(false);
|
||||||
|
|
||||||
// 课程操作映射
|
// 课程操作映射
|
||||||
const courseOperations = {
|
const courseOperations = {
|
||||||
addVideo: (index) => {
|
addVideo: () => {
|
||||||
|
courseMetadata.resType = 10;
|
||||||
showDialog.value = true;
|
showDialog.value = true;
|
||||||
},
|
},
|
||||||
addAudio: () => {
|
addAudio: () => {
|
||||||
console.log("添加音频功能调用");
|
courseMetadata.resType = 20;
|
||||||
},
|
showDialog.value = true;
|
||||||
addDocument: () => {
|
|
||||||
console.log("添加文档功能调用");
|
|
||||||
},
|
},
|
||||||
|
addDocument: () => {},
|
||||||
addImageText: () => {
|
addImageText: () => {
|
||||||
console.log("添加图文功能调用");
|
courseMetadata.resType = 41;
|
||||||
|
chooseItemData.value.resType = 41;
|
||||||
|
showSettingDialog.value = true;
|
||||||
},
|
},
|
||||||
addExternalLink: () => {
|
addExternalLink: () => {
|
||||||
console.log("添加外部链接功能调用");
|
console.log("添加外部链接功能调用");
|
||||||
@@ -62,7 +54,6 @@ const courseOperations = {
|
|||||||
console.log("添加评估功能调用");
|
console.log("添加评估功能调用");
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// 执行课程操作
|
// 执行课程操作
|
||||||
const executeCourseOperation = (operationName, data) => {
|
const executeCourseOperation = (operationName, data) => {
|
||||||
courseMetadata.chooseIndex = data;
|
courseMetadata.chooseIndex = data;
|
||||||
@@ -74,24 +65,21 @@ const executeCourseOperation = (operationName, data) => {
|
|||||||
console.warn(`未找到操作: ${operationName}`);
|
console.warn(`未找到操作: ${operationName}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const chooseItem = (data) => {
|
const chooseItem = (data) => {
|
||||||
console.log(data);
|
|
||||||
chooseItemData.value = data;
|
chooseItemData.value = data;
|
||||||
|
|
||||||
console.log(chooseItemData.value);
|
|
||||||
showSettingDialog.value = true;
|
showSettingDialog.value = true;
|
||||||
};
|
};
|
||||||
|
// 保存
|
||||||
const saveContent = () => {
|
const saveContent = () => {
|
||||||
console.log(chooseItemData.value);
|
|
||||||
if (courseMetadata.selectionIndex !== null) {
|
if (courseMetadata.selectionIndex !== null) {
|
||||||
|
courseList.value[courseMetadata.chooseIndex].data[
|
||||||
|
courseMetadata.selectionIndex
|
||||||
|
] = chooseItemData.value;
|
||||||
} else {
|
} else {
|
||||||
console.log(courseList.value, courseMetadata);
|
courseList.value[courseMetadata.chooseIndex].data.push({
|
||||||
|
resType: courseMetadata.resType,
|
||||||
courseList.value[courseMetadata.chooseIndex].data.push(
|
...chooseItemData.value,
|
||||||
chooseItemData.value
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
showDialog.value = false;
|
showDialog.value = false;
|
||||||
showSettingDialog.value = false;
|
showSettingDialog.value = false;
|
||||||
@@ -99,7 +87,16 @@ const saveContent = () => {
|
|||||||
const deleteRow = (data) => {
|
const deleteRow = (data) => {
|
||||||
courseMetadata.chooseIndex = data.index;
|
courseMetadata.chooseIndex = data.index;
|
||||||
courseMetadata.selectionIndex = data.selectionIndex;
|
courseMetadata.selectionIndex = data.selectionIndex;
|
||||||
chooseItemData.value = data.record;
|
ElMessageBox.confirm(`确定删除${data.record.name}吗?`, "删除确认", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "error",
|
||||||
|
}).then(() => {
|
||||||
|
courseList.value[courseMetadata.chooseIndex].data.splice(
|
||||||
|
courseMetadata.selectionIndex,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
const settingRow = (data) => {
|
const settingRow = (data) => {
|
||||||
courseMetadata.chooseIndex = data.index;
|
courseMetadata.chooseIndex = data.index;
|
||||||
@@ -164,18 +161,29 @@ const previewRow = (data) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 选择文件列表-->
|
<!-- 选择文件列表-->
|
||||||
<el-dialog v-model="showDialog" title="请选择操作">
|
<el-dialog v-model="showDialog" :title="getType(courseMetadata.resType)">
|
||||||
<chooseFileList @chooseItem="chooseItem"></chooseFileList>
|
<chooseFileList
|
||||||
|
v-if="showDialog"
|
||||||
|
@chooseItem="chooseItem"
|
||||||
|
:resType="courseMetadata.resType"
|
||||||
|
></chooseFileList>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 设置预览弹窗 -->
|
<!-- 设置预览弹窗 -->
|
||||||
<el-dialog v-model="showSettingDialog" title="请选择操作">
|
<el-dialog
|
||||||
|
v-model="showSettingDialog"
|
||||||
|
:title="isPreview ? '预览' : getType(chooseItemData.resType)"
|
||||||
|
>
|
||||||
|
<div v-for="item in mapComponents">
|
||||||
|
{{ chooseItemData.resType }}, {{ item }}
|
||||||
<component
|
<component
|
||||||
v-for="item in mapComponents"
|
v-if="Number(chooseItemData.resType) === item.resType"
|
||||||
:is="item"
|
:is="item"
|
||||||
v-model:dialogVideoForm="chooseItemData"
|
v-model:dialogVideoForm="chooseItemData"
|
||||||
:isPreview="isPreview"
|
:isPreview="isPreview"
|
||||||
></component>
|
></component>
|
||||||
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="dialog-footer">
|
<div class="dialog-footer">
|
||||||
<el-button @click="showSettingDialog = false">取消</el-button>
|
<el-button @click="showSettingDialog = false">取消</el-button>
|
||||||
|
|||||||
@@ -163,9 +163,10 @@ const renderNameColumn = () => {
|
|||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
border: "1px solid #d9d9d9",
|
border: "1px solid #d9d9d9",
|
||||||
|
outline: "none",
|
||||||
borderRadius: "4px",
|
borderRadius: "4px",
|
||||||
padding: "4px 11px",
|
padding: "4px 11px",
|
||||||
width: "200px",
|
width: "80%",
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
h(
|
h(
|
||||||
|
|||||||
Reference in New Issue
Block a user