mirror of
https://github.com/MrXujiang/h5-Dooring.git
synced 2025-12-21 08:40:18 +00:00
🆕 添加右键菜单,支持删除和复制组件 🆕 添加帮助引导
This commit is contained in:
parent
a7132c2c99
commit
68eedbd245
@ -34,6 +34,10 @@ export default defineConfig({
|
|||||||
path: '/ide',
|
path: '/ide',
|
||||||
component: '../pages/ide',
|
component: '../pages/ide',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/help',
|
||||||
|
component: '../pages/help',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/login',
|
path: '/login',
|
||||||
component: '../pages/login',
|
component: '../pages/login',
|
||||||
|
|||||||
@ -70,6 +70,7 @@
|
|||||||
"react": "^16.12.0",
|
"react": "^16.12.0",
|
||||||
"react-codemirror2": "^7.2.1",
|
"react-codemirror2": "^7.2.1",
|
||||||
"react-color": "^2.18.1",
|
"react-color": "^2.18.1",
|
||||||
|
"react-contexify": "^4.1.1",
|
||||||
"react-dnd": "^11.1.3",
|
"react-dnd": "^11.1.3",
|
||||||
"react-dnd-html5-backend": "^11.1.3",
|
"react-dnd-html5-backend": "^11.1.3",
|
||||||
"react-dom": "^16.12.0",
|
"react-dom": "^16.12.0",
|
||||||
|
|||||||
BIN
src/assets/1.png
Executable file
BIN
src/assets/1.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
BIN
src/assets/2.png
Executable file
BIN
src/assets/2.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
BIN
src/assets/3.png
Executable file
BIN
src/assets/3.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 144 KiB |
BIN
src/assets/4.png
Executable file
BIN
src/assets/4.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
BIN
src/assets/5.png
Executable file
BIN
src/assets/5.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 110 KiB |
BIN
src/assets/6.png
Executable file
BIN
src/assets/6.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 101 KiB |
@ -2,13 +2,14 @@ import React, { memo, useCallback, useContext, useEffect, useMemo, useState } fr
|
|||||||
import { useDrop } from 'react-dnd';
|
import { useDrop } from 'react-dnd';
|
||||||
import Draggable, { DraggableData, DraggableEvent } from 'react-draggable';
|
import Draggable, { DraggableData, DraggableEvent } from 'react-draggable';
|
||||||
import GridLayout, { ItemCallback } from 'react-grid-layout';
|
import GridLayout, { ItemCallback } from 'react-grid-layout';
|
||||||
import { Tooltip } from 'antd';
|
|
||||||
import { connect } from 'dva';
|
import { connect } from 'dva';
|
||||||
import DynamicEngine from 'components/DynamicEngine';
|
import DynamicEngine from 'components/DynamicEngine';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
import { uuid } from '@/utils/tool';
|
import { uuid } from '@/utils/tool';
|
||||||
import { Dispatch } from 'umi';
|
import { Dispatch } from 'umi';
|
||||||
import { StateWithHistory } from 'redux-undo';
|
import { StateWithHistory } from 'redux-undo';
|
||||||
|
import { Menu, Item, MenuProvider } from 'react-contexify';
|
||||||
|
import 'react-contexify/dist/ReactContexify.min.css';
|
||||||
import { dooringContext } from '@/layouts';
|
import { dooringContext } from '@/layouts';
|
||||||
interface SourceBoxProps {
|
interface SourceBoxProps {
|
||||||
pstate: { pointData: { id: string; item: any; point: any; isMenu?: any }[]; curPoint: any };
|
pstate: { pointData: { id: string; item: any; point: any; isMenu?: any }[]; curPoint: any };
|
||||||
@ -148,6 +149,43 @@ const SourceBox = memo((props: SourceBoxProps) => {
|
|||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleContextMenuDel = () => {
|
||||||
|
if (pstate.curPoint) {
|
||||||
|
dispatch({
|
||||||
|
type: 'editorModal/delPointData',
|
||||||
|
payload: { id: pstate.curPoint.id },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleContextMenuCopy = () => {
|
||||||
|
if (pstate.curPoint) {
|
||||||
|
dispatch({
|
||||||
|
type: 'editorModal/copyPointData',
|
||||||
|
payload: { id: pstate.curPoint.id },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onConTextClick = (type: string) => {
|
||||||
|
if (type === 'del') {
|
||||||
|
handleContextMenuDel();
|
||||||
|
} else if (type === 'copy') {
|
||||||
|
handleContextMenuCopy();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const MyAwesomeMenu = useCallback(
|
||||||
|
() => (
|
||||||
|
<Menu id="menu_id">
|
||||||
|
<Item onClick={() => onConTextClick('copy')}>复制</Item>
|
||||||
|
<Item onClick={() => onConTextClick('del')}>删除</Item>
|
||||||
|
</Menu>
|
||||||
|
),
|
||||||
|
[onConTextClick],
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let { width, height } = document.getElementById(canvasId)!.getBoundingClientRect();
|
let { width, height } = document.getElementById(canvasId)!.getBoundingClientRect();
|
||||||
console.log(width, height);
|
console.log(width, height);
|
||||||
@ -176,6 +214,7 @@ const SourceBox = memo((props: SourceBoxProps) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className={styles.canvasBox}>
|
<div className={styles.canvasBox}>
|
||||||
|
<MenuProvider id="menu_id">
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
transform: `scale(${scaleNum})`,
|
transform: `scale(${scaleNum})`,
|
||||||
@ -227,6 +266,7 @@ const SourceBox = memo((props: SourceBoxProps) => {
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</MenuProvider>
|
||||||
</div>
|
</div>
|
||||||
</Draggable>
|
</Draggable>
|
||||||
);
|
);
|
||||||
@ -356,7 +396,12 @@ const SourceBox = memo((props: SourceBoxProps) => {
|
|||||||
clonePointData,
|
clonePointData,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return <>{render}</>;
|
return (
|
||||||
|
<>
|
||||||
|
{render}
|
||||||
|
<MyAwesomeMenu />
|
||||||
|
</>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect((state: StateWithHistory<any>) => ({
|
export default connect((state: StateWithHistory<any>) => ({
|
||||||
|
|||||||
@ -142,6 +142,10 @@ const HeaderComponent = memo((props: HeaderComponentProps) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toHelp = () => {
|
||||||
|
window.open('/help');
|
||||||
|
};
|
||||||
|
|
||||||
const toBack = () => {
|
const toBack = () => {
|
||||||
history.push('/');
|
history.push('/');
|
||||||
};
|
};
|
||||||
@ -262,6 +266,15 @@ const HeaderComponent = memo((props: HeaderComponentProps) => {
|
|||||||
<Button type="link" onClick={toPreview} disabled={!pointData.length}>
|
<Button type="link" onClick={toPreview} disabled={!pointData.length}>
|
||||||
预览
|
预览
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
style={{ marginRight: '9px' }}
|
||||||
|
onClick={toHelp}
|
||||||
|
disabled={!pointData.length}
|
||||||
|
title="使用帮助"
|
||||||
|
>
|
||||||
|
帮助
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.btnArea}>
|
<div className={styles.btnArea}>
|
||||||
<Select
|
<Select
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
* @LastEditors: dragon
|
* @LastEditors: dragon
|
||||||
* @LastEditTime: 2020-10-08 16:12:26
|
* @LastEditTime: 2020-10-08 16:12:26
|
||||||
*/
|
*/
|
||||||
|
import { uuid } from '@/utils/tool';
|
||||||
const pointData = localStorage.getItem('userData') || '[]';
|
const pointData = localStorage.getItem('userData') || '[]';
|
||||||
|
|
||||||
function overSave(name, data) {
|
function overSave(name, data) {
|
||||||
@ -43,6 +44,22 @@ export default {
|
|||||||
curPoint: payload,
|
curPoint: payload,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
copyPointData(state, { payload }) {
|
||||||
|
const { id } = payload;
|
||||||
|
const pointData = [];
|
||||||
|
state.pointData.forEach(item => {
|
||||||
|
pointData.push({ ...item });
|
||||||
|
if (item.id === id) {
|
||||||
|
pointData.push({ ...item, id: uuid(6, 10) });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
overSave('userData', pointData);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
pointData,
|
||||||
|
};
|
||||||
|
},
|
||||||
delPointData(state, { payload }) {
|
delPointData(state, { payload }) {
|
||||||
const { id } = payload;
|
const { id } = payload;
|
||||||
const pointData = state.pointData.filter(item => item.id !== id);
|
const pointData = state.pointData.filter(item => item.id !== id);
|
||||||
|
|||||||
23
src/pages/help/index.less
Normal file
23
src/pages/help/index.less
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
.helpWrap {
|
||||||
|
width: 880px;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: auto;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding-top: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
h2 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.helpItem {
|
||||||
|
border-bottom: 1px dashed #ccc;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
h3 {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.imgWrap {
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
src/pages/help/index.tsx
Normal file
54
src/pages/help/index.tsx
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import A from '@/assets/1.png';
|
||||||
|
import B from '@/assets/2.png';
|
||||||
|
import C from '@/assets/3.png';
|
||||||
|
import D from '@/assets/4.png';
|
||||||
|
import E from '@/assets/5.png';
|
||||||
|
import F from '@/assets/6.png';
|
||||||
|
import styles from './index.less';
|
||||||
|
|
||||||
|
const Help = () => {
|
||||||
|
return (
|
||||||
|
<div className={styles.helpWrap}>
|
||||||
|
<h2>H5-Dooring使用指南</h2>
|
||||||
|
<div className={styles.helpItem}>
|
||||||
|
<h3>1. 首页功能介绍</h3>
|
||||||
|
<div className={styles.imgWrap}>
|
||||||
|
<img src={A} alt="H5编辑器, H5制作, H5设计" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={styles.helpItem}>
|
||||||
|
<h3>2. 客服机器人</h3>
|
||||||
|
<div className={styles.imgWrap}>
|
||||||
|
<img src={B} alt="H5编辑器, H5制作, H5设计" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={styles.helpItem}>
|
||||||
|
<h3>3. 编辑器页面使用说明</h3>
|
||||||
|
<div className={styles.imgWrap}>
|
||||||
|
<img src={C} alt="H5编辑器, H5制作, H5设计" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={styles.helpItem}>
|
||||||
|
<h3>4. 管理后台入口</h3>
|
||||||
|
<div className={styles.imgWrap}>
|
||||||
|
<img src={D} alt="H5编辑器, H5制作, H5设计" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={styles.helpItem}>
|
||||||
|
<h3>5. 页面管理系统使用</h3>
|
||||||
|
<div className={styles.imgWrap}>
|
||||||
|
<img src={E} alt="H5编辑器, H5制作, H5设计" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={styles.helpItem}>
|
||||||
|
<h3>6. 页面数据分析, 数据收集</h3>
|
||||||
|
<div className={styles.imgWrap}>
|
||||||
|
<img src={F} alt="H5编辑器, H5制作, H5设计" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Help;
|
||||||
@ -11791,6 +11791,14 @@ react-color@^2.18.1:
|
|||||||
reactcss "^1.2.0"
|
reactcss "^1.2.0"
|
||||||
tinycolor2 "^1.4.1"
|
tinycolor2 "^1.4.1"
|
||||||
|
|
||||||
|
react-contexify@^4.1.1:
|
||||||
|
version "4.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-contexify/-/react-contexify-4.1.1.tgz#f5eba1ad82a923c033c91d0abcea1da0a71ebaa1"
|
||||||
|
integrity sha512-WJeRI4ohHEOmNiH0xb62a/eV+5ae168FB7H6pfbeEVJkf0UN7D5H99l6b89poc2LHKN1gOimFjREyY8quGVsXA==
|
||||||
|
dependencies:
|
||||||
|
classnames "^2.2.6"
|
||||||
|
prop-types "^15.6.2"
|
||||||
|
|
||||||
react-dnd-html5-backend@^11.1.3:
|
react-dnd-html5-backend@^11.1.3:
|
||||||
version "11.1.3"
|
version "11.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-11.1.3.tgz#2749f04f416ec230ea193f5c1fbea2de7dffb8f7"
|
resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-11.1.3.tgz#2749f04f416ec230ea193f5c1fbea2de7dffb8f7"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user