增加预览pdf

This commit is contained in:
lyc 2024-08-22 09:42:55 +08:00
parent 13598615c7
commit 8ec96996c6
4 changed files with 356 additions and 243 deletions

View File

@ -43,6 +43,7 @@
"pinia-plugin-persistedstate": "^3.2.1", "pinia-plugin-persistedstate": "^3.2.1",
"spark-md5": "^3.0.2", "spark-md5": "^3.0.2",
"vue-router": "^4.4.0", "vue-router": "^4.4.0",
"xgplayer": "^3.0.19",
"xlsx": "^0.18.5" "xlsx": "^0.18.5"
}, },
"devDependencies": { "devDependencies": {

View File

@ -8,7 +8,7 @@
http-equiv="Content-Security-Policy" http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:"
/> --> /> -->
<meta http-equiv="Content-Security-Policy" content="connect-src *; default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src * 'self' data: blob:" /> <meta http-equiv="Content-Security-Policy" content="connect-src *; default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src * 'self' ;img-src * 'self' data: blob:" />
</head> </head>

View File

@ -0,0 +1,113 @@
<template>
<el-drawer v-model="model" class="preview-drawer" title="title" :modal="false" :with-header="false" append-to-body
size="50%" :before-close="handleClose">
<div class="flex drawer-header">
<div>
<div class="flex file-name">
<FileImage :size="30" :file-name="'xx.jpg'" />
<span class="name">地理0831-10</span>
</div>
<div class="flex file-tag">
<el-tag type="info" class="tag">图片</el-tag>
<el-tag type="info" class="tag">扩展素材</el-tag>
</div>
</div>
<div class="header-close" @click="onClose"><i class="iconfont icon-guanbi"></i></div>
</div>
<div class="drawer-content">
<!-- <iframe src="./aaa.pdf" width="600px" height="600px"></iframe> -->
<div ref="playerRef" class="video-box"></div>
</div>
</el-drawer>
</template>
<script setup>
import { watch, ref, nextTick } from 'vue'
import Player from 'xgplayer';
import 'xgplayer/dist/index.min.css'
import FileImage from '@/components/file-image/index.vue'
const model = defineModel()
const playerRef = ref();
const handleClose = () => {
}
//
const onClose = () => {
model.value = false
}
const init = () => {
nextTick(() => {
let player = new Player({
el: playerRef.value,
url: 'https://sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-360p.mp4',
width: '100%',
autoplay: false,// false
autoplayMuted: true,// false
screenShot: true,// 使false
videoAttributes: {// video
crossOrigin: 'anonymous',// CORS
},
marginControls: false,// false
loop:true,// false
volume:0.3,// ,0 ~ 1(0.6)
});
})
}
watch(model, (newVal) => {
if (newVal) {
init()
}
})
</script>
<style lang="scss" scoped>
:deep(.el-drawer__body) {
padding: 0;
}
.preview-drawer {
padding: 0;
}
.drawer-header {
justify-content: space-between;
align-items: center;
background-color: #fff;
.file-name {
align-items: center;
margin-bottom: 5px;
.name {
margin-left: 5px;
}
}
.file-tag {
.tag {
margin-right: 10px;
}
}
.header-close {
cursor: pointer;
.icon-guanbi {
font-size: 20px;
}
}
}
.drawer-content {
margin-top: 10px;
}
.video-box {
width: 100%;
height: 300px
}
</style>

View File

@ -1,17 +1,17 @@
<template> <template>
<el-dialog v-model="dialogVisible" center top="10vh" width="600px" :show-close="false" append-to-body <el-dialog v-model="model" center top="10vh" width="600px" :show-close="false" append-to-body
style="border-radius: 10px; padding: 10px 15px;"> style="border-radius: 10px; padding: 10px 15px;">
<template #header> <template #header>
<div class="homerwork-header flex"> <div class="homerwork-header flex">
<span>{{ title }}</span> <span>{{ title }}</span>
<i class="iconfont icon-guanbi" @click="cloneDialog"></i> <i class="iconfont icon-guanbi" @click="cloneDialog(ruleFormRef)"></i>
</div> </div>
</template> </template>
<div v-loading="setLoading"> <div v-loading="setLoading">
<el-form :model="form" label-width="80px" ref="ruleForm" :rules="rules"> <el-form :model="form" label-width="80px" ref="ruleFormRef" :rules="rules">
<el-form-item label="班级" prop="grade"> <el-form-item label="班级" prop="grade">
<el-scrollbar max-height="200px" style="width: 100%;"> <el-scrollbar max-height="200px" style="width: 100%;">
<el-tree ref="treeRef" :data="gradeList" :props="defaultProps" :load="getLoad" node-key="id" <el-tree ref="treeRef" :props="defaultProps" :load="getLoad" node-key="id" :default-expanded-keys="defaultExpandedKeys"
@check="handleCheckChange" lazy show-checkbox /> @check="handleCheckChange" lazy show-checkbox />
</el-scrollbar> </el-scrollbar>
</el-form-item> </el-form-item>
@ -41,8 +41,8 @@
</div> </div>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button @click.stop="cloneDialog">取消</el-button> <el-button @click.stop="cloneDialog(ruleFormRef)">取消</el-button>
<el-button type="primary" @click.stop="onSubmit('ruleForm')"> <el-button type="primary" @click.stop="onSubmit(ruleFormRef)">
确定 确定
</el-button> </el-button>
</div> </div>
@ -50,256 +50,257 @@
</el-dialog> </el-dialog>
</template> </template>
<script> <script setup>
import { onMounted, reactive, ref } from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { listClassmain, listClassgroup } from '@/api/classManage/index' import { listClassmain, listClassgroup } from '@/api/classManage/index'
import { saveByClassWorkArray } from '@/api/teaching/classwork' import { saveByClassWorkArray } from '@/api/teaching/classwork'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
import { uniqBy, groupBy } from 'lodash' import { uniqBy, groupBy } from 'lodash'
export default { const props = defineProps({
props: { entpcourseid: {
modelValue: { default: ''
type: Boolean,
default: false
},
entpcourseid: {
default: ''
},
row: {
default: ''
},
title: {
type: String,
default: '布置作业'
}
}, },
data() { row: {
default: ''
},
title: {
type: String,
default: '布置作业'
}
})
const emit = defineEmits(['on-close', 'on-success'])
return { const model = defineModel({ type: Boolean, default: false })
dialogVisible: false, const ruleFormRef = ref('')
defaultProps: { //
children: 'children', const defaultProps = {
label: 'label', children: 'children',
isLeaf: 'leaf', label: 'label',
}, isLeaf: 'leaf',
setLoading: false, }
// const treeRef = ref(null);
userInfo: null, //
// const defaultExpandedKeys = ref([])
gradeList: [], // loading
curGradeId: '', const setLoading = ref(false)
// //
groupList: [], const userInfo = useUserStore().user
// //
studentList: [], const gradeList = ref([])
// //
form: { const studentList = ref([])
feedback: '必做', //
deaddate: '', const form = reactive({
timelength: 1 feedback: '必做',
}, deaddate: '',
// timelength: 1
rules: { })
grade: [ //
{ validator: this.validateGrade, trigger: 'blur' } const validateGrade = (rule, value, callback) => {
], if (studentList.value.length == 0) {
student: [ callback(new Error('请勾选班级或者学生'));
{ validator: this.validateStudent, trigger: 'blur' } }
] else {
} callback()
}
}
const validateStudent = (rule, value, callback)=>{
if (studentList.value.length == 0) {
callback(new Error('学生不能为空'));
}
else {
callback()
}
}
const rules = reactive({
grade: [
{ validator: validateGrade, trigger: 'blur' }
],
student: [
{ validator: validateStudent, trigger: 'blur' }
]
})
}
}, //
created() { const getGradeList = async ()=> {
// let { rows } = await listClassmain({ classuserid: userInfo.userId, pageSize: 100, status: 'open' })
this.form.deaddate = this.getCurrentDate() + ' ' + '10:00:00' rows.forEach(item => {
this.userInfo = useUserStore().user item.label = item.caption
}, item.level = 0
methods: { item.leaf = false
// item.children = []
getGradeList() { item.classstudentlist = JSON.parse("[" + item.classstudentlist + "]")
listClassmain({ classuserid: this.userInfo.userId, pageSize: 100, status: 'open' }).then(res => { item.classstudentlist.forEach(el => {
let list = res.rows el.classId = item.id
list.forEach(item => { })
item.label = item.caption })
item.level = 0 return rows
item.children = [] }
item.classstudentlist = JSON.parse("[" + item.classstudentlist + "]") //
item.classstudentlist.forEach(el => { const getLoad = async (node, resolve) => {
el.classId = item.id //
}) if (node.level == 0) {
}) gradeList.value = await getGradeList()
this.gradeList = list resolve(gradeList.value)
}) }
}, //
// if (node.level == 1) {
getLoad(node, resolve) { listClassgroup({ classid: node.key, orderby: 'orderidx', pageSize: 100 }).then(res => {
if (node.level == 0) return resolve([]) if (res.rows.length > 0) {
// let ary = []
if (node.level == 1) { res.rows.forEach(item => {
listClassgroup({ classid: node.key, orderby: 'orderidx', pageSize: 100 }).then(res => { if (item.parentid === 0) {
if (res.rows.length > 0) { //studentGroup
let ary = [] let studentGroup = JSON.parse("[" + item.studentlist + "]")
res.rows.forEach(item => { studentGroup.forEach(el => {
if (item.parentid === 0) { el.label = el.name
//studentGroup el.leaf = true
let studentGroup = JSON.parse("[" + item.studentlist + "]") el.level = 2
studentGroup.forEach(el => { el.id = el.studentid
el.label = el.name el.classId = item.classid
el.leaf = true })
el.level = 2, ary.push({
el.id = el.studentid label: item.groupname,
el.classId = item.classid leaf: false,
}) ...item,
ary.push({ level: 1,
label: item.groupname, // children
...item, children: studentGroup
level: 1,
children: studentGroup
})
}
}) })
resolve(ary)
}
else {
resolve([])
} }
}) })
} resolve(ary)
//
if (node.level == 2) {
resolve(node.data.children)
}
},
//
handleCheckChange(data, checked) {
this.studentList = []
//
let checkNodes = checked.checkedNodes
let ary = []
checkNodes.forEach(item => {
//
if (item.level == 0) {
ary = [...ary, ...(item.classstudentlist)]
}
//
if (item.level == 1) {
ary = [...ary, ...(item.children)]
}
//
if (item.level == 2) {
ary = [...ary, item]
}
})
this.studentList = uniqBy(ary, 'studentid')
},
//
delStudent(index) {
this.studentList.splice(index, 1)
},
onSubmit(formName) {
this.$refs[formName].validate(valid => {
if (valid) {
/**
* 根据学生列表中的classId分班
* studentList 为选中的所有学生 这些学生可能来自不同班级
*/
let gradeObj = groupBy(this.studentList, 'classId')
//
let ary = []
for (const value in gradeObj) {
// AIx web
let obj = {
id: 0,
parentid: this.row.id,
classid: value,
classcourseid: 0,
entpcourseid: this.entpcourseid,
studentlist: JSON.stringify(gradeObj[value]),
feedback: this.form.feedback,
workkey: "",
timelength: this.form.timelength,
weights: 1,
deaddate: this.form.deaddate,
workdate: this.getCurrentDate(),
uniquekey: this.row.uniquekey,
entpcourseworklist: "[" + this.row.entpcourseworklist + "]",
needMsgNotifine: 'false',
msgkey: 'newclasswork',
title: "作业任务",
msgcontent: '',
teachername: this.userInfo.nickName,
unixstamp: new Date().getTime(),
worktype: this.row.worktype
}
ary.push(obj)
}
this.setLoading = true
saveByClassWorkArray({
classworkarray: JSON.stringify(ary)
}).then(() => {
this.setLoading = false
ElMessage.success('操作成功')
this.cloneDialog()
}).catch(()=>{
this.setLoading = false
})
} else {
return false
}
})
},
//
cloneDialog() {
this.$emit('on-close')
this.studentList = []
this.$refs['ruleForm'].resetFields();
},
//
getCurrentDate() {
const now = new Date();
const year = now.getFullYear();
let month = now.getMonth() + 1; // 0+1
let day = now.getDate()
if(month < 10){
month = '0' + month
}
if(day < 10){
day = '0' + day
}
return `${year}-${month}-${day}`;
},
validateGrade(rule, value, callback) {
if (this.studentList.length == 0) {
callback(new Error('请勾选班级或者学生'));
} }
else { else {
callback() //
let students = node.data.classstudentlist
students.forEach(item =>{
item.label = item.name
item.level = 2
item.leaf = true
})
resolve(students)
} }
}, })
validateStudent(rule, value, callback) { }
if (this.studentList.length == 0) { //
callback(new Error('学生不能为空')); if (node.level == 2) {
} resolve(node.data.children)
else { }
callback()
}
},
},
watch: {
modelValue(val) {
this.dialogVisible = val
if (val) {
this.getGradeList()
}
}
},
} }
//
const handleCheckChange = (data, checked)=> {
studentList.value = []
//
let checkNodes = checked.checkedNodes
let ary = []
checkNodes.forEach(item => {
//
if (item.level == 0) {
ary = [...ary, ...(item.classstudentlist)]
}
//
if (item.level == 1) {
ary = [...ary, ...(item.children)]
}
//
if (item.level == 2) {
ary = [...ary, item]
}
})
studentList.value = uniqBy(ary, 'studentid')
}
//
const delStudent = (index) => {
studentList.value.splice(index, 1)
}
const onSubmit = (formEl)=> {
if(!formEl) return
formEl.validate(valid => {
if (valid) {
/**
* 根据学生列表中的classId分班
* studentList 为选中的所有学生 这些学生可能来自不同班级
*/
let gradeObj = groupBy(studentList.value, 'classId')
//
let ary = []
for (const value in gradeObj) {
// AIx web
let obj = {
id: 0,
parentid: props.row.id,
classid: value,
classcourseid: 0,
entpcourseid: props.entpcourseid,
studentlist: JSON.stringify(gradeObj[value]),
feedback: form.feedback,
workkey: "",
timelength: form.timelength,
weights: 1,
deaddate: form.deaddate,
workdate: getCurrentDate(),
uniquekey: props.row.uniquekey,
entpcourseworklist: "[" + props.row.entpcourseworklist + "]",
needMsgNotifine: 'false',
msgkey: 'newclasswork',
title: "作业任务",
msgcontent: '',
teachername: userInfo.nickName,
unixstamp: new Date().getTime(),
worktype: props.row.worktype
}
ary.push(obj)
}
setLoading.value = true
saveByClassWorkArray({
classworkarray: JSON.stringify(ary)
}).then(() => {
setLoading.value = false
ElMessage.success('操作成功')
emit('on-success')
cloneDialog(formEl)
}).catch(()=>{
setLoading.value = false
})
} else {
return false
}
})
}
//
const cloneDialog = (formEl)=> {
studentList.value = []
treeRef.value.setCheckedKeys([])
defaultExpandedKeys.value = []
formEl.resetFields()
model.value = false
}
//
const getCurrentDate = ()=> {
const now = new Date();
const year = now.getFullYear();
let month = now.getMonth() + 1; // 0+1
let day = now.getDate()
if(month < 10){
month = '0' + month
}
if(day < 10){
day = '0' + day
}
return `${year}-${month}-${day}`;
}
onMounted(()=>{
//
form.deaddate = getCurrentDate() + ' ' + '10:00:00'
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -326,7 +327,5 @@ export default {
:deep(.el-checkbox){ :deep(.el-checkbox){
transform : scale(1.3) transform : scale(1.3)
} }
:deep(.el-icon){
transform : scale(1.3)
}
</style> </style>