|
|
|
@ -1,10 +1,12 @@ |
|
|
|
|
import {Editor} from 'amis-editor' |
|
|
|
|
import { useEffect, useState } from 'react'; |
|
|
|
|
import { useEffect, useState, useRef } from 'react'; |
|
|
|
|
import css from './index.module.scss'; |
|
|
|
|
import { PlusOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons' |
|
|
|
|
import { Modal, Form, Input, Button, message, Menu, Popconfirm } from 'antd' |
|
|
|
|
import { PlusOutlined, DeleteOutlined, EditOutlined, CloudOutlined, CopyOutlined } from '@ant-design/icons' |
|
|
|
|
import { Modal, Form, Input, Button, message, Menu, Popconfirm, Drawer, Upload } from 'antd' |
|
|
|
|
import api from '../../request/api/edit' |
|
|
|
|
|
|
|
|
|
import svgCloud from './cloud.svg' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export default function Edit(){ |
|
|
|
|
// 刷新 |
|
|
|
@ -15,8 +17,22 @@ export default function Edit(){ |
|
|
|
|
const [menuList, setMenuList] = useState([]) |
|
|
|
|
// 原始菜单 |
|
|
|
|
const [atomMenuList, setAtomMenuList] = useState([]) |
|
|
|
|
|
|
|
|
|
// 文件库 |
|
|
|
|
const [fileCloud, setFileCloud] = useState([]); |
|
|
|
|
// 获取文件进行时 |
|
|
|
|
const [getFileState, setGetFileState] = useState(false) |
|
|
|
|
// 文件页面容器 |
|
|
|
|
const filePageContent = useRef(null) |
|
|
|
|
// 当前菜单ID |
|
|
|
|
const [nowMenuItemId, setNowMenuItemId] = useState('') |
|
|
|
|
// 当前菜单内容 |
|
|
|
|
const [nowMenuItemContent, setNowMenuItemContent] = useState(null); |
|
|
|
|
// 当前页内容 |
|
|
|
|
const [nowEditorContent, setNowEditorContent] = useState({ |
|
|
|
|
asideResizor: false, |
|
|
|
|
pullRefresh: {disabled: true}, |
|
|
|
|
regions: ['body'] |
|
|
|
|
}); |
|
|
|
|
useEffect(() => { |
|
|
|
|
api.getMenu().then( |
|
|
|
|
resd => { |
|
|
|
@ -37,6 +53,26 @@ export default function Edit(){ |
|
|
|
|
const list = formateMenuList(atomMenuList) |
|
|
|
|
setMenuTree(list) |
|
|
|
|
}, [atomMenuList]) |
|
|
|
|
|
|
|
|
|
const [filePage, setFilePage] = useState({ |
|
|
|
|
pageNum: 1, |
|
|
|
|
pageSize: 5, |
|
|
|
|
total: 0, |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
api.getFileList(filePage).then( |
|
|
|
|
resd => { |
|
|
|
|
// console.log(resd.data.data.rows) |
|
|
|
|
setFileCloud(resd.data.data.rows) |
|
|
|
|
setFilePage({ |
|
|
|
|
pageNum: filePage.pageNum, |
|
|
|
|
pageSize: filePage.pageSize, |
|
|
|
|
total: resd.data.data.total, |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
}, [0]) |
|
|
|
|
// 消息 |
|
|
|
|
const [messageApi, contextHolder] = message.useMessage(); |
|
|
|
|
// 菜单的打开状态 |
|
|
|
@ -48,6 +84,68 @@ export default function Edit(){ |
|
|
|
|
const [isModalOpenForCreateMneu, setIsModalOpenForCreateMneu] = useState(false); |
|
|
|
|
// 编辑菜单弹窗状态 |
|
|
|
|
const [isModalOpenForEditMneu, setIsModalOpenForEditMneu] = useState(false); |
|
|
|
|
// 文件抽屉的状态 |
|
|
|
|
const [fileDrawerState, setFileDrawerState] = useState(false); |
|
|
|
|
// 滚动获取文件 |
|
|
|
|
|
|
|
|
|
let a = true |
|
|
|
|
let last = 0; |
|
|
|
|
// 监听文件容器滚动事件 |
|
|
|
|
useEffect(() => { |
|
|
|
|
function listen(){ |
|
|
|
|
const maxHeight = filePageContent.current.children[0].offsetHeight |
|
|
|
|
const scrollHeight = filePageContent.current.scrollTop + filePageContent.current.offsetHeight |
|
|
|
|
if(maxHeight - scrollHeight + 40 < 3){ |
|
|
|
|
if(scrollHeight > last){ |
|
|
|
|
if(a){ |
|
|
|
|
a = false |
|
|
|
|
function getNewFile(){ |
|
|
|
|
if(!getFileState){ |
|
|
|
|
setGetFileState(true) |
|
|
|
|
if(filePage.pageNum * filePage.pageSize > filePage.total){ |
|
|
|
|
|
|
|
|
|
}else{ |
|
|
|
|
const newPage = { |
|
|
|
|
pageNum: filePage.pageNum + 1, |
|
|
|
|
pageSize: filePage.pageSize, |
|
|
|
|
total: filePage.total, |
|
|
|
|
} |
|
|
|
|
api.getFileList(newPage).then( |
|
|
|
|
resd => { |
|
|
|
|
setFileCloud([...fileCloud, ...resd.data.data.rows]) |
|
|
|
|
setFilePage({ |
|
|
|
|
pageNum: newPage.pageNum, |
|
|
|
|
pageSize: newPage.pageSize, |
|
|
|
|
total: resd.data.data.total, |
|
|
|
|
}) |
|
|
|
|
setTimeout(() => { |
|
|
|
|
setGetFileState(false) |
|
|
|
|
}, 300) |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
getNewFile() |
|
|
|
|
setTimeout(() => { |
|
|
|
|
a = true |
|
|
|
|
},200) |
|
|
|
|
} |
|
|
|
|
last = scrollHeight |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if(fileDrawerState){ |
|
|
|
|
if(filePageContent.current){ |
|
|
|
|
filePageContent.current.addEventListener('scroll',listen) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return () => { |
|
|
|
|
filePageContent.current && listen && filePageContent.current.removeEventListener('scroll', listen) |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
// 添加菜单数据 |
|
|
|
|
const [ createMenuForm ] = Form.useForm(); |
|
|
|
|
const [ editMenuForm ] = Form.useForm(); |
|
|
|
@ -68,50 +166,33 @@ export default function Edit(){ |
|
|
|
|
setMenuParentId(null) |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// 打开编辑菜单 |
|
|
|
|
const editMenu = key => { |
|
|
|
|
console.log(key) |
|
|
|
|
console.log(menuList, menuTree) |
|
|
|
|
const data = menuList.find(item => { |
|
|
|
|
// console.log(item) |
|
|
|
|
return item.id == key |
|
|
|
|
}) |
|
|
|
|
setNowMenuItemId(data.id) |
|
|
|
|
editMenuForm.setFieldsValue({ |
|
|
|
|
name : data.name, |
|
|
|
|
value: data.value |
|
|
|
|
}) |
|
|
|
|
setIsModalOpenForEditMneu(true) |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
// 确认编辑菜单弹窗 |
|
|
|
|
const handleOkForEditMneu = () => { |
|
|
|
|
editMenuForm.submit() |
|
|
|
|
}; |
|
|
|
|
// 关闭编辑菜单弹窗 |
|
|
|
|
const handleCancelForEditMneu = () => { |
|
|
|
|
setIsModalOpenForEditMneu(false); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 切换菜单 |
|
|
|
|
const onOpenChange = (keys) => { |
|
|
|
|
const latestOpenKey = keys.find((key) => openKeys.indexOf(key) === -1); |
|
|
|
|
setOpenKeys(latestOpenKey ? [latestOpenKey] : []); |
|
|
|
|
// console.log(keys) |
|
|
|
|
// if (rootSubmenuKeys.indexOf(latestOpenKey) === -1) { |
|
|
|
|
// setOpenKeys(keys); |
|
|
|
|
// } else { |
|
|
|
|
// |
|
|
|
|
// } |
|
|
|
|
setOpenKeys(keys) |
|
|
|
|
}; |
|
|
|
|
// 选中菜单 |
|
|
|
|
function onSelectMenu(val){ |
|
|
|
|
// console.log(val) |
|
|
|
|
const menuItemData =val.item.props.data; |
|
|
|
|
if(menuItemData.menuContentList.length == 0){ |
|
|
|
|
setNowEditorContent({ |
|
|
|
|
asideResizor: false, |
|
|
|
|
pullRefresh: {disabled: true}, |
|
|
|
|
regions: ['body'] |
|
|
|
|
}) |
|
|
|
|
}else{ |
|
|
|
|
const nowEditData = menuItemData.menuContentList.find(item => item.type == '0') |
|
|
|
|
const data = JSON.parse(nowEditData.content) |
|
|
|
|
setNowEditorContent(data) |
|
|
|
|
} |
|
|
|
|
setNowMenuItemId(val.key) |
|
|
|
|
setNowMenuItemContent(val.item.props.data) |
|
|
|
|
}; |
|
|
|
|
// 删除菜单 |
|
|
|
|
function deleteMenuItem(id){ |
|
|
|
|
function deleteMenuItem(id, e){ |
|
|
|
|
e.stopPropagation(); |
|
|
|
|
api.deleteMenuItem(id).then( |
|
|
|
|
resd => { |
|
|
|
|
if(resd.data.code == 200){ |
|
|
|
@ -130,12 +211,35 @@ export default function Edit(){ |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
}; |
|
|
|
|
// 打开编辑菜单 |
|
|
|
|
const editMenu = (key, e) => { |
|
|
|
|
e.stopPropagation(); |
|
|
|
|
const data = menuList.find(item => { |
|
|
|
|
return item.id == key |
|
|
|
|
}) |
|
|
|
|
setNowMenuItemId(data.id) |
|
|
|
|
editMenuForm.setFieldsValue({ |
|
|
|
|
name : data.name, |
|
|
|
|
value: data.value |
|
|
|
|
}) |
|
|
|
|
setIsModalOpenForEditMneu(true) |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
// 确认编辑菜单弹窗 |
|
|
|
|
const handleOkForEditMneu = () => { |
|
|
|
|
editMenuForm.submit() |
|
|
|
|
}; |
|
|
|
|
// 关闭编辑菜单弹窗 |
|
|
|
|
const handleCancelForEditMneu = () => { |
|
|
|
|
setIsModalOpenForEditMneu(false); |
|
|
|
|
}; |
|
|
|
|
// 新建子菜单 |
|
|
|
|
function createSonMenu(key){ |
|
|
|
|
function createSonMenu(key, e){ |
|
|
|
|
e.stopPropagation(); |
|
|
|
|
showModalForCreateMneu() |
|
|
|
|
setMenuParentId(key) |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// 格式化菜单数据 |
|
|
|
|
function formateMenuList(list){ |
|
|
|
|
const newList = [] |
|
|
|
@ -146,19 +250,20 @@ export default function Edit(){ |
|
|
|
|
label: <div className={css.menuItem}> |
|
|
|
|
<div title={item.name}>{item.name}</div> |
|
|
|
|
<div> |
|
|
|
|
<span onClick={() => createSonMenu(item.id.toString())}> |
|
|
|
|
<span onClick={(e) => createSonMenu(item.id.toString(), e)}> |
|
|
|
|
<Button type="ghost" icon={<PlusOutlined />} size={'small'}/> |
|
|
|
|
</span> |
|
|
|
|
<span onClick={() => editMenu(item.id.toString())}> |
|
|
|
|
<span onClick={(e) => editMenu(item.id.toString(), e)}> |
|
|
|
|
<Button type="ghost" icon={<EditOutlined />} size={'small'}/> |
|
|
|
|
</span> |
|
|
|
|
<span > |
|
|
|
|
<Popconfirm |
|
|
|
|
title="删除目录" |
|
|
|
|
description="去人要删除当前目录吗?" |
|
|
|
|
onConfirm={() => deleteMenuItem(item.id.toString())} |
|
|
|
|
onConfirm={(e) => deleteMenuItem(item.id.toString(), e)} |
|
|
|
|
onCancel={e => e.stopPropagation()} |
|
|
|
|
> |
|
|
|
|
<Button danger type="text" icon={<DeleteOutlined />} size={'small'}/> |
|
|
|
|
<Button danger type="text" icon={<DeleteOutlined />} size={'small'} onClick={e => e.stopPropagation()}/> |
|
|
|
|
</Popconfirm> |
|
|
|
|
</span></div></div>, |
|
|
|
|
data: item |
|
|
|
@ -247,11 +352,102 @@ export default function Edit(){ |
|
|
|
|
// console.log('Failed:', errorInfo); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const data = { |
|
|
|
|
value:{}, |
|
|
|
|
onChange: (value ) => { |
|
|
|
|
console.log(value) |
|
|
|
|
} |
|
|
|
|
// 打开文件抽屉 |
|
|
|
|
const showFileDrawer = () => { |
|
|
|
|
setFileDrawerState(true); |
|
|
|
|
}; |
|
|
|
|
// 关闭文件抽屉 |
|
|
|
|
const closeFileDrawer = () => { |
|
|
|
|
setFileDrawerState(false); |
|
|
|
|
}; |
|
|
|
|
// 保存文件信息 |
|
|
|
|
function saveFile(fileData){ |
|
|
|
|
console.log(fileData) |
|
|
|
|
api.saveFileUrl(fileData).then( |
|
|
|
|
resd => { |
|
|
|
|
if(resd.data.code == 200){ |
|
|
|
|
api.getFileList(filePage).then( |
|
|
|
|
resd => { |
|
|
|
|
setFileCloud(resd.data.data.rows) |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
}else{ |
|
|
|
|
message.error(`保存${fileData.name}路径失败`); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
}; |
|
|
|
|
// 上传文件配置 |
|
|
|
|
const uploadProps = { |
|
|
|
|
name: 'file', |
|
|
|
|
action: '/api/file/upload', |
|
|
|
|
headers: { |
|
|
|
|
authorization: window.localStorage.getItem('token'), |
|
|
|
|
}, |
|
|
|
|
onChange(info) { |
|
|
|
|
console.log(info.file.response) |
|
|
|
|
if (info.file.status !== 'uploading') { |
|
|
|
|
console.log(info.file, info.fileList); |
|
|
|
|
} |
|
|
|
|
if (info.file.status === 'done') { |
|
|
|
|
if(info.file.response.code == 200){ |
|
|
|
|
saveFile({ |
|
|
|
|
name: info.file.response.data.name, |
|
|
|
|
url: info.file.response.data.url |
|
|
|
|
}) |
|
|
|
|
message.success(`${info.file.name} file uploaded successfully`); |
|
|
|
|
}else{ |
|
|
|
|
message.error(`${info.file.name} file upload failed.`); |
|
|
|
|
} |
|
|
|
|
} else if (info.file.status === 'error') { |
|
|
|
|
message.error(`${info.file.name} file upload failed.`); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
// 删除文件 |
|
|
|
|
function deleteFile(id, e){ |
|
|
|
|
api.deleteFile(id).then( |
|
|
|
|
resd => { |
|
|
|
|
if(resd.data.code == 200){ |
|
|
|
|
message.success(`删除文件成功`); |
|
|
|
|
api.getFileList(filePage).then( |
|
|
|
|
resd => { |
|
|
|
|
setFileCloud(resd.data.data.rows) |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
}else{ |
|
|
|
|
message.error(`删除文件失败`); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
e.stopPropagation() |
|
|
|
|
} |
|
|
|
|
// 赋值文件地址 |
|
|
|
|
function copyFilePath(url){ |
|
|
|
|
navigator.clipboard.writeText(url) |
|
|
|
|
message.success(`复制文件成功成功,可在编辑器内粘贴使用!`); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 监听编辑器内容变化 |
|
|
|
|
function handleEditorChange(value){ |
|
|
|
|
setNowEditorContent(value) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 保存文件内容 |
|
|
|
|
function savgEditorContent(){ |
|
|
|
|
api.createContent({ |
|
|
|
|
homeMenuId:nowMenuItemContent.id, |
|
|
|
|
content: JSON.stringify(nowEditorContent), |
|
|
|
|
name: (new Date().getTime()).toString(), |
|
|
|
|
type: 0 |
|
|
|
|
}).then(resd => { |
|
|
|
|
if(resd.data.code == 200){ |
|
|
|
|
message.success(`保存文章成功!`); |
|
|
|
|
setReflush(!reflush) |
|
|
|
|
}else{ |
|
|
|
|
message.error(`保存文章失败!`); |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
return ( |
|
|
|
|
<div className={css.main}> |
|
|
|
@ -264,7 +460,7 @@ export default function Edit(){ |
|
|
|
|
mode="inline" |
|
|
|
|
openKeys={openKeys} |
|
|
|
|
onOpenChange={onOpenChange} |
|
|
|
|
style={{ width: 200 }} |
|
|
|
|
style={{ width: 240 }} |
|
|
|
|
onSelect={onSelectMenu} |
|
|
|
|
items={menuTree} |
|
|
|
|
/> |
|
|
|
@ -272,15 +468,25 @@ export default function Edit(){ |
|
|
|
|
</div> |
|
|
|
|
<div className={css.right}> |
|
|
|
|
<div className="Editor-Demo"> |
|
|
|
|
<div className="Editor-header"></div> |
|
|
|
|
<Editor value={data.value} onChange={data.onChange}/> |
|
|
|
|
{!nowMenuItemContent && <div className={css.editTop}>未选中菜单</div>} |
|
|
|
|
{nowMenuItemContent && <div className="Editor-header"> |
|
|
|
|
<div className={css.editHeader}> |
|
|
|
|
<div onClick={showFileDrawer}> |
|
|
|
|
<img src={svgCloud} alt=""/> |
|
|
|
|
<span>文件管理</span> |
|
|
|
|
</div> |
|
|
|
|
<div className={css.title}></div> |
|
|
|
|
<div><Button type="primary" onClick={savgEditorContent}>保存</Button></div> |
|
|
|
|
</div> |
|
|
|
|
</div>} |
|
|
|
|
{nowMenuItemContent && <Editor value={nowEditorContent} onChange={handleEditorChange}/>} |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
{contextHolder} |
|
|
|
|
<Modal title="添加菜单" open={isModalOpenForCreateMneu} onOk={handleOkForCreateMneu} onCancel={handleCancelForCreateMneu}> |
|
|
|
|
<div> |
|
|
|
|
<Form |
|
|
|
|
name="basic" |
|
|
|
|
name="create" |
|
|
|
|
labelCol={{ span: 5 }} |
|
|
|
|
wrapperCol={{ span: 18 }} |
|
|
|
|
style={{ maxWidth: 600 }} |
|
|
|
@ -311,7 +517,7 @@ export default function Edit(){ |
|
|
|
|
<Modal title="编辑菜单" open={isModalOpenForEditMneu} onOk={handleOkForEditMneu} onCancel={handleCancelForEditMneu}> |
|
|
|
|
<div> |
|
|
|
|
<Form |
|
|
|
|
name="basic" |
|
|
|
|
name="edit" |
|
|
|
|
labelCol={{ span: 5 }} |
|
|
|
|
wrapperCol={{ span: 18 }} |
|
|
|
|
style={{ maxWidth: 600 }} |
|
|
|
@ -339,6 +545,53 @@ export default function Edit(){ |
|
|
|
|
</Form> |
|
|
|
|
</div> |
|
|
|
|
</Modal> |
|
|
|
|
<Drawer title="文件管理" placement="left" onClose={closeFileDrawer} open={fileDrawerState}> |
|
|
|
|
<div className={css.fileContainer}> |
|
|
|
|
<header> |
|
|
|
|
<Upload {...uploadProps}> |
|
|
|
|
<Button type="primary" icon={<CloudOutlined />}>上传文件</Button> |
|
|
|
|
</Upload> |
|
|
|
|
</header> |
|
|
|
|
<div ref={filePageContent}> |
|
|
|
|
<div> |
|
|
|
|
{ |
|
|
|
|
fileCloud.map(item => { |
|
|
|
|
return <div className={css.fileBox} key={item.id}> |
|
|
|
|
<div> |
|
|
|
|
<div className={css.name}>{item.name}</div> |
|
|
|
|
<div className={css.url}>{item.url}</div> |
|
|
|
|
<div className={css.show}> |
|
|
|
|
{['png', 'svg', 'webp', 'jpg', 'ico'].indexOf(item.url.split('.').slice(-1)[0]) > -1 &&<div className={css.photo}> |
|
|
|
|
<img src={item.url} alt=""/> |
|
|
|
|
</div>} |
|
|
|
|
{['mp4'].indexOf(item.url.split('.').slice(-1)[0]) > -1 &&<div className={css.video}> |
|
|
|
|
<video src={item.url} alt=""/> |
|
|
|
|
</div>} |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
<div> |
|
|
|
|
<div> |
|
|
|
|
<Popconfirm |
|
|
|
|
title="删除目录" |
|
|
|
|
description="去人要删除当前目录吗?" |
|
|
|
|
onConfirm={(e) => deleteFile(item.id.toString(), e)} |
|
|
|
|
onCancel={e => e.stopPropagation()} |
|
|
|
|
> |
|
|
|
|
<Button danger type="text" icon={<DeleteOutlined />} onClick={e => e.stopPropagation()}/> |
|
|
|
|
</Popconfirm> |
|
|
|
|
</div> |
|
|
|
|
<div> |
|
|
|
|
<Button type="text" icon={<CopyOutlined />} onClick={e => {copyFilePath(item.url)}}></Button> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
{filePage.pageNum * filePage.pageSize > filePage.total && <div className={css.nofile}>没有了</div>} |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</Drawer> |
|
|
|
|
</div> |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|