Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into yws_dev
This commit is contained in:
commit
0aa09e9d9a
|
@ -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 {
|
||||||
|
|
|
@ -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>
|
|
@ -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) {
|
||||||
|
|
|
@ -154,13 +154,15 @@ const topImgWrapperPositionStyle = computed(() => {
|
||||||
const topImgPositionStyle = computed(() => {
|
const topImgPositionStyle = computed(() => {
|
||||||
const bottomWidth = imgPosition.value.width
|
const bottomWidth = imgPosition.value.width
|
||||||
const bottomHeight = imgPosition.value.height
|
const bottomHeight = imgPosition.value.height
|
||||||
|
console.log("底层图片位置大小(遮罩区域图片)", imgPosition.value)
|
||||||
|
|
||||||
const { top, left, width, height } = topImgWrapperPosition.value
|
const { top, left, width, height } = topImgWrapperPosition.value
|
||||||
|
console.log("width", ((bottomWidth / width * 100) - (left * (100 / width))) + '%')
|
||||||
|
console.log("height", bottomHeight / height * 100 + '%')
|
||||||
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) - (left * (100 / width))) + '%' ,
|
||||||
height: bottomHeight / height * 100 + '%',
|
height: bottomHeight / height * 100 + '%',
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -228,6 +230,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 +478,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)
|
||||||
|
|
|
@ -36,13 +36,13 @@ export const processList = (row, aloneOption=false) => {
|
||||||
row[i].method = jjj.method
|
row[i].method = jjj.method
|
||||||
row[i].discuss = jjj.discuss
|
row[i].discuss = jjj.discuss
|
||||||
//row[i].discusscollapse = false;
|
//row[i].discusscollapse = false;
|
||||||
if (row[i].examdate !== null && row[i].examdate !== undefined) {
|
if (row[i].examdate && row[i].examdate != "") {
|
||||||
row[i].examdate = row[i].examdate.substring(0, 10)
|
row[i].examdate = row[i].examdate.substring(0, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 具体题型数据结构处理
|
// 具体题型数据结构处理
|
||||||
if (row[i].worktype == '复合题') {
|
if (row[i].worktype == '复合题') {
|
||||||
// 旧类型
|
// 复合题 - 旧格式
|
||||||
if (row[i].title.indexOf('!@#$%') !== -1) {
|
if (row[i].title.indexOf('!@#$%') !== -1) {
|
||||||
// 1.选项解析替换
|
// 1.选项解析替换
|
||||||
const options = JSON.parse(row[i].workdesc)
|
const options = JSON.parse(row[i].workdesc)
|
||||||
|
@ -129,7 +129,9 @@ export const processList = (row, aloneOption=false) => {
|
||||||
|
|
||||||
row[i].workanswerFormat = answer
|
row[i].workanswerFormat = answer
|
||||||
} else {
|
} else {
|
||||||
// 处理[题干显示] - 不再需要处理
|
// 复合题 - 现格式
|
||||||
|
|
||||||
|
// 处理[题干显示] - 不再需要处理(头部已处理)
|
||||||
// row[i].titleFormat = row[i].title; // 仅占位提示
|
// row[i].titleFormat = row[i].title; // 仅占位提示
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -222,6 +224,7 @@ export const processList = (row, aloneOption=false) => {
|
||||||
row[i].workanswerFormat = workAnswerHtml
|
row[i].workanswerFormat = workAnswerHtml
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
|
/** 主观题/非基础题(其中主要为第三方的各类解答题) */
|
||||||
row[i].worktype == '主观题' ||
|
row[i].worktype == '主观题' ||
|
||||||
(row[i].worktype !== '单选题' &&
|
(row[i].worktype !== '单选题' &&
|
||||||
row[i].worktype !== '多选题' &&
|
row[i].worktype !== '多选题' &&
|
||||||
|
@ -236,7 +239,7 @@ export const processList = (row, aloneOption=false) => {
|
||||||
row[i].workanswerFormat = JSON.parse(row[i].workanswer)
|
row[i].workanswerFormat = JSON.parse(row[i].workanswer)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 单选题|多选题|填空题|判断题|主观题?(待确认是否归在这里)
|
// 基础题: 单选题|多选题|填空题|判断题|主观题?(待确认是否归在这里)
|
||||||
// 通用选项结构 ['ABC123','ABC123'] | ['ABC123','ABC123'] | [](填空题无选项) | [](判断题无选项)
|
// 通用选项结构 ['ABC123','ABC123'] | ['ABC123','ABC123'] | [](填空题无选项) | [](判断题无选项)
|
||||||
let workDescArr = []
|
let workDescArr = []
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -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等)图片地址');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -16,6 +16,16 @@
|
||||||
<el-table-column align="center" prop="worktype" width="100"></el-table-column>
|
<el-table-column align="center" prop="worktype" width="100"></el-table-column>
|
||||||
<el-table-column align="center" prop="worktag" width="120"></el-table-column>
|
<el-table-column align="center" prop="worktag" width="120"></el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
<!-- 分页-->
|
||||||
|
<div style="height: 48px;">
|
||||||
|
<el-pagination
|
||||||
|
v-show="paginationParams.total > 0"
|
||||||
|
v-model:page="paginationParams.pageNum"
|
||||||
|
v-model:limit="paginationParams.pageSize"
|
||||||
|
:total="paginationParams.total"
|
||||||
|
:style="{ position: 'relative', 'padding': '8px 20px 0 0' }"
|
||||||
|
@change="changePageNum" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 试题详细信息 -->
|
<!-- 试题详细信息 -->
|
||||||
<examDetailsDrawer ref="examDetailsDrawerRef"></examDetailsDrawer>
|
<examDetailsDrawer ref="examDetailsDrawerRef"></examDetailsDrawer>
|
||||||
|
@ -54,11 +64,13 @@ const { proxy } = getCurrentInstance()
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
listExamQuestion: {type: Array},
|
listExamQuestion: {type: Array},
|
||||||
loading: {type: Boolean}
|
loading: {type: Boolean},
|
||||||
|
paginationParams: {type: Object},
|
||||||
})
|
})
|
||||||
|
|
||||||
const activeExamInfoDrawer = ref(false);
|
const activeExamInfoDrawer = ref(false);
|
||||||
const activeExam = ref({});
|
const activeExam = ref({});
|
||||||
|
const emit = defineEmits(['updatePageNum'])
|
||||||
|
|
||||||
const showExamAnalyseDrawer = (row) => {
|
const showExamAnalyseDrawer = (row) => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
|
@ -69,13 +81,17 @@ const showExamAnalyseDrawer = (row) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const changePageNum = (pageNum) => {
|
||||||
|
emit('updatePageNum', pageNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.table-main {
|
.table-main {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: calc(100% - 48px);
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
|
||||||
.main-title {
|
.main-title {
|
||||||
|
|
|
@ -47,10 +47,13 @@
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div :style="{'width': (viewportWidth - 400) + 'px','height': (viewportHeight-38) + 'px','overflow-y': 'auto'}">
|
<!-- <div :style="{'width': (viewportWidth - 400) + 'px','height': (viewportHeight-38) + 'px','overflow-y': 'auto'}"> -->
|
||||||
|
<div style="width: 100%; height: 100%; overflow-y: auto; border-radius: 10px;">
|
||||||
<examReview
|
<examReview
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:listExamQuestion="listExamQuestion"
|
:listExamQuestion="listExamQuestion"
|
||||||
|
:paginationParams="paginationParams"
|
||||||
|
@updatePageNum="updatePageNum"
|
||||||
v-if="curTask.viewkey=='真题回顾' "
|
v-if="curTask.viewkey=='真题回顾' "
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -77,12 +80,15 @@ import ChooseTextbook from '@/components/choose-textbook/index.vue'
|
||||||
import {listEntpcoursework, listEntpcourseworkNew} from '@/api/education/entpCourseWork'
|
import {listEntpcoursework, listEntpcourseworkNew} from '@/api/education/entpCourseWork'
|
||||||
import { processList } from '@/hooks/useProcessList'
|
import { processList } from '@/hooks/useProcessList'
|
||||||
import { JYApiListCT} from "@/utils/examQuestion/jyeoo"
|
import { JYApiListCT} from "@/utils/examQuestion/jyeoo"
|
||||||
|
import useClassTaskStore from '@/store/modules/classTask'
|
||||||
|
|
||||||
import examReview from './container/examReview.vue'
|
import examReview from './container/examReview.vue'
|
||||||
import pointAnalysis from './container/pointAnalysis.vue'
|
import pointAnalysis from './container/pointAnalysis.vue'
|
||||||
import examMocks from './container/examMocks.vue'
|
import examMocks from './container/examMocks.vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
|
const classTaskStore = useClassTaskStore();
|
||||||
|
|
||||||
const {proxy} = getCurrentInstance();
|
const {proxy} = getCurrentInstance();
|
||||||
const sourceStore = useResoureStore();
|
const sourceStore = useResoureStore();
|
||||||
const viewportHeight = ref(0);
|
const viewportHeight = ref(0);
|
||||||
|
@ -91,6 +97,11 @@ const viewportWidth = ref(0);
|
||||||
const curNode = ref({});
|
const curNode = ref({});
|
||||||
// 试题集合
|
// 试题集合
|
||||||
const listExamQuestion = ref([]);
|
const listExamQuestion = ref([]);
|
||||||
|
const paginationParams = reactive({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
});
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const curTask = reactive({
|
const curTask = reactive({
|
||||||
viewkey: '真题回顾',
|
viewkey: '真题回顾',
|
||||||
|
@ -107,6 +118,22 @@ const listWorkType = ref([{
|
||||||
value: 0,
|
value: 0,
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @desc: 翻页
|
||||||
|
* @return: {*}
|
||||||
|
* @param {*} pageNum
|
||||||
|
*/
|
||||||
|
const updatePageNum = (pageNum) => {
|
||||||
|
paginationParams.pageNum = pageNum;
|
||||||
|
queryExamQuestionByParams();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @desc: 具体获取试题及格式化
|
||||||
|
* @return: {*}
|
||||||
|
* @param {*} params
|
||||||
|
*/
|
||||||
const getCourseWorkList = async (params) => {
|
const getCourseWorkList = async (params) => {
|
||||||
const res = await listEntpcourseworkNew(params);
|
const res = await listEntpcourseworkNew(params);
|
||||||
if(res.data == null) {
|
if(res.data == null) {
|
||||||
|
@ -115,7 +142,14 @@ const getCourseWorkList = async (params) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
listExamQuestion.value = res.data;
|
listExamQuestion.value = res.data;
|
||||||
// queryParams.total = res.total;
|
// 判断获取到的总数
|
||||||
|
const total = parseInt(res.msg)
|
||||||
|
if (!isNaN(total)) {
|
||||||
|
paginationParams.total = total;
|
||||||
|
} else {
|
||||||
|
console.error('无法将 res.msg 转换为数字');
|
||||||
|
paginationParams.total = 0; // 重新设置默认值
|
||||||
|
}
|
||||||
// 格式化试题
|
// 格式化试题
|
||||||
processList(listExamQuestion.value);
|
processList(listExamQuestion.value);
|
||||||
}
|
}
|
||||||
|
@ -132,7 +166,8 @@ const getData = async (data) => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|
||||||
// 1.获取题型
|
// 1.获取题型
|
||||||
getWorkType(data.node);
|
//getWorkType(data.node);
|
||||||
|
listWorkType.value = classTaskStore.entpCourseWorkTypeList;
|
||||||
|
|
||||||
// 2.获取试题集合
|
// 2.获取试题集合
|
||||||
curNode.value = data.node;
|
curNode.value = data.node;
|
||||||
|
@ -166,6 +201,8 @@ const getData = async (data) => {
|
||||||
edusubject: curNode.value.edusubject,
|
edusubject: curNode.value.edusubject,
|
||||||
edustage: curNode.value.edustage,
|
edustage: curNode.value.edustage,
|
||||||
sectionName: curNode.value.itemtitle,
|
sectionName: curNode.value.itemtitle,
|
||||||
|
currentPage: paginationParams.pageNum,
|
||||||
|
pageSize: paginationParams.pageSize,
|
||||||
}
|
}
|
||||||
await getCourseWorkList(params);
|
await getCourseWorkList(params);
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
@ -181,6 +218,7 @@ const changeTaskView = (item, key) => {
|
||||||
curTask.viewkey = item;
|
curTask.viewkey = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 目前暂不使用, 题型已通过classTaskStore获取
|
||||||
const getWorkType = async (data) => {
|
const getWorkType = async (data) => {
|
||||||
const selName = `${data.edustage}${data.edusubject}`
|
const selName = `${data.edustage}${data.edusubject}`
|
||||||
const curName = `${curNode.value.edustage}${curNode.value.edusubject}`
|
const curName = `${curNode.value.edustage}${curNode.value.edusubject}`
|
||||||
|
@ -231,6 +269,8 @@ const queryExamQuestionByParams = async () => {
|
||||||
edusubject: curNode.value.edusubject,
|
edusubject: curNode.value.edusubject,
|
||||||
edustage: curNode.value.edustage,
|
edustage: curNode.value.edustage,
|
||||||
sectionName: curNode.value.itemtitle,
|
sectionName: curNode.value.itemtitle,
|
||||||
|
currentPage: paginationParams.pageNum,
|
||||||
|
pageSize: paginationParams.pageSize,
|
||||||
}
|
}
|
||||||
await getCourseWorkList(params);
|
await getCourseWorkList(params);
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-dialog v-model="open" v-bind="dAttrs">
|
||||||
|
<el-progress type="dashboard" v-bind="$attrs.pg" />
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
// 功能说明 弹窗进度条组件
|
||||||
|
import { computed, useAttrs } from 'vue'
|
||||||
|
const attrs = useAttrs()
|
||||||
|
const props = defineProps({
|
||||||
|
visible: { // 是否显示弹窗
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// 数据更新
|
||||||
|
const emit = defineEmits(['update:visible'])
|
||||||
|
// 弹窗显示-双向绑定
|
||||||
|
const open = computed({
|
||||||
|
get: () => props.visible,
|
||||||
|
set: val => emit('update:visible', val)
|
||||||
|
})
|
||||||
|
// 弹窗属性
|
||||||
|
const dAttrs = computed(() => {
|
||||||
|
const attrsNew = { ...attrs }
|
||||||
|
delete attrsNew.pg
|
||||||
|
return attrsNew
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -50,6 +50,7 @@
|
||||||
<EditDialog v-model="isEdit" :item="curItem" />
|
<EditDialog v-model="isEdit" :item="curItem" />
|
||||||
<AdjustDialog v-model="isAdjust" :item="curItem" />
|
<AdjustDialog v-model="isAdjust" :item="curItem" />
|
||||||
<PptDialog @add-success="addAiPPT" :dataList="resultList" v-model="pptDialog"/>
|
<PptDialog @add-success="addAiPPT" :dataList="resultList" v-model="pptDialog"/>
|
||||||
|
<progress-dialog v-model:visible="pgDialog.visible" v-bind="pgDialog" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
@ -58,6 +59,7 @@ import { sessionStore } from '@/utils/store'
|
||||||
import emitter from '@/utils/mitt'
|
import emitter from '@/utils/mitt'
|
||||||
import EditDialog from './edit-dialog.vue'
|
import EditDialog from './edit-dialog.vue'
|
||||||
import AdjustDialog from './adjust-dialog.vue'
|
import AdjustDialog from './adjust-dialog.vue'
|
||||||
|
import progressDialog from './progress-dialog.vue'
|
||||||
import { completion, tempResult } from '@/api/mode/index.js'
|
import { completion, tempResult } from '@/api/mode/index.js'
|
||||||
// import { dataSetJson } from '@/utils/comm.js'
|
// import { dataSetJson } from '@/utils/comm.js'
|
||||||
import * as commUtils from '@/utils/comm.js'
|
import * as commUtils from '@/utils/comm.js'
|
||||||
|
@ -77,7 +79,22 @@ const resultList = ref([])
|
||||||
const courseObj = reactive({
|
const courseObj = reactive({
|
||||||
node: null, // 选择的课程节点
|
node: null, // 选择的课程节点
|
||||||
})
|
})
|
||||||
|
const pgDialog = reactive({ // 弹窗-进度条
|
||||||
|
visible: false,
|
||||||
|
title: 'PPT解析中...',
|
||||||
|
width: 300,
|
||||||
|
showClose: false,
|
||||||
|
draggable: true,
|
||||||
|
beforeClose: done => {}, // 阻止-弹窗事件
|
||||||
|
pg: { // 进度条-参数
|
||||||
|
percentage: 0, // 百分比
|
||||||
|
color: [
|
||||||
|
{ color: '#1989fa', percentage: 50 }, // 蓝色
|
||||||
|
{ color: '#e6a23c', percentage: 80 }, // 橙色
|
||||||
|
{ color: '#5cb87a', percentage: 100 }, // 绿色
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
emitter.on('changeMode', (item) => {
|
emitter.on('changeMode', (item) => {
|
||||||
console.log(item, 'item')
|
console.log(item, 'item')
|
||||||
resultList.value = item.child
|
resultList.value = item.child
|
||||||
|
@ -115,6 +132,8 @@ const params = reactive(
|
||||||
const addAiPPT = async(res) => {
|
const addAiPPT = async(res) => {
|
||||||
let node = courseObj.node
|
let node = courseObj.node
|
||||||
if (!node) return msgUtils.msgWarning('请选择章节?')
|
if (!node) return msgUtils.msgWarning('请选择章节?')
|
||||||
|
pgDialog.visible = true
|
||||||
|
pgDialog.pg.percentage = 0
|
||||||
//TODO res中有PPT地址
|
//TODO res中有PPT地址
|
||||||
const params = { evalid: node.id, edituserid: userStore.id, pageSize: 1 }
|
const params = { evalid: node.id, edituserid: userStore.id, pageSize: 1 }
|
||||||
const resEnpt = await HTTP_SERVER_API('getCourseList', params)
|
const resEnpt = await HTTP_SERVER_API('getCourseList', params)
|
||||||
|
@ -129,10 +148,16 @@ const addAiPPT = async(res) => {
|
||||||
const resPptJson = await PPTXFileToJson(buffer)
|
const resPptJson = await PPTXFileToJson(buffer)
|
||||||
const { def, slides, ...content } = resPptJson
|
const { def, slides, ...content } = resPptJson
|
||||||
// 转换图片|音频|视频 为线上地址
|
// 转换图片|音频|视频 为线上地址
|
||||||
|
let completed = 0
|
||||||
|
const total = slides.length
|
||||||
for( let o of slides ) {
|
for( let o of slides ) {
|
||||||
|
completed++
|
||||||
await toRousrceUrl(o)
|
await toRousrceUrl(o)
|
||||||
|
// 设置进度条
|
||||||
|
pgDialog.pg.percentage = Math.floor(completed / total * 100)
|
||||||
}
|
}
|
||||||
// return
|
pgDialog.pg.percentage = 0
|
||||||
|
pgDialog.visible = false
|
||||||
// 生成ppt课件-父级
|
// 生成ppt课件-父级
|
||||||
const p_params = {parentContent: JSON.stringify(content)}
|
const p_params = {parentContent: JSON.stringify(content)}
|
||||||
const parentid = await HTTP_SERVER_API('addEntpcoursefile', p_params)
|
const parentid = await HTTP_SERVER_API('addEntpcoursefile', p_params)
|
||||||
|
|
Loading…
Reference in New Issue