mirror of
https://codeup.aliyun.com/67762337eccfc218f6110e0e/vue/fe-manage.git
synced 2025-12-06 17:36:44 +08:00
feat(course): implement video selection and management features
- Added AddVideo component for video selection with preview and settings - Implemented BasicTable component for displaying paginated data with custom rendering - Created course file API module for managing course materials - Enhanced dragTable component with edit, preview, and delete functionalities - Added comprehensive styling utilities for margins, paddings, and dimensions - Integrated video selection dialog in course creation workflow - Added support for video drag-and-drop and completion rule configuration - Implemented reusable course data management hook with icon support - Added chapter and section management capabilities - Enhanced course operation mapping for various content types
This commit is contained in:
92
src/api/modules/courseFile.js
Normal file
92
src/api/modules/courseFile.js
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
/**
|
||||||
|
* 课件文件内容的相关处理,当前只是业务管理员和教师功能使用<br/>
|
||||||
|
* 下载课件,一期是直接在新的窗口打开文件的地址就可以了。不采用流的方式下载
|
||||||
|
*/
|
||||||
|
import ajax from "./xajax.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询,课件的管理列表
|
||||||
|
* @param {Object} data
|
||||||
|
* {
|
||||||
|
name:查询的名称的关键字
|
||||||
|
self:true/false,默认是true,是否只查询自己上传的课件
|
||||||
|
resOwner1:资源归属一级的id
|
||||||
|
resOwner2:资源归属二级的id
|
||||||
|
resOwner3:资源归属三级的id
|
||||||
|
resType: 文件类型,10视频,20音频,30图片, 40 文档,41表图文,50表scrom包,90表其它
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const pageList = function (data) {
|
||||||
|
return ajax.post("/systemapi/xboe/m/course/file/pagelist", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择课件的查询,这里也是分页查询,只是返回的内容,字段会很少,用于课件制作那选择已有课件内容。
|
||||||
|
*
|
||||||
|
* @param {Object} data
|
||||||
|
* 查询参数如上面pageList方法
|
||||||
|
*/
|
||||||
|
const findList = function (data) {
|
||||||
|
//一期返回内容就对象,之后优化只是返回需要的几字段,不是全部
|
||||||
|
return ajax.post("/systemapi/xboe/m/course/file/pagelist", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传保存,上传课件成功后,再调用此接口,保存上传的文件信息。
|
||||||
|
* 接口返回课件记录(json对象),直接追加到列表中。
|
||||||
|
* @param {Object} data
|
||||||
|
* {
|
||||||
|
fileName:上传文件的名称
|
||||||
|
fileType: 文件的后缀名,比如:.mp4
|
||||||
|
filePath: 文件的保存路径
|
||||||
|
resOwner1:资源归属一级的id
|
||||||
|
resOwner2:资源归属二级的id
|
||||||
|
resOwner3:资源归属三级的id
|
||||||
|
resType: 文件类型,10视频,20音频,30图片, 40 文档,50表图文,60表scrom包,90表其它,
|
||||||
|
remark: 备注说明,可以为空,不填
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const saveUpload = function (data) {
|
||||||
|
return ajax.post("/systemapi/xboe/m/course/file/upload/save", data, {
|
||||||
|
timeout: 60000,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量更新,上传时,一个一个上传,下面的列表的保存,使用此方法
|
||||||
|
* @param {Object} data list集合
|
||||||
|
*saveUpload方法返回的对象
|
||||||
|
*/
|
||||||
|
|
||||||
|
const batchUpdate = function (data) {
|
||||||
|
return ajax.postJson("/systemapi/xboe/m/course/file/batch/update", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除一个课件文件
|
||||||
|
* @param {Object} data
|
||||||
|
* {
|
||||||
|
id:删除记录的id,
|
||||||
|
filePath: 文件的路径
|
||||||
|
flag: true/false, 是否是物理删除,在上传那是物理删除,在列表中是逻辑删除
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const delFile = function (data) {
|
||||||
|
return ajax.post("/systemapi/xboe/m/course/file/delete", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id获取详细信息,用于显示课件内容时,播放时
|
||||||
|
* @param {Object} id
|
||||||
|
*/
|
||||||
|
const detail = function (id) {
|
||||||
|
return ajax.get("/systemapi/xboe/m/course/file/detail?id=" + id);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
pageList,
|
||||||
|
saveUpload,
|
||||||
|
batchUpdate,
|
||||||
|
detail,
|
||||||
|
delFile,
|
||||||
|
};
|
||||||
@@ -766,3 +766,53 @@ textarea {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
//循环 生成 mt mb 从 5 10 20 30
|
||||||
|
@for $i from 1 through 100 {
|
||||||
|
.mt#{$i} {
|
||||||
|
margin-top: $i * 1px;
|
||||||
|
}
|
||||||
|
.mb#{$i} {
|
||||||
|
margin-bottom: $i * 1px;
|
||||||
|
}
|
||||||
|
.ml#{$i} {
|
||||||
|
margin-left: $i * 1px;
|
||||||
|
}
|
||||||
|
.mr#{$i} {
|
||||||
|
margin-right: $i * 1px;
|
||||||
|
}
|
||||||
|
.mv#{$i} {
|
||||||
|
margin-top: $i * 1px;
|
||||||
|
margin-bottom: $i * 1px;
|
||||||
|
}
|
||||||
|
.mh#{$i} {
|
||||||
|
margin-left: $i * 1px;
|
||||||
|
margin-right: $i * 1px;
|
||||||
|
}
|
||||||
|
.fs#{$i} {
|
||||||
|
font-size: $i * 1px;
|
||||||
|
}
|
||||||
|
.pt#{$i} {
|
||||||
|
padding-top: $i * 1px;
|
||||||
|
}
|
||||||
|
.pb#{$i} {
|
||||||
|
padding-bottom: $i * 1px;
|
||||||
|
}
|
||||||
|
.pl#{$i} {
|
||||||
|
padding-left: $i * 1px;
|
||||||
|
}
|
||||||
|
.pr#{$i} {
|
||||||
|
padding-right: $i * 1px;
|
||||||
|
}
|
||||||
|
.pv#{$i} {
|
||||||
|
padding-top: $i * 1px;
|
||||||
|
padding-bottom: $i * 1px;
|
||||||
|
}
|
||||||
|
.ph#{$i} {
|
||||||
|
padding-left: $i * 1px;
|
||||||
|
padding-right: $i * 1px;
|
||||||
|
}
|
||||||
|
.w#{$i} {
|
||||||
|
width: $i * 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
87
src/components/BasicElTable/BasicTable.vue
Normal file
87
src/components/BasicElTable/BasicTable.vue
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<script setup>
|
||||||
|
// import { ElTable, ElTableColumn } from "element-plus";
|
||||||
|
import { computed } from "vue";
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
pagination: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
pageIndex: 1,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
console.log(props);
|
||||||
|
|
||||||
|
const paginationCopy = computed(() => {
|
||||||
|
return {
|
||||||
|
pageSize: props.pagination.pageSize,
|
||||||
|
total: props.pagination.total,
|
||||||
|
current: props.pagination.pageIndex,
|
||||||
|
pageSizeOptions: ["10", "20", "50", "100"],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["change"]);
|
||||||
|
const change = (tablePage) => {
|
||||||
|
emit("changePage", tablePage);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a-table
|
||||||
|
:data-source="data"
|
||||||
|
:columns="columns"
|
||||||
|
:pagination="paginationCopy.pageSize ? paginationCopy : false"
|
||||||
|
class="tableBox"
|
||||||
|
@change="change"
|
||||||
|
align="center"
|
||||||
|
:loading="loading"
|
||||||
|
bordered
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ text, record, index, column }">
|
||||||
|
<div v-if="column.render" style="text-align: center">
|
||||||
|
<component :is="column.render({ row: record, index })"></component>
|
||||||
|
</div>
|
||||||
|
<div v-else style="text-align: center">
|
||||||
|
{{ record[column.key] }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
|
||||||
|
<!-- <el-table :data="data">-->
|
||||||
|
<!-- <el-table-column-->
|
||||||
|
<!-- v-for="(column, index) in columns"-->
|
||||||
|
<!-- :key="index"-->
|
||||||
|
<!-- :label="column.title"-->
|
||||||
|
<!-- :width="column.width"-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- <template #default="{ row }">-->
|
||||||
|
<!-- <div v-if="column.render">-->
|
||||||
|
<!-- <component :is="column.render({ row })"></component>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <div v-else>-->
|
||||||
|
<!-- {{ row[column.key] }}-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- </template>-->
|
||||||
|
<!-- </el-table-column>-->
|
||||||
|
<!-- </el-table>-->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
// 样式已移除,使用项目中全局定义的 .tableBox 样式
|
||||||
|
</style>
|
||||||
225
src/components/CreatedCourse/AddVideo.vue
Normal file
225
src/components/CreatedCourse/AddVideo.vue
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
<script setup>
|
||||||
|
import { reactive, onMounted, ref, h } from "vue";
|
||||||
|
import {
|
||||||
|
ElButton,
|
||||||
|
ElInput,
|
||||||
|
ElDialog,
|
||||||
|
ElForm,
|
||||||
|
ElFormItem,
|
||||||
|
ElRadioGroup,
|
||||||
|
ElRadio,
|
||||||
|
ElInputNumber,
|
||||||
|
} from "element-plus";
|
||||||
|
import BasicTable from "@/components/BasicElTable/BasicTable.vue";
|
||||||
|
import { getPageListByType } from "@/hooks/useCreateCourseMaps";
|
||||||
|
const tableData = ref([]);
|
||||||
|
const form = reactive({
|
||||||
|
name: "",
|
||||||
|
resType: 10,
|
||||||
|
});
|
||||||
|
let pagination = reactive({
|
||||||
|
pageSize: 10,
|
||||||
|
current: 1,
|
||||||
|
total: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const dialogVideoForm = ref({
|
||||||
|
name: "",
|
||||||
|
isDrag: false,
|
||||||
|
completeSetup: 0,
|
||||||
|
setupTage: "",
|
||||||
|
});
|
||||||
|
const loading = ref(false);
|
||||||
|
const showDialog = ref(false);
|
||||||
|
const emit = defineEmits(["saveContent"]);
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: "序号",
|
||||||
|
render: (params) => {
|
||||||
|
return h("span", {}, params.index + 1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "名称",
|
||||||
|
key: "name",
|
||||||
|
dataIndex: "name",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "创建人",
|
||||||
|
key: "sysCreateBy",
|
||||||
|
dataIndex: "sysCreateBy",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "创建时间",
|
||||||
|
key: "sysCreateTime",
|
||||||
|
dataIndex: "sysCreateTime",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "操作",
|
||||||
|
key: "action",
|
||||||
|
dataIndex: "action",
|
||||||
|
width: 150,
|
||||||
|
render: (params) => {
|
||||||
|
return h("div", [
|
||||||
|
h(
|
||||||
|
ElButton,
|
||||||
|
{
|
||||||
|
type: "primary",
|
||||||
|
size: "small",
|
||||||
|
onClick: () => {
|
||||||
|
console.log(params);
|
||||||
|
showDialog.value = true;
|
||||||
|
dialogVideoForm.value = {
|
||||||
|
...dialogVideoForm.value,
|
||||||
|
...params.row,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"选择"
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const changePagination = (PAGINATION) => {
|
||||||
|
pagination = PAGINATION;
|
||||||
|
getVideoList();
|
||||||
|
};
|
||||||
|
const getVideoList = () => {
|
||||||
|
loading.value = true;
|
||||||
|
let paramsData = {
|
||||||
|
...form,
|
||||||
|
pageSize: pagination.pageSize,
|
||||||
|
pageIndex: pagination.current,
|
||||||
|
self: true,
|
||||||
|
};
|
||||||
|
getPageListByType(paramsData).then((res) => {
|
||||||
|
loading.value = false;
|
||||||
|
tableData.value = res.result.list;
|
||||||
|
pagination.total = res.result.count;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveContent = (type) => {
|
||||||
|
showDialog.value = false;
|
||||||
|
emit("saveContent", {
|
||||||
|
...dialogVideoForm,
|
||||||
|
type: 10,
|
||||||
|
});
|
||||||
|
// postData.content=this.cware.content;
|
||||||
|
// this.cwareChange.content = deepClone(this.cware.content)
|
||||||
|
// if(this.cware.content.contentType==52){
|
||||||
|
// if(this.cware.linkInfo.url==''){
|
||||||
|
// this.$message.error("请填写外连URL地址");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// postData.content.content=JSON.stringify(this.cware.linkInfo);
|
||||||
|
// this.cwareChange.linkInfo = deepClone(this.cware.linkInfo)
|
||||||
|
// }else if(this.cware.content.contentType==10 || this.cware.content.contentType==20){
|
||||||
|
// if(this.cware.curriculumData.url==''){
|
||||||
|
// this.$message.error("请选择课件");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// postData.content.content=JSON.stringify(this.cware.curriculumData);
|
||||||
|
// this.cwareChange.curriculumData = deepClone(this.cware.curriculumData)
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getVideoList();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="add-video">
|
||||||
|
<div class="add-vide-header">
|
||||||
|
<div>
|
||||||
|
<el-button>上传新视频</el-button>
|
||||||
|
<span class="desc ml10">文件大小限制:1G,支持的文件类型:mp4 </span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-input
|
||||||
|
style="width: 150px"
|
||||||
|
placeholder="请输入视频名称"
|
||||||
|
v-model="form.name"
|
||||||
|
clearable
|
||||||
|
></el-input>
|
||||||
|
<el-button class="ml10" @click="getVideoList">查询</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt10">
|
||||||
|
<BasicTable
|
||||||
|
:columns="columns"
|
||||||
|
:data="tableData"
|
||||||
|
:pagination="pagination"
|
||||||
|
@changePage="changePagination"
|
||||||
|
:loading="loading"
|
||||||
|
></BasicTable>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-dialog v-model="showDialog" title="视频">
|
||||||
|
<el-form>
|
||||||
|
<el-form-item label="视频名称">
|
||||||
|
<el-input v-model="dialogVideoForm.name"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<video
|
||||||
|
controls
|
||||||
|
style="width: 100%; max-height: 400px"
|
||||||
|
class="mb10"
|
||||||
|
v-if="showDialog"
|
||||||
|
>
|
||||||
|
<source
|
||||||
|
:src="'http://home.hzer.xyz:9960/upload/' + dialogVideoForm.filePath"
|
||||||
|
type="video/mp4"
|
||||||
|
/>
|
||||||
|
您的浏览器不支持video
|
||||||
|
</video>
|
||||||
|
<el-form-item label="是否允许拖拽">
|
||||||
|
<el-radio-group v-model="dialogVideoForm.isDrag" 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="完成规则设置">
|
||||||
|
<el-radio-group v-model="dialogVideoForm.completeSetup">
|
||||||
|
<el-radio :label="0">默认(系统自动控制)</el-radio>
|
||||||
|
<el-radio :label="1"
|
||||||
|
>按进度
|
||||||
|
<el-input-number
|
||||||
|
:disabled="dialogVideoForm.completeSetup === 0"
|
||||||
|
v-model="dialogVideoForm.setupTage"
|
||||||
|
size="mini"
|
||||||
|
:min="0"
|
||||||
|
:max="100"
|
||||||
|
label="描述文字"
|
||||||
|
controls-position="right"
|
||||||
|
></el-input-number>
|
||||||
|
%</el-radio
|
||||||
|
>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="dialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="saveContent(1)"> 保存 </el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.add-video {
|
||||||
|
.add-vide-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
.desc {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,53 +1,271 @@
|
|||||||
import { ref, reactive } from "vue";
|
import { ref, reactive } from "vue";
|
||||||
import { message } from "ant-design-vue";
|
// import { message } from "ant-design-vue";
|
||||||
|
import {
|
||||||
|
SettingOutlined,
|
||||||
|
EyeOutlined,
|
||||||
|
DeleteOutlined,
|
||||||
|
MenuOutlined,
|
||||||
|
VideoCameraOutlined,
|
||||||
|
AudioOutlined,
|
||||||
|
FileTextOutlined,
|
||||||
|
PictureOutlined,
|
||||||
|
LinkOutlined,
|
||||||
|
FolderOpenOutlined,
|
||||||
|
BankOutlined,
|
||||||
|
EditOutlined,
|
||||||
|
} from "@ant-design/icons-vue";
|
||||||
|
import { createVNode, h } from "vue";
|
||||||
|
import { getType } from "@/hooks/useCreateCourseMaps";
|
||||||
/**
|
/**
|
||||||
* 课程数据管理hook
|
* 课程数据管理hook
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function useCourseData() {
|
export function useCourseData() {
|
||||||
// 课程元数据
|
// 课程元数据
|
||||||
const courseMetadata = reactive({
|
const courseMetadata = reactive({
|
||||||
courseName: "",
|
courseName: "",
|
||||||
createTime: "",
|
createTime: "",
|
||||||
|
chooseIndex: "",
|
||||||
|
sectionIndex: "",
|
||||||
});
|
});
|
||||||
|
const tableColumns = [
|
||||||
|
{
|
||||||
|
title: "序号",
|
||||||
|
key: "index",
|
||||||
|
width: 100,
|
||||||
|
customRender: ({ index }) => {
|
||||||
|
return h(
|
||||||
|
"span",
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[
|
||||||
|
h("span", { class: "drag-handle" }, [
|
||||||
|
createVNode(MenuOutlined, {
|
||||||
|
style: { fontSize: "14px", color: "#666" },
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
h("span", {}, index + 1),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "节名称",
|
||||||
|
key: "name",
|
||||||
|
dataIndex: "name",
|
||||||
|
customRender: ({ record }) => {
|
||||||
|
// 检查当前行是否处于编辑状态
|
||||||
|
if (record._value.isEdit) {
|
||||||
|
return h(
|
||||||
|
"span",
|
||||||
|
{ style: { display: "flex", alignItems: "center", gap: "8px" } },
|
||||||
|
[
|
||||||
|
h("input", {
|
||||||
|
value: record._value.copyName,
|
||||||
|
onInput: (e) => {
|
||||||
|
record._value.copyName = e.target.value;
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
border: "1px solid #d9d9d9",
|
||||||
|
borderRadius: "4px",
|
||||||
|
padding: "4px 11px",
|
||||||
|
width: "200px",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
h(
|
||||||
|
"a",
|
||||||
|
{
|
||||||
|
href: "javascript:void(0)",
|
||||||
|
style: { fontSize: "16px", color: "#52c41a" },
|
||||||
|
onClick: () => {
|
||||||
|
record._value.name = record._value.copyName;
|
||||||
|
record._value.copyName = null;
|
||||||
|
record._value.isEdit = false;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"✓"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 否则显示正常文本和编辑图标
|
||||||
|
const getIconComponent = (type) => {
|
||||||
|
switch (type) {
|
||||||
|
case "视频":
|
||||||
|
return VideoCameraOutlined;
|
||||||
|
case "音频":
|
||||||
|
return AudioOutlined;
|
||||||
|
case "文档":
|
||||||
|
return FileTextOutlined;
|
||||||
|
case "图文":
|
||||||
|
return PictureOutlined;
|
||||||
|
case "链接":
|
||||||
|
return LinkOutlined;
|
||||||
|
case "SCORM":
|
||||||
|
return FolderOpenOutlined;
|
||||||
|
case "考试":
|
||||||
|
return BankOutlined;
|
||||||
|
case "作业":
|
||||||
|
return EditOutlined;
|
||||||
|
case "评估":
|
||||||
|
return BankOutlined;
|
||||||
|
default:
|
||||||
|
return FileTextOutlined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Icon = getIconComponent(getType(record._value.resType));
|
||||||
|
return h(
|
||||||
|
"span",
|
||||||
|
{ style: { display: "flex", alignItems: "center", gap: "8px" } },
|
||||||
|
[
|
||||||
|
createVNode(Icon, { style: { color: "#1890ff" } }),
|
||||||
|
h("span", {}, record._value.name),
|
||||||
|
h(
|
||||||
|
"a",
|
||||||
|
{
|
||||||
|
href: "javascript:void(0)",
|
||||||
|
style: { marginLeft: "4px", fontSize: "12px" },
|
||||||
|
onClick: () => {
|
||||||
|
record._value.copyName = record._value.name;
|
||||||
|
record._value.isEdit = true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"✎"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "类型",
|
||||||
|
key: "resType",
|
||||||
|
dataIndex: "resType",
|
||||||
|
align: "center",
|
||||||
|
customRender: ({ record }) => {
|
||||||
|
return h(
|
||||||
|
"span",
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
display: "block",
|
||||||
|
textAlign: "center",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
getType(record._value.resType)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "操作",
|
||||||
|
key: "action",
|
||||||
|
width: 220,
|
||||||
|
align: "center",
|
||||||
|
customRender: ({ record, index, data }) => {
|
||||||
|
return h(
|
||||||
|
"span",
|
||||||
|
{
|
||||||
|
style: { display: "flex", justifyContent: "center", gap: "12px" },
|
||||||
|
},
|
||||||
|
[
|
||||||
|
// 设置
|
||||||
|
h(
|
||||||
|
"a",
|
||||||
|
{
|
||||||
|
href: "javascript:void(0)",
|
||||||
|
onClick: () => {
|
||||||
|
console.log("设置:", record);
|
||||||
|
// 在这里添加设置功能,比如打开设置弹窗
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[
|
||||||
|
createVNode(SettingOutlined, {
|
||||||
|
style: {
|
||||||
|
fontSize: "14px",
|
||||||
|
color: "#1890ff",
|
||||||
|
paddingRight: "10px",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
h(
|
||||||
|
"span",
|
||||||
|
{ style: { marginLeft: "4px", fontSize: "12px" } },
|
||||||
|
"设置"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
// 预览
|
||||||
|
h(
|
||||||
|
"a",
|
||||||
|
{
|
||||||
|
href: "javascript:void(0)",
|
||||||
|
onClick: () => {
|
||||||
|
console.log("预览:", record);
|
||||||
|
// 在这里添加预览功能
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[
|
||||||
|
createVNode(EyeOutlined, {
|
||||||
|
style: { fontSize: "14px", color: "#1890ff" },
|
||||||
|
}),
|
||||||
|
h(
|
||||||
|
"span",
|
||||||
|
{ style: { marginLeft: "4px", fontSize: "12px" } },
|
||||||
|
"预览"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
// 删除
|
||||||
|
h(
|
||||||
|
"a",
|
||||||
|
{
|
||||||
|
href: "javascript:void(0)",
|
||||||
|
onClick: () => {
|
||||||
|
console.log("删除:", record, "索引:", index);
|
||||||
|
// 执行删除操作
|
||||||
|
data.splice(index, 1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[
|
||||||
|
createVNode(DeleteOutlined, {
|
||||||
|
style: { fontSize: "14px", color: "red" },
|
||||||
|
}),
|
||||||
|
h(
|
||||||
|
"span",
|
||||||
|
{ style: { marginLeft: "4px", fontSize: "12px" } },
|
||||||
|
"删除"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
// 课程列表数据
|
// 课程列表数据
|
||||||
const courseList = ref([
|
const courseList = ref([
|
||||||
{
|
{
|
||||||
title: "课程1",
|
title: "课程1",
|
||||||
data: [
|
data: [],
|
||||||
{ key: "1-1", name: "视频课件名称", type: "视频" },
|
|
||||||
{ key: "1-2", name: "音频课件名称", type: "音频" },
|
|
||||||
{ key: "1-3", name: "文档课件名称", type: "文档" },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "课程2",
|
title: "课程2",
|
||||||
data: [
|
data: [],
|
||||||
{ key: "2-1", name: "图文课件名称", type: "图文" },
|
|
||||||
{ key: "2-2", name: "外部链接", type: "链接" },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "课程3",
|
title: "课程3",
|
||||||
data: [
|
data: [],
|
||||||
{ key: "3-1", name: "SCORM", type: "SCORM" },
|
|
||||||
{ key: "3-2", name: "考试名称", type: "考试" },
|
|
||||||
{ key: "3-3", name: "自定义考试名称", type: "考试" },
|
|
||||||
{ key: "3-4", name: "作业名称", type: "作业" },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 课程操作映射
|
// 课程操作映射
|
||||||
const courseOperations = {
|
const courseOperations = {
|
||||||
addVideo: (index) => {
|
addVideo: (index) => {
|
||||||
message.error("功能开发中");
|
courseMetadata.chooseIndex = index;
|
||||||
console.log("添加视频功能调用,索引:", index);
|
|
||||||
if (index !== undefined && courseList.value[index]) {
|
|
||||||
courseList.value[index].title = "课程4";
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
addAudio: () => {
|
addAudio: () => {
|
||||||
console.log("添加音频功能调用");
|
console.log("添加音频功能调用");
|
||||||
@@ -137,6 +355,7 @@ export function useCourseData() {
|
|||||||
courseMetadata,
|
courseMetadata,
|
||||||
courseList,
|
courseList,
|
||||||
courseActionButtons,
|
courseActionButtons,
|
||||||
executeCourseOperation
|
executeCourseOperation,
|
||||||
|
tableColumns,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
36
src/hooks/useCreateCourseMaps.js
Normal file
36
src/hooks/useCreateCourseMaps.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import apiCourseFile from "@/api/modules/courseFile";
|
||||||
|
|
||||||
|
const contentTypeMaps = {
|
||||||
|
10: "视频",
|
||||||
|
20: "音频",
|
||||||
|
30: "图片",
|
||||||
|
40: "文档",
|
||||||
|
41: "图文",
|
||||||
|
50: "scorm",
|
||||||
|
52: "外链",
|
||||||
|
60: "作业",
|
||||||
|
61: "考试",
|
||||||
|
62: "评估",
|
||||||
|
90: "其它",
|
||||||
|
};
|
||||||
|
export function getType(type) {
|
||||||
|
return contentTypeMaps[type];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据不同type 类型查询 媒体 视频等列表
|
||||||
|
export function getPageListByType(params) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
apiCourseFile
|
||||||
|
.pageList(params)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
resolve(res);
|
||||||
|
} else {
|
||||||
|
reject(res.message);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,44 +1,94 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import dragCollapse from "./dragCollapse.vue";
|
import dragCollapse from "./dragCollapse.vue";
|
||||||
import { ElButton, ElCheckbox } from "element-plus";
|
import { ElButton, ElCheckbox, ElDialog } from "element-plus";
|
||||||
import dragTable from "./dragTable.vue";
|
import dragTable from "./dragTable.vue";
|
||||||
import { message } from "ant-design-vue";
|
import { ref } from "vue";
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: "CreateCourse",
|
name: "CreateCourse",
|
||||||
});
|
});
|
||||||
import { ref, reactive, watch, toRaw, computed } from "vue";
|
|
||||||
import { useRoute, useRouter } from "vue-router";
|
|
||||||
import { useCourseData } from "@/hooks/useCourseData";
|
import { useCourseData } from "@/hooks/useCourseData";
|
||||||
|
import AddVideoComp from "@/components/CreatedCourse/AddVideo.vue";
|
||||||
|
|
||||||
// 使用课程数据hook
|
// 使用课程数据hook
|
||||||
const { courseMetadata, courseList, courseActionButtons, executeCourseOperation } = useCourseData();
|
const { courseMetadata, courseList, courseActionButtons } = useCourseData();
|
||||||
|
|
||||||
// 定义表格列
|
// 定义表格列
|
||||||
const tableColumns = [
|
|
||||||
{
|
// 添加章
|
||||||
title: "序号",
|
const addChapter = () => {
|
||||||
key: "index",
|
courseList.value.push({
|
||||||
width: 80,
|
title: "视频课程名称",
|
||||||
align: "center",
|
data: [],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const showDialog = ref(false);
|
||||||
|
|
||||||
|
// 课程操作映射
|
||||||
|
const courseOperations = {
|
||||||
|
addVideo: (index) => {
|
||||||
|
showDialog.value = true;
|
||||||
},
|
},
|
||||||
{
|
addAudio: () => {
|
||||||
title: "节名称",
|
console.log("添加音频功能调用");
|
||||||
key: "name",
|
|
||||||
dataIndex: "name",
|
|
||||||
},
|
},
|
||||||
{
|
addDocument: () => {
|
||||||
title: "类型",
|
console.log("添加文档功能调用");
|
||||||
key: "type",
|
|
||||||
dataIndex: "type",
|
|
||||||
align: "center",
|
|
||||||
},
|
},
|
||||||
{
|
addImageText: () => {
|
||||||
title: "操作",
|
console.log("添加图文功能调用");
|
||||||
key: "action",
|
|
||||||
width: 220,
|
|
||||||
align: "center",
|
|
||||||
},
|
},
|
||||||
];
|
addExternalLink: () => {
|
||||||
|
console.log("添加外部链接功能调用");
|
||||||
|
},
|
||||||
|
addScorm: () => {
|
||||||
|
console.log("添加SCORM功能调用");
|
||||||
|
},
|
||||||
|
addExam: () => {
|
||||||
|
console.log("添加考试功能调用");
|
||||||
|
},
|
||||||
|
addHomework: () => {
|
||||||
|
console.log("添加作业功能调用");
|
||||||
|
},
|
||||||
|
addAssessment: () => {
|
||||||
|
console.log("添加评估功能调用");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// 执行课程操作
|
||||||
|
const executeCourseOperation = (operationName, data) => {
|
||||||
|
courseMetadata.chooseIndex = data;
|
||||||
|
courseMetadata.selectionIndex = null;
|
||||||
|
if (courseOperations[operationName]) {
|
||||||
|
courseOperations[operationName](data);
|
||||||
|
} else {
|
||||||
|
console.warn(`未找到操作: ${operationName}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const isSetting = ref(false);
|
||||||
|
|
||||||
|
const saveVideo = (data) => {
|
||||||
|
showDialog.value = false;
|
||||||
|
if (isSetting.value) {
|
||||||
|
} else {
|
||||||
|
courseList.value[courseMetadata.chooseIndex].data.push(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteRow = (data) => {
|
||||||
|
console.log(data);
|
||||||
|
courseMetadata.chooseIndex = data.index;
|
||||||
|
courseMetadata.selectionIndex = data.selectionIndex;
|
||||||
|
};
|
||||||
|
const settingRow = (data) => {
|
||||||
|
courseMetadata.chooseIndex = data.index;
|
||||||
|
courseMetadata.selectionIndex = data.selectionIndex;
|
||||||
|
};
|
||||||
|
const previewRow = (data) => {
|
||||||
|
courseMetadata.chooseIndex = data.index;
|
||||||
|
courseMetadata.selectionIndex = data.selectionIndex;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -49,7 +99,7 @@ const tableColumns = [
|
|||||||
</div>
|
</div>
|
||||||
<div class="course-content">
|
<div class="course-content">
|
||||||
<div style="padding: 10px">
|
<div style="padding: 10px">
|
||||||
<el-button>添加章</el-button>
|
<el-button @click="addChapter">添加章</el-button>
|
||||||
<el-checkbox style="margin-left: 10px">顺序学习</el-checkbox>
|
<el-checkbox style="margin-left: 10px">顺序学习</el-checkbox>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -74,15 +124,23 @@ const tableColumns = [
|
|||||||
<!-- 修改:添加 groupId 和 tableId 属性以支持跨表格拖拽 -->
|
<!-- 修改:添加 groupId 和 tableId 属性以支持跨表格拖拽 -->
|
||||||
<dragTable
|
<dragTable
|
||||||
:data="course.data"
|
:data="course.data"
|
||||||
:columns="tableColumns"
|
|
||||||
:group-id="'course-chapters'"
|
:group-id="'course-chapters'"
|
||||||
:table-id="'chapter-' + index"
|
:table-id="'chapter-' + index"
|
||||||
|
:index="index"
|
||||||
|
@delete="deleteRow"
|
||||||
|
@setting="settingRow"
|
||||||
|
@preview="previewRow"
|
||||||
></dragTable>
|
></dragTable>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</dragCollapse>
|
</dragCollapse>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 课程按钮弹窗-->
|
||||||
|
<el-dialog v-model="showDialog" title="请选择操作">
|
||||||
|
<AddVideoComp @saveContent="saveVideo"></AddVideoComp>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -93,6 +151,10 @@ const tableColumns = [
|
|||||||
.course-header {
|
.course-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
.title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.drag-course-btn-content {
|
.drag-course-btn-content {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import {
|
|||||||
EyeOutlined,
|
EyeOutlined,
|
||||||
SettingOutlined,
|
SettingOutlined,
|
||||||
} from "@ant-design/icons-vue";
|
} from "@ant-design/icons-vue";
|
||||||
|
import { getType } from "@/hooks/useCreateCourseMaps";
|
||||||
// 定义 props
|
// 定义 props
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
@@ -60,8 +60,14 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
index: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 设置 预览 删除 三个按钮emit 事件
|
||||||
|
const emit = defineEmits(["setting", "preview", "delete"]);
|
||||||
// 根据类型返回对应图标组件
|
// 根据类型返回对应图标组件
|
||||||
const getIconComponent = (type) => {
|
const getIconComponent = (type) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -95,24 +101,191 @@ const editValue = ref("");
|
|||||||
|
|
||||||
// 开始编辑
|
// 开始编辑
|
||||||
const startEdit = (record) => {
|
const startEdit = (record) => {
|
||||||
editingKey.value = record.key;
|
record._value.copyName = record._value.name;
|
||||||
editValue.value = record.name;
|
record._value.isEdit = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 保存编辑
|
// 保存编辑
|
||||||
const saveEdit = (record) => {
|
const saveEdit = (record) => {
|
||||||
record.name = editValue.value;
|
record._value.name = record._value.copyName;
|
||||||
editingKey.value = "";
|
record._value.copyName = null;
|
||||||
editValue.value = "";
|
record._value.isEdit = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 删除处理函数
|
// 删除处理函数
|
||||||
const handleDelete = (key) => {
|
const handleDelete = (index) => {
|
||||||
const index = props.data.findIndex((item) => item.key === key);
|
emit("delete", { index: props.index, selectionIndex: index });
|
||||||
if (index > -1) {
|
};
|
||||||
props.data.splice(index, 1);
|
const handleSetting = (index) => {
|
||||||
console.log("删除了:", key);
|
emit("setting", { index: props.index, selectionIndex: index });
|
||||||
}
|
};
|
||||||
|
const handlePreview = (index) => {
|
||||||
|
emit("preview", { index: props.index, selectionIndex: index });
|
||||||
|
};
|
||||||
|
|
||||||
|
// 渲染序号列
|
||||||
|
const renderIndexColumn = () => {
|
||||||
|
return ({ index }) => {
|
||||||
|
return h(
|
||||||
|
"span",
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[
|
||||||
|
h("span", { class: "drag-handle" }, [
|
||||||
|
createVNode(MenuOutlined, {
|
||||||
|
style: { fontSize: "14px", color: "#666" },
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
h("span", {}, index + 1),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 渲染名称列
|
||||||
|
const renderNameColumn = () => {
|
||||||
|
return ({ record }) => {
|
||||||
|
// 如果处于编辑状态,显示输入框和确认按钮
|
||||||
|
if (record._value.isEdit) {
|
||||||
|
return h(
|
||||||
|
"span",
|
||||||
|
{ style: { display: "flex", alignItems: "center", gap: "8px" } },
|
||||||
|
[
|
||||||
|
h("input", {
|
||||||
|
value: record._value.copyName,
|
||||||
|
onInput: (e) => {
|
||||||
|
record._value.copyName = e.target.value;
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
border: "1px solid #d9d9d9",
|
||||||
|
borderRadius: "4px",
|
||||||
|
padding: "4px 11px",
|
||||||
|
width: "200px",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
h(
|
||||||
|
"a",
|
||||||
|
{
|
||||||
|
href: "javascript:void(0)",
|
||||||
|
style: { fontSize: "16px", color: "#52c41a" },
|
||||||
|
onClick: () => {
|
||||||
|
saveEdit(record);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"✓"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 否则显示正常文本和编辑图标
|
||||||
|
const Icon = getIconComponent(getType(record._value.resType));
|
||||||
|
return h(
|
||||||
|
"span",
|
||||||
|
{ style: { display: "flex", alignItems: "center", gap: "8px" } },
|
||||||
|
[
|
||||||
|
createVNode(Icon, { style: { color: "#1890ff" } }),
|
||||||
|
h("span", {}, record._value.name),
|
||||||
|
h(
|
||||||
|
"a",
|
||||||
|
{
|
||||||
|
href: "javascript:void(0)",
|
||||||
|
style: { marginLeft: "4px", fontSize: "12px" },
|
||||||
|
onClick: () => {
|
||||||
|
startEdit(record);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"✎"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 渲染资源类型列
|
||||||
|
const renderResTypeColumn = () => {
|
||||||
|
return ({ record }) => {
|
||||||
|
return h(
|
||||||
|
"span",
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
display: "block",
|
||||||
|
textAlign: "center",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
getType(record._value.resType)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 渲染操作列
|
||||||
|
const renderActionColumn = () => {
|
||||||
|
return ({ record, index }) => {
|
||||||
|
return h(
|
||||||
|
"span",
|
||||||
|
{
|
||||||
|
style: { display: "flex", justifyContent: "center", gap: "12px" },
|
||||||
|
},
|
||||||
|
[
|
||||||
|
// 设置
|
||||||
|
h(
|
||||||
|
"a",
|
||||||
|
{ href: "javascript:void(0)", onClick: () => handleSetting(index) },
|
||||||
|
[
|
||||||
|
createVNode(SettingOutlined, {
|
||||||
|
style: {
|
||||||
|
fontSize: "14px",
|
||||||
|
color: "#1890ff",
|
||||||
|
paddingRight: "10px",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
h(
|
||||||
|
"span",
|
||||||
|
{ style: { marginLeft: "4px", fontSize: "12px" } },
|
||||||
|
"设置"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
// 预览
|
||||||
|
h(
|
||||||
|
"a",
|
||||||
|
{ href: "javascript:void(0)", onClick: () => handlePreview(index) },
|
||||||
|
[
|
||||||
|
createVNode(EyeOutlined, {
|
||||||
|
style: { fontSize: "14px", color: "#1890ff" },
|
||||||
|
}),
|
||||||
|
h(
|
||||||
|
"span",
|
||||||
|
{ style: { marginLeft: "4px", fontSize: "12px" } },
|
||||||
|
"预览"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
// 删除
|
||||||
|
h(
|
||||||
|
"a",
|
||||||
|
{
|
||||||
|
href: "javascript:void(0)",
|
||||||
|
onClick: () => handleDelete(index),
|
||||||
|
},
|
||||||
|
[
|
||||||
|
createVNode(DeleteOutlined, {
|
||||||
|
style: { fontSize: "14px", color: "red" },
|
||||||
|
}),
|
||||||
|
h(
|
||||||
|
"span",
|
||||||
|
{ style: { marginLeft: "4px", fontSize: "12px" } },
|
||||||
|
"删除"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理列定义,添加自定义渲染逻辑
|
// 处理列定义,添加自定义渲染逻辑
|
||||||
@@ -125,142 +298,21 @@ const processedColumns = computed(() => {
|
|||||||
|
|
||||||
// 为序号列添加自定义渲染
|
// 为序号列添加自定义渲染
|
||||||
if (col.key === "index") {
|
if (col.key === "index") {
|
||||||
processedCol.customRender = ({ index }) => {
|
processedCol.customRender = renderIndexColumn();
|
||||||
return h(
|
|
||||||
"span",
|
|
||||||
{
|
|
||||||
style: {
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[
|
|
||||||
h("span", { class: "drag-handle" }, [
|
|
||||||
createVNode(MenuOutlined, {
|
|
||||||
style: { fontSize: "14px", color: "#666" },
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
h("span", {}, index + 1),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 为节名称列添加自定义渲染
|
// 为节名称列添加自定义渲染
|
||||||
if (col.key === "name") {
|
if (col.key === "name") {
|
||||||
processedCol.customRender = ({ record }) => {
|
processedCol.customRender = renderNameColumn();
|
||||||
// 检查当前行是否处于编辑状态
|
}
|
||||||
const isEditing = record.key === editingKey.value;
|
|
||||||
|
|
||||||
// 如果处于编辑状态,显示输入框和确认按钮
|
if (col.key === "resType") {
|
||||||
if (isEditing) {
|
processedCol.customRender = renderResTypeColumn();
|
||||||
return h(
|
|
||||||
"span",
|
|
||||||
{ style: { display: "flex", alignItems: "center", gap: "8px" } },
|
|
||||||
[
|
|
||||||
h("input", {
|
|
||||||
value: editValue.value,
|
|
||||||
onInput: (e) => {
|
|
||||||
editValue.value = e.target.value;
|
|
||||||
},
|
|
||||||
style: {
|
|
||||||
border: "1px solid #d9d9d9",
|
|
||||||
borderRadius: "4px",
|
|
||||||
padding: "4px 11px",
|
|
||||||
width: "200px",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
h(
|
|
||||||
"a",
|
|
||||||
{
|
|
||||||
href: "javascript:void(0)",
|
|
||||||
style: { fontSize: "16px", color: "#52c41a" },
|
|
||||||
onClick: () => saveEdit(record),
|
|
||||||
},
|
|
||||||
"✓"
|
|
||||||
),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 否则显示正常文本和编辑图标
|
|
||||||
const Icon = getIconComponent(record.type);
|
|
||||||
return h(
|
|
||||||
"span",
|
|
||||||
{ style: { display: "flex", alignItems: "center", gap: "8px" } },
|
|
||||||
[
|
|
||||||
createVNode(Icon, { style: { color: "#1890ff" } }),
|
|
||||||
h("span", {}, record.name),
|
|
||||||
h(
|
|
||||||
"a",
|
|
||||||
{
|
|
||||||
href: "javascript:void(0)",
|
|
||||||
style: { marginLeft: "4px", fontSize: "12px" },
|
|
||||||
onClick: () => startEdit(record),
|
|
||||||
},
|
|
||||||
"✎"
|
|
||||||
),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 为操作列添加自定义渲染
|
// 为操作列添加自定义渲染
|
||||||
if (col.key === "action") {
|
if (col.key === "action") {
|
||||||
processedCol.customRender = ({ record }) => {
|
processedCol.customRender = renderActionColumn();
|
||||||
return h(
|
|
||||||
"span",
|
|
||||||
{
|
|
||||||
style: { display: "flex", justifyContent: "center", gap: "12px" },
|
|
||||||
},
|
|
||||||
[
|
|
||||||
// 设置
|
|
||||||
h("a", { href: "javascript:void(0)" }, [
|
|
||||||
createVNode(SettingOutlined, {
|
|
||||||
style: {
|
|
||||||
fontSize: "14px",
|
|
||||||
color: "#1890ff",
|
|
||||||
paddingRight: "10px",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
h(
|
|
||||||
"span",
|
|
||||||
{ style: { marginLeft: "4px", fontSize: "12px" } },
|
|
||||||
"设置"
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
// 预览
|
|
||||||
h("a", { href: "javascript:void(0)" }, [
|
|
||||||
createVNode(EyeOutlined, {
|
|
||||||
style: { fontSize: "14px", color: "#1890ff" },
|
|
||||||
}),
|
|
||||||
h(
|
|
||||||
"span",
|
|
||||||
{ style: { marginLeft: "4px", fontSize: "12px" } },
|
|
||||||
"预览"
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
// 删除
|
|
||||||
h(
|
|
||||||
"a",
|
|
||||||
{
|
|
||||||
href: "javascript:void(0)",
|
|
||||||
onClick: () => handleDelete(record.key),
|
|
||||||
},
|
|
||||||
[
|
|
||||||
createVNode(DeleteOutlined, {
|
|
||||||
style: { fontSize: "14px", color: "red" },
|
|
||||||
}),
|
|
||||||
h(
|
|
||||||
"span",
|
|
||||||
{ style: { marginLeft: "4px", fontSize: "12px" } },
|
|
||||||
"删除"
|
|
||||||
),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return processedCol;
|
return processedCol;
|
||||||
@@ -274,85 +326,13 @@ const processedColumns = computed(() => {
|
|||||||
key: "index",
|
key: "index",
|
||||||
width: 80,
|
width: 80,
|
||||||
align: "center",
|
align: "center",
|
||||||
customRender: ({ index }) => {
|
customRender: renderIndexColumn(),
|
||||||
return h(
|
|
||||||
"span",
|
|
||||||
{
|
|
||||||
style: {
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[
|
|
||||||
h("span", { class: "drag-handle" }, [
|
|
||||||
createVNode(MenuOutlined, {
|
|
||||||
style: { fontSize: "14px", color: "#666" },
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
h("span", {}, index + 1),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "节名称",
|
title: "节名称",
|
||||||
key: "name",
|
key: "name",
|
||||||
dataIndex: "name",
|
dataIndex: "name",
|
||||||
customRender: ({ record }) => {
|
customRender: renderNameColumn(),
|
||||||
// 检查当前行是否处于编辑状态
|
|
||||||
const isEditing = record.key === editingKey.value;
|
|
||||||
|
|
||||||
// 如果处于编辑状态,显示输入框和确认按钮
|
|
||||||
if (isEditing) {
|
|
||||||
return h(
|
|
||||||
"span",
|
|
||||||
{ style: { display: "flex", alignItems: "center", gap: "8px" } },
|
|
||||||
[
|
|
||||||
h("input", {
|
|
||||||
value: editValue.value,
|
|
||||||
onInput: (e) => {
|
|
||||||
editValue.value = e.target.value;
|
|
||||||
},
|
|
||||||
style: {
|
|
||||||
border: "1px solid #d9d9d9",
|
|
||||||
borderRadius: "4px",
|
|
||||||
padding: "4px 11px",
|
|
||||||
width: "200px",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
h(
|
|
||||||
"a",
|
|
||||||
{
|
|
||||||
href: "javascript:void(0)",
|
|
||||||
style: { fontSize: "16px", color: "#52c41a" },
|
|
||||||
onClick: () => saveEdit(record),
|
|
||||||
},
|
|
||||||
"✓"
|
|
||||||
),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 否则显示正常文本和编辑图标
|
|
||||||
const Icon = getIconComponent(record.type);
|
|
||||||
return h(
|
|
||||||
"span",
|
|
||||||
{ style: { display: "flex", alignItems: "center", gap: "8px" } },
|
|
||||||
[
|
|
||||||
createVNode(Icon, { style: { color: "#1890ff" } }),
|
|
||||||
h("span", {}, record.name),
|
|
||||||
h(
|
|
||||||
"a",
|
|
||||||
{
|
|
||||||
href: "javascript:void(0)",
|
|
||||||
style: { marginLeft: "4px", fontSize: "12px" },
|
|
||||||
onClick: () => startEdit(record),
|
|
||||||
},
|
|
||||||
"✎"
|
|
||||||
),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "类型",
|
title: "类型",
|
||||||
@@ -365,58 +345,7 @@ const processedColumns = computed(() => {
|
|||||||
key: "action",
|
key: "action",
|
||||||
width: 220,
|
width: 220,
|
||||||
align: "center",
|
align: "center",
|
||||||
customRender: ({ record }) => {
|
customRender: renderActionColumn(),
|
||||||
return h(
|
|
||||||
"span",
|
|
||||||
{ style: { display: "flex", justifyContent: "center", gap: "12px" } },
|
|
||||||
[
|
|
||||||
// 设置
|
|
||||||
h("a", { href: "javascript:void(0)" }, [
|
|
||||||
createVNode(SettingOutlined, {
|
|
||||||
style: {
|
|
||||||
fontSize: "14px",
|
|
||||||
color: "#1890ff",
|
|
||||||
paddingRight: "10px",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
h(
|
|
||||||
"span",
|
|
||||||
{ style: { marginLeft: "4px", fontSize: "12px" } },
|
|
||||||
"设置"
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
// 预览
|
|
||||||
h("a", { href: "javascript:void(0)" }, [
|
|
||||||
createVNode(EyeOutlined, {
|
|
||||||
style: { fontSize: "14px", color: "#1890ff" },
|
|
||||||
}),
|
|
||||||
h(
|
|
||||||
"span",
|
|
||||||
{ style: { marginLeft: "4px", fontSize: "12px" } },
|
|
||||||
"预览"
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
// 删除
|
|
||||||
h(
|
|
||||||
"a",
|
|
||||||
{
|
|
||||||
href: "javascript:void(0)",
|
|
||||||
onClick: () => handleDelete(record.key),
|
|
||||||
},
|
|
||||||
[
|
|
||||||
createVNode(DeleteOutlined, {
|
|
||||||
style: { fontSize: "14px", color: "red" },
|
|
||||||
}),
|
|
||||||
h(
|
|
||||||
"span",
|
|
||||||
{ style: { marginLeft: "4px", fontSize: "12px" } },
|
|
||||||
"删除"
|
|
||||||
),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
@@ -440,10 +369,6 @@ const components = {
|
|||||||
pull: props.allowDragOut,
|
pull: props.allowDragOut,
|
||||||
put: props.allowDragIn,
|
put: props.allowDragIn,
|
||||||
},
|
},
|
||||||
onStart: () => {},
|
|
||||||
onEnd: (evt) => {
|
|
||||||
console.log("拖拽结束,新顺序:", props.data);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
item: ({ element, index }) =>
|
item: ({ element, index }) =>
|
||||||
|
|||||||
Reference in New Issue
Block a user