完成编辑部份的整体,还可以优化显示效果

main
expressgy 2 years ago
parent b5b91b8ccb
commit 2e27efcaf8
  1. 1
      src/assets/add.svg
  2. 48
      src/assets/default.scss
  3. 7
      src/assets/setting.svg
  4. 56
      src/components/DirectoryStructureTree/index.jsx
  5. 44
      src/components/DirectoryStructureTree/index.module.scss
  6. 4
      src/components/Editor/index.jsx
  7. 20
      src/request/api.js
  8. 50
      src/store/defaultStore.js
  9. 2
      src/tools/index.js
  10. 164
      src/view/EditPageNew/index.jsx
  11. 48
      src/view/EditPageNew/index.module.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="1676972114612" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2775" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64z m192 472c0 4.4-3.6 8-8 8H544v152c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V544H328c-4.4 0-8-3.6-8-8v-48c0-4.4 3.6-8 8-8h152V328c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v152h152c4.4 0 8 3.6 8 8v48z" p-id="2776" data-spm-anchor-id="a313x.7781069.0.i0" class="selected" fill="#ff9a00"></path></svg>

After

Width:  |  Height:  |  Size: 703 B

@ -3,14 +3,17 @@
src: local("Apple Color Emojiji"), local("Segoe UI Emoji"), local("Segoe UI Symbol"), local("Noto Color Emoji");
unicode-range: U+1F000-1F644, U+203C-3299;
}
//无线字体
body {
font-family: system-ui, apple-system, Segoe UI, Rototo, Emoji, Helvetica, Arial, sans-serif;
}
//衬线字体
@mixin font-serif {
font-family: Georgia, Cambria, "Times New Roman", Times, serif;
}
//等宽字体
@mixin font-mono {
font-family: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
@ -18,33 +21,50 @@ body {
//以上字体总结 来源于B站Upzhangxinxu https://www.bilibili.com/video/BV1b54y1Z7pu/?spm_id_from=333.337.search-card.all.click&vd_source=2f8cd1eff8d87be6af7bdcbccbd60ade
@mixin widthAuto{
@mixin widthAuto {
/*div宽度适应文字*/
width:fit-content;
width:-webkit-fit-content;
width:-moz-fit-content;
width: fit-content;
width: -webkit-fit-content;
width: -moz-fit-content;
}
@mixin noSelect{
@mixin noSelect {
/*无法选中*/
-webkit-touch-callout:none;
-webkit-user-select:none;
-khtml-user-select:none;
-moz-user-select:none;
-ms-user-select:none;
user-select:none;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
//浸水模糊效果
@mixin beautifulBlurWhite{
@mixin beautifulBlurWhite {
background-color: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(20px) saturate(5);
}
//浸水模糊效果
@mixin beautifulBlur{
@mixin beautifulBlur {
backdrop-filter: blur(20px) saturate(1);
}
//壁纸适应效果
@mixin autoBackgroundImg{
@mixin autoBackgroundImg {
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
@mixin autoHide {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@mixin threeLineHide {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
}

@ -0,0 +1,7 @@
<?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="1676972140689" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3897"
xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200">
<path d="M940.8 512C940.8 454.4 972.8 403.2 1024 384 998.4 294.4 947.2 211.2 883.2 147.2 838.4 179.2 774.4 185.6 723.2 160 672 128 646.4 76.8 652.8 19.2 608 6.4 556.8 0 512 0 460.8 0 416 6.4 371.2 19.2 377.6 70.4 352 128 300.8 160 249.6 192 185.6 185.6 140.8 147.2 76.8 211.2 25.6 294.4 0 384 51.2 403.2 83.2 454.4 83.2 512 83.2 569.6 51.2 620.8 0 640 25.6 729.6 76.8 812.8 140.8 876.8 185.6 844.8 249.6 838.4 300.8 864 352 896 377.6 947.2 371.2 1004.8 416 1017.6 467.2 1024 512 1024 563.2 1024 608 1017.6 652.8 1004.8 646.4 953.6 672 896 723.2 864 774.4 832 838.4 838.4 883.2 876.8 947.2 812.8 998.4 729.6 1024 640 972.8 620.8 940.8 569.6 940.8 512L940.8 512ZM512 723.2C390.4 723.2 294.4 627.2 294.4 512 294.4 396.8 390.4 300.8 512 300.8 633.6 300.8 729.6 396.8 729.6 512 729.6 627.2 633.6 723.2 512 723.2ZM512 640C582.692448 640 640 582.692448 640 512 640 441.307552 582.692448 384 512 384 441.307552 384 384 441.307552 384 512 384 582.692448 441.307552 640 512 640Z"
fill="#17B978" p-id="3898" data-spm-anchor-id="a313x.7781069.0.i3" class="selected"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -1,14 +1,60 @@
// Nie 2023/2/8
import css from './index.module.scss'
export default function DirectoryStructureTree(props){
import svgSetting from '@/assets/setting.svg'
import svgAdd from '@/assets/add.svg'
import {defaultStore} from "@/store/index.js";
import {useEffect, useState} from "react";
import {autorun} from "mobx";
export default function DirectoryStructureTree(props) {
const [chooseId, setChooseId] = useState(null)
function handleSetting(e, id) {
e.stopPropagation();
defaultStore.setSettingMenuId(id)
}
function handleCreate(e, id) {
e.stopPropagation();
defaultStore.setNewMenuChildren(id)
}
function handleChoose(e, id){
e.stopPropagation();
defaultStore.setChooseMenuId(id)
}
useEffect(() => {
const a = autorun(() => {
if(defaultStore.menuId == chooseId) return
console.log(defaultStore.menuId)
setChooseId(defaultStore.menuId)
})
return () => {
a()
}
})
return props.tree.map((item, index) => {
if(item.children && Array.isArray(item.children)){
if (item.children && Array.isArray(item.children)) {
return <div key={index} className={css.directoryStructureTree}>
<div>{item.name}</div>
<div className={chooseId == item.id ? [css.title, css.titleChoose].join(' ') : css.title} onClick={e => handleChoose(e, item.id)}>
<div className={css.text}>{item.name}</div>
<div className={css.cmd}>
<img src={svgAdd} alt="" onClick={e => handleCreate(e, item.id)}/><img src={svgSetting} alt=""
onClick={e => handleSetting(e, item.id)}/>
</div>
</div>
<div>{DirectoryStructureTree({tree: item.children})}</div>
</div>
}else{
return <div key={index} className={css.directoryStructureTree}>{item.name}</div>
} else {
return <div key={index} className={css.directoryStructureTree}>
<div className={chooseId == item.id ? [css.title, css.titleChoose].join(' ') : css.title} onClick={e => handleChoose(e, item.id)}>
<div className={css.text}>{item.name}</div>
<div className={css.cmd}><img src={svgAdd} alt="" onClick={e => handleCreate(e, item.id)}/><img
src={svgSetting} alt="" onClick={e => handleSetting(e, item.id)}/></div>
</div>
</div>
}
})
}

@ -1,7 +1,47 @@
.directoryStructureTree{
@import '@/assets/default.scss';
.directoryStructureTree {
position: relative;
line-height: 1.5em;
border-radius: 10px;
margin: 1em;
margin: 0.5rem 0;
padding-left: 0.5rem;
cursor: pointer;
& > div.title {
position: relative;
display: flex;
border-radius: 10px;
padding: 0.3rem 0.5rem;
transition: background ease-in-out 300ms;
&:hover{
background: #66666622;
}
& > div.text {
position: relative;
flex: 1;
@include autoHide;
@include font-serif;
font-weight: 600;
}
& > div.cmd {
position: relative;
//width: 50px;
flex-shrink: 0;
display: flex;
align-items: center;
& > img{
width: 25px;
}
& > img:nth-child(2){
width: 22px;
margin-left: 10px;
}
}
}
& > div.titleChoose{
background: #ffc93c99 !important;
}
}

@ -14,7 +14,7 @@ export default function Editor(props) {
const [inputValue, setInputValue] = useState('')
const [img, setImg] = useState(svgImg)
const [defaultImg, setDefaultImg] = useState('')
if(!props.element) return null
useEffect(() => {
// console.log('ELement', props.element)
setElement(props.element)
@ -111,7 +111,7 @@ export default function Editor(props) {
defaultStore.setInputValue(url)
}
if(!props.element) return null
switch (element.identify) {
//

@ -29,5 +29,25 @@ export default {
formData.append(item, data[item])
})
return instance.post('/fileStorage/putfile/',formData)
},
getMenuList(){
return instance.get('/menu/getMenu/')
},
createMenuItem(data){
const formData = new FormData()
Object.keys(data).map(item => {
formData.append(item, data[item])
})
return instance.post('/menu/createMneuItem/',formData)
},
deleteMenuItem(data){
return instance.delete('/menu/deleteMenu/',{params:data})
},
updateMenuItem(data){
const formData = new FormData()
Object.keys(data).map(item => {
formData.append(item, data[item])
})
return instance.put('/menu/updateMenu/',formData)
}
}

@ -38,8 +38,14 @@ class DefaultStore {
// 容器列表
thumbnailList = [];
// 菜单列表
menuList = [];
// 当前MenuId
menuId = 10;
// 创建子菜单的ID
newMenuChidlrenId = null;
// 设置菜单
settingMenuId = null;
// 修改样式参数
styleRealRand = null;
styleReal = null;
@ -64,6 +70,7 @@ class DefaultStore {
deleteChooseNodeId: observable,
newElementIdentify: observable,
thumbnailList: observable,
menuList: observable,
menuId: observable,
styleRealRand: observable,
styleReal: observable,
@ -72,6 +79,8 @@ class DefaultStore {
templateList:observable,
templateAddModalState: observable,
templateContainer: observable,
newMenuChidlrenId: observable,
settingMenuId: observable,
containerList: computed,
@ -89,9 +98,15 @@ class DefaultStore {
setTemplateAddModalState: action,
setTemplateContainer:action,
createTemplateConatiner: action,
getMenuList: action,
createMneuItem: action,
setNewMenuChildren: action,
setSettingMenuId: action,
setChooseMenuId: action
});
}
// 获取页面容器列表
get containerList() {
const containerList = {}
this.thumbnailList.map(item => {
@ -134,6 +149,18 @@ class DefaultStore {
setTemplateContainer(container){
this.templateContainer = container
}
// 设置增加子菜单
setNewMenuChildren(id){
this.newMenuChidlrenId = id
}
// 设置菜单
setSettingMenuId(id){
this.settingMenuId = id
}
// 选择菜单
setChooseMenuId(id){
this.menuId = id
}
// 获取内容列表
async getContainerList(menuId) {
@ -181,6 +208,29 @@ class DefaultStore {
const response = await api.deleteContainer(data)
this.getContainerList(this.menuId)
}
// 获取菜单
async getMenuList(){
const response = await api.getMenuList()
runInAction(() => {
this.menuList = response.data.data
console.log(this.menuList)
})
}
// 添加菜单
async createMneuItem(data){
await api.createMenuItem(data)
this.getMenuList()
}
// 删除菜单
async deleteMenuItem(data){
await api.deleteMenuItem(data)
this.getMenuList()
}
// 更新菜单
async updateMenuItem(data){
await api.updateMenuItem(data)
this.getMenuList()
}
}
export default DefaultStore

@ -34,7 +34,7 @@ export function getTargetNode(id, node) {
if (node.id == id) {
return node
} else {
if (node.childElement.length > 0) {
if (node.childElement && node.childElement.length > 0) {
const s = getTargetNode(id, node.childElement)
if (s) targetNode = s
}

@ -34,6 +34,7 @@ export default function EditPageNew() {
const [nowElement, setNowElement] = useState(null);
//
const [nowMenuId, setNowMenuId] = useState(10);
//
const [nowContainerId, setNowContainerId] = useState(0)
//
@ -41,6 +42,15 @@ export default function EditPageNew() {
//
const [attrLabelPosition, setAttrLabelPosition] = useState(0);
//
const [createMenuItemState, setCreateMenuItemState] = useState(false)
//
const [menuData, setMenuData] = useState({name:'', route:'', rank:0, father:0, icon: '', remarks:''})
//
const [menuList, setMenuList] = useState([])
//
const [deleteMenuState, setDeleteMenuState] = useState(false)
//
const [templateAddModalState, setTemplateAddModalState] = useState(false)
@ -51,9 +61,70 @@ export default function EditPageNew() {
useEffect(() => {
console.log('生命周期开始,发送请求!')
defaultStore.getContainerList(10)
// defaultStore.getContainerList(10)
defaultStore.getTemplateList()
defaultStore.getMenuList()
}, [0])
//
useEffect(() => {
const a = autorun(() => {
if(defaultStore.menuList.length ==0)return
setMenuList(defaultStore.menuList)
})
return () => {
a()
}
})
//
useEffect(() => {
const a = autorun(() => {
if(defaultStore.newMenuChidlrenId == null)return;
const menu = {name:'', route:'', rank:0, father:0, icon: '', remarks:''}
const menuItem = menuList.find(item => {
if(item.id == defaultStore.newMenuChidlrenId) return true
})
menu.father = menuItem.id
setCreateMenuItemState(true)
setMenuData({...menu})
//
defaultStore.setNewMenuChildren(null)
})
return () => {
a()
}
})
//
useEffect(() => {
const a = autorun(() => {
if(defaultStore.settingMenuId == null)return;
const menuItem = menuList.find(item => {
if(item.id == defaultStore.settingMenuId) return true
})
setCreateMenuItemState(true)
setMenuData({...menuItem})
setDeleteMenuState(true)
//
defaultStore.setSettingMenuId(null)
})
return () => {
a()
}
})
//
useEffect(() => {
const a = autorun(() => {
if(defaultStore.menuId == nowMenuId) return
setNowMenuId(defaultStore.menuId)
defaultStore.getContainerList(defaultStore.menuId)
setNowContent({})
setNowElement(null)
defaultStore.setChooseNodeId(null)
setNowContainerId(0)
})
return () => {
a()
}
},[nowMenuId])
//
useEffect(() => {
const q = autorun(() => {
@ -147,12 +218,13 @@ export default function EditPageNew() {
const a = autorun(() => {
if(!(defaultStore.inputValue && nowElement))return
const node = getTargetNode(defaultStore.chooseNodeId, nowContent)
console.log(node)
if (!node) {
alert('未找到节点元素。')
} else {
setNowElement(node)
// setNowElement(node)
}
nowElement.inputValue = defaultStore.inputValue
node.inputValue = defaultStore.inputValue
setNowElement(JSON.parse(JSON.stringify(nowElement)))
setNowContent(JSON.parse(JSON.stringify(nowContent)))
for (let i in nowContentList) {
@ -184,7 +256,6 @@ export default function EditPageNew() {
if(defaultStore.templateList){
if(defaultStore.templateList != templateList){
setTemplateList(defaultStore.templateList)
console.log('SETT', defaultStore.templateList)
}
}
})
@ -318,6 +389,52 @@ export default function EditPageNew() {
setAttrLabelPosition(index)
}
//
function closeCreateMenuModal(){
setCreateMenuItemState(false)
setDeleteMenuState(false)
}
//
function handleCancelCreateMenuItem(){
closeCreateMenuModal()
}
//
function handleCreateMenuItem(){
closeCreateMenuModal()
if(deleteMenuState){
defaultStore.updateMenuItem(menuData)
}else{
defaultStore.createMneuItem(menuData)
}
setDeleteMenuState(false)
}
//
function handleDeleteMenuItem(){
closeCreateMenuModal()
defaultStore.deleteMenuItem({
id:menuData.id
})
}
//
function handleMenuDataChange(e, name){
const value = e.target.value
switch (name){
case 'name':
menuData.name = value
break;
case 'route':
menuData.route = value
break;
case 'rank':
menuData.rank = value
break;
case 'remarks':
menuData.remarks = value
break
}
setMenuData({...menuData})
}
return <div className={css.editPageNew}>
<div className={css.container}>
@ -332,8 +449,37 @@ export default function EditPageNew() {
</header>
<div className={css.main}>
<div className={css.container}>
<Modal state={createMenuItemState} close={closeCreateMenuModal} width={"400"}>
<div className={css.menuModal}>
<div className={css.title}>编辑菜单信息</div>
<div className={css.main}>
<div className={css.box}>
<div>菜单名称</div>
<div><input type="text" value={menuData.name} onChange={e => handleMenuDataChange(e, 'name')}/></div>
</div>
<div className={css.box}>
<div>路由标志</div>
<div><input type="text" value={menuData.route} onChange={e => handleMenuDataChange(e, 'route')}/></div>
</div>
<div className={css.box}>
<div>菜单说明</div>
<div><input type="text" value={menuData.remarks} onChange={e => handleMenuDataChange(e, 'remarks')}/></div>
</div>
<div className={css.box}>
<div>菜单位置</div>
<div><input type="number" value={menuData.rank} onChange={e => handleMenuDataChange(e, 'rank')}/></div>
</div>
</div>
<div className={css.footer}>
<Button onClick={handleCancelCreateMenuItem}>取消</Button>
{deleteMenuState && <Button onClick={handleDeleteMenuItem} type={'error'}>删除</Button>}
<Button type={'success'} onClick={handleCreateMenuItem}>确认</Button>
</div>
</div>
</Modal>
<div className={css.addMenu}><Button size={'undersize'} type={'warning'} onClick={() => setCreateMenuItemState(true)}>添加根目录</Button></div>
<DirectoryStructureTree
tree={defaultStore.directoryStructureTree}></DirectoryStructureTree>
tree={menuList}></DirectoryStructureTree>
</div>
</div>
<footer>
@ -351,7 +497,7 @@ export default function EditPageNew() {
<div className={css.main}>
<div className={css.container}>
<div className={css.left}>
<div className={css.title}>大纲</div>
<div className={css.title}>页面容器</div>
<div className={css.thumbnail}>
<div className={css.container}>
<div className={css.moleculeList}>
@ -387,7 +533,7 @@ export default function EditPageNew() {
</div>
<Modal state={addThumbnailState} close={closeThumbnailModal} width={"300"}>
<div className={css.addThumbnailState}>
<div className={css.title}>添加大纲</div>
<div className={css.title}>添加容器</div>
<div className={css.main}>
<div>大纲名称</div>
<div><input type="text" value={newThumbnailName}
@ -395,7 +541,7 @@ export default function EditPageNew() {
setNewThumbnailName(event.target.value)
}}/></div>
</div>
<div className={css.ok}><div onClick={addThumbnail}>确认</div>
<div className={css.ok}><Button onClick={addThumbnail}>确认</Button>
</div>
</div>
</Modal>
@ -409,7 +555,7 @@ export default function EditPageNew() {
setTemplateName(event.target.value)
}}/></div>
</div>
<div className={css.ok}><div onClick={addTemplate}>确认</div>
<div className={css.ok}><Button onClick={addTemplate}>确认</Button>
</div>
</div>
</Modal>

@ -123,6 +123,11 @@
div.container {
position: relative;
flex: 1;
& > div.addMenu{
display: flex;
align-items: center;
justify-content: center;
}
}
}
@ -555,4 +560,47 @@
display: flex;
justify-content: center;
}
}
div.menuModal{
position: relative;
& > div.title{
position: relative;
text-align: center;
font-size: 1.2rem;
@include font-serif;
font-weight: 600;
}
& > div.main{
position: relative;
& > div.box{
position: relative;
display: flex;
margin: 0.5rem 0;
& > div:nth-child(1){
position: relative;
flex-shrink: 0;
margin-right: 1rem;
}
& > div:nth-child(2){
position: relative;
flex: 1;
border-bottom: 1px solid #333;
display: flex;
& > input{
//display: block;
flex: 1;
}
}
}
}
& > div.footer{
position: relative;
@include widthAuto;
display: flex;
margin: 0 auto;
& > div{
margin: 0 1rem;
}
}
}
Loading…
Cancel
Save