expressgy 1 year ago
parent 477986c61a
commit 2fa5dc27f2
  1. 1
      src/pages/Edit/cloud.svg
  2. 357
      src/pages/Edit/index.jsx
  3. 140
      src/pages/Edit/index.module.scss
  4. 126
      src/pages/Home/index.jsx
  5. 2
      src/pages/Home/index.module.scss
  6. 23
      src/request/api/edit.js
  7. 2
      src/scss/style.scss

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1687761771287" class="icon" viewBox="0 0 1356 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3414" xmlns:xlink="http://www.w3.org/1999/xlink" width="264.84375" height="200"><path d="M1299.773101 471.022325a366.046369 366.046369 0 0 0-97.271063-99.190887 379.485135 379.485135 0 0 0-29.437296-123.508653 398.683371 398.683371 0 0 0-89.591768-127.988241A405.722724 405.722724 0 0 0 950.365203 28.822952 409.562371 409.562371 0 0 0 794.85949 0.025598a401.243136 401.243136 0 0 0-226.539187 67.833767 411.482195 411.482195 0 0 0-97.911004 91.511593 261.735953 261.735953 0 0 0-63.994121-7.679295 247.657246 247.657246 0 0 0-176.623772 71.033474 245.737423 245.737423 0 0 0-72.313357 202.861362 325.730074 325.730074 0 0 0-84.472239 72.953298A309.731543 309.731543 0 0 0 0.052513 703.960924a311.011426 311.011426 0 0 0 97.271063 229.098951A323.81025 323.81025 0 0 0 328.982292 1023.931526h660.419324a360.92684 360.92684 0 0 0 255.976483-104.950357 360.92684 360.92684 0 0 0 81.272533-116.4693 355.167369 355.167369 0 0 0 27.517471-138.867241 345.568251 345.568251 0 0 0-54.395002-192.622303z" fill="#5E5C5C" p-id="3415"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -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>
)
}

@ -11,7 +11,7 @@
& > div.left {
height: 100%;
flex-shrink: 0;
width: 220px;
width: 260px;
border-right: 1px solid #cdcdcd;
display: flex;
flex-direction: column;
@ -44,6 +44,48 @@
& > div.right {
height: 100%;
flex: 1;
.editHeader{
position: relative;
height: 100%;
width: 100%;
//background: #2468f2;
display: flex;
& > div:first-child{
position: relative;
padding: 10px;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
border-radius: 5px;
transition: all ease-in-out 300ms;
&:hover{
background: #33333311;
}
& > img{
position: relative;
width: 40px;
}
& > span{
position: relative;
color:#555;
padding-left: 10px;
}
}
& > div.title{
position: relative;
padding: 10px;
flex: 1;
}
& > div:last-child{
position: relative;
padding: 10px;
flex-shrink: 0;
}
}
}
}
@ -58,7 +100,103 @@
text-overflow: ellipsis;
white-space: nowrap;
}
& > div:last-child{
position: relative;
}
}
.fileContainer{
position: relative;
height: 100%;
flex-direction: column;
display: flex;
& > header{
position: relative;
flex-shrink: 0;
}
& > div{
position: relative;
flex: 1;
overflow: auto;
padding: 10px 0;
}
}
.fileBox{
position: relative;
display: flex;
margin: 10px 0;
cursor: pointer;
transition: all ease-in-out 300ms;
border-radius: 5px;
padding: 5px;
background: #33333311;
width: 100%;
box-sizing: border-box;
overflow: hidden;
&:hover{
background: #33333333;
}
& > div{
position: relative;
}
& > div:first-child{
flex: 1;
width: 75%;
& > div{
position: relative;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
& > div.name{
font-size: 14px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
& > div.url{
color: #999;
}
& > div.show{
& > div.photo{
width: 90%;
text-align: center;
& > img{
max-height: 140px;
}
}
& > div.video{
width: 90%;
text-align: center;
& > video{
max-height: 140px;
}
}
}
}
& > div:last-child{
flex-shrink: 0;
}
}
.nofile{
position: relative;
height: 50px;
background: #2468f222;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
color:#666;
cursor: pointer;
}
.editTop{
position: relative;
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
color:#333;
}

@ -1,5 +1,9 @@
import css from './index.module.scss';
import {useNavigate, Outlet} from 'react-router-dom'
import {useNavigate, Outlet, useLocation} from 'react-router-dom'
import {useEffect, useState} from "react";
import api from "../../request/api/edit";
import { Modal, Form, Input, Button, message, Menu, Popconfirm, Drawer, Upload } from 'antd'
import {DeleteOutlined, EditOutlined, PlusOutlined} from "@ant-design/icons";
export default function Home(){
const navigate = useNavigate()
@ -11,10 +15,122 @@ export default function Home(){
window.location.href = '/'
}
console.log(useLocation().pathname)
//
const [reflush, setReflush] = useState(true)
//
const [menuTree, setMenuTree] = useState([])
//
const [menuList, setMenuList] = useState([])
//
const [atomMenuList, setAtomMenuList] = useState([])
const [messageApi, contextHolder] = message.useMessage();
//
const [openKeys, setOpenKeys] = useState([]);
// 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 => {
if(resd.data.code == 200){
setMenuList(formateMenuToList([...resd.data.data]))
setAtomMenuList([...resd.data.data])
}else{
messageApi.open({
type: 'error',
content: '获取菜单失败!',
});
}
}
)
}, [reflush])
useEffect(() => {
const list = formateMenuList(atomMenuList)
setMenuTree(list)
}, [atomMenuList])
useEffect(() => {
console.log(menuList[0])
menuList[0] && setNowMenuItemId([menuList[0].id])
}, [menuList])
//
function formateMenuList(list){
const newList = []
for(let i in list){
const item = list[i];
const newItem = {
key: item.id.toString(),
label: <div className={css.menuItem}>
<div title={item.name}>{item.name}</div></div>,
data: item
}
if(item.childrenList){
newItem.children = formateMenuList(item.childrenList)
}
newList.push(newItem)
}
return newList
};
function formateMenuToList(list){
const newList = []
list.map(item => {
const now = {...item}
if(item.childrenList){
const sonList = formateMenuToList(item.childrenList)
newList.push(...sonList)
delete now.childrenList
}
newList.push(now)
})
return newList
}
//
const onOpenChange = (keys) => {
setOpenKeys(keys)
};
//
function onSelectMenu(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)
};
return <div className={css.main}>
<header>
<div>
<div className={css.nav}></div>
<div className={css.nav}>
<Menu
mode="horizontal"
openKeys={openKeys}
onOpenChange={onOpenChange}
style={{ height: '100%', fontSize: '18px', display: 'flex', alignItems: 'center', color: '#555' }}
onSelect={onSelectMenu}
selectedKeys = {nowMenuItemId}
items={menuTree}
/>
</div>
<div className={css.cmd}>
<div>
<div className={css.title}>管理</div>
@ -27,7 +143,11 @@ export default function Home(){
</div>
</header>
<div className={css.body}>
<Outlet></Outlet>
{ useLocation().pathname != '/amis' && <Outlet></Outlet>}
{ useLocation().pathname == '/amis' && <div>
哈哈哈
</div>}
</div>
{contextHolder}
</div>
}

@ -12,7 +12,7 @@
flex-shrink: 0;
height: 80px;
border-bottom: 1px solid #cdcdcd;
z-index: 10000 !important;
z-index: 10 !important;
overflow: visible;
& > div{
position: relative;

@ -22,6 +22,29 @@ const agreementApi = {
method: 'put',
data: data
}),
// 获取图片列表
getFileList: params => request({
url: '/jiaSheng/pictureDictionary/pagePictureList',
method: 'get',
params
}),
// 保存文件信息
saveFileUrl: data => request({
url: '/jiaSheng/pictureDictionary/add',
method: 'post',
data
}),
// 删除文件信息
deleteFile: id => request({
url: `/jiaSheng/pictureDictionary/${id}`,
method: 'delete',
}),
// 添加文章内容
createContent: data => request({
url: `/jiaSheng/menuContent/add`,
method: 'post',
data
}),
// 获取 可发起 流程列表
getApproveListPage: data => request({

@ -53,7 +53,7 @@ html,body,#root{
display: flex;
border-bottom: 1px solid $editor-border-color;
box-sizing: border-box;
z-index: 1000;
z-index: 2;
.editor-header-icon svg,
.shortcut-icon-btn svg {

Loading…
Cancel
Save