dbsd_kczx/src/views/zy/jiaoXueDanYuanNeiRong/stuIndex.vue

596 lines
21 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.

<template>
<div class="max">
<!-- <a-affix :offset-top="0" :target="() => doctomen"> -->
<div class="topButton" v-if="!props.hiddenBtn">
<a-space>
<!-- <a-button type="primary" @click="save" :loading="saveLoading">保存</a-button> -->
<a-button @click="reload"><Icon icon="ant-design:reload-outlined"/>刷新</a-button>
<!-- <a-button type="primary" @click="addOne()" class="addBtn" title="新增一级"><Icon icon="ant-design:plus-outlined"/>新增标题</a-button> -->
</a-space>
</div>
<!-- </a-affix> -->
<div class="maxDiv">
<a-empty v-if="!dataSource || !dataSource.length"/>
<div v-for="(one, oneIndex) in dataSource" :key="oneIndex">
<div class="box">
<!-- 下一层 -->
<a-card>
<a-collapse ghost expandIconPosition="right">
<a-collapse-panel :key="one._id" forceRender>
<template #header>
<div class="topDiv">
<div>{{ one.sort }}</div>
<div class="inputd">
<div class="ainput ainputNoEdit" @click="(e) => { stop(e); }">&nbsp;{{ one.title }}</div>
</div>
</div>
</template>
<!-- <template #extra>
<a-space>
<div><a-button type="primary" @click="addTwo($event, one)" class="twoBtn addBtn" title="新增二级"><Icon icon="ant-design:plus-outlined"/>新增章节</a-button></div>
<div><a-button type="primary" danger @click="delOne($event, one)" class="addBtn" title="删除此项及以下"><Icon icon="ant-design:delete"/>删除</a-button></div>
</a-space>
</template> -->
<div v-for="(two, twoIndex) in one.childrenList" :key="twoIndex">
<div class="box">
<!-- 下一层 -->
<a-card>
<a-collapse ghost expandIconPosition="right">
<a-collapse-panel :key="two._id" forceRender>
<template #header>
<div class="twoTopDiv">
<div class="topDiv">
<div>{{ one.sort }}.{{ two.sort }}</div>
<div class="twoInputd">
<!-- <a-input v-if="two.isEdit" :value="two.title" @change="changeInput($event, two, 'title')" @blur="() => { two.isEdit = false }" @click="stop" class="ainput"/> -->
<div class="ainput ainputNoEdit" @click="(e) => { stop(e); }" >&nbsp;{{ two.title }}</div>
</div>
</div>
</div>
</template>
<!-- <template #extra>
<a-space>
<a-button type="primary" class="addBtn" title="展开收起"><Icon icon="ant-design:plus-outlined"/>上传资源</a-button>
<a-button type="primary" danger @click="delTwo($event, one, two)" class="addBtn" title="删除此项及以下"><Icon icon="ant-design:delete"/>删除</a-button>
</a-space>
</template> -->
<!-- <div style="padding-top: 1rem;">
<a-space>
<div><a-button type="primary" @click="addThree($event, two, 'video')" class="addBtn"><Icon icon="ant-design:video-camera-outlined"/>视频</a-button></div>
<div><a-button type="primary" @click="addThree($event, two, 'document')" class="addBtn"><Icon icon="ant-design:file-outlined"/>文档</a-button></div>
<div><a-button type="primary" @click="addThree($event, two, 'richText')" class="addBtn"><Icon icon="ant-design:file-text-outlined"/>富文本</a-button></div>
</a-space>
</div> -->
<div v-for="(three, threeIndex) in two.childrenList" :key="threeIndex">
<div class="box" @mouseenter="() => three.showBtn = true" @mouseleave="() => three.showBtn = false">
<Icon icon="ant-design:holder-outlined"/>
{{ one.sort }}.{{ two.sort }}.{{ three.sort }}
<a-tag class="hand" @click="viewThreePage(three)">
<template v-if="three.type == 'video'"><Icon icon="ant-design:video-camera-outlined" />视频</template>
<template v-if="three.type == 'document'"><Icon icon="ant-design:file-outlined" />文档</template>
<template v-if="three.type == 'richText'"><Icon icon="ant-design:file-text-outlined" />富文本</template>
</a-tag>
<span class="hand" @click="viewThreePage(three)">{{ three.title }}</span>
<span v-show="three.showBtn">
<a-space>
<a-button type="primary" size="small" title="下载" v-if="three.type == 'video' || three.type == 'document'" @click="downloadFile(three)" class="addBtn"><Icon icon="ant-design:vertical-align-bottom-outlined"/></a-button>
<a-button type="primary" size="small" title="查看" v-if="three.type == 'richText'" @click="viewThreePage(three)" class="addBtn"><Icon icon="ant-design:fund-view-outlined"/></a-button>
</a-space>
</span>
<a-card v-if="false">
<template #title>
{{ one.sort }}.{{ two.sort }}.{{ three.sort }}
<template v-if="three.type == 'video'">
<Icon icon="ant-design:video-camera-outlined" />视频
</template>
<template v-else-if="three.type == 'document'">
<Icon icon="ant-design:file-outlined" />文档
</template>
<template v-else-if="three.type == 'richText'">
<Icon icon="ant-design:file-text-outlined" />富文本
</template>
</template>
<!-- <template #extra>
<a-space>
<a-button type="primary" v-if="three.isEdit" @click="() => three.isEdit = false" class="addBtn"><Icon icon="ant-design:edit"/>确认</a-button>
<a-button type="primary" v-if="!three.isEdit" @click="() => three.isEdit = true" class="addBtn"><Icon icon="ant-design:edit"/>编辑</a-button>
<a-button type="primary" danger @click="delThree($event, two, three)" class="addBtn"><Icon icon="ant-design:delete"/>删除</a-button>
</a-space>
</template> -->
<div class="topDiv">
<template v-if="three.type == 'video'">
<!-- <j-upload v-model:value="three.filePath" maxCount="1" suffixList="avi,mov,mkv,mpeg,asf,3gp,wmv,mp4,flv,rmvb"/> video/mp4,video/webm,video/ogv-->
<!-- <j-upload v-if="three.isEdit" v-model:value="three.filePath" maxCount="1" text="上传视频" accept=".mp4,.webm,.ogv" :forceAcceptVerify="true"/> -->
<!-- <div class="ainput">&nbsp;{{ getFileAccessHttpUrl(three.filePath) }}</div> -->
<!-- <downloadAssembly :filePath="three.filePath"/> -->
<downloadAssembly :filePath="three.filePath"/>
</template>
<template v-if="three.type == 'document'">
<!-- <j-upload v-if="three.isEdit" v-model:value="three.filePath" maxCount="1"/> -->
<downloadAssembly :filePath="three.filePath"/>
</template>
<template v-if="three.type == 'richText'">
<!-- <j-editor v-if="three.isEdit" v-model:value="three.richText"/> -->
<div class="richText" v-html="three.richText"></div>
</template>
<!-- <template v-if="three.type == 'classroomTest'">
随堂测试
</template>
<template v-if="three.type == 'discuss'">
讨论
</template> -->
</div>
</a-card>
</div>
</div>
</a-collapse-panel>
</a-collapse>
</a-card>
</div>
</div>
</a-collapse-panel>
</a-collapse>
</a-card>
</div>
<!-- <template #footer> -->
<!-- <a-button @click="sureChange" type="primary" style="margin-top: 100px">确定</a-button> -->
<!-- </template> -->
</div>
</div>
<a-modal :title="threePageTitle" :width="800" :visible="threePageOpen" @ok="threePageHandleOk" :okButtonProps="{ class: { 'jee-hidden': threePageDisableSubmit } }" @cancel="threePageHandleCancel" cancelText="关闭">
<a-card>
<div>
标题:
<a-input v-if="!threePageDisableSubmit" :value="threePageData.three.title" @change="changeInput($event, threePageData.three, 'title')" @click="stop" class="ainput"/>
<div v-else>{{ threePageData.three.title }}</div>
</div>
<div>
<template v-if="threePageData.three.type == 'video'">
<j-upload v-if="!threePageDisableSubmit" v-model:value="threePageData.three.filePath" :maxCount="1" text="上传视频" accept=".mp4,.webm,.ogv" :forceAcceptVerify="true"/>
<downloadAssembly v-else :filePath="threePageData.three.filePath"/>
</template>
<template v-if="threePageData.three.type == 'document'">
<j-upload v-if="!threePageDisableSubmit" v-model:value="threePageData.three.filePath" :maxCount="1"/>
<downloadAssembly v-else :filePath="threePageData.three.filePath"/>
</template>
<template v-if="threePageData.three.type == 'richText' && threePageOpen">
<j-editor v-if="!threePageDisableSubmit" v-model:value="threePageData.three.richText"/>
<div v-else class="richText" v-html="threePageData.three.richText"></div>
</template>
</div>
</a-card>
</a-modal>
</div>
</template>
<script lang="ts" name="jiaoXueDanYuanNeiRongIndex" setup>
import { ref, reactive, onMounted, unref, nextTick, watch } from 'vue';
import { Input, Popover, Pagination, Empty, Affix as aAffix } from 'ant-design-vue';
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
import { useRouter } from 'vue-router';
import { randomString, simpleDebounce, getFileAccessHttpUrl } from '/@/utils/common/compUtils'
import draggable from 'vuedraggable';
import JUpload from '/@/components/Form/src/jeecg/components/JUpload/JUpload.vue';
import JEditor from '/@/components/Form/src/jeecg/components/JEditor.vue';
import downloadAssembly from '/@/views/zy/jiaoXueDanYuanNeiRong/downloadAssembly.vue';
//当前路由信息
const { currentRoute } = useRouter();
const { query } = unref(currentRoute);
const { rwbh, xqxn, type, teano } = query;//获取传递参数
const props = defineProps({
hiddenBtn: { type: Boolean, default: false },
});
// watch(() => props.hiddenBtn, (v) => {
// if(v){
// reload();
// }
// });
const { createConfirm, createMessage } = useMessage();
const queryParam = ref<any>({});
const dataSource = ref<any>([]);
const isNotMove = ref<boolean>(true);
const saveLoading = ref<boolean>(false);
const threePageTitle = ref<String>('详细');
const threePageOpen = ref<boolean>(false);
const threePageDisableSubmit = ref<boolean>(false);
const threePageData = ref<Object>(null);
//公共的拖动排序组件绑定数据
const draggableBind = ref<Object>({
sort: false,
//唯一键
itemKey: '_id',
// onStart: moveDraggable,
// onAdd: onAddFn,
// onRemove: onRemoveFn,
// onUpdate: onUpdateFn,
//有效移动后触发
onEnd: endDraggable,
//鼠标按下触发
// onChoose: simpleDebounce(chooseDraggable, 500),
// onChoose: chooseDraggable,
//鼠标松开后触发
// onUnchoose: unchooseDraggable,
// onSort: onSortFn,
// onFilter: onFilterFn,
// onClone: onCloneFn,
// onMove: onMoveFn,
});
enum Api {
list = '/teachingunitcontent/kcTeachingUnitContentOne/allList',
edit = '/teachingunitcontent/kcTeachingUnitContentOne/edit',
}
/**
* 列表接口
* @param params
*/
const listAll = (params) => defHttp.get({ url: Api.list, params });
const editAll = (params) => defHttp.post({ url: Api.edit, params }, { isTransformResponse: true });
function reload() {
loadData();
}
async function loadData() {
dataSource.value = [];
let params = {
rwbh,
xqxn,
teano,
fabu:'1',
}
await listAll(params).then(res => {
dataRecursion(res, (x) => x._id = x.id);
dataSource.value = res;
});
nextTick(() => {
// setTimeout(() => {
expandAllTable();
// nextTick(() => {
// expandAllTable();
// });
// }, 1000);
});
}
function expandAllTable() {
document.querySelectorAll('.max .ant-collapse-header').forEach(x => {
if(x.getAttribute('aria-expanded') == 'false') x.click()
});
}
//递归执行方法
function dataRecursion(list, fn){
let _list = list;
_list.forEach((x,i) => {
fn(x,i);
if(x.childrenList && x.childrenList.length){
dataRecursion(x.childrenList, fn);
}
})
}
//刷新数据的排序
function refreshDataSort(){
dataRecursion(dataSource.value, (x, i) => x.sort = i+1);
}
//创建新的节点
function createNoneData(){
let data = {
//临时ID兼容新增和修改
_id: randomString(32),
title: null,
sort: 0,
childrenList: [],
}
return data;
}
function stop(e) {
e?.stopPropagation();
}
function changeInput(e, pdata, key) {
let { target } = e;
let { value } = target;
pdata[key] = value;
}
function addOne(){
dataSource.value.push(createNoneData());
createMessage.success('添加标题成功!');
nextTick(() => {
refreshDataSort();
})
}
function delOne(e, one){
stop(e);
let index = dataSource.value.findIndex(x => x == one);
if(index == -1) return;
dataSource.value.splice(index, 1);
createMessage.success('删除标题成功!');
nextTick(() => {
refreshDataSort();
})
}
// function insertOne(index){
// dataSource.value.splice(index,0, createNoneData());
// }
//获取祖宗级对象
function getBtnEle(e, className){
if(e){
//如果一级就是,直接甩出去
if(e?.classList?.contains(className)){
return e;
} else {
//如果父节点也没有,往更父的节点查找
return getBtnEle(e.parentElement, className);
}
// //如果父节点也没有,往更深的
// if(!e.parentElement.classList.contains(className)){
// //不存在
// console.log('111111',e.parentElement);
// }else{
// console.log('2222',e.parentElement);
// return e.parentElement;
// }
}
}
function addTwo(e, one){
let btn = getBtnEle(e.target, 'twoBtn');
if(btn == null){
console.error('出大事了!');
return;
}
let tab = null;
document.querySelectorAll('.maxDiv .box .ant-collapse-header').forEach(x => {
let twoBtn = x.querySelector('.twoBtn');
if(twoBtn == btn){
tab = x;
}
});
let ariaExpanded = tab.getAttribute('aria-expanded');
if(ariaExpanded == 'false') {
}else{
stop(e);
}
if(one.childrenList){
one.childrenList.push(createNoneData());
}else{
one.childrenList = [ createNoneData() ];
}
createMessage.success('添加章节成功!');
nextTick(() => {
refreshDataSort();
})
}
function delTwo(e, one, two){
stop(e);
let index = one.childrenList.findIndex(x => x == two);
if(index == -1) return;
one.childrenList.splice(index, 1);
createMessage.success('删除章节成功!');
nextTick(() => {
refreshDataSort();
})
}
// function insertTwo(one, index){
// one.childrenList.splice(index,0, createNoneData());
// }
function addThree(e, two, type){
stop(e);
let data = createNoneData();
delete data.title;
data.type = type;
data.richText = null;
data.filePath = null;
if(two.childrenList){
two.childrenList.push(data);
}else{
two.childrenList = [ data ];
}
createMessage.success('新增成功!');
nextTick(() => {
refreshDataSort();
})
}
function delThree(e, two, three){
stop(e);
let index = two.childrenList.findIndex(x => x == three);
if(index == -1) return;
two.childrenList.splice(index, 1);
createMessage.success('删除成功!');
nextTick(() => {
refreshDataSort();
})
}
function viewThreePage(three) {
threePageOpen.value = true;
threePageDisableSubmit.value = true;
threePageData.value = { three };
}
function threePageHandleOk(){
threePageOpen.value = false;
}
function threePageHandleCancel(){
threePageOpen.value = false;
}
function downloadFile(three) {
let url = getFileAccessHttpUrl(three.filePath);
window.open(url,"_blank");
}
//移动结束时触发,如果未移动则不触发,刷新排序,
function endDraggable(){
//移动后如果有富文本编辑器则会失效,需要此法重置一下
isNotMove.value = false;
nextTick(() => {
isNotMove.value = true;
refreshDataSort();
})
}
//按下鼠标按键后触发
// function chooseDraggable(){
// // isNotMove.value = false;
// }
//松开鼠标按键后触发
// function unchooseDraggable(){
// // isNotMove.value = true;
// }
// function onAddFn() { console.log('onAddFn'); }
// function onRemoveFn() { console.log('onRemoveFn'); }
// function onUpdateFn() { console.log('onUpdateFn'); }
// function onChooseFn() { console.log('onChooseFn'); }
// function onUnchooseFn() { console.log('onUnchooseFn'); }
// function onSortFn() { console.log('onSortFn'); }
// function onFilterFn() { console.log('onFilterFn'); }
// function onCloneFn() { console.log('onCloneFn'); }
// function onMoveFn() { console.log('onMoveFn'); }
// //移动时触发,关闭富文本编辑器
// function moveDraggable() {
// console.log('move');
// isNotMove.value = false;
// }
async function save(){
saveLoading.value = true;
console.log(unref(dataSource));
let saveData = {
rwbh,
xqxn,
teachingUnitContentOneList: unref(dataSource),
}
if(!saveData.rwbh || !saveData.xqxn){
createMessage.error('无法保存!');
saveLoading.value = false;
return;
}else if(!saveData.teachingUnitContentOneList || !saveData.teachingUnitContentOneList.length){
createMessage.warn('请添加数据!');
saveLoading.value = false;
return;
}
await editAll(saveData);
saveLoading.value = false;
}
loadData();
defineExpose({
reload,
})
</script>
<style lang="less" scoped>
.hand {
cursor:pointer;
}
.max {
height: calc(100vh - 225px);
//height: calc(-132px + 100vh);
// min-height: calc(-132px + 100vh);
// max-height: calc(-132px + 100vh);
overflow: auto;
//overflow: hidden;
.maxDiv {
height: calc(100% - 94px);
overflow-y: auto;
}
}
.box {
margin: .5rem 0 0 0;
.itemTop {
width: 100%;
}
}
.topButton {
padding-top: 5px;
}
.ainput {
width: 100%;
}
.ainputNoEdit {
border: #d9d9d9 solid 1px;
}
.inputd {
width: calc(100% - 35px);
}
.topDiv {
width: 100%;
display: flex;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
}
.twoInputd {
width: calc(100% - 45px);
}
.twoTopDiv {
width: 100%;
}
.richText {
max-height: 400px;
overflow: auto;
}
:deep(.maxDiv) .ant-collapse-header{
align-items: center;
}
/deep/.ant-card-body{
padding: 5px;
}
/deep/.ant-collapse-ghost > .ant-collapse-item > .ant-collapse-content > .ant-collapse-content-box {
padding-top: 0px;
padding-bottom: 8px;
}
</style>