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

chore: update

上级 2be389ac
...@@ -15,7 +15,10 @@ import { ...@@ -15,7 +15,10 @@ import {
Radio, Radio,
} from 'antd' } from 'antd'
import { SlateTransforms } from '@wangeditor/editor' import { SlateTransforms } from '@wangeditor/editor'
import { removeSelectedEmptyParagraph } from '../../shared/editor-operations' import {
insertBlockNodesAndFocus,
removeSelectedEmptyParagraph,
} from '../../shared/editor-operations'
const { TextArea } = Input const { TextArea } = Input
import '../ai-research/search.less' import '../ai-research/search.less'
import './image.less' import './image.less'
...@@ -147,7 +150,7 @@ export default function AIImageModal(props) { ...@@ -147,7 +150,7 @@ export default function AIImageModal(props) {
children: [{ text: prompt || 'AI生成的图片' }], children: [{ text: prompt || 'AI生成的图片' }],
} }
SlateTransforms.insertNodes(editor, [oImg, oP]) insertBlockNodesAndFocus(editor, SlateTransforms, [oImg, oP])
message.success('图片已插入编辑器!') message.success('图片已插入编辑器!')
setIsModalOpen(false) setIsModalOpen(false)
} else { } else {
......
...@@ -20,7 +20,10 @@ import { ...@@ -20,7 +20,10 @@ import {
InputNumber, InputNumber,
} from 'antd' } from 'antd'
import { SlateTransforms } from '@wangeditor/editor' import { SlateTransforms } from '@wangeditor/editor'
import { removeSelectedEmptyParagraph } from '../../shared/editor-operations' import {
insertBlockNodesAndFocus,
removeSelectedEmptyParagraph,
} from '../../shared/editor-operations'
import { useVideo } from '@ezijing/ai-react' import { useVideo } from '@ezijing/ai-react'
import { uploadFileByUrl } from '@/utils/oss' import { uploadFileByUrl } from '@/utils/oss'
import '../ai-research/search.less' import '../ai-research/search.less'
...@@ -128,7 +131,7 @@ export default function AIVideoModal(props) { ...@@ -128,7 +131,7 @@ export default function AIVideoModal(props) {
editor.restoreSelection() editor.restoreSelection()
removeEmptyParagraph(editor) removeEmptyParagraph(editor)
SlateTransforms.insertNodes(editor, { insertBlockNodesAndFocus(editor, SlateTransforms, {
type: 'chapterVideo', type: 'chapterVideo',
videoUrl: ossUrl, videoUrl: ossUrl,
title: videoPrompt || 'AI生成的视频', title: videoPrompt || 'AI生成的视频',
......
...@@ -26,7 +26,10 @@ import { saveAs } from 'file-saver' ...@@ -26,7 +26,10 @@ import { saveAs } from 'file-saver'
import { uploadFileByUrl } from '@/utils/oss' import { uploadFileByUrl } from '@/utils/oss'
import useDigitalHuman from '@/components/editor/hooks/useDigitalHuman' import useDigitalHuman from '@/components/editor/hooks/useDigitalHuman'
import './digital-human.less' import './digital-human.less'
import { removeSelectedEmptyParagraph } from '../../shared/editor-operations' import {
insertBlockNodesAndFocus,
removeSelectedEmptyParagraph,
} from '../../shared/editor-operations'
const { TextArea } = Input const { TextArea } = Input
...@@ -100,7 +103,7 @@ export default function AIDigitalHumanModal(props) { ...@@ -100,7 +103,7 @@ export default function AIDigitalHumanModal(props) {
if (editor) { if (editor) {
editor.restoreSelection() editor.restoreSelection()
removeSelectedEmptyParagraph(editor, SlateTransforms) removeSelectedEmptyParagraph(editor, SlateTransforms)
SlateTransforms.insertNodes(editor, { insertBlockNodesAndFocus(editor, SlateTransforms, {
type: 'chapterVideo', type: 'chapterVideo',
videoUrl: ossUrl, videoUrl: ossUrl,
title: `${generatedVideo.figureName} - AI播报`, title: `${generatedVideo.figureName} - AI播报`,
......
...@@ -4,7 +4,10 @@ import { CloudUploadOutlined } from '@ant-design/icons' ...@@ -4,7 +4,10 @@ import { CloudUploadOutlined } from '@ant-design/icons'
import { SlateTransforms } from '@wangeditor/editor' import { SlateTransforms } from '@wangeditor/editor'
import '../../index.less' import '../../index.less'
import { uploadFile } from '@/utils/oss' import { uploadFile } from '@/utils/oss'
import { removeSelectedEmptyParagraph } from '../../shared/editor-operations' import {
insertBlockNodesAndFocus,
removeSelectedEmptyParagraph,
} from '../../shared/editor-operations'
const { Dragger } = Upload const { Dragger } = Upload
...@@ -70,7 +73,7 @@ const AudioModal = ({ open, onClose, payload = {}, runtime }) => { ...@@ -70,7 +73,7 @@ const AudioModal = ({ open, onClose, payload = {}, runtime }) => {
removeSelectedEmptyParagraph(editor, SlateTransforms) removeSelectedEmptyParagraph(editor, SlateTransforms)
SlateTransforms.insertNodes(editor, { insertBlockNodesAndFocus(editor, SlateTransforms, {
type: 'chapterAudio', type: 'chapterAudio',
audioUrl: values.audioUrl, audioUrl: values.audioUrl,
title: values.audioTitle, title: values.audioTitle,
......
...@@ -12,7 +12,10 @@ import { ...@@ -12,7 +12,10 @@ import {
Col, Col,
} from 'antd' } from 'antd'
import { SlateEditor, SlateTransforms, SlateElement } from '@wangeditor/editor' import { SlateEditor, SlateTransforms, SlateElement } from '@wangeditor/editor'
import { removeSelectedEmptyParagraph } from '../../shared/editor-operations' import {
insertBlockNodesAndFocus,
removeSelectedEmptyParagraph,
} from '../../shared/editor-operations'
import { fontFamilyList, fontSizeList } from '../../shared/editor-settings' import { fontFamilyList, fontSizeList } from '../../shared/editor-settings'
import '../../index.less' import '../../index.less'
...@@ -104,7 +107,7 @@ const ChapterItemModal = (props, ref) => { ...@@ -104,7 +107,7 @@ const ChapterItemModal = (props, ref) => {
} }
const random = Math.random().toString(10).substring(2, 10) const random = Math.random().toString(10).substring(2, 10)
editor.insertNode({ insertBlockNodesAndFocus(editor, SlateTransforms, {
type: 'chapterSection', type: 'chapterSection',
title: values.title, title: values.title,
textColor: values.textColor, textColor: values.textColor,
...@@ -235,7 +238,6 @@ const ChapterItemModal = (props, ref) => { ...@@ -235,7 +238,6 @@ const ChapterItemModal = (props, ref) => {
controls={false} controls={false}
placeholder='' placeholder=''
style={{ width: '100%', textAlign: 'left' }} style={{ width: '100%', textAlign: 'left' }}
allowClear
/> />
</Form.Item> </Form.Item>
</Col> </Col>
......
...@@ -16,7 +16,10 @@ import { ...@@ -16,7 +16,10 @@ import {
} from 'antd' } from 'antd'
import { CloudUploadOutlined } from '@ant-design/icons' import { CloudUploadOutlined } from '@ant-design/icons'
import { SlateEditor, SlateTransforms, SlateElement } from '@wangeditor/editor' import { SlateEditor, SlateTransforms, SlateElement } from '@wangeditor/editor'
import { removeSelectedEmptyParagraph } from '../../shared/editor-operations' import {
insertBlockNodesAndFocus,
removeSelectedEmptyParagraph,
} from '../../shared/editor-operations'
import { fontFamilyList, fontSizeList } from '../../shared/editor-settings' import { fontFamilyList, fontSizeList } from '../../shared/editor-settings'
import '../../index.less' import '../../index.less'
...@@ -161,7 +164,7 @@ const ImageModal = (props, ref) => { ...@@ -161,7 +164,7 @@ const ImageModal = (props, ref) => {
const docBody = parser.parseFromString(html, 'text/html') const docBody = parser.parseFromString(html, 'text/html')
const section = docBody.body.querySelectorAll('.chapter-item-header') // 是否存在章头 const section = docBody.body.querySelectorAll('.chapter-item-header') // 是否存在章头
editor.insertNode({ insertBlockNodesAndFocus(editor, SlateTransforms, {
type: 'chapterHeader', type: 'chapterHeader',
title: values.title, title: values.title,
textColor: values.textColor, textColor: values.textColor,
...@@ -347,7 +350,6 @@ const ImageModal = (props, ref) => { ...@@ -347,7 +350,6 @@ const ImageModal = (props, ref) => {
controls={false} controls={false}
placeholder='' placeholder=''
style={{ width: '100%', textAlign: 'left' }} style={{ width: '100%', textAlign: 'left' }}
allowClear
/> />
</Form.Item> </Form.Item>
</Col> </Col>
......
...@@ -21,6 +21,7 @@ import '../../index.less' ...@@ -21,6 +21,7 @@ import '../../index.less'
import { addExpandRead, expandReadInfo } from '../../shared/request' import { addExpandRead, expandReadInfo } from '../../shared/request'
import { import {
findElementPathByAttribute, findElementPathByAttribute,
insertBlockNodesAndFocus,
removeSelectedEmptyParagraph, removeSelectedEmptyParagraph,
} from '../../shared/editor-operations' } from '../../shared/editor-operations'
...@@ -148,7 +149,7 @@ const ExpandModal = (props, ref) => { ...@@ -148,7 +149,7 @@ const ExpandModal = (props, ref) => {
}) })
if (parseInt(values.flex) === 1) { if (parseInt(values.flex) === 1) {
editor.insertNode({ insertBlockNodesAndFocus(editor, SlateTransforms, {
type: 'chapterExpandRead', type: 'chapterExpandRead',
flex: parseInt(values.flex), flex: parseInt(values.flex),
name: values.name, name: values.name,
......
...@@ -5,7 +5,10 @@ import { addGallery } from '../../shared/request' ...@@ -5,7 +5,10 @@ import { addGallery } from '../../shared/request'
import { SlateTransforms } from '@wangeditor/editor' import { SlateTransforms } from '@wangeditor/editor'
import { findNodeWithParent, fontSizeList } from '../../shared/editor-settings' import { findNodeWithParent, fontSizeList } from '../../shared/editor-settings'
import { removeSelectedEmptyParagraph } from '../../shared/editor-operations' import {
insertBlockNodesAndFocus,
removeSelectedEmptyParagraph,
} from '../../shared/editor-operations'
import GalleryFormItem from './GalleryItem' import GalleryFormItem from './GalleryItem'
const randomOne = Math.random().toString(16).substring(2, 10) const randomOne = Math.random().toString(16).substring(2, 10)
...@@ -274,7 +277,7 @@ const GalleryModal = (props, ref) => { ...@@ -274,7 +277,7 @@ const GalleryModal = (props, ref) => {
children: [{ text: '' }], children: [{ text: '' }],
}) })
} else { } else {
editor.insertNode({ insertBlockNodesAndFocus(editor, SlateTransforms, {
type: 'chapterGallery', type: 'chapterGallery',
title: galleryTitle, title: galleryTitle,
galleryList: encodeURI(JSON.stringify(gallery)), galleryList: encodeURI(JSON.stringify(gallery)),
......
...@@ -4,7 +4,10 @@ import { CloudUploadOutlined } from '@ant-design/icons' ...@@ -4,7 +4,10 @@ import { CloudUploadOutlined } from '@ant-design/icons'
import { DomEditor, SlateTransforms } from '@wangeditor/editor' import { DomEditor, SlateTransforms } from '@wangeditor/editor'
import '../../index.less' import '../../index.less'
import OnlineImageList from '../../shared/online-image/OnlineImageList' import OnlineImageList from '../../shared/online-image/OnlineImageList'
import { removeSelectedEmptyParagraph } from '../../shared/editor-operations' import {
insertBlockNodesAndFocus,
removeSelectedEmptyParagraph,
} from '../../shared/editor-operations'
import { uploadFile } from '@/utils/oss' import { uploadFile } from '@/utils/oss'
...@@ -122,7 +125,7 @@ const ImageModal = (props, ref) => { ...@@ -122,7 +125,7 @@ const ImageModal = (props, ref) => {
nodes.push(oP) nodes.push(oP)
} }
SlateTransforms.insertNodes(editor, nodes) insertBlockNodesAndFocus(editor, SlateTransforms, nodes)
clear() clear()
} }
......
...@@ -15,6 +15,7 @@ import image from './image/feature' ...@@ -15,6 +15,7 @@ import image from './image/feature'
import link from './link/feature' import link from './link/feature'
import practice from './practice/feature' import practice from './practice/feature'
import preview from './preview/feature' import preview from './preview/feature'
import tableActions from './table-actions/feature'
import tooltip from './tooltip/feature' import tooltip from './tooltip/feature'
import video from './video/feature' import video from './video/feature'
...@@ -37,6 +38,7 @@ export const editorFeatures = [ ...@@ -37,6 +38,7 @@ export const editorFeatures = [
aiResearch, aiResearch,
preview, preview,
history, history,
tableActions,
] ]
export const editorFeatureRegistry = createFeatureRegistry(editorFeatures) export const editorFeatureRegistry = createFeatureRegistry(editorFeatures)
...@@ -257,7 +257,6 @@ const LinkModal = (props, ref) => { ...@@ -257,7 +257,6 @@ const LinkModal = (props, ref) => {
</Form.Item> </Form.Item>
<Form.Item label={` `}> <Form.Item label={` `}>
<ColorPicker <ColorPicker
disabledAlpha
value={themeValue} value={themeValue}
defaultValue={themeValue} defaultValue={themeValue}
format='hex' format='hex'
......
...@@ -17,7 +17,10 @@ export default defineEditorFeature({ ...@@ -17,7 +17,10 @@ export default defineEditorFeature({
{ {
name: 'CustomerLinkClick', name: 'CustomerLinkClick',
handler: ({ editor }) => handler: ({ editor }) =>
openEditorDialog(editor, 'link.insert', { selectionSize: getSelectionFontSize(editor) }), openEditorDialog(editor, 'link.insert', {
selectionSize: getSelectionFontSize(editor),
theme: '#ab1941',
}),
}, },
], ],
}) })
import { defineEditorFeature } from '../../core/define-editor-feature'
import { insertTableColAfterMenu, insertTableRowAfterMenu } from './insert-after-menu'
export default defineEditorFeature({
id: 'table-actions',
menus: [
{ order: 170, config: insertTableRowAfterMenu },
{ order: 180, config: insertTableColAfterMenu },
],
})
import { DomEditor, SlateRange, SlateTransforms } from '@wangeditor/editor'
const createCell = (isHeader = false) => ({
type: 'table-cell',
...(isHeader ? { isHeader: true } : {}),
children: [{ text: '' }],
})
class InsertTableAfterMenu {
constructor() {
this.tag = 'button'
}
getValue() {
return ''
}
isActive() {
return false
}
isDisabled(editor) {
return (
editor.selection === null ||
SlateRange.isExpanded(editor.selection) ||
DomEditor.getSelectedNodeByType(editor, 'table') === null
)
}
}
class InsertTableRowAfter extends InsertTableAfterMenu {
constructor() {
super()
this.title = '向前插入行'
this.iconSvg =
'<svg viewBox="0 0 1048 1024"><g transform="translate(0 917.504) scale(1 -1)"><path d="M707.7888 521.0112h-147.456v-147.456H488.2432v147.456h-147.456v68.8128h147.456v147.456h72.0896v-147.456h147.456zM0 917.504V0h1048.576v917.504H0zM327.68 65.536H65.536v196.608H327.68V65.536z m327.68 0H393.216v196.608h262.144V65.536z m327.68 0h-262.144v196.608h262.144V65.536z m0 258.8672H65.536v462.0288H983.04V324.4032z"></path></g></svg>'
}
exec(editor) {
if (this.isDisabled(editor)) return
const row = DomEditor.getSelectedNodeByType(editor, 'table-row')
if (!row?.children?.length) return
const rowPath = DomEditor.findPath(editor, row)
SlateTransforms.insertNodes(
editor,
{
type: 'table-row',
children: row.children.map(() => createCell()),
},
{ at: rowPath },
)
}
}
class InsertTableColAfter extends InsertTableAfterMenu {
constructor() {
super()
this.title = '向后插入列'
this.iconSvg =
'<svg viewBox="0 0 1048 1024"><g transform="translate(1048 0) scale(-1 1)"><path d="M327.68 193.3312v186.7776H140.9024v91.7504H327.68v186.7776h88.4736V471.8592h190.0544V380.1088H416.1536V193.3312zM0 917.504V0h1048.576v917.504H0zM655.36 65.536H65.536v720.896H655.36V65.536z m327.68 0h-262.144v196.608h262.144V65.536z m0 262.144h-262.144v196.608h262.144V327.68z m0 262.144h-262.144v196.608h262.144v-196.608z"></path></g></svg>'
}
exec(editor) {
if (this.isDisabled(editor)) return
const table = DomEditor.getSelectedNodeByType(editor, 'table')
const cell = DomEditor.getSelectedNodeByType(editor, 'table-cell')
if (!table || !cell) return
const cellPath = DomEditor.findPath(editor, cell)
const columnIndex = cellPath[2]
const firstRowIsHeader = table.children?.[0]?.children?.every((item) => item.isHeader)
table.children.forEach((_, rowIndex) => {
SlateTransforms.insertNodes(editor, createCell(rowIndex === 0 && firstRowIsHeader), {
at: [cellPath[0], rowIndex, columnIndex + 1],
})
})
}
}
export const insertTableRowAfterMenu = {
key: 'insertTableRowAfter',
factory() {
return new InsertTableRowAfter()
},
}
export const insertTableColAfterMenu = {
key: 'insertTableColAfter',
factory() {
return new InsertTableColAfter()
},
}
...@@ -5,7 +5,10 @@ import { SlateTransforms } from '@wangeditor/editor' ...@@ -5,7 +5,10 @@ import { SlateTransforms } from '@wangeditor/editor'
import '../../index.less' import '../../index.less'
import { uploadFile } from '@/utils/oss' import { uploadFile } from '@/utils/oss'
import { removeSelectedEmptyParagraph } from '../../shared/editor-operations' import {
insertBlockNodesAndFocus,
removeSelectedEmptyParagraph,
} from '../../shared/editor-operations'
const { Dragger } = Upload const { Dragger } = Upload
...@@ -70,7 +73,7 @@ const VideoModal = ({ open, onClose, payload = {}, runtime }) => { ...@@ -70,7 +73,7 @@ const VideoModal = ({ open, onClose, payload = {}, runtime }) => {
removeSelectedEmptyParagraph(editor, SlateTransforms) removeSelectedEmptyParagraph(editor, SlateTransforms)
SlateTransforms.insertNodes(editor, { insertBlockNodesAndFocus(editor, SlateTransforms, {
type: 'chapterVideo', type: 'chapterVideo',
videoUrl: values.videoUrl, videoUrl: values.videoUrl,
title: values.videoTitle, title: values.videoTitle,
......
...@@ -532,13 +532,13 @@ ...@@ -532,13 +532,13 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 100%; width: 100%;
max-height: 320px; max-height: 110px;
overflow: hidden; overflow: hidden;
img { img {
display: block; display: block;
max-width: 100%; max-width: 100%;
max-height: 320px; max-height: 110px;
width: auto; width: auto;
height: auto; height: auto;
object-fit: contain; object-fit: contain;
......
...@@ -13,6 +13,30 @@ export const removeSelectedEmptyParagraph = (editor, transforms) => { ...@@ -13,6 +13,30 @@ export const removeSelectedEmptyParagraph = (editor, transforms) => {
if (path) transforms.removeNodes(editor, { at: path }) if (path) transforms.removeNodes(editor, { at: path })
} }
export const insertBlockNodesAndFocus = (editor, transforms, nodes) => {
const insertedNodes = Array.isArray(nodes) ? nodes : [nodes]
const lastInsertedNode = insertedNodes[insertedNodes.length - 1]
transforms.insertNodes(editor, insertedNodes)
const insertedIndex = editor.children.findIndex((node) => node === lastInsertedNode)
if (insertedIndex < 0) return
const nextPath = [insertedIndex + 1]
const nextNode = editor.children[nextPath[0]]
const nextFirstChild = nextNode?.children?.[0]
if (!nextFirstChild || !('text' in nextFirstChild)) {
transforms.insertNodes(
editor,
{ type: 'paragraph', children: [{ text: '' }] },
{ at: nextPath },
)
}
transforms.select(editor, {
anchor: { path: [...nextPath, 0], offset: 0 },
focus: { path: [...nextPath, 0], offset: 0 },
})
}
export const findElementPathByAttribute = (children, attribute, value) => { export const findElementPathByAttribute = (children, attribute, value) => {
const index = children?.findIndex((node) => String(node?.[attribute]) === String(value)) const index = children?.findIndex((node) => String(node?.[attribute]) === String(value))
return index >= 0 ? [index] : null return index >= 0 ? [index] : null
......
...@@ -99,6 +99,20 @@ export const createEditorConfig = ({ onFocus, onContentChange }) => ({ ...@@ -99,6 +99,20 @@ export const createEditorConfig = ({ onFocus, onContentChange }) => ({
image: { image: {
menuKeys: ['imageWidth30', 'imageWidth50', 'imageWidth100', 'ImageEditor', 'deleteImage'], menuKeys: ['imageWidth30', 'imageWidth50', 'imageWidth100', 'ImageEditor', 'deleteImage'],
}, },
table: {
menuKeys: [
'enter',
'tableHeader',
'tableFullWidth',
'insertTableRow',
'insertTableRowAfter',
'deleteTableRow',
'insertTableCol',
'insertTableColAfter',
'deleteTableCol',
'deleteTable',
],
},
ImageAuto: { ImageAuto: {
menuKeys: [ menuKeys: [
'imageWidthChpater100', 'imageWidthChpater100',
......
...@@ -19,22 +19,22 @@ export default defineConfig(() => { ...@@ -19,22 +19,22 @@ export default defineConfig(() => {
target: 'http://127.0.0.1:7419', target: 'http://127.0.0.1:7419',
changeOrigin: true, changeOrigin: true,
secure: false, secure: false,
rewrite: path => path.replace(/^\/api\/admin/, ''), rewrite: (path) => path.replace(/^\/api\/admin/, ''),
}, },
'/api/qwen': { '/api/qwen': {
target: 'https://dashscope.aliyuncs.com', target: 'https://dashscope.aliyuncs.com',
changeOrigin: true, changeOrigin: true,
rewrite: path => path.replace(/^\/api\/qwen/, ''), rewrite: (path) => path.replace(/^\/api\/qwen/, ''),
}, },
'/api/qianfan': { '/api/qianfan': {
target: 'https://aip.baidubce.com', target: 'https://aip.baidubce.com',
changeOrigin: true, changeOrigin: true,
rewrite: path => path.replace(/^\/api\/qianfan/, ''), rewrite: (path) => path.replace(/^\/api\/qianfan/, ''),
}, },
'/api/deepseek': { '/api/deepseek': {
target: 'https://api.deepseek.com', target: 'https://api.deepseek.com',
changeOrigin: true, changeOrigin: true,
rewrite: path => path.replace(/^\/api\/deepseek/, ''), rewrite: (path) => path.replace(/^\/api\/deepseek/, ''),
}, },
}, },
}, },
......
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论