Skip to content

Commit 0bd2342

Browse files
committed
feat(preview): add preview modal
1 parent a34f5f1 commit 0bd2342

File tree

10 files changed

+371
-13
lines changed

10 files changed

+371
-13
lines changed

back-end/h5-api/views/engine.ejs

+18-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
<script>window.__work = <%- JSON.stringify(work) %></script>
1818
<script src="/engine-assets/engine.js"></script>
1919
<style>
20+
* {
21+
outline: none;
22+
}
2023
.swiper-container {
2124
width: 100%;
2225
height: 100vh;
@@ -26,7 +29,9 @@
2629

2730
<body>
2831
<div id="app">
29-
<engine />
32+
<button class="swiper-button-next" style="position: fixed;left: 1000px">Next</button>
33+
<button class="swiper-button-prev" style="position: fixed;left: 1000px">Prev</button>
34+
<engine />
3035
</div>
3136
<script>
3237
// Vue.component('engine', window.Engine)
@@ -59,6 +64,18 @@
5964
el: '.swiper-scrollbar',
6065
},
6166
});
67+
68+
function displayMessage ({ origin, data }) {
69+
if (data && origin === "http://localhost:8080") {
70+
document.querySelector(`.swiper-button-${data}`).click()
71+
}
72+
}
73+
74+
if (window.addEventListener) {
75+
window.addEventListener("message", displayMessage, false);
76+
} else {
77+
window.attachEvent("onmessage", displayMessage);
78+
}
6279
</script>
6380
<!-- build:js scripts/vendor.js -->
6481
<!-- endbuild -->

front-end/h5/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"core-js": "^2.6.5",
1616
"element-ui": "^2.9.1",
1717
"font-awesome": "4.7.0",
18+
"qrcode": "^1.4.1",
1819
"register-service-worker": "^1.6.2",
1920
"strapi-sdk-javascript": "^0.3.1",
2021
"vue": "^2.6.10",

front-end/h5/public/index.html

+5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
<meta name="viewport" content="width=device-width,initial-scale=1.0">
77
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
88
<title>鲁班-H5</title>
9+
<style>
10+
* {
11+
outline: none;
12+
}
13+
</style>
914
</head>
1015
<body>
1116
<noscript>

front-end/h5/src/components/core/editor/index.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import RenderPropsEditor from './edit-panel/props'
1010
import RenderScriptEditor from './edit-panel/script'
1111
import RenderActoionEditor from './edit-panel/action'
1212
import RenderShortcutsPanel from './shortcuts-panel/index'
13+
import PreviewDialog from './modals/preview.vue'
1314

1415
const sidebarMenus = [
1516
{
@@ -34,7 +35,8 @@ export default {
3435
data: () => ({
3536
activeMenuKey: 'pluginList',
3637
isPreviewMode: false,
37-
activeTabKey: '属性'
38+
activeTabKey: '属性',
39+
previewVisible: false
3840
}),
3941
computed: {
4042
...mapState('editor', {
@@ -109,7 +111,7 @@ export default {
109111
<a-button class="transparent-bg" style={{ color: 'white' }} type="dashed" size="small" onClick={() => undoRedoHistory.redo()}><i class={['shortcut-icon', 'fa', `fa-mail-forward`]} aria-hidden='true'/> 重做</a-button>
110112
</a-button-group>
111113
</a-menu-item>
112-
<a-menu-item key="1" class="transparent-bg"><a-button type="primary" size="small">预览</a-button></a-menu-item>
114+
<a-menu-item key="1" class="transparent-bg"><a-button type="primary" size="small" onClick={() => { this.previewVisible = true }}>预览</a-button></a-menu-item>
113115
<a-menu-item key="2" class="transparent-bg"><a-button size="small" onClick={() => this.saveWork()}>保存</a-button></a-menu-item>
114116
<a-menu-item key="3" class="transparent-bg"><a-button size="small">发布</a-button></a-menu-item>
115117
</a-menu>
@@ -185,6 +187,7 @@ export default {
185187
</a-tabs>
186188
</a-layout-sider>
187189
</a-layout>
190+
<PreviewDialog visible={this.previewVisible} handleClose={() => { this.previewVisible = false }} />
188191
</a-layout>
189192
)
190193
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
<script>
2+
import { mapActions, mapState } from 'vuex'
3+
import QRCode from 'qrcode'
4+
export default {
5+
props: {
6+
visible: {
7+
type: Boolean,
8+
default: false
9+
},
10+
handleClose: {
11+
type: Function,
12+
default: () => {}
13+
}
14+
},
15+
computed: {
16+
...mapState('editor', {
17+
work: state => state.work,
18+
}),
19+
releaseUrl () {
20+
return `//localhost:1337/works/preview/${this.work.id}`
21+
}
22+
},
23+
data() {
24+
return {
25+
confirmLoading: false,
26+
qrcodeSize: 500,
27+
}
28+
},
29+
watch: {
30+
visible (val) {
31+
if (!val) return;
32+
this.$nextTick(() => this.drawQRcode());
33+
},
34+
},
35+
methods: {
36+
...mapActions('editor', [
37+
'saveWork',
38+
'updateWork'
39+
]),
40+
handleOk(e) {
41+
this.confirmLoading = true;
42+
this.saveWork().then(res => {
43+
this.handleClose()
44+
this.confirmLoading = false;
45+
})
46+
// setTimeout(() => {
47+
// }, 2000);
48+
},
49+
handleCancel(e) {
50+
console.log('Clicked cancel button');
51+
this.handleClose()
52+
},
53+
drawQRcode () {
54+
var canvas = document.getElementById('qrcode-container');
55+
QRCode.toCanvas(canvas, this.releaseUrl, { scale: 4 }, err => {
56+
console.log(err);
57+
});
58+
},
59+
postMessage2Iframe (message) {
60+
let iframeWin = document.getElementById('iframe-for-preview').contentWindow
61+
// iframeWin.postMessage('next', window.location.origin);
62+
iframeWin.postMessage(message, 'http://localhost:1337');
63+
}
64+
},
65+
render (h) {
66+
return (
67+
<div>
68+
<a-modal
69+
title="作品设置"
70+
visible={this.visible}
71+
confirmLoading={this.confirmLoading}
72+
onOk={this.handleOk}
73+
onCancel={this.handleCancel}
74+
width="70%"
75+
okText="保存"
76+
>
77+
<div class="preview-wrapper">
78+
<a-row gutter={20}>
79+
<a-col span={8}>
80+
<div class="phone-wrapper">
81+
<div class="phone">
82+
<div class="float-ctrl-panel">
83+
<a class="page-controller" onClick={(e) => { this.postMessage2Iframe('prev') }}>上一页</a>
84+
<a class="page-controller" onClick={(e) => { this.postMessage2Iframe('next') }}>下一页</a>
85+
{/**
86+
<a-button icon="up" shape="circle" onClick={() => { this.postMessage2Iframe('prev') }}></a-button>
87+
<a-button icon="down" shape="circle" onClick={() => { this.postMessage2Iframe('next') }}></a-button>
88+
<a-icon type="up" class="page-controller" onClick={() => { this.postMessage2Iframe('prev') }}/>
89+
<a-icon type="down" class="page-controller" onClick={() => { this.postMessage2Iframe('next') }}/>
90+
*/}
91+
</div>
92+
<iframe
93+
id="iframe-for-preview"
94+
src="http://localhost:1337/works/preview/12"
95+
frameborder="0"
96+
style="height: 100%;width: 100%;"
97+
></iframe>
98+
{/** <engine :work="editingWork" :map-config="{}" /> */}
99+
</div>
100+
</div>
101+
</a-col>
102+
<a-col span={12} offset={4}>
103+
<div class="setting">
104+
<div class="info">
105+
<div class="label">设置作品信息</div>
106+
<a-input
107+
class="input"
108+
value={this.work.title}
109+
onChange={e => this.updateWork({ title: e.target.value})}
110+
// onBlur={this.saveTitle}
111+
placeholder="请输入标题"
112+
></a-input>
113+
<a-input
114+
class="input"
115+
value={this.work.description}
116+
onChange={e => this.updateWork({ description: e.target.value})}
117+
// v-model="description"
118+
// onBlur={this.saveDescription}
119+
placeholder="请输入描述"
120+
type="textarea"
121+
></a-input>
122+
</div>
123+
<div class="qrcode my-4">
124+
<div class="label">手机扫码分享给好友</div>
125+
<div class="code">
126+
<canvas style="float: left" id="qrcode-container"></canvas>
127+
<a-radio-group class="radios" value={this.qrcodeSize} onChange={e => {this.qrcodeSize = e.target.value}}>
128+
<a-radio label={500} value={500}>500x500</a-radio>
129+
<a-radio label={1000} value={1000}>1000x1000</a-radio>
130+
<a-radio label={2000} value={2000}>2000x2000</a-radio>
131+
</a-radio-group>
132+
</div>
133+
</div>
134+
</div>
135+
</a-col>
136+
</a-row>
137+
</div>
138+
</a-modal>
139+
</div>
140+
)
141+
},
142+
mounted () {
143+
}
144+
}
145+
</script>
146+
147+
148+
<style lang="scss">
149+
.preview-wrapper {
150+
position: relative;
151+
min-height: 600px;
152+
min-width: 800px;
153+
154+
.phone-wrapper {
155+
position: absolute;
156+
// margin-top: -300px;
157+
left: 10px;
158+
top: 50%;
159+
width: 320px;
160+
height: 600px;
161+
box-sizing: content-box;
162+
.phone {
163+
position: absolute;
164+
// left: 40px;
165+
width: 100%;
166+
height: calc(638px - 70px);
167+
display: inline-block;
168+
background: #fff;
169+
box-sizing: content-box;
170+
border-top: 10px solid #f6f6f6;
171+
border-left: 10px solid #f6f6f6;
172+
border-right: 10px solid #f6f6f6;
173+
border-bottom: 20px solid #f6f6f6;
174+
border-radius: 20px;
175+
-webkit-transform-origin: 100% 0;
176+
transform-origin: 100% 0;
177+
-webkit-transform: scale(1);
178+
transform: scale(1);
179+
180+
.float-ctrl-panel {
181+
position: absolute;
182+
top: 100px;
183+
right: -40px;
184+
185+
.page-controller {
186+
display: block;
187+
cursor: pointer;
188+
width: 30px;
189+
height: 80px;
190+
border-top-right-radius: 5px;
191+
border-bottom-right-radius: 5px;
192+
background: #2096f9;
193+
font-size: 12px;
194+
text-align: center;
195+
border: 1px solid #2096f9;
196+
color: #fff;
197+
// position: absolute;
198+
padding: 14px 8px;
199+
margin-top: 12px;
200+
// margin-top: -50px;
201+
}
202+
203+
}
204+
}
205+
}
206+
.setting {
207+
color: #4a4a4a;
208+
font-size: 14px;
209+
float: right;
210+
width: 380px;
211+
.info {
212+
.input {
213+
margin-top: 10px;
214+
}
215+
}
216+
.qrcode {
217+
margin-top: 20px;
218+
}
219+
.code {
220+
// !#zh 防止浮动塌陷
221+
overflow: hidden;
222+
.radios {
223+
width: 80px;
224+
margin-top: 5px;
225+
margin-left: 30px;
226+
label {
227+
margin-left: 0px;
228+
margin-top: 10px;
229+
}
230+
button {
231+
margin-top: 15px;
232+
}
233+
}
234+
}
235+
.link {
236+
width: 100%;
237+
display: block;
238+
}
239+
.edit {
240+
text-align: center;
241+
margin-top: 20px;
242+
}
243+
}
244+
}
245+
246+
</style>

front-end/h5/src/components/core/models/element.js

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { parsePx } from '../../../utils/element.js'
2+
13
const clone = (value) => JSON.parse(JSON.stringify(value))
24

35
const defaultProps = {
@@ -56,14 +58,14 @@ class Element {
5658
return pluginProps
5759
}
5860

59-
getStyle ({ position = 'static' }) {
61+
getStyle ({ position = 'static', isRem = false }) {
6062
const pluginProps = this.pluginProps
6163
const commonStyle = this.commonStyle
6264
let style = {
63-
top: `${pluginProps.top || commonStyle.top}px`,
64-
left: `${pluginProps.left || commonStyle.left}px`,
65-
width: `${pluginProps.width || commonStyle.width}px`,
66-
height: `${pluginProps.height || commonStyle.height}px`,
65+
top: parsePx(pluginProps.top || commonStyle.top),
66+
left: parsePx(pluginProps.left || commonStyle.left),
67+
width: parsePx(pluginProps.width || commonStyle.width),
68+
height: parsePx(pluginProps.height || commonStyle.height),
6769
fontSize: `${pluginProps.fontSize || commonStyle.fontSize}px`,
6870
color: pluginProps.color || commonStyle.color,
6971
// backgroundColor: pluginProps.backgroundColor || commonStyle.backgroundColor,

front-end/h5/src/store/modules/work.js

+13-1
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,21 @@ export const actions = {
1818
// commit('pageManager', { type: 'add' })
1919
// commit('setEditingPage')
2020
},
21+
updateWork ({ commit, state }, payload = {}) {
22+
// update work with strapi
23+
const work = {
24+
...state.work,
25+
...payload
26+
}
27+
commit('setWork', work)
28+
},
2129
saveWork ({ commit, state }, payload = {}) {
2230
// update work with strapi
23-
strapi.updateEntry('works', state.work.id, state.work)
31+
const work = {
32+
...state.work,
33+
...payload
34+
}
35+
strapi.updateEntry('works', state.work.id, work)
2436
},
2537
fetchWork ({ commit, state }, workId) {
2638
strapi.getEntry('works', workId).then(entry => {

0 commit comments

Comments
 (0)