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

feat: 添加侧边栏宽度调整功能

上级 b978b149
import { useState, useEffect, useRef } from 'react' import { useState, useEffect, useRef, useCallback } from 'react'
import { Button, Row, Col, Descriptions, Tree, Dropdown, Modal, Spin, App } from 'antd' import { Button, Row, Col, Descriptions, Tree, Dropdown, Modal, Spin, App } from 'antd'
import { EllipsisOutlined, DiffOutlined, MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons' import { EllipsisOutlined, DiffOutlined, MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons'
import WangEditorCustomer from '@/common/wangeditor-customer' import WangEditorCustomer from '@/common/wangeditor-customer'
...@@ -18,7 +18,7 @@ import { ...@@ -18,7 +18,7 @@ import {
findFirstNotHasChildren, findFirstNotHasChildren,
findParentLevelOne, findParentLevelOne,
findTreeToIndex, findTreeToIndex,
findNodeById findNodeById,
} from '@/utils/common' } from '@/utils/common'
import { getAllList, getInfoByChapterId, sectionEdit, chapterDel, dragOrder } from './request' import { getAllList, getInfoByChapterId, sectionEdit, chapterDel, dragOrder } from './request'
import './index.less' import './index.less'
...@@ -30,7 +30,7 @@ const Examine = () => { ...@@ -30,7 +30,7 @@ const Examine = () => {
const id = get(location, 'state.id', '') const id = get(location, 'state.id', '')
const isAdminOrCreator = get(location, 'state.isAdminOrCreator', false) const isAdminOrCreator = get(location, 'state.isAdminOrCreator', false)
const { treeChapter, userInfo } = useSelector(state => state.user) const { treeChapter, userInfo } = useSelector((state) => state.user)
const navigate = useNavigate() const navigate = useNavigate()
const dispatch = useDispatch() const dispatch = useDispatch()
...@@ -44,6 +44,9 @@ const Examine = () => { ...@@ -44,6 +44,9 @@ const Examine = () => {
const [nowTitle, setNowTitle] = useState('') const [nowTitle, setNowTitle] = useState('')
// 编辑操作 // 编辑操作
const [isCollapse, setisCollapse] = useState(false) const [isCollapse, setisCollapse] = useState(false)
const [sidebarWidth, setSidebarWidth] = useState(280)
const isResizing = useRef(false)
const sidebarRef = useRef(null)
const [editKey, setEditKey] = useState(null) const [editKey, setEditKey] = useState(null)
const [parentId, setParentId] = useState(null) const [parentId, setParentId] = useState(null)
const [editValue, setEditValue] = useState('') const [editValue, setEditValue] = useState('')
...@@ -60,6 +63,38 @@ const Examine = () => { ...@@ -60,6 +63,38 @@ const Examine = () => {
// 关联知识图谱 // 关联知识图谱
const [bindKnowledgeGraphIsOpen, setBindKnowledgeGraphIsOpen] = useState(false) const [bindKnowledgeGraphIsOpen, setBindKnowledgeGraphIsOpen] = useState(false)
// 拖拽改变侧边栏宽度
const handleMouseDown = useCallback(
(e) => {
e.preventDefault()
isResizing.current = true
document.body.style.cursor = 'col-resize'
document.body.style.userSelect = 'none'
const startX = e.clientX
const startWidth = sidebarWidth
const handleMouseMove = (e) => {
if (!isResizing.current) return
const delta = e.clientX - startX
const newWidth = Math.min(Math.max(startWidth + delta, 200), 600)
setSidebarWidth(newWidth)
}
const handleMouseUp = () => {
isResizing.current = false
document.body.style.cursor = ''
document.body.style.userSelect = ''
document.removeEventListener('mousemove', handleMouseMove)
document.removeEventListener('mouseup', handleMouseUp)
}
document.addEventListener('mousemove', handleMouseMove)
document.addEventListener('mouseup', handleMouseUp)
},
[sidebarWidth],
)
// 编辑器内容 // 编辑器内容
const editorRef = useRef() const editorRef = useRef()
const saveInterRef = useRef() const saveInterRef = useRef()
...@@ -81,7 +116,7 @@ const Examine = () => { ...@@ -81,7 +116,7 @@ const Examine = () => {
return return
} }
const uniqueBookList = [...new Set(data.map(item => item.book_id))][0] const uniqueBookList = [...new Set(data.map((item) => item.book_id))][0]
setBookId(uniqueBookList) setBookId(uniqueBookList)
const arr = convertToAntdTreeData(data, 'name') const arr = convertToAntdTreeData(data, 'name')
setGData(arr) setGData(arr)
...@@ -123,9 +158,9 @@ const Examine = () => { ...@@ -123,9 +158,9 @@ const Examine = () => {
setNowTitle(title) setNowTitle(title)
} }
// 递归函数,获取所有节点的key // 递归函数,获取所有节点的key
const getAllNodeKeys = nodes => { const getAllNodeKeys = (nodes) => {
let keys = [] let keys = []
nodes.forEach(node => { nodes.forEach((node) => {
keys.push(node.key) keys.push(node.key)
if (node.children && node.children.length > 0) { if (node.children && node.children.length > 0) {
keys = keys.concat(getAllNodeKeys(node.children)) keys = keys.concat(getAllNodeKeys(node.children))
...@@ -153,7 +188,7 @@ const Examine = () => { ...@@ -153,7 +188,7 @@ const Examine = () => {
setLoading(false) setLoading(false)
} }
const onExpand = expandedKeys => { const onExpand = (expandedKeys) => {
setExpandedKeys(expandedKeys) setExpandedKeys(expandedKeys)
} }
const handleSelect = async (selectedKeys, info) => { const handleSelect = async (selectedKeys, info) => {
...@@ -205,7 +240,7 @@ const Examine = () => { ...@@ -205,7 +240,7 @@ const Examine = () => {
const data = await sectionEdit({ const data = await sectionEdit({
id: contentId, id: contentId,
content: contentHtml, content: contentHtml,
word_count word_count,
}) })
if (data) { if (data) {
if ((data.code && data.code === 3000) || data.code === '3000') { if ((data.code && data.code === 3000) || data.code === '3000') {
...@@ -233,7 +268,7 @@ const Examine = () => { ...@@ -233,7 +268,7 @@ const Examine = () => {
setParentId(-1) setParentId(-1)
} }
const delChapter = async node => { const delChapter = async (node) => {
const childInKey = findParentLevelOne(gData, 'key', node.key) const childInKey = findParentLevelOne(gData, 'key', node.key)
let current = null let current = null
if (childInKey && childInKey.children && childInKey.children.length > 0) { if (childInKey && childInKey.children && childInKey.children.length > 0) {
...@@ -296,11 +331,11 @@ const Examine = () => { ...@@ -296,11 +331,11 @@ const Examine = () => {
label: '一键AI', label: '一键AI',
children: [ children: [
{ key: '61', label: '一键AI创作课件', disabled: true }, { key: '61', label: '一键AI创作课件', disabled: true },
{ key: '62', label: '一键AI创作教案', disabled: true } { key: '62', label: '一键AI创作教案', disabled: true },
] ],
}, },
{ key: '3', label: '编辑' }, { key: '3', label: '编辑' },
{ key: '4', label: '删除' } { key: '4', label: '删除' },
] ]
if (!isAdminOrCreator) { if (!isAdminOrCreator) {
chapterMenuItems = [{ key: '1', label: '展开全部' }] chapterMenuItems = [{ key: '1', label: '展开全部' }]
...@@ -330,7 +365,7 @@ const Examine = () => { ...@@ -330,7 +365,7 @@ const Examine = () => {
content: `确认删除子节【${node.title}】?`, content: `确认删除子节【${node.title}】?`,
onOk() { onOk() {
delChapter(node) delChapter(node)
} },
}) })
} else if (e.key == 5) { } else if (e.key == 5) {
setEditChapterEditorsIsOpen(true) setEditChapterEditorsIsOpen(true)
...@@ -340,18 +375,18 @@ const Examine = () => { ...@@ -340,18 +375,18 @@ const Examine = () => {
} }
// 章节名称 // 章节名称
const chapterTitleRender = node => { const chapterTitleRender = (node) => {
return ( return (
<div className="chapter-tree-item"> <div className="chapter-tree-item">
<p className="title">{node.title}</p> <p className="title">{node.title}</p>
<Dropdown trigger={['click']} menu={{ items: chapterMenuItems, onClick: e => handleMenuClick(e, node) }}> <Dropdown trigger={['click']} menu={{ items: chapterMenuItems, onClick: (e) => handleMenuClick(e, node) }}>
<EllipsisOutlined onClick={e => e.stopPropagation()} /> <EllipsisOutlined onClick={(e) => e.stopPropagation()} />
</Dropdown> </Dropdown>
</div> </div>
) )
} }
const onDrop = async info => { const onDrop = async (info) => {
const dropToGap = info.dropToGap // true 为同级或最大级 false 为子级 const dropToGap = info.dropToGap // true 为同级或最大级 false 为子级
const nowDropNode = info.dragNode.key const nowDropNode = info.dragNode.key
const sideDropNode = info.node.key const sideDropNode = info.node.key
...@@ -369,7 +404,7 @@ const Examine = () => { ...@@ -369,7 +404,7 @@ const Examine = () => {
book_id: id, book_id: id,
drag_node: nowDropNode, drag_node: nowDropNode,
position_node: sideDropNode, position_node: sideDropNode,
drop_type: 'after' drop_type: 'after',
}) })
} else { } else {
if (dragOverGapTop) { if (dragOverGapTop) {
...@@ -378,14 +413,14 @@ const Examine = () => { ...@@ -378,14 +413,14 @@ const Examine = () => {
book_id: id, book_id: id,
drag_node: nowDropNode, drag_node: nowDropNode,
position_node: sideDropNode, position_node: sideDropNode,
drop_type: 'before' drop_type: 'before',
}) })
} else if (dragOverGapBottom) { } else if (dragOverGapBottom) {
data = await dragOrder({ data = await dragOrder({
book_id: id, book_id: id,
drag_node: nowDropNode, drag_node: nowDropNode,
position_node: sideDropNode, position_node: sideDropNode,
drop_type: 'after' drop_type: 'after',
}) })
} }
} }
...@@ -395,7 +430,7 @@ const Examine = () => { ...@@ -395,7 +430,7 @@ const Examine = () => {
book_id: id, book_id: id,
drag_node: nowDropNode, drag_node: nowDropNode,
position_node: sideDropNode, position_node: sideDropNode,
drop_type: 'inner' drop_type: 'inner',
}) })
} }
if (data) { if (data) {
...@@ -406,8 +441,11 @@ const Examine = () => { ...@@ -406,8 +441,11 @@ const Examine = () => {
return ( return (
<div className="examine"> <div className="examine">
<div className="content-box"> <div className="content-box">
<Row gutter={10} style={{ height: '100%' }} className="book-content-row"> <div className="book-content-row">
<Col span={isCollapse ? 1 : 4} className="book-content-tree"> <div
ref={sidebarRef}
className="book-content-tree"
style={{ width: isCollapse ? 50 : sidebarWidth, minWidth: isCollapse ? 50 : 200, flexShrink: 0 }}>
<div className="border"> <div className="border">
{!isCollapse ? ( {!isCollapse ? (
<> <>
...@@ -431,8 +469,8 @@ const Examine = () => { ...@@ -431,8 +469,8 @@ const Examine = () => {
onClick={() => setisCollapse(true)}></Button> onClick={() => setisCollapse(true)}></Button>
</Col> </Col>
</Row> </Row>
) ),
} },
]} ]}
/> />
{gData && gData.length > 0 && ( {gData && gData.length > 0 && (
...@@ -450,7 +488,7 @@ const Examine = () => { ...@@ -450,7 +488,7 @@ const Examine = () => {
disabled={loading} disabled={loading}
treeData={gData} treeData={gData}
onExpand={onExpand} onExpand={onExpand}
titleRender={nodeData => chapterTitleRender(nodeData)} titleRender={(nodeData) => chapterTitleRender(nodeData)}
/> />
)} )}
</> </>
...@@ -470,14 +508,15 @@ const Examine = () => { ...@@ -470,14 +508,15 @@ const Examine = () => {
onClick={() => setisCollapse(false)}></Button> onClick={() => setisCollapse(false)}></Button>
</Col> </Col>
</Row> </Row>
) ),
} },
]} ]}
/> />
)} )}
</div> </div>
</Col> </div>
<Col span={isCollapse ? 23 : 20} className="book-content-tree"> {!isCollapse && <div className="resize-handle" onMouseDown={handleMouseDown} />}
<div className="book-content-editor" style={{ flex: 1, minWidth: 0 }}>
<div className="editor-right"> <div className="editor-right">
<Spin spinning={loading}> <Spin spinning={loading}>
<WangEditorCustomer <WangEditorCustomer
...@@ -494,8 +533,8 @@ const Examine = () => { ...@@ -494,8 +533,8 @@ const Examine = () => {
/> />
</Spin> </Spin>
</div> </div>
</Col> </div>
</Row> </div>
</div> </div>
<Modal <Modal
...@@ -509,7 +548,7 @@ const Examine = () => { ...@@ -509,7 +548,7 @@ const Examine = () => {
closeIcon={false} // 添加这一行以隐藏关闭按钮 closeIcon={false} // 添加这一行以隐藏关闭按钮
onCancel={() => setEditKey(false)} onCancel={() => setEditKey(false)}
classNames={{ classNames={{
wrapper: 'chapter-title-modal' wrapper: 'chapter-title-modal',
}}> }}>
<EditChapterTitle <EditChapterTitle
setEditKey={setEditKey} setEditKey={setEditKey}
......
...@@ -7,9 +7,46 @@ ...@@ -7,9 +7,46 @@
.book-content-row { .book-content-row {
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
display: flex;
gap: 0;
.book-content-tree { .book-content-tree {
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
transition: width 0s;
}
.book-content-editor {
height: 100%;
overflow: hidden;
}
}
.resize-handle {
width: 6px;
cursor: col-resize;
background: transparent;
position: relative;
flex-shrink: 0;
z-index: 10;
transition: background 0.2s;
&:hover,
&:active {
background: #1890ff;
border-radius: 3px;
}
&::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 2px;
height: 30px;
background: #d9d9d9;
border-radius: 1px;
transition: background 0.2s;
}
&:hover::after,
&:active::after {
background: #fff;
} }
} }
.ant-descriptions-item-label { .ant-descriptions-item-label {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论