Merge remote-tracking branch 'origin/main'

This commit is contained in:
朱浩 2024-12-09 10:51:25 +08:00
commit 222b0f54f8
7 changed files with 252 additions and 20 deletions

View File

@ -125,6 +125,7 @@ import {
User, User,
Switch, Switch,
More, More,
Material
} from '@icon-park/vue-next' } from '@icon-park/vue-next'
export interface Icons { export interface Icons {
@ -255,6 +256,7 @@ export const icons: Icons = {
IconUser: User, IconUser: User,
IconSwitch: Switch, IconSwitch: Switch,
IconMore: More, IconMore: More,
IconMaterial: Material
} }
export default { export default {

View File

@ -0,0 +1,173 @@
<template>
<header class="flex material-header">
<span>选择素材</span>
<i class="iconfont icon-guanbi" @click="onClose"></i>
</header>
<div class="flex material-list" v-loading="loading">
<div class="flex material-item" v-for="item in list" :key="item.id" >
<div class="flex">
<el-image :src="fileUrl(item)" class="img" />
<el-text truncated>{{ item.fileShowName }}</el-text>
</div>
<el-button type="primary" @click="onInsert(item)">插入</el-button>
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, computed } from 'vue';
import { sessionStore } from '@/utils/store'
import { getSmarttalkPage } from '@/api/file'
import { getFileSuffix, urlToBase64 } from '@/utils/ruoyi.js'
const emit = defineEmits(['insertMaterial', 'close'])
const curNode = reactive({})
let params = {
textbookId: '',
levelFirstId: '',
levelSecondId: null,
fileSource: '个人',
fileRoot: '备课',
orderByColumn: 'uploadTime',
isAsc: 'desc',
pageSize: 500
}
const suffixAry = [ 'jpeg','jpg','png','gif','mp3','mp4','avi','mov']
const videoSuffix = ['mp3','mp4','avi','mov']
const list = ref([])
const loading = ref(false)
const init = () => {
loading.value = true
getSmarttalkPage(params).then(res => {
loading.value = false
if(res.rows && res.rows.length){
//
list.value = res.rows.filter( item => suffixAry.indexOf(getFileSuffix(item.fileShowName)) != -1)
}
})
}
const fileUrl = computed(() => (item) =>{
if(videoSuffix.indexOf(getFileSuffix(item.fileShowName)) != -1){
return item.coverPic
}
else{
return item.fileFullPath
}
})
//
const onInsert = async (item) =>{
if(videoSuffix.indexOf(getFileSuffix(item.fileShowName)) != -1){
emit('insertMaterial',{ type: 'video', data: item.fileFullPath })
}
else{
const base64 = await urlToBase64(item.fileFullPath)
emit('insertMaterial',{ type: 'img', data: base64 })
}
}
const GetUrlParameters = (parameters) => {
let resData = "";
let url = document.location.toString();
let arrUrl = url.split("?");
//
if (arrUrl.length > 1) {
//
let parametersArr = arrUrl[1].split("&");
//
for (let i = 0; i <= parametersArr.length; i++) {
if (parametersArr[i]) {
//
let parameterStr = parametersArr[i].split("=");
if (parameters == parameterStr[0]) {
resData = parameterStr[1];
break;
}
}
}
}
return resData;
}
const proxyToBase64 = (url)=> {
const dourl = GetUrlParameters(url)
console.log(dourl,'dourl')
return
axios({
url: "/api/logo.png",
method: "get",
responseType: "blob",
}).then((res) => {
const reader = new FileReader();
reader.readAsDataURL(res.data);
reader.onload = () => {
console.log(reader.result);
};
});
}
//
const onClose = () =>{
emit('close')
}
onMounted(() => {
let data = sessionStore.get('subject.curNode')
Object.assign(curNode, data);
params.textbookId = curNode.rootid
if (curNode.parentNode) {
params.levelFirstId = curNode.parentNode.id
params.levelSecondId = curNode.id
}
else {
params.levelFirstId = curNode.id
}
init()
})
</script>
<style lang="scss" scoped>
.material-header {
font-size: 17px;
font-weight: bold;
margin-bottom: 20px;
justify-content: space-between;
align-items: center;
.icon-guanbi{
font-size: 20px;
cursor: pointer;
}
}
.material-list{
flex-direction: column;
min-height: 150px;
max-height: 500px;
overflow-y: auto
}
.material-item {
align-items: center;
margin-bottom: 10px;
font-size: 14px;
justify-content: space-between;
.img{
width: 100px;
height: 100px;
margin-right: 20px;
}
}
</style>

View File

@ -82,6 +82,7 @@
<IconVideoTwo class="handler-item" v-tooltip="'插入音视频'" /> <IconVideoTwo class="handler-item" v-tooltip="'插入音视频'" />
</Popover> </Popover>
<IconPreviewOpen class="handler-item" v-tooltip="'插入试题'" @click="classWorkTaskVisible = true" /> <IconPreviewOpen class="handler-item" v-tooltip="'插入试题'" @click="classWorkTaskVisible = true" />
<IconMaterial class="handler-item" v-tooltip="'插入素材'" @click="materiaVisible = true"/>
</div> </div>
<div class="right-handler"> <div class="right-handler">
@ -112,17 +113,22 @@
/> />
</Modal> </Modal>
<Modal
v-model:visible="classWorkTaskVisible" <el-dialog v-model="classWorkTaskVisible" append-to-body :show-close="false" width="70%">
:width="880"
>
<QuestToPPTist <QuestToPPTist
class="class-work-task-modal" class="class-work-task-modal"
@close="classWorkTaskVisible = false" @close="classWorkTaskVisible = false"
@update="data => { onhtml2canvas(data); classWorkTaskVisible = false }" @update="data => { onhtml2canvas(data); classWorkTaskVisible = false }"
/> />
</el-dialog>
<Modal
v-model:visible="materiaVisible"
:width="880">
<MaterialDialog @close="materiaVisible = false" @insertMaterial="insertMaterial"/>
</Modal> </Modal>
</div> </div>
</template> </template>
@ -149,6 +155,7 @@ import Divider from '../../../components/Divider.vue'
import Popover from '../../../components/Popover.vue' import Popover from '../../../components/Popover.vue'
import PopoverMenuItem from '../../../components/PopoverMenuItem.vue' import PopoverMenuItem from '../../../components/PopoverMenuItem.vue'
import QuestToPPTist from '@/views/classTask/newClassTaskAssign/questToPPTist/index.vue' import QuestToPPTist from '@/views/classTask/newClassTaskAssign/questToPPTist/index.vue'
import MaterialDialog from './MaterialDialog.vue'
const mainStore = useMainStore() const mainStore = useMainStore()
const { creatingElement, creatingCustomShape, showSelectPanel, showSearchPanel, showNotesPanel } = storeToRefs(mainStore) const { creatingElement, creatingCustomShape, showSelectPanel, showSearchPanel, showNotesPanel } = storeToRefs(mainStore)
@ -200,6 +207,7 @@ const classWorkTaskVisible = ref(false)
const textTypeSelectVisible = ref(false) const textTypeSelectVisible = ref(false)
const shapeMenuVisible = ref(false) const shapeMenuVisible = ref(false)
const moreVisible = ref(false) const moreVisible = ref(false)
const materiaVisible = ref(false)
// //
const drawText = (vertical = false) => { const drawText = (vertical = false) => {
@ -246,6 +254,23 @@ const toggleSraechPanel = () => {
const toggleNotesPanel = () => { const toggleNotesPanel = () => {
mainStore.setNotesPanelState(!showNotesPanel.value) mainStore.setNotesPanelState(!showNotesPanel.value)
} }
//
interface MaterialParams {
type: string,
data: string
}
const insertMaterial = (item: MaterialParams) =>{
const { type, data } = item
if(type == 'video'){
createVideoElement(data)
}
else{
createImageElement(data)
}
materiaVisible.value = false
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -363,7 +388,7 @@ const toggleNotesPanel = () => {
} }
} }
.class-work-task-modal{ .class-work-task-modal{
height: 80vh; height: 70vh;
} }
@media screen and (width <= 1200px) { @media screen and (width <= 1200px) {

View File

@ -160,7 +160,7 @@ const topImgPositionStyle = computed(() => {
return { return {
left: -left * (100 / width) + '%', left: -left * (100 / width) + '%',
top: -top * (100 / height) + '%', top: -top * (100 / height) + '%',
width: bottomWidth / width * 100 + '%', width: bottomWidth / width * 100 + '%' ,
height: bottomHeight / height * 100 + '%', height: bottomHeight / height * 100 + '%',
} }
}) })
@ -228,6 +228,7 @@ const updateRange = () => {
width: parseInt(topImgPositionStyle.value.width), width: parseInt(topImgPositionStyle.value.width),
height: parseInt(topImgPositionStyle.value.height), height: parseInt(topImgPositionStyle.value.height),
} }
console.log('retPosition', retPosition)
const widthScale = 100 / retPosition.width const widthScale = 100 / retPosition.width
const heightScale = 100 / retPosition.height const heightScale = 100 / retPosition.height
@ -475,7 +476,7 @@ const scaleClipRange = (e: MouseEvent, type: OperateResizeHandlers) => {
isMouseDown = false isMouseDown = false
document.onmousemove = null document.onmousemove = null
document.onmouseup = null document.onmouseup = null
console.log('----------------------------------')
updateRange() updateRange()
setTimeout(() => isSettingClipRange.value = false, 0) setTimeout(() => isSettingClipRange.value = false, 0)
@ -537,6 +538,7 @@ const edgePoints = [
img { img {
position: absolute; position: absolute;
max-width: none !important;
} }
} }
} }

View File

@ -183,6 +183,7 @@ const handleClip = (data: ImageClipedEmitData | null) => {
} }
img { img {
position: absolute; position: absolute;
max-width: none !important; //
} }
} }
.color-mask { .color-mask {

View File

@ -258,16 +258,45 @@ export const getFileName = (filename) => {
return filename.replace(/\.[^/.]+$/, ""); return filename.replace(/\.[^/.]+$/, "");
} }
// 清除当前选中的教材 章节 相关信息
export const clearBookInfo = () =>{ /**
//当前选中的教材 * 根据图片的url转换对应的base64值
localStorage.removeItem('curBook') * @param { String } url http://xxxx/xxx.png
// 当前选中的节点 * @returns base64取值
localStorage.removeItem('curNode') */
// 所有章节单元数据 export const urlToBase64 = (url) => {
localStorage.removeItem('unitList')
// 所有教材数据 return new Promise((resolve, reject) => {
localStorage.removeItem('subjectList') if (!url) {
// 展开的节点 reject('请传入url内容')
localStorage.removeItem('defaultExpandedKeys') }
if (/\.(png|jpe?g|gif|svg)(\?.*)?$/.test(url)) {
// 图片地址
let image = new Image()
// 设置跨域问题
image.setAttribute('crossOrigin', 'anonymous')
// 图片地址
image.src = url +"?v=" + Math.random(); // 处理缓存,fix缓存bug,有缓存,浏览器会报错;
image.onload = () => {
let canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = image.width
canvas.height = image.height
ctx.drawImage(image, 0, 0, image.width, image.height)
// 获取图片后缀
const ext = url.substring(url.lastIndexOf('.') + 1).toLowerCase()
// 转base64
const dataUrl = canvas.toDataURL(`image/${ext}`)
resolve(dataUrl || '')
canvas = null // 清除canvas元素
image = null // 清除img元素
}
} else {
// 非图片地址
reject('非(png/jpe?g/gif/svg等)图片地址');
}
})
} }

View File

@ -68,7 +68,7 @@ defineExpose({
.page-resource { .page-resource {
user-select: none; user-select: none;
height: calc(100% - 55px); height: 100%;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: nowrap; flex-wrap: nowrap;