提交 6737d2b7 authored 作者: 王鹏飞's avatar 王鹏飞

chore: update

上级 5ff64b0f
......@@ -7,7 +7,7 @@ import EditorSimple from '@/common/editor-simple'
import './index.less'
import { addExpandRead, expandReadInfo } from '../utils/request'
const ExpandModal = forwardRef((props, ref) => {
const ExpandModal = (props, ref) => {
const {
editor,
ossClient,
......@@ -361,6 +361,6 @@ const ExpandModal = forwardRef((props, ref) => {
</div>
</div>
)
})
}
export default ExpandModal
export default forwardRef(ExpandModal)
import React, { useEffect, useState, useRef, useImperativeHandle, forwardRef } from 'react';
import { Modal, Drawer, Tree, Button, Spin, Space, Input, Image } from 'antd';
import { LeftOutlined, RightOutlined } from '@ant-design/icons';
import { getInfoByChapterId } from '@/pages/books/section/request';
import { get } from 'lodash-es';
import $, { event } from 'jquery';
import baike from '@/assets/images/editor/icon-baike.png';
import { getChapterTopic, expandReadInfo } from '../utils/request';
import TopicItem from '../practice/components/topicItem';
import '../utils/iconfont';
import '@/common/preview.less';
import { clacTopicText } from '@/utils/common';
import hljs from 'highlight.js';
import 'highlight.js/styles/github.css';
import React, { useEffect, useState, useRef, useImperativeHandle, forwardRef } from 'react'
import { Modal, Drawer, Tree, Button, Spin, Space, Input, Image } from 'antd'
import { LeftOutlined, RightOutlined } from '@ant-design/icons'
import { getInfoByChapterId } from '@/pages/books/section/request'
import { get } from 'lodash-es'
import $, { event } from 'jquery'
import baike from '@/assets/images/editor/icon-baike.png'
import { getChapterTopic, expandReadInfo } from '../utils/request'
import TopicItem from '../practice/components/topicItem'
import '../utils/iconfont'
import '@/common/preview.less'
import { clacTopicText } from '@/utils/common'
import hljs from 'highlight.js'
import 'highlight.js/styles/github.css'
const correctList = [
'A',
......@@ -40,137 +40,135 @@ const correctList = [
'W',
'X',
'Y',
'Z',
];
const PreviewScreen = forwardRef((props, ref) => {
const { editor, bookId, chapterId, gData, nowTitle } = props;
const [loading, setLoading] = useState(false); // 展示
const [prviewHtml, setPrviewHtml] = useState(''); // 预览html
const [open, setOpen] = useState(false); // 抽屉
const [toolTip, setTooltip] = useState({});
const [headTitle, setHeadTitle] = useState(nowTitle);
const [newChapterId, setNewChapterId] = useState(chapterId);
const [opend, setOpend] = useState(false);
const [gallery, setGallery] = useState([]);
const [galleryIndex, setGalleryIndex] = useState(0);
const [isType, setIsType] = useState('');
const [secondType, setSecondType] = useState(false);
const [topicList, setTopicList] = useState([]); // 题库
const [radioList, setRadioList] = useState([]); // 单选
const [checkBoxList, setCheckBoxList] = useState([]); // 多选
const [judgeList, setJudgeList] = useState([]); // 判断
const [fillList, setFillList] = useState([]); // 填空
const [textareaList, setTextareaList] = useState([]); // 简答
const [expandContent, setExpandContent] = useState(''); // 扩展阅读内容
const [previewImg, setPreviewImg] = useState(''); // 扩展阅读内容
'Z'
]
const PreviewScreen = (props, ref) => {
const { editor, bookId, chapterId, gData, nowTitle } = props
const [loading, setLoading] = useState(false) // 展示
const [prviewHtml, setPrviewHtml] = useState('') // 预览html
const [open, setOpen] = useState(false) // 抽屉
const [toolTip, setTooltip] = useState({})
const [headTitle, setHeadTitle] = useState(nowTitle)
const [newChapterId, setNewChapterId] = useState(chapterId)
const [opend, setOpend] = useState(false)
const [gallery, setGallery] = useState([])
const [galleryIndex, setGalleryIndex] = useState(0)
const [isType, setIsType] = useState('')
const [secondType, setSecondType] = useState(false)
const [topicList, setTopicList] = useState([]) // 题库
const [radioList, setRadioList] = useState([]) // 单选
const [checkBoxList, setCheckBoxList] = useState([]) // 多选
const [judgeList, setJudgeList] = useState([]) // 判断
const [fillList, setFillList] = useState([]) // 填空
const [textareaList, setTextareaList] = useState([]) // 简答
const [expandContent, setExpandContent] = useState('') // 扩展阅读内容
const [previewImg, setPreviewImg] = useState('') // 扩展阅读内容
const getTopicList = async ({ practicenum, chapterid, bookid }) => {
const data = await getChapterTopic({
position: practicenum,
book_id: bookid,
chapter_id: chapterid,
});
chapter_id: chapterid
})
const temp = [];
data.forEach((item) => {
let obj = { ...item };
const temp = []
data.forEach(item => {
let obj = { ...item }
if ([1, 2, 3].includes(parseInt(item.question_style))) {
try {
obj.question_list = JSON.parse(item.question_list);
obj.question_list = JSON.parse(item.question_list)
} catch (err) {
obj.question_list = [];
obj.question_list = []
}
}
temp.push(obj);
});
const tempRadio = temp.filter((item) => parseInt(item.question_style) === 1);
const tempCheckbox = temp.filter((item) => parseInt(item.question_style) === 2);
const tempJudge = temp.filter((item) => parseInt(item.question_style) === 3);
const tempFill = temp.filter((item) => parseInt(item.question_style) === 4);
const tempTextarea = temp.filter((item) => parseInt(item.question_style) === 5);
setRadioList(tempRadio);
setCheckBoxList(tempCheckbox);
setJudgeList(tempJudge);
setFillList(tempFill);
setTextareaList(tempTextarea);
setTopicList(temp);
};
temp.push(obj)
})
const tempRadio = temp.filter(item => parseInt(item.question_style) === 1)
const tempCheckbox = temp.filter(item => parseInt(item.question_style) === 2)
const tempJudge = temp.filter(item => parseInt(item.question_style) === 3)
const tempFill = temp.filter(item => parseInt(item.question_style) === 4)
const tempTextarea = temp.filter(item => parseInt(item.question_style) === 5)
setRadioList(tempRadio)
setCheckBoxList(tempCheckbox)
setJudgeList(tempJudge)
setFillList(tempFill)
setTextareaList(tempTextarea)
setTopicList(temp)
}
const getExpandInfo = async ({ chapterId, position }) => {
const data = await expandReadInfo({
book_id: bookId,
chapter_id: chapterId,
position: position,
});
position: position
})
if (data) {
setExpandContent(data.content);
setExpandContent(data.content)
}
}
};
const handlerClick = () => {
const iParentW = $('.preview-content-it').innerWidth();
const iParentH = $('.preview-content-it').innerHeight();
const parentOffset = $('.preview-content-it').offset(); // 获取父元素相对于文档的位置
const parentRect = $('.preview-content-it')[0].getBoundingClientRect(); // 获取父元素相对于文档的位置
$('.preview-content-html').on('click', (ev) => {
ev.stopPropagation();
const target = ev.target;
const tooltip = $(target).closest('.chapter-item-tooltip');
const alink = $(target).closest('.chapter-item-link');
const aGallery = $(target).closest('.chapter-gallery-container');
const practice = $(target).closest('.chapter-practice');
const aA = $(target).closest('a');
const aExpand = $(target).closest('.chapter-expand');
const iParentW = $('.preview-content-it').innerWidth()
const iParentH = $('.preview-content-it').innerHeight()
const parentOffset = $('.preview-content-it').offset() // 获取父元素相对于文档的位置
const parentRect = $('.preview-content-it')[0].getBoundingClientRect() // 获取父元素相对于文档的位置
$('.preview-content-html').on('click', ev => {
ev.stopPropagation()
const target = ev.target
const tooltip = $(target).closest('.chapter-item-tooltip')
const alink = $(target).closest('.chapter-item-link')
const aGallery = $(target).closest('.chapter-gallery-container')
const practice = $(target).closest('.chapter-practice')
const aA = $(target).closest('a')
const aExpand = $(target).closest('.chapter-expand')
if (tooltip.length > 0) {
const random = $(tooltip).data('random');
const link = $(tooltip).data('link');
const content = $(tooltip).data('content');
const tooltipType = $(tooltip).data('tooltip-type');
const title = $(tooltip).data('title');
const tooltipParent = $(target).closest(
'p, div, h1, h2, h3, h4, h5, h6, li, dt, dd, section',
);
const tooltipParentPosition = $(tooltipParent).position();
const tooltipPosition = $(tooltip).position();
const childOffset = $(tooltip).offset(); // 获取子元素相对于文档的位置
const childWidth = $(tooltip).outerWidth(true); // 获取元素的宽度
const childHeight = $(tooltip).outerHeight(true); // 获取元素的高度
let toolRect = null;
let targetPositon = null;
const random = $(tooltip).data('random')
const link = $(tooltip).data('link')
const content = $(tooltip).data('content')
const tooltipType = $(tooltip).data('tooltip-type')
const title = $(tooltip).data('title')
const tooltipParent = $(target).closest('p, div, h1, h2, h3, h4, h5, h6, li, dt, dd, section')
const tooltipParentPosition = $(tooltipParent).position()
const tooltipPosition = $(tooltip).position()
const childOffset = $(tooltip).offset() // 获取子元素相对于文档的位置
const childWidth = $(tooltip).outerWidth(true) // 获取元素的宽度
const childHeight = $(tooltip).outerHeight(true) // 获取元素的高度
let toolRect = null
let targetPositon = null
if (target.nodeName.toLowerCase() === 'svg' || target.nodeName.toLowerCase() === 'use') {
toolRect = target.parentNode.parentNode.getBoundingClientRect();
targetPositon = $(target).closest('.chapter-item-tooltip').position();
toolRect = target.parentNode.parentNode.getBoundingClientRect()
targetPositon = $(target).closest('.chapter-item-tooltip').position()
} else {
toolRect = target.parentNode.getBoundingClientRect();
targetPositon = $(target).position();
toolRect = target.parentNode.getBoundingClientRect()
targetPositon = $(target).position()
}
const lineHeight = $(tooltip).css('line-height');
let inSide = '';
let left = childOffset.left - parentOffset.left;
let top = 0;
let squareStyle = {};
const lineHeight = $(tooltip).css('line-height')
let inSide = ''
let left = childOffset.left - parentOffset.left
let top = 0
let squareStyle = {}
if (childWidth + left >= iParentW) {
left = iParentW - childWidth - 10;
left = iParentW - childWidth - 10
}
if (left <= 0) {
left = 10;
left = 10
}
let style1 = {
top: `${top}px`,
left: `${left}px`,
};
left: `${left}px`
}
setTooltip({
title,
......@@ -180,53 +178,53 @@ const PreviewScreen = forwardRef((props, ref) => {
tooltipType,
inSide,
style: style1,
squareStyle: squareStyle,
});
squareStyle: squareStyle
})
setTimeout(() => {
const childMoveHeight = $('.tooltip').outerHeight(); // 获取元素的高度
const childMoveWidth = $('.tooltip').outerWidth(); // 获取元素的高度
const scrollTop = $('.preview-content-show').scrollTop();
let squareStyle = {};
const childMoveHeight = $('.tooltip').outerHeight() // 获取元素的高度
const childMoveWidth = $('.tooltip').outerWidth() // 获取元素的高度
const scrollTop = $('.preview-content-show').scrollTop()
let squareStyle = {}
if (left <= 0) {
left = 10;
squareStyle.left = 10;
left = 10
squareStyle.left = 10
} else if (left + childMoveWidth >= iParentW) {
left = iParentW - childMoveWidth - 20;
squareStyle.left = targetPositon.left - left;
left = iParentW - childMoveWidth - 20
squareStyle.left = targetPositon.left - left
} else {
squareStyle.left = childWidth / 2;
squareStyle.left = childWidth / 2
}
// 换行了
// console.log(toolRect.height, parseInt(lineHeight));
if (tooltipType === 1 && toolRect.height / 1.5 > parseInt(lineHeight)) {
left = toolRect.right - parentRect.left - childMoveWidth + 15;
squareStyle.left = childMoveWidth - 30;
left = toolRect.right - parentRect.left - childMoveWidth + 15
squareStyle.left = childMoveWidth - 30
}
// 是否被遮挡
if (tooltipPosition.top + childMoveHeight + childHeight + 30 >= scrollTop + iParentH) {
inSide = 'bottom';
top = tooltipPosition.top - childMoveHeight;
squareStyle.left = childWidth / 2;
inSide = 'bottom'
top = tooltipPosition.top - childMoveHeight
squareStyle.left = childWidth / 2
} else {
inSide = 'top';
inSide = 'top'
if (toolRect.height / 1.5 > parseInt(lineHeight)) {
top = tooltipPosition.top + childHeight + toolRect.height;
top = tooltipPosition.top + toolRect.height + parseInt(lineHeight);
top = tooltipPosition.top + childHeight + toolRect.height
top = tooltipPosition.top + toolRect.height + parseInt(lineHeight)
} else {
top = tooltipPosition.top + childHeight + 25;
top = tooltipPosition.top + childHeight + 25
}
}
top = top - scrollTop;
top = top - scrollTop
let style2 = {
top: `${top}px`,
left: `${left}px`,
zIndex: 1000,
opacity: 1,
};
opacity: 1
}
setTooltip({
title,
random,
......@@ -235,142 +233,142 @@ const PreviewScreen = forwardRef((props, ref) => {
tooltipType,
inSide,
style: style2,
squareStyle: squareStyle,
});
}, 100);
squareStyle: squareStyle
})
}, 100)
return false;
return false
} else if (alink.length > 0) {
const link = $(alink).data('link');
const linkType = $(alink).data('linktype');
const chapters = $(alink).data('chapters');
const title = $(alink).data('title');
const link = $(alink).data('link')
const linkType = $(alink).data('linktype')
const chapters = $(alink).data('chapters')
const title = $(alink).data('title')
let last = '';
let last = ''
if (parseInt(linkType) === 2) {
if (chapters.toString().indexOf(',') > -1) {
const arr = chapters.split(',');
last = arr[arr.length - 1];
const arr = chapters.split(',')
last = arr[arr.length - 1]
} else {
last = chapters;
last = chapters
}
setHeadTitle(title);
setOpend(true);
setNewChapterId(last);
setHeadTitle(title)
setOpend(true)
setNewChapterId(last)
} else {
window.open(link);
window.open(link)
}
ev.preventDefault();
return false;
ev.preventDefault()
return false
} else if (aGallery.length > 0) {
const title = $(aGallery).data('title');
const flex = $(aGallery).data('flex');
const gallerylist = $(aGallery).data('gallerylist');
const galleryArr = JSON.parse(decodeURI(gallerylist));
const title = $(aGallery).data('title')
const flex = $(aGallery).data('flex')
const gallerylist = $(aGallery).data('gallerylist')
const galleryArr = JSON.parse(decodeURI(gallerylist))
setOpend(true);
setHeadTitle(title);
setOpend(true)
setHeadTitle(title)
if (galleryArr && galleryArr.length > 0 && galleryArr instanceof Array) {
setGallery(galleryArr);
setGallery(galleryArr)
if (parseInt(flex) === 2) {
setGalleryIndex(0);
setGalleryIndex(0)
} else {
setGalleryIndex($(target).closest('.chapter-gallery-item').index());
setGalleryIndex($(target).closest('.chapter-gallery-item').index())
}
} else {
setGallery([]);
setGallery([])
}
setIsType('gallery');
setTooltip({});
return false;
setIsType('gallery')
setTooltip({})
return false
} else if (practice.length > 0) {
const title = $(practice).data('title');
const bookid = $(practice).data('bookid');
const chapterid = $(practice).data('chapterid');
const practicenum = $(practice).data('practicenum');
getTopicList({ practicenum, chapterid, bookid });
setOpend(true);
setHeadTitle(title);
setIsType('practice');
ev.preventDefault();
return false;
const title = $(practice).data('title')
const bookid = $(practice).data('bookid')
const chapterid = $(practice).data('chapterid')
const practicenum = $(practice).data('practicenum')
getTopicList({ practicenum, chapterid, bookid })
setOpend(true)
setHeadTitle(title)
setIsType('practice')
ev.preventDefault()
return false
} else if (aA.length > 0) {
const href = $(aA).attr('href');
const href = $(aA).attr('href')
let newLink = '';
let newLink = ''
if (!/^https*:\/\//.test(href)) {
newLink = `http://${href}`;
newLink = `http://${href}`
} else {
newLink = href;
newLink = href
}
window.open(newLink);
ev.preventDefault();
return false;
window.open(newLink)
ev.preventDefault()
return false
} else if (aExpand.length > 0) {
const title = $(aExpand).data('title');
const name = $(aExpand).data('name');
const position = $(aExpand).data('random');
setOpend(true);
getExpandInfo({ chapterId, position });
setIsType('expand');
setHeadTitle(name);
const title = $(aExpand).data('title')
const name = $(aExpand).data('name')
const position = $(aExpand).data('random')
setOpend(true)
getExpandInfo({ chapterId, position })
setIsType('expand')
setHeadTitle(name)
} else if (target.nodeName.toLowerCase() === 'img') {
const alt = $(target).attr('alt');
const src = $(target).attr('src');
setOpend(true);
setIsType('img');
setPreviewImg(src);
setHeadTitle(alt ? alt : '图片展示');
const alt = $(target).attr('alt')
const src = $(target).attr('src')
setOpend(true)
setIsType('img')
setPreviewImg(src)
setHeadTitle(alt ? alt : '图片展示')
}
setTooltip({});
setGallery([]);
});
setTooltip({})
setGallery([])
})
$('.expand-content, .gallery-prview-container').on('click', (ev) => {
const target = ev.target;
$('.expand-content, .gallery-prview-container').on('click', ev => {
const target = ev.target
if (target.nodeName.toLowerCase() === 'img') {
const alt = $(target).attr('alt');
const src = $(target).attr('src');
setOpend(true);
setIsType('img');
setPreviewImg(src);
setSecondType('扩展图片');
const alt = $(target).attr('alt')
const src = $(target).attr('src')
setOpend(true)
setIsType('img')
setPreviewImg(src)
setSecondType('扩展图片')
}
})
}
});
};
useEffect(() => {
handlerClick();
}, [isType]);
handlerClick()
}, [])
const getChapterId = async () => {
setLoading(true);
const data = await getInfoByChapterId({ chapter_id: newChapterId });
setLoading(true)
const data = await getInfoByChapterId({ chapter_id: newChapterId })
if (data) {
const content = get(data, 'content', '');
setPrviewHtml(content);
const content = get(data, 'content', '')
setPrviewHtml(content)
$('#previee-container')
.find('video audio')
.each((index, item) => {
$(item).attr('controls', true).attr('controlslist', 'nodownload');
});
$(item).attr('controls', true).attr('controlslist', 'nodownload')
})
setTimeout(() => {
document
.querySelectorAll('.preview-content-show ')[0]
.querySelectorAll('pre code')
.forEach((el) => {
hljs.highlightElement(el);
});
}, 200);
.forEach(el => {
hljs.highlightElement(el)
})
}, 200)
}
setLoading(false)
}
setLoading(false);
};
const onClose = () => {
setOpen(false);
};
setOpen(false)
}
// const handleSelect = async (checkedKeys, info) => {
// setLoading(true);
// const data = await getInfoByChapterId({ chapter_id: info.node.key });
......@@ -388,345 +386,300 @@ const PreviewScreen = forwardRef((props, ref) => {
// };
useEffect(() => {
getChapterId();
}, [bookId, newChapterId]);
getChapterId()
}, [bookId, newChapterId])
const galleryLeft = () => {
let temp = galleryIndex;
let temp = galleryIndex
if (temp <= 0) {
temp = 0;
temp = 0
} else {
temp = temp - 1;
temp = temp - 1
}
setGalleryIndex(temp)
}
setGalleryIndex(temp);
};
const galleryRight = () => {
let temp = galleryIndex;
let temp = galleryIndex
if (temp >= gallery.length - 1) {
temp = gallery.length - 1;
temp = gallery.length - 1
} else {
temp = temp + 1;
temp = temp + 1
}
setGalleryIndex(temp)
}
setGalleryIndex(temp);
};
return (
<div className='priview-modal'>
<div className='previee-container' id='previee-container'>
<div className='chapter-head-title'>
<div className="priview-modal">
<div className="previee-container" id="previee-container">
<div className="chapter-head-title">
<h2>
{opend ? (
<Space>
<Button
type='text'
type="text"
onClick={() => {
if (secondType) {
setSecondType(false);
setPreviewImg(null);
setIsType('expand');
return;
setSecondType(false)
setPreviewImg(null)
setIsType('expand')
return
}
setOpend(false);
setIsType('');
setExpandContent('');
setTopicList([]);
setGalleryIndex(-1);
setNewChapterId(chapterId);
setPreviewImg('');
}}
>
setOpend(false)
setIsType('')
setExpandContent('')
setTopicList([])
setGalleryIndex(-1)
setNewChapterId(chapterId)
setPreviewImg('')
}}>
<LeftOutlined />
</Button>
{secondType ? secondType : headTitle}
</Space>
) : (
<span className='no'>{nowTitle}</span>
<span className="no">{nowTitle}</span>
)}
</h2>
</div>
<div className='preview-content-it'>
<div className='preview-content-show'>
<Spin spinning={loading} wrapperClassName='chapter-loading'>
<div
className='preview-content-html'
dangerouslySetInnerHTML={{ __html: prviewHtml }}
></div>
<div className="preview-content-it">
<div className="preview-content-show">
<Spin spinning={loading} wrapperClassName="chapter-loading">
<div className="preview-content-html" dangerouslySetInnerHTML={{ __html: prviewHtml }}></div>
</Spin>
</div>
{isType && (
<div className='preview-content-other'>
<div className="preview-content-other">
{isType === 'gallery' && (
<div className='gallery-prview-container'>
<div className="gallery-prview-container">
{gallery && gallery.length > 0 ? (
<>
<div className='gallery-img'>
<img
src={gallery[parseInt(galleryIndex)].url}
alt={gallery[parseInt(galleryIndex)].title}
/>
<div className='opa prev' onClick={galleryLeft}></div>
<div className='opa next' onClick={galleryRight}></div>
<div className="gallery-img">
<img src={gallery[parseInt(galleryIndex)].url} alt={gallery[parseInt(galleryIndex)].title} />
<div className="opa prev" onClick={galleryLeft}></div>
<div className="opa next" onClick={galleryRight}></div>
</div>
<div className='steps'>
<div className="steps">
当前 {parseInt(galleryIndex) + 1}/{gallery.length}
</div>
<div className='title'>{gallery[parseInt(galleryIndex)].title}</div>
<div className='desc'>{gallery[parseInt(galleryIndex)].desc}</div>
<div className="title">{gallery[parseInt(galleryIndex)].title}</div>
<div className="desc">{gallery[parseInt(galleryIndex)].desc}</div>
</>
) : (
<>
<div className='gallery-img noData'>画廊数据异常</div>
<div className="gallery-img noData">画廊数据异常</div>
</>
)}
</div>
)}
{isType === 'practice' && (
<div className='practice-insert-topic'>
<div className="practice-insert-topic">
{radioList.length > 0 && (
<div className='topic_style'>
<div className="topic_style">
<h3>{clacTopicText('radio')}. 单选题</h3>
<div className='practice-list'>
<div className="practice-list">
{radioList.map((item, index) => {
return (
<div className='practice-item' key={index}>
<div className="practice-item" key={index}>
<div
className='topic-choose-title'
className="topic-choose-title"
dangerouslySetInnerHTML={{
__html: `<span class="index">${index + 1}.</span>${item.titles}`,
}}
></div>
__html: `<span class="index">${index + 1}.</span>${item.titles}`
}}></div>
<div className='topic_choose-list'>
<div className="topic_choose-list">
{[1, 2, 3].includes(parseInt(item.question_style)) &&
item.question_list.map((citem, cindex) => {
return (
<div className='topic_choose-item' key={cindex}>
<div className='choose-ico'>
<i
className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}
></i>
<div className="topic_choose-item" key={cindex}>
<div className="choose-ico">
<i className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}></i>
</div>
<div
className='topic_content'
className="topic_content"
dangerouslySetInnerHTML={{
__html: `<span class="correct">${correctList[cindex]}.</span> ${citem.option}`,
}}
></div>
__html: `<span class="correct">${correctList[cindex]}.</span> ${citem.option}`
}}></div>
</div>
);
)
})}
{item.question_style === 5 && (
<div>
<Input.TextArea
disabled={true}
autoSize={{ minRows: 4, maxRows: 6 }}
/>
<Input.TextArea disabled={true} autoSize={{ minRows: 4, maxRows: 6 }} />
</div>
)}
</div>
</div>
);
)
})}
</div>
</div>
)}
{checkBoxList.length > 0 && (
<div className='topic_style'>
<div className="topic_style">
<h3>{clacTopicText('checkbox', radioList)}. 多选题</h3>
<div className='practice-list'>
<div className="practice-list">
{checkBoxList.map((item, index) => {
return (
<div className='practice-item' key={index}>
<div className="practice-item" key={index}>
<div
className='topic-choose-title'
className="topic-choose-title"
dangerouslySetInnerHTML={{
__html: `<span class="index">${index + 1}.</span>${item.titles}`,
}}
></div>
__html: `<span class="index">${index + 1}.</span>${item.titles}`
}}></div>
<div className='topic_choose-list'>
<div className="topic_choose-list">
{[1, 2, 3].includes(parseInt(item.question_style)) &&
item.question_list.map((citem, cindex) => {
return (
<div className='topic_choose-item' key={cindex}>
<div className='choose-ico'>
<i
className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}
></i>
<div className="topic_choose-item" key={cindex}>
<div className="choose-ico">
<i className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}></i>
</div>
<div
className='topic_content'
className="topic_content"
dangerouslySetInnerHTML={{
__html: `<span class="correct">${correctList[cindex]}.</span> ${citem.option}`,
}}
></div>
__html: `<span class="correct">${correctList[cindex]}.</span> ${citem.option}`
}}></div>
</div>
);
)
})}
{item.question_style === 5 && (
<div>
<Input.TextArea
disabled={true}
autoSize={{ minRows: 4, maxRows: 6 }}
/>
<Input.TextArea disabled={true} autoSize={{ minRows: 4, maxRows: 6 }} />
</div>
)}
</div>
</div>
);
)
})}
</div>
</div>
)}
{judgeList.length > 0 && (
<div className='topic_style'>
<div className="topic_style">
<h3>{clacTopicText('judge', radioList, checkBoxList)}. 判断题</h3>
<div className='practice-list'>
<div className="practice-list">
{judgeList.map((item, index) => {
return (
<div className='practice-item' key={index}>
<div className="practice-item" key={index}>
<div
className='topic-choose-title'
className="topic-choose-title"
dangerouslySetInnerHTML={{
__html: `<span class="index">${index + 1}.</span>${item.titles}`,
}}
></div>
__html: `<span class="index">${index + 1}.</span>${item.titles}`
}}></div>
<div className='topic_choose-list'>
<div className="topic_choose-list">
{[1, 2, 3].includes(parseInt(item.question_style)) &&
item.question_list.map((citem, cindex) => {
return (
<div className='topic_choose-item' key={cindex}>
<div className='choose-ico'>
<i
className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}
></i>
<div className="topic_choose-item" key={cindex}>
<div className="choose-ico">
<i className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}></i>
</div>
<div
className='topic_content'
className="topic_content"
dangerouslySetInnerHTML={{
__html: `<span class="correct">${correctList[cindex]}.</span> ${citem.option}`,
}}
></div>
__html: `<span class="correct">${correctList[cindex]}.</span> ${citem.option}`
}}></div>
</div>
);
)
})}
{item.question_style === 5 && (
<div>
<Input.TextArea
disabled={true}
autoSize={{ minRows: 4, maxRows: 6 }}
/>
<Input.TextArea disabled={true} autoSize={{ minRows: 4, maxRows: 6 }} />
</div>
)}
</div>
</div>
);
)
})}
</div>
</div>
)}
{fillList.length > 0 && (
<div className='topic_style'>
<div className="topic_style">
<h3>{clacTopicText('fill', radioList, checkBoxList, judgeList)}. 填空题</h3>
<div className='practice-list'>
<div className="practice-list">
{fillList.map((item, index) => {
return (
<div className='practice-item' key={index}>
<div className="practice-item" key={index}>
<div
className='topic-choose-title'
className="topic-choose-title"
dangerouslySetInnerHTML={{
__html: `<span class="index">${index + 1}.</span>${item.titles}`,
}}
></div>
__html: `<span class="index">${index + 1}.</span>${item.titles}`
}}></div>
<div className='topic_choose-list'>
<div className="topic_choose-list">
{[1, 2, 3].includes(parseInt(item.question_style)) &&
item.question_list.map((citem, cindex) => {
return (
<div className='topic_choose-item' key={cindex}>
<div className='choose-ico'>
<i
className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}
></i>
<div className="topic_choose-item" key={cindex}>
<div className="choose-ico">
<i className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}></i>
</div>
<div
className='topic_content'
className="topic_content"
dangerouslySetInnerHTML={{
__html: `<span class="correct">${correctList[cindex]}.</span> ${citem.option}`,
}}
></div>
__html: `<span class="correct">${correctList[cindex]}.</span> ${citem.option}`
}}></div>
</div>
);
)
})}
{item.question_style === 5 && (
<div>
<Input.TextArea
disabled={true}
autoSize={{ minRows: 4, maxRows: 6 }}
/>
<Input.TextArea disabled={true} autoSize={{ minRows: 4, maxRows: 6 }} />
</div>
)}
</div>
</div>
);
)
})}
</div>
</div>
)}
{textareaList.length > 0 && (
<div className='topic_style'>
<h3>
{clacTopicText('textarea', radioList, checkBoxList, judgeList, fillList)}.
简答题
</h3>
<div className='practice-list'>
<div className="topic_style">
<h3>{clacTopicText('textarea', radioList, checkBoxList, judgeList, fillList)}. 简答题</h3>
<div className="practice-list">
{textareaList.map((item, index) => {
return (
<div className='practice-item' key={index}>
<div className="practice-item" key={index}>
<div
className='topic-choose-title'
className="topic-choose-title"
dangerouslySetInnerHTML={{
__html: `<span class="index">${index + 1}.</span>${item.titles}`,
}}
></div>
__html: `<span class="index">${index + 1}.</span>${item.titles}`
}}></div>
<div className='topic_choose-list'>
<div className="topic_choose-list">
{[1, 2, 3].includes(parseInt(item.question_style)) &&
item.question_list.map((citem, cindex) => {
return (
<div className='topic_choose-item' key={cindex}>
<div className='choose-ico'>
<i
className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}
></i>
<div className="topic_choose-item" key={cindex}>
<div className="choose-ico">
<i className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}></i>
</div>
<div
className='topic_content'
className="topic_content"
dangerouslySetInnerHTML={{
__html: `${correctList[cindex]}. ${citem.option}`,
}}
></div>
__html: `${correctList[cindex]}. ${citem.option}`
}}></div>
</div>
);
)
})}
{item.question_style === 5 && (
<div>
<Input.TextArea
disabled={true}
autoSize={{ minRows: 4, maxRows: 6 }}
/>
<Input.TextArea disabled={true} autoSize={{ minRows: 4, maxRows: 6 }} />
</div>
)}
</div>
</div>
);
)
})}
</div>
</div>
......@@ -734,33 +687,31 @@ const PreviewScreen = forwardRef((props, ref) => {
</div>
)}
{isType === 'expand' && (
<div className='expand-container'>
<div
className='expand-content'
dangerouslySetInnerHTML={{ __html: expandContent }}
></div>
<div className="expand-container">
<div className="expand-content" dangerouslySetInnerHTML={{ __html: expandContent }}></div>
</div>
)}
{isType === 'img' && (
<div className='img-preview'>
<div className="img-preview">
<Image width={430} src={previewImg} />
</div>
)}
</div>
)}
<div className='tooltip' style={toolTip.style}>
<div className="tooltip" style={toolTip.style}>
<div
className={`square ${toolTip.inSide === 'top' ? 'square_top' : toolTip.inSide === 'bottom' ? 'square_bottom' : ''}`}
style={toolTip.squareStyle}
></div>
<div className='tooltip-content-container'>
<div className='tooltip-content'>
<div className='content'>
className={`square ${
toolTip.inSide === 'top' ? 'square_top' : toolTip.inSide === 'bottom' ? 'square_bottom' : ''
}`}
style={toolTip.squareStyle}></div>
<div className="tooltip-content-container">
<div className="tooltip-content">
<div className="content">
<p>{toolTip.content}</p>
</div>
{toolTip.link && (
<div className='content-opa'>
<a href={toolTip.link} target='_blank' rel='noreferrer' className='c-link'></a>
<div className="content-opa">
<a href={toolTip.link} target="_blank" rel="noreferrer" className="c-link"></a>
</div>
)}
</div>
......@@ -788,7 +739,7 @@ const PreviewScreen = forwardRef((props, ref) => {
/>
</Drawer> */}
</div>
);
});
)
}
export default PreviewScreen;
export default forwardRef(PreviewScreen)
import React, { useState, forwardRef, useImperativeHandle, useRef } from 'react';
import { Input, InputNumber } from 'antd';
import '../index.less';
import React, { useState, forwardRef, useImperativeHandle, useRef } from 'react'
import { Input, InputNumber } from 'antd'
import '../index.less'
const PaddingSpace = forwardRef((props, ref) => {
const { editorNodes, editor } = props;
const [inputValue1, setInputValue1] = useState('');
const [inputValue2, setInputValue2] = useState('');
const [inputValue3, setInputValue3] = useState('');
const timeDebonceRef = useRef();
const PaddingSpace = (props, ref) => {
const { editorNodes, editor } = props
const [inputValue1, setInputValue1] = useState('')
const [inputValue2, setInputValue2] = useState('')
const [inputValue3, setInputValue3] = useState('')
const timeDebonceRef = useRef()
const InpoutValueChange1 = (value) => {
setInputValue1(value);
changeIt();
};
const InpoutValueChange2 = (value) => {
setInputValue2(value);
};
const InpoutValueChange3 = (value) => {
setInputValue3(value);
};
const InpoutValueChange1 = value => {
setInputValue1(value)
changeIt()
}
const InpoutValueChange2 = value => {
setInputValue2(value)
}
const InpoutValueChange3 = value => {
setInputValue3(value)
}
const changeIt = () => {
clearTimeout(timeDebonceRef.current);
timeDebonceRef.current = setTimeout(() => {
}, 500);
clearTimeout(timeDebonceRef.current)
timeDebonceRef.current = setTimeout(() => {}, 500)
if (editorNodes) {
} else {
}
}
......@@ -37,49 +33,34 @@ const PaddingSpace = forwardRef((props, ref) => {
return {
inputValue1,
inputValue2,
inputValue3,
};
});
inputValue3
}
})
return (
<div className='custom-bar-box-input'>
<div className='box'>
<div className='customer-box-input-item'>
<div className="custom-bar-box-input">
<div className="box">
<div className="customer-box-input-item">
<p>
<InputNumber
controls={false}
id='padding_1'
value={inputValue1}
onChange={InpoutValueChange1}
/>
<InputNumber controls={false} id="padding_1" value={inputValue1} onChange={InpoutValueChange1} />
</p>
<p className='text'>段前间距</p>
<p className="text">段前间距</p>
</div>
<div className='customer-box-input-item'>
<div className="customer-box-input-item">
<p>
<InputNumber
controls={false}
id='padding_2'
value={inputValue2}
onChange={InpoutValueChange2}
/>
<InputNumber controls={false} id="padding_2" value={inputValue2} onChange={InpoutValueChange2} />
</p>
<p className='text'>段后间距</p>
<p className="text">段后间距</p>
</div>
<div className='customer-box-input-item'>
<div className="customer-box-input-item">
<p>
<InputNumber
controls={false}
id='padding_3'
value={inputValue3}
onChange={InpoutValueChange3}
/>
<InputNumber controls={false} id="padding_3" value={inputValue3} onChange={InpoutValueChange3} />
</p>
<p className='text'>行距</p>
<p className="text">行距</p>
</div>
</div>
</div>
);
});
)
}
export default PaddingSpace;
export default forwardRef(PaddingSpace)
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
import { Form, Space, Input, Select, Button, Spin, Row, Col, Checkbox, Radio } from 'antd';
import { MinusOutlined, PlusOutlined } from '@ant-design/icons';
import { useSelector } from 'react-redux';
import { Editor, Toolbar } from '@wangeditor/editor-for-react';
import { DomEditor } from '@wangeditor/editor';
import { questionAdd, typeAllList, questionAddType, bookNameList } from '../request';
import AliOSS from 'ali-oss';
import dayjs from 'dayjs';
import { getAliOSSSTSToken } from '@/pages/setting/help/addedit/requet';
import { uploadFiles } from '@/utils/upload';
import QuestionEditr from '@/pages/books/question-bank/questionEditr';
import { values } from 'lodash-es';
const CustomerTopic = forwardRef((props, ref) => {
const { getTopList, bookNameIdData, setPracticeStatus, bookId, setCustomerType } = props;
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react'
import { Form, Space, Input, Select, Button, Spin, Row, Col, Checkbox, Radio } from 'antd'
import { MinusOutlined, PlusOutlined } from '@ant-design/icons'
import { useSelector } from 'react-redux'
import { Editor, Toolbar } from '@wangeditor/editor-for-react'
import { DomEditor } from '@wangeditor/editor'
import { questionAdd, typeAllList, questionAddType, bookNameList } from '../request'
import AliOSS from 'ali-oss'
import dayjs from 'dayjs'
import { getAliOSSSTSToken } from '@/pages/setting/help/addedit/requet'
import { uploadFiles } from '@/utils/upload'
import QuestionEditr from '@/pages/books/question-bank/questionEditr'
import { values } from 'lodash-es'
const CustomerTopic = (props, ref) => {
const { getTopList, bookNameIdData, setPracticeStatus, bookId, setCustomerType } = props
// 获取操作权限
const { operationPermissionsList } = useSelector((state) => state.user);
const { operationPermissionsList } = useSelector(state => state.user)
useImperativeHandle(ref, () => {
return {};
});
return {}
})
// oss
const [ossClient, setOssClient] = useState(null); // oss 操作
const [STSToken, setSTSToken] = useState(null); // oss 过期设置
const [loading, setLoading] = useState(false);
const [form] = Form.useForm();
const questionType = Form.useWatch('question_style', form);
const [ossClient, setOssClient] = useState(null) // oss 操作
const [STSToken, setSTSToken] = useState(null) // oss 过期设置
const [loading, setLoading] = useState(false)
const [form] = Form.useForm()
const questionType = Form.useWatch('question_style', form)
// 题干名称的编辑器实例
const [titlesEditor, setTitlesEditor] = useState(null);
const [quesList, setQuesList] = useState([]);
const [titlesEditor, setTitlesEditor] = useState(null)
const [quesList, setQuesList] = useState([])
const [initialValues, setinitialValues] = useState({
titles: '',
type_id: '',
......@@ -39,20 +39,20 @@ const CustomerTopic = forwardRef((props, ref) => {
analysis: '',
answers: '',
question_list: [],
book_id: bookId,
});
book_id: bookId
})
// 书籍名称的参数和获取
const [selectedBookId, setSelectedBookId] = useState(bookId);
const [selectedBookId, setSelectedBookId] = useState(bookId)
useEffect(() => {
setSelectedBookId(bookId);
}, [bookId]);
setSelectedBookId(bookId)
}, [bookId])
const getStsAuthToken = async () => {
const data = await getAliOSSSTSToken();
const data = await getAliOSSSTSToken()
if (data) {
window.sessionStorage.setItem('sts', JSON.stringify(data));
setSTSToken(data);
window.sessionStorage.setItem('sts', JSON.stringify(data))
setSTSToken(data)
const ossClientTemp = await new AliOSS({
accessKeyId: data.AccessKeyId,
accessKeySecret: data.AccessKeySecret,
......@@ -62,66 +62,66 @@ const CustomerTopic = forwardRef((props, ref) => {
timeout: 180000,
refreshSTSToken: async () => {
const info = await getAliOSSSTSToken();
const info = await getAliOSSSTSToken()
return {
AccessKeyId: info.AccessKeyId,
AccessKeySecret: info.AccessKeySecret,
SecurityToken: info.SecurityToken,
};
SecurityToken: info.SecurityToken
}
},
refreshSTSTokenInterval: 14 * 60 * 1000,
});
setOssClient(ossClientTemp);
refreshSTSTokenInterval: 14 * 60 * 1000
})
setOssClient(ossClientTemp)
}
}
};
// 显示不同类型的选项函数
const [edierVal, setedierVal] = useState('');
const [edierVal, setedierVal] = useState('')
// 是否显示选项
const [showList, setShowList] = useState(false);
const [formLoading, setFormLoading] = useState(false);
const [typeDate, setTypeDate] = useState([]);
const [showAddClass, setShowAddClass] = useState(false);
const [addClassVal, setaddClassVal] = useState(''); // 添加分类
const [questionStyle, setQuestionStyle] = useState('');
const [showList, setShowList] = useState(false)
const [formLoading, setFormLoading] = useState(false)
const [typeDate, setTypeDate] = useState([])
const [showAddClass, setShowAddClass] = useState(false)
const [addClassVal, setaddClassVal] = useState('') // 添加分类
const [questionStyle, setQuestionStyle] = useState('')
// 题目分类
const getTypeList = async () => {
const { list } = await typeAllList({ page: 1, page_size: 999 });
setTypeDate(list);
};
const { list } = await typeAllList({ page: 1, page_size: 999 })
setTypeDate(list)
}
// 获取数据
useEffect(() => {
(async () => {
await getTypeList();
await getStsAuthToken();
})();
}, []);
;(async () => {
await getTypeList()
await getStsAuthToken()
})()
}, [])
// 分类
const sureFn = async () => {
const bool = await questionAddType({ typename: addClassVal });
const bool = await questionAddType({ typename: addClassVal })
if (bool) {
await getTypeList();
form.setFieldsValue({ type_id: bool.type_id });
setinitialValues({ ...initialValues, type_id: bool.type_id });
setaddClassVal('');
setShowAddClass(false);
await getTypeList()
form.setFieldsValue({ type_id: bool.type_id })
setinitialValues({ ...initialValues, type_id: bool.type_id })
setaddClassVal('')
setShowAddClass(false)
}
}
};
// 工具栏配置
const toolbarConfig = {};
toolbarConfig.toolbarKeys = ['uploadImage'];
const toolbarConfig = {}
toolbarConfig.toolbarKeys = ['uploadImage']
// 编辑器配置
const editorConfig = {
// JS 语法
placeholder: '请输入内容...',
hoverbarKeys: {
text: {
menuKeys: [],
},
menuKeys: []
}
},
MENU_CONF: {
// 配置默认字号
......@@ -132,158 +132,144 @@ const CustomerTopic = forwardRef((props, ref) => {
fieldName: 'image',
headers: {
'Content-Type': 'multipart/form-data',
Authorization: 'Bearer ' + localStorage.getItem('token'),
Authorization: 'Bearer ' + localStorage.getItem('token')
},
maxFileSize: 10 * 1024 * 1024, // 10M
base64LimitSize: 5 * 1024, // 5kb 以下插入 base64
customUpload: async (file, insertFn) => {
if (!ossClient) {
console.error('ossClient还未初始化', ossClient);
return false;
console.error('ossClient还未初始化', ossClient)
return false
}
const fileExt = file.name.substring(file.name.lastIndexOf('.'));
const fileName = `practice-${dayjs().valueOf()}-${Math.random()
.toString(36)
.substring(2)}${fileExt}`;
const filePath = `${dayjs().format('YYYY/MM/DD')}/${fileName}`;
const fileExt = file.name.substring(file.name.lastIndexOf('.'))
const fileName = `practice-${dayjs().valueOf()}-${Math.random().toString(36).substring(2)}${fileExt}`
const filePath = `${dayjs().format('YYYY/MM/DD')}/${fileName}`
const result = await ossClient.put(filePath, file);
const result = await ossClient.put(filePath, file)
console.log('result', result);
insertFn(result.url, '题库图片');
console.log('result', result)
insertFn(result.url, '题库图片')
// const { url } = await uploadFiles({ file, file_type: 'question' });
// insertFn(url, '题库图片');
},
},
}
}
},
customPaste: (editor, event) => {
// const html = event.clipboardData.getData('text/html') // 获取粘贴的 html
const text = event.clipboardData.getData('text/plain'); // 获取粘贴的纯文本
const text = event.clipboardData.getData('text/plain') // 获取粘贴的纯文本
// const rtf = event.clipboardData.getData('text/rtf') // 获取 rtf 数据(如从 word wsp 复制粘贴)
// 异步
setTimeout(() => {
editor.insertText(text);
}, 500);
editor.insertText(text)
}, 500)
// 阻止默认的粘贴行为
event.preventDefault();
return false;
},
};
event.preventDefault()
return false
}
}
// 及时销毁 editor ,重要!
useEffect(() => {
if (titlesEditor !== null) {
const toolbar = DomEditor.getToolbar(titlesEditor);
const toolbar = DomEditor.getToolbar(titlesEditor)
}
return () => {
if (titlesEditor === null) return;
titlesEditor.destroy();
setTitlesEditor(null);
};
}, [titlesEditor]);
const submitForm = async (obj) => {
let ilen = 0;
let obj2 = { ...obj };
if (titlesEditor === null) return
titlesEditor.destroy()
setTitlesEditor(null)
}
}, [titlesEditor])
const submitForm = async obj => {
let ilen = 0
let obj2 = { ...obj }
if ([1, 2, 3].includes(parseInt(obj.question_style))) {
obj.question_list.forEach((item, index) => {
if (item.correct && item.correct === true) {
ilen++;
ilen++
}
});
})
if ([1, 3].includes(parseInt(obj.question_style))) {
if (ilen > 1 || ilen === 0) {
form.setFields([
{
name: ['question_list', obj.question_list.length - 1, 'correct'],
errors: [
`${parseInt(obj.question_style) === 3 ? '判断题' : '单选题'}有且仅有一个正确答案!`,
],
},
]);
return false;
errors: [`${parseInt(obj.question_style) === 3 ? '判断题' : '单选题'}有且仅有一个正确答案!`]
}
])
return false
} else {
form.setFields([
{ name: ['question_list', obj.question_list.length - 1, 'correct'], errors: [''] },
]);
form.setFields([{ name: ['question_list', obj.question_list.length - 1, 'correct'], errors: [''] }])
}
} else {
if (ilen <= 1) {
form.setFields([
{
name: ['question_list', obj.question_list.length - 1, 'correct'],
errors: ['多选题需要2个及以上正确答案!'],
},
]);
return false;
errors: ['多选题需要2个及以上正确答案!']
}
])
return false
} else {
form.setFields([
{ name: ['question_list', obj.question_list.length - 1, 'correct'], errors: [''] },
]);
form.setFields([{ name: ['question_list', obj.question_list.length - 1, 'correct'], errors: [''] }])
}
}
obj2['question_list'] = JSON.stringify(quesList);
obj2['question_list'] = JSON.stringify(quesList)
} else {
obj2['answers'] = edierVal;
obj2['answers'] = edierVal
}
setLoading(true);
setLoading(true)
const data = await questionAdd({
...obj,
...obj2,
});
...obj2
})
if (data) {
setCustomerType(obj.type_id);
setPracticeStatus(false);
setCustomerType(obj.type_id)
setPracticeStatus(false)
}
setLoading(false)
}
setLoading(false);
};
// 校验
const vaildaterHtml = (_, value) => {
if (value === '<p><br></p>') {
return Promise.reject('问题内容不能为空');
return Promise.reject('问题内容不能为空')
} else {
return Promise.resolve();
return Promise.resolve()
}
}
};
useEffect(() => {
console.log(quesList);
}, [quesList]);
console.log(quesList)
}, [quesList])
return (
<div style={{ paddingTop: 20 }} className='practice_customer'>
<div style={{ paddingTop: 20 }} className="practice_customer">
<Form
form={form}
initialValues={initialValues}
onFinish={submitForm}
labelCol={{ span: 5 }}
wrapperCol={{ span: 19 }}
>
<Form.Item
name='book_id'
label='书籍名称'
rules={[{ required: true, message: '请选择书籍' }]}
>
wrapperCol={{ span: 19 }}>
<Form.Item name="book_id" label="书籍名称" rules={[{ required: true, message: '请选择书籍' }]}>
<Select
placeholder='请选择书籍名称'
placeholder="请选择书籍名称"
allowClear
id='classify'
id="classify"
style={{ width: '200px' }}
showSearch //下拉框出现搜素,并可以输入
optionFilterProp='children' // 使搜索匹配子节点的文本内容
optionFilterProp="children" // 使搜索匹配子节点的文本内容
defaultValue={selectedBookId}
onChange={(value) => setSelectedBookId(value)}
>
onChange={value => setSelectedBookId(value)}>
{bookNameIdData &&
bookNameIdData.length &&
bookNameIdData.map((item, index) => (
......@@ -294,19 +280,14 @@ const CustomerTopic = forwardRef((props, ref) => {
</Select>
</Form.Item>
<Form.Item
name='question_style'
label='题目类型'
rules={[{ required: true, message: '请选择题目类型' }]}
>
<Form.Item name="question_style" label="题目类型" rules={[{ required: true, message: '请选择题目类型' }]}>
<Select
onChange={(ev) => {
setShowList(true);
setQuestionStyle(ev);
onChange={ev => {
setShowList(true)
setQuestionStyle(ev)
}}
style={{ width: 260 }}
placeholder='请请选择题目类型'
>
placeholder="请请选择题目类型">
<Select.Option value={1}>单选题</Select.Option>
<Select.Option value={2}>多选题</Select.Option>
<Select.Option value={3}>判断题</Select.Option>
......@@ -314,23 +295,18 @@ const CustomerTopic = forwardRef((props, ref) => {
<Select.Option value={5}>简答题</Select.Option>
</Select>
</Form.Item>
<Form.Item
label='题目分类'
name='type_id'
rules={[{ required: true, message: '请选择题目分类' }]}
>
<Form.Item label="题目分类" name="type_id" rules={[{ required: true, message: '请选择题目分类' }]}>
{!showAddClass ? (
<>
<Select
onChange={(value) => {
form.setFieldValue('type_id', value);
onChange={value => {
form.setFieldValue('type_id', value)
}}
style={{ width: 260 }}
placeholder='请选择题目分类'
>
placeholder="请选择题目分类">
{typeDate &&
typeDate.length &&
typeDate.map((item) => (
typeDate.map(item => (
<Select.Option key={item.id} value={item.id}>
{item.typename}
</Select.Option>
......@@ -338,12 +314,11 @@ const CustomerTopic = forwardRef((props, ref) => {
</Select>
<Button
onClick={() => {
setShowAddClass(true);
form.setFieldsValue({ type_id: '' });
setShowAddClass(true)
form.setFieldsValue({ type_id: '' })
}}
type='link'
style={{ textDecoration: 'underline', color: '#1672EC' }}
>
type="link"
style={{ textDecoration: 'underline', color: '#1672EC' }}>
添加分类
</Button>
</>
......@@ -352,23 +327,17 @@ const CustomerTopic = forwardRef((props, ref) => {
<Input
style={{ width: 260 }}
value={addClassVal}
onChange={(e) => setaddClassVal(e.target.value)}
autoComplete='off'
placeholder='请输入题目分类'
></Input>
onChange={e => setaddClassVal(e.target.value)}
autoComplete="off"
placeholder="请输入题目分类"></Input>
<Space>
<Button
onClick={sureFn}
type='link'
style={{ textDecoration: 'underline', color: '#1672EC' }}
>
<Button onClick={sureFn} type="link" style={{ textDecoration: 'underline', color: '#1672EC' }}>
添加
</Button>
<Button
type='link'
type="link"
onClick={() => setShowAddClass(false)}
style={{ textDecoration: 'underline', color: '#AA1941', marginLeft: -30 }}
>
style={{ textDecoration: 'underline', color: '#AA1941', marginLeft: -30 }}>
取消
</Button>
</Space>
......@@ -376,20 +345,19 @@ const CustomerTopic = forwardRef((props, ref) => {
)}
</Form.Item>
<Form.Item
name='titles'
label='题干名称'
name="titles"
label="题干名称"
rules={[
{ required: true, message: '请输入题干名称' },
{ validator: vaildaterHtml, validateTrigger: 'onChange' },
{ validator: vaildaterHtml, validateTrigger: 'onChange' }
]}
extra={questionType === 4 ? '请在需要填空的位置使用2个或以上的下划线进行区分!' : ''}
>
extra={questionType === 4 ? '请在需要填空的位置使用2个或以上的下划线进行区分!' : ''}>
<Spin spinning={formLoading}>
<div style={{ border: '1px solid #ccc', zIndex: 100 }}>
<Toolbar
editor={titlesEditor}
defaultConfig={toolbarConfig}
mode='default'
mode="default"
style={{ borderBottom: '1px solid #ccc' }}
/>
{ossClient && (
......@@ -397,38 +365,38 @@ const CustomerTopic = forwardRef((props, ref) => {
defaultConfig={editorConfig}
value={initialValues.titles}
onCreated={setTitlesEditor}
onChange={(editor) => {
form.setFieldValue('titles', editor.getHtml());
onChange={editor => {
form.setFieldValue('titles', editor.getHtml())
// setHtml(editor.getHtml())
}}
config={{
uploadImgServer: 'your_upload_server_address',
uploadImgServer: 'your_upload_server_address'
// other config options
}}
mode='default'
mode="default"
style={{ height: '200px', overflowY: 'hidden' }}
/>
)}
</div>
</Spin>
</Form.Item>
<Form.Item name='analysis' label='题目解析'>
<Form.Item name="analysis" label="题目解析">
<Input.TextArea
placeholder='请输入题目解析'
placeholder="请输入题目解析"
autoSize={{
minRows: 5,
maxRows: 8,
maxRows: 8
}}
/>
</Form.Item>
{(questionStyle === 1 || questionStyle === 2 || questionStyle === 3) && (
<Form.List name='question_list'>
<Form.List name="question_list">
{(fields, { add, remove }) => (
<Form.Item label='题目选项'>
<Form.Item label="题目选项">
{fields.map(({ key, name, ...restField }, index) => (
<Row gutter={4} key={key}>
<Col span={14} className='form_inside-out'>
<Form.Item className='inside-it'>
<Col span={14} className="form_inside-out">
<Form.Item className="inside-it">
<QuestionEditr
editorValue={quesList && quesList[index] && quesList[index].option}
quesList={quesList}
......@@ -446,18 +414,17 @@ const CustomerTopic = forwardRef((props, ref) => {
validator: (_, value) => {
if (value !== '') {
if (value === '<p><br></p>') {
return Promise.reject(new Error('请输入正确的内容'));
return Promise.reject(new Error('请输入正确的内容'))
} else {
return Promise.resolve();
return Promise.resolve()
}
} else {
return Promise.reject(new Error(''));
return Promise.reject(new Error(''))
}
}
}
},
},
]}
className='form_inside-out-none'
>
className="form_inside-out-none">
<Input.TextArea />
</Form.Item>
</Col>
......@@ -465,26 +432,24 @@ const CustomerTopic = forwardRef((props, ref) => {
<Form.Item
{...restField}
name={[name, 'correct']}
valuePropName='checked'
initialValue={restField.correct || false}
>
valuePropName="checked"
initialValue={restField.correct || false}>
<Checkbox
onChange={(e) => {
onChange={e => {
if (quesList.length) {
let temp = JSON.parse(JSON.stringify(quesList));
let temp = JSON.parse(JSON.stringify(quesList))
if (questionStyle === 1 || questionStyle === 3) {
if (e.target.checked) {
temp.forEach((item) => {
item.correct = false;
});
temp.forEach(item => {
item.correct = false
})
}
}
temp[index].correct = e.target.checked;
setQuesList(temp);
form.setFieldValue('question_list', temp);
temp[index].correct = e.target.checked
setQuesList(temp)
form.setFieldValue('question_list', temp)
}
}}
>
}}>
正确答案
</Checkbox>
</Form.Item>
......@@ -492,37 +457,34 @@ const CustomerTopic = forwardRef((props, ref) => {
<Col span={3}>
<Button
onClick={async () => {
let temp = JSON.parse(JSON.stringify(quesList));
temp.splice(index, 1);
setQuesList(temp);
let temp = JSON.parse(JSON.stringify(quesList))
temp.splice(index, 1)
setQuesList(temp)
await remove(name);
await remove(name)
}}
icon={<MinusOutlined />}
></Button>
icon={<MinusOutlined />}></Button>
</Col>
</Row>
))}
{quesList.length < 2 && questionStyle === 3 && (
<Form.Item>
<Button
type='dashed'
type="dashed"
onClick={async () => {
await add();
await add()
}}
icon={<PlusOutlined />}
></Button>
icon={<PlusOutlined />}></Button>
</Form.Item>
)}
{[1, 2].includes(questionStyle) && (
<Form.Item>
<Button
type='dashed'
type="dashed"
onClick={async () => {
await add();
await add()
}}
icon={<PlusOutlined />}
></Button>
icon={<PlusOutlined />}></Button>
</Form.Item>
)}
</Form.Item>
......@@ -530,25 +492,20 @@ const CustomerTopic = forwardRef((props, ref) => {
</Form.List>
)}
{(questionStyle === 5 || questionStyle === 4) && (
<Form.Item name='answers' label='正确答案'>
<QuestionEditr
editorValue={edierVal}
setedierVal={setedierVal}
form={form}
name='answers'
/>
<Form.Item name="answers" label="正确答案">
<QuestionEditr editorValue={edierVal} setedierVal={setedierVal} form={form} name="answers" />
</Form.Item>
)}
<Form.Item wrapperCol={{ offset: 5, span: 16 }}>
<Space size={20}>
<Button className='submit' disabled={showAddClass} loading={loading} htmlType='submit'>
<Button className="submit" disabled={showAddClass} loading={loading} htmlType="submit">
提交
</Button>
</Space>
</Form.Item>
</Form>
</div>
);
});
)
}
export default CustomerTopic;
export default forwardRef(CustomerTopic)
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
import { Button, Popconfirm, message } from 'antd';
import { CloseOutlined } from '@ant-design/icons';
import { useDispatch } from 'react-redux';
import { setPracticeRandom } from '@/store/modules/editor';
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react'
import { Button, Popconfirm, message } from 'antd'
import { CloseOutlined } from '@ant-design/icons'
import { useDispatch } from 'react-redux'
import { setPracticeRandom } from '@/store/modules/editor'
import TopicItem from './topicItem';
import { addChapterTopic, getChapterTopic } from '../../utils/request';
import { clacTopicText } from '@/utils/common';
import TopicItem from './topicItem'
import { addChapterTopic, getChapterTopic } from '../../utils/request'
import { clacTopicText } from '@/utils/common'
const InsertTopic = forwardRef((props, ref) => {
const InsertTopic = (props, ref) => {
const {
insertList,
setInsertList,
......@@ -17,233 +17,208 @@ const InsertTopic = forwardRef((props, ref) => {
practiceRandom = '',
closePanel,
chapterId,
bookId,
} = props;
const dispatch = useDispatch();
bookId
} = props
const dispatch = useDispatch()
useImperativeHandle(ref, () => {
return {};
});
return {}
})
// 插入的题库
const [btnLoading, setBtnLoading] = useState(false);
const [radioList, setRadioList] = useState([]);
const [checkboxList, setCheckboxList] = useState([]);
const [equalsList, setEqualsList] = useState([]);
const [pressList, setPressList] = useState([]);
const [textareaList, setTextAreaList] = useState([]);
const [btnLoading, setBtnLoading] = useState(false)
const [radioList, setRadioList] = useState([])
const [checkboxList, setCheckboxList] = useState([])
const [equalsList, setEqualsList] = useState([])
const [pressList, setPressList] = useState([])
const [textareaList, setTextAreaList] = useState([])
// 删除
const delConfirm = (record) => {
const temp = JSON.parse(JSON.stringify(insertList));
const newTemp = temp.filter((item) => parseInt(item.choose_id) !== parseInt(record.choose_id));
setInsertList(newTemp);
setChooseList(newTemp);
};
const delConfirm = record => {
const temp = JSON.parse(JSON.stringify(insertList))
const newTemp = temp.filter(item => parseInt(item.choose_id) !== parseInt(record.choose_id))
setInsertList(newTemp)
setChooseList(newTemp)
}
// 添加
const addChapterQuestion = async () => {
setBtnLoading(true);
setBtnLoading(true)
const question_ids = insertList.map((item) => item.choose_id);
const question_ids = insertList.map(item => item.choose_id)
const data = await addChapterTopic({
book_id: bookId,
chapter_id: chapterId,
question_ids,
position: practiceRandom,
});
position: practiceRandom
})
if (data) {
message.success('添加成功!');
dispatch(setPracticeRandom({ practiceNum: '', practiceTitle: '' }));
setBtnLoading(false);
closePanel();
message.success('添加成功!')
dispatch(setPracticeRandom({ practiceNum: '', practiceTitle: '' }))
setBtnLoading(false)
closePanel()
}
}
};
useEffect(() => {
if (insertList.length > 0) {
const t1 = insertList.filter((item) => parseInt(item.question_style) === 1);
const t2 = insertList.filter((item) => parseInt(item.question_style) === 2);
const t3 = insertList.filter((item) => parseInt(item.question_style) === 3);
const t4 = insertList.filter((item) => parseInt(item.question_style) === 4);
const t5 = insertList.filter((item) => parseInt(item.question_style) === 5);
const t1 = insertList.filter(item => parseInt(item.question_style) === 1)
const t2 = insertList.filter(item => parseInt(item.question_style) === 2)
const t3 = insertList.filter(item => parseInt(item.question_style) === 3)
const t4 = insertList.filter(item => parseInt(item.question_style) === 4)
const t5 = insertList.filter(item => parseInt(item.question_style) === 5)
setRadioList(t1);
setCheckboxList(t2);
setEqualsList(t3);
setPressList(t4);
setTextAreaList(t5);
setRadioList(t1)
setCheckboxList(t2)
setEqualsList(t3)
setPressList(t4)
setTextAreaList(t5)
} else {
setRadioList([]);
setCheckboxList([]);
setEqualsList([]);
setPressList([]);
setTextAreaList([]);
setRadioList([])
setCheckboxList([])
setEqualsList([])
setPressList([])
setTextAreaList([])
}
}, [insertList]);
}, [insertList])
return (
<div className='practice-insert-container'>
<div className='practice-insert-topic list-topic-box'>
<div className="practice-insert-container">
<div className="practice-insert-topic list-topic-box">
{radioList.length > 0 && (
<div className='list-topic-container'>
<div className="list-topic-container">
<h4>{clacTopicText('radio')}. 单选题</h4>
<div>
{radioList.map((item, index) => {
return (
<div className='topic-item' key={index}>
<div className='topic-info'>
<div className="topic-item" key={index}>
<div className="topic-info">
<TopicItem topic={item} index={index + 1} />
</div>
<div className='checkbox'>
<div className="checkbox">
<Popconfirm
title='确认删除此题目吗?'
title="确认删除此题目吗?"
onConfirm={() => delConfirm(item)}
okText='确认'
cancelText='取消'
>
<Button
type='link'
icon={<CloseOutlined />}
style={{ color: '#b83956' }}
></Button>
okText="确认"
cancelText="取消">
<Button type="link" icon={<CloseOutlined />} style={{ color: '#b83956' }}></Button>
</Popconfirm>
</div>
</div>
);
)
})}
</div>
</div>
)}
{checkboxList.length > 0 && (
<div className='list-topic-container'>
<div className="list-topic-container">
<h4>{clacTopicText('checkbox', radioList)}. 多选题</h4>
<div>
{checkboxList.map((item, index) => {
return (
<div className='topic-item' key={index}>
<div className='topic-info'>
<div className="topic-item" key={index}>
<div className="topic-info">
<TopicItem topic={item} index={index + 1} />
</div>
<div className='checkbox'>
<div className="checkbox">
<Popconfirm
title='确认删除此题目吗?'
title="确认删除此题目吗?"
onConfirm={() => delConfirm(item)}
okText='确认'
cancelText='取消'
>
<Button
type='link'
icon={<CloseOutlined />}
style={{ color: '#b83956' }}
></Button>
okText="确认"
cancelText="取消">
<Button type="link" icon={<CloseOutlined />} style={{ color: '#b83956' }}></Button>
</Popconfirm>
</div>
</div>
);
)
})}
</div>
</div>
)}
{equalsList.length > 0 && (
<div className='list-topic-container'>
<div className="list-topic-container">
<h4>{clacTopicText('judge', radioList, checkboxList)}. 判断题</h4>
<div>
{equalsList.map((item, index) => {
return (
<div className='topic-item' key={index}>
<div className='topic-info'>
<div className="topic-item" key={index}>
<div className="topic-info">
<TopicItem topic={item} index={index + 1} />
</div>
<div className='checkbox'>
<div className="checkbox">
<Popconfirm
title='确认删除此题目吗?'
title="确认删除此题目吗?"
onConfirm={() => delConfirm(item)}
okText='确认'
cancelText='取消'
>
<Button
type='link'
icon={<CloseOutlined />}
style={{ color: '#b83956' }}
></Button>
okText="确认"
cancelText="取消">
<Button type="link" icon={<CloseOutlined />} style={{ color: '#b83956' }}></Button>
</Popconfirm>
</div>
</div>
);
)
})}
</div>
</div>
)}
{pressList.length > 0 && (
<div className='list-topic-container'>
<div className="list-topic-container">
<h4>{clacTopicText('fill', radioList, checkboxList, equalsList)}. 填空题</h4>
<div>
{pressList.map((item, index) => {
return (
<div className='topic-item' key={index}>
<div className='topic-info'>
<div className="topic-item" key={index}>
<div className="topic-info">
<TopicItem topic={item} index={index + 1} />
</div>
<div className='checkbox'>
<div className="checkbox">
<Popconfirm
title='确认删除此题目吗?'
title="确认删除此题目吗?"
onConfirm={() => delConfirm(item)}
okText='确认'
cancelText='取消'
>
<Button
type='link'
icon={<CloseOutlined />}
style={{ color: '#b83956' }}
></Button>
okText="确认"
cancelText="取消">
<Button type="link" icon={<CloseOutlined />} style={{ color: '#b83956' }}></Button>
</Popconfirm>
</div>
</div>
);
)
})}
</div>
</div>
)}
{textareaList.length > 0 && (
<div className='list-topic-container'>
<div className="list-topic-container">
<h4>{clacTopicText('textarea', radioList, checkboxList, equalsList, pressList)}. 简答题</h4>
<div>
{textareaList.map((item, index) => {
return (
<div className='topic-item' key={index}>
<div className='topic-info'>
<div className="topic-item" key={index}>
<div className="topic-info">
<TopicItem topic={item} index={index + 1} />
</div>
<div className='checkbox'>
<div className="checkbox">
<Popconfirm
title='确认删除此题目吗?'
title="确认删除此题目吗?"
onConfirm={() => delConfirm(item)}
okText='确认'
cancelText='取消'
>
<Button
type='link'
icon={<CloseOutlined />}
style={{ color: '#b83956' }}
></Button>
okText="确认"
cancelText="取消">
<Button type="link" icon={<CloseOutlined />} style={{ color: '#b83956' }}></Button>
</Popconfirm>
</div>
</div>
);
)
})}
</div>
</div>
)}
</div>
<div className='practice-insert-buttons'>
<Button type='primary' loading={btnLoading} onClick={addChapterQuestion}>
<div className="practice-insert-buttons">
<Button type="primary" loading={btnLoading} onClick={addChapterQuestion}>
确定
</Button>
</div>
</div>
);
});
)
}
export default InsertTopic;
export default forwardRef(InsertTopic)
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
import { Pagination, Space, Select, Button, Input, Checkbox, Spin, Row, Col } from 'antd';
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react'
import { Pagination, Space, Select, Button, Input, Checkbox, Spin, Row, Col } from 'antd'
import TopicItem from './topicItem';
import TopicItem from './topicItem'
import { getList, typeAllList, bookNameList } from '../request';
import { getList, typeAllList, bookNameList } from '../request'
const topicStyle = [
{ id: 1, name: '单选题' },
{ id: 2, name: '多选题' },
{ id: 3, name: '判断题' },
{ id: 4, name: '填空题' },
{ id: 5, name: '简答题' },
];
{ id: 5, name: '简答题' }
]
const ListTopic = forwardRef((props, ref) => {
const { addTopicList, chooseList, setChooseList, bookId, bookNameIdData, practiceStatus, customerType } = props;
const ListTopic = (props, ref) => {
const { addTopicList, chooseList, setChooseList, bookId, bookNameIdData, practiceStatus, customerType } = props
const [loading, setLoading] = useState(false);
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
const [source, setSource] = useState([]);
const [total, setTotal] = useState(0);
const [loading, setLoading] = useState(false)
const [page, setPage] = useState(1)
const [pageSize, setPageSize] = useState(10)
const [source, setSource] = useState([])
const [total, setTotal] = useState(0)
const [typeList, setTypeList] = useState([]);
const [checkedArr, setCheckedArr] = useState([]);
const [typeList, setTypeList] = useState([])
const [checkedArr, setCheckedArr] = useState([])
const [selectedBookId, setSelectedBookId] = useState(bookId);
const [selectedBookId, setSelectedBookId] = useState(bookId)
useEffect(() => {
let arr = [];
chooseList.forEach((item) => {
arr.push(item.choose_id);
});
setCheckedArr(arr);
}, [chooseList]);
let arr = []
chooseList.forEach(item => {
arr.push(item.choose_id)
})
setCheckedArr(arr)
}, [chooseList])
// 筛选条件设置
const [questionStyle, setQuestionStyle] = useState('');
const [typeId, setTypeId] = useState(customerType || '');
const [titles, setTitles] = useState('');
const [questionStyle, setQuestionStyle] = useState('')
const [typeId, setTypeId] = useState(customerType || '')
const [titles, setTitles] = useState('')
useImperativeHandle(ref, () => {
return {
setPage,
};
});
setPage
}
})
// 页码选择
const onChange = (number) => {
setPage(number);
const onChange = number => {
setPage(number)
}
const onShowSizeChange = (current, size) => {
setPageSize(size);
setPageSize(size)
}
const getTypeList = async () => {
const data = await typeAllList({ page: 1, page_size: 100000 });
if (data) setTypeList(data.list);
};
const data = await typeAllList({ page: 1, page_size: 100000 })
if (data) setTypeList(data.list)
}
useEffect(() => {
getTypeList();
}, []);
const getData = async (bool) => {
setLoading(true);
let obj = { page, page_size: pageSize };
if (questionStyle) obj.question_style = questionStyle;
if (typeId) obj.type_id = typeId;
if (titles) obj.titles = titles;
if (selectedBookId) obj.book_id = selectedBookId;
getTypeList()
}, [])
const getData = async bool => {
setLoading(true)
let obj = { page, page_size: pageSize }
if (questionStyle) obj.question_style = questionStyle
if (typeId) obj.type_id = typeId
if (titles) obj.titles = titles
if (selectedBookId) obj.book_id = selectedBookId
if (bool) {
setPage(1);
obj.page = 1;
setPage(1)
obj.page = 1
}
const data = await getList(obj);
const data = await getList(obj)
if (data) {
let dataSource = [];
let dataSource = []
data.list.forEach((item, index) => {
dataSource.push({ ...item, choose_id: item.id });
});
setTotal(data.total);
setSource(dataSource);
dataSource.push({ ...item, choose_id: item.id })
})
setTotal(data.total)
setSource(dataSource)
}
setLoading(false)
}
setLoading(false);
};
useEffect(() => {
if (selectedBookId !== null && !practiceStatus && customerType) {
getData(true);
getData(true)
} else {
getData();
getData()
}
}, [page, pageSize, practiceStatus, customerType]);
}, [page, pageSize, practiceStatus, customerType])
const topicChange = (e, record) => {
const temp = JSON.parse(JSON.stringify(chooseList));
let newTemp = [];
const temp = JSON.parse(JSON.stringify(chooseList))
let newTemp = []
if (e.target.checked) {
newTemp = [...temp, record];
newTemp = [...temp, record]
} else {
newTemp = temp.filter((item) => item.choose_id !== record.choose_id);
newTemp = temp.filter(item => item.choose_id !== record.choose_id)
}
setChooseList(newTemp)
}
setChooseList(newTemp);
};
return (
<div className='list-topic-container'>
<div className='list-topic-filter'>
<div className='list-topic-filter-list'>
<div className='filter-item'>
<div className="list-topic-container">
<div className="list-topic-filter">
<div className="list-topic-filter-list">
<div className="filter-item">
<Space>
<span className='label'>书籍名称:</span>
<span className="label">书籍名称:</span>
<Select
placeholder='请选择书籍名称'
placeholder="请选择书籍名称"
allowClear
defaultValue={bookId}
value={selectedBookId}
onChange={(value) => {
setSelectedBookId(value);
}}
>
onChange={value => {
setSelectedBookId(value)
}}>
{bookNameIdData &&
bookNameIdData.length > 0 &&
bookNameIdData.map((item, index) => (
......@@ -132,15 +130,14 @@ const ListTopic = forwardRef((props, ref) => {
</Select>
</Space>
</div>
<div className='filter-item'>
<div className="filter-item">
<Space>
<span className='label'>题目类型:</span>
<span className="label">题目类型:</span>
<Select
placeholder='请选择题目类型'
placeholder="请选择题目类型"
value={questionStyle}
onChange={(value) => setQuestionStyle(value)}
allowClear
>
onChange={value => setQuestionStyle(value)}
allowClear>
{topicStyle &&
topicStyle.length > 0 &&
topicStyle.map((item, index) => (
......@@ -151,15 +148,10 @@ const ListTopic = forwardRef((props, ref) => {
</Select>
</Space>
</div>
<div className='filter-item'>
<div className="filter-item">
<Space>
<span className='label'>题目分类:</span>
<Select
placeholder='请选择题目分类'
value={typeId}
onChange={(value) => setTypeId(value)}
allowClear
>
<span className="label">题目分类:</span>
<Select placeholder="请选择题目分类" value={typeId} onChange={value => setTypeId(value)} allowClear>
{typeList &&
typeList.length > 0 &&
typeList.map((item, index) => (
......@@ -170,50 +162,42 @@ const ListTopic = forwardRef((props, ref) => {
</Select>
</Space>
</div>
<div className='filter-item'>
<div className="filter-item">
<Space>
<span className='label'>题干名称:</span>
<Input
placeholder='请输入题干名称'
value={titles}
onChange={(e) => setTitles(e.target.value)}
allowClear
/>
<span className="label">题干名称:</span>
<Input placeholder="请输入题干名称" value={titles} onChange={e => setTitles(e.target.value)} allowClear />
</Space>
</div>
</div>
<div className='list-topic-filter-btn'>
<div className="list-topic-filter-btn">
<Space>
<Button type='default' onClick={() => getData(true)}>
<Button type="default" onClick={() => getData(true)}>
筛选
</Button>
</Space>
</div>
</div>
<div className='list-topic-box'>
<div className="list-topic-box">
<Spin spinning={loading}>
{/* <Checkbox.Group> */}
{source &&
source.length > 0 &&
source.map((item, index) => {
return (
<div className='topic-item' key={index}>
<div className='checkbox'>
<Checkbox
checked={checkedArr.includes(item.choose_id)}
onChange={(e) => topicChange(e, item)}
/>
<div className="topic-item" key={index}>
<div className="checkbox">
<Checkbox checked={checkedArr.includes(item.choose_id)} onChange={e => topicChange(e, item)} />
</div>
<div className='topic-info'>
<div className="topic-info">
<TopicItem topic={item} index={(page - 1) * pageSize + index + 1} />
</div>
</div>
);
)
})}
{/* </Checkbox.Group> */}
</Spin>
</div>
<div className='list-page'>
<div className="list-page">
<Pagination
showQuickJumper
showSizeChanger
......@@ -223,12 +207,12 @@ const ListTopic = forwardRef((props, ref) => {
onShowSizeChange={onShowSizeChange}
/>
<Button type='primary' onClick={addTopicList}>
<Button type="primary" onClick={addTopicList}>
添加
</Button>
</div>
</div>
);
});
)
}
export default ListTopic;
export default forwardRef(ListTopic)
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
import { Input } from 'antd';
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react'
import { Input } from 'antd'
const inCorrect = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
const inCorrect = [
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z'
]
const TopicItem = forwardRef((props, ref) => {
const { topic, index, preview = false } = props;
const [recordInfo, setRecordInfo] = useState({});
const [choose, setChoose] = useState(false);
const [chooseAnswer, setChooseAnswer] = useState([]);
const [isMap, setIsMap] = useState(false);
const TopicItem = (props, ref) => {
const { topic, index, preview = false } = props
const [recordInfo, setRecordInfo] = useState({})
const [choose, setChoose] = useState(false)
const [chooseAnswer, setChooseAnswer] = useState([])
const [isMap, setIsMap] = useState(false)
useEffect(() => {
if (Object.entries(topic).length) {
let temp = {};
let temp = {}
for (const key in topic) {
if (key === 'question_list') {
try {
temp[key] = JSON.parse(topic[key]);
temp[key] = JSON.parse(topic[key])
} catch (e) {
temp[key] = topic[key];
temp[key] = topic[key]
}
} else {
temp[key] = topic[key];
temp[key] = topic[key]
}
}
if (temp.question_style === 1 || temp.question_style === 2 || temp.question_style === 3) {
setChoose(true);
setChoose(true)
}
if (temp.question_list instanceof Array && temp.question_list.length > 0) {
setIsMap(true);
let an = [];
setIsMap(true)
let an = []
temp.question_list.forEach((item, index) => {
if (item.correct && (item.correct === 'true' || item.correct === true)) {
an.push(inCorrect[index]);
an.push(inCorrect[index])
}
});
setChooseAnswer(an);
})
setChooseAnswer(an)
}
setRecordInfo(temp);
setRecordInfo(temp)
}
}, [topic]);
}, [topic])
useImperativeHandle(ref, () => {
return {};
});
return {}
})
return (
<div className='topic-item-info'>
<div className="topic-item-info">
{Object.entries(recordInfo).length && (
<>
<div className='index'>{index}.</div>
<div className='topic'>
<div className="index">{index}.</div>
<div className="topic">
{/* <div>{recordInfo.titles}</div> */}
<div
className='topic-choose-title'
dangerouslySetInnerHTML={{ __html: recordInfo.titles }}
></div>
<div className="topic-choose-title" dangerouslySetInnerHTML={{ __html: recordInfo.titles }}></div>
{[1, 2, 3].includes(parseInt(recordInfo.question_style)) && (
<div className='topic-choose'>
<div className="topic-choose">
{choose &&
isMap &&
recordInfo &&
......@@ -67,28 +91,27 @@ const TopicItem = forwardRef((props, ref) => {
recordInfo.question_list.map((item, cindex) => {
return (
<div
className='topic-choose-item'
className="topic-choose-item"
key={cindex}
dangerouslySetInnerHTML={{
__html: `${inCorrect[cindex]}. ` + item.option,
}}
></div>
);
__html: `${inCorrect[cindex]}. ` + item.option
}}></div>
)
})}
</div>
)}
{preview && (
<div className='notes-preivew'>
<div className="notes-preivew">
{recordInfo.question_style === 5 && (
<div className='textarea'>
<div className="textarea">
<Input.TextArea autoSize={{ minRows: 3, maxRows: 4 }} />
</div>
)}
</div>
)}
<div className='answer'>
<div className="answer">
<strong>答案: </strong>
{[1, 2, 3].includes(recordInfo.question_style) ? (
<span>{chooseAnswer.join(' ')}</span>
......@@ -100,7 +123,7 @@ const TopicItem = forwardRef((props, ref) => {
</>
)}
</div>
);
});
)
}
export default TopicItem;
export default forwardRef(TopicItem)
......@@ -16,7 +16,7 @@ import { bookNameList } from './request'
import '../utils/iconfont'
import './index.less'
const PracticeSettingModal = forwardRef((props, ref) => {
const PracticeSettingModal = (props, ref) => {
const { editor, chapterId, bookId, closePanel } = props
const dispatch = useDispatch()
const { practiceRandom, practiceTitle, practiceTheme } = useSelector(state => state.editor)
......@@ -248,6 +248,6 @@ const PracticeSettingModal = forwardRef((props, ref) => {
</Row>
</div>
)
})
}
export default PracticeSettingModal
export default forwardRef(PracticeSettingModal)
import React, { useEffect, useState, useRef, useImperativeHandle, forwardRef } from 'react';
import { Modal, Drawer, Tree, Spin, Space, Button, Input, Image } from 'antd';
import { CloseOutlined, LeftOutlined, BarsOutlined } from '@ant-design/icons';
import { getInfoByChapterId, getAllList } from '@/pages/books/section/request';
import { getChapterTopic, expandReadInfo } from '@/common/wangeditor-customer/utils/request';
import '@/common/wangeditor-customer/utils/iconfont';
import {
convertToAntdTreeData,
findTreeElementByKey,
findFirstNotHasChildren,
clacTopicText,
} from '@/utils/common';
import { get } from 'lodash-es';
import $ from 'jquery';
import '@/common/preview.less';
import hljs from 'highlight.js';
import 'highlight.js/styles/github.css';
import React, { useEffect, useState, useRef, useImperativeHandle, forwardRef } from 'react'
import { Modal, Drawer, Tree, Spin, Space, Button, Input, Image } from 'antd'
import { CloseOutlined, LeftOutlined, BarsOutlined } from '@ant-design/icons'
import { getInfoByChapterId, getAllList } from '@/pages/books/section/request'
import { getChapterTopic, expandReadInfo } from '@/common/wangeditor-customer/utils/request'
import '@/common/wangeditor-customer/utils/iconfont'
import { convertToAntdTreeData, findTreeElementByKey, findFirstNotHasChildren, clacTopicText } from '@/utils/common'
import { get } from 'lodash-es'
import $ from 'jquery'
import '@/common/preview.less'
import hljs from 'highlight.js'
import 'highlight.js/styles/github.css'
const correctList = [
'A',
......@@ -43,196 +38,194 @@ const correctList = [
'W',
'X',
'Y',
'Z',
];
'Z'
]
const PreviewScreen = forwardRef((props, ref) => {
const { bookId } = props;
const [gData, setGData] = useState([]);
const [loading, setLoading] = useState(false); // 展示
const [prviewHtml, setPrviewHtml] = useState(''); // 预览html
const [open, setOpen] = useState(false); // 抽屉
const [secondType, setSecondType] = useState(false);
const PreviewScreen = (props, ref) => {
const { bookId } = props
const [gData, setGData] = useState([])
const [loading, setLoading] = useState(false) // 展示
const [prviewHtml, setPrviewHtml] = useState('') // 预览html
const [open, setOpen] = useState(false) // 抽屉
const [secondType, setSecondType] = useState(false)
const [toolTip, setTooltip] = useState({});
const [toolTip, setTooltip] = useState({})
// 树节点设置
const [expandedKeys, setExpandedKeys] = useState([]);
const [checkedKeys, setCheckedKeys] = useState([]);
const [headTitle, setHeadTitle] = useState('');
const [oldTitle, setOldTitle] = useState('');
const [newChapterId, setNewChapterId] = useState('');
const [opend, setOpend] = useState(false);
const [gallery, setGallery] = useState([]);
const [galleryIndex, setGalleryIndex] = useState(0);
const [isType, setIsType] = useState('');
const [topicList, setTopicList] = useState([]); // 题库
const [radioList, setRadioList] = useState([]); // 单选
const [checkBoxList, setCheckBoxList] = useState([]); // 多选
const [judgeList, setJudgeList] = useState([]); // 判断
const [fillList, setFillList] = useState([]); // 填空
const [textareaList, setTextareaList] = useState([]); // 简答
const [expandContent, setExpandContent] = useState(''); // 扩展阅读内容
const [previewImg, setPreviewImg] = useState(''); // 扩展阅读内容
const newId = useRef(null);
const [expandedKeys, setExpandedKeys] = useState([])
const [checkedKeys, setCheckedKeys] = useState([])
const [headTitle, setHeadTitle] = useState('')
const [oldTitle, setOldTitle] = useState('')
const [newChapterId, setNewChapterId] = useState('')
const [opend, setOpend] = useState(false)
const [gallery, setGallery] = useState([])
const [galleryIndex, setGalleryIndex] = useState(0)
const [isType, setIsType] = useState('')
const [topicList, setTopicList] = useState([]) // 题库
const [radioList, setRadioList] = useState([]) // 单选
const [checkBoxList, setCheckBoxList] = useState([]) // 多选
const [judgeList, setJudgeList] = useState([]) // 判断
const [fillList, setFillList] = useState([]) // 填空
const [textareaList, setTextareaList] = useState([]) // 简答
const [expandContent, setExpandContent] = useState('') // 扩展阅读内容
const [previewImg, setPreviewImg] = useState('') // 扩展阅读内容
const newId = useRef(null)
// 递归函数,获取所有节点的key
const getAllNodeKeys = (nodes) => {
let keys = [];
nodes.forEach((node) => {
keys.push(node.key);
const getAllNodeKeys = nodes => {
let keys = []
nodes.forEach(node => {
keys.push(node.key)
if (node.children && node.children.length > 0) {
keys = keys.concat(getAllNodeKeys(node.children));
keys = keys.concat(getAllNodeKeys(node.children))
}
})
return keys
}
});
return keys;
};
const getChapterTreeList = async () => {
setLoading(true);
const data = await getAllList({ book_id: bookId });
setLoading(true)
const data = await getAllList({ book_id: bookId })
if (!data.data.length) {
setLoading(false);
return;
setLoading(false)
return
}
const arr = convertToAntdTreeData(data.data, 'name')
setGData(arr)
const allKeys = getAllNodeKeys(arr)
setExpandedKeys(allKeys)
const first = findFirstNotHasChildren(arr)
setOldTitle(first.title)
setNewChapterId(first.key)
setLoading(false)
}
const arr = convertToAntdTreeData(data.data, 'name');
setGData(arr);
const allKeys = getAllNodeKeys(arr);
setExpandedKeys(allKeys);
const first = findFirstNotHasChildren(arr);
setOldTitle(first.title);
setNewChapterId(first.key);
setLoading(false);
};
const getTopicList = async ({ practicenum, chapterid, bookid }) => {
const data = await getChapterTopic({
position: practicenum,
book_id: bookid,
chapter_id: chapterid,
});
chapter_id: chapterid
})
const temp = [];
data.forEach((item) => {
let obj = { ...item };
const temp = []
data.forEach(item => {
let obj = { ...item }
if ([1, 2, 3].includes(parseInt(item.question_style))) {
try {
obj.question_list = JSON.parse(item.question_list);
obj.question_list = JSON.parse(item.question_list)
} catch (err) {
obj.question_list = [];
obj.question_list = []
}
}
temp.push(obj);
});
const tempRadio = temp.filter((item) => parseInt(item.question_style) === 1);
const tempCheckbox = temp.filter((item) => parseInt(item.question_style) === 2);
const tempJudge = temp.filter((item) => parseInt(item.question_style) === 3);
const tempFill = temp.filter((item) => parseInt(item.question_style) === 4);
const tempTextarea = temp.filter((item) => parseInt(item.question_style) === 5);
setRadioList(tempRadio);
setCheckBoxList(tempCheckbox);
setJudgeList(tempJudge);
setFillList(tempFill);
setTextareaList(tempTextarea);
setTopicList(temp);
};
temp.push(obj)
})
const tempRadio = temp.filter(item => parseInt(item.question_style) === 1)
const tempCheckbox = temp.filter(item => parseInt(item.question_style) === 2)
const tempJudge = temp.filter(item => parseInt(item.question_style) === 3)
const tempFill = temp.filter(item => parseInt(item.question_style) === 4)
const tempTextarea = temp.filter(item => parseInt(item.question_style) === 5)
setRadioList(tempRadio)
setCheckBoxList(tempCheckbox)
setJudgeList(tempJudge)
setFillList(tempFill)
setTextareaList(tempTextarea)
setTopicList(temp)
}
const getExpandInfo = async ({ chapterId, position }) => {
const data = await expandReadInfo({
book_id: bookId,
chapter_id: chapterId,
position: position,
});
position: position
})
if (data) {
setExpandContent(data.content);
setExpandContent(data.content)
}
}
};
const getChapterId = async () => {
setLoading(true);
newId.current = newChapterId;
const data = await getInfoByChapterId({ chapter_id: newChapterId });
setLoading(true)
newId.current = newChapterId
const data = await getInfoByChapterId({ chapter_id: newChapterId })
if (data) {
const content = get(data, 'content', '');
setPrviewHtml(content);
const content = get(data, 'content', '')
setPrviewHtml(content)
$('#previee-container')
.find('video audio')
.each((index, item) => {
$(item).attr('controls', true).attr('controlslist', 'nodownload');
});
$(item).attr('controls', true).attr('controlslist', 'nodownload')
})
setTimeout(() => {
document
.querySelectorAll('.preview-content-show ')[0]
.querySelectorAll('pre code')
.forEach((el) => {
hljs.highlightElement(el);
});
}, 200);
.forEach(el => {
hljs.highlightElement(el)
})
}, 200)
}
setLoading(false)
}
setLoading(false);
};
const handlerClick = () => {
const iParentW = $('.preview-content-it').innerWidth();
const iParentH = $('.preview-content-it').innerHeight();
const parentOffset = $('.preview-content-it').offset(); // 获取父元素相对于文档的位置
const parentRect = $('.preview-content-it')[0].getBoundingClientRect(); // 获取父元素相对于文档的位置
$('.preview-content-html').on('click', async (ev) => {
ev.stopPropagation();
const target = ev.target;
const tooltip = $(target).closest('.chapter-item-tooltip');
const alink = $(target).closest('.chapter-item-link');
const aGallery = $(target).closest('.chapter-gallery-container');
const practice = $(target).closest('.chapter-practice');
const aA = $(target).closest('a');
const aExpand = $(target).closest('.chapter-expand');
const iParentW = $('.preview-content-it').innerWidth()
const iParentH = $('.preview-content-it').innerHeight()
const parentOffset = $('.preview-content-it').offset() // 获取父元素相对于文档的位置
const parentRect = $('.preview-content-it')[0].getBoundingClientRect() // 获取父元素相对于文档的位置
$('.preview-content-html').on('click', async ev => {
ev.stopPropagation()
const target = ev.target
const tooltip = $(target).closest('.chapter-item-tooltip')
const alink = $(target).closest('.chapter-item-link')
const aGallery = $(target).closest('.chapter-gallery-container')
const practice = $(target).closest('.chapter-practice')
const aA = $(target).closest('a')
const aExpand = $(target).closest('.chapter-expand')
if (tooltip.length > 0) {
const random = $(tooltip).data('random');
const link = $(tooltip).data('link');
const content = $(tooltip).data('content');
const tooltipType = $(tooltip).data('tooltip-type');
const title = $(tooltip).data('title');
const tooltipParent = $(target).closest(
'p, div, h1, h2, h3, h4, h5, h6, li, dt, dd, section',
);
const tooltipParentPosition = $(tooltipParent).position();
const tooltipPosition = $(tooltip).position();
const childOffset = $(tooltip).offset(); // 获取子元素相对于文档的位置
const childWidth = $(tooltip).outerWidth(true); // 获取元素的宽度
const childHeight = $(tooltip).outerHeight(true); // 获取元素的高度
let toolRect = null;
let targetPositon = null;
const random = $(tooltip).data('random')
const link = $(tooltip).data('link')
const content = $(tooltip).data('content')
const tooltipType = $(tooltip).data('tooltip-type')
const title = $(tooltip).data('title')
const tooltipParent = $(target).closest('p, div, h1, h2, h3, h4, h5, h6, li, dt, dd, section')
const tooltipParentPosition = $(tooltipParent).position()
const tooltipPosition = $(tooltip).position()
const childOffset = $(tooltip).offset() // 获取子元素相对于文档的位置
const childWidth = $(tooltip).outerWidth(true) // 获取元素的宽度
const childHeight = $(tooltip).outerHeight(true) // 获取元素的高度
let toolRect = null
let targetPositon = null
if (target.nodeName.toLowerCase() === 'svg' || target.nodeName.toLowerCase() === 'use') {
toolRect = target.parentNode.parentNode.getBoundingClientRect();
targetPositon = $(target).closest('.chapter-item-tooltip').position();
toolRect = target.parentNode.parentNode.getBoundingClientRect()
targetPositon = $(target).closest('.chapter-item-tooltip').position()
} else {
toolRect = target.parentNode.getBoundingClientRect();
targetPositon = $(target).position();
toolRect = target.parentNode.getBoundingClientRect()
targetPositon = $(target).position()
}
const lineHeight = $(tooltip).css('line-height');
let inSide = '';
let left = childOffset.left - parentOffset.left;
let top = 0;
let squareStyle = {};
const lineHeight = $(tooltip).css('line-height')
let inSide = ''
let left = childOffset.left - parentOffset.left
let top = 0
let squareStyle = {}
if (childWidth + left >= iParentW) {
left = iParentW - childWidth - 10;
left = iParentW - childWidth - 10
}
if (left <= 0) {
left = 10;
left = 10
}
let style1 = {
top: `${top}px`,
left: `${left}px`,
};
left: `${left}px`
}
setTooltip({
title,
......@@ -242,52 +235,52 @@ const PreviewScreen = forwardRef((props, ref) => {
tooltipType,
inSide,
style: style1,
squareStyle: squareStyle,
});
squareStyle: squareStyle
})
setTimeout(() => {
const childMoveHeight = $('.tooltip').outerHeight(); // 获取元素的高度
const childMoveWidth = $('.tooltip').outerWidth(); // 获取元素的高度
const scrollTop = $('.preview-content-show').scrollTop();
let squareStyle = {};
const childMoveHeight = $('.tooltip').outerHeight() // 获取元素的高度
const childMoveWidth = $('.tooltip').outerWidth() // 获取元素的高度
const scrollTop = $('.preview-content-show').scrollTop()
let squareStyle = {}
if (left <= 0) {
left = 10;
squareStyle.left = 10;
left = 10
squareStyle.left = 10
} else if (left + childMoveWidth >= iParentW) {
left = iParentW - childMoveWidth - 20;
squareStyle.left = targetPositon.left - left;
left = iParentW - childMoveWidth - 20
squareStyle.left = targetPositon.left - left
} else {
squareStyle.left = childWidth / 2;
squareStyle.left = childWidth / 2
}
// 换行了
if (toolRect.height / 1.5 > parseInt(lineHeight)) {
left = toolRect.right - parentRect.left - childMoveWidth + 15;
squareStyle.left = childMoveWidth - 30;
left = toolRect.right - parentRect.left - childMoveWidth + 15
squareStyle.left = childMoveWidth - 30
}
// 是否被遮挡
if (tooltipPosition.top + childMoveHeight + childHeight + 30 >= scrollTop + iParentH) {
inSide = 'bottom';
top = tooltipPosition.top - childMoveHeight;
squareStyle.left = childWidth / 2;
inSide = 'bottom'
top = tooltipPosition.top - childMoveHeight
squareStyle.left = childWidth / 2
} else {
inSide = 'top';
inSide = 'top'
if (toolRect.height / 1.5 > parseInt(lineHeight)) {
top = tooltipPosition.top + childHeight;
top = tooltipPosition.top + childHeight
} else {
top = tooltipPosition.top + childHeight + 25;
top = tooltipPosition.top + childHeight + 25
}
// squareStyle.left = childWidth / 2;
}
top = top - scrollTop;
top = top - scrollTop
let style2 = {
top: `${top}px`,
left: `${left}px`,
zIndex: 1000,
opacity: 1,
};
opacity: 1
}
setTooltip({
title,
random,
......@@ -296,493 +289,448 @@ const PreviewScreen = forwardRef((props, ref) => {
tooltipType,
inSide,
style: style2,
squareStyle: squareStyle,
});
}, 100);
squareStyle: squareStyle
})
}, 100)
return false;
return false
} else if (alink.length > 0) {
const link = $(alink).data('link');
const linkType = $(alink).data('linktype');
const chapters = $(alink).data('chapters');
const title = $(alink).data('title');
const link = $(alink).data('link')
const linkType = $(alink).data('linktype')
const chapters = $(alink).data('chapters')
const title = $(alink).data('title')
let last = '';
let last = ''
if (parseInt(linkType) === 2) {
if (chapters.toString().indexOf(',') > -1) {
const arr = chapters.split(',');
last = arr[arr.length - 1];
const arr = chapters.split(',')
last = arr[arr.length - 1]
} else {
last = chapters;
last = chapters
}
setHeadTitle(title);
setOpend(true);
setNewChapterId(last);
setHeadTitle(title)
setOpend(true)
setNewChapterId(last)
} else {
window.open(link);
window.open(link)
}
ev.preventDefault();
return false;
ev.preventDefault()
return false
} else if (aGallery.length > 0) {
const title = $(aGallery).data('title');
const flex = $(aGallery).data('flex');
const gallerylist = $(aGallery).data('gallerylist');
const galleryArr = JSON.parse(decodeURI(gallerylist));
const title = $(aGallery).data('title')
const flex = $(aGallery).data('flex')
const gallerylist = $(aGallery).data('gallerylist')
const galleryArr = JSON.parse(decodeURI(gallerylist))
if (galleryArr && galleryArr.length > 0 && galleryArr instanceof Array) {
setGallery(galleryArr);
setGallery(galleryArr)
if (parseInt(flex) === 2) {
setGalleryIndex(0);
setGalleryIndex(0)
} else {
setGalleryIndex($(target).closest('.chapter-gallery-item').index());
setGalleryIndex($(target).closest('.chapter-gallery-item').index())
}
} else {
setGallery([]);
setGallery([])
}
setOpend(true);
setHeadTitle(title);
setIsType('gallery');
setTooltip({});
return false;
setOpend(true)
setHeadTitle(title)
setIsType('gallery')
setTooltip({})
return false
} else if (practice.length > 0) {
const title = $(practice).data('title');
const bookid = $(practice).data('bookid');
const chapterid = $(practice).data('chapterid');
const practicenum = $(practice).data('practicenum');
getTopicList({ practicenum, chapterid, bookid });
setOpend(true);
setHeadTitle(title);
setIsType('practice');
ev.preventDefault();
return false;
const title = $(practice).data('title')
const bookid = $(practice).data('bookid')
const chapterid = $(practice).data('chapterid')
const practicenum = $(practice).data('practicenum')
getTopicList({ practicenum, chapterid, bookid })
setOpend(true)
setHeadTitle(title)
setIsType('practice')
ev.preventDefault()
return false
} else if (aA.length > 0) {
const href = $(aA).attr('href');
const href = $(aA).attr('href')
let newLink = '';
let newLink = ''
if (!/^https*:\/\//.test(href)) {
newLink = `http://${href}`;
newLink = `http://${href}`
} else {
newLink = href;
newLink = href
}
window.open(newLink);
ev.preventDefault();
return false;
window.open(newLink)
ev.preventDefault()
return false
} else if (aExpand.length > 0) {
const title = $(aExpand).data('title');
const name = $(aExpand).data('name');
const position = $(aExpand).data('random');
setOpend(true);
setIsType('expand');
setHeadTitle(name);
await getExpandInfo({ chapterId: newId.current, position });
const title = $(aExpand).data('title')
const name = $(aExpand).data('name')
const position = $(aExpand).data('random')
setOpend(true)
setIsType('expand')
setHeadTitle(name)
await getExpandInfo({ chapterId: newId.current, position })
} else if (target.nodeName.toLowerCase() === 'img') {
const alt = $(target).attr('alt');
const src = $(target).attr('src');
setOpend(true);
setIsType('img');
setPreviewImg(src);
setHeadTitle(alt ? alt : '图片展示');
const alt = $(target).attr('alt')
const src = $(target).attr('src')
setOpend(true)
setIsType('img')
setPreviewImg(src)
setHeadTitle(alt ? alt : '图片展示')
}
setTooltip({});
setGallery([]);
});
setTooltip({})
setGallery([])
})
$('.expand-content, .gallery-prview-container').on('click', (ev) => {
const target = ev.target;
$('.expand-content, .gallery-prview-container').on('click', ev => {
const target = ev.target
if (target.nodeName.toLowerCase() === 'img') {
const alt = $(target).attr('alt');
const src = $(target).attr('src');
setOpend(true);
setIsType('img');
setPreviewImg(src);
setSecondType('扩展图片');
const alt = $(target).attr('alt')
const src = $(target).attr('src')
setOpend(true)
setIsType('img')
setPreviewImg(src)
setSecondType('扩展图片')
}
})
}
});
};
useEffect(() => {
handlerClick();
}, [isType]);
handlerClick()
}, [isType])
useEffect(() => {
if (bookId) {
getChapterTreeList();
getChapterTreeList()
}
}, [bookId]);
}, [bookId])
useEffect(() => {
if (newChapterId) {
getChapterId();
getChapterId()
}
}, [newChapterId]);
}, [newChapterId])
const onClose = () => {
setOpen(false);
};
const openDrawer = (e) => {
e.preventDefault();
e.stopPropagation();
setOpen(true);
};
setOpen(false)
}
const openDrawer = e => {
e.preventDefault()
e.stopPropagation()
setOpen(true)
}
const handleSelect = async (checkedKeys, info) => {
if (info.node.children && info.node.children.length > 0) {
const temp = JSON.parse(JSON.stringify(expandedKeys));
const temp = JSON.parse(JSON.stringify(expandedKeys))
if (temp.includes(info.node.key)) {
const newExpands = temp.filter((item) => item !== info.node.key);
setExpandedKeys([...newExpands]);
const newExpands = temp.filter(item => item !== info.node.key)
setExpandedKeys([...newExpands])
} else {
setExpandedKeys([...temp, info.node.key]);
setExpandedKeys([...temp, info.node.key])
}
} else {
setOldTitle(info.node.title);
setNewChapterId(info.node.key);
newId.current = info.node.key;
setCheckedKeys(checkedKeys);
setOpen(false);
setOldTitle(info.node.title)
setNewChapterId(info.node.key)
newId.current = info.node.key
setCheckedKeys(checkedKeys)
setOpen(false)
}
}
};
const galleryLeft = () => {
let temp = galleryIndex;
let temp = galleryIndex
if (temp <= 0) {
temp = 0;
temp = 0
} else {
temp = temp - 1;
temp = temp - 1
}
setGalleryIndex(temp)
}
setGalleryIndex(temp);
};
const galleryRight = () => {
let temp = galleryIndex;
let temp = galleryIndex
if (temp >= gallery.length - 1) {
temp = gallery.length - 1;
temp = gallery.length - 1
} else {
temp = temp + 1;
temp = temp + 1
}
setGalleryIndex(temp)
}
setGalleryIndex(temp);
};
return (
<div className='priview-modal'>
<div className="priview-modal">
{/* <Spin spinning={loading}> */}
<div className='previee-container' id='previee-container'>
<div className='chapter-head-title'>
<h2 className='tree'>
<div className="previee-container" id="previee-container">
<div className="chapter-head-title">
<h2 className="tree">
{opend ? (
<Space>
<Button
type='text'
type="text"
onClick={() => {
if (secondType) {
setSecondType(false);
setPreviewImg(null);
setIsType('expand');
return;
}
setOpend(false);
setIsType('');
setExpandContent('');
setTopicList([]);
setGalleryIndex(-1);
setNewChapterId(newChapterId);
setPreviewImg('');
}}
>
setSecondType(false)
setPreviewImg(null)
setIsType('expand')
return
}
setOpend(false)
setIsType('')
setExpandContent('')
setTopicList([])
setGalleryIndex(-1)
setNewChapterId(newChapterId)
setPreviewImg('')
}}>
<LeftOutlined />
</Button>
{secondType ? secondType : headTitle}
</Space>
) : (
<>
<span className='no'>{oldTitle}</span>
<span className='menu'>
<span className="no">{oldTitle}</span>
<span className="menu">
<BarsOutlined style={{ fontSize: 22 }} onClick={() => setOpen(true)} />
</span>
</>
)}
</h2>
</div>
<div className='preview-content-it'>
<div className='preview-content-show'>
<Spin spinning={loading} wrapperClassName='chapter-loading'>
<div
className='preview-content-html'
dangerouslySetInnerHTML={{ __html: prviewHtml }}
></div>
<div className="preview-content-it">
<div className="preview-content-show">
<Spin spinning={loading} wrapperClassName="chapter-loading">
<div className="preview-content-html" dangerouslySetInnerHTML={{ __html: prviewHtml }}></div>
</Spin>
</div>
{isType && (
<div className='preview-content-other'>
<div className="preview-content-other">
{isType === 'gallery' && (
<div className='gallery-prview-container'>
<div className="gallery-prview-container">
{gallery && gallery.length > 0 ? (
<>
<div className='gallery-img'>
<img
src={gallery[parseInt(galleryIndex)].url}
alt={gallery[parseInt(galleryIndex)].title}
/>
<div className='opa prev' onClick={galleryLeft}></div>
<div className='opa next' onClick={galleryRight}></div>
<div className="gallery-img">
<img src={gallery[parseInt(galleryIndex)].url} alt={gallery[parseInt(galleryIndex)].title} />
<div className="opa prev" onClick={galleryLeft}></div>
<div className="opa next" onClick={galleryRight}></div>
</div>
<div className='steps'>
<div className="steps">
当前 {parseInt(galleryIndex) + 1}/{gallery.length}
</div>
<div className='title'>{gallery[parseInt(galleryIndex)].title}</div>
<div className='desc'>{gallery[parseInt(galleryIndex)].desc}</div>
<div className="title">{gallery[parseInt(galleryIndex)].title}</div>
<div className="desc">{gallery[parseInt(galleryIndex)].desc}</div>
</>
) : (
<>
<div className='gallery-img noData'>画廊数据异常</div>
<div className="gallery-img noData">画廊数据异常</div>
</>
)}
</div>
)}
{isType === 'practice' && (
<div className='practice-insert-topic'>
<div className="practice-insert-topic">
{radioList.length > 0 && (
<div className='topic_style'>
<div className="topic_style">
<h3>{clacTopicText('radio')}. 单选题</h3>
<div className='practice-list'>
<div className="practice-list">
{radioList.map((item, index) => {
return (
<div className='practice-item' key={index}>
<div className="practice-item" key={index}>
<div
className='topic-choose-title'
className="topic-choose-title"
dangerouslySetInnerHTML={{
__html: `<span class="index">${index + 1}.</span>${item.titles}`,
}}
></div>
__html: `<span class="index">${index + 1}.</span>${item.titles}`
}}></div>
<div className='topic_choose-list'>
<div className="topic_choose-list">
{[1, 2, 3].includes(parseInt(item.question_style)) &&
item.question_list.map((citem, cindex) => {
return (
<div className='topic_choose-item' key={cindex}>
<div className='choose-ico'>
<i
className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}
></i>
<div className="topic_choose-item" key={cindex}>
<div className="choose-ico">
<i className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}></i>
</div>
<div
className='topic_content'
className="topic_content"
dangerouslySetInnerHTML={{
__html: `<span class="correct">${correctList[cindex]}.</span> ${citem.option}`,
}}
></div>
__html: `<span class="correct">${correctList[cindex]}.</span> ${citem.option}`
}}></div>
</div>
);
)
})}
{item.question_style === 5 && (
<div>
<Input.TextArea
disabled={true}
autoSize={{ minRows: 4, maxRows: 6 }}
/>
<Input.TextArea disabled={true} autoSize={{ minRows: 4, maxRows: 6 }} />
</div>
)}
</div>
</div>
);
)
})}
</div>
</div>
)}
{checkBoxList.length > 0 && (
<div className='topic_style'>
<div className="topic_style">
<h3>{clacTopicText('checkbox', radioList)}. 多选题</h3>
<div className='practice-list'>
<div className="practice-list">
{checkBoxList.map((item, index) => {
return (
<div className='practice-item' key={index}>
<div className="practice-item" key={index}>
<div
className='topic-choose-title'
className="topic-choose-title"
dangerouslySetInnerHTML={{
__html: `<span class="index">${index + 1}.</span>${item.titles}`,
}}
></div>
__html: `<span class="index">${index + 1}.</span>${item.titles}`
}}></div>
<div className='topic_choose-list'>
<div className="topic_choose-list">
{[1, 2, 3].includes(parseInt(item.question_style)) &&
item.question_list.map((citem, cindex) => {
return (
<div className='topic_choose-item' key={cindex}>
<div className='choose-ico'>
<i
className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}
></i>
<div className="topic_choose-item" key={cindex}>
<div className="choose-ico">
<i className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}></i>
</div>
<div
className='topic_content'
className="topic_content"
dangerouslySetInnerHTML={{
__html: `<span class="correct">${correctList[cindex]}.</span> ${citem.option}`,
}}
></div>
__html: `<span class="correct">${correctList[cindex]}.</span> ${citem.option}`
}}></div>
</div>
);
)
})}
{item.question_style === 5 && (
<div>
<Input.TextArea
disabled={true}
autoSize={{ minRows: 4, maxRows: 6 }}
/>
<Input.TextArea disabled={true} autoSize={{ minRows: 4, maxRows: 6 }} />
</div>
)}
</div>
</div>
);
)
})}
</div>
</div>
)}
{judgeList.length > 0 && (
<div className='topic_style'>
<div className="topic_style">
<h3>{clacTopicText('judge', radioList, checkBoxList)}. 判断题</h3>
<div className='practice-list'>
<div className="practice-list">
{judgeList.map((item, index) => {
return (
<div className='practice-item' key={index}>
<div className="practice-item" key={index}>
<div
className='topic-choose-title'
className="topic-choose-title"
dangerouslySetInnerHTML={{
__html: `<span class="index">${index + 1}.</span>${item.titles}`,
}}
></div>
__html: `<span class="index">${index + 1}.</span>${item.titles}`
}}></div>
<div className='topic_choose-list'>
<div className="topic_choose-list">
{[1, 2, 3].includes(parseInt(item.question_style)) &&
item.question_list.map((citem, cindex) => {
return (
<div className='topic_choose-item' key={cindex}>
<div className='choose-ico'>
<i
className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}
></i>
<div className="topic_choose-item" key={cindex}>
<div className="choose-ico">
<i className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}></i>
</div>
<div
className='topic_content'
className="topic_content"
dangerouslySetInnerHTML={{
__html: `<span class="correct">${correctList[cindex]}.</span> ${citem.option}`,
}}
></div>
__html: `<span class="correct">${correctList[cindex]}.</span> ${citem.option}`
}}></div>
</div>
);
)
})}
{item.question_style === 5 && (
<div>
<Input.TextArea
disabled={true}
autoSize={{ minRows: 4, maxRows: 6 }}
/>
<Input.TextArea disabled={true} autoSize={{ minRows: 4, maxRows: 6 }} />
</div>
)}
</div>
</div>
);
)
})}
</div>
</div>
)}
{fillList.length > 0 && (
<div className='topic_style'>
<div className="topic_style">
<h3>{clacTopicText('fill', radioList, checkBoxList, judgeList)}. 填空题</h3>
<div className='practice-list'>
<div className="practice-list">
{fillList.map((item, index) => {
return (
<div className='practice-item' key={index}>
<div className="practice-item" key={index}>
<div
className='topic-choose-title'
className="topic-choose-title"
dangerouslySetInnerHTML={{
__html: `<span class="index">${index + 1}.</span>${item.titles}`,
}}
></div>
__html: `<span class="index">${index + 1}.</span>${item.titles}`
}}></div>
<div className='topic_choose-list'>
<div className="topic_choose-list">
{[1, 2, 3].includes(parseInt(item.question_style)) &&
item.question_list.map((citem, cindex) => {
return (
<div className='topic_choose-item' key={cindex}>
<div className='choose-ico'>
<i
className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}
></i>
<div className="topic_choose-item" key={cindex}>
<div className="choose-ico">
<i className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}></i>
</div>
<div
className='topic_content'
className="topic_content"
dangerouslySetInnerHTML={{
__html: `<span class="correct">${correctList[cindex]}.</span> ${citem.option}`,
}}
></div>
__html: `<span class="correct">${correctList[cindex]}.</span> ${citem.option}`
}}></div>
</div>
);
)
})}
{item.question_style === 5 && (
<div>
<Input.TextArea
disabled={true}
autoSize={{ minRows: 4, maxRows: 6 }}
/>
<Input.TextArea disabled={true} autoSize={{ minRows: 4, maxRows: 6 }} />
</div>
)}
</div>
</div>
);
)
})}
</div>
</div>
)}
{textareaList.length > 0 && (
<div className='topic_style'>
<h3>
{clacTopicText('textarea', radioList, checkBoxList, judgeList, fillList)}.
简答题
</h3>
<div className='practice-list'>
<div className="topic_style">
<h3>{clacTopicText('textarea', radioList, checkBoxList, judgeList, fillList)}. 简答题</h3>
<div className="practice-list">
{textareaList.map((item, index) => {
return (
<div className='practice-item' key={index}>
<div className="practice-item" key={index}>
<div
className='topic-choose-title'
className="topic-choose-title"
dangerouslySetInnerHTML={{
__html: `<span class="index">${index + 1}.</span>${item.titles}`,
}}
></div>
__html: `<span class="index">${index + 1}.</span>${item.titles}`
}}></div>
<div className='topic_choose-list'>
<div className="topic_choose-list">
{[1, 2, 3].includes(parseInt(item.question_style)) &&
item.question_list.map((citem, cindex) => {
return (
<div className='topic_choose-item' key={cindex}>
<div className='choose-ico'>
<i
className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}
></i>
<div className="topic_choose-item" key={cindex}>
<div className="choose-ico">
<i className={`ico ${item.question_style === 2 ? 'checkbox' : 'radio'}`}></i>
</div>
<div
className='topic_content'
className="topic_content"
dangerouslySetInnerHTML={{
__html: `${correctList[cindex]}. ${citem.option}`,
}}
></div>
__html: `${correctList[cindex]}. ${citem.option}`
}}></div>
</div>
);
)
})}
{item.question_style === 5 && (
<div>
<Input.TextArea
disabled={true}
autoSize={{ minRows: 4, maxRows: 6 }}
/>
<Input.TextArea disabled={true} autoSize={{ minRows: 4, maxRows: 6 }} />
</div>
)}
</div>
</div>
);
)
})}
</div>
</div>
......@@ -790,33 +738,31 @@ const PreviewScreen = forwardRef((props, ref) => {
</div>
)}
{isType === 'expand' && (
<div className='expand-container'>
<div
className='expand-content'
dangerouslySetInnerHTML={{ __html: expandContent }}
></div>
<div className="expand-container">
<div className="expand-content" dangerouslySetInnerHTML={{ __html: expandContent }}></div>
</div>
)}
{isType === 'img' && (
<div className='img-preview'>
<div className="img-preview">
<Image width={430} src={previewImg} />
</div>
)}
</div>
)}
<div className='tooltip' style={toolTip.style}>
<div className="tooltip" style={toolTip.style}>
<div
className={`square ${toolTip.inSide === 'top' ? 'square_top' : toolTip.inSide === 'bottom' ? 'square_bottom' : ''}`}
style={toolTip.squareStyle}
></div>
<div className='tooltip-content-container'>
<div className='tooltip-content'>
<div className='content'>
className={`square ${
toolTip.inSide === 'top' ? 'square_top' : toolTip.inSide === 'bottom' ? 'square_bottom' : ''
}`}
style={toolTip.squareStyle}></div>
<div className="tooltip-content-container">
<div className="tooltip-content">
<div className="content">
<p>{toolTip.content}</p>
</div>
{toolTip.link && (
<div className='content-opa'>
<a href={toolTip.link} target='_blank' rel='noreferrer' className='c-link'></a>
<div className="content-opa">
<a href={toolTip.link} target="_blank" rel="noreferrer" className="c-link"></a>
{/* <a
href={`https://baike.baidu.com/item/${toolTip?.title}`}
target='_blank'
......@@ -836,14 +782,13 @@ const PreviewScreen = forwardRef((props, ref) => {
onClose={onClose}
open={open}
getContainer={false}
placement='left'
placement="left"
classNames={{ header: 'priview-drawer-header', body: 'priview-drawer-body' }}
width='300'
title='章节列表'
rootClassName='priview-drawer-container'
>
width="300"
title="章节列表"
rootClassName="priview-drawer-container">
<Tree
className='draggable-tree'
className="draggable-tree"
onSelect={handleSelect}
defaultExpandedKeys={expandedKeys}
expandedKeys={expandedKeys}
......@@ -854,7 +799,7 @@ const PreviewScreen = forwardRef((props, ref) => {
</Drawer>
{/* </Spin> */}
</div>
);
});
)
}
export default PreviewScreen;
export default forwardRef(PreviewScreen)
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
import { Form, Space, Input, Select, Button, Spin, Row, Col, Checkbox, Radio } from 'antd';
import { MinusOutlined, PlusOutlined } from '@ant-design/icons';
import { useSelector } from 'react-redux';
import { Editor, Toolbar } from '@wangeditor/editor-for-react';
import { DomEditor } from '@wangeditor/editor';
import {
questionAdd,
typeList,
questionAddType,
questionEdit,
bookNameList,
} from '@/pages/books/question-bank/request';
import { uploadFiles } from '@/utils/upload';
import QuestionEditr from '@/pages/books/question-bank/questionEditr';
import './index.less';
import dayjs from 'dayjs';
import AliOSS from 'ali-oss';
import { getAliOSSSTSToken } from '@/pages/setting/help/addedit/requet';
const CustomerTopic = forwardRef((props, ref) => {
const {
topicData,
isadd,
init,
getTypeList,
typeDate,
setShowModal,
bookNameData,
bookIdList,
typeId,
} = props;
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react'
import { Form, Space, Input, Select, Button, Spin, Row, Col, Checkbox, Radio } from 'antd'
import { MinusOutlined, PlusOutlined } from '@ant-design/icons'
import { useSelector } from 'react-redux'
import { Editor, Toolbar } from '@wangeditor/editor-for-react'
import { DomEditor } from '@wangeditor/editor'
import { questionAdd, typeList, questionAddType, questionEdit, bookNameList } from '@/pages/books/question-bank/request'
import { uploadFiles } from '@/utils/upload'
import QuestionEditr from '@/pages/books/question-bank/questionEditr'
import './index.less'
import dayjs from 'dayjs'
import AliOSS from 'ali-oss'
import { getAliOSSSTSToken } from '@/pages/setting/help/addedit/requet'
const CustomerTopic = (props, ref) => {
const { topicData, isadd, init, getTypeList, typeDate, setShowModal, bookNameData, bookIdList, typeId } = props
// oss
const [ossClient, setOssClient] = useState(null); // oss 操作
const [STSToken, setSTSToken] = useState(null); // oss 过期设置
let ossClientTemp;
const [ossClient, setOssClient] = useState(null) // oss 操作
const [STSToken, setSTSToken] = useState(null) // oss 过期设置
let ossClientTemp
const getStsAuthToken = async () => {
const data = await getAliOSSSTSToken();
const data = await getAliOSSSTSToken()
if (data) {
window.sessionStorage.setItem('sts', JSON.stringify(data));
setSTSToken(data);
window.sessionStorage.setItem('sts', JSON.stringify(data))
setSTSToken(data)
ossClientTemp = await new AliOSS({
accessKeyId: data.AccessKeyId,
accessKeySecret: data.AccessKeySecret,
......@@ -50,36 +34,36 @@ const CustomerTopic = forwardRef((props, ref) => {
timeout: 180000,
refreshSTSToken: async () => {
const info = await getAliOSSSTSToken();
const info = await getAliOSSSTSToken()
return {
AccessKeyId: info.AccessKeyId,
AccessKeySecret: info.AccessKeySecret,
SecurityToken: info.SecurityToken,
};
SecurityToken: info.SecurityToken
}
},
refreshSTSTokenInterval: 14 * 60 * 1000,
});
setOssClient(ossClientTemp);
refreshSTSTokenInterval: 14 * 60 * 1000
})
setOssClient(ossClientTemp)
}
}
};
useEffect(() => {
(async () => {
await getStsAuthToken();
})();
}, []);
;(async () => {
await getStsAuthToken()
})()
}, [])
useImperativeHandle(ref, () => {
return {};
});
return {}
})
const [form] = Form.useForm();
const questionType = Form.useWatch('question_style', form);
const [form] = Form.useForm()
const questionType = Form.useWatch('question_style', form)
// 获取操作权限
const { operationPermissionsList } = useSelector((state) => state.user);
const { operationPermissionsList } = useSelector(state => state.user)
// 题干名称的编辑器实例
const [titlesEditor, setTitlesEditor] = useState(null);
const [quesList, setQuesList] = useState([]);
const [titlesEditor, setTitlesEditor] = useState(null)
const [quesList, setQuesList] = useState([])
const [initialValues, setinitialValues] = useState({
titles: '',
type_id: null,
......@@ -87,23 +71,23 @@ const CustomerTopic = forwardRef((props, ref) => {
analysis: '',
answers: '',
question_list: [],
book_id: '',
});
book_id: ''
})
const [selectedTypeId, setSelectedTypeId] = useState([]);
const [selectedTypeId, setSelectedTypeId] = useState([])
useEffect(() => {
// console.log('typeId', typeId); //书的typeid
// console.log('props.typeDate', props.typeDate); //所有的typeid和typename
const getTypeNameById = (id) => {
const selectedType = props.typeDate.find((item) => item.id === id);
return selectedType ? selectedType.typename : '';
};
const getTypeNameById = id => {
const selectedType = props.typeDate.find(item => item.id === id)
return selectedType ? selectedType.typename : ''
}
const matchedTypename = getTypeNameById(typeId);
setSelectedTypeId(matchedTypename);
}, [props.typeDate, typeId]);
const matchedTypename = getTypeNameById(typeId)
setSelectedTypeId(matchedTypename)
}, [props.typeDate, typeId])
useEffect(() => {
let obj = {
......@@ -113,71 +97,71 @@ const CustomerTopic = forwardRef((props, ref) => {
analysis: '',
answers: '',
question_list: [],
book_id: '',
};
book_id: ''
}
if (!isadd && Object.entries(topicData)) {
obj = {
...topicData,
};
setQuestionStyle(obj.question_style);
...topicData
}
setQuestionStyle(obj.question_style)
if (topicData.question_style === 4 || topicData.question_style === 5) {
setedierVal(topicData.answers);
setedierVal(topicData.answers)
setQuesList([]);
setQuesList([])
} else {
if (topicData.question_list && topicData.question_list.length) {
try {
obj.question_list = JSON.parse(topicData.question_list);
setQuesList(JSON.parse(topicData.question_list));
obj.question_list = JSON.parse(topicData.question_list)
setQuesList(JSON.parse(topicData.question_list))
} catch (e) {
obj.question_list = [];
setQuesList([]);
obj.question_list = []
setQuesList([])
}
} else {
obj.question_list = [];
setQuesList([]);
obj.question_list = []
setQuesList([])
}
}
setinitialValues({ ...obj });
form.setFieldsValue({ ...obj });
setinitialValues({ ...obj })
form.setFieldsValue({ ...obj })
} else {
setinitialValues(obj);
form.setFieldsValue({ ...obj });
setinitialValues(obj)
form.setFieldsValue({ ...obj })
}
}, [topicData, isadd]);
}, [topicData, isadd])
// 显示不同类型的选项函数
const [edierVal, setedierVal] = useState('');
const [edierVal, setedierVal] = useState('')
// 是否显示选项
const [showList, setShowList] = useState(false);
const [formLoading, setFormLoading] = useState(false);
const [showAddClass, setShowAddClass] = useState(false);
const [addClassVal, setaddClassVal] = useState(''); // 添加分类
const [questionStyle, setQuestionStyle] = useState('');
const [showList, setShowList] = useState(false)
const [formLoading, setFormLoading] = useState(false)
const [showAddClass, setShowAddClass] = useState(false)
const [addClassVal, setaddClassVal] = useState('') // 添加分类
const [questionStyle, setQuestionStyle] = useState('')
// 分类
const sureFn = async () => {
const bool = await questionAddType({ typename: addClassVal });
const bool = await questionAddType({ typename: addClassVal })
if (bool) {
await getTypeList();
form.setFieldsValue({ type_id: bool.type_id });
setinitialValues({ ...initialValues, type_id: [bool.type_id] });
setaddClassVal('');
setShowAddClass(false);
await getTypeList()
form.setFieldsValue({ type_id: bool.type_id })
setinitialValues({ ...initialValues, type_id: [bool.type_id] })
setaddClassVal('')
setShowAddClass(false)
}
}
};
// 工具栏配置
const toolbarConfig = {};
toolbarConfig.toolbarKeys = ['uploadImage'];
const toolbarConfig = {}
toolbarConfig.toolbarKeys = ['uploadImage']
// 编辑器配置
const editorConfig = {
// JS 语法
placeholder: '请输入内容...',
hoverbarKeys: {
text: {
menuKeys: [],
},
menuKeys: []
}
},
MENU_CONF: {
// 配置默认字号
......@@ -188,156 +172,145 @@ const CustomerTopic = forwardRef((props, ref) => {
fieldName: 'image',
headers: {
'Content-Type': 'multipart/form-data',
Authorization: 'Bearer ' + localStorage.getItem('token'),
Authorization: 'Bearer ' + localStorage.getItem('token')
},
maxFileSize: 10 * 1024 * 1024, // 10M
base64LimitSize: 5 * 1024, // 5kb 以下插入 base64
customUpload: async (file, insertFn) => {
if (!ossClient) {
console.error('ossClient还未初始化', ossClient);
return false;
console.error('ossClient还未初始化', ossClient)
return false
}
const fileExt = file.name.substring(file.name.lastIndexOf('.'));
const fileName = `ad-${dayjs().valueOf()}-${Math.random().toString(36).substring(2)}${fileExt}`;
const filePath = `${dayjs().format('YYYY/MM/DD')}/${fileName}`;
const result = await ossClient.put(filePath, file);
const fileExt = file.name.substring(file.name.lastIndexOf('.'))
const fileName = `ad-${dayjs().valueOf()}-${Math.random().toString(36).substring(2)}${fileExt}`
const filePath = `${dayjs().format('YYYY/MM/DD')}/${fileName}`
const result = await ossClient.put(filePath, file)
console.log('result', result);
insertFn(result.url, '题库图片');
console.log('result', result)
insertFn(result.url, '题库图片')
// const { url } = await uploadFiles({ file, file_type: 'question' });
// insertFn(url, '题库图片');
},
},
}
}
},
customPaste: (editor, event) => {
// const html = event.clipboardData.getData('text/html') // 获取粘贴的 html
const text = event.clipboardData.getData('text/plain'); // 获取粘贴的纯文本
const text = event.clipboardData.getData('text/plain') // 获取粘贴的纯文本
// const rtf = event.clipboardData.getData('text/rtf') // 获取 rtf 数据(如从 word wsp 复制粘贴)
// 异步
setTimeout(() => {
editor.insertText(text);
}, 500);
editor.insertText(text)
}, 500)
// 阻止默认的粘贴行为
event.preventDefault();
return false;
},
};
event.preventDefault()
return false
}
}
// 及时销毁 editor ,重要!
useEffect(() => {
if (titlesEditor !== null) {
const toolbar = DomEditor.getToolbar(titlesEditor);
const toolbar = DomEditor.getToolbar(titlesEditor)
}
return () => {
if (titlesEditor === null) return;
titlesEditor.destroy();
setTitlesEditor(null);
};
}, [titlesEditor]);
const submitForm = async (obj) => {
let ilen = 0;
let obj2 = { ...obj };
if (titlesEditor === null) return
titlesEditor.destroy()
setTitlesEditor(null)
}
}, [titlesEditor])
const submitForm = async obj => {
let ilen = 0
let obj2 = { ...obj }
if ([1, 2, 3].includes(parseInt(obj.question_style))) {
obj.question_list.forEach((item, index) => {
if (item.correct && item.correct === true) {
ilen++;
ilen++
}
});
})
if ([1, 3].includes(parseInt(obj.question_style))) {
if (ilen > 1 || ilen === 0) {
form.setFields([
{
name: ['question_list', obj.question_list.length - 1, 'correct'],
errors: [
`${parseInt(obj.question_style) === 3 ? '判断题' : '单选题'}有且仅有一个正确答案!`,
],
},
]);
return false;
errors: [`${parseInt(obj.question_style) === 3 ? '判断题' : '单选题'}有且仅有一个正确答案!`]
}
])
return false
} else {
form.setFields([
{ name: ['question_list', obj.question_list.length - 1, 'correct'], errors: [''] },
]);
form.setFields([{ name: ['question_list', obj.question_list.length - 1, 'correct'], errors: [''] }])
}
} else {
if (ilen <= 1) {
form.setFields([
{
name: ['question_list', obj.question_list.length - 1, 'correct'],
errors: ['多选题需要2个及以上正确答案!'],
},
]);
return false;
errors: ['多选题需要2个及以上正确答案!']
}
])
return false
} else {
form.setFields([
{ name: ['question_list', obj.question_list.length - 1, 'correct'], errors: [''] },
]);
form.setFields([{ name: ['question_list', obj.question_list.length - 1, 'correct'], errors: [''] }])
}
}
obj2['question_list'] = JSON.stringify(quesList);
obj2['question_list'] = JSON.stringify(quesList)
} else {
obj2['answers'] = edierVal;
obj2['answers'] = edierVal
}
setShowAddClass(true);
let bool = null;
setShowAddClass(true)
let bool = null
if (isadd) {
bool = await questionAdd({
...obj2,
});
...obj2
})
} else {
bool = await questionEdit({
...obj2,
id: topicData.id,
});
id: topicData.id
})
}
setShowAddClass(false);
if (!bool) return;
setShowModal(false);
init();
};
setShowAddClass(false)
if (!bool) return
setShowModal(false)
init()
}
// 校验
const vaildaterHtml = (_, value) => {
if (value === '<p><br></p>') {
return Promise.reject('问题内容不能为空');
return Promise.reject('问题内容不能为空')
} else if (!value.trim()) {
return Promise.reject(new Error('请输入正确的内容'));
return Promise.reject(new Error('请输入正确的内容'))
} else {
return Promise.resolve();
return Promise.resolve()
}
}
};
return (
<div className='practice_customer'>
<div className="practice_customer">
<Form
form={form}
initialValues={initialValues}
onFinish={submitForm}
labelCol={{ span: 5 }}
wrapperCol={{ span: 19 }}
>
<Form.Item
name='book_id'
label='书籍名称'
rules={[{ required: true, message: '请选择书籍名称' }]}
>
wrapperCol={{ span: 19 }}>
<Form.Item name="book_id" label="书籍名称" rules={[{ required: true, message: '请选择书籍名称' }]}>
<Select
onChange={(ev) => {
setShowList(true);
onChange={ev => {
setShowList(true)
}}
style={{ width: 260 }}
placeholder='请选择书籍名称'
placeholder="请选择书籍名称"
showSearch //下拉框出现搜素,并可以输入
optionFilterProp='children' // 使搜索匹配子节点的文本内容
optionFilterProp="children" // 使搜索匹配子节点的文本内容
>
{bookIdList &&
bookIdList.length &&
......@@ -348,21 +321,16 @@ const CustomerTopic = forwardRef((props, ref) => {
))}
</Select>
</Form.Item>
<Form.Item
name='question_style'
label='题目类型'
rules={[{ required: true, message: '请选择题目类型' }]}
>
<Form.Item name="question_style" label="题目类型" rules={[{ required: true, message: '请选择题目类型' }]}>
<Select
onChange={(ev) => {
setShowList(true);
onChange={ev => {
setShowList(true)
// setinitialValues({ ...initialValues, question_style: ev });
// form.setFieldValue('question_style', ev);
setQuestionStyle(ev);
setQuestionStyle(ev)
}}
style={{ width: 260 }}
placeholder='请选择题目类型'
>
placeholder="请选择题目类型">
<Select.Option value={1}>单选题</Select.Option>
<Select.Option value={2}>多选题</Select.Option>
<Select.Option value={3}>判断题</Select.Option>
......@@ -370,26 +338,21 @@ const CustomerTopic = forwardRef((props, ref) => {
<Select.Option value={5}>简答题</Select.Option>
</Select>
</Form.Item>
<Form.Item
label='题目分类'
name='type_id'
rules={[{ required: true, message: '请选择题目分类' }]}
>
<Form.Item label="题目分类" name="type_id" rules={[{ required: true, message: '请选择题目分类' }]}>
{!showAddClass ? (
<>
<Select
onChange={(ev) => {
form.setFieldValue('type_id', ev);
onChange={ev => {
form.setFieldValue('type_id', ev)
setSelectedTypeId(ev);
setSelectedTypeId(ev)
}}
style={{ width: 220 }}
placeholder='请选择题目分类'
value={selectedTypeId}
>
placeholder="请选择题目分类"
value={selectedTypeId}>
{typeDate &&
typeDate.length &&
typeDate.map((item) => (
typeDate.map(item => (
<Select.Option key={item.id} value={item.id}>
{item.typename}
</Select.Option>
......@@ -397,12 +360,11 @@ const CustomerTopic = forwardRef((props, ref) => {
</Select>
<Button
onClick={() => {
setShowAddClass(true);
form.setFieldsValue({ type_id: '' });
setShowAddClass(true)
form.setFieldsValue({ type_id: '' })
}}
type='link'
style={{ textDecoration: 'underline', color: '#1672EC' }}
>
type="link"
style={{ textDecoration: 'underline', color: '#1672EC' }}>
添加分类
</Button>
</>
......@@ -411,23 +373,17 @@ const CustomerTopic = forwardRef((props, ref) => {
<Input
style={{ width: 200 }}
value={addClassVal}
onChange={(e) => setaddClassVal(e.target.value)}
autoComplete='off'
placeholder='请输入题目分类'
></Input>
onChange={e => setaddClassVal(e.target.value)}
autoComplete="off"
placeholder="请输入题目分类"></Input>
<Space>
<Button
onClick={sureFn}
type='link'
style={{ textDecoration: 'underline', color: '#1672EC' }}
>
<Button onClick={sureFn} type="link" style={{ textDecoration: 'underline', color: '#1672EC' }}>
添加
</Button>
<Button
type='link'
type="link"
onClick={() => setShowAddClass(false)}
style={{ textDecoration: 'underline', color: '#AA1941', marginLeft: -30 }}
>
style={{ textDecoration: 'underline', color: '#AA1941', marginLeft: -30 }}>
取消
</Button>
</Space>
......@@ -435,20 +391,19 @@ const CustomerTopic = forwardRef((props, ref) => {
)}
</Form.Item>
<Form.Item
name='titles'
label='题干名称'
name="titles"
label="题干名称"
rules={[
{ required: true, message: '请输入题干名称' },
{ validator: vaildaterHtml, validateTrigger: 'onChange' },
{ validator: vaildaterHtml, validateTrigger: 'onChange' }
]}
extra={questionType === 4 ? '请在需要填空的位置使用2个或以上的下划线进行区分!' : ''}
>
extra={questionType === 4 ? '请在需要填空的位置使用2个或以上的下划线进行区分!' : ''}>
<Spin spinning={formLoading}>
<div style={{ border: '1px solid #ccc', zIndex: 100 }}>
<Toolbar
editor={titlesEditor}
defaultConfig={toolbarConfig}
mode='default'
mode="default"
style={{ borderBottom: '1px solid #ccc' }}
/>
{ossClient && (
......@@ -456,40 +411,40 @@ const CustomerTopic = forwardRef((props, ref) => {
defaultConfig={editorConfig}
value={initialValues.titles}
onCreated={setTitlesEditor}
onChange={(editor) => {
form.setFieldValue('titles', editor.getHtml());
onChange={editor => {
form.setFieldValue('titles', editor.getHtml())
// setHtml(editor.getHtml())
}}
config={{
uploadImgServer: 'your_upload_server_address',
uploadImgServer: 'your_upload_server_address'
// other config options
}}
mode='default'
mode="default"
style={{ height: '200px', overflowY: 'hidden' }}
/>
)}
</div>
</Spin>
</Form.Item>
<Form.Item name='analysis' label='题目解析'>
<Form.Item name="analysis" label="题目解析">
<Input.TextArea
placeholder='请输入题目解析'
placeholder="请输入题目解析"
autoSize={{
minRows: 5,
maxRows: 8,
maxRows: 8
}}
name='analysis'
name="analysis"
/>
</Form.Item>
{(questionStyle === 1 || questionStyle === 2 || questionStyle === 3) && (
<Form.List name='question_list'>
<Form.List name="question_list">
{(fields, { add, remove }) => (
<Form.Item label='题目选项'>
<Form.Item label="题目选项">
{fields.map(({ key, name, ...restField }, index) => (
<Row gutter={4} key={key}>
<Col span={14} className='form_inside-out'>
<Form.Item className='inside-it'>
<Col span={14} className="form_inside-out">
<Form.Item className="inside-it">
<QuestionEditr
editorValue={quesList && quesList[index] && quesList[index].option}
quesList={quesList}
......@@ -507,18 +462,17 @@ const CustomerTopic = forwardRef((props, ref) => {
validator: (_, value) => {
if (value !== '') {
if (value === '<p><br></p>') {
return Promise.reject(new Error('请输入正确的内容'));
return Promise.reject(new Error('请输入正确的内容'))
} else {
return Promise.resolve();
return Promise.resolve()
}
} else {
return Promise.reject(new Error(''));
return Promise.reject(new Error(''))
}
}
}
},
},
]}
className='form_inside-out-none'
>
className="form_inside-out-none">
<Input.TextArea />
</Form.Item>
</Col>
......@@ -527,28 +481,26 @@ const CustomerTopic = forwardRef((props, ref) => {
<Form.Item
{...restField}
name={[name, 'correct']}
valuePropName='checked'
initialValue={restField.correct || false}
>
valuePropName="checked"
initialValue={restField.correct || false}>
<Checkbox
onChange={(e) => {
onChange={e => {
// if (quesList.length && temp[index]) {
if (quesList.length) {
let temp = JSON.parse(JSON.stringify(quesList));
let temp = JSON.parse(JSON.stringify(quesList))
if (questionStyle === 1 || questionStyle === 3) {
if (e.target.checked) {
temp.forEach((item) => {
item.correct = false;
});
temp.forEach(item => {
item.correct = false
})
}
}
temp[index].correct = e.target.checked;
setQuesList(temp);
form.setFieldValue('question_list', temp);
temp[index].correct = e.target.checked
setQuesList(temp)
form.setFieldValue('question_list', temp)
}
}}
>
}}>
正确答案
</Checkbox>
</Form.Item>
......@@ -556,45 +508,42 @@ const CustomerTopic = forwardRef((props, ref) => {
<Col span={3}>
<Button
onClick={async () => {
let temp = JSON.parse(JSON.stringify(quesList));
temp.splice(index, 1);
setQuesList(temp);
let temp = JSON.parse(JSON.stringify(quesList))
temp.splice(index, 1)
setQuesList(temp)
await remove(name);
await remove(name)
}}
icon={<MinusOutlined />}
></Button>
icon={<MinusOutlined />}></Button>
</Col>
</Row>
))}
{quesList.length < 2 && questionStyle === 3 && (
<Form.Item>
<Button
type='dashed'
type="dashed"
onClick={async () => {
let tempQuestion = JSON.parse(JSON.stringify(quesList));
tempQuestion.push({ option: '', correct: false });
setQuesList(tempQuestion);
let tempQuestion = JSON.parse(JSON.stringify(quesList))
tempQuestion.push({ option: '', correct: false })
setQuesList(tempQuestion)
await add();
await add()
}}
icon={<PlusOutlined />}
></Button>
icon={<PlusOutlined />}></Button>
</Form.Item>
)}
{[1, 2].includes(questionStyle) && (
<Form.Item>
<Button
type='dashed'
type="dashed"
onClick={async () => {
let tempQuestion = JSON.parse(JSON.stringify(quesList));
tempQuestion.push({ option: '', correct: false });
setQuesList(tempQuestion);
let tempQuestion = JSON.parse(JSON.stringify(quesList))
tempQuestion.push({ option: '', correct: false })
setQuesList(tempQuestion)
await add();
await add()
}}
icon={<PlusOutlined />}
></Button>
icon={<PlusOutlined />}></Button>
</Form.Item>
)}
</Form.Item>
......@@ -625,28 +574,23 @@ const CustomerTopic = forwardRef((props, ref) => {
</Form.Item>
)} */}
{(questionStyle === 5 || questionStyle === 4) && (
<Form.Item name='answers' label='正确答案'>
<QuestionEditr
editorValue={edierVal}
setedierVal={setedierVal}
form={form}
name='answers'
/>
<Form.Item name="answers" label="正确答案">
<QuestionEditr editorValue={edierVal} setedierVal={setedierVal} form={form} name="answers" />
</Form.Item>
)}
<Form.Item wrapperCol={{ offset: 11, span: 16 }}>
<Space size={20}>
<Button className='cancel' onClick={() => setShowModal(false)}>
<Button className="cancel" onClick={() => setShowModal(false)}>
取消
</Button>
<Button className='submit' disabled={showAddClass} htmlType='submit'>
<Button className="submit" disabled={showAddClass} htmlType="submit">
提交
</Button>
</Space>
</Form.Item>
</Form>
</div>
);
});
)
}
export default CustomerTopic;
export default forwardRef(CustomerTopic)
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论