Commit 722031c925351e82ea30a93d90ddc3f462f4084f

Authored by ly525
1 parent d21296a7

feat: support long page mode(alpha);

#!zh: 支持长页面(alpha)
back-end/h5-api/api/work/documentation/1.0.0/work.json
@@ -1002,6 +1002,18 @@ @@ -1002,6 +1002,18 @@
1002 }, 1002 },
1003 "is_template": { 1003 "is_template": {
1004 "type": "boolean" 1004 "type": "boolean"
  1005 + },
  1006 + "mode": {
  1007 + "type": "string",
  1008 + "enum": [
  1009 + "h5_swipper",
  1010 + "h5_long_page",
  1011 + "h5_form"
  1012 + ]
  1013 + },
  1014 + "height": {
  1015 + "type": "integer",
  1016 + "default": 568
1005 } 1017 }
1006 } 1018 }
1007 }, 1019 },
@@ -1024,6 +1036,18 @@ @@ -1024,6 +1036,18 @@
1024 }, 1036 },
1025 "is_template": { 1037 "is_template": {
1026 "type": "boolean" 1038 "type": "boolean"
  1039 + },
  1040 + "mode": {
  1041 + "type": "string",
  1042 + "enum": [
  1043 + "h5_swipper",
  1044 + "h5_long_page",
  1045 + "h5_form"
  1046 + ]
  1047 + },
  1048 + "height": {
  1049 + "type": "integer",
  1050 + "default": 568
1027 } 1051 }
1028 } 1052 }
1029 } 1053 }
back-end/h5-api/api/work/models/Work.settings.json
@@ -31,6 +31,18 @@ @@ -31,6 +31,18 @@
31 }, 31 },
32 "is_template": { 32 "is_template": {
33 "type": "boolean" 33 "type": "boolean"
  34 + },
  35 + "mode": {
  36 + "type": "enumeration",
  37 + "enum": [
  38 + "h5_swipper",
  39 + "h5_long_page",
  40 + "h5_form"
  41 + ]
  42 + },
  43 + "height": {
  44 + "type": "integer",
  45 + "default": 568
34 } 46 }
35 } 47 }
36 -}  
37 \ No newline at end of file 48 \ No newline at end of file
  49 +}
back-end/h5-api/api/workform/documentation/1.0.0/workform.json
@@ -550,6 +550,12 @@ @@ -550,6 +550,12 @@
550 }, 550 },
551 "is_template": { 551 "is_template": {
552 "type": "boolean" 552 "type": "boolean"
  553 + },
  554 + "mode": {
  555 + "type": "string"
  556 + },
  557 + "height": {
  558 + "type": "integer"
553 } 559 }
554 } 560 }
555 } 561 }
back-end/h5-api/extensions/documentation/documentation/1.0.0/full_documentation.json
1 { 1 {
2 "openapi": "3.0.0", 2 "openapi": "3.0.0",
3 "info": { 3 "info": {
4 - "version": "0.0.1",  
5 - "title": "#!zh: 鲁班H5-后端API 文档",  
6 - "description": "#!zh: 鲁班H5-后端API 文档(#!en: API docs for luban-h5)", 4 + "version": "1.0.0",
  5 + "title": "DOCUMENTATION",
  6 + "description": "",
  7 + "termsOfService": "YOUR_TERMS_OF_SERVICE_URL",
7 "contact": { 8 "contact": {
8 - "name": "Feedback",  
9 - "url": "https://github.com/ly525/luban-h5/issues/new?title=[api-docs-feedback]" 9 + "name": "TEAM",
  10 + "email": "contact-email@something.io",
  11 + "url": "mywebsite.io"
10 }, 12 },
11 - "x-generation-date": "01/26/2020 5:36:49 PM" 13 + "license": {
  14 + "name": "Apache 2.0",
  15 + "url": "https://www.apache.org/licenses/LICENSE-2.0.html"
  16 + },
  17 + "x-generation-date": "05/10/2020 10:31:59 PM"
12 }, 18 },
13 "x-strapi-config": { 19 "x-strapi-config": {
14 "path": "/documentation", 20 "path": "/documentation",
@@ -29,8 +35,8 @@ @@ -29,8 +35,8 @@
29 } 35 }
30 ], 36 ],
31 "externalDocs": { 37 "externalDocs": {
32 - "description": "#!zh 鲁班H5完整文档(#!en Full Docs for Luban-H5)",  
33 - "url": "https://ly525.github.io/luban-h5/" 38 + "description": "Find out more",
  39 + "url": "https://strapi.io/documentation/3.0.0-beta.x/"
34 }, 40 },
35 "security": [ 41 "security": [
36 { 42 {
@@ -3706,6 +3712,18 @@ @@ -3706,6 +3712,18 @@
3706 }, 3712 },
3707 "is_template": { 3713 "is_template": {
3708 "type": "boolean" 3714 "type": "boolean"
  3715 + },
  3716 + "mode": {
  3717 + "type": "string",
  3718 + "enum": [
  3719 + "h5_swipper",
  3720 + "h5_long_page",
  3721 + "h5_form"
  3722 + ]
  3723 + },
  3724 + "height": {
  3725 + "type": "integer",
  3726 + "default": 568
3709 } 3727 }
3710 } 3728 }
3711 }, 3729 },
@@ -3728,6 +3746,18 @@ @@ -3728,6 +3746,18 @@
3728 }, 3746 },
3729 "is_template": { 3747 "is_template": {
3730 "type": "boolean" 3748 "type": "boolean"
  3749 + },
  3750 + "mode": {
  3751 + "type": "string",
  3752 + "enum": [
  3753 + "h5_swipper",
  3754 + "h5_long_page",
  3755 + "h5_form"
  3756 + ]
  3757 + },
  3758 + "height": {
  3759 + "type": "integer",
  3760 + "default": 568
3731 } 3761 }
3732 } 3762 }
3733 }, 3763 },
@@ -3767,6 +3797,12 @@ @@ -3767,6 +3797,12 @@
3767 }, 3797 },
3768 "is_template": { 3798 "is_template": {
3769 "type": "boolean" 3799 "type": "boolean"
  3800 + },
  3801 + "mode": {
  3802 + "type": "string"
  3803 + },
  3804 + "height": {
  3805 + "type": "integer"
3770 } 3806 }
3771 } 3807 }
3772 } 3808 }
front-end/h5/src/components/core/editor/canvas/edit.js
@@ -10,7 +10,7 @@ export default { @@ -10,7 +10,7 @@ export default {
10 contextmenuPos: [] 10 contextmenuPos: []
11 }), 11 }),
12 computed: { 12 computed: {
13 - ...mapState('editor', ['editingElement']) 13 + ...mapState('editor', ['editingElement', 'work'])
14 }, 14 },
15 methods: { 15 methods: {
16 ...mapActions('editor', [ 16 ...mapActions('editor', [
@@ -18,7 +18,8 @@ export default { @@ -18,7 +18,8 @@ export default {
18 'setElementPosition', 18 'setElementPosition',
19 'setElementShape', 19 'setElementShape',
20 'recordElementRect', 20 'recordElementRect',
21 - 'elementManager' 21 + 'elementManager',
  22 + 'updateWork'
22 ]), 23 ]),
23 // TODO #!zh: 优化代码 24 // TODO #!zh: 优化代码
24 // generate vertical line 25 // generate vertical line
@@ -142,6 +143,43 @@ export default { @@ -142,6 +143,43 @@ export default {
142 } 143 }
143 }, 144 },
144 /** 145 /**
  146 + * 更新作品高度
  147 + * @param {Number} height
  148 + */
  149 + updateWorkHeight (height) {
  150 + this.updateWork({ height })
  151 + },
  152 + /**
  153 + * TODO 封装 adjust editor scale 组件
  154 + * scale: height/width
  155 + * @param {MouseEvent} e
  156 + */
  157 + mousedownForAdjustLine (e) {
  158 + let startY = e.clientY
  159 + let startHeight = this.work.height
  160 +
  161 + const canvasOuterWrapper = document.querySelector('#canvas-outer-wrapper')
  162 +
  163 + let move = moveEvent => {
  164 + // !#zh 移动的时候,不需要向后代元素传递事件,只需要单纯的移动就OK
  165 + moveEvent.stopPropagation()
  166 + moveEvent.preventDefault()
  167 +
  168 + let currY = moveEvent.clientY
  169 + let currentHeight = currY - startY + startHeight
  170 + this.updateWorkHeight(currentHeight)
  171 + // 交互效果:滚动条同步滚动至底部
  172 + canvasOuterWrapper && (canvasOuterWrapper.scrollTop = canvasOuterWrapper.scrollHeight)
  173 + }
  174 +
  175 + let up = moveEvent => {
  176 + document.removeEventListener('mousemove', move, true)
  177 + document.removeEventListener('mouseup', up, true)
  178 + }
  179 + document.addEventListener('mousemove', move, true)
  180 + document.addEventListener('mouseup', up, true)
  181 + },
  182 + /**
145 * #!zh: renderCanvas 渲染中间画布 183 * #!zh: renderCanvas 渲染中间画布
146 * elements 184 * elements
147 * @param {*} h 185 * @param {*} h
@@ -251,6 +289,26 @@ export default { @@ -251,6 +289,26 @@ export default {
251 onHideMenu={this.hideContextMenu} 289 onHideMenu={this.hideContextMenu}
252 /> : null 290 /> : null
253 } 291 }
  292 + <div style={{
  293 + position: 'absolute',
  294 + top: `${this.work.height}px`,
  295 + width: '100%'
  296 + }}>
  297 + <div class="long-page-adjust">
  298 + <div class="adjust-line"></div>
  299 + <div class="adjust-button" onMousedown={this.mousedownForAdjustLine}><div class="indicator"></div></div>
  300 + <div class="adjust-tip">
  301 + <span>320 x</span>
  302 + <a-input-number
  303 + size="small"
  304 + style="margin: 0 4px; width:60px;"
  305 + value={this.work.height}
  306 + onChange={height => { this.updateWork({ height }) }}
  307 + />
  308 + <span>px</span>
  309 + </div>
  310 + </div>
  311 + </div>
254 </div> 312 </div>
255 ) 313 )
256 } 314 }
front-end/h5/src/components/core/editor/edit-panel/props.js
1 import Vue from 'vue' 1 import Vue from 'vue'
2 import { mapState, mapActions } from 'vuex' 2 import { mapState, mapActions } from 'vuex'
3 import { getVM, getComponentsForPropsEditor } from '../../../../utils/element' 3 import { getVM, getComponentsForPropsEditor } from '../../../../utils/element'
  4 +import RenderGlobalWorkPropsEditor from './props/global-work.vue'
4 5
5 export default { 6 export default {
6 data: () => ({ 7 data: () => ({
@@ -141,11 +142,14 @@ export default { @@ -141,11 +142,14 @@ export default {
141 } 142 }
142 </a-form> 143 </a-form>
143 ) 144 )
  145 + },
  146 + renderWorkGlobalPropsPanel (h) {
  147 + return <RenderGlobalWorkPropsEditor />
144 } 148 }
145 }, 149 },
146 render (h) { 150 render (h) {
147 const ele = this.editingElement 151 const ele = this.editingElement
148 - if (!ele) return (<span>{this.$t('editor.editPanel.common.empty')}</span>) 152 + if (!ele) return this.renderWorkGlobalPropsPanel(h)
149 this.mixinEnhancedPropsEditor(ele) 153 this.mixinEnhancedPropsEditor(ele)
150 return this.renderPropsEditorPanel(h, ele) 154 return this.renderPropsEditorPanel(h, ele)
151 }, 155 },
front-end/h5/src/components/core/editor/edit-panel/props/global-work.vue 0 → 100644
  1 +<!--
  2 + * @Author: ly525
  3 + * @Date: 2020-05-10 23:10:52
  4 + * @LastEditors: ly525
  5 + * @LastEditTime: 2020-05-10 23:20:22
  6 + * @FilePath: /luban-h5/front-end/h5/src/components/core/editor/edit-panel/props/global-work.vue
  7 + * @Github: https://github.com/ly525/luban-h5
  8 + * @Description: Do not edit
  9 + * @Copyright 2018 - 2019 luban-h5. All Rights Reserved
  10 + -->
  11 +<template>
  12 + <a-form :layout="formLayout">
  13 + <a-form-item
  14 + label="H5类型"
  15 + >
  16 + <a-radio-group default-value="h5_swipper" @change="handleChangeMode" size="small">
  17 + <a-radio-button value="h5_swipper">
  18 + 翻页H5
  19 + </a-radio-button>
  20 + <a-radio-button value="h5_long_page">
  21 + 长页面H5
  22 + </a-radio-button>
  23 + </a-radio-group>
  24 + </a-form-item>
  25 + </a-form>
  26 +</template>
  27 +
  28 +<script>
  29 +import { mapActions } from 'vuex'
  30 +export default {
  31 + data () {
  32 + return {
  33 + formLayout: 'vertical'
  34 + }
  35 + },
  36 + methods: {
  37 + ...mapActions('editor', [
  38 + 'updateWork'
  39 + ]),
  40 + handleModeChange (e) {
  41 + this.updateWork({ mode: e.target.value })
  42 + }
  43 + }
  44 +}
  45 +</script>
front-end/h5/src/components/core/editor/index.js
@@ -311,7 +311,7 @@ export default { @@ -311,7 +311,7 @@ export default {
311 <a-layout-sider width="240" theme='light' style={{ background: '#fff', padding: '12px' }}> 311 <a-layout-sider width="240" theme='light' style={{ background: '#fff', padding: '12px' }}>
312 { this._renderMenuContent() } 312 { this._renderMenuContent() }
313 </a-layout-sider> 313 </a-layout-sider>
314 - <a-layout> 314 + <a-layout id="canvas-outer-wrapper">
315 <div class="mode-toggle-wrapper"> 315 <div class="mode-toggle-wrapper">
316 <a-radio-group 316 <a-radio-group
317 size="small" 317 size="small"
@@ -330,7 +330,9 @@ export default { @@ -330,7 +330,9 @@ export default {
330 </a-radio-group> 330 </a-radio-group>
331 </div> 331 </div>
332 <a-layout-content style={{ transform: `scale(${this.scaleRate})`, 'transform-origin': 'center top' }}> 332 <a-layout-content style={{ transform: `scale(${this.scaleRate})`, 'transform-origin': 'center top' }}>
333 - <div class='canvas-wrapper'> 333 + <div class='canvas-wrapper' style={{
  334 + height: `${this.work.height}px`
  335 + }}>
334 {/* { this.isPreviewMode ? this.renderPreview(h, this.elements) : this.renderCanvas(h, this.elements) } */} 336 {/* { this.isPreviewMode ? this.renderPreview(h, this.elements) : this.renderCanvas(h, this.elements) } */}
335 { this.isPreviewMode 337 { this.isPreviewMode
336 ? <RenderPreviewCanvas elements={this.elements}/> 338 ? <RenderPreviewCanvas elements={this.elements}/>
front-end/h5/src/components/core/models/work.js
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 * @Author: ly525 2 * @Author: ly525
3 * @Date: 2019-11-24 18:51:58 3 * @Date: 2019-11-24 18:51:58
4 * @LastEditors: ly525 4 * @LastEditors: ly525
5 - * @LastEditTime: 2019-12-15 16:24:33 5 + * @LastEditTime: 2020-05-10 23:23:40
6 * @FilePath: /luban-h5/front-end/h5/src/components/core/models/work.js 6 * @FilePath: /luban-h5/front-end/h5/src/components/core/models/work.js
7 * @Github: https://github.com/ly525/luban-h5 7 * @Github: https://github.com/ly525/luban-h5
8 * @Description: work model 8 * @Description: work model
@@ -12,6 +12,7 @@ import Page from &#39;./page.js&#39; @@ -12,6 +12,7 @@ import Page from &#39;./page.js&#39;
12 12
13 class Work { 13 class Work {
14 constructor (work = {}) { 14 constructor (work = {}) {
  15 + this.id = work.id
15 this.title = work.title || '标题' 16 this.title = work.title || '标题'
16 this.description = work.description || '描述' 17 this.description = work.description || '描述'
17 this.pages = work.pages || [new Page()] 18 this.pages = work.pages || [new Page()]
@@ -30,6 +31,13 @@ class Work { @@ -30,6 +31,13 @@ class Work {
30 31
31 this.is_publish = false 32 this.is_publish = false
32 this.is_template = false 33 this.is_template = false
  34 + this.height = work.height || 568
  35 + /**
  36 + * 页面模式,枚举值
  37 + * h5_swipper 翻页H5
  38 + * h5_long_page 长页面H5
  39 + */
  40 + this.mode = work.mode || 'h5_swipper'
33 } 41 }
34 } 42 }
35 43
front-end/h5/src/components/core/styles/canvas-wrapper.scss
@@ -11,7 +11,8 @@ $designerWidthHalf: $designerWidth / 2; @@ -11,7 +11,8 @@ $designerWidthHalf: $designerWidth / 2;
11 position: relative; 11 position: relative;
12 top: 60px; 12 top: 60px;
13 width: $designerWidth; 13 width: $designerWidth;
14 - height: $designerHeight; 14 + // height: $designerHeight;
  15 + min-height: $designerHeight;
15 margin: 0 auto; 16 margin: 0 auto;
16 background: #fff; 17 background: #fff;
17 border: 1px solid #e7e7e7; 18 border: 1px solid #e7e7e7;
@@ -33,3 +34,41 @@ $designerWidthHalf: $designerWidth / 2; @@ -33,3 +34,41 @@ $designerWidthHalf: $designerWidth / 2;
33 left: calc(50% - 120px); 34 left: calc(50% - 120px);
34 text-align: center; 35 text-align: center;
35 } 36 }
  37 +
  38 +
  39 +.long-page-adjust {
  40 + .adjust-line {
  41 + width: 100%;
  42 + height: 1px;
  43 + background-color: #1593ff;
  44 + }
  45 +
  46 + .adjust-button {
  47 + margin: 0 auto;
  48 + width: 30px;
  49 + height: 10px;
  50 + border-radius: 2px;
  51 + padding-top: 4px;
  52 + cursor: ns-resize;
  53 + background-color: #1593ff;
  54 +
  55 + .indicator {
  56 + margin: 0 auto;
  57 + width: 10px;
  58 + height: 1px;
  59 + background-color: #ccd5db;
  60 + }
  61 + }
  62 +
  63 + .adjust-tip {
  64 + letter-spacing: 1px;
  65 + padding: 0;
  66 + height: 24px;
  67 + margin: 2px auto 0;
  68 + text-align: center;
  69 + line-height: 24px;
  70 + font-size: 12px;
  71 + color: #868484;
  72 + vertical-align: middle;
  73 + }
  74 +}
36 \ No newline at end of file 75 \ No newline at end of file
front-end/h5/src/engine-entry.js
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 * @Author: ly525 2 * @Author: ly525
3 * @Date: 2019-11-24 18:51:58 3 * @Date: 2019-11-24 18:51:58
4 * @LastEditors: ly525 4 * @LastEditors: ly525
5 - * @LastEditTime: 2019-12-15 17:09:51 5 + * @LastEditTime: 2020-05-10 23:43:42
6 * @FilePath: /luban-h5/front-end/h5/src/engine-entry.js 6 * @FilePath: /luban-h5/front-end/h5/src/engine-entry.js
7 * @Github: https://github.com/ly525/luban-h5 7 * @Github: https://github.com/ly525/luban-h5
8 * @Description: 8 * @Description:
@@ -32,9 +32,22 @@ const Engine = { @@ -32,9 +32,22 @@ const Engine = {
32 }, 32 },
33 methods: { 33 methods: {
34 renderPreview (h, _elements) { 34 renderPreview (h, _elements) {
  35 + const isLongPage = window.__work.mode === 'h5_long_page'
35 const elements = _elements.map(element => new Element(element)) 36 const elements = _elements.map(element => new Element(element))
  37 + let pageWrapperStyle = {
  38 + height: '100%',
  39 + position: 'relative'
  40 + }
  41 +
  42 + if (isLongPage) {
  43 + pageWrapperStyle = {
  44 + ...pageWrapperStyle,
  45 + 'overflow-y': 'scroll'
  46 + }
  47 + }
  48 +
36 return ( 49 return (
37 - <div style={{ height: '100%', position: 'relative' }}> 50 + <div style={pageWrapperStyle}>
38 { 51 {
39 elements.map((element, index) => { 52 elements.map((element, index) => {
40 // const style = element.getStyle({ position: 'absolute', isRem: true }) 53 // const style = element.getStyle({ position: 'absolute', isRem: true })
front-end/h5/src/store/modules/work.js
@@ -257,7 +257,7 @@ export const mutations = { @@ -257,7 +257,7 @@ export const mutations = {
257 page.elements = page.elements.map(element => new Element(element)) 257 page.elements = page.elements.map(element => new Element(element))
258 return new Page(page) 258 return new Page(page)
259 }) 259 })
260 - state.work = work 260 + state.work = new Work(work)
261 }, 261 },
262 previewWork (state, { type, value }) {}, 262 previewWork (state, { type, value }) {},
263 deployWork (state, { type, value }) {}, 263 deployWork (state, { type, value }) {},