🆕编辑器添加一键生成H5分享海报图功能 | The editor adds a one-click build H5 share poster chart feature

This commit is contained in:
xujiang 2020-11-18 13:11:47 +08:00
parent c27ca0cccd
commit c98dc26094
13 changed files with 331 additions and 503 deletions

View File

@ -11,9 +11,9 @@ export default defineConfig({
devtool: 'source-map',
antd: {},
title: '趣谈前端-h5-dooring',
exportStatic: {},
// exportStatic: {},
base: '/',
publicPath: './',
publicPath: '/',
outputPath: 'dist',
esbuild: {},
routes: [

View File

@ -1,40 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link
href="http://io.nainor.com/uploads/logo_1742fd359da.png"
rel="shortcut icon"
type="image/vnd.microsoft.icon"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>趣谈前端-h5-dooring</title>
<meta
name="description"
content="Dooring是一款功能强大开源免费的H5可视化页面配置解决方案致力于提供一套简单方便、专业可靠、无限可能的H5落地页最佳实践。"
/>
<meta
name="keywords"
content="H5,HTML5,javascript,react,nodejs,前端开发,github,开源"
/>
<meta name="author" content="徐小夕" />
<!-- <meta name="robots" content="noindex, nofollow"> -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<link
href="https://cdn.bootcdn.net/ajax/libs/spinkit/2.0.1/spinkit.min.css"
rel="stylesheet"
/>
<link rel="stylesheet" href="./umi.css" />
<script>
window.routerBase = "/";
</script>
<script>
//! umi version: 3.2.23
</script>
</head>
<body>
<div id="root"></div>
<script src="./umi.js"></script>
</body>
</html>

40
dist/help/index.html vendored
View File

@ -1,40 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link
href="http://io.nainor.com/uploads/logo_1742fd359da.png"
rel="shortcut icon"
type="image/vnd.microsoft.icon"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>趣谈前端-h5-dooring</title>
<meta
name="description"
content="Dooring是一款功能强大开源免费的H5可视化页面配置解决方案致力于提供一套简单方便、专业可靠、无限可能的H5落地页最佳实践。"
/>
<meta
name="keywords"
content="H5,HTML5,javascript,react,nodejs,前端开发,github,开源"
/>
<meta name="author" content="徐小夕" />
<!-- <meta name="robots" content="noindex, nofollow"> -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<link
href="https://cdn.bootcdn.net/ajax/libs/spinkit/2.0.1/spinkit.min.css"
rel="stylesheet"
/>
<link rel="stylesheet" href="./umi.css" />
<script>
window.routerBase = "/";
</script>
<script>
//! umi version: 3.2.23
</script>
</head>
<body>
<div id="root"></div>
<script src="./umi.js"></script>
</body>
</html>

40
dist/ide/index.html vendored
View File

@ -1,40 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link
href="http://io.nainor.com/uploads/logo_1742fd359da.png"
rel="shortcut icon"
type="image/vnd.microsoft.icon"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>趣谈前端-h5-dooring</title>
<meta
name="description"
content="Dooring是一款功能强大开源免费的H5可视化页面配置解决方案致力于提供一套简单方便、专业可靠、无限可能的H5落地页最佳实践。"
/>
<meta
name="keywords"
content="H5,HTML5,javascript,react,nodejs,前端开发,github,开源"
/>
<meta name="author" content="徐小夕" />
<!-- <meta name="robots" content="noindex, nofollow"> -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<link
href="https://cdn.bootcdn.net/ajax/libs/spinkit/2.0.1/spinkit.min.css"
rel="stylesheet"
/>
<link rel="stylesheet" href="./umi.css" />
<script>
window.routerBase = "/";
</script>
<script>
//! umi version: 3.2.23
</script>
</head>
<body>
<div id="root"></div>
<script src="./umi.js"></script>
</body>
</html>

6
dist/index.html vendored
View File

@ -8,7 +8,7 @@
type="image/vnd.microsoft.icon"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>趣谈前端-h5-dooring</title>
<title>H5编辑器之神-Dooring</title>
<meta
name="description"
content="Dooring是一款功能强大开源免费的H5可视化页面配置解决方案致力于提供一套简单方便、专业可靠、无限可能的H5落地页最佳实践。"
@ -24,7 +24,7 @@
href="https://cdn.bootcdn.net/ajax/libs/spinkit/2.0.1/spinkit.min.css"
rel="stylesheet"
/>
<link rel="stylesheet" href="./umi.css" />
<link rel="stylesheet" href="/umi.css" />
<script>
window.routerBase = "/";
</script>
@ -35,6 +35,6 @@
<body>
<div id="root"></div>
<script src="./umi.js"></script>
<script src="/umi.js"></script>
</body>
</html>

40
dist/login/index.html vendored
View File

@ -1,40 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link
href="http://io.nainor.com/uploads/logo_1742fd359da.png"
rel="shortcut icon"
type="image/vnd.microsoft.icon"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>趣谈前端-h5-dooring</title>
<meta
name="description"
content="Dooring是一款功能强大开源免费的H5可视化页面配置解决方案致力于提供一套简单方便、专业可靠、无限可能的H5落地页最佳实践。"
/>
<meta
name="keywords"
content="H5,HTML5,javascript,react,nodejs,前端开发,github,开源"
/>
<meta name="author" content="徐小夕" />
<!-- <meta name="robots" content="noindex, nofollow"> -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<link
href="https://cdn.bootcdn.net/ajax/libs/spinkit/2.0.1/spinkit.min.css"
rel="stylesheet"
/>
<link rel="stylesheet" href="./umi.css" />
<script>
window.routerBase = "/";
</script>
<script>
//! umi version: 3.2.23
</script>
</head>
<body>
<div id="root"></div>
<script src="./umi.js"></script>
</body>
</html>

View File

@ -1,40 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link
href="http://io.nainor.com/uploads/logo_1742fd359da.png"
rel="shortcut icon"
type="image/vnd.microsoft.icon"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>趣谈前端-h5-dooring</title>
<meta
name="description"
content="Dooring是一款功能强大开源免费的H5可视化页面配置解决方案致力于提供一套简单方便、专业可靠、无限可能的H5落地页最佳实践。"
/>
<meta
name="keywords"
content="H5,HTML5,javascript,react,nodejs,前端开发,github,开源"
/>
<meta name="author" content="徐小夕" />
<!-- <meta name="robots" content="noindex, nofollow"> -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<link
href="https://cdn.bootcdn.net/ajax/libs/spinkit/2.0.1/spinkit.min.css"
rel="stylesheet"
/>
<link rel="stylesheet" href="./umi.css" />
<script>
window.routerBase = "/";
</script>
<script>
//! umi version: 3.2.23
</script>
</head>
<body>
<div id="root"></div>
<script src="./umi.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@ -1,40 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link
href="http://io.nainor.com/uploads/logo_1742fd359da.png"
rel="shortcut icon"
type="image/vnd.microsoft.icon"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>趣谈前端-h5-dooring</title>
<meta
name="description"
content="Dooring是一款功能强大开源免费的H5可视化页面配置解决方案致力于提供一套简单方便、专业可靠、无限可能的H5落地页最佳实践。"
/>
<meta
name="keywords"
content="H5,HTML5,javascript,react,nodejs,前端开发,github,开源"
/>
<meta name="author" content="徐小夕" />
<!-- <meta name="robots" content="noindex, nofollow"> -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<link
href="https://cdn.bootcdn.net/ajax/libs/spinkit/2.0.1/spinkit.min.css"
rel="stylesheet"
/>
<link rel="stylesheet" href="./umi.css" />
<script>
window.routerBase = "/";
</script>
<script>
//! umi version: 3.2.23
</script>
</head>
<body>
<div id="root"></div>
<script src="./umi.js"></script>
</body>
</html>

443
dist/umi.js vendored

File diff suppressed because it is too large Load Diff

2
dist/umi.js.map vendored

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
import React, { useRef, memo, useMemo, useContext, useState, useEffect } from 'react';
import { Button, Input, Modal, Select, Upload } from 'antd';
import { Button, Input, Modal, Select, Upload, Tooltip, Badge } from 'antd';
import {
ArrowLeftOutlined,
MobileOutlined,
@ -12,6 +12,7 @@ import {
CodeOutlined,
SketchOutlined,
UploadOutlined,
InstagramOutlined,
} from '@ant-design/icons';
import { history } from 'umi';
import QRCode from 'qrcode.react';
@ -38,6 +39,8 @@ interface HeaderComponentProps {
const HeaderComponent = memo((props: HeaderComponentProps) => {
const { pointData, location, clearData, undohandler, redohandler, importTpl } = props;
const [showModalIframe, setShowModalIframe] = useState(false);
const [showFaceModal, setShowFaceModal] = useState(false);
const [faceUrl, setFaceUrl] = useState('');
const iptRef = useRef<Input>(null);
const toPreview = () => {
@ -205,6 +208,18 @@ const HeaderComponent = memo((props: HeaderComponentProps) => {
[],
);
const generatePoster = () => {
localStorage.setItem('pointData', JSON.stringify(pointData));
setShowModalIframe(true);
setTimeout(() => {
setShowFaceModal(true);
}, 3600);
};
const handleReloadPage = () => {
document.getElementById('previewPage').contentWindow.location.reload();
};
const { setTheme } = useContext(dooringContext);
return (
<div className={styles.header}>
@ -288,6 +303,18 @@ const HeaderComponent = memo((props: HeaderComponentProps) => {
<Button type="link" style={{ marginRight: '9px' }} title="重做" onClick={redohandler}>
<RedoOutlined />
</Button>
<Tooltip placement="bottom" title="一键生成海报分享图">
<Badge dot offset={[-18, 10]}>
<Button
type="link"
style={{ marginRight: '6px' }}
onClick={generatePoster}
disabled={!pointData.length}
>
<InstagramOutlined />
</Button>
</Badge>
</Tooltip>
<Button type="link" onClick={toPreview} disabled={!pointData.length}>
</Button>
@ -323,19 +350,31 @@ const HeaderComponent = memo((props: HeaderComponentProps) => {
</Button>
</div>
<Modal
title="正在生成封面..."
title="生成封面...(长时间未反应请点右侧按钮重试)"
visible={showModalIframe}
footer={null}
width={420}
closable={false}
width={414}
closeIcon={<RedoOutlined />}
destroyOnClose={true}
onCancel={handleReloadPage}
maskClosable={false}
>
<iframe
title="editor"
src={`/h5_plus/preview?tid=${props.location.query.tid}&gf=1`}
id="previewPage"
src={`/preview?tid=${props.location.query.tid}&gf=1`}
style={{ width: '100%', border: 'none', height: '600px' }}
></iframe>
</Modal>
<Modal
title="封面图(右键复制图片)"
visible={showFaceModal}
footer={null}
width={414}
destroyOnClose={true}
onCancel={() => setShowFaceModal(false)}
>
<img src={faceUrl} style={{ width: '100%' }} />
</Modal>
</div>
);
});

View File

@ -6,6 +6,7 @@ import req from '@/utils/req';
import styles from './index.less';
import { useGetScrollBarWidth } from '@/utils/tool';
import { LocationDescriptorObject } from 'history-with-query';
const isMac = navigator.platform.indexOf('Mac') === 0;
interface PreviewPageProps {
@ -33,20 +34,38 @@ const PreviewPage = memo((props: PreviewPageProps) => {
}));
});
const [pageData, setPageData] = useState(() => {
let pageConfigStr = localStorage.getItem('pageConfig');
let pageConfig;
try {
pageConfig = JSON.parse(pageConfigStr!) || {};
} catch (err) {
pageConfig = {};
}
return pageConfig;
});
const vw = window.innerWidth;
useEffect(() => {
const { tid, gf } = props.location.query!;
if (!gf) {
if (!gf && parent.window.location.pathname === '/preview') {
req
.get<any, PointDataItem[]>('/visible/preview/get', { params: { tid } })
.get<any, any>('/xxx/xxx/你的自定义接口地址', { params: { tid } })
.then(res => {
const { pageConfig, tpl } = res || { pageConfig: {}, tpl: [] };
// 设置标题
document.title = pageConfig.title || 'H5-Dooring | 强大的H5编辑神器';
// 设置数据源
setPointData(
res.map(item => ({
tpl.map(item => ({
...item,
point: { ...item.point, isDraggable: false, isResizable: false },
})),
);
setPageData(pageConfig);
})
.catch(err => {
console.error(err);
@ -62,27 +81,31 @@ const PreviewPage = memo((props: PreviewPageProps) => {
}, [props.location.query]);
const ref = useRef<HTMLDivElement>(null);
const refImgDom = useRef<HTMLDivElement>(null);
const width = useGetScrollBarWidth(ref);
const pcStyle: CSSProperties = useMemo(() => {
return {
width: isMac ? 395 : 375 + width + 1, //小数会有偏差
width: isMac ? 382 : 375 + width + 1, //小数会有偏差
margin: '55px auto',
height: '684px',
overflow: 'auto',
position: 'relative',
transform: 'scale(0.7) translateY(-80px)',
backgroundColor: pageData.bgColor,
};
}, [width]);
const generateImg = (cb: any) => {
domtoimage
.toBlob(ref.current)
.toBlob(refImgDom.current, {
bgcolor: '#fff',
})
.then(function(blob: Blob) {
const formData = new FormData();
formData.append('file', blob, 'tpl.jpg');
req.post('/files/xxx', formData).then((res: any) => {
cb && cb(res.url);
});
const reader = new FileReader();
reader.onload = function(e) {
cb && cb(e?.target?.result);
};
reader.readAsDataURL(blob);
})
.catch(function(error: any) {
console.error('oops, something went wrong!', error);
@ -91,20 +114,35 @@ const PreviewPage = memo((props: PreviewPageProps) => {
return (
<>
<div ref={ref} style={vw > 800 ? pcStyle : {}}>
<GridLayout
className={styles.layout}
cols={24}
rowHeight={2}
width={vw > 800 ? 375 : vw}
margin={[0, 0]}
>
{pointData.map((value: PointDataItem) => (
<div className={styles.dragItem} key={value.id} data-grid={value.point}>
<DynamicEngine {...(value.item as any)} />
</div>
))}
</GridLayout>
<div
ref={ref}
style={
vw > 800
? pcStyle
: { height: '100vh', overflow: 'auto', backgroundColor: pageData.bgColor }
}
>
<div ref={refImgDom}>
<GridLayout
className={styles.layout}
cols={24}
rowHeight={2}
width={vw > 800 ? 375 : vw}
margin={[0, 0]}
style={{
backgroundColor: pageData.bgColor,
backgroundImage: pageData.bgImage ? `url(${pageData.bgImage[0].url})` : 'initial',
backgroundSize: 'contain',
backgroundRepeat: 'no-repeat',
}}
>
{pointData.map((value: PointDataItem) => (
<div className={styles.dragItem} key={value.id} data-grid={value.point}>
<DynamicEngine {...(value.item as any)} />
</div>
))}
</GridLayout>
</div>
</div>
{vw > 800 ? (