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

chore: update

上级 17692dfa
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react'; import { useState, forwardRef, useImperativeHandle } from 'react'
import { Modal, Divider, Upload, Input, Space, Button, Form, Spin, message } from 'antd'; import { Modal, Divider, Upload, Input, Space, Button, Form, Spin, message } from 'antd'
import { CloudUploadOutlined } from '@ant-design/icons'; import { CloudUploadOutlined } from '@ant-design/icons'
import { SlateTransforms, SlateEditor, DomEditor, SlateElement } from '@wangeditor/editor'; import { SlateTransforms, SlateEditor, SlateElement } from '@wangeditor/editor'
import './index.less'; import './index.less'
import { uploadFile } from '@/utils/oss'
import { partSize, normalUploader, multipartUploader } from '../utils/upload'; const { Dragger } = Upload
const { Dragger } = Upload; const AudioModal = (props, ref) => {
const { editor } = props
const AudioModal = forwardRef((props, ref) => { const fileAccept = ['.mp3', '.wav', '.ogg']
const { editor, ossClient } = props; const [form] = Form.useForm()
const [visible, setVisible] = useState(false)
const [uploading, setUploading] = useState(false) // 文件上传状态
const [progress, setProgress] = useState(0)
const [file, setFile] = useState({})
const fileAccept = ['.mp3', '.wav', '.ogg',]; const [audioUrl, setAudioUrl] = useState('')
const [form] = Form.useForm();
const [visible, setVisible] = useState(false);
const [uploading, setUploading] = useState(false); // 文件上传状态
const [progress, setProgress] = useState(0);
const [file, setFile] = useState({});
const [fileList, setFileList] = useState([]);
const [audioUrl, setAudioUrl] = useState('');
// http://zxts-book-file.zijingebook.com/2024/02/24/audio-1708768923192-5u9t1c8t19n.mp3
useImperativeHandle(ref, () => { useImperativeHandle(ref, () => {
return { return {
setVisible, setVisible
};
});
const normFile = (e) => {
if (Array.isArray(e)) {
return e;
} }
return e?.fileList; })
};
const uploadProps = { const uploadProps = {
name: 'file', name: 'file',
maxCount: 1, maxCount: 1,
showUploadList: false, showUploadList: false,
accept: fileAccept.join(','), accept: fileAccept.join(','),
beforeUpload: (file, fileList) => { beforeUpload: file => {
const fileExt = file.name.substring(file.name.lastIndexOf('.')); const fileExt = file.name.substring(file.name.lastIndexOf('.'))
if (!fileAccept.includes(fileExt.toLowerCase())) { if (!fileAccept.includes(fileExt.toLowerCase())) {
message.error('请上传正确格式的音频文件'); message.error('请上传正确格式的音频文件')
return false; return false
} }
setProgress(0); setProgress(0)
setUploading(false); setUploading(false)
setFile(file); setFile(file)
setFileList(fileList);
}, },
customRequest: async () => { customRequest: async () => {
setUploading(true); setUploading(true)
let data = null; const url = await uploadFile(file)
if (file.size >= partSize) {
data = await multipartUploader(file, 'audio', ossClient, (progress, checkpoint) => {
console.log(`上传进度 ${progress}`);
setProgress(parseInt(progress * 100));
});
console.log('multipartUploader --> ', data);
} else {
data = await normalUploader(file, 'audio', ossClient);
console.log('normalUploader --> ', data);
}
if (data.status === 200 && data.statusCode === 200) { setAudioUrl(url)
const { url, name } = data; form.setFieldsValue({ audioUrl: url })
setAudioUrl(url); setUploading(false)
form.setFieldsValue({ audioUrl: url }); }
} }
setUploading(false);
},
};
const onFinish = (values) => { const onFinish = values => {
editor.restoreSelection(); editor.restoreSelection()
// editor.insertNode({
// type: 'chapterAudio',
// title: values.videoTitle,
// audioUrl: values.audioUrl,
// children: [{ text: '' }],
// });
const nodeEntries = SlateEditor.nodes(editor, { const nodeEntries = SlateEditor.nodes(editor, {
match: (node) => { match: node => {
// JS syntax
if (SlateElement.isElement(node)) { if (SlateElement.isElement(node)) {
if (node.type === 'paragraph') { if (node.type === 'paragraph') {
return true; // 匹配 paragraph return true // 匹配 paragraph
} }
} }
return false; return false
}, },
universal: true, universal: true
}); })
for (let nodeEntry of nodeEntries) { for (let nodeEntry of nodeEntries) {
const [node, path] = nodeEntry; const [node] = nodeEntry
if (node.children[0].text === '') { if (node.children[0].text === '') {
SlateTransforms.removeNodes(editor); SlateTransforms.removeNodes(editor)
} }
} }
...@@ -106,21 +77,21 @@ const AudioModal = forwardRef((props, ref) => { ...@@ -106,21 +77,21 @@ const AudioModal = forwardRef((props, ref) => {
src: values.audioUrl, src: values.audioUrl,
height: 60, height: 60,
width: 260, width: 260,
children: [{ text: '' }], children: [{ text: '' }]
}, },
{ {
type: 'paragraph', type: 'paragraph',
textAlign: 'center', textAlign: 'center',
children: [{ text: values.videoTitle }], children: [{ text: values.videoTitle }]
}, }
]; ]
SlateTransforms.insertNodes(editor, nodes); SlateTransforms.insertNodes(editor, nodes)
setAudioUrl(''); setAudioUrl('')
setProgress(0); setProgress(0)
setUploading(false); setUploading(false)
form.resetFields(); form.resetFields()
setVisible(false); setVisible(false)
}; }
return ( return (
<div> <div>
...@@ -129,58 +100,38 @@ const AudioModal = forwardRef((props, ref) => { ...@@ -129,58 +100,38 @@ const AudioModal = forwardRef((props, ref) => {
footer={null} footer={null}
centered centered
destroyOnClose destroyOnClose
title='插入音频' title="插入音频"
classNames={{ classNames={{
header: 'editor-header-customer', header: 'editor-header-customer',
body: 'editor-body-customer', body: 'editor-body-customer',
wrapper: 'editor-wrapper-customer', wrapper: 'editor-wrapper-customer'
}} }}
maskClosable={false} maskClosable={false}
onCancel={() => setVisible(false)} onCancel={() => setVisible(false)}>
>
<Divider /> <Divider />
<div className='editor-content-form'> <div className="editor-content-form">
<Form <Form layout="vertical" name="validate_other" form={form} onFinish={onFinish} initialValues={{ audioUrl: audioUrl, videoTitle: '' }}>
layout='vertical' <Form.Item label="上传音频" name="audioUrl">
name='validate_other'
form={form}
onFinish={onFinish}
initialValues={{ audioUrl: audioUrl, videoTitle: '' }}
>
<Form.Item
label='上传音频'
valuePropName='fileList'
name='audioUrl'
getValueFromEvent={normFile}
// rules={[{ required: true, message: '请上传音频' }]}
>
<Spin spinning={uploading} tip={`${progress}%`}> <Spin spinning={uploading} tip={`${progress}%`}>
<div className='editor-dragger'> <div className="editor-dragger">
<Dragger {...uploadProps} showUploadList={false}> <Dragger {...uploadProps} showUploadList={false}>
{!audioUrl && ( {!audioUrl && (
<div className='editor-uploader-process'> <div className="editor-uploader-process">
<p className='ant-upload-drag-icon'> <p className="ant-upload-drag-icon">
<CloudUploadOutlined style={{ fontSize: 40 }} /> <CloudUploadOutlined style={{ fontSize: 40 }} />
</p> </p>
<p className='ant-upload-text'>点击上传或拖拽到此处上传</p> <p className="ant-upload-text">点击上传或拖拽到此处上传</p>
<p className='ant-upload-hint'> <p className="ant-upload-hint">支持上传 .mp3、.wav、.ogg 格式的文件</p>
支持上传 .mp3、.wav、.ogg 格式的文件
</p>
</div> </div>
)} )}
{audioUrl && ( {audioUrl && (
<> <>
<div className='editor-uploader-result'> <div className="editor-uploader-result">
<div className='editor-uploader-result-img'> <div className="editor-uploader-result-img">
<audio src={audioUrl} controls height='50' width='100'></audio> <audio src={audioUrl} controls height="50" width="100"></audio>
</div> </div>
<div className='editor-uploader-result-tips'> <div className="editor-uploader-result-tips">
<Button <Button size="small" type="primary" ghost onClick={() => setAudioUrl(null)}>
size='small'
type='primary'
ghost
onClick={() => setAudioUrl(null)}
>
替换 替换
</Button> </Button>
</div> </div>
...@@ -191,20 +142,15 @@ const AudioModal = forwardRef((props, ref) => { ...@@ -191,20 +142,15 @@ const AudioModal = forwardRef((props, ref) => {
</div> </div>
</Spin> </Spin>
</Form.Item> </Form.Item>
<Form.Item <Form.Item label="音频标题" name="videoTitle" rules={[{ required: true, message: '请输入图片标题' }]} extra="最多输入100字">
label='音频标题' <Input maxLength={100} placeholder="" allowClear />
name='videoTitle'
rules={[{ required: true, message: '请输入图片标题' }]}
extra='最多输入100字'
>
<Input maxLength={100} placeholder='' allowClear />
</Form.Item> </Form.Item>
<Form.Item className='editor-form-buttons'> <Form.Item className="editor-form-buttons">
<Space> <Space>
<Button type='default' disabled={uploading} onClick={() => setVisible(false)}> <Button type="default" disabled={uploading} onClick={() => setVisible(false)}>
取消 取消
</Button> </Button>
<Button type='primary' disabled={uploading} htmlType='submit'> <Button type="primary" disabled={uploading} htmlType="submit">
插入 插入
</Button> </Button>
</Space> </Space>
...@@ -213,7 +159,7 @@ const AudioModal = forwardRef((props, ref) => { ...@@ -213,7 +159,7 @@ const AudioModal = forwardRef((props, ref) => {
</div> </div>
</Modal> </Modal>
</div> </div>
); )
}); }
export default AudioModal; export default forwardRef(AudioModal)
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react' import { useState, useEffect, forwardRef } from 'react'
import { Modal, Divider, Upload, Input, Space, Button, Form, Spin, message, ColorPicker, Select, InputNumber, Row, Col } from 'antd' import { Divider, Input, Space, Button, Form, ColorPicker, Select, InputNumber, Row, Col } from 'antd'
import { DomEditor, SlateEditor, SlateTransforms, SlateElement } from '@wangeditor/editor' import { SlateEditor, SlateTransforms, SlateElement } from '@wangeditor/editor'
import { fontFamilyList, fontSizeList } from '../utils/setting' import { fontFamilyList, fontSizeList } from '../utils/setting'
import $ from 'jquery'
import './index.less' import './index.less'
const ChapterItemModal = forwardRef((props, ref) => { const ChapterItemModal = (props, ref) => {
const { editor, setSectionInfo, sectionInfo, setSectionVisible } = props const { editor, setSectionInfo, sectionInfo, setSectionVisible } = props
const [form] = Form.useForm() const [form] = Form.useForm()
const [visible, setVisible] = useState(false)
// 是否更新的判断 // 是否更新的判断
const [toolStatus, setToolStatus] = useState(false)
const [bgColorValue, setBgColorValue] = useState('#000000') const [bgColorValue, setBgColorValue] = useState('#000000')
const [textColor, setTextColor] = useState('#ffffff') const [textColor, setTextColor] = useState('#ffffff')
const [nowRandom, setNowRandom] = useState(null) const [nowRandom, setNowRandom] = useState(null)
...@@ -25,12 +22,6 @@ const ChapterItemModal = forwardRef((props, ref) => { ...@@ -25,12 +22,6 @@ const ChapterItemModal = forwardRef((props, ref) => {
family: '黑体' family: '黑体'
}) })
useImperativeHandle(ref, () => {
return {
setVisible
}
})
useEffect(() => { useEffect(() => {
if (sectionInfo && Object.entries(sectionInfo).length > 0) { if (sectionInfo && Object.entries(sectionInfo).length > 0) {
setInitValues({ ...sectionInfo }) setInitValues({ ...sectionInfo })
...@@ -60,24 +51,9 @@ const ChapterItemModal = forwardRef((props, ref) => { ...@@ -60,24 +51,9 @@ const ChapterItemModal = forwardRef((props, ref) => {
height: height, height: height,
size: size size: size
}) })
setToolStatus(true)
setNowRandom(random) setNowRandom(random)
} }
// 获取当前节点的上一个节点
function getPreviousNode(editor) {
const { selection } = editor
if (!selection) return null
const [start] = SlateEditor.nodes(editor, { at: selection })
const previous = SlateEditor.previous(editor, { at: start[1] })
if (previous) {
return previous
}
return null
}
const onFinish = values => { const onFinish = values => {
editor.restoreSelection() editor.restoreSelection()
const nodeEntries = SlateEditor.nodes(editor, { const nodeEntries = SlateEditor.nodes(editor, {
...@@ -129,11 +105,7 @@ const ChapterItemModal = forwardRef((props, ref) => { ...@@ -129,11 +105,7 @@ const ChapterItemModal = forwardRef((props, ref) => {
return return
} }
const html = editor.getHtml()
const parser = new DOMParser()
let random = Math.random().toString(10).substring(2, 10) let random = Math.random().toString(10).substring(2, 10)
const docBody = parser.parseFromString(html, 'text/html')
const section = docBody.body.querySelectorAll('.chapter-item-section') // 节头标签
editor.insertNode({ editor.insertNode({
type: 'chapterSection', type: 'chapterSection',
...@@ -217,14 +189,6 @@ const ChapterItemModal = forwardRef((props, ref) => { ...@@ -217,14 +189,6 @@ const ChapterItemModal = forwardRef((props, ref) => {
})} })}
</Select> </Select>
</Form.Item> </Form.Item>
{/* <InputNumber
controls={false}
min={10}
placeholder=''
style={{ width: '100%', textAlign: 'left' }}
allowClear
/> */}
</Col> </Col>
<Col span={12}> <Col span={12}>
<Form.Item label="对齐方式" name="align" rules={[{ required: true, message: '请选择对齐方式' }]}> <Form.Item label="对齐方式" name="align" rules={[{ required: true, message: '请选择对齐方式' }]}>
...@@ -257,6 +221,6 @@ const ChapterItemModal = forwardRef((props, ref) => { ...@@ -257,6 +221,6 @@ const ChapterItemModal = forwardRef((props, ref) => {
</div> </div>
</div> </div>
) )
}) }
export default ChapterItemModal export default forwardRef(ChapterItemModal)
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react' import { useState, useEffect, forwardRef, useImperativeHandle } from 'react'
import { Modal, Divider, Upload, Input, Space, Button, Form, Spin, message, ColorPicker, Select, InputNumber, Row, Col } from 'antd' import { Divider, Upload, Input, Space, Button, Form, Spin, message, ColorPicker, Select, InputNumber, Row, Col } from 'antd'
import { CloudUploadOutlined } from '@ant-design/icons' import { CloudUploadOutlined } from '@ant-design/icons'
import { DomEditor, SlateEditor, SlateTransforms, SlateElement } from '@wangeditor/editor' import { SlateEditor, SlateTransforms, SlateElement } from '@wangeditor/editor'
import { fontFamilyList, fontSizeList } from '../utils/setting' import { fontFamilyList, fontSizeList } from '../utils/setting'
import './index.less' import './index.less'
import $ from 'jquery'
import { partSize, normalUploader, multipartUploader } from '../utils/upload' import { uploadFile } from '@/utils/oss'
const { Dragger } = Upload const { Dragger } = Upload
const imgUrl2 = 'http://zxts-book-file.zijingebook.com/2024/03/05/image-1709606013683-6k5qmzf75zj.png' const ImageModal = (props, ref) => {
const { editor, setTitleVisible, titleInfo, setTitleInfo } = props
const ImageModal = forwardRef((props, ref) => {
const { editor, ossClient, setTitleVisible, titleInfo, setTitleInfo } = props
const fileAccept = ['.png', '.jpg', '.jpeg', '.svg'] const fileAccept = ['.png', '.jpg', '.jpeg', '.svg']
const [form] = Form.useForm() const [form] = Form.useForm()
...@@ -22,7 +19,6 @@ const ImageModal = forwardRef((props, ref) => { ...@@ -22,7 +19,6 @@ const ImageModal = forwardRef((props, ref) => {
const [uploading, setUploading] = useState(false) // 文件上传状态 const [uploading, setUploading] = useState(false) // 文件上传状态
const [progress, setProgress] = useState(0) const [progress, setProgress] = useState(0)
const [file, setFile] = useState({}) const [file, setFile] = useState({})
const [fileList, setFileList] = useState([])
const [imgUrl, setImgUrl] = useState('') const [imgUrl, setImgUrl] = useState('')
const [initValues, setInitValues] = useState({ const [initValues, setInitValues] = useState({
title: '', title: '',
...@@ -81,45 +77,25 @@ const ImageModal = forwardRef((props, ref) => { ...@@ -81,45 +77,25 @@ const ImageModal = forwardRef((props, ref) => {
setNowRandom(random) setNowRandom(random)
} }
const normFile = e => {
if (Array.isArray(e)) {
return e
}
return e?.fileList
}
const uploadProps = { const uploadProps = {
name: 'file', name: 'file',
maxCount: 1, maxCount: 1,
showUploadList: false, showUploadList: false,
accept: fileAccept.join(','), accept: fileAccept.join(','),
beforeUpload: (file, fileList) => { beforeUpload: file => {
const fileExt = file.name.substring(file.name.lastIndexOf('.')) const fileExt = file.name.substring(file.name.lastIndexOf('.'))
if (!fileAccept.includes(fileExt.toLowerCase())) { if (!fileAccept.includes(fileExt.toLowerCase())) {
message.error('请上传正确格式的图片') message.error('请上传正确格式的图片')
return false return false
} }
setFile(file) setFile(file)
setFileList(fileList)
}, },
customRequest: async () => { customRequest: async () => {
setUploading(true) setUploading(true)
let data = null const url = await uploadFile(file)
if (file.size >= partSize) {
data = await multipartUploader(file, 'image', ossClient, (progress, checkpoint) => {
console.log(`上传进度 ${progress}`)
setProgress(parseInt(progress * 100))
})
console.log('multipartUploader --> ', data)
} else {
data = await normalUploader(file, 'image', ossClient)
console.log('normalUploader --> ', data)
}
if (data.status === 200 && data.statusCode === 200) {
const { url, name } = data
setImgUrl(url) setImgUrl(url)
form.setFieldsValue({ bgImgUrl: url }) form.setFieldsValue({ bgImgUrl: url })
}
setUploading(false) setUploading(false)
} }
} }
...@@ -139,7 +115,7 @@ const ImageModal = forwardRef((props, ref) => { ...@@ -139,7 +115,7 @@ const ImageModal = forwardRef((props, ref) => {
universal: true universal: true
}) })
for (let nodeEntry of nodeEntries) { for (let nodeEntry of nodeEntries) {
const [node, path] = nodeEntry const [node] = nodeEntry
if (node.children[0].text === '') { if (node.children[0].text === '') {
SlateTransforms.removeNodes(editor) SlateTransforms.removeNodes(editor)
} }
...@@ -211,7 +187,7 @@ const ImageModal = forwardRef((props, ref) => { ...@@ -211,7 +187,7 @@ const ImageModal = forwardRef((props, ref) => {
<Divider /> <Divider />
<div className="editor-content-form"> <div className="editor-content-form">
<Form layout="vertical" name="validate_other" form={form} onFinish={onFinish} initialValues={initValues}> <Form layout="vertical" name="validate_other" form={form} onFinish={onFinish} initialValues={initValues}>
<Form.Item label="章头背景图片" valuePropName="fileList" getValueFromEvent={normFile} name="bgImgUrl"> <Form.Item label="章头背景图片" name="bgImgUrl">
<Spin spinning={uploading} tip={`${progress}%`}> <Spin spinning={uploading} tip={`${progress}%`}>
<div className="editor-dragger"> <div className="editor-dragger">
<Dragger {...uploadProps} showUploadList={false}> <Dragger {...uploadProps} showUploadList={false}>
...@@ -351,6 +327,6 @@ const ImageModal = forwardRef((props, ref) => { ...@@ -351,6 +327,6 @@ const ImageModal = forwardRef((props, ref) => {
</div> </div>
</div> </div>
) )
}) }
export default ImageModal export default forwardRef(ImageModal)
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react'; import { useState, useEffect, forwardRef, useImperativeHandle } from 'react'
import { Modal, Divider, Space, Button, message } from 'antd'; import { Modal, Divider, Space, Button, message } from 'antd'
import { SlateTransforms, SlateEditor, DomEditor, SlateElement } from '@wangeditor/editor';
// import formulaEditor from 'easy-formula-editor'; // import formulaEditor from 'easy-formula-editor';
import './index.less'; import './index.less'
const FormulaModal = forwardRef((props, ref) => { const FormulaModal = (props, ref) => {
const { editor, ossClient } = props; const { editor } = props
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false)
const [editor2, setEditor2] = useState(null); const [editor2, setEditor2] = useState(null)
useImperativeHandle(ref, () => { useImperativeHandle(ref, () => {
return { return {
setVisible, setVisible
}; }
}); })
useEffect(() => { useEffect(() => {
if (visible) { if (visible) {
setTimeout(() => { setTimeout(() => {
const editor2 = new formulaEditor(); const editor2 = new formulaEditor()
// 增加预设公式 // 增加预设公式
// editor2.menusConfig.presets.push({ label: '勾股定理', value: 'a^2+b^2=c^2' }); // editor2.menusConfig.presets.push({ label: '勾股定理', value: 'a^2+b^2=c^2' });
editor2.config.width = '900px'; editor2.config.width = '900px'
editor2.create('#test'); editor2.create('#test')
setEditor2(editor2); setEditor2(editor2)
}, 500); }, 500)
} else { } else {
editor2 && editor2.destoryDom(); editor2 && editor2.destoryDom()
} }
}, [visible]); }, [visible])
const insertFormula = () => { const insertFormula = () => {
editor.restoreSelection(); editor.restoreSelection()
// latex 公式 // latex 公式
// console.log(editor2.latex.text()); // console.log(editor2.latex.text());
// html 公式 // html 公式
// console.log(editor2.$textSvgElem.html()); // console.log(editor2.$textSvgElem.html());
const html = editor2.$textSvgElem.html(); const html = editor2.$textSvgElem.html()
if (html) { if (html) {
// editor // editor
editor.insertNode({ editor.insertNode({
type: 'chapterFormula', type: 'chapterFormula',
formulaHtml: html, formulaHtml: html,
children: [{ text: '' }], children: [{ text: '' }]
}); })
setVisible(false); setVisible(false)
} else { } else {
message.error('请选择公式内容!'); message.error('请选择公式内容!')
}
} }
};
return ( return (
<div> <div>
...@@ -58,33 +57,32 @@ const FormulaModal = forwardRef((props, ref) => { ...@@ -58,33 +57,32 @@ const FormulaModal = forwardRef((props, ref) => {
footer={null} footer={null}
centered centered
destroyOnClose destroyOnClose
title='公式' title="公式"
classNames={{ classNames={{
header: 'editor-header-customer', header: 'editor-header-customer',
body: 'editor-body-customer', body: 'editor-body-customer',
wrapper: 'editor-wrapper-customer', wrapper: 'editor-wrapper-customer'
}} }}
maskClosable={false} maskClosable={false}
onCancel={() => setVisible(false)} onCancel={() => setVisible(false)}
width='900px' width="900px">
>
<Divider /> <Divider />
<div className='formula-container'> <div className="formula-container">
<div id='test'></div> <div id="test"></div>
</div> </div>
<div className='formula-buttons'> <div className="formula-buttons">
<Space> <Space>
<Button type='default' onClick={() => setVisible(false)}> <Button type="default" onClick={() => setVisible(false)}>
取消 取消
</Button> </Button>
<Button type='primary' onClick={insertFormula}> <Button type="primary" onClick={insertFormula}>
插入公式 插入公式
</Button> </Button>
</Space> </Space>
</div> </div>
</Modal> </Modal>
</div> </div>
); )
}); }
export default FormulaModal; export default forwardRef(FormulaModal)
...@@ -9,7 +9,7 @@ import GalleryFormItem from './galleryItem' ...@@ -9,7 +9,7 @@ import GalleryFormItem from './galleryItem'
const randomOne = Math.random().toString(16).substring(2, 10) const randomOne = Math.random().toString(16).substring(2, 10)
const GalleryModal = props => { const GalleryModal = props => {
const { editor, ossClient, galleryInfo, bookId, chapterId, setGalleryVisible, setGalleryInfo, selectionSize = 18, isOnline = false } = props const { editor, galleryInfo, bookId, chapterId, setGalleryVisible, setGalleryInfo, selectionSize = 18, isOnline = false } = props
const [form] = Form.useForm() const [form] = Form.useForm()
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
...@@ -47,9 +47,7 @@ const GalleryModal = props => { ...@@ -47,9 +47,7 @@ const GalleryModal = props => {
const initialItems = [ const initialItems = [
{ {
label: '图 1', label: '图 1',
children: ( children: <GalleryFormItem form={form} galleryInfo={galleryInfo} activeKey={randomOne} setPicList={setPicList} isOnline={isOnline} />,
<GalleryFormItem ossClient={ossClient} form={form} galleryInfo={galleryInfo} activeKey={randomOne} setPicList={setPicList} isOnline={isOnline} />
),
key: randomOne, key: randomOne,
forceRender: true forceRender: true
} }
...@@ -68,9 +66,7 @@ const GalleryModal = props => { ...@@ -68,9 +66,7 @@ const GalleryModal = props => {
const newActiveKey = `${random}` const newActiveKey = `${random}`
newPanes.push({ newPanes.push({
label: `图 ${index + 1}`, label: `图 ${index + 1}`,
children: ( children: <GalleryFormItem form={form} galleryInfo={galleryInfo} activeKey={newActiveKey} setPicList={setPicList} isOnline={isOnline} />,
<GalleryFormItem ossClient={ossClient} form={form} galleryInfo={galleryInfo} activeKey={newActiveKey} setPicList={setPicList} isOnline={isOnline} />
),
key: newActiveKey, key: newActiveKey,
forceRender: true forceRender: true
}) })
...@@ -163,7 +159,6 @@ const GalleryModal = props => { ...@@ -163,7 +159,6 @@ const GalleryModal = props => {
label: `图 ${index + 1}`, label: `图 ${index + 1}`,
children: ( children: (
<GalleryFormItem <GalleryFormItem
ossClient={ossClient}
galleryInfo={{ ...galleryInfo, galleryList: encodeURI(JSON.stringify(galleryArr)) }} galleryInfo={{ ...galleryInfo, galleryList: encodeURI(JSON.stringify(galleryArr)) }}
form={form} form={form}
setPicList={setPicList} setPicList={setPicList}
......
import { useState, useEffect, useImperativeHandle, forwardRef } from 'react' import { useState, useEffect, useImperativeHandle, forwardRef } from 'react'
import { CloudUploadOutlined } from '@ant-design/icons' import { CloudUploadOutlined } from '@ant-design/icons'
import { Form, Input, Spin, Upload, Button } from 'antd' import { Form, Input, Spin, Upload, Button } from 'antd'
import { partSize, normalUploader, multipartUploader } from '../utils/upload'
import OnlineImageList from './onlineImageList' import OnlineImageList from './onlineImageList'
import { uploadFile } from '@/utils/oss'
const fileAccept = ['.png', '.jpg', '.jpeg', '.svg'] const fileAccept = ['.png', '.jpg', '.jpeg', '.svg']
const randomOne = Math.random().toString(16).substring(2, 10) const randomOne = Math.random().toString(16).substring(2, 10)
const GalleryFormItem = (props, ref) => { const GalleryFormItem = (props, ref) => {
const { activeKey, ossClient, form, setPicList, galleryInfo, isOnline = false } = props const { activeKey, form, setPicList, galleryInfo, isOnline = false } = props
const [uploading, setUploading] = useState(false) // 文件上传状态 const [uploading, setUploading] = useState(false) // 文件上传状态
const [progress, setProgress] = useState(0)
const [file, setFile] = useState({}) const [file, setFile] = useState({})
const [fileList, setFileList] = useState([])
const [imgUrl, setImgUrl] = useState('') const [imgUrl, setImgUrl] = useState('')
useImperativeHandle(ref, () => { useImperativeHandle(ref, () => {
...@@ -36,7 +34,7 @@ const GalleryFormItem = (props, ref) => { ...@@ -36,7 +34,7 @@ const GalleryFormItem = (props, ref) => {
if (galleryArr.length > 0) { if (galleryArr.length > 0) {
const values = { ['content']: {} } const values = { ['content']: {} }
galleryArr.forEach((item) => { galleryArr.forEach(item => {
values['content'][item.key] = { values['content'][item.key] = {
url: item.url, url: item.url,
title: item.title, title: item.title,
...@@ -45,7 +43,7 @@ const GalleryFormItem = (props, ref) => { ...@@ -45,7 +43,7 @@ const GalleryFormItem = (props, ref) => {
}) })
form.setFieldsValue({ ...values, gallery: galleryArr }) form.setFieldsValue({ ...values, gallery: galleryArr })
const item = galleryArr.filter((item) => item.key === activeKey) const item = galleryArr.filter(item => item.key === activeKey)
if (item.length > 0) { if (item.length > 0) {
const itemGallery = item[0] const itemGallery = item[0]
setImgUrl(itemGallery.url) setImgUrl(itemGallery.url)
...@@ -56,44 +54,17 @@ const GalleryFormItem = (props, ref) => { ...@@ -56,44 +54,17 @@ const GalleryFormItem = (props, ref) => {
useEffect(() => {}, []) useEffect(() => {}, [])
const normFile = (e) => {
if (Array.isArray(e)) {
return e
}
return e?.fileList
}
const uploadProps = { const uploadProps = {
name: 'file', name: 'file',
maxCount: 1, maxCount: 1,
showUploadList: false, showUploadList: false,
accept: fileAccept.join(','), accept: fileAccept.join(','),
beforeUpload: (file, fileList) => { beforeUpload: file => {
const fileExt = file.name.substring(file.name.lastIndexOf('.'))
if (!fileAccept.includes(fileExt.toLowerCase())) {
message.error('请上传正确格式的图片')
return false
}
setFile(file) setFile(file)
setFileList(fileList)
}, },
customRequest: async () => { customRequest: async () => {
setUploading(true) setUploading(true)
let data = null const url = await uploadFile(file)
if (file.size >= partSize) {
data = await multipartUploader(file, 'gallery', ossClient, (progress, checkpoint) => {
console.log(`上传进度 ${progress}`)
setProgress(parseInt(progress * 100))
})
console.log('multipartUploader --> ', data)
} else {
data = await normalUploader(file, 'gallery', ossClient)
console.log('normalUploader --> ', data)
}
if (data.status === 200 && data.statusCode === 200) {
const { url, name } = data
const filename = file.name.substring(0, file.name.lastIndexOf('.'))
const values = { const values = {
['content']: { ['content']: {
[activeKey]: { [activeKey]: {
...@@ -113,12 +84,11 @@ const GalleryFormItem = (props, ref) => { ...@@ -113,12 +84,11 @@ const GalleryFormItem = (props, ref) => {
} }
setPicList(newGalleryList) setPicList(newGalleryList)
form.setFieldsValue({ gallery: newGalleryList }) form.setFieldsValue({ gallery: newGalleryList })
}
setUploading(false) setUploading(false)
} }
} }
const changeTitleValue = (e) => { const changeTitleValue = e => {
const allContent = form.getFieldValue('content') const allContent = form.getFieldValue('content')
const newGalleryList = [] const newGalleryList = []
// eslint-disable-next-line guard-for-in // eslint-disable-next-line guard-for-in
...@@ -128,7 +98,7 @@ const GalleryFormItem = (props, ref) => { ...@@ -128,7 +98,7 @@ const GalleryFormItem = (props, ref) => {
setPicList(newGalleryList) setPicList(newGalleryList)
form.setFieldsValue({ gallery: newGalleryList }) form.setFieldsValue({ gallery: newGalleryList })
} }
const changeDescValue = (e) => { const changeDescValue = e => {
const allContent = form.getFieldValue('content') const allContent = form.getFieldValue('content')
const newGalleryList = [] const newGalleryList = []
// eslint-disable-next-line guard-for-in // eslint-disable-next-line guard-for-in
...@@ -139,7 +109,7 @@ const GalleryFormItem = (props, ref) => { ...@@ -139,7 +109,7 @@ const GalleryFormItem = (props, ref) => {
form.setFieldsValue({ gallery: newGalleryList }) form.setFieldsValue({ gallery: newGalleryList })
} }
const onOnlineImageChange = (url) => { const onOnlineImageChange = url => {
setImgUrl(url) setImgUrl(url)
const values = { const values = {
['content']: { ['content']: {
...@@ -165,23 +135,11 @@ const GalleryFormItem = (props, ref) => { ...@@ -165,23 +135,11 @@ const GalleryFormItem = (props, ref) => {
return ( return (
<> <>
{isOnline ? ( {isOnline ? (
<Form.Item <Form.Item label="在线图片" extra="最多可上传10张" name={['content', activeKey, 'url']} rules={[{ required: true, message: '请选择图片' }]}>
label="在线图片"
valuePropName="fileList"
getValueFromEvent={normFile}
extra="最多可上传10张"
name={['content', activeKey, 'url']}
rules={[{ required: true, message: '请选择图片' }]}>
<OnlineImageList imgUrl={imgUrl} onChange={onOnlineImageChange}></OnlineImageList> <OnlineImageList imgUrl={imgUrl} onChange={onOnlineImageChange}></OnlineImageList>
</Form.Item> </Form.Item>
) : ( ) : (
<Form.Item <Form.Item label="上传图片" extra="最多可上传10张" name={['content', activeKey, 'url']} rules={[{ required: true, message: '请上传画廊图片' }]}>
label="上传图片"
valuePropName="fileList"
getValueFromEvent={normFile}
extra="最多可上传10张"
name={['content', activeKey, 'url']}
rules={[{ required: true, message: '请上传画廊图片' }]}>
<Spin spinning={uploading} tip="Loading"> <Spin spinning={uploading} tip="Loading">
<div className="editor-dragger"> <div className="editor-dragger">
<Upload.Dragger {...uploadProps} showUploadList={false}> <Upload.Dragger {...uploadProps} showUploadList={false}>
......
...@@ -5,12 +5,12 @@ import { SlateTransforms, SlateEditor, SlateElement } from '@wangeditor/editor' ...@@ -5,12 +5,12 @@ import { SlateTransforms, SlateEditor, SlateElement } from '@wangeditor/editor'
import './index.less' import './index.less'
import OnlineImageList from './onlineImageList' import OnlineImageList from './onlineImageList'
import { partSize, normalUploader, multipartUploader } from '../utils/upload' import { uploadFile } from '@/utils/oss'
const { Dragger } = Upload const { Dragger } = Upload
const ImageModal = (props, ref) => { const ImageModal = (props, ref) => {
const { editor, ossClient, setImageVisible, imageInfo, setImageInfo, isOnline = false } = props const { editor, setImageVisible, imageInfo, setImageInfo, isOnline = false } = props
const [imgUrl, setImgUrl] = useState('') const [imgUrl, setImgUrl] = useState('')
const fileAccept = ['.png', '.jpg', '.jpeg', '.svg'] const fileAccept = ['.png', '.jpg', '.jpeg', '.svg']
...@@ -18,62 +18,39 @@ const ImageModal = (props, ref) => { ...@@ -18,62 +18,39 @@ const ImageModal = (props, ref) => {
const [uploading, setUploading] = useState(false) // 文件上传状态 const [uploading, setUploading] = useState(false) // 文件上传状态
const [progress, setProgress] = useState(0) const [progress, setProgress] = useState(0)
const [file, setFile] = useState({}) const [file, setFile] = useState({})
const [fileList, setFileList] = useState([])
const [initValues, setInitValues] = useState({ imgUrl: '', imgTitle: '', imgDescript: '' }) const [initValues, setInitValues] = useState({ imgUrl: '', imgTitle: '', imgDescript: '' })
const [tempNodeInfo, setTempNodeInfo] = useState(null) const [tempNodeInfo, setTempNodeInfo] = useState(null)
useEffect(() => { useEffect(() => {
if (imageInfo && Object.entries(imageInfo).length > 0) { if (imageInfo && Object.entries(imageInfo).length > 0) {
const { image, node } = imageInfo const { image } = imageInfo
setImgUrl(image.src) setImgUrl(image.src)
setInitValues({ imgUrl: image.src, imgTitle: image.alt, imgDescript: image.href }) setInitValues({ imgUrl: image.src, imgTitle: image.alt, imgDescript: image.href })
form.setFieldsValue({ imgUrl: image.src, imgTitle: image.alt, imgDescript: image.href }) form.setFieldsValue({ imgUrl: image.src, imgTitle: image.alt, imgDescript: image.href })
setTempNodeInfo(imageInfo) setTempNodeInfo(imageInfo)
setFile({}) setFile({})
setFileList([])
setImageInfo({}) setImageInfo({})
} }
}, [imageInfo]) }, [imageInfo])
const normFile = (e) => {
if (Array.isArray(e)) {
return e
}
return e?.fileList
}
const uploadProps = { const uploadProps = {
name: 'file', name: 'file',
maxCount: 1, maxCount: 1,
showUploadList: false, showUploadList: false,
accept: fileAccept.join(','), accept: fileAccept.join(','),
beforeUpload: (file, fileList) => { beforeUpload: file => {
const fileExt = file.name.substring(file.name.lastIndexOf('.')) const fileExt = file.name.substring(file.name.lastIndexOf('.'))
if (!fileAccept.includes(fileExt.toLowerCase())) { if (!fileAccept.includes(fileExt.toLowerCase())) {
message.error('请上传正确格式的图片') message.error('请上传正确格式的图片')
return false return false
} }
setFile(file) setFile(file)
setFileList(fileList)
}, },
customRequest: async () => { customRequest: async () => {
setUploading(true) setUploading(true)
let data = null const url = await uploadFile(file)
if (file.size >= partSize) {
data = await multipartUploader(file, 'image', ossClient, (progress, checkpoint) => {
console.log(`上传进度 ${progress}`)
setProgress(parseInt(progress * 100))
})
console.log('multipartUploader --> ', data)
} else {
data = await normalUploader(file, 'image', ossClient)
console.log('normalUploader --> ', data)
}
if (data.status === 200 && data.statusCode === 200) {
const { url, name } = data
setImgUrl(url) setImgUrl(url)
form.setFieldsValue({ imgUrl: url }) form.setFieldsValue({ imgUrl: url })
}
setUploading(false) setUploading(false)
} }
} }
...@@ -88,19 +65,12 @@ const ImageModal = (props, ref) => { ...@@ -88,19 +65,12 @@ const ImageModal = (props, ref) => {
setImageVisible(false) setImageVisible(false)
} }
const onFinish = (values) => { const onFinish = values => {
console.log(values) console.log(values)
editor.restoreSelection() editor.restoreSelection()
// editor.insertNode({
// type: 'chapterImage',
// title: values.imgTitle,
// imgUrl: values.imgUrl,
// imgDescript: values.imgDescript,
// children: [{ text: '' }],
// });
const nodeEntries = SlateEditor.nodes(editor, { const nodeEntries = SlateEditor.nodes(editor, {
match: (node) => { match: node => {
// JS syntax // JS syntax
if (SlateElement.isElement(node)) { if (SlateElement.isElement(node)) {
if (node.type === 'paragraph') { if (node.type === 'paragraph') {
...@@ -112,7 +82,7 @@ const ImageModal = (props, ref) => { ...@@ -112,7 +82,7 @@ const ImageModal = (props, ref) => {
universal: true universal: true
}) })
for (let nodeEntry of nodeEntries) { for (let nodeEntry of nodeEntries) {
const [node, path] = nodeEntry const [node] = nodeEntry
if (node.children[0].text === '') { if (node.children[0].text === '') {
SlateTransforms.removeNodes(editor) SlateTransforms.removeNodes(editor)
} }
...@@ -142,20 +112,6 @@ const ImageModal = (props, ref) => { ...@@ -142,20 +112,6 @@ const ImageModal = (props, ref) => {
if (tempNodeInfo && Object.entries(tempNodeInfo).length > 0) { if (tempNodeInfo && Object.entries(tempNodeInfo).length > 0) {
const elem = editor.toDOMNode(tempNodeInfo.node) // 返回 HTMLElement const elem = editor.toDOMNode(tempNodeInfo.node) // 返回 HTMLElement
let nodeProps = JSON.parse(JSON.stringify(tempNodeInfo.node))
let obj = {}
let cIndex = -1
nodeProps.children.forEach((element, index) => {
if (element.type === 'image') {
obj = {
...element,
alt: values.imgTitle,
src: values.imgUrl,
href: values.imgDescript
}
cIndex = index
}
})
SlateTransforms.removeNodes(editor) SlateTransforms.removeNodes(editor)
const elem2 = elem.nextSibling const elem2 = elem.nextSibling
...@@ -181,7 +137,7 @@ const ImageModal = (props, ref) => { ...@@ -181,7 +137,7 @@ const ImageModal = (props, ref) => {
clear() clear()
} }
const onOnlineImageChange = (url) => { const onOnlineImageChange = url => {
setImgUrl(url) setImgUrl(url)
form.setFieldsValue({ imgUrl: url }) form.setFieldsValue({ imgUrl: url })
} }
...@@ -195,7 +151,7 @@ const ImageModal = (props, ref) => { ...@@ -195,7 +151,7 @@ const ImageModal = (props, ref) => {
<OnlineImageList imgUrl={imgUrl} onChange={onOnlineImageChange}></OnlineImageList> <OnlineImageList imgUrl={imgUrl} onChange={onOnlineImageChange}></OnlineImageList>
</Form.Item> </Form.Item>
) : ( ) : (
<Form.Item label="上传图片" valuePropName="fileList" name="imgUrl" getValueFromEvent={normFile} rules={[{ required: true, message: '请上传图片' }]}> <Form.Item label="上传图片" name="imgUrl" rules={[{ required: true, message: '请上传图片' }]}>
<Spin spinning={uploading} tip={`${progress}%`}> <Spin spinning={uploading} tip={`${progress}%`}>
<div className="editor-dragger"> <div className="editor-dragger">
<Dragger {...uploadProps} showUploadList={false}> <Dragger {...uploadProps} showUploadList={false}>
...@@ -209,7 +165,6 @@ const ImageModal = (props, ref) => { ...@@ -209,7 +165,6 @@ const ImageModal = (props, ref) => {
</div> </div>
)} )}
{imgUrl && ( {imgUrl && (
<>
<div className="editor-uploader-result"> <div className="editor-uploader-result">
<div className="editor-uploader-result-img"> <div className="editor-uploader-result-img">
<img src={imgUrl} alt="" /> <img src={imgUrl} alt="" />
...@@ -220,7 +175,6 @@ const ImageModal = (props, ref) => { ...@@ -220,7 +175,6 @@ const ImageModal = (props, ref) => {
</Button> </Button>
</div> </div>
</div> </div>
</>
)} )}
</Dragger> </Dragger>
</div> </div>
......
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react' import { useState, useEffect, forwardRef } from 'react'
import { Modal, Divider, Upload, Input, Space, Button, Form, Spin, message, Select, Cascader, ColorPicker, Row, Col } from 'antd' import { Divider, Input, Space, Button, Form, message, Select, Cascader, ColorPicker, Row, Col } from 'antd'
import { SlateTransforms, SlateEditor, DomEditor, SlateElement } from '@wangeditor/editor' import { SlateTransforms, SlateEditor, SlateElement } from '@wangeditor/editor'
import './index.less' import './index.less'
import { addChapterTooltip, delChapterTooltip } from '../utils/request'
import { fontSizeList } from '../utils/setting' import { fontSizeList } from '../utils/setting'
import { findTreeElementByKey } from '@/utils/common' import { findTreeElementByKey } from '@/utils/common'
const LinkModal = forwardRef((props, ref) => { const LinkModal = (props, ref) => {
const { editor, ossClient, bookId, chapterId, setLinkVisible, setLinkInfo, linkInfo, gData, selectionSize = 18 } = props const { editor, setLinkVisible, setLinkInfo, linkInfo, gData, selectionSize = 18 } = props
const [form] = Form.useForm() const [form] = Form.useForm()
const linktype = Form.useWatch('linktype', form) const linktype = Form.useWatch('linktype', form)
...@@ -20,9 +19,7 @@ const LinkModal = forwardRef((props, ref) => { ...@@ -20,9 +19,7 @@ const LinkModal = forwardRef((props, ref) => {
theme: '#ab1941', theme: '#ab1941',
fontSize: selectionSize || 18 fontSize: selectionSize || 18
}) })
const [toolStatus, setToolStatus] = useState(false)
const [nowRandom, setNowRandom] = useState(null) const [nowRandom, setNowRandom] = useState(null)
const [fontsize, setFontsize] = useState(selectionSize)
const linkChange = value => { const linkChange = value => {
if (value === 2) { if (value === 2) {
...@@ -75,7 +72,7 @@ const LinkModal = forwardRef((props, ref) => { ...@@ -75,7 +72,7 @@ const LinkModal = forwardRef((props, ref) => {
} }
setLoading(true) setLoading(true)
const { linktype, link, ...other } = values const { link } = values
let newLink = '' let newLink = ''
if (link) { if (link) {
if (!/^https*:\/\//.test(link)) { if (!/^https*:\/\//.test(link)) {
...@@ -143,47 +140,6 @@ const LinkModal = forwardRef((props, ref) => { ...@@ -143,47 +140,6 @@ const LinkModal = forwardRef((props, ref) => {
setLoading(false) setLoading(false)
} }
const deleteNowTooltip = async () => {
const data = await delChapterTooltip({
book_id: bookId,
chapter_id: chapterId,
position: nowRandom
})
if (data) {
editor.restoreSelection()
const nodeEntries = SlateEditor.nodes(editor, {
match: node => {
// JS syntax
if (SlateElement.isElement(node)) {
if (node.type === 'chapterLink') {
return true // 匹配 chapterToolTip
}
}
return false
},
universal: true
})
// 遍历匹配的节点迭代器,获取匹配的节点路径
let nodePaths = []
let nodes = []
if (nodeEntries === null) {
console.log('当前未选中的 chapterLink')
} else {
for (let nodeEntry of nodeEntries) {
const [node, path] = nodeEntry
nodePaths.push(path)
nodes.push(node)
}
// 将属性应用到匹配的节点
for (const path of nodePaths) {
SlateTransforms.removeNodes(editor, { at: path })
}
}
setNowRandom(null)
setLinkVisible(false)
}
}
return ( return (
<div> <div>
<Divider /> <Divider />
...@@ -256,11 +212,6 @@ const LinkModal = forwardRef((props, ref) => { ...@@ -256,11 +212,6 @@ const LinkModal = forwardRef((props, ref) => {
</Form.Item> </Form.Item>
<Form.Item className="editor-form-buttons"> <Form.Item className="editor-form-buttons">
<Space> <Space>
{toolStatus && (
<Button type="default" onClick={deleteNowTooltip}>
删除
</Button>
)}
<Button type="primary" loading={loading} htmlType="submit"> <Button type="primary" loading={loading} htmlType="submit">
{nowRandom ? '更新' : '插入'} {nowRandom ? '更新' : '插入'}
</Button> </Button>
...@@ -270,6 +221,6 @@ const LinkModal = forwardRef((props, ref) => { ...@@ -270,6 +221,6 @@ const LinkModal = forwardRef((props, ref) => {
</div> </div>
</div> </div>
) )
}) }
export default LinkModal export default forwardRef(LinkModal)
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react'; import { useState, forwardRef, useImperativeHandle } from 'react'
import { import { Divider, Input, Space, Button, Form, ColorPicker } from 'antd'
Modal,
Divider,
Upload,
Input,
Space,
Button,
Form,
Spin,
message,
ColorPicker,
} from 'antd';
import { CloudUploadOutlined } from '@ant-design/icons';
import { SlateTransforms, SlateEditor, DomEditor, SlateElement } from '@wangeditor/editor'; import { SlateTransforms, SlateEditor, SlateElement } from '@wangeditor/editor'
import { setPracticeRandom } from '@/store/modules/editor'; import { setPracticeRandom } from '@/store/modules/editor'
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux'
import './index.less'; import './index.less'
const PracticeModal = forwardRef((props, ref) => { const PracticeModal = (props, ref) => {
const { bookId, chapterId, setPracticeOpenVisible } = props; const { bookId, chapterId, setPracticeOpenVisible } = props
const dispatch = useDispatch(); const dispatch = useDispatch()
const { editor, ossClient } = props; const { editor } = props
const [form] = Form.useForm(); const [form] = Form.useForm()
const [themeValue, setThemeValue] = useState('#ab1941'); const [themeValue, setThemeValue] = useState('#ab1941')
const [initValues, setInitValues] = useState({ practice: '', theme: '#ab1941' }); const [initValues, setInitValues] = useState({ practice: '', theme: '#ab1941' })
const [nodes, setNodes] = useState(null); const [nodes, setNodes] = useState(null)
useImperativeHandle(ref, () => { useImperativeHandle(ref, () => {
return { return {
nodes, nodes
}; }
}); })
const textColorChange = (value, hex) => { const textColorChange = (value, hex) => {
setThemeValue(hex); setThemeValue(hex)
form.setFieldsValue({ theme: hex }); form.setFieldsValue({ theme: hex })
}; }
const callback = (practiceNum, practiceTitle) => { const callback = (practiceNum, practiceTitle) => {
const nodeEntries = SlateEditor.nodes(editor, { const nodeEntries = SlateEditor.nodes(editor, {
match: (node) => { match: node => {
// JS syntax // JS syntax
if (SlateElement.isElement(node)) { if (SlateElement.isElement(node)) {
if (node.type === 'chapterPractice') { if (node.type === 'chapterPractice') {
return true; return true
} }
} }
return false; return false
}, },
universal: true, universal: true
}); })
setNodes(nodeEntries); setNodes(nodeEntries)
dispatch(setPracticeRandom({ practiceNum, practiceTitle })); dispatch(setPracticeRandom({ practiceNum, practiceTitle }))
}; }
const onFinish = (values) => { const onFinish = values => {
editor.restoreSelection(); editor.restoreSelection()
const nodeEntries = SlateEditor.nodes(editor, { const nodeEntries = SlateEditor.nodes(editor, {
match: (node) => { match: node => {
// JS syntax // JS syntax
if (SlateElement.isElement(node)) { if (SlateElement.isElement(node)) {
if (node.type === 'paragraph') { if (node.type === 'paragraph') {
return true; // 匹配 paragraph return true // 匹配 paragraph
} }
} }
return false; return false
}, },
universal: true, universal: true
}); })
for (let nodeEntry of nodeEntries) { for (let nodeEntry of nodeEntries) {
const [node, path] = nodeEntry; const [node] = nodeEntry
if (node.children[0].text === '') { if (node.children[0].text === '') {
SlateTransforms.removeNodes(editor); SlateTransforms.removeNodes(editor)
} }
} }
const practiceNum = Math.random().toString(32).substring(2, 10); const practiceNum = Math.random().toString(32).substring(2, 10)
editor.insertNode({ editor.insertNode({
type: 'chapterPractice', type: 'chapterPractice',
title: values.practice, title: values.practice,
...@@ -88,62 +76,44 @@ const PracticeModal = forwardRef((props, ref) => { ...@@ -88,62 +76,44 @@ const PracticeModal = forwardRef((props, ref) => {
chapterId, chapterId,
theme: values.theme, theme: values.theme,
callback: callback, callback: callback,
children: [{ text: '' }], children: [{ text: '' }]
}); })
form.resetFields(); form.resetFields()
setPracticeOpenVisible(false); setPracticeOpenVisible(false)
editor.focus(); editor.focus()
}; }
return ( return (
<div> <div>
<Divider /> <Divider />
<div className='editor-content-form'> <div className="editor-content-form">
<Form <Form layout="vertical" name="validate_other" form={form} onFinish={onFinish} initialValues={initValues}>
layout='vertical' <Form.Item label="标题" name="practice" rules={[{ required: true, message: '请输入标题' }]} extra="最多输入100字">
name='validate_other' <Input maxLength={100} placeholder="" allowClear />
form={form}
onFinish={onFinish}
initialValues={initValues}
>
<Form.Item
label='标题'
name='practice'
rules={[{ required: true, message: '请输入标题' }]}
extra='最多输入100字'
>
<Input maxLength={100} placeholder='' allowClear />
</Form.Item> </Form.Item>
<Form.Item> <Form.Item>
<div className='justcontent-color-inline'> <div className="justcontent-color-inline">
<Form.Item <Form.Item
label='练习主题色' label="练习主题色"
name='theme' name="theme"
className='flex-max' className="flex-max"
rules={[ rules={[
{ required: true, message: '请选择颜色' }, { required: true, message: '请选择颜色' },
{ pattern: /^#[0-9A-Fa-f]{6}$/i, message: '请输入正确的16进制色值' }, { pattern: /^#[0-9A-Fa-f]{6}$/i, message: '请输入正确的16进制色值' }
]} ]}>
> <Input placeholder="" allowClear />
<Input placeholder='' allowClear />
</Form.Item> </Form.Item>
<Form.Item label={` `}> <Form.Item label={` `}>
<ColorPicker <ColorPicker disabledAlpha value={themeValue} defaultValue={themeValue} format="hex" onChange={textColorChange} />
disabledAlpha
value={themeValue}
defaultValue={themeValue}
format='hex'
onChange={textColorChange}
/>
</Form.Item> </Form.Item>
</div> </div>
</Form.Item> </Form.Item>
<Form.Item className='editor-form-buttons'> <Form.Item className="editor-form-buttons">
<Space> <Space>
<Button type='default' onClick={() => setPracticeOpenVisible(false)}> <Button type="default" onClick={() => setPracticeOpenVisible(false)}>
取消 取消
</Button> </Button>
<Button type='primary' htmlType='submit'> <Button type="primary" htmlType="submit">
插入 插入
</Button> </Button>
</Space> </Space>
...@@ -151,7 +121,7 @@ const PracticeModal = forwardRef((props, ref) => { ...@@ -151,7 +121,7 @@ const PracticeModal = forwardRef((props, ref) => {
</Form> </Form>
</div> </div>
</div> </div>
); )
}); }
export default PracticeModal; export default forwardRef(PracticeModal)
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react' import { useState, useEffect, forwardRef } from 'react'
import { Modal, Divider, Upload, Input, Space, Button, Form, Spin, message, Select, ColorPicker, Row, Col } from 'antd' import { Divider, Input, Space, Button, Form, message, Select, ColorPicker, Row, Col } from 'antd'
import { SlateTransforms, SlateEditor, DomEditor, SlateElement } from '@wangeditor/editor' import { SlateTransforms, SlateEditor, SlateElement } from '@wangeditor/editor'
import './index.less' import './index.less'
import { addChapterTooltip, delChapterTooltip } from '../utils/request' import { addChapterTooltip, delChapterTooltip } from '../utils/request'
import { findNodeWithParent, fontSizeList } from '../utils/setting' import { findNodeWithParent, fontSizeList } from '../utils/setting'
const TooltipModal = forwardRef((props, ref) => { const TooltipModal = (props, ref) => {
const { editor, ossClient, bookId, chapterId, setTooltipVisible, setTooltipInfo, tooltipInfo, selectionSize = 18 } = props const { editor, bookId, chapterId, setTooltipVisible, setTooltipInfo, tooltipInfo, selectionSize = 18 } = props
const [form] = Form.useForm() const [form] = Form.useForm()
const tooltipTypeValue = Form.useWatch('tooltipType', form) const tooltipTypeValue = Form.useWatch('tooltipType', form)
...@@ -44,7 +44,7 @@ const TooltipModal = forwardRef((props, ref) => { ...@@ -44,7 +44,7 @@ const TooltipModal = forwardRef((props, ref) => {
const onFinish = async values => { const onFinish = async values => {
editor.restoreSelection() editor.restoreSelection()
setLoading(true) setLoading(true)
const { tooltipType, link, theme, fontSize, ...other } = values const { tooltipType, link, theme, ...other } = values
let newLink = '' let newLink = ''
if (link) { if (link) {
if (!/^https*:\/\//.test(link)) { if (!/^https*:\/\//.test(link)) {
...@@ -78,7 +78,6 @@ const TooltipModal = forwardRef((props, ref) => { ...@@ -78,7 +78,6 @@ const TooltipModal = forwardRef((props, ref) => {
return return
} }
const text = editor.getSelectionText()
let random = Math.random().toString(10).substring(2, 10) let random = Math.random().toString(10).substring(2, 10)
const data = await addChapterTooltip({ const data = await addChapterTooltip({
book_id: bookId, book_id: bookId,
...@@ -231,6 +230,6 @@ const TooltipModal = forwardRef((props, ref) => { ...@@ -231,6 +230,6 @@ const TooltipModal = forwardRef((props, ref) => {
</div> </div>
</div> </div>
) )
}) }
export default TooltipModal export default forwardRef(TooltipModal)
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react'; import { useState, useEffect, forwardRef, useImperativeHandle } from 'react'
import { Modal, Divider, Upload, Input, Space, Button, Form, Spin, message } from 'antd'; import { Modal, Divider, Upload, Input, Space, Button, Form, Spin, message } from 'antd'
import { CloudUploadOutlined } from '@ant-design/icons'; import { CloudUploadOutlined } from '@ant-design/icons'
import { SlateTransforms, SlateEditor, DomEditor, SlateElement } from '@wangeditor/editor'; import { SlateTransforms, SlateEditor, SlateElement } from '@wangeditor/editor'
import dayjs from 'dayjs'; import './index.less'
import './index.less';
import { partSize, parallel, normalUploader, multipartUploader } from '../utils/upload'; import { uploadFile } from '@/utils/oss'
const { Dragger } = Upload; const { Dragger } = Upload
const VideoModal = forwardRef((props, ref) => { const VideoModal = (props, ref) => {
const { editor, ossClient, STSToken } = props; const { editor } = props
const fileAccept = ['.ogg', '.mp4', '.webm']; const fileAccept = ['.ogg', '.mp4', '.webm']
const [form] = Form.useForm(); const [form] = Form.useForm()
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false)
const [uploading, setUploading] = useState(false); // 文件上传状态 const [uploading, setUploading] = useState(false) // 文件上传状态
const [progress, setProgress] = useState(0); const [progress, setProgress] = useState(0)
const [file, setFile] = useState({}); const [file, setFile] = useState({})
const [fileList, setFileList] = useState([]);
const [videoUrl, setVideoUrl] = useState(''); const [videoUrl, setVideoUrl] = useState('')
useEffect(() => { useEffect(() => {
if (!visible) { if (!visible) {
setVideoUrl(''); setVideoUrl('')
form.resetFields(); form.resetFields()
} }
}, [visible]); }, [visible])
useImperativeHandle(ref, () => { useImperativeHandle(ref, () => {
return { return {
setVisible, setVisible
};
});
const normFile = (e) => {
if (Array.isArray(e)) {
return e;
} }
return e?.fileList; })
};
const uploadProps = { const uploadProps = {
name: 'file', name: 'file',
maxCount: 1, maxCount: 1,
showUploadList: false, showUploadList: false,
accept: fileAccept.join(','), accept: fileAccept.join(','),
beforeUpload: (file, fileList) => { beforeUpload: file => {
const fileExt = file.name.substring(file.name.lastIndexOf('.')); const fileExt = file.name.substring(file.name.lastIndexOf('.'))
if (!fileAccept.includes(fileExt.toLowerCase())) { if (!fileAccept.includes(fileExt.toLowerCase())) {
message.error('请上传正确格式的图片'); message.error('请上传正确格式的视频')
return false; return false
} }
setProgress(0); setProgress(0)
setUploading(false); setUploading(false)
setFile(file); setFile(file)
setFileList(fileList);
}, },
customRequest: async () => { customRequest: async () => {
setUploading(true); setUploading(true)
let data = null; const url = await uploadFile(file)
if (file.size >= partSize) { setVideoUrl(url)
data = await multipartUploader(file, 'video', ossClient, (progress, checkpoint) => { form.setFieldsValue({ videoUrl: url })
console.log(`上传进度 ${progress}`); setUploading(false)
setProgress(parseInt(progress * 100));
});
console.log('multipartUploader --> ', data);
} else {
data = await normalUploader(file, 'video', ossClient);
console.log('normalUploader --> ', data);
} }
if (data.status === 200 && data.statusCode === 200) {
const { url, name } = data;
setVideoUrl(url);
form.setFieldsValue({ videoUrl: url });
} }
setUploading(false);
},
};
const onFinish = (values) => { const onFinish = values => {
editor.restoreSelection(); editor.restoreSelection()
// editor.insertNode({
// type: 'chapterVideo',
// title: values.videoTitle,
// videoUrl: values.videoUrl,
// children: [{ text: '' }],
// });
// editor.insertNode({
// type: 'video',
// // title: values.videoTitle,
// src: values.videoUrl,
// children: [{ text: '' }],
// });
const nodeEntries = SlateEditor.nodes(editor, { const nodeEntries = SlateEditor.nodes(editor, {
match: (node) => { match: node => {
// JS syntax // JS syntax
if (SlateElement.isElement(node)) { if (SlateElement.isElement(node)) {
if (node.type === 'paragraph') { if (node.type === 'paragraph') {
return true; // 匹配 paragraph return true // 匹配 paragraph
} }
} }
return false; return false
}, },
universal: true, universal: true
}); })
for (let nodeEntry of nodeEntries) { for (let nodeEntry of nodeEntries) {
const [node, path] = nodeEntry; const [node] = nodeEntry
if (node.children[0].text === '') { if (node.children[0].text === '') {
SlateTransforms.removeNodes(editor); SlateTransforms.removeNodes(editor)
} }
} }
...@@ -118,21 +83,21 @@ const VideoModal = forwardRef((props, ref) => { ...@@ -118,21 +83,21 @@ const VideoModal = forwardRef((props, ref) => {
{ {
type: 'video', type: 'video',
src: values.videoUrl, src: values.videoUrl,
children: [{ text: '' }], children: [{ text: '' }]
}, },
{ {
type: 'paragraph', type: 'paragraph',
children: [{ text: values.videoTitle }], children: [{ text: values.videoTitle }]
}, }
]; ]
SlateTransforms.insertNodes(editor, nodes); SlateTransforms.insertNodes(editor, nodes)
setVideoUrl(''); setVideoUrl('')
setProgress(0); setProgress(0)
setUploading(false); setUploading(false)
form.resetFields(); form.resetFields()
setVisible(false); setVisible(false)
}; }
return ( return (
<div> <div>
...@@ -141,58 +106,38 @@ const VideoModal = forwardRef((props, ref) => { ...@@ -141,58 +106,38 @@ const VideoModal = forwardRef((props, ref) => {
footer={null} footer={null}
centered centered
destroyOnClose destroyOnClose
title='插入视频' title="插入视频"
classNames={{ classNames={{
header: 'editor-header-customer', header: 'editor-header-customer',
body: 'editor-body-customer', body: 'editor-body-customer',
wrapper: 'editor-wrapper-customer', wrapper: 'editor-wrapper-customer'
}} }}
maskClosable={false} maskClosable={false}
onCancel={() => setVisible(false)} onCancel={() => setVisible(false)}>
>
<Divider /> <Divider />
<div className='editor-content-form'> <div className="editor-content-form">
<Form <Form layout="vertical" name="validate_other" form={form} onFinish={onFinish} initialValues={{ videoUrl: videoUrl, videoTitle: '' }}>
layout='vertical' <Form.Item label="上传视频" name="videoUrl" rules={[{ required: true, message: '请上传视频' }]}>
name='validate_other'
form={form}
onFinish={onFinish}
initialValues={{ videoUrl: videoUrl, videoTitle: '' }}
>
<Form.Item
label='上传视频'
valuePropName='fileList'
name='videoUrl'
getValueFromEvent={normFile}
rules={[{ required: true, message: '请上传视频' }]}
>
<Spin spinning={uploading} tip={`${progress}%`}> <Spin spinning={uploading} tip={`${progress}%`}>
<div className='editor-dragger'> <div className="editor-dragger">
<Dragger {...uploadProps} showUploadList={false}> <Dragger {...uploadProps} showUploadList={false}>
{!videoUrl && ( {!videoUrl && (
<div className='editor-uploader-process'> <div className="editor-uploader-process">
<p className='ant-upload-drag-icon'> <p className="ant-upload-drag-icon">
<CloudUploadOutlined style={{ fontSize: 40 }} /> <CloudUploadOutlined style={{ fontSize: 40 }} />
</p> </p>
<p className='ant-upload-text'>点击上传或拖拽到此处上传</p> <p className="ant-upload-text">点击上传或拖拽到此处上传</p>
<p className='ant-upload-hint'> <p className="ant-upload-hint">支持上传 .ogg、.mp4、.webm 格式的文件</p>
支持上传 .ogg、.mp4、.webm 格式的文件
</p>
</div> </div>
)} )}
{videoUrl && ( {videoUrl && (
<> <>
<div className='editor-uploader-result'> <div className="editor-uploader-result">
<div className='editor-uploader-result-img'> <div className="editor-uploader-result-img">
<video src={videoUrl} autoPlay height='110' width='200' alt='' /> <video src={videoUrl} autoPlay height="110" width="200" alt="" />
</div> </div>
<div className='editor-uploader-result-tips'> <div className="editor-uploader-result-tips">
<Button <Button size="small" type="primary" ghost onClick={() => setVideoUrl(null)}>
size='small'
type='primary'
ghost
onClick={() => setVideoUrl(null)}
>
替换 替换
</Button> </Button>
</div> </div>
...@@ -203,20 +148,15 @@ const VideoModal = forwardRef((props, ref) => { ...@@ -203,20 +148,15 @@ const VideoModal = forwardRef((props, ref) => {
</div> </div>
</Spin> </Spin>
</Form.Item> </Form.Item>
<Form.Item <Form.Item label="视频标题" name="videoTitle" rules={[{ required: true, message: '请输入视频标题' }]} extra="最多输入100字">
label='视频标题' <Input maxLength={100} placeholder="" allowClear />
name='videoTitle'
rules={[{ required: true, message: '请输入图片标题' }]}
extra='最多输入100字'
>
<Input maxLength={100} placeholder='' allowClear />
</Form.Item> </Form.Item>
<Form.Item className='editor-form-buttons'> <Form.Item className="editor-form-buttons">
<Space> <Space>
<Button type='default' disabled={uploading} onClick={() => setVisible(false)}> <Button type="default" disabled={uploading} onClick={() => setVisible(false)}>
取消 取消
</Button> </Button>
<Button type='primary' disabled={uploading} htmlType='submit'> <Button type="primary" disabled={uploading} htmlType="submit">
插入 插入
</Button> </Button>
</Space> </Space>
...@@ -225,7 +165,7 @@ const VideoModal = forwardRef((props, ref) => { ...@@ -225,7 +165,7 @@ const VideoModal = forwardRef((props, ref) => {
</div> </div>
</Modal> </Modal>
</div> </div>
); )
}); }
export default VideoModal; export default forwardRef(VideoModal)
import { useState, useEffect, useRef, forwardRef, useImperativeHandle } from 'react' import { useState, useEffect, useRef, forwardRef, useImperativeHandle } from 'react'
import { Button, Divider, Space, Modal } from 'antd' import { Button, Divider, Space, Modal } from 'antd'
import { EyeOutlined, SaveOutlined, CloseOutlined, HistoryOutlined } from '@ant-design/icons' import { EyeOutlined, SaveOutlined, CloseOutlined, HistoryOutlined } from '@ant-design/icons'
import AliOSS from 'ali-oss'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import './utils/iconfont' import './utils/iconfont'
...@@ -80,9 +79,7 @@ import PreviewModal from './components/preview' ...@@ -80,9 +79,7 @@ import PreviewModal from './components/preview'
import HistoryModal from './history/' import HistoryModal from './history/'
import $ from 'jquery' import $ from 'jquery'
import { getAliOSSSTSToken } from './utils/request'
import './index.less' import './index.less'
const bookBucketName = 'zxts-book-file'
const module = { const module = {
menus: [ menus: [
...@@ -152,9 +149,6 @@ const WangEditorCustomer = (props, ref) => { ...@@ -152,9 +149,6 @@ const WangEditorCustomer = (props, ref) => {
const toolbarRef = useRef() const toolbarRef = useRef()
const [ossClient, setOssClient] = useState(null) // oss 操作
const [STSToken, setSTSToken] = useState(null) // oss 过期设置
const [tabKey, setTabKey] = useState('text') const [tabKey, setTabKey] = useState('text')
// editor 实例 // editor 实例
const [editor, setEditor] = useState(null) const [editor, setEditor] = useState(null)
...@@ -615,71 +609,6 @@ const WangEditorCustomer = (props, ref) => { ...@@ -615,71 +609,6 @@ const WangEditorCustomer = (props, ref) => {
setHistoryVisible(true) setHistoryVisible(true)
} }
const getStsAuthToken = async () => {
const data = await getAliOSSSTSToken()
if (data) {
window.sessionStorage.setItem('sts', JSON.stringify(data))
setSTSToken(data)
const ossClientTemp = new AliOSS({
accessKeyId: data.AccessKeyId,
accessKeySecret: data.AccessKeySecret,
stsToken: data.SecurityToken,
endpoint: 'zijingebook.com',
// region: 'cn-beijing',
// endpoint: data.endpoint,
bucket: bookBucketName,
timeout: 60000,
refreshSTSToken: async () => {
const info = await getAliOSSSTSToken()
return {
AccessKeyId: info.AccessKeyId,
AccessKeySecret: info.AccessKeySecret,
SecurityToken: info.SecurityToken
}
},
refreshSTSTokenInterval: 14 * 60 * 1000
})
setOssClient(ossClientTemp)
}
}
useEffect(() => {
;(async () => {
const tempStsToken = window.sessionStorage ? window.sessionStorage.getItem('sts') : ''
try {
const stsToken = JSON.parse(tempStsToken)
// 15 分钟过期
if (dayjs(stsToken.Expiration).valueOf() - dayjs().valueOf() >= 14 * 60 * 1000) {
getStsAuthToken()
} else {
const ossClientTemp = await new AliOSS({
accessKeyId: data.AccessKeyId,
accessKeySecret: data.AccessKeySecret,
stsToken: data.SecurityToken,
// endpoint: data.endpoint,
// region: 'cn-beijing',
endpoint: 'zijingebook.com',
bucket: bookBucketName,
timeout: 180000,
refreshSTSToken: async () => {
const info = await getAliOSSSTSToken()
return {
AccessKeyId: info.AccessKeyId,
AccessKeySecret: info.AccessKeySecret,
SecurityToken: info.SecurityToken
}
},
refreshSTSTokenInterval: 14 * 60 * 1000
})
setOssClient(ossClientTemp)
setSTSToken(stsToken)
}
} catch (e) {
getStsAuthToken()
}
})()
}, [])
const colorList = [ const colorList = [
{ color: '#ab1941', name: '默认' }, { color: '#ab1941', name: '默认' },
{ color: '#2970f6', name: '蓝色' }, { color: '#2970f6', name: '蓝色' },
...@@ -799,18 +728,9 @@ const WangEditorCustomer = (props, ref) => { ...@@ -799,18 +728,9 @@ const WangEditorCustomer = (props, ref) => {
}} }}
maskClosable={false} maskClosable={false}
onCancel={() => setImageVisible(false)}> onCancel={() => setImageVisible(false)}>
<ImageModal <ImageModal ref={imageRef} isOnline={isOnline} editor={editor} setImageVisible={setImageVisible} imageInfo={imageInfo} setImageInfo={setImageInfo} />
ref={imageRef}
isOnline={isOnline}
editor={editor}
ossClient={ossClient}
STSToken={STSToken}
setImageVisible={setImageVisible}
imageInfo={imageInfo}
setImageInfo={setImageInfo}
/>
</Modal> </Modal>
<VideoModal ref={videoRef} editor={editor} ossClient={ossClient} STSToken={STSToken} /> <VideoModal ref={videoRef} editor={editor} />
<Modal <Modal
open={galleryVisible} open={galleryVisible}
footer={null} footer={null}
...@@ -829,8 +749,6 @@ const WangEditorCustomer = (props, ref) => { ...@@ -829,8 +749,6 @@ const WangEditorCustomer = (props, ref) => {
ref={galleryRef} ref={galleryRef}
isOnline={isOnline} isOnline={isOnline}
editor={editor} editor={editor}
ossClient={ossClient}
STSToken={STSToken}
chapterId={chapterId} chapterId={chapterId}
bookId={bookId} bookId={bookId}
setGalleryVisible={setGalleryVisible} setGalleryVisible={setGalleryVisible}
...@@ -839,7 +757,7 @@ const WangEditorCustomer = (props, ref) => { ...@@ -839,7 +757,7 @@ const WangEditorCustomer = (props, ref) => {
selectionSize={selectionSize} selectionSize={selectionSize}
/> />
</Modal> </Modal>
<AudioModal ref={audioRef} editor={editor} ossClient={ossClient} STSToken={STSToken} /> <AudioModal ref={audioRef} editor={editor} />
<Modal <Modal
open={titleVisible} open={titleVisible}
footer={null} footer={null}
...@@ -853,15 +771,7 @@ const WangEditorCustomer = (props, ref) => { ...@@ -853,15 +771,7 @@ const WangEditorCustomer = (props, ref) => {
}} }}
maskClosable={false} maskClosable={false}
onCancel={() => setTitleVisible(false)}> onCancel={() => setTitleVisible(false)}>
<ChapterTitleModal <ChapterTitleModal ref={chapterTitleRef} editor={editor} setTitleVisible={setTitleVisible} titleInfo={titleInfo} setTitleInfo={setTitleInfo} />
ref={chapterTitleRef}
editor={editor}
ossClient={ossClient}
STSToken={STSToken}
setTitleVisible={setTitleVisible}
titleInfo={titleInfo}
setTitleInfo={setTitleInfo}
/>
</Modal> </Modal>
<Modal <Modal
...@@ -880,8 +790,6 @@ const WangEditorCustomer = (props, ref) => { ...@@ -880,8 +790,6 @@ const WangEditorCustomer = (props, ref) => {
<ChapterItemModal <ChapterItemModal
ref={chapterItemRef} ref={chapterItemRef}
editor={editor} editor={editor}
ossClient={ossClient}
STSToken={STSToken}
setSectionVisible={setSectionVisible} setSectionVisible={setSectionVisible}
sectionInfo={sectionInfo} sectionInfo={sectionInfo}
setSectionInfo={setSectionInfo} setSectionInfo={setSectionInfo}
...@@ -902,18 +810,10 @@ const WangEditorCustomer = (props, ref) => { ...@@ -902,18 +810,10 @@ const WangEditorCustomer = (props, ref) => {
}} }}
maskClosable={false} maskClosable={false}
onCancel={() => setPracticeOpenVisible(false)}> onCancel={() => setPracticeOpenVisible(false)}>
<PracticeModal <PracticeModal ref={practiceRef} chapterId={chapterId} bookId={bookId} editor={editor} setPracticeOpenVisible={setPracticeOpenVisible} />
ref={practiceRef}
chapterId={chapterId}
bookId={bookId}
editor={editor}
ossClient={ossClient}
STSToken={STSToken}
setPracticeOpenVisible={setPracticeOpenVisible}
/>
</Modal> </Modal>
<FormulaModal ref={formulaRef} editor={editor} ossClient={ossClient} STSToken={STSToken} /> <FormulaModal ref={formulaRef} editor={editor} />
<Modal <Modal
open={tooltipVisible} open={tooltipVisible}
footer={null} footer={null}
...@@ -932,8 +832,6 @@ const WangEditorCustomer = (props, ref) => { ...@@ -932,8 +832,6 @@ const WangEditorCustomer = (props, ref) => {
editor={editor} editor={editor}
chapterId={chapterId} chapterId={chapterId}
bookId={bookId} bookId={bookId}
ossClient={ossClient}
STSToken={STSToken}
tooltipInfo={tooltipInfo} tooltipInfo={tooltipInfo}
setTooltipInfo={setTooltipInfo} setTooltipInfo={setTooltipInfo}
setTooltipVisible={setTooltipVisible} setTooltipVisible={setTooltipVisible}
...@@ -958,8 +856,6 @@ const WangEditorCustomer = (props, ref) => { ...@@ -958,8 +856,6 @@ const WangEditorCustomer = (props, ref) => {
editor={editor} editor={editor}
chapterId={chapterId} chapterId={chapterId}
bookId={bookId} bookId={bookId}
ossClient={ossClient}
STSToken={STSToken}
gData={gData} gData={gData}
linkInfo={linkInfo} linkInfo={linkInfo}
setLinkInfo={setLinkInfo} setLinkInfo={setLinkInfo}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论