Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
C
center-book
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
center-book
Commits
227c5f8b
提交
227c5f8b
authored
6月 14, 2024
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
chore: update
上级
253a8d2e
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
15 个修改的文件
包含
353 行增加
和
252 行删除
+353
-252
chuangkit.js
src/api/chuangkit.js
+6
-0
index.jsx
src/common/wangeditor-customer/ai-drawer/index.jsx
+10
-11
gallery.jsx
src/common/wangeditor-customer/components/gallery.jsx
+15
-15
galleryItem.jsx
src/common/wangeditor-customer/components/galleryItem.jsx
+78
-41
image.jsx
src/common/wangeditor-customer/components/image.jsx
+46
-34
index.less
src/common/wangeditor-customer/components/index.less
+29
-2
onlineImageList.jsx
...common/wangeditor-customer/components/onlineImageList.jsx
+27
-0
Gallery.js
src/common/wangeditor-customer/customer/Gallery.js
+1
-1
GalleryOnline.js
src/common/wangeditor-customer/customer/GalleryOnline.js
+7
-7
Image.js
src/common/wangeditor-customer/customer/Image.js
+1
-1
ImageOnline.js
src/common/wangeditor-customer/customer/ImageOnline.js
+12
-12
index.jsx
src/common/wangeditor-customer/index.jsx
+50
-33
gallery.js
src/common/wangeditor-customer/node/gallery.js
+0
-0
galleryInline.js
src/common/wangeditor-customer/node/galleryInline.js
+71
-95
image.jsx
src/common/wangeditor-customer/node/image.jsx
+0
-0
没有找到文件。
src/api/chuangkit.js
0 → 100644
浏览文件 @
227c5f8b
import
axios
from
'@/utils/axios'
// 查询我的设计
export
function
getChuangKitDesigns
(
data
)
{
return
axios
.
post
(
'/api/ai/chuangKit/designs'
,
data
)
}
src/common/wangeditor-customer/ai-drawer/index.jsx
浏览文件 @
227c5f8b
import
React
,
{
useState
,
useEffect
,
useCallback
}
from
'react'
import
{
useState
,
useEffect
}
from
'react'
import
{
SendOutlined
}
from
'@ant-design/icons'
import
{
Input
,
Space
,
Button
,
message
}
from
'antd'
import
{
Input
,
Button
,
message
}
from
'antd'
import
md5
from
'js-md5'
import
dayjs
from
'dayjs'
import
{
sleep
}
from
'@/utils/common'
...
...
@@ -14,11 +14,11 @@ const UUID = 'f3846153ba784b6d86bdcd5533259c88'
const
auth_key
=
'f3846153ba784b6d86bdcd5533259c88'
const
auth_secret
=
'HO4IyLEwEOHpeOXBxaLQUOqWslJRGs1M'
const
AIDrawerComponent
=
props
=>
{
const
AIDrawerComponent
=
(
props
)
=>
{
const
{
selectText
}
=
props
const
dispatch
=
useDispatch
()
const
{
userInfo
}
=
useSelector
(
state
=>
state
.
user
)
// 用户状态信息
const
{
editorAi
}
=
useSelector
(
state
=>
state
.
editor
)
// ai信息设置
const
{
userInfo
}
=
useSelector
(
(
state
)
=>
state
.
user
)
// 用户状态信息
const
{
editorAi
}
=
useSelector
(
(
state
)
=>
state
.
editor
)
// ai信息设置
const
[
value
,
setValue
]
=
useState
(
selectText
)
// 输入值
const
[
loading
,
setLoading
]
=
useState
(
false
)
// loading
...
...
@@ -31,7 +31,7 @@ const AIDrawerComponent = props => {
if
(
editorAi
&&
Object
.
entries
(
editorAi
).
length
>
0
)
{
let
tempJSON
=
JSON
.
parse
(
JSON
.
stringify
(
chatContentList
))
let
conversationId
=
editorAi
.
conversationId
const
item
=
tempJSON
.
filter
(
item
=>
item
.
conversationId
===
conversationId
)
const
item
=
tempJSON
.
filter
(
(
item
)
=>
item
.
conversationId
===
conversationId
)
if
(
item
&&
item
.
length
>
0
)
{
tempJSON
[
tempJSON
.
length
-
1
]
=
editorAi
}
else
{
...
...
@@ -57,7 +57,6 @@ const AIDrawerComponent = props => {
}
},
[])
let
cData
=
[]
let
buffer
=
''
const
readBuffer
=
(
reader
,
decoder
)
=>
{
...
...
@@ -85,7 +84,7 @@ const AIDrawerComponent = props => {
})
}
const
processBuffer
=
text
=>
{
const
processBuffer
=
(
text
)
=>
{
let
aiContent
=
{}
try
{
const
content
=
text
.
replace
(
/
\n
+/g
,
''
).
split
(
'data:'
)
...
...
@@ -129,7 +128,7 @@ const AIDrawerComponent = props => {
}),
mode
:
'cors'
})
.
then
(
response
=>
{
.
then
(
(
response
)
=>
{
// response.body 是一个 ReadableStream 对象
const
stream
=
response
.
body
// 使用流式数据
...
...
@@ -147,7 +146,7 @@ const AIDrawerComponent = props => {
// 开始读取流数据
readBuffer
(
reader
,
decoder
)
})
.
catch
(
error
=>
{
.
catch
(
(
error
)
=>
{
// 处理请求错误
console
.
error
(
'Request failed:'
,
error
)
})
...
...
@@ -200,7 +199,7 @@ const AIDrawerComponent = props => {
defaultValue=
{
value
}
allowClear
disabled=
{
loading
}
onChange=
{
e
=>
setValue
(
e
.
target
.
value
)
}
onChange=
{
(
e
)
=>
setValue
(
e
.
target
.
value
)
}
palceholder=
"请输入内容"
style=
{
{
height
:
'80px'
,
resize
:
'none'
}
}
></
Input
.
TextArea
>
</
div
>
...
...
src/common/wangeditor-customer/components/gallery.jsx
浏览文件 @
227c5f8b
...
...
@@ -7,14 +7,9 @@ import { SlateEditor, SlateTransforms, SlateElement } from '@wangeditor/editor'
import
{
findNodeWithParent
,
fontFizeList
}
from
'../utils/setting'
import
GalleryFormItem
from
'./galleryItem'
const
temp
=
[
'http://zxts-book-file.zijingebook.com/2024/02/27/gallery-1709002611091-nrxnqw595pc.png'
,
'http://zxts-book-file.zijingebook.com/2024/02/27/gallery-1709002615115-ngpulfnmspr.jpg'
]
const
randomOne
=
Math
.
random
().
toString
(
16
).
substring
(
2
,
10
)
const
GalleryModal
=
props
=>
{
const
{
editor
,
ossClient
,
galleryInfo
,
bookId
,
chapterId
,
setGalleryVisible
,
setGalleryInfo
,
selectionSize
=
18
}
=
props
const
GalleryModal
=
(
props
)
=>
{
const
{
editor
,
ossClient
,
galleryInfo
,
bookId
,
chapterId
,
setGalleryVisible
,
setGalleryInfo
,
selectionSize
=
18
,
isOnline
=
false
}
=
props
const
[
form
]
=
Form
.
useForm
()
const
[
loading
,
setLoading
]
=
useState
(
false
)
...
...
@@ -52,7 +47,9 @@ const GalleryModal = props => {
const
initialItems
=
[
{
label
:
'图 1'
,
children
:
<
GalleryFormItem
ossClient=
{
ossClient
}
form=
{
form
}
galleryInfo=
{
galleryInfo
}
activeKey=
{
randomOne
}
setPicList=
{
setPicList
}
/>,
children
:
(
<
GalleryFormItem
ossClient=
{
ossClient
}
form=
{
form
}
galleryInfo=
{
galleryInfo
}
activeKey=
{
randomOne
}
setPicList=
{
setPicList
}
isOnline=
{
isOnline
}
/>
),
key
:
randomOne
,
forceRender
:
true
}
...
...
@@ -60,7 +57,7 @@ const GalleryModal = props => {
const
[
activeKey
,
setActiveKey
]
=
useState
(
initialItems
[
0
].
key
)
const
[
items
,
setItems
]
=
useState
(
initialItems
)
const
onChange
=
newActiveKey
=>
{
const
onChange
=
(
newActiveKey
)
=>
{
setActiveKey
(
newActiveKey
)
}
const
add
=
()
=>
{
...
...
@@ -71,7 +68,9 @@ const GalleryModal = props => {
const
newActiveKey
=
`
${
random
}
`
newPanes
.
push
({
label
:
`图
${
index
+
1
}
`
,
children
:
<
GalleryFormItem
ossClient=
{
ossClient
}
form=
{
form
}
galleryInfo=
{
galleryInfo
}
activeKey=
{
newActiveKey
}
setPicList=
{
setPicList
}
/>,
children
:
(
<
GalleryFormItem
ossClient=
{
ossClient
}
form=
{
form
}
galleryInfo=
{
galleryInfo
}
activeKey=
{
newActiveKey
}
setPicList=
{
setPicList
}
isOnline=
{
isOnline
}
/>
),
key
:
newActiveKey
,
forceRender
:
true
})
...
...
@@ -82,8 +81,8 @@ const GalleryModal = props => {
setItems
(
newPanes
)
setActiveKey
(
newActiveKey
)
}
const
remove
=
async
targetKey
=>
{
const
tempGallery
=
picList
.
filter
(
item
=>
item
.
key
!==
targetKey
)
const
remove
=
async
(
targetKey
)
=>
{
const
tempGallery
=
picList
.
filter
(
(
item
)
=>
item
.
key
!==
targetKey
)
await
setPicList
(
tempGallery
)
console
.
log
(
tempGallery
)
form
.
setFieldsValue
({
gallery
:
tempGallery
})
...
...
@@ -95,7 +94,7 @@ const GalleryModal = props => {
lastIndex
=
i
-
1
}
})
let
newPanes
=
items
.
filter
(
item
=>
item
.
key
!==
targetKey
)
let
newPanes
=
items
.
filter
(
(
item
)
=>
item
.
key
!==
targetKey
)
if
(
newPanes
.
length
&&
newActiveKey
===
targetKey
)
{
if
(
lastIndex
>=
0
)
{
newActiveKey
=
newPanes
[
lastIndex
].
key
...
...
@@ -169,6 +168,7 @@ const GalleryModal = props => {
form=
{
form
}
setPicList=
{
setPicList
}
activeKey=
{
newActiveKey
}
isOnline=
{
isOnline
}
/>
),
key
:
newActiveKey
,
...
...
@@ -184,7 +184,7 @@ const GalleryModal = props => {
}
},
[
galleryInfo
])
const
onFinish
=
async
values
=>
{
const
onFinish
=
async
(
values
)
=>
{
editor
.
restoreSelection
()
// setLoading(true);
const
{
galleryTitle
,
flex
,
gallery
,
fontSize
,
theme
=
''
}
=
values
...
...
@@ -193,7 +193,7 @@ const GalleryModal = props => {
if
(
parseInt
(
flex
)
!==
2
)
{
// 删除空白的p标签
const
nodeEntries
=
SlateEditor
.
nodes
(
editor
,
{
match
:
node
=>
{
match
:
(
node
)
=>
{
// JS syntax
if
(
SlateElement
.
isElement
(
node
))
{
if
(
node
.
type
===
'paragraph'
)
{
...
...
src/common/wangeditor-customer/components/galleryItem.jsx
浏览文件 @
227c5f8b
...
...
@@ -2,12 +2,13 @@ import { useState, useEffect, useImperativeHandle, forwardRef } from 'react'
import
{
CloudUploadOutlined
}
from
'@ant-design/icons'
import
{
Form
,
Input
,
Spin
,
Upload
,
Button
}
from
'antd'
import
{
partSize
,
normalUploader
,
multipartUploader
}
from
'../utils/upload'
import
OnlineImageList
from
'./onlineImageList'
const
fileAccept
=
[
'.png'
,
'.jpg'
,
'.jpeg'
,
'.svg'
]
const
randomOne
=
Math
.
random
().
toString
(
16
).
substring
(
2
,
10
)
const
GalleryFormItem
=
(
props
,
ref
)
=>
{
const
{
activeKey
,
ossClient
,
form
,
setPicList
,
galleryInfo
}
=
props
const
{
activeKey
,
ossClient
,
form
,
setPicList
,
galleryInfo
,
isOnline
=
false
}
=
props
const
[
uploading
,
setUploading
]
=
useState
(
false
)
// 文件上传状态
const
[
progress
,
setProgress
]
=
useState
(
0
)
...
...
@@ -35,7 +36,7 @@ const GalleryFormItem = (props, ref) => {
if
(
galleryArr
.
length
>
0
)
{
const
values
=
{
[
'content'
]:
{}
}
galleryArr
.
forEach
(
item
=>
{
galleryArr
.
forEach
(
(
item
)
=>
{
values
[
'content'
][
item
.
key
]
=
{
url
:
item
.
url
,
title
:
item
.
title
,
...
...
@@ -44,7 +45,7 @@ const GalleryFormItem = (props, ref) => {
})
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
)
{
const
itemGallery
=
item
[
0
]
setImgUrl
(
itemGallery
.
url
)
...
...
@@ -55,7 +56,7 @@ const GalleryFormItem = (props, ref) => {
useEffect
(()
=>
{},
[])
const
normFile
=
e
=>
{
const
normFile
=
(
e
)
=>
{
if
(
Array
.
isArray
(
e
))
{
return
e
}
...
...
@@ -117,7 +118,7 @@ const GalleryFormItem = (props, ref) => {
}
}
const
changeTitleValue
=
e
=>
{
const
changeTitleValue
=
(
e
)
=>
{
const
allContent
=
form
.
getFieldValue
(
'content'
)
const
newGalleryList
=
[]
// eslint-disable-next-line guard-for-in
...
...
@@ -127,7 +128,30 @@ const GalleryFormItem = (props, ref) => {
setPicList
(
newGalleryList
)
form
.
setFieldsValue
({
gallery
:
newGalleryList
})
}
const
changeDescValue
=
e
=>
{
const
changeDescValue
=
(
e
)
=>
{
const
allContent
=
form
.
getFieldValue
(
'content'
)
const
newGalleryList
=
[]
// eslint-disable-next-line guard-for-in
for
(
let
key
in
allContent
)
{
newGalleryList
.
push
({
...
allContent
[
key
],
key
:
key
})
}
setPicList
(
newGalleryList
)
form
.
setFieldsValue
({
gallery
:
newGalleryList
})
}
const
onOnlineImageChange
=
(
url
)
=>
{
setImgUrl
(
url
)
const
values
=
{
[
'content'
]:
{
[
activeKey
]:
{
url
:
url
,
title
:
''
,
desc
:
''
}
}
}
setImgUrl
(
url
)
form
.
setFieldsValue
({
...
values
})
const
allContent
=
form
.
getFieldValue
(
'content'
)
const
newGalleryList
=
[]
// eslint-disable-next-line guard-for-in
...
...
@@ -140,42 +164,55 @@ const GalleryFormItem = (props, ref) => {
return
(
<>
<
Form
.
Item
label=
"上传图片"
valuePropName=
"fileList"
getValueFromEvent=
{
normFile
}
extra=
"最多可上传10张"
name=
{
[
'content'
,
activeKey
,
'url'
]
}
rules=
{
[{
required
:
true
,
message
:
'请上传画廊图片'
}]
}
>
<
Spin
spinning=
{
uploading
}
tip=
"Loading"
>
<
div
className=
"editor-dragger"
>
<
Upload
.
Dragger
{
...
uploadProps
}
showUploadList=
{
false
}
>
{
!
imgUrl
?
(
<>
<
div
className=
"editor-uploader-process"
>
<
p
className=
"ant-upload-drag-icon"
>
<
CloudUploadOutlined
style=
{
{
fontSize
:
40
}
}
/>
</
p
>
<
p
className=
"ant-upload-text"
>
点击上传或拖拽到此处上传
</
p
>
<
p
className=
"ant-upload-hint"
>
支持上传 .png、.jpg、.jpeg、.svg格式的图片
</
p
>
{
isOnline
?
(
<
Form
.
Item
label=
"在线图片"
valuePropName=
"fileList"
getValueFromEvent=
{
normFile
}
extra=
"最多可上传10张"
name=
{
[
'content'
,
activeKey
,
'url'
]
}
rules=
{
[{
required
:
true
,
message
:
'请选择图片'
}]
}
>
<
OnlineImageList
imgUrl=
{
imgUrl
}
onChange=
{
onOnlineImageChange
}
></
OnlineImageList
>
</
Form
.
Item
>
)
:
(
<
Form
.
Item
label=
"上传图片"
valuePropName=
"fileList"
getValueFromEvent=
{
normFile
}
extra=
"最多可上传10张"
name=
{
[
'content'
,
activeKey
,
'url'
]
}
rules=
{
[{
required
:
true
,
message
:
'请上传画廊图片'
}]
}
>
<
Spin
spinning=
{
uploading
}
tip=
"Loading"
>
<
div
className=
"editor-dragger"
>
<
Upload
.
Dragger
{
...
uploadProps
}
showUploadList=
{
false
}
>
{
!
imgUrl
?
(
<>
<
div
className=
"editor-uploader-process"
>
<
p
className=
"ant-upload-drag-icon"
>
<
CloudUploadOutlined
style=
{
{
fontSize
:
40
}
}
/>
</
p
>
<
p
className=
"ant-upload-text"
>
点击上传或拖拽到此处上传
</
p
>
<
p
className=
"ant-upload-hint"
>
支持上传 .png、.jpg、.jpeg、.svg格式的图片
</
p
>
</
div
>
</>
)
:
(
<
div
className=
"editor-uploader-result"
>
<
div
className=
"editor-uploader-result-img"
>
<
img
src=
{
imgUrl
}
alt=
""
/>
</
div
>
<
div
className=
"editor-uploader-result-tips"
>
<
Button
size=
"small"
type=
"primary"
ghost
onClick=
{
()
=>
setImgUrl
(
null
)
}
>
替换
</
Button
>
</
div
>
</
div
>
</>
)
:
(
<
div
className=
"editor-uploader-result"
>
<
div
className=
"editor-uploader-result-img"
>
<
img
src=
{
imgUrl
}
alt=
""
/>
</
div
>
<
div
className=
"editor-uploader-result-tips"
>
<
Button
size=
"small"
type=
"primary"
ghost
onClick=
{
()
=>
setImgUrl
(
null
)
}
>
替换
</
Button
>
</
div
>
</
div
>
)
}
</
Upload
.
Dragger
>
</
div
>
</
Spin
>
</
Form
.
Item
>
)
}
</
Upload
.
Dragger
>
</
div
>
</
Spin
>
</
Form
.
Item
>
)
}
<
Form
.
Item
label=
"标题"
rules=
{
[{
required
:
false
,
message
:
'请输入图片标题'
}]
}
name=
{
[
'content'
,
activeKey
,
'title'
]
}
extra=
"最多输入100字"
>
<
Input
maxLength=
{
100
}
placeholder=
""
allowClear
onChange=
{
changeTitleValue
}
/>
</
Form
.
Item
>
...
...
src/common/wangeditor-customer/components/image.jsx
浏览文件 @
227c5f8b
...
...
@@ -3,13 +3,14 @@ import { Divider, Upload, Input, Space, Button, Form, Spin, message } from 'antd
import
{
CloudUploadOutlined
}
from
'@ant-design/icons'
import
{
SlateTransforms
,
SlateEditor
,
SlateElement
}
from
'@wangeditor/editor'
import
'./index.less'
import
OnlineImageList
from
'./onlineImageList'
import
{
partSize
,
normalUploader
,
multipartUploader
}
from
'../utils/upload'
const
{
Dragger
}
=
Upload
const
ImageModal
=
(
props
,
ref
)
=>
{
const
{
editor
,
ossClient
,
setImageVisible
,
imageInfo
,
setImageInfo
}
=
props
const
{
editor
,
ossClient
,
setImageVisible
,
imageInfo
,
setImageInfo
,
isOnline
=
false
}
=
props
const
[
imgUrl
,
setImgUrl
]
=
useState
(
''
)
const
fileAccept
=
[
'.png'
,
'.jpg'
,
'.jpeg'
,
'.svg'
]
...
...
@@ -34,7 +35,7 @@ const ImageModal = (props, ref) => {
}
},
[
imageInfo
])
const
normFile
=
e
=>
{
const
normFile
=
(
e
)
=>
{
if
(
Array
.
isArray
(
e
))
{
return
e
}
...
...
@@ -87,7 +88,8 @@ const ImageModal = (props, ref) => {
setImageVisible
(
false
)
}
const
onFinish
=
values
=>
{
const
onFinish
=
(
values
)
=>
{
console
.
log
(
values
)
editor
.
restoreSelection
()
// editor.insertNode({
// type: 'chapterImage',
...
...
@@ -98,7 +100,7 @@ const ImageModal = (props, ref) => {
// });
const
nodeEntries
=
SlateEditor
.
nodes
(
editor
,
{
match
:
node
=>
{
match
:
(
node
)
=>
{
// JS syntax
if
(
SlateElement
.
isElement
(
node
))
{
if
(
node
.
type
===
'paragraph'
)
{
...
...
@@ -179,42 +181,52 @@ const ImageModal = (props, ref) => {
clear
()
}
const
onOnlineImageChange
=
(
url
)
=>
{
setImgUrl
(
url
)
form
.
setFieldsValue
({
imgUrl
:
url
})
}
return
(
<
div
>
<
Divider
/>
<
div
className=
"editor-content-form"
>
<
Form
layout=
"vertical"
name=
"validate_other"
form=
{
form
}
onFinish=
{
onFinish
}
initialValues=
{
initValues
}
>
<
Form
.
Item
label=
"上传图片"
valuePropName=
"fileList"
name=
"imgUrl"
getValueFromEvent=
{
normFile
}
rules=
{
[{
required
:
true
,
message
:
'请上传图片'
}]
}
>
<
Spin
spinning=
{
uploading
}
tip=
{
`${progress}%`
}
>
<
div
className=
"editor-dragger"
>
<
Dragger
{
...
uploadProps
}
showUploadList=
{
false
}
>
{
!
imgUrl
&&
(
<
div
className=
"editor-uploader-process"
>
<
p
className=
"ant-upload-drag-icon"
>
<
CloudUploadOutlined
style=
{
{
fontSize
:
40
}
}
/>
</
p
>
<
p
className=
"ant-upload-text"
>
点击上传或拖拽到此处上传
</
p
>
<
p
className=
"ant-upload-hint"
>
支持上传 .png、.jpg、.jpeg、.svg格式的图片
</
p
>
</
div
>
)
}
{
imgUrl
&&
(
<>
<
div
className=
"editor-uploader-result"
>
<
div
className=
"editor-uploader-result-img"
>
<
img
src=
{
imgUrl
}
alt=
""
/>
</
div
>
<
div
className=
"editor-uploader-result-tips"
>
<
Button
size=
"small"
type=
"primary"
ghost
onClick=
{
()
=>
setImgUrl
(
null
)
}
>
替换
</
Button
>
</
div
>
{
isOnline
?
(
<
Form
.
Item
label=
"在线图片"
name=
"imgUrl"
rules=
{
[{
required
:
true
,
message
:
'请选择图片'
}]
}
>
<
OnlineImageList
imgUrl=
{
imgUrl
}
onChange=
{
onOnlineImageChange
}
></
OnlineImageList
>
</
Form
.
Item
>
)
:
(
<
Form
.
Item
label=
"上传图片"
valuePropName=
"fileList"
name=
"imgUrl"
getValueFromEvent=
{
normFile
}
rules=
{
[{
required
:
true
,
message
:
'请上传图片'
}]
}
>
<
Spin
spinning=
{
uploading
}
tip=
{
`${progress}%`
}
>
<
div
className=
"editor-dragger"
>
<
Dragger
{
...
uploadProps
}
showUploadList=
{
false
}
>
{
!
imgUrl
&&
(
<
div
className=
"editor-uploader-process"
>
<
p
className=
"ant-upload-drag-icon"
>
<
CloudUploadOutlined
style=
{
{
fontSize
:
40
}
}
/>
</
p
>
<
p
className=
"ant-upload-text"
>
点击上传或拖拽到此处上传
</
p
>
<
p
className=
"ant-upload-hint"
>
支持上传 .png、.jpg、.jpeg、.svg格式的图片
</
p
>
</
div
>
</>
)
}
</
Dragger
>
</
div
>
</
Spin
>
</
Form
.
Item
>
)
}
{
imgUrl
&&
(
<>
<
div
className=
"editor-uploader-result"
>
<
div
className=
"editor-uploader-result-img"
>
<
img
src=
{
imgUrl
}
alt=
""
/>
</
div
>
<
div
className=
"editor-uploader-result-tips"
>
<
Button
size=
"small"
type=
"primary"
ghost
onClick=
{
()
=>
setImgUrl
(
null
)
}
>
替换
</
Button
>
</
div
>
</
div
>
</>
)
}
</
Dragger
>
</
div
>
</
Spin
>
</
Form
.
Item
>
)
}
<
Form
.
Item
label=
"图片标题"
name=
"imgTitle"
extra=
"最多输入100字"
>
<
Input
maxLength=
{
100
}
placeholder=
""
allowClear
/>
</
Form
.
Item
>
...
...
src/common/wangeditor-customer/components/index.less
浏览文件 @
227c5f8b
...
...
@@ -125,4 +125,32 @@
display: flex;
justify-content: center;
}
}
\ No newline at end of file
}
.online-image-list {
display: flex;
background: #ffffff;
border-width: 1px;
border-style: solid;
border-color: #d9d9d9;
border-radius: 6px;
padding: 10px;
gap: 10px;
flex-wrap: wrap;
.online-image-list-item {
width: 200px;
height: 100px;
border-radius: 10px;
overflow: hidden;
box-sizing: border-box;
cursor: pointer;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
&.is-active {
border: 4px solid #ab1941;
}
}
}
src/common/wangeditor-customer/components/onlineImageList.jsx
0 → 100644
浏览文件 @
227c5f8b
import
{
getChuangKitDesigns
}
from
'@/api/chuangkit'
import
{
useState
,
useEffect
}
from
'react'
import
{
useSelector
}
from
'react-redux'
export
default
function
OnlineImageList
({
imgUrl
,
onChange
})
{
const
[
list
,
setList
]
=
useState
([])
const
{
userInfo
}
=
useSelector
((
state
)
=>
state
.
user
)
useEffect
(()
=>
{
getChuangKitDesigns
({
params
:
{
time_order
:
1
,
user_flag
:
userInfo
.
id
}
}).
then
((
res
)
=>
{
setList
(
res
.
data
.
list
)
})
},
[
userInfo
])
return
(
<
div
className=
"online-image-list"
>
{
list
.
map
((
item
)
=>
{
return
(
<
div
className=
{
'online-image-list-item '
+
(
imgUrl
===
item
.
thumbUrl
?
'is-active'
:
''
)
}
key=
{
item
.
designId
}
onClick=
{
()
=>
onChange
(
item
.
thumbUrl
)
}
>
<
img
src=
{
item
.
thumbUrl
}
/>
</
div
>
)
})
}
</
div
>
)
}
src/common/wangeditor-customer/customer/Gallery.js
浏览文件 @
227c5f8b
...
...
@@ -2,7 +2,7 @@ import { DomEditor, SlateTransforms, SlateRange } from '@wangeditor/editor';
class
GalleryAuto
{
constructor
()
{
this
.
title
=
'画廊'
this
.
title
=
'
离线
画廊'
this
.
iconSvg
=
`<svg width="24px" height="19px" viewBox="0 0 24 19" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>图标</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
...
...
src/common/wangeditor-customer/customer/GalleryOnline.js
浏览文件 @
227c5f8b
import
{
DomEditor
,
SlateRange
}
from
'@wangeditor/editor'
class
GalleryAuto
{
class
GalleryAuto
Online
{
constructor
()
{
this
.
title
=
'画廊'
this
.
title
=
'
在线
画廊'
this
.
iconSvg
=
`<svg width="24px" height="19px" viewBox="0 0 24 19" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>图标</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
...
...
@@ -39,7 +39,7 @@ class GalleryAuto {
// if (hasVoidElem) return true // 选中了 void 元素,禁用
// eslint-disable-next-line array-callback-return
const
hasPreElem
=
selectedElems
.
some
(
elem
=>
{
const
hasPreElem
=
selectedElems
.
some
(
(
elem
)
=>
{
const
type
=
DomEditor
.
getNodeType
(
elem
)
// 代码块 引用 表格 禁用
if
(
type
===
'pre'
||
type
===
'blockquote'
||
type
===
'table'
||
type
===
'table-row'
||
type
===
'table-cell'
)
return
true
...
...
@@ -53,15 +53,15 @@ class GalleryAuto {
if
(
this
.
isDisabled
(
editor
))
{
return
}
editor
.
emit
(
'GalleryMenuClick'
)
editor
.
emit
(
'Gallery
Online
MenuClick'
)
}
}
export
default
{
key
:
'GalleryAuto'
,
// 定义 menu key :要保证唯一、不重复(重要)
key
:
'GalleryAuto
Online
'
,
// 定义 menu key :要保证唯一、不重复(重要)
factory
()
{
return
new
GalleryAuto
()
// 把 `YourMenuClass` 替换为你菜单的 class
return
new
GalleryAuto
Online
()
// 把 `YourMenuClass` 替换为你菜单的 class
}
}
export
{
GalleryAuto
}
export
{
GalleryAuto
Online
}
src/common/wangeditor-customer/customer/Image.js
浏览文件 @
227c5f8b
...
...
@@ -3,7 +3,7 @@ import { DomEditor, SlateTransforms as Transforms, SlateRange } from '@wangedito
// Extend menu
class
ImageAuto
{
constructor
()
{
this
.
title
=
'图片'
this
.
title
=
'
离线
图片'
this
.
iconSvg
=
`<svg width="23px" height="21px" viewBox="0 0 23 21" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编辑器图片样式</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
...
...
src/common/wangeditor-customer/customer/ImageOnline.js
浏览文件 @
227c5f8b
import
{
DomEditor
,
SlateTransforms
as
Transforms
,
SlateRange
}
from
'@wangeditor/editor'
// Extend menu
class
ImageAuto
{
class
ImageAuto
Online
{
constructor
()
{
this
.
title
=
'图片'
this
.
title
=
'
在线
图片'
this
.
iconSvg
=
`<svg width="23px" height="21px" viewBox="0 0 23 21" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编辑器图片样式</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
...
...
@@ -29,11 +29,11 @@ class ImageAuto {
const
selectedElems
=
DomEditor
.
getSelectedElems
(
editor
)
const
hasVoidElem
=
selectedElems
.
some
(
elem
=>
editor
.
isVoid
(
elem
))
const
hasVoidElem
=
selectedElems
.
some
(
(
elem
)
=>
editor
.
isVoid
(
elem
))
if
(
hasVoidElem
)
return
true
// 选中了 void 元素,禁用
// eslint-disable-next-line array-callback-return
const
hasPreElem
=
selectedElems
.
some
(
elem
=>
{
const
hasPreElem
=
selectedElems
.
some
(
(
elem
)
=>
{
const
type
=
DomEditor
.
getNodeType
(
elem
)
// 代码块 引用 表格 禁用
if
(
type
===
'pre'
||
type
===
'blockquote'
)
return
true
...
...
@@ -48,7 +48,7 @@ class ImageAuto {
exec
(
editor
,
value
)
{
// editor.insertText(value) // value 即 this.getValue(editor) 的返回值
editor
.
emit
(
'ImageMenuClick'
)
editor
.
emit
(
'Image
Online
MenuClick'
)
if
(
this
.
isDisabled
(
editor
))
{
return
...
...
@@ -71,30 +71,30 @@ class ImageAuto {
}
Transforms
.
setNodes
(
editor
,
props
,
{
match
:
n
=>
DomEditor
.
checkNodeType
(
n
,
'chapterImage'
)
match
:
(
n
)
=>
DomEditor
.
checkNodeType
(
n
,
'chapterImage'
)
})
}
}
class
ImageWidthCustomer100
extends
ImageAuto
{
class
ImageWidthCustomer100
extends
ImageAuto
Online
{
title
=
'100%'
// 菜单标题
value
=
'100%'
// css width 的值
}
class
ImageWidthCustomer50
extends
ImageAuto
{
class
ImageWidthCustomer50
extends
ImageAuto
Online
{
title
=
'50%'
// 菜单标题
value
=
'50%'
// css width 的值
}
class
ImageWidthCustomer30
extends
ImageAuto
{
class
ImageWidthCustomer30
extends
ImageAuto
Online
{
title
=
'30%'
// 菜单标题
value
=
'30%'
// css width 的值
}
export
default
{
key
:
'ImageAuto'
,
// 定义 menu key :要保证唯一、不重复(重要)
key
:
'ImageAuto
Online
'
,
// 定义 menu key :要保证唯一、不重复(重要)
factory
()
{
return
new
ImageAuto
()
// 把 `YourMenuClass` 替换为你菜单的 class
return
new
ImageAuto
Online
()
// 把 `YourMenuClass` 替换为你菜单的 class
}
}
...
...
@@ -119,4 +119,4 @@ const imageWidth30MenuChapterConf = {
}
}
export
{
ImageAuto
,
imageWidth100MenuChapterConf
,
imageWidth50MenuChapterConf
,
imageWidth30MenuChapterConf
}
export
{
ImageAuto
Online
,
imageWidth100MenuChapterConf
,
imageWidth50MenuChapterConf
,
imageWidth30MenuChapterConf
}
src/common/wangeditor-customer/index.jsx
浏览文件 @
227c5f8b
import
React
,
{
useState
,
useEffect
,
useRef
,
forwardRef
,
useImperativeHandle
}
from
'react'
import
{
Input
,
Spin
,
message
,
Button
,
Divider
,
Space
,
Modal
,
Row
,
Drawer
}
from
'antd'
import
{
useState
,
useEffect
,
useRef
,
forwardRef
,
useImperativeHandle
}
from
'react'
import
{
Button
,
Divider
,
Space
,
Modal
,
Drawer
}
from
'antd'
import
{
EyeOutlined
,
SaveOutlined
,
CloseOutlined
,
HistoryOutlined
}
from
'@ant-design/icons'
import
AliOSS
from
'ali-oss'
import
dayjs
from
'dayjs'
...
...
@@ -7,7 +7,7 @@ import './utils/iconfont'
import
{
useSelector
,
useDispatch
}
from
'react-redux'
import
{
setPracticeRandom
}
from
'@/store/modules/editor'
import
formulaEditor
from
'easy-formula-editor'
//
import formulaEditor from 'easy-formula-editor'
import
'./utils/jax.less'
import
{
Boot
}
from
'@wangeditor/editor'
...
...
@@ -24,7 +24,9 @@ import { storageChange } from '@/utils/storage.js'
// import PaddingSpace from './customer/padding';
import
ImageAutoOnlineConf
from
'./customer/ImageOnline'
import
GalleryAutoConf
from
'./customer/Gallery'
import
GalleryAutoOnlineConf
from
'./customer/GalleryOnline'
import
VideoAutoConf
from
'./customer/Video'
import
AudioAutoConf
from
'./customer/Audio'
import
ChapterTitleAutoConf
from
'./customer/ChapterTitle'
...
...
@@ -75,21 +77,12 @@ import PreviewModal from './components/preview'
import
HistoryModal
from
'./history/'
import
$
from
'jquery'
import
{
getInfoByChapterId
}
from
'@/pages/books/section/request'
import
{
getAliOSSSTSToken
,
getRecordInfo
}
from
'./utils/request'
import
{
getAliOSSSTSToken
}
from
'./utils/request'
import
'./index.less'
const
jsonContent
=
[
{
type
:
'paragraph'
,
lineHeight
:
'1.5'
,
children
:
[{
text
:
''
,
fontFamily
:
'黑体'
,
fontSize
:
'16px'
}]
}
]
const
menuArr0
=
[
'重做'
,
'撤销'
]
const
menuArr1
=
[
'字体样式'
,
'字号'
,
'行高'
]
const
menuArr2
=
[
'
图片'
,
'
画廊'
,
'视频'
,
'音频'
,
'表格'
]
const
menuArr2
=
[
'
离线图片'
,
'在线图片'
,
'离线画廊'
,
'在线
画廊'
,
'视频'
,
'音频'
,
'表格'
]
const
menuArr3
=
[
'代码块'
,
'引用'
,
'链接'
,
'公式'
,
'章头'
,
'节头'
,
'交互练习'
,
'气泡'
,
'扩展阅读'
]
const
menuArr4
=
[
'改写'
,
'扩写'
,
'缩写'
,
'总结'
]
const
colorList
=
[
'#ab1941'
,
'#2970f6'
,
'#2ad882'
,
'#eb3351'
]
...
...
@@ -98,7 +91,9 @@ const bookBucketName = 'zxts-book-file'
const
module
=
{
menus
:
[
// ImageAutoConf,
ImageAutoOnlineConf
,
GalleryAutoConf
,
GalleryAutoOnlineConf
,
VideoAutoConf
,
AudioAutoConf
,
FormulaAutoConf
,
...
...
@@ -150,15 +145,13 @@ const tabsMenu = [
storageChange
()
const
WangEditorCustomer
=
(
props
,
ref
)
=>
{
const
{
chapterId
,
bookId
,
contentId
,
html
,
setHtml
,
saveContent
,
gData
,
nowTitle
,
recordList
}
=
props
const
{
chapterId
,
bookId
,
contentId
,
html
,
setHtml
,
saveContent
,
gData
,
nowTitle
}
=
props
const
dispatch
=
useDispatch
()
// 自动保存时间
const
{
autosaveTime
}
=
useSelector
(
state
=>
state
.
editor
)
const
{
autosaveTime
}
=
useSelector
(
(
state
)
=>
state
.
editor
)
const
toolbarRef
=
useRef
()
const
paddingSpaceRef
=
useRef
()
const
[
cId
,
setCId
]
=
useState
(
contentId
)
const
[
ossClient
,
setOssClient
]
=
useState
(
null
)
// oss 操作
const
[
STSToken
,
setSTSToken
]
=
useState
(
null
)
// oss 过期设置
...
...
@@ -167,7 +160,6 @@ const WangEditorCustomer = (props, ref) => {
const
[
loading
,
setLoading
]
=
useState
(
true
)
// editor 实例
const
[
editor
,
setEditor
]
=
useState
(
null
)
const
[
editorNodes
,
setEditorNodes
]
=
useState
(
null
)
const
[
content
,
setContent
]
=
useState
(
html
)
const
saveRef
=
useRef
()
...
...
@@ -193,11 +185,11 @@ const WangEditorCustomer = (props, ref) => {
const
[
priviewVisible
,
setPriviewVisible
]
=
useState
(
false
)
const
[
historyVisible
,
setHistoryVisible
]
=
useState
(
false
)
//点击历史
const
[
delMoadal
,
setDelModal
]
=
useState
(
false
)
const
[
selectedRecordName
,
setSelectedRecordName
]
=
useState
(
''
)
const
[
selectionSize
,
setSelectionSize
]
=
useState
(
16
)
// 当前字号大小
const
[
isOnline
,
setIsOnline
]
=
useState
(
false
)
window
.
addEventListener
(
'setItemEvent'
,
function
(
e
)
{
if
(
e
.
key
===
'chapterTitleNum'
)
{
setTitleInfo
(
JSON
.
parse
(
e
.
newValue
))
...
...
@@ -256,7 +248,7 @@ const WangEditorCustomer = (props, ref) => {
}
})
const
listenNodeStyle
=
path
=>
{
const
listenNodeStyle
=
(
path
)
=>
{
const
children
=
editor
.
children
let
node
=
null
if
(
path
[
1
]
===
0
)
{
...
...
@@ -384,7 +376,9 @@ const WangEditorCustomer = (props, ref) => {
index
:
30
,
keys
:
[
'ImageAuto'
,
'ImageAutoOnline'
,
'GalleryAuto'
,
'GalleryAutoOnline'
,
'VideoAuto'
,
'AudioAuto'
,
'CustomerLink'
,
...
...
@@ -537,7 +531,9 @@ const WangEditorCustomer = (props, ref) => {
const
itemBox4
=
document
.
createElement
(
'div'
)
itemBox4
.
setAttribute
(
'class'
,
'custom-bar-box media'
)
toolbarElement
.
insertBefore
(
itemBox4
,
allChildren
[
8
])
console
.
log
(
$
(
allChildren
[
8
]),
$
(
allChildren
[
13
]),
$
(
allChildren
[
9
]))
$
(
allChildren
[
8
]).
append
(
$
(
allChildren
[
13
]).
detach
())
$
(
allChildren
[
8
]).
append
(
$
(
allChildren
[
13
]).
detach
())
$
(
allChildren
[
8
]).
append
(
$
(
allChildren
[
13
]).
detach
())
$
(
allChildren
[
8
]).
append
(
$
(
allChildren
[
13
]).
detach
())
$
(
allChildren
[
8
]).
append
(
$
(
allChildren
[
13
]).
detach
())
...
...
@@ -609,18 +605,18 @@ const WangEditorCustomer = (props, ref) => {
setLoading
(
false
)
},
350
)
}
editorConfig
.
onCreated
=
editor
=>
{
editorConfig
.
onCreated
=
(
editor
)
=>
{
setLoading
(
true
)
}
editorConfig
.
onFocus
=
editor
=>
{
editorConfig
.
onFocus
=
(
editor
)
=>
{
clearTimeout
(
saveRef
.
current
)
}
editorConfig
.
onBlur
=
editor
=>
{
editorConfig
.
onBlur
=
(
editor
)
=>
{
// 失焦保存
setHtml
(
editor
.
getHtml
())
setContent
(
editor
.
getHtml
())
}
editorConfig
.
onChange
=
editor
=>
{
editorConfig
.
onChange
=
(
editor
)
=>
{
setHtml
(
editor
.
getHtml
())
setContent
(
editor
.
getHtml
())
}
...
...
@@ -635,6 +631,13 @@ const WangEditorCustomer = (props, ref) => {
// 图片上传
editor
.
on
(
'ImageMenuClick'
,
()
=>
{
console
.
log
(
'ImageMenuClick'
,
'----'
)
setIsOnline
(
false
)
setImageVisible
(
true
)
})
// 在线图片
editor
.
on
(
'ImageOnlineMenuClick'
,
()
=>
{
console
.
log
(
'ImageOnlineMenuClick'
,
'----'
)
setIsOnline
(
true
)
setImageVisible
(
true
)
})
// 画廊上传
...
...
@@ -644,6 +647,17 @@ const WangEditorCustomer = (props, ref) => {
}
console
.
log
(
'GalleryMenuClick'
,
'----'
)
// galleryRef.current.setVisible(true);
setIsOnline
(
false
)
setGalleryVisible
(
true
)
})
// 在线画廊
editor
.
on
(
'GalleryOnlineMenuClick'
,
()
=>
{
if
(
editor
.
selection
)
{
listenNodeStyle
(
editor
.
selection
.
anchor
.
path
)
}
console
.
log
(
'GalleryOnlineMenuClick'
,
'----'
)
// galleryRef.current.setVisible(true);
setIsOnline
(
true
)
setGalleryVisible
(
true
)
})
// 视频上传
...
...
@@ -681,7 +695,7 @@ const WangEditorCustomer = (props, ref) => {
console
.
log
(
'ImageEditorClick'
,
'----'
)
const
nodeEntries
=
SlateEditor
.
nodes
(
editor
,
{
match
:
node
=>
{
match
:
(
node
)
=>
{
// JS syntax
if
(
SlateElement
.
isElement
(
node
))
{
if
(
node
.
type
===
'paragraph'
)
{
...
...
@@ -707,6 +721,7 @@ const WangEditorCustomer = (props, ref) => {
info
.
path
=
path
}
setImageInfo
(
info
)
setIsOnline
(
false
)
setImageVisible
(
true
)
})
// 气泡
...
...
@@ -799,7 +814,7 @@ const WangEditorCustomer = (props, ref) => {
}
},
[
gData
,
editor
])
const
tabKeyChange
=
key
=>
{
const
tabKeyChange
=
(
key
)
=>
{
if
(
key
===
'text'
)
{
toolSetttingReplace
()
}
...
...
@@ -883,15 +898,15 @@ const WangEditorCustomer = (props, ref) => {
})()
},
[])
const
setColor
=
type
=>
{
const
setColor
=
(
type
)
=>
{
const
headers
=
document
.
querySelectorAll
(
`.w-e-scroll .chapter-item-header`
)
const
sections
=
document
.
querySelectorAll
(
`.w-e-scroll .chapter-item-section`
)
headers
.
forEach
(
item
=>
{
headers
.
forEach
(
(
item
)
=>
{
const
node
=
DomEditor
.
toSlateNode
(
editor
,
item
)
const
path
=
DomEditor
.
findPath
(
editor
,
node
)
SlateTransforms
.
setNodes
(
editor
,
{
...
node
,
textColor
:
'#ffffff'
,
bgColor
:
colorList
[
type
-
1
]
},
{
at
:
path
})
})
sections
.
forEach
(
item
=>
{
sections
.
forEach
(
(
item
)
=>
{
const
node
=
DomEditor
.
toSlateNode
(
editor
,
item
)
const
path
=
DomEditor
.
findPath
(
editor
,
node
)
SlateTransforms
.
setNodes
(
editor
,
{
...
node
,
textColor
:
'#ffffff'
,
bgColor
:
colorList
[
type
-
1
]
},
{
at
:
path
})
...
...
@@ -948,7 +963,7 @@ const WangEditorCustomer = (props, ref) => {
<
div
className=
"tabs"
>
{
tabsMenu
&&
tabsMenu
.
length
&&
tabsMenu
.
map
(
item
=>
{
tabsMenu
.
map
(
(
item
)
=>
{
return
(
<
div
className=
{
`tabs-item ${item.key === tabKey ? 'active' : ''}`
}
key=
{
item
.
key
}
onClick=
{
()
=>
tabKeyChange
(
item
.
key
)
}
>
{
item
.
title
}
...
...
@@ -1028,6 +1043,7 @@ const WangEditorCustomer = (props, ref) => {
onCancel=
{
()
=>
setImageVisible
(
false
)
}
>
<
ImageModal
ref=
{
imageRef
}
isOnline=
{
isOnline
}
editor=
{
editor
}
ossClient=
{
ossClient
}
STSToken=
{
STSToken
}
...
...
@@ -1053,6 +1069,7 @@ const WangEditorCustomer = (props, ref) => {
width=
"800px"
>
<
GalleryModal
ref=
{
galleryRef
}
isOnline=
{
isOnline
}
editor=
{
editor
}
ossClient=
{
ossClient
}
STSToken=
{
STSToken
}
...
...
src/common/wangeditor-customer/node/gallery.js
浏览文件 @
227c5f8b
差异被折叠。
点击展开。
src/common/wangeditor-customer/node/galleryInline.js
浏览文件 @
227c5f8b
import
{
DomEditor
,
SlateTransforms
,
SlateEditor
,
SlateElement
,
SlateNode
,
}
from
'@wangeditor/editor'
;
import
{
h
}
from
'snabbdom'
;
import
$
from
'jquery'
;
import
iconGalleryInline
from
'@/assets/images/editor/icon_gallery_editor.png'
;
import
{
DomEditor
,
SlateTransforms
}
from
'@wangeditor/editor'
import
{
h
}
from
'snabbdom'
const
withGalleryInlineNode
=
(
editor
)
=>
{
const
{
isInline
,
isVoid
,
normalizeNode
}
=
editor
;
const
newEditor
=
editor
;
const
{
isInline
,
isVoid
,
normalizeNode
}
=
editor
const
newEditor
=
editor
newEditor
.
isInline
=
(
elem
)
=>
{
const
type
=
DomEditor
.
getNodeType
(
elem
)
;
if
(
type
===
'chapterGalleryInline'
)
return
true
;
// 设置为 inline
return
isInline
(
elem
)
;
}
;
const
type
=
DomEditor
.
getNodeType
(
elem
)
if
(
type
===
'chapterGalleryInline'
)
return
true
// 设置为 inline
return
isInline
(
elem
)
}
newEditor
.
isVoid
=
(
elem
)
=>
{
const
type
=
DomEditor
.
getNodeType
(
elem
)
;
if
(
type
===
'chapterGalleryInline'
)
return
true
;
// 设置为 void
return
isVoid
(
elem
)
;
}
;
const
type
=
DomEditor
.
getNodeType
(
elem
)
if
(
type
===
'chapterGalleryInline'
)
return
true
// 设置为 void
return
isVoid
(
elem
)
}
// 重新 normalize
newEditor
.
normalizeNode
=
([
node
,
path
])
=>
{
const
type
=
DomEditor
.
getNodeType
(
node
)
;
const
type
=
DomEditor
.
getNodeType
(
node
)
if
(
type
!==
'chapterGalleryInline'
)
{
// 未命中 chapterGalleryInline ,执行默认的 normalizeNode
return
normalizeNode
([
node
,
path
])
;
return
normalizeNode
([
node
,
path
])
}
const
topLevelNodes
=
newEditor
.
children
||
[]
;
const
nextNode
=
topLevelNodes
[
path
[
0
]]
||
{}
;
const
topLevelNodes
=
newEditor
.
children
||
[]
const
nextNode
=
topLevelNodes
[
path
[
0
]]
||
{}
if
(
nextNode
.
type
===
'paragraph'
)
{
const
lastChild
=
nextNode
.
children
[
nextNode
.
children
.
length
-
1
];
const
lastChild
=
nextNode
.
children
[
nextNode
.
children
.
length
-
1
]
if
(
lastChild
.
type
===
'chapterExpandReadSimple'
)
{
SlateTransforms
.
insertNodes
(
newEditor
,
{
type
:
'span'
,
children
:
[{
text
:
''
}]
},
{
at
:
path
,
// 在 link-card 后面插入
});
SlateTransforms
.
insertNodes
(
newEditor
,
{
type
:
'span'
,
children
:
[{
text
:
''
}]
},
{
at
:
path
// 在 link-card 后面插入
}
)
}
}
}
;
}
return
newEditor
;
// 返回 newEditor ,重要!!!
}
;
return
newEditor
// 返回 newEditor ,重要!!!
}
// 在编辑器中渲染新元素
// 定义 renderElem 函数
const
renderGalleryInline
=
(
elem
,
children
,
editor
)
=>
{
// 获取“附件”的数据,参考上文 myResume 数据结构
const
{
title
=
''
,
galleryList
=
''
,
random
=
''
,
flex
=
1
,
theme
=
'#ab1941'
,
fontsize
=
18
,
callback
,
}
=
elem
;
const
str
=
`<svg class="svg-icon" style="color:
${
theme
}
; fill: currentColor; overflow: hidden; width:
${
fontsize
}
px; height:
${
fontsize
}
px;" aria-hidden="true"><use xlink:href="#icon-hualangshangchuan"></use></svg>`
;
const
{
title
=
''
,
galleryList
=
''
,
random
=
''
,
flex
=
1
,
theme
=
'#ab1941'
,
fontsize
=
18
,
callback
}
=
elem
const
str
=
`<svg class="svg-icon" style="color:
${
theme
}
; fill: currentColor; overflow: hidden; width:
${
fontsize
}
px; height:
${
fontsize
}
px;" aria-hidden="true"><use xlink:href="#icon-hualangshangchuan"></use></svg>`
const
span
=
h
(
'span'
,
...
...
@@ -72,7 +60,7 @@ const renderGalleryInline = (elem, children, editor) => {
width
:
`
${
fontsize
}
px`
,
height
:
`
${
fontsize
}
px`
,
alignItems
:
'center'
,
display
:
'inline-flex'
,
display
:
'inline-flex'
},
dataset
:
{
galleryList
:
galleryList
,
...
...
@@ -80,12 +68,12 @@ const renderGalleryInline = (elem, children, editor) => {
flex
:
flex
,
theme
,
title
,
fontsize
,
fontsize
},
on
:
{
click
(
ev
)
{
ev
.
stopPropagation
()
;
ev
.
preventDefault
()
;
ev
.
stopPropagation
()
ev
.
preventDefault
()
localStorage
.
setItem
(
'galleryNum'
,
...
...
@@ -96,11 +84,11 @@ const renderGalleryInline = (elem, children, editor) => {
galleryList
:
galleryList
,
flex
:
flex
,
theme
,
fontsize
,
})
,
)
;
}
,
}
,
fontsize
})
)
}
}
},
[
h
(
'span'
,
{
...
...
@@ -108,49 +96,42 @@ const renderGalleryInline = (elem, children, editor) => {
style
:
{
width
:
`
${
fontsize
}
px`
,
height
:
`
${
fontsize
}
px`
,
marginLeft
:
'2px'
,
}
,
marginLeft
:
'2px'
}
}),
h
(
'span'
,
{},
[
''
])
]
,
)
;
return
span
;
}
;
]
)
return
span
}
const
renderElemConf
=
{
type
:
'chapterGalleryInline'
,
renderElem
:
renderGalleryInline
,
}
;
renderElem
:
renderGalleryInline
}
// 把新元素转换为 HTML
const
chapterGalleryInlineToHtml
=
(
elem
,
childrenHtml
)
=>
{
// console.log('chapterGalleryInlineToHtml', elem);
// 获取附件元素的数据
const
{
title
=
''
,
galleryList
=
[],
random
=
''
,
theme
=
'#ab1941'
,
flex
=
1
,
fontsize
=
18
,
}
=
elem
;
const
str
=
`<svg class="svg-icon" style="color:
${
theme
}
; fill: currentColor; overflow: hidden; width:
${
fontsize
}
px; height:
${
fontsize
}
px;" aria-hidden="true"><use xlink:href="#icon-hualangshangchuan"></use></svg>`
;
return
`<span class="chapter-gallery-container chapter-gallery-inline" data-w-e-type="chapterGalleryInline" data-galleryList="
${
galleryList
}
" data-random="
${
random
}
" data-title="
${
title
}
" data-theme="
${
theme
}
" data-fontsize="
${
fontsize
}
" data-flex="
${
flex
}
" style="cursor: pointer; display: inline-flex; align-items: center; width:
${
fontsize
}
px; height:
${
fontsize
}
px; margin: 0 2px;">
${
str
}
</span>`
;
};
const
{
title
=
''
,
galleryList
=
[],
random
=
''
,
theme
=
'#ab1941'
,
flex
=
1
,
fontsize
=
18
}
=
elem
const
str
=
`<svg class="svg-icon" style="color:
${
theme
}
; fill: currentColor; overflow: hidden; width:
${
fontsize
}
px; height:
${
fontsize
}
px;" aria-hidden="true"><use xlink:href="#icon-hualangshangchuan"></use></svg>`
return
`<span class="chapter-gallery-container chapter-gallery-inline" data-w-e-type="chapterGalleryInline" data-galleryList="
${
galleryList
}
" data-random="
${
random
}
" data-title="
${
title
}
" data-theme="
${
theme
}
" data-fontsize="
${
fontsize
}
" data-flex="
${
flex
}
" style="cursor: pointer; display: inline-flex; align-items: center; width:
${
fontsize
}
px; height:
${
fontsize
}
px; margin: 0 2px;">
${
str
}
</span>`
}
const
chapterGalleryInlineElemToHtmlConf
=
{
type
:
'chapterGalleryInline'
,
// 新元素的 type ,重要!!!
elemToHtml
:
chapterGalleryInlineToHtml
,
}
;
elemToHtml
:
chapterGalleryInlineToHtml
}
// 解析新元素 HTML 到编辑器
const
parseGalleryInlineHtml
=
(
domElem
,
children
,
editor
)
=>
{
// 从 DOM element 中获取“附件”的信息
const
galleryList
=
domElem
.
getAttribute
(
'data-galleryList'
)
||
''
;
const
title
=
domElem
.
getAttribute
(
'data-title'
)
||
''
;
const
random
=
domElem
.
getAttribute
(
'data-random'
)
||
''
;
const
flex
=
domElem
.
getAttribute
(
'data-flex'
)
||
1
;
const
theme
=
domElem
.
getAttribute
(
'data-theme'
)
||
'#ab1941'
;
const
fontsize
=
domElem
.
getAttribute
(
'data-fontsize'
)
||
18
;
const
galleryList
=
domElem
.
getAttribute
(
'data-galleryList'
)
||
''
const
title
=
domElem
.
getAttribute
(
'data-title'
)
||
''
const
random
=
domElem
.
getAttribute
(
'data-random'
)
||
''
const
flex
=
domElem
.
getAttribute
(
'data-flex'
)
||
1
const
theme
=
domElem
.
getAttribute
(
'data-theme'
)
||
'#ab1941'
const
fontsize
=
domElem
.
getAttribute
(
'data-fontsize'
)
||
18
// 生成“附件”元素(按照此前约定的数据结构)
const
myResume
=
{
...
...
@@ -161,27 +142,22 @@ const parseGalleryInlineHtml = (domElem, children, editor) => {
theme
,
fontsize
,
galleryList
:
galleryList
,
children
:
[{
text
:
''
}]
,
// void node 必须有 children ,其中有一个空字符串,重要!!!
}
;
children
:
[{
text
:
''
}]
// void node 必须有 children ,其中有一个空字符串,重要!!!
}
return
myResume
;
}
;
return
myResume
}
const
parseGalleryInlineConf
=
{
selector
:
'span[data-w-e-type="chapterGalleryInline"]'
,
// CSS 选择器,匹配特定的 HTML 标签
parseElemHtml
:
parseGalleryInlineHtml
,
}
;
parseElemHtml
:
parseGalleryInlineHtml
}
const
chapterGalleryInlineModule
=
{
editorPlugin
:
withGalleryInlineNode
,
renderElems
:
[
renderElemConf
],
elemsToHtml
:
[
chapterGalleryInlineElemToHtmlConf
],
parseElemsHtml
:
[
parseGalleryInlineConf
],
};
export
default
chapterGalleryInlineModule
;
export
{
withGalleryInlineNode
,
renderElemConf
,
chapterGalleryInlineElemToHtmlConf
,
parseGalleryInlineConf
,
};
parseElemsHtml
:
[
parseGalleryInlineConf
]
}
export
default
chapterGalleryInlineModule
export
{
withGalleryInlineNode
,
renderElemConf
,
chapterGalleryInlineElemToHtmlConf
,
parseGalleryInlineConf
}
src/common/wangeditor-customer/node/image.jsx
浏览文件 @
227c5f8b
差异被折叠。
点击展开。
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论