增加预览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,19 +50,15 @@
</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: {
modelValue: {
type: Boolean,
default: false
},
entpcourseid: { entpcourseid: {
default: '' default: ''
}, },
@ -73,69 +69,83 @@ export default {
type: String, type: String,
default: '布置作业' default: '布置作业'
} }
}, })
data() { const emit = defineEmits(['on-close', 'on-success'])
return { const model = defineModel({ type: Boolean, default: false })
dialogVisible: false, const ruleFormRef = ref('')
defaultProps: { //
const defaultProps = {
children: 'children', children: 'children',
label: 'label', label: 'label',
isLeaf: 'leaf', isLeaf: 'leaf',
}, }
setLoading: false, const treeRef = ref(null);
//
const defaultExpandedKeys = ref([])
// loading
const setLoading = ref(false)
// //
userInfo: null, const userInfo = useUserStore().user
// //
gradeList: [], const gradeList = ref([])
curGradeId: '', //
// const studentList = ref([])
groupList: [],
//
studentList: [],
// //
form: { const form = reactive({
feedback: '必做', feedback: '必做',
deaddate: '', deaddate: '',
timelength: 1 timelength: 1
}, })
// //
rules: { const validateGrade = (rule, value, callback) => {
if (studentList.value.length == 0) {
callback(new Error('请勾选班级或者学生'));
}
else {
callback()
}
}
const validateStudent = (rule, value, callback)=>{
if (studentList.value.length == 0) {
callback(new Error('学生不能为空'));
}
else {
callback()
}
}
const rules = reactive({
grade: [ grade: [
{ validator: this.validateGrade, trigger: 'blur' } { validator: validateGrade, trigger: 'blur' }
], ],
student: [ student: [
{ validator: this.validateStudent, trigger: 'blur' } { 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
},
methods: {
//
getGradeList() {
listClassmain({ classuserid: this.userInfo.userId, pageSize: 100, status: 'open' }).then(res => {
let list = res.rows
list.forEach(item => {
item.label = item.caption item.label = item.caption
item.level = 0 item.level = 0
item.leaf = false
item.children = [] item.children = []
item.classstudentlist = JSON.parse("[" + item.classstudentlist + "]") item.classstudentlist = JSON.parse("[" + item.classstudentlist + "]")
item.classstudentlist.forEach(el => { item.classstudentlist.forEach(el => {
el.classId = item.id el.classId = item.id
}) })
}) })
this.gradeList = list return rows
}) }
},
// //
getLoad(node, resolve) { const getLoad = async (node, resolve) => {
if (node.level == 0) return resolve([]) //
if (node.level == 0) {
gradeList.value = await getGradeList()
resolve(gradeList.value)
}
// //
if (node.level == 1) { if (node.level == 1) {
listClassgroup({ classid: node.key, orderby: 'orderidx', pageSize: 100 }).then(res => { listClassgroup({ classid: node.key, orderby: 'orderidx', pageSize: 100 }).then(res => {
@ -143,19 +153,21 @@ export default {
let ary = [] let ary = []
res.rows.forEach(item => { res.rows.forEach(item => {
if (item.parentid === 0) { if (item.parentid === 0) {
//studentGroup //studentGroup
let studentGroup = JSON.parse("[" + item.studentlist + "]") let studentGroup = JSON.parse("[" + item.studentlist + "]")
studentGroup.forEach(el => { studentGroup.forEach(el => {
el.label = el.name el.label = el.name
el.leaf = true el.leaf = true
el.level = 2, el.level = 2
el.id = el.studentid el.id = el.studentid
el.classId = item.classid el.classId = item.classid
}) })
ary.push({ ary.push({
label: item.groupname, label: item.groupname,
leaf: false,
...item, ...item,
level: 1, level: 1,
// children
children: studentGroup children: studentGroup
}) })
} }
@ -163,7 +175,14 @@ export default {
resolve(ary) resolve(ary)
} }
else { else {
resolve([]) //
let students = node.data.classstudentlist
students.forEach(item =>{
item.label = item.name
item.level = 2
item.leaf = true
})
resolve(students)
} }
}) })
} }
@ -172,10 +191,10 @@ export default {
resolve(node.data.children) resolve(node.data.children)
} }
}, }
// //
handleCheckChange(data, checked) { const handleCheckChange = (data, checked)=> {
this.studentList = [] studentList.value = []
// //
let checkNodes = checked.checkedNodes let checkNodes = checked.checkedNodes
let ary = [] let ary = []
@ -193,74 +212,78 @@ export default {
ary = [...ary, item] ary = [...ary, item]
} }
}) })
this.studentList = uniqBy(ary, 'studentid') studentList.value = uniqBy(ary, 'studentid')
}, }
// //
delStudent(index) { const delStudent = (index) => {
this.studentList.splice(index, 1) studentList.value.splice(index, 1)
}, }
onSubmit(formName) {
this.$refs[formName].validate(valid => { const onSubmit = (formEl)=> {
if(!formEl) return
formEl.validate(valid => {
if (valid) { if (valid) {
/** /**
* 根据学生列表中的classId分班 * 根据学生列表中的classId分班
* studentList 为选中的所有学生 这些学生可能来自不同班级 * studentList 为选中的所有学生 这些学生可能来自不同班级
*/ */
let gradeObj = groupBy(this.studentList, 'classId') let gradeObj = groupBy(studentList.value, 'classId')
// //
let ary = [] let ary = []
for (const value in gradeObj) { for (const value in gradeObj) {
// AIx web // AIx web
let obj = { let obj = {
id: 0, id: 0,
parentid: this.row.id, parentid: props.row.id,
classid: value, classid: value,
classcourseid: 0, classcourseid: 0,
entpcourseid: this.entpcourseid, entpcourseid: props.entpcourseid,
studentlist: JSON.stringify(gradeObj[value]), studentlist: JSON.stringify(gradeObj[value]),
feedback: this.form.feedback, feedback: form.feedback,
workkey: "", workkey: "",
timelength: this.form.timelength, timelength: form.timelength,
weights: 1, weights: 1,
deaddate: this.form.deaddate, deaddate: form.deaddate,
workdate: this.getCurrentDate(), workdate: getCurrentDate(),
uniquekey: this.row.uniquekey, uniquekey: props.row.uniquekey,
entpcourseworklist: "[" + this.row.entpcourseworklist + "]", entpcourseworklist: "[" + props.row.entpcourseworklist + "]",
needMsgNotifine: 'false', needMsgNotifine: 'false',
msgkey: 'newclasswork', msgkey: 'newclasswork',
title: "作业任务", title: "作业任务",
msgcontent: '', msgcontent: '',
teachername: this.userInfo.nickName, teachername: userInfo.nickName,
unixstamp: new Date().getTime(), unixstamp: new Date().getTime(),
worktype: this.row.worktype worktype: props.row.worktype
} }
ary.push(obj) ary.push(obj)
} }
this.setLoading = true setLoading.value = true
saveByClassWorkArray({ saveByClassWorkArray({
classworkarray: JSON.stringify(ary) classworkarray: JSON.stringify(ary)
}).then(() => { }).then(() => {
this.setLoading = false setLoading.value = false
ElMessage.success('操作成功') ElMessage.success('操作成功')
this.cloneDialog() emit('on-success')
cloneDialog(formEl)
}).catch(()=>{ }).catch(()=>{
this.setLoading = false setLoading.value = false
}) })
} else { } else {
return false return false
} }
}) })
}, }
// //
cloneDialog() { const cloneDialog = (formEl)=> {
this.$emit('on-close') studentList.value = []
this.studentList = [] treeRef.value.setCheckedKeys([])
this.$refs['ruleForm'].resetFields(); defaultExpandedKeys.value = []
}, formEl.resetFields()
model.value = false
}
// //
getCurrentDate() { const getCurrentDate = ()=> {
const now = new Date(); const now = new Date();
const year = now.getFullYear(); const year = now.getFullYear();
let month = now.getMonth() + 1; // 0+1 let month = now.getMonth() + 1; // 0+1
@ -272,34 +295,12 @@ export default {
day = '0' + day day = '0' + day
} }
return `${year}-${month}-${day}`; return `${year}-${month}-${day}`;
},
validateGrade(rule, value, callback) {
if (this.studentList.length == 0) {
callback(new Error('请勾选班级或者学生'));
} }
else {
callback()
}
},
validateStudent(rule, value, callback) {
if (this.studentList.length == 0) {
callback(new Error('学生不能为空'));
}
else {
callback()
}
},
},
watch: {
modelValue(val) {
this.dialogVisible = val
if (val) {
this.getGradeList()
}
}
},
} 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>