Commit cbea4adce501421098256fff897a8da488801347
Committed by
GitHub
Merge pull request #248 from ly525/editor-core-package
@luban-h5/core-editor
Showing
100 changed files
with
1473 additions
and
712 deletions
Too many changes to show.
To preserve performance only 100 of 124 files are displayed.
back-end/h5-api/api/work/config/routes.json
back-end/h5-api/api/work/controllers/Work.js
| 1 | 1 | /* |
| 2 | 2 | * @Author: ly525 |
| 3 | 3 | * @Date: 2019-12-04 19:55:24 |
| 4 | - * @LastEditors : ly525 | |
| 5 | - * @LastEditTime : 2020-01-01 18:42:41 | |
| 4 | + * @LastEditors: ly525 | |
| 5 | + * @LastEditTime: 2020-10-11 20:02:09 | |
| 6 | 6 | * @FilePath: /luban-h5/back-end/h5-api/api/work/controllers/Work.js |
| 7 | 7 | * @Github: https://github.com/ly525/luban-h5 |
| 8 | 8 | * @Description: |
| ... | ... | @@ -14,7 +14,7 @@ const _ = require('lodash'); |
| 14 | 14 | // 浏览模式 |
| 15 | 15 | const VIEW_MODE = { |
| 16 | 16 | PREVIEW: 'preview' // 预览 |
| 17 | -} | |
| 17 | +}; | |
| 18 | 18 | |
| 19 | 19 | /** |
| 20 | 20 | * Read the documentation (https://strapi.io/documentation/3.0.0-beta.x/guides/controllers.html#core-controllers) |
| ... | ... | @@ -25,14 +25,17 @@ module.exports = { |
| 25 | 25 | // GET /previewOne |
| 26 | 26 | // strapi-hook-ejs: https://github.com/strapi/strapi/tree/master/packages/strapi-hook-ejs |
| 27 | 27 | previewOne: async (ctx) => { |
| 28 | - const { view_mode } = ctx.request.query | |
| 28 | + const { view_mode } = ctx.request.query; | |
| 29 | 29 | const work = await strapi.services.work.findOne(ctx.params); |
| 30 | 30 | // 非发布状态, 查看不到内容 |
| 31 | 31 | // 非预览模式, 查看不到内容 |
| 32 | - const canRender = view_mode === VIEW_MODE.PREVIEW || work.is_publish | |
| 33 | - if (!canRender) work.pages = [] | |
| 32 | + const canRender = view_mode === VIEW_MODE.PREVIEW || work.is_publish; | |
| 33 | + if (!canRender) work.pages = []; | |
| 34 | 34 | return ctx.render('engine', { work }); |
| 35 | 35 | }, |
| 36 | + renderCoreEditor: async (ctx) => { | |
| 37 | + return ctx.render('core-editor'); | |
| 38 | + }, | |
| 36 | 39 | submitForm: async (ctx) => { |
| 37 | 40 | const work = await strapi.services.work.findOne(ctx.params); |
| 38 | 41 | const formData = ctx.request.body; | ... | ... |
back-end/h5-api/api/work/documentation/1.0.0/work.json
| ... | ... | @@ -114,6 +114,63 @@ |
| 114 | 114 | "parameters": [] |
| 115 | 115 | } |
| 116 | 116 | }, |
| 117 | + "/works/editor": { | |
| 118 | + "get": { | |
| 119 | + "deprecated": false, | |
| 120 | + "description": "", | |
| 121 | + "responses": { | |
| 122 | + "200": { | |
| 123 | + "description": "response", | |
| 124 | + "content": { | |
| 125 | + "application/json": { | |
| 126 | + "schema": { | |
| 127 | + "properties": { | |
| 128 | + "foo": { | |
| 129 | + "type": "string" | |
| 130 | + } | |
| 131 | + } | |
| 132 | + } | |
| 133 | + } | |
| 134 | + } | |
| 135 | + }, | |
| 136 | + "403": { | |
| 137 | + "description": "Forbidden", | |
| 138 | + "content": { | |
| 139 | + "application/json": { | |
| 140 | + "schema": { | |
| 141 | + "$ref": "#/components/schemas/Error" | |
| 142 | + } | |
| 143 | + } | |
| 144 | + } | |
| 145 | + }, | |
| 146 | + "404": { | |
| 147 | + "description": "Not found", | |
| 148 | + "content": { | |
| 149 | + "application/json": { | |
| 150 | + "schema": { | |
| 151 | + "$ref": "#/components/schemas/Error" | |
| 152 | + } | |
| 153 | + } | |
| 154 | + } | |
| 155 | + }, | |
| 156 | + "default": { | |
| 157 | + "description": "unexpected error", | |
| 158 | + "content": { | |
| 159 | + "application/json": { | |
| 160 | + "schema": { | |
| 161 | + "$ref": "#/components/schemas/Error" | |
| 162 | + } | |
| 163 | + } | |
| 164 | + } | |
| 165 | + } | |
| 166 | + }, | |
| 167 | + "summary": "", | |
| 168 | + "tags": [ | |
| 169 | + "Work" | |
| 170 | + ], | |
| 171 | + "parameters": [] | |
| 172 | + } | |
| 173 | + }, | |
| 117 | 174 | "/works": { |
| 118 | 175 | "get": { |
| 119 | 176 | "deprecated": false, | ... | ... |
back-end/h5-api/views/core-editor.ejs
0 → 100644
| 1 | +<html> | |
| 2 | + <head> | |
| 3 | + <meta charset="UTF-8"> | |
| 4 | + <title>鲁班H5 编辑器</title> | |
| 5 | + <script src="https://unpkg.com/vue"></script> | |
| 6 | + <script src="https://unpkg.com/@luban-h5/core-editor"></script> | |
| 7 | + </head> | |
| 8 | + <body> | |
| 9 | + <div id="app"> <core-editor :work-id="id" /></div> | |
| 10 | + <script> | |
| 11 | + const id = new URLSearchParams(window.location.search).get('id') | |
| 12 | + new Vue({ data: () => ({id }), el: '#app'}); | |
| 13 | + </script> | |
| 14 | + </body> | |
| 15 | +</html> | |
| 0 | 16 | \ No newline at end of file | ... | ... |
front-end/h5/package.json
| ... | ... | @@ -11,7 +11,8 @@ |
| 11 | 11 | "test:e2e": "vue-cli-service test:e2e", |
| 12 | 12 | "test:unit": "vue-cli-service test:unit", |
| 13 | 13 | "build:editor": "cross-env PAGE=EDITOR vue-cli-service build", |
| 14 | - "build:engine": "cross-env PAGE=ENGINE vue-cli-service build --target lib --name engine ./src/engine-entry.js" | |
| 14 | + "build:engine": "cross-env PAGE=ENGINE vue-cli-service build --target lib --name engine ./src/engine-entry.js", | |
| 15 | + "build:core_editor": "cross-env PAGE=CORE_EDITOR vue-cli-service build --target lib --name core-editor ./src/components/core/index.js" | |
| 15 | 16 | }, |
| 16 | 17 | "dependencies": { |
| 17 | 18 | "@luban-h5/lbc-button": "^0.0.3", | ... | ... |
front-end/h5/public/index.html
| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | * @FilePath: /luban-h5/front-end/h5/public/index.html |
| 7 | 7 | * @Github: https://github.com/ly525/luban-h5 |
| 8 | 8 | * @Description: Do not edit |
| 9 | - * @Copyright 2018 - 2019 luban-h5. All Rights Reserved | |
| 9 | + * @Copyright 2018 - 2020 luban-h5. All Rights Reserved | |
| 10 | 10 | --> |
| 11 | 11 | <!DOCTYPE html> |
| 12 | 12 | <html lang="en"> | ... | ... |
front-end/h5/src/App.vue
front-end/h5/src/components/common/header/LangSelect.vue
front-end/h5/src/components/common/header/index.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <a-layout-header class="layout-header"> | |
| 3 | + <LogoOfHeader /> | |
| 4 | + <div style="float:right;"> | |
| 5 | + <Links /> | |
| 6 | + <slot name="action-menu"></slot> | |
| 7 | + <LangSelect /> | |
| 8 | + </div> | |
| 9 | + </a-layout-header> | |
| 10 | +</template> | |
| 11 | +<script> | |
| 12 | +import LogoOfHeader from './logo.js' | |
| 13 | +import LangSelect from './LangSelect' | |
| 14 | +import Links from './links' | |
| 15 | +export default { | |
| 16 | + name: 'Header', | |
| 17 | + components: { | |
| 18 | + LogoOfHeader, | |
| 19 | + LangSelect, | |
| 20 | + Links | |
| 21 | + } | |
| 22 | +} | |
| 23 | +</script> | |
| 24 | +<style lang="scss" scoped> | |
| 25 | +.layout-header { | |
| 26 | + padding: 0 10px; | |
| 27 | + .logo { | |
| 28 | + width: 120px; | |
| 29 | + height: 31px; | |
| 30 | + margin: 16px 28px 16px 0; | |
| 31 | + float: left; | |
| 32 | + | |
| 33 | + line-height: 31px; | |
| 34 | + text-align: center; | |
| 35 | + color: white; | |
| 36 | + font-size: 16px; | |
| 37 | + } | |
| 38 | + | |
| 39 | + .lang-select-activator, | |
| 40 | + .user-avatar-activator { | |
| 41 | + // float: right; | |
| 42 | + background: transparent; | |
| 43 | + margin: 0 28px 16px 0; | |
| 44 | + cursor: pointer; | |
| 45 | + | |
| 46 | + .anticon { | |
| 47 | + color: white; | |
| 48 | + } | |
| 49 | + } | |
| 50 | +} | |
| 51 | +</style> | ... | ... |
front-end/h5/src/components/common/header/links.js
| ... | ... | @@ -10,7 +10,7 @@ export default { |
| 10 | 10 | theme="dark" |
| 11 | 11 | mode="horizontal" |
| 12 | 12 | defaultSelectedKeys={['2']} |
| 13 | - style={{ lineHeight: '64px', display: 'inline-block', float: 'right' }} | |
| 13 | + style={{ lineHeight: '64px', display: 'inline-block' }} | |
| 14 | 14 | > |
| 15 | 15 | <a-menu-item key="dingtalk" > |
| 16 | 16 | <a-popover title="👨🏻💻👩🏻💻欢迎加入鲁班-H5交流群"> | ... | ... |
front-end/h5/src/components/common/work/card-cover.js
| 1 | 1 | /* |
| 2 | 2 | * @Author: ly525 |
| 3 | 3 | * @Date: 2019-12-01 18:11:49 |
| 4 | - * @LastEditors : ly525 | |
| 5 | - * @LastEditTime : 2020-01-04 13:51:26 | |
| 4 | + * @LastEditors: ly525 | |
| 5 | + * @LastEditTime: 2020-10-10 23:29:06 | |
| 6 | 6 | * @FilePath: /luban-h5/front-end/h5/src/components/common/work/card-cover.js |
| 7 | 7 | * @Github: https://github.com/ly525/luban-h5 |
| 8 | 8 | * @Description: Do not edit |
| 9 | - * @Copyright 2018 - 2019 luban-h5. All Rights Reserved | |
| 9 | + * @Copyright 2018 - 2020 luban-h5. All Rights Reserved | |
| 10 | 10 | */ |
| 11 | 11 | import placeholderImg from '@/assets/lbp-picture-placeholder.png' |
| 12 | +import './card-cover.scss' | |
| 12 | 13 | |
| 13 | 14 | function getDefaultStyle (img, isPlaceholder) { |
| 14 | 15 | return { | ... | ... |
front-end/h5/src/components/common/work/card-cover.scss
0 → 100644
front-end/h5/src/constants/animation.js renamed to front-end/h5/src/components/core/constants/animation.js
front-end/h5/src/constants/work.js renamed to front-end/h5/src/components/core/constants/work.js
front-end/h5/src/components/core/editor/canvas/edit.js
| 1 | 1 | import { mapState, mapActions } from 'vuex' |
| 2 | -import Shape from '../../support/shape' | |
| 3 | -import ContextMenu from '../../support/contexmenu' | |
| 2 | +import Shape from 'core/support/shape' | |
| 3 | +import ContextMenu from 'core/support/contexmenu' | |
| 4 | 4 | |
| 5 | 5 | export default { |
| 6 | 6 | props: ['elements', 'handleClickElementProp', 'handleClickCanvasProp'], | ... | ... |
front-end/h5/src/components/core/editor/canvas/index.js
0 → 100644
| 1 | +import { mapState, mapActions } from 'vuex' | |
| 2 | + | |
| 3 | +import RenderEditCanvas from './edit' | |
| 4 | +import RenderPreviewCanvas from './preview' | |
| 5 | + | |
| 6 | +export default { | |
| 7 | + name: 'EditorCanvas', | |
| 8 | + data: () => ({ | |
| 9 | + isPreviewMode: false | |
| 10 | + }), | |
| 11 | + computed: { | |
| 12 | + ...mapState('editor', { | |
| 13 | + editingPage: state => state.editingPage, | |
| 14 | + editingElement: state => state.editingElement, | |
| 15 | + elements: state => state.editingPage.elements, | |
| 16 | + pages: state => state.work.pages, | |
| 17 | + work: state => state.work, | |
| 18 | + scaleRate: state => state.scaleRate | |
| 19 | + }), | |
| 20 | + ...mapState('loading', [ | |
| 21 | + 'saveWork_loading', | |
| 22 | + 'previewWork_loading', | |
| 23 | + 'setWorkAsTemplate_loading', | |
| 24 | + 'uploadWorkCover_loading' | |
| 25 | + ]) | |
| 26 | + }, | |
| 27 | + methods: { | |
| 28 | + ...mapActions('editor', [ | |
| 29 | + 'elementManager', | |
| 30 | + 'pageManager', | |
| 31 | + 'saveWork', | |
| 32 | + 'createWork', | |
| 33 | + 'fetchWork', | |
| 34 | + 'updateWork', | |
| 35 | + 'setWorkAsTemplate', | |
| 36 | + 'setEditingElement', | |
| 37 | + 'setEditingPage' | |
| 38 | + ]), | |
| 39 | + handleToggleMode (isPreviewMode) { | |
| 40 | + this.isPreviewMode = isPreviewMode | |
| 41 | + if (isPreviewMode) { | |
| 42 | + // 当切换到预览模式的时候,清空当前编辑元素 | |
| 43 | + this.setEditingElement() // 相当于 setEditingElement(null) | |
| 44 | + } | |
| 45 | + } | |
| 46 | + }, | |
| 47 | + render (h) { | |
| 48 | + return ( | |
| 49 | + <a-layout id="canvas-outer-wrapper"> | |
| 50 | + <a-radio-group | |
| 51 | + class="mode-toggle-wrapper" | |
| 52 | + size="small" | |
| 53 | + value={this.isPreviewMode} | |
| 54 | + onInput={this.handleToggleMode} | |
| 55 | + > | |
| 56 | + {/* 编辑模式、预览模式 */} | |
| 57 | + <a-radio-button label={false} value={false}>{this.$t('editor.centerPanel.mode.edit')}</a-radio-button> | |
| 58 | + <a-radio-button label={true} value={true}>{this.$t('editor.centerPanel.mode.preview')}</a-radio-button> | |
| 59 | + </a-radio-group> | |
| 60 | + <a-layout-content style={{ transform: `scale(${this.scaleRate})`, 'transform-origin': 'center top' }}> | |
| 61 | + <div class='canvas-wrapper' style={{ | |
| 62 | + height: `${this.work.height}px` | |
| 63 | + }}> | |
| 64 | + { this.isPreviewMode | |
| 65 | + ? <RenderPreviewCanvas elements={this.elements}/> | |
| 66 | + : <RenderEditCanvas | |
| 67 | + class="edit-mode" | |
| 68 | + elements={this.elements} | |
| 69 | + /> | |
| 70 | + } | |
| 71 | + </div> | |
| 72 | + </a-layout-content> | |
| 73 | + </a-layout> | |
| 74 | + ) | |
| 75 | + } | |
| 76 | +} | ... | ... |
front-end/h5/src/components/core/editor/canvas/preview.js
front-end/h5/src/components/core/editor/fixed-tools/index.js
0 → 100644
| 1 | +import { mapActions, mapState } from 'vuex' | |
| 2 | +import hotkeys from 'hotkeys-js' | |
| 3 | +import fixedTools from './options' | |
| 4 | + | |
| 5 | +export default { | |
| 6 | + computed: { | |
| 7 | + ...mapState('editor', { | |
| 8 | + scaleRate: state => state.scaleRate | |
| 9 | + }) | |
| 10 | + }, | |
| 11 | + methods: { | |
| 12 | + ...mapActions('editor', ['pageManager', 'elementManager', 'updateScaleRate']) | |
| 13 | + }, | |
| 14 | + render () { | |
| 15 | + return ( | |
| 16 | + <a-layout-sider | |
| 17 | + width="40" | |
| 18 | + theme='light' | |
| 19 | + style={{ background: '#fff', border: '1px solid #eee' }} | |
| 20 | + > | |
| 21 | + <a-button-group style={{ display: 'flex', flexDirection: 'column' }}> | |
| 22 | + { | |
| 23 | + fixedTools.map(tool => ( | |
| 24 | + <a-tooltip | |
| 25 | + effect="dark" | |
| 26 | + placement="left" | |
| 27 | + title={this.$t(tool.i18nTooltip, { hotkey: tool.hotkeyTooltip })}> | |
| 28 | + <a-button | |
| 29 | + block | |
| 30 | + class="transparent-bg" | |
| 31 | + type="link" | |
| 32 | + size="small" | |
| 33 | + style={{ height: '40px', color: '#000' }} | |
| 34 | + disabled={!!tool.disabled} | |
| 35 | + onClick={() => tool.action && tool.action.call(this)} | |
| 36 | + > | |
| 37 | + { | |
| 38 | + tool.icon | |
| 39 | + ? <i class={['shortcut-icon', 'fa', `fa-${tool.icon}`]} aria-hidden='true' /> | |
| 40 | + : (tool.text || this.$t(tool.i18nTooltip)) | |
| 41 | + } | |
| 42 | + </a-button> | |
| 43 | + { tool.icon === 'minus' && <div style={{ fontSize: '12px', textAlign: 'center' }}>{this.scaleRate * 100}%</div>} | |
| 44 | + </a-tooltip> | |
| 45 | + )) | |
| 46 | + } | |
| 47 | + </a-button-group> | |
| 48 | + </a-layout-sider> | |
| 49 | + ) | |
| 50 | + }, | |
| 51 | + mounted () { | |
| 52 | + fixedTools.map(tool => { | |
| 53 | + tool.hotkey && hotkeys(tool.hotkey, { splitKey: '&' }, (event, handler) => { | |
| 54 | + event.preventDefault() | |
| 55 | + event.stopPropagation() | |
| 56 | + tool.action && tool.action.call(this) | |
| 57 | + }) | |
| 58 | + }) | |
| 59 | + } | |
| 60 | +} | ... | ... |
front-end/h5/src/components/core/editor/fixed-tools/options.js
0 → 100644
| 1 | +import undoRedoHistory from 'core/store/plugins/undo-redo/History' | |
| 2 | + | |
| 3 | +const fixedTools = [ | |
| 4 | + { | |
| 5 | + i18nTooltip: 'editor.fixedTool.undo', | |
| 6 | + icon: 'mail-reply', | |
| 7 | + action: () => undoRedoHistory.undo(), | |
| 8 | + hotkey: 'ctrl&z,⌘&z', | |
| 9 | + hotkeyTooltip: '(ctrl+z)' | |
| 10 | + }, | |
| 11 | + { | |
| 12 | + i18nTooltip: 'editor.fixedTool.redo', | |
| 13 | + icon: 'mail-forward', | |
| 14 | + action: () => undoRedoHistory.redo(), | |
| 15 | + hotkey: 'ctrl&y,⌘&u', | |
| 16 | + hotkeyTooltip: '(ctrl+y)' | |
| 17 | + }, | |
| 18 | + { | |
| 19 | + i18nTooltip: 'editor.fixedTool.preview', | |
| 20 | + icon: 'eye', | |
| 21 | + action: function () { this.previewDialogVisible = true } | |
| 22 | + }, | |
| 23 | + { | |
| 24 | + i18nTooltip: 'editor.fixedTool.copyCurrentPage', | |
| 25 | + icon: 'copy', | |
| 26 | + action: function () { this.pageManager({ type: 'copy' }) }, | |
| 27 | + hotkey: 'ctrl&c,⌘&c' | |
| 28 | + }, | |
| 29 | + { | |
| 30 | + i18nTooltip: 'editor.fixedTool.copyCurrentElement', | |
| 31 | + icon: 'copy', | |
| 32 | + action: function () { this.elementManager({ type: 'copy' }) } | |
| 33 | + }, | |
| 34 | + { | |
| 35 | + i18nTooltip: 'editor.fixedTool.importPSD', | |
| 36 | + text: 'Ps', | |
| 37 | + icon: '', // 优先级: icon > text > i18nTooltip | |
| 38 | + action: '', | |
| 39 | + disabled: true | |
| 40 | + }, | |
| 41 | + { | |
| 42 | + i18nTooltip: 'editor.fixedTool.zoomOut', | |
| 43 | + icon: 'plus', | |
| 44 | + action: function () { this.updateScaleRate(0.25) }, | |
| 45 | + hotkey: 'ctrl&=,⌘&=', | |
| 46 | + hotkeyTooltip: '(ctrl +)' | |
| 47 | + }, | |
| 48 | + { | |
| 49 | + i18nTooltip: 'editor.fixedTool.zoomIn', | |
| 50 | + icon: 'minus', | |
| 51 | + action: function () { this.updateScaleRate(-0.25) }, | |
| 52 | + hotkey: 'ctrl&-,⌘&-', | |
| 53 | + hotkeyTooltip: '(ctrl -)' | |
| 54 | + }, | |
| 55 | + { | |
| 56 | + i18nTooltip: 'editor.fixedTool.issues', | |
| 57 | + icon: 'question', | |
| 58 | + action: function () { window.open('https://github.com/ly525/luban-h5/issues/110') } | |
| 59 | + } | |
| 60 | +] | |
| 61 | + | |
| 62 | +export default fixedTools | ... | ... |
front-end/h5/src/components/core/editor/header/action-menu.js
0 → 100644
| 1 | +import { mapState, mapActions } from 'vuex' | |
| 2 | + | |
| 3 | +export default { | |
| 4 | + name: 'EditorActionMenu', | |
| 5 | + data: () => ({ | |
| 6 | + previewDialogVisible: false, | |
| 7 | + propsPanelWidth: 320 | |
| 8 | + }), | |
| 9 | + computed: { | |
| 10 | + ...mapState('editor', { | |
| 11 | + editingPage: state => state.editingPage, | |
| 12 | + editingElement: state => state.editingElement, | |
| 13 | + elements: state => state.editingPage.elements, | |
| 14 | + pages: state => state.work.pages, | |
| 15 | + work: state => state.work | |
| 16 | + }), | |
| 17 | + ...mapState('loading', [ | |
| 18 | + 'saveWork_loading', | |
| 19 | + 'previewWork_loading', | |
| 20 | + 'setWorkAsTemplate_loading', | |
| 21 | + 'uploadWorkCover_loading' | |
| 22 | + ]) | |
| 23 | + }, | |
| 24 | + methods: { | |
| 25 | + ...mapActions('editor', [ | |
| 26 | + 'elementManager', | |
| 27 | + 'pageManager', | |
| 28 | + 'saveWork', | |
| 29 | + 'createWork', | |
| 30 | + 'fetchWork', | |
| 31 | + 'updateWork', | |
| 32 | + 'setWorkAsTemplate', | |
| 33 | + // 'setEditingElement', | |
| 34 | + 'setEditingPage' | |
| 35 | + ]), | |
| 36 | + ...mapActions('loading', { | |
| 37 | + updateLoading: 'update' | |
| 38 | + }), | |
| 39 | + handlePreview () { | |
| 40 | + this.saveWork({ loadingName: 'previewWork_loading' }).then(() => { | |
| 41 | + this.$emit('preview') | |
| 42 | + // this.previewDialogVisible = true | |
| 43 | + }) | |
| 44 | + }, | |
| 45 | + handleSave () { | |
| 46 | + this.saveWork({ isSaveCover: true }) | |
| 47 | + }, | |
| 48 | + handlePublish () { | |
| 49 | + this.updateWork({ is_publish: true }) | |
| 50 | + this.saveWork({ successMsg: '发布成功' }) | |
| 51 | + }, | |
| 52 | + handleSetAsTemplate () { | |
| 53 | + this.updateLoading({ type: 'setWorkAsTemplate_loading', value: true }) | |
| 54 | + this.saveWork().then(() => { | |
| 55 | + this.setWorkAsTemplate() | |
| 56 | + }) | |
| 57 | + }, | |
| 58 | + handleSelectItem ({ key }) { | |
| 59 | + switch (key) { | |
| 60 | + case 'setAsTemplate': | |
| 61 | + this.handleSetAsTemplate() | |
| 62 | + } | |
| 63 | + } | |
| 64 | + }, | |
| 65 | + render (h) { | |
| 66 | + return ( | |
| 67 | + <a-menu | |
| 68 | + slot="action-menu" | |
| 69 | + theme="dark" | |
| 70 | + mode="horizontal" | |
| 71 | + defaultSelectedKeys={['2']} | |
| 72 | + style={{ lineHeight: '64px', float: 'right', background: 'transparent' }} | |
| 73 | + > | |
| 74 | + {/* 保存、预览、发布、设置为模板 */} | |
| 75 | + <a-menu-item key="1" class="transparent-bg"> | |
| 76 | + <a-button | |
| 77 | + type="primary" | |
| 78 | + size="small" | |
| 79 | + onClick={this.handlePreview} | |
| 80 | + loading={this.previewWork_loading} | |
| 81 | + >{this.$t('editor.header.preview')}</a-button> | |
| 82 | + </a-menu-item> | |
| 83 | + <a-menu-item key="2" class="transparent-bg"> | |
| 84 | + <a-button | |
| 85 | + size="small" | |
| 86 | + onClick={this.handleSave} | |
| 87 | + loading={this.saveWork_loading || this.uploadWorkCover_loading} | |
| 88 | + >{this.$t('editor.header.save')}</a-button> | |
| 89 | + </a-menu-item> | |
| 90 | + {/* <a-menu-item key="3" class="transparent-bg"><a-button size="small">发布</a-button></a-menu-item> */} | |
| 91 | + <a-menu-item key="3" class="transparent-bg"> | |
| 92 | + <a-dropdown-button | |
| 93 | + size="small" | |
| 94 | + onClick={this.handlePublish} | |
| 95 | + loading={this.saveWork_loading || this.uploadWorkCover_loading} | |
| 96 | + > | |
| 97 | + {this.$t('editor.header.publish') /* 发布 */} | |
| 98 | + <a-menu slot="overlay" onClick={this.handleSelectItem}> | |
| 99 | + <a-menu-item key="setAsTemplate"> | |
| 100 | + <a-spin spinning={this.setWorkAsTemplate_loading} size="small"> | |
| 101 | + {/* 设置为模板 */} | |
| 102 | + <a-icon type="cloud-upload" />{this.$t('editor.header.setAsTemplate')} | |
| 103 | + </a-spin> | |
| 104 | + </a-menu-item> | |
| 105 | + {/* <a-menu-item key="2"><a-icon type="user" />2nd menu item</a-menu-item> */} | |
| 106 | + {/* <a-menu-item key="3"><a-icon type="user" />3rd item</a-menu-item> */} | |
| 107 | + </a-menu> | |
| 108 | + </a-dropdown-button> | |
| 109 | + </a-menu-item> | |
| 110 | + </a-menu> | |
| 111 | + ) | |
| 112 | + } | |
| 113 | +} | ... | ... |
front-end/h5/src/components/core/editor/index.js deleted
100644 → 0
| 1 | -import { mapState, mapActions } from 'vuex' | |
| 2 | -import hotkeys from 'hotkeys-js' | |
| 3 | -import undoRedoHistory from '../../../store/plugins/undo-redo/History' | |
| 4 | - | |
| 5 | -import '../styles/index.scss' | |
| 6 | -import 'animate.css' | |
| 7 | - | |
| 8 | -import RenderEditCanvas from './canvas/edit' | |
| 9 | -import RenderPreviewCanvas from './canvas/preview' | |
| 10 | -import RenderPropsEditor from './edit-panel/props' | |
| 11 | -import RenderScriptEditor from './edit-panel/script' | |
| 12 | -import RenderAnimationEditor from './edit-panel/animation' | |
| 13 | -import RenderActionEditor from './edit-panel/action' | |
| 14 | -import RenderBackgroundEditor from './edit-panel/background' | |
| 15 | -import RenderShortcutsPanel from './shortcuts-panel/index' | |
| 16 | -import RenderPageManager from './page-manager/index' | |
| 17 | -import PreviewDialog from './modals/preview.vue' | |
| 18 | - | |
| 19 | -import LogoOfHeader from '@/components/common/header/logo.js' | |
| 20 | -import ExternalLinksOfHeader from '@/components/common/header/links.js' | |
| 21 | -import LangSelect from '@/components/common/header/LangSelect.vue' | |
| 22 | -import Feedback from '@/components/common/feedback/index' | |
| 23 | -import AdjustLineV from '@/components/core/support/adjust-line/vertical' | |
| 24 | - | |
| 25 | -import DragMixin from './drag-mixin' | |
| 26 | - | |
| 27 | -const fixedTools = [ | |
| 28 | - { | |
| 29 | - i18nTooltip: 'editor.fixedTool.undo', | |
| 30 | - icon: 'mail-reply', | |
| 31 | - action: () => undoRedoHistory.undo(), | |
| 32 | - hotkey: 'ctrl&z,⌘&z', | |
| 33 | - hotkeyTooltip: '(ctrl+z)' | |
| 34 | - }, | |
| 35 | - { | |
| 36 | - i18nTooltip: 'editor.fixedTool.redo', | |
| 37 | - icon: 'mail-forward', | |
| 38 | - action: () => undoRedoHistory.redo(), | |
| 39 | - hotkey: 'ctrl&y,⌘&u', | |
| 40 | - hotkeyTooltip: '(ctrl+y)' | |
| 41 | - }, | |
| 42 | - { | |
| 43 | - i18nTooltip: 'editor.fixedTool.preview', | |
| 44 | - icon: 'eye', | |
| 45 | - action: function () { this.previewDialogVisible = true } | |
| 46 | - }, | |
| 47 | - { | |
| 48 | - i18nTooltip: 'editor.fixedTool.copyCurrentPage', | |
| 49 | - icon: 'copy', | |
| 50 | - action: function () { this.pageManager({ type: 'copy' }) }, | |
| 51 | - hotkey: 'ctrl&c,⌘&c' | |
| 52 | - }, | |
| 53 | - { | |
| 54 | - i18nTooltip: 'editor.fixedTool.copyCurrentElement', | |
| 55 | - icon: 'copy', | |
| 56 | - action: function () { this.elementManager({ type: 'copy' }) } | |
| 57 | - }, | |
| 58 | - { | |
| 59 | - i18nTooltip: 'editor.fixedTool.importPSD', | |
| 60 | - text: 'Ps', | |
| 61 | - icon: '', // 优先级: icon > text > i18nTooltip | |
| 62 | - action: '', | |
| 63 | - disabled: true | |
| 64 | - }, | |
| 65 | - { | |
| 66 | - i18nTooltip: 'editor.fixedTool.zoomOut', | |
| 67 | - icon: 'plus', | |
| 68 | - action: function () { this.scaleRate += 0.25 }, | |
| 69 | - hotkey: 'ctrl&=,⌘&=', | |
| 70 | - hotkeyTooltip: '(ctrl +)' | |
| 71 | - }, | |
| 72 | - { | |
| 73 | - i18nTooltip: 'editor.fixedTool.zoomIn', | |
| 74 | - icon: 'minus', | |
| 75 | - action: function () { this.scaleRate -= 0.25 }, | |
| 76 | - hotkey: 'ctrl&-,⌘&-', | |
| 77 | - hotkeyTooltip: '(ctrl -)' | |
| 78 | - }, | |
| 79 | - { | |
| 80 | - i18nTooltip: 'editor.fixedTool.issues', | |
| 81 | - icon: 'question', | |
| 82 | - action: function () { window.open('https://github.com/ly525/luban-h5/issues/110') } | |
| 83 | - } | |
| 84 | -] | |
| 85 | - | |
| 86 | -export default { | |
| 87 | - mixins: [DragMixin], | |
| 88 | - name: 'Editor', | |
| 89 | - components: { | |
| 90 | - LogoOfHeader, | |
| 91 | - ExternalLinksOfHeader, | |
| 92 | - LangSelect | |
| 93 | - }, | |
| 94 | - data: () => ({ | |
| 95 | - activeMenuKey: 'pluginList', | |
| 96 | - isPreviewMode: false, | |
| 97 | - activeTabKey: '属性', | |
| 98 | - previewDialogVisible: false, | |
| 99 | - scaleRate: 1, | |
| 100 | - propsPanelWidth: 320 | |
| 101 | - }), | |
| 102 | - computed: { | |
| 103 | - ...mapState('editor', { | |
| 104 | - editingPage: state => state.editingPage, | |
| 105 | - editingElement: state => state.editingElement, | |
| 106 | - elements: state => state.editingPage.elements, | |
| 107 | - pages: state => state.work.pages, | |
| 108 | - work: state => state.work | |
| 109 | - }), | |
| 110 | - ...mapState('loading', [ | |
| 111 | - 'saveWork_loading', | |
| 112 | - 'previewWork_loading', | |
| 113 | - 'setWorkAsTemplate_loading', | |
| 114 | - 'uploadWorkCover_loading' | |
| 115 | - ]) | |
| 116 | - }, | |
| 117 | - methods: { | |
| 118 | - ...mapActions('editor', [ | |
| 119 | - 'elementManager', | |
| 120 | - 'pageManager', | |
| 121 | - 'saveWork', | |
| 122 | - 'createWork', | |
| 123 | - 'fetchWork', | |
| 124 | - 'updateWork', | |
| 125 | - 'setWorkAsTemplate', | |
| 126 | - 'setEditingElement', | |
| 127 | - 'setEditingPage' | |
| 128 | - ]), | |
| 129 | - ...mapActions('loading', { | |
| 130 | - updateLoading: 'update' | |
| 131 | - }), | |
| 132 | - /** | |
| 133 | - * !#zh 点击插件,copy 其基础数据到组件树(中间画布) | |
| 134 | - * #!en click the plugin shortcut, create new Element with the plugin's meta data | |
| 135 | - * pluginInfo {Object}: 插件列表中的基础数据, {name}=pluginInfo | |
| 136 | - * | |
| 137 | - * shortcutItem: PluginListItem = { | |
| 138 | - name: String, | |
| 139 | - shortcutProps: {} | |
| 140 | - } | |
| 141 | - */ | |
| 142 | - clone (shortcutItem) { | |
| 143 | - this.elementManager({ | |
| 144 | - type: 'add', | |
| 145 | - value: shortcutItem | |
| 146 | - }) | |
| 147 | - }, | |
| 148 | - /** | |
| 149 | - * #!zh: 设置 背景图tab 作为 active tab | |
| 150 | - * #!en: set background(bg) tab as active tab | |
| 151 | - */ | |
| 152 | - setActiveTab (activeTabKey) { | |
| 153 | - this.activeTabKey = activeTabKey | |
| 154 | - }, | |
| 155 | - _renderMenuContent () { | |
| 156 | - return ( | |
| 157 | - <a-tabs | |
| 158 | - style="height: 100%;" | |
| 159 | - tabBarGutter={10} | |
| 160 | - > | |
| 161 | - <a-tab-pane key="plugin-list" tab={this.$t('editor.sidebar.components')}> | |
| 162 | - <div class="plugin-usage-tip "> | |
| 163 | - <a-icon type="info-circle" /> | |
| 164 | - {/* <span class="ml-1">使用提示: <strong>点击</strong>组件即可</span> */} | |
| 165 | - {/* Tip: just click on component */} | |
| 166 | - <i18n path="editor.tip.componentUsage" tag="span" class="ml-1"> | |
| 167 | - <strong>{ this.$t('editor.tip.click') }</strong>{ this.$t('editor.tip.click') } | |
| 168 | - </i18n> | |
| 169 | - </div> | |
| 170 | - <RenderShortcutsPanel | |
| 171 | - pluginsList={this.pluginsList} | |
| 172 | - handleClickShortcut={this.clone} | |
| 173 | - handleDragStart={this.handleDragStartFromMixin} | |
| 174 | - /> | |
| 175 | - </a-tab-pane> | |
| 176 | - <a-tab-pane key='page-manager' tab={this.$t('editor.sidebar.pages')}> | |
| 177 | - <RenderPageManager | |
| 178 | - pages={this.pages} | |
| 179 | - editingPage={this.editingPage} | |
| 180 | - onSelectMenuItem={(menuKey) => { | |
| 181 | - this.pageManager({ type: menuKey }) | |
| 182 | - }} | |
| 183 | - onEditTitle={({ pageIndexForEditingTitle, newTitle }) => { | |
| 184 | - this.pageManager({ type: 'editTitle', value: { pageIndexForEditingTitle, newTitle } }) | |
| 185 | - this.saveWork({ isSaveCover: false }) | |
| 186 | - }} | |
| 187 | - onSelectPage={(pageIndex) => { this.setEditingPage(pageIndex) }} | |
| 188 | - /> | |
| 189 | - </a-tab-pane> | |
| 190 | - </a-tabs> | |
| 191 | - ) | |
| 192 | - }, | |
| 193 | - handlePreview () { | |
| 194 | - this.saveWork({ loadingName: 'previewWork_loading' }).then(() => { | |
| 195 | - this.previewDialogVisible = true | |
| 196 | - }) | |
| 197 | - }, | |
| 198 | - handleSave () { | |
| 199 | - this.saveWork({ isSaveCover: true }) | |
| 200 | - }, | |
| 201 | - handlePublish () { | |
| 202 | - this.updateWork({ is_publish: true }) | |
| 203 | - this.saveWork({ successMsg: '发布成功' }) | |
| 204 | - } | |
| 205 | - }, | |
| 206 | - mounted () { | |
| 207 | - fixedTools.map(tool => { | |
| 208 | - tool.hotkey && hotkeys(tool.hotkey, { splitKey: '&' }, (event, handler) => { | |
| 209 | - event.preventDefault() | |
| 210 | - event.stopPropagation() | |
| 211 | - tool.action && tool.action.call(this) | |
| 212 | - }) | |
| 213 | - }) | |
| 214 | - }, | |
| 215 | - render (h) { | |
| 216 | - return ( | |
| 217 | - <a-layout id="luban-editor-layout" style={{ height: '100vh' }}> | |
| 218 | - <a-layout-header class="header"> | |
| 219 | - <LogoOfHeader /> | |
| 220 | - <LangSelect style="float: right;cursor: pointer;" /> | |
| 221 | - {/* we can show the plugins shortcuts here */} | |
| 222 | - <a-menu | |
| 223 | - theme="dark" | |
| 224 | - mode="horizontal" | |
| 225 | - defaultSelectedKeys={['2']} | |
| 226 | - style={{ lineHeight: '64px', float: 'right', background: 'transparent' }} | |
| 227 | - > | |
| 228 | - {/* 保存、预览、发布、设置为模板 */} | |
| 229 | - <a-menu-item key="1" class="transparent-bg"> | |
| 230 | - <a-button | |
| 231 | - type="primary" | |
| 232 | - size="small" | |
| 233 | - onClick={this.handlePreview} | |
| 234 | - loading={this.previewWork_loading} | |
| 235 | - >{this.$t('editor.header.preview')}</a-button> | |
| 236 | - </a-menu-item> | |
| 237 | - <a-menu-item key="2" class="transparent-bg"> | |
| 238 | - <a-button | |
| 239 | - size="small" | |
| 240 | - onClick={this.handleSave} | |
| 241 | - loading={this.saveWork_loading || this.uploadWorkCover_loading} | |
| 242 | - >{this.$t('editor.header.save')}</a-button> | |
| 243 | - </a-menu-item> | |
| 244 | - {/* <a-menu-item key="3" class="transparent-bg"><a-button size="small">发布</a-button></a-menu-item> */} | |
| 245 | - <a-menu-item key="3" class="transparent-bg"> | |
| 246 | - <a-dropdown-button | |
| 247 | - size="small" | |
| 248 | - onClick={this.handlePublish} | |
| 249 | - loading={this.saveWork_loading || this.uploadWorkCover_loading} | |
| 250 | - > | |
| 251 | - {/* 发布 */} | |
| 252 | - {this.$t('editor.header.publish')} | |
| 253 | - <a-menu slot="overlay" onClick={({ key }) => { | |
| 254 | - switch (key) { | |
| 255 | - case 'setAsTemplate': | |
| 256 | - this.updateLoading({ type: 'setWorkAsTemplate_loading', value: true }) | |
| 257 | - this.saveWork().then(() => { | |
| 258 | - this.setWorkAsTemplate() | |
| 259 | - }) | |
| 260 | - } | |
| 261 | - }}> | |
| 262 | - <a-menu-item key="setAsTemplate"> | |
| 263 | - <a-spin spinning={this.setWorkAsTemplate_loading} size="small"> | |
| 264 | - {/* 设置为模板 */} | |
| 265 | - <a-icon type="cloud-upload" />{this.$t('editor.header.setAsTemplate')} | |
| 266 | - </a-spin> | |
| 267 | - </a-menu-item> | |
| 268 | - {/* <a-menu-item key="2"><a-icon type="user" />2nd menu item</a-menu-item> */} | |
| 269 | - {/* <a-menu-item key="3"><a-icon type="user" />3rd item</a-menu-item> */} | |
| 270 | - </a-menu> | |
| 271 | - </a-dropdown-button> | |
| 272 | - </a-menu-item> | |
| 273 | - </a-menu> | |
| 274 | - <ExternalLinksOfHeader /> | |
| 275 | - </a-layout-header> | |
| 276 | - <a-layout> | |
| 277 | - {/* <a-layout-sider collapsedWidth={40} style="background: #fff" collapsed> | |
| 278 | - <a-menu | |
| 279 | - mode="inline" | |
| 280 | - defaultSelectedKeys={['pluginList']} | |
| 281 | - style={{ height: '100%', borderRight: 1 }} | |
| 282 | - onSelect={({ key }) => { this.activeMenuKey = key }} | |
| 283 | - > | |
| 284 | - { | |
| 285 | - sidebarMenus.map(menu => ( | |
| 286 | - <a-menu-item key={menu.value}> | |
| 287 | - <a-icon type={menu.antIcon} /> | |
| 288 | - <span>{this.$t(menu.i18nLabel)}</span> | |
| 289 | - </a-menu-item> | |
| 290 | - )) | |
| 291 | - } | |
| 292 | - </a-menu> | |
| 293 | - </a-layout-sider> */} | |
| 294 | - <a-layout-sider width="240" theme='light' style={{ background: '#fff', padding: '12px' }}> | |
| 295 | - { this._renderMenuContent() } | |
| 296 | - </a-layout-sider> | |
| 297 | - <a-layout id="canvas-outer-wrapper"> | |
| 298 | - <div class="mode-toggle-wrapper"> | |
| 299 | - <a-radio-group | |
| 300 | - size="small" | |
| 301 | - value={this.isPreviewMode} | |
| 302 | - onInput={isPreviewMode => { | |
| 303 | - this.isPreviewMode = isPreviewMode | |
| 304 | - if (isPreviewMode) { | |
| 305 | - // 当切换到预览模式的时候,清空当前编辑元素 | |
| 306 | - this.setEditingElement() // 相当于 setEditingElement(null) | |
| 307 | - } | |
| 308 | - }} | |
| 309 | - > | |
| 310 | - {/* 编辑模式、预览模式 */} | |
| 311 | - <a-radio-button label={false} value={false}>{this.$t('editor.centerPanel.mode.edit')}</a-radio-button> | |
| 312 | - <a-radio-button label={true} value={true}>{this.$t('editor.centerPanel.mode.preview')}</a-radio-button> | |
| 313 | - </a-radio-group> | |
| 314 | - </div> | |
| 315 | - <a-layout-content style={{ transform: `scale(${this.scaleRate})`, 'transform-origin': 'center top' }}> | |
| 316 | - <div class='canvas-wrapper' style={{ | |
| 317 | - height: `${this.work.height}px` | |
| 318 | - }}> | |
| 319 | - {/* { this.isPreviewMode ? this.renderPreview(h, this.elements) : this.renderCanvas(h, this.elements) } */} | |
| 320 | - { this.isPreviewMode | |
| 321 | - ? <RenderPreviewCanvas elements={this.elements}/> | |
| 322 | - : <RenderEditCanvas | |
| 323 | - class="edit-mode" | |
| 324 | - elements={this.elements} | |
| 325 | - /> | |
| 326 | - } | |
| 327 | - </div> | |
| 328 | - </a-layout-content> | |
| 329 | - </a-layout> | |
| 330 | - <AdjustLineV onLineMove={(offset) => { | |
| 331 | - this.propsPanelWidth += offset | |
| 332 | - }} /> | |
| 333 | - <a-layout-sider width="40" theme='light' style={{ background: '#fff', border: '1px solid #eee' }}> | |
| 334 | - {/* <div> | |
| 335 | - <a-button shape="circle" icon="search" type="link" /> | |
| 336 | - </div> */} | |
| 337 | - <a-button-group style={{ display: 'flex', flexDirection: 'column' }}> | |
| 338 | - { | |
| 339 | - fixedTools.map(tool => ( | |
| 340 | - <a-tooltip effect="dark" placement="left" title={this.$t(tool.i18nTooltip, { hotkey: tool.hotkeyTooltip })}> | |
| 341 | - <a-button block class="transparent-bg" type="link" size="small" style={{ height: '40px', color: '#000' }} onClick={() => tool.action && tool.action.call(this) } disabled={!!tool.disabled}> | |
| 342 | - { tool.icon ? <i class={['shortcut-icon', 'fa', `fa-${tool.icon}`]} aria-hidden='true'/> : (tool.text || this.$t(tool.i18nTooltip)) } | |
| 343 | - </a-button> | |
| 344 | - { tool.icon === 'minus' && <div style={{ fontSize: '12px', textAlign: 'center' }}>{this.scaleRate * 100}%</div> } | |
| 345 | - </a-tooltip> | |
| 346 | - )) | |
| 347 | - } | |
| 348 | - </a-button-group> | |
| 349 | - </a-layout-sider> | |
| 350 | - <a-layout-sider width={this.propsPanelWidth} data-set-width={this.propsPanelWidth} theme='light' style={{ background: '#fff', padding: '0 0 0 12px' }}> | |
| 351 | - <a-tabs | |
| 352 | - style="height: 100%;" | |
| 353 | - tabBarGutter={10} | |
| 354 | - defaultActiveKey={this.activeTabKey} | |
| 355 | - activeKey={this.activeTabKey} | |
| 356 | - onChange={this.setActiveTab} | |
| 357 | - > | |
| 358 | - {/* | |
| 359 | - #!zh tab 标题: | |
| 360 | - #!en tab title | |
| 361 | - ElementUI:label | |
| 362 | - Ant Design Vue:tab | |
| 363 | - */} | |
| 364 | - <a-tab-pane key="属性"><span slot="tab">{this.$t('editor.editPanel.tab.prop')}</span><RenderPropsEditor/></a-tab-pane> | |
| 365 | - <a-tab-pane label="动画" key='动画' tab={this.$t('editor.editPanel.tab.animation')}><RenderAnimationEditor /></a-tab-pane> | |
| 366 | - <a-tab-pane label="动作" key='动作' tab={this.$t('editor.editPanel.tab.action')}>{ this.activeTabKey === '动作' && <RenderActionEditor/> }</a-tab-pane> | |
| 367 | - <a-tab-pane label="脚本" key='脚本' tab={this.$t('editor.editPanel.tab.script')}><RenderScriptEditor/></a-tab-pane> | |
| 368 | - <a-tab-pane label="背景" key='background' tab={this.$t('editor.editPanel.tab.background')}>{ this.activeTabKey === 'background' && <RenderBackgroundEditor/> }</a-tab-pane> | |
| 369 | - </a-tabs> | |
| 370 | - </a-layout-sider> | |
| 371 | - | |
| 372 | - </a-layout> | |
| 373 | - { | |
| 374 | - <PreviewDialog | |
| 375 | - work={this.work} | |
| 376 | - visible={this.previewDialogVisible} | |
| 377 | - handleClose={() => { this.previewDialogVisible = false }} | |
| 378 | - /> | |
| 379 | - } | |
| 380 | - <Feedback /> | |
| 381 | - </a-layout> | |
| 382 | - ) | |
| 383 | - }, | |
| 384 | - created () { | |
| 385 | - // event bus for editor | |
| 386 | - window.getEditorApp = this | |
| 387 | - let workId = this.$route.params.workId | |
| 388 | - if (workId) { | |
| 389 | - this.fetchWork(workId).then(() => this.setActiveTab('background')) | |
| 390 | - } else { | |
| 391 | - this.$message.error('no work id!') | |
| 392 | - } | |
| 393 | - | |
| 394 | - window.getEditorApp.$on('setEditingElement', ({ name }) => { | |
| 395 | - this.setActiveTab(name === 'lbp-background' ? 'background' : '属性') | |
| 396 | - }) | |
| 397 | - } | |
| 398 | -} |
front-end/h5/src/components/core/editor/left-panel/index.js
0 → 100644
| 1 | +import RenderShortcutsPanel from './shortcuts-panel/index' | |
| 2 | +import RenderPageManager from './page-manager/index' | |
| 3 | +import RenderPageTree from './page-tree/index' | |
| 4 | + | |
| 5 | +export default { | |
| 6 | + name: 'EditorLeftPanel', | |
| 7 | + render (h) { | |
| 8 | + return ( | |
| 9 | + <a-layout-sider width="240" theme='light' style={{ background: '#fff', padding: '12px' }}> | |
| 10 | + <a-tabs | |
| 11 | + style="height: 100%;" | |
| 12 | + tabBarGutter={10} | |
| 13 | + > | |
| 14 | + <a-tab-pane key="plugin-list" tab={this.$t('editor.sidebar.components')}> | |
| 15 | + <RenderShortcutsPanel /> | |
| 16 | + </a-tab-pane> | |
| 17 | + <a-tab-pane key='page-manager' tab={this.$t('editor.sidebar.pages')}> | |
| 18 | + <RenderPageManager /> | |
| 19 | + </a-tab-pane> | |
| 20 | + <a-tab-pane key='page-tree' tab={this.$t('editor.sidebar.tree')}> | |
| 21 | + <RenderPageTree /> | |
| 22 | + </a-tab-pane> | |
| 23 | + </a-tabs> | |
| 24 | + </a-layout-sider> | |
| 25 | + ) | |
| 26 | + } | |
| 27 | +} | ... | ... |
front-end/h5/src/components/core/editor/left-panel/page-manager/index.js
0 → 100644
| 1 | +import { mapState, mapActions } from 'vuex' | |
| 2 | +import PageTitleEditor from './title-editor' | |
| 3 | +import PageTitleMenu from './title-menu' | |
| 4 | +import PageTitleText from './title-text' | |
| 5 | + | |
| 6 | +export default { | |
| 7 | + data: () => ({ | |
| 8 | + hoverIndex: -1 // 显示编辑按钮 | |
| 9 | + }), | |
| 10 | + computed: { | |
| 11 | + ...mapState('editor', { | |
| 12 | + editingPage: state => state.editingPage, | |
| 13 | + editingElement: state => state.editingElement, | |
| 14 | + elements: state => state.editingPage.elements, | |
| 15 | + pages: state => state.work.pages, | |
| 16 | + work: state => state.work | |
| 17 | + }) | |
| 18 | + }, | |
| 19 | + methods: { | |
| 20 | + ...mapActions('editor', [ | |
| 21 | + 'elementManager', | |
| 22 | + 'pageManager', | |
| 23 | + 'saveWork', | |
| 24 | + 'setEditingPage' | |
| 25 | + ]), | |
| 26 | + onSelectMenuItem (menuKey) { | |
| 27 | + this.pageManager({ type: menuKey }) | |
| 28 | + }, | |
| 29 | + onEditTitle ({ pageIndex, newTitle }) { | |
| 30 | + this.pageManager({ type: 'editTitle', value: { pageIndex, newTitle } }) | |
| 31 | + this.saveWork({ isSaveCover: false }) | |
| 32 | + }, | |
| 33 | + onSelectPage (pageIndex) { this.setEditingPage(pageIndex) }, | |
| 34 | + onLeave () { | |
| 35 | + this.hoverIndex = -1 | |
| 36 | + } | |
| 37 | + }, | |
| 38 | + render (h) { | |
| 39 | + const addPageText = this.$t('editor.pageManager.action.add') | |
| 40 | + return ( | |
| 41 | + <div class="page-manager-panel"> | |
| 42 | + { | |
| 43 | + this.pages.map((page, index) => ( | |
| 44 | + <span | |
| 45 | + class={[ | |
| 46 | + 'cursor-pointer', | |
| 47 | + 'page-manager-panel__item', | |
| 48 | + page.uuid === this.editingPage.uuid && 'active' | |
| 49 | + ]} | |
| 50 | + onClick={() => this.onSelectPage(index)} | |
| 51 | + // https://github.com/vuetifyjs/vuetify/blob/master/packages/vuetify/src/components/VHover/VHover.ts | |
| 52 | + onMouseenter={() => { this.hoverIndex = index }} | |
| 53 | + > | |
| 54 | + <PageTitleText page={page} pageIndex={index} /> | |
| 55 | + <span> | |
| 56 | + { | |
| 57 | + this.hoverIndex === index && | |
| 58 | + <PageTitleEditor | |
| 59 | + page={page} | |
| 60 | + pageIndex={index} | |
| 61 | + onEditTitle={this.onEditTitle} | |
| 62 | + /> | |
| 63 | + } | |
| 64 | + <PageTitleMenu onSelectMenuItem={this.onSelectMenuItem} /> | |
| 65 | + </span> | |
| 66 | + </span> | |
| 67 | + )) | |
| 68 | + } | |
| 69 | + <a-button | |
| 70 | + icon="plus" | |
| 71 | + type="dashed" | |
| 72 | + class="footer-actions" | |
| 73 | + onClick={() => this.onSelectMenuItem('add') } | |
| 74 | + >{addPageText}</a-button> | |
| 75 | + </div> | |
| 76 | + ) | |
| 77 | + } | |
| 78 | +} | ... | ... |
front-end/h5/src/components/core/editor/left-panel/page-manager/title-editor.js
0 → 100644
| 1 | +export default { | |
| 2 | + props: ['page', 'pageIndex'], | |
| 3 | + data: () => ({ | |
| 4 | + editingTitle: '' // 临时缓存当前编辑的 title,点击 Yes 再真正用其更新 page title | |
| 5 | + }), | |
| 6 | + methods: { | |
| 7 | + getTitle () { | |
| 8 | + return this.page.title || this.$t('editor.pageManager.title', { index: this.pageIndex }) | |
| 9 | + } | |
| 10 | + }, | |
| 11 | + render () { | |
| 12 | + return ( | |
| 13 | + <a-popconfirm | |
| 14 | + placement="bottom" | |
| 15 | + onConfirm={() => { | |
| 16 | + this.$emit('editTitle', { newTitle: this.editingTitle, pageIndex: this.pageIndex }) | |
| 17 | + }} | |
| 18 | + onCancel={() => {}} | |
| 19 | + okText="Yes" | |
| 20 | + cancelText="No" | |
| 21 | + > | |
| 22 | + <a-input | |
| 23 | + slot="title" | |
| 24 | + value={this.editingTitle} | |
| 25 | + size="small" | |
| 26 | + onChange={e => { | |
| 27 | + this.editingTitle = e.target.value | |
| 28 | + }} | |
| 29 | + > | |
| 30 | + </a-input> | |
| 31 | + <a-icon type="edit" onClick={(e) => { | |
| 32 | + e.stopPropagation() // 将 click icon 与 click page item 隔离开。编辑标题的同时不要切换页面 | |
| 33 | + this.editingTitle = this.getTitle() | |
| 34 | + }}/> | |
| 35 | + </a-popconfirm> | |
| 36 | + | |
| 37 | + ) | |
| 38 | + } | |
| 39 | +} | ... | ... |
front-end/h5/src/components/core/editor/left-panel/page-manager/title-menu.js
0 → 100644
| 1 | +export default { | |
| 2 | + render () { | |
| 3 | + const addPageText = this.$t('editor.pageManager.action.add') | |
| 4 | + const copyPageText = this.$t('editor.pageManager.action.copy') | |
| 5 | + const deletePageText = this.$t('editor.pageManager.action.delete') | |
| 6 | + return ( | |
| 7 | + <a-dropdown trigger={['hover']} placement='bottomCenter'> | |
| 8 | + <a class="ant-dropdown-link" href="#" class="ml-2"><a-icon type="down" /></a> | |
| 9 | + <a-menu slot="overlay" onClick={({ key }) => this.$emit('selectMenuItem', key)}> | |
| 10 | + <a-menu-item key="add"><a-icon type="plus" />{addPageText}</a-menu-item> | |
| 11 | + <a-menu-item key="copy"><a-icon type="copy" />{copyPageText}</a-menu-item> | |
| 12 | + <a-menu-item key="delete"><a-icon type="delete" />{deletePageText}</a-menu-item> | |
| 13 | + </a-menu> | |
| 14 | + </a-dropdown> | |
| 15 | + ) | |
| 16 | + } | |
| 17 | +} | ... | ... |
front-end/h5/src/components/core/editor/left-panel/page-manager/title-text.js
0 → 100644
| 1 | +export default { | |
| 2 | + props: ['page', 'pageIndex'], | |
| 3 | + methods: { | |
| 4 | + getTitle () { | |
| 5 | + return this.page.title || this.$t('editor.pageManager.title', { index: this.pageIndex }) | |
| 6 | + } | |
| 7 | + }, | |
| 8 | + render (h) { | |
| 9 | + // #!en: Page<Index> | |
| 10 | + // #!zh: 第<Index>页面 | |
| 11 | + return ( | |
| 12 | + <span> | |
| 13 | + <a-badge | |
| 14 | + count={this.pageIndex + 1} | |
| 15 | + numberStyle={{ backgroundColor: '#fff', color: '#999', boxShadow: '0 0 0 1px #d9d9d9 inset' }} | |
| 16 | + /> | |
| 17 | + <span class="ml-3">{this.getTitle()}</span> | |
| 18 | + </span> | |
| 19 | + ) | |
| 20 | + } | |
| 21 | +} | ... | ... |
front-end/h5/src/components/core/editor/left-panel/page-tree/index.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <a-tree | |
| 3 | + class="draggable-tree" | |
| 4 | + :default-expanded-keys="expandedKeys" | |
| 5 | + draggable | |
| 6 | + :tree-data="treeData" | |
| 7 | + @dragenter="onDragEnter" | |
| 8 | + @drop="onDrop" | |
| 9 | + /> | |
| 10 | +</template> | |
| 11 | + | |
| 12 | +<script> | |
| 13 | +import { mapState } from 'vuex' | |
| 14 | +function getTreeNode (ele) { | |
| 15 | + return { | |
| 16 | + title: ele.name, | |
| 17 | + key: ele.uuid, | |
| 18 | + children: (ele.children || []).map(getTreeNode) | |
| 19 | + } | |
| 20 | +} | |
| 21 | + | |
| 22 | +export default { | |
| 23 | + computed: { | |
| 24 | + ...mapState('editor', { | |
| 25 | + elements: state => state.editingPage.elements | |
| 26 | + }), | |
| 27 | + treeData () { | |
| 28 | + return this.elements.map(getTreeNode) | |
| 29 | + } | |
| 30 | + }, | |
| 31 | + data () { | |
| 32 | + return { | |
| 33 | + gData: [], | |
| 34 | + expandedKeys: [] | |
| 35 | + } | |
| 36 | + }, | |
| 37 | + methods: { | |
| 38 | + onDragEnter (info) { | |
| 39 | + }, | |
| 40 | + onDrop (info) { | |
| 41 | + } | |
| 42 | + } | |
| 43 | +} | |
| 44 | +</script> | ... | ... |
front-end/h5/src/components/core/editor/shortcuts-panel/index.js renamed to front-end/h5/src/components/core/editor/left-panel/shortcuts-panel/index.js
| 1 | 1 | import ShortcutButton from './shortcut-button' |
| 2 | +import UsageTip from './usage-tip' | |
| 2 | 3 | import LoadNpmPlugins from './load-npm-plugins.vue' |
| 3 | -import langMixin from '@/mixins/i18n' | |
| 4 | +import langMixin from 'core/mixins/i18n' | |
| 5 | +import dragMixin from 'core/mixins/drag' | |
| 6 | +import loadPluginsMixin from 'core/plugins/index' | |
| 7 | +import { mapActions } from 'vuex' | |
| 8 | + | |
| 4 | 9 | export default { |
| 5 | - mixins: [langMixin], | |
| 6 | - props: { | |
| 7 | - pluginsList: { | |
| 8 | - required: false, | |
| 9 | - type: Array, | |
| 10 | - default: () => [] | |
| 11 | - }, | |
| 12 | - handleClickShortcut: { | |
| 13 | - type: Function | |
| 14 | - }, | |
| 15 | - handleDragStart: { | |
| 16 | - type: Function, | |
| 17 | - default: (e) => {} | |
| 18 | - } | |
| 19 | - }, | |
| 10 | + mixins: [langMixin, dragMixin, loadPluginsMixin], | |
| 20 | 11 | data: () => ({ |
| 21 | 12 | npmPackages: [] |
| 22 | 13 | }), |
| 23 | 14 | methods: { |
| 24 | - onClickShortcut (item) { | |
| 25 | - if (this.handleClickShortcut) { | |
| 26 | - this.handleClickShortcut(item) | |
| 27 | - } | |
| 15 | + ...mapActions('editor', [ | |
| 16 | + 'elementManager', | |
| 17 | + 'pageManager', | |
| 18 | + 'saveWork', | |
| 19 | + 'setEditingPage' | |
| 20 | + ]), | |
| 21 | + ...mapActions('loading', { | |
| 22 | + updateLoading: 'update' | |
| 23 | + }), | |
| 24 | + /** | |
| 25 | + * !#zh 点击插件,copy 其基础数据到组件树(中间画布) | |
| 26 | + * #!en click the plugin shortcut, create new Element with the plugin's meta data | |
| 27 | + * pluginInfo {Object}: 插件列表中的基础数据, {name}=pluginInfo | |
| 28 | + * | |
| 29 | + * shortcutItem: PluginListItem = { | |
| 30 | + name: String, | |
| 31 | + shortcutProps: {} | |
| 32 | + } | |
| 33 | + */ | |
| 34 | + clone (shortcutItem) { | |
| 35 | + this.elementManager({ | |
| 36 | + type: 'add', | |
| 37 | + value: shortcutItem | |
| 38 | + }) | |
| 28 | 39 | } |
| 29 | 40 | /** |
| 30 | 41 | * #!zh 渲染多个插件的快捷方式 |
| ... | ... | @@ -70,8 +81,8 @@ export default { |
| 70 | 81 | // /> |
| 71 | 82 | // }, |
| 72 | 83 | /** |
| 73 | - * #!zh: 在左侧或顶部导航上显示可用的组件快捷方式,用户点击之后,即可将其添加到中间画布上 | |
| 74 | - * #!en: render shortcust at the sidebar or the header. if user click the shortcut, the related plugin will be added to the canvas | |
| 84 | + * #!zh: 在左侧或顶部导航上显示可用的组件快捷方式,用户点击/拖拽之后,即可将其添加到中间画布上 | |
| 85 | + * #!en: render shortcust at the sidebar or the header. if user click/drag the shortcut, the related plugin will be added to the canvas | |
| 75 | 86 | * @param {Object} group: {children, title, icon} |
| 76 | 87 | */ |
| 77 | 88 | // renderShortCutsPanel (groups) { |
| ... | ... | @@ -92,23 +103,31 @@ export default { |
| 92 | 103 | // ) |
| 93 | 104 | // } |
| 94 | 105 | }, |
| 106 | + /** | |
| 107 | + * #!zh: 在左侧或顶部导航上显示可用的组件快捷方式,用户点击/拖拽之后,即可将其添加到中间画布上 | |
| 108 | + * #!en: render shortcust at the sidebar or the header. | |
| 109 | + * if user click/drag the shortcut, the related plugin will be added to the canvas | |
| 110 | + */ | |
| 95 | 111 | render (h) { |
| 96 | 112 | // return this.renderShortCutsPanel(this.groups) |
| 97 | 113 | return ( |
| 98 | 114 | <a-row gutter={20} style="max-height: calc(100vh - 140px);overflow: scroll;"> |
| 115 | + <UsageTip /> | |
| 99 | 116 | { |
| 100 | - [].concat(this.pluginsList, this.npmPackages).filter(plugin => plugin.visible).map(plugin => ( | |
| 101 | - <a-col span={12} style={{ marginTop: '10px' }}> | |
| 102 | - <ShortcutButton | |
| 103 | - clickFn={this.onClickShortcut.bind(this, plugin)} | |
| 104 | - mousedownFn={this.handleDragStart.bind(this, plugin)} | |
| 105 | - // title={plugin.title} | |
| 106 | - title={plugin.i18nTitle[this.currentLang] || plugin.title} | |
| 107 | - faIcon={plugin.icon} | |
| 108 | - disabled={plugin.disabled} | |
| 109 | - /> | |
| 110 | - </a-col> | |
| 111 | - )) | |
| 117 | + [].concat(this.pluginsList, this.npmPackages) | |
| 118 | + .filter(plugin => plugin.visible) | |
| 119 | + .map(plugin => ( | |
| 120 | + <a-col span={12} style={{ marginTop: '10px' }}> | |
| 121 | + <ShortcutButton | |
| 122 | + clickFn={this.clone.bind(this, plugin)} | |
| 123 | + mousedownFn={this.handleDragStartFromMixin.bind(this, plugin)} | |
| 124 | + // title={plugin.title} | |
| 125 | + title={plugin.i18nTitle[this.currentLang] || plugin.title} | |
| 126 | + faIcon={plugin.icon} | |
| 127 | + disabled={plugin.disabled} | |
| 128 | + /> | |
| 129 | + </a-col> | |
| 130 | + )) | |
| 112 | 131 | } |
| 113 | 132 | <LoadNpmPlugins onLoadComplete={npmPackages => { |
| 114 | 133 | this.npmPackages = npmPackages | ... | ... |
front-end/h5/src/components/core/editor/shortcuts-panel/load-npm-plugins.vue renamed to front-end/h5/src/components/core/editor/left-panel/shortcuts-panel/load-npm-plugins.vue
| ... | ... | @@ -2,11 +2,11 @@ |
| 2 | 2 | * @Author: ly525 |
| 3 | 3 | * @Date: 2019-11-23 12:35:43 |
| 4 | 4 | * @LastEditors: ly525 |
| 5 | - * @LastEditTime: 2019-11-23 19:37:29 | |
| 6 | - * @FilePath: /luban-h5/front-end/h5/src/components/core/editor/shortcuts-panel/load-npm-plugins.vue | |
| 5 | + * @LastEditTime: 2020-10-10 23:31:49 | |
| 6 | + * @FilePath: /luban-h5/front-end/h5/src/components/core/editor/left-panel/shortcuts-panel/load-npm-plugins.vue | |
| 7 | 7 | * @Github: https://github.com/ly525/luban-h5 |
| 8 | 8 | * @Description: Do not edit |
| 9 | - * @Copyright 2018 - 2019 luban-h5. All Rights Reserved | |
| 9 | + * @Copyright 2018 - 2020 luban-h5. All Rights Reserved | |
| 10 | 10 | --> |
| 11 | 11 | |
| 12 | 12 | <template> | ... | ... |
front-end/h5/src/components/core/editor/shortcuts-panel/shortcut-button.js renamed to front-end/h5/src/components/core/editor/left-panel/shortcuts-panel/shortcut-button.js
front-end/h5/src/components/core/editor/left-panel/shortcuts-panel/usage-tip.js
0 → 100644
| 1 | +export default { | |
| 2 | + render () { | |
| 3 | + return ( | |
| 4 | + <div class="plugin-usage-tip "> | |
| 5 | + <a-icon type="info-circle" /> | |
| 6 | + {/* 使用提示: 点击或拖拽 组件即可 */} | |
| 7 | + {/* Tip: just click/drag component */} | |
| 8 | + <i18n path="editor.tip.componentUsage" tag="span" class="ml-1"> | |
| 9 | + <strong>{ this.$t('editor.tip.click') }</strong>{ this.$t('editor.tip.click') } | |
| 10 | + </i18n> | |
| 11 | + </div> | |
| 12 | + ) | |
| 13 | + } | |
| 14 | +} | ... | ... |
front-end/h5/src/components/core/editor/page-manager/index.js deleted
100644 → 0
| 1 | -export default { | |
| 2 | - props: { | |
| 3 | - pages: { | |
| 4 | - required: false, | |
| 5 | - type: Array, | |
| 6 | - default: () => [] | |
| 7 | - }, | |
| 8 | - editingPage: { | |
| 9 | - type: Object, | |
| 10 | - default: () => {} | |
| 11 | - } | |
| 12 | - }, | |
| 13 | - data: () => ({ | |
| 14 | - hoverIndex: -1, // 显示编辑按钮 | |
| 15 | - editingTitle: '' // 临时缓存当前编辑的 title,点击 Yes 再真正用其更新 page title | |
| 16 | - }), | |
| 17 | - methods: { | |
| 18 | - getTitle (page, index) { | |
| 19 | - return page.title || this.$t('editor.pageManager.title', { index }) | |
| 20 | - }, | |
| 21 | - _renderEditTitle (page, index) { | |
| 22 | - return ( | |
| 23 | - <a-popconfirm | |
| 24 | - placement="bottom" | |
| 25 | - onConfirm={() => { | |
| 26 | - this.$emit('editTitle', { newTitle: this.editingTitle, pageIndexForEditingTitle: index }) | |
| 27 | - }} | |
| 28 | - onCancel={() => {}} | |
| 29 | - okText="Yes" | |
| 30 | - cancelText="No" | |
| 31 | - > | |
| 32 | - <a-input | |
| 33 | - slot="title" | |
| 34 | - value={this.editingTitle} | |
| 35 | - size="small" | |
| 36 | - onChange={e => { | |
| 37 | - this.editingTitle = e.target.value | |
| 38 | - }} | |
| 39 | - > | |
| 40 | - </a-input> | |
| 41 | - <a-icon type="edit" onClick={(e) => { | |
| 42 | - e.stopPropagation() // 将 click icon 与 click page item 隔离开。编辑标题的同时不要切换页面 | |
| 43 | - this.editingTitle = this.getTitle(page, index) | |
| 44 | - }}/> | |
| 45 | - </a-popconfirm> | |
| 46 | - ) | |
| 47 | - }, | |
| 48 | - _renderTitleMenu (page, index) { | |
| 49 | - const addPageText = this.$t('editor.pageManager.action.add') | |
| 50 | - const copyPageText = this.$t('editor.pageManager.action.copy') | |
| 51 | - const deletePageText = this.$t('editor.pageManager.action.delete') | |
| 52 | - return ( | |
| 53 | - <a-dropdown trigger={['hover']} placement='bottomCenter'> | |
| 54 | - <a class="ant-dropdown-link" href="#" class="ml-2"><a-icon type="down" /></a> | |
| 55 | - <a-menu slot="overlay" onClick={({ key }) => this.$emit('selectMenuItem', key)}> | |
| 56 | - <a-menu-item key="add"><a-icon type="plus" />{addPageText}</a-menu-item> | |
| 57 | - <a-menu-item key="copy"><a-icon type="copy" />{copyPageText}</a-menu-item> | |
| 58 | - <a-menu-item key="delete"><a-icon type="delete" />{deletePageText}</a-menu-item> | |
| 59 | - </a-menu> | |
| 60 | - </a-dropdown> | |
| 61 | - ) | |
| 62 | - }, | |
| 63 | - onLeave () { | |
| 64 | - this.hoverIndex = -1 | |
| 65 | - } | |
| 66 | - }, | |
| 67 | - render (h) { | |
| 68 | - const addPageText = this.$t('editor.pageManager.action.add') | |
| 69 | - return ( | |
| 70 | - <div class="page-manager-panel"> | |
| 71 | - { | |
| 72 | - this.pages.map((page, index) => ( | |
| 73 | - <span | |
| 74 | - class={[ | |
| 75 | - 'cursor-pointer', | |
| 76 | - 'page-manager-panel__item', | |
| 77 | - page.uuid === this.editingPage.uuid && 'active' | |
| 78 | - ]} | |
| 79 | - onClick={() => { this.$emit('selectPage', index) }} | |
| 80 | - // https://github.com/vuetifyjs/vuetify/blob/master/packages/vuetify/src/components/VHover/VHover.ts | |
| 81 | - onMouseenter={() => { this.hoverIndex = index }} | |
| 82 | - > | |
| 83 | - {/* #!en: Page<Index> */} | |
| 84 | - {/* #!zh: 第<Index>页面 */} | |
| 85 | - <span> | |
| 86 | - <a-badge | |
| 87 | - count={index + 1} | |
| 88 | - numberStyle={{ backgroundColor: '#fff', color: '#999', boxShadow: '0 0 0 1px #d9d9d9 inset' }} | |
| 89 | - /> | |
| 90 | - <span class="ml-3">{this.getTitle(page, index)}</span> | |
| 91 | - </span> | |
| 92 | - <span> | |
| 93 | - {this.hoverIndex === index && this._renderEditTitle(page, index)} | |
| 94 | - {this._renderTitleMenu(page, index)} | |
| 95 | - </span> | |
| 96 | - </span> | |
| 97 | - )) | |
| 98 | - } | |
| 99 | - <a-button | |
| 100 | - icon="plus" | |
| 101 | - type="dashed" | |
| 102 | - class="footer-actions" | |
| 103 | - onClick={() => { this.$emit('selectMenuItem', 'add') }} | |
| 104 | - >{addPageText}</a-button> | |
| 105 | - </div> | |
| 106 | - ) | |
| 107 | - } | |
| 108 | -} |
front-end/h5/src/components/core/editor/edit-panel/action.js renamed to front-end/h5/src/components/core/editor/right-panel/action.js
front-end/h5/src/components/core/editor/edit-panel/animation.js renamed to front-end/h5/src/components/core/editor/right-panel/animation.js
| 1 | 1 | import { mapState } from 'vuex' |
| 2 | -import { animationOptions, animationValue2Name, firstLevelAnimationOptions } from '@/constants/animation.js' | |
| 2 | +import { animationOptions, animationValue2Name, firstLevelAnimationOptions } from 'core/constants/animation.js' | |
| 3 | 3 | |
| 4 | 4 | export default { |
| 5 | 5 | computed: { |
| ... | ... | @@ -32,7 +32,7 @@ export default { |
| 32 | 32 | }, |
| 33 | 33 | runAnimate () { |
| 34 | 34 | // front-end/h5/src/components/core/editor/index.js created() |
| 35 | - window.getEditorApp.$emit('RUN_ANIMATIONS') | |
| 35 | + window.EditorApp.$emit('RUN_ANIMATIONS') | |
| 36 | 36 | }, |
| 37 | 37 | renderSecondAnimationTabs (animations) { |
| 38 | 38 | return ( |
| ... | ... | @@ -208,7 +208,7 @@ export default { |
| 208 | 208 | const ele = this.editingElement |
| 209 | 209 | if (!ele) return (<span>{this.$t('editor.editPanel.common.empty')}</span>) |
| 210 | 210 | return ( |
| 211 | - <div class="main-animate widget" id="animation-edit-panel"> | |
| 211 | + <div class="main-animate widget" id="animation-right-panel"> | |
| 212 | 212 | <a-button-group> |
| 213 | 213 | {/* 添加动画、运行动画 */} |
| 214 | 214 | <a-button type="primary" onClick={this.addAnimation}><a-icon type="plus" />{this.$t('editor.editPanel.animation.add')}</a-button> | ... | ... |
front-end/h5/src/components/core/editor/edit-panel/background.js renamed to front-end/h5/src/components/core/editor/right-panel/background.js
| 1 | 1 | /* |
| 2 | 2 | * @Author: ly525 |
| 3 | 3 | * @Date: 2019-12-01 18:11:49 |
| 4 | - * @LastEditors : ly525 | |
| 5 | - * @LastEditTime : 2020-01-15 01:03:31 | |
| 6 | - * @FilePath: /luban-h5/front-end/h5/src/components/core/editor/edit-panel/background.js | |
| 4 | + * @LastEditors: ly525 | |
| 5 | + * @LastEditTime: 2020-10-10 23:36:27 | |
| 6 | + * @FilePath: /luban-h5/front-end/h5/src/components/core/editor/right-panel/background.js | |
| 7 | 7 | * @Github: https://github.com/ly525/luban-h5 |
| 8 | 8 | * @Description: Do not edit |
| 9 | - * @Copyright 2018 - 2019 luban-h5. All Rights Reserved | |
| 9 | + * @Copyright 2018 - 2020 luban-h5. All Rights Reserved | |
| 10 | 10 | */ |
| 11 | -import propsEditPanel from './props.js' | |
| 11 | +import PropsEditPanel from './props.js' | |
| 12 | 12 | import { mapState, mapActions } from 'vuex' |
| 13 | +import RenderWorkMode from './work-mode.vue' | |
| 13 | 14 | |
| 14 | 15 | export default { |
| 15 | 16 | computed: { |
| ... | ... | @@ -24,10 +25,15 @@ export default { |
| 24 | 25 | }, |
| 25 | 26 | render () { |
| 26 | 27 | const bgEle = this.editingPage.elements.find(e => e.name === 'lbp-background') |
| 27 | - return <propsEditPanel | |
| 28 | - layout="vertical" | |
| 29 | - realEditingElement={bgEle} | |
| 30 | - /> | |
| 28 | + return ( | |
| 29 | + <div> | |
| 30 | + <RenderWorkMode /> | |
| 31 | + <PropsEditPanel | |
| 32 | + layout="vertical" | |
| 33 | + realEditingElement={bgEle} | |
| 34 | + /> | |
| 35 | + </div> | |
| 36 | + ) | |
| 31 | 37 | } |
| 32 | 38 | |
| 33 | 39 | } | ... | ... |
front-end/h5/src/components/core/editor/right-panel/index.js
0 → 100644
| 1 | +import RenderPropsEditor from './props' | |
| 2 | +import RenderScriptEditor from './script' | |
| 3 | +import RenderAnimationEditor from './animation' | |
| 4 | +import RenderActionEditor from './action' | |
| 5 | +import RenderBackgroundEditor from './background' | |
| 6 | +export default { | |
| 7 | + name: 'ElementPropsEditor', | |
| 8 | + props: { | |
| 9 | + width: { | |
| 10 | + type: Number, | |
| 11 | + default: 320 | |
| 12 | + } | |
| 13 | + }, | |
| 14 | + data: () => ({ | |
| 15 | + activeTabKey: '页面' | |
| 16 | + }), | |
| 17 | + methods: { | |
| 18 | + /** | |
| 19 | + * #!zh: 设置 页面图tab 作为 active tab | |
| 20 | + * #!en: set background(bg) tab as active tab | |
| 21 | + */ | |
| 22 | + setActiveTab (activeTabKey) { | |
| 23 | + this.activeTabKey = activeTabKey | |
| 24 | + } | |
| 25 | + }, | |
| 26 | + render (h) { | |
| 27 | + return ( | |
| 28 | + <a-layout-sider width={this.width} data-set-width={this.width} theme='light' style={{ background: '#fff', padding: '0 12px 0 12px' }}> | |
| 29 | + <a-tabs | |
| 30 | + style="height: 100%;" | |
| 31 | + tabBarGutter={10} | |
| 32 | + defaultActiveKey={this.activeTabKey} | |
| 33 | + activeKey={this.activeTabKey} | |
| 34 | + onChange={this.setActiveTab} | |
| 35 | + > | |
| 36 | + <a-tab-pane key="属性"><span slot="tab">{this.$t('editor.editPanel.tab.prop')}</span><RenderPropsEditor/></a-tab-pane> | |
| 37 | + <a-tab-pane label="动画" key='动画' tab={this.$t('editor.editPanel.tab.animation')}><RenderAnimationEditor /></a-tab-pane> | |
| 38 | + <a-tab-pane label="动作" key='动作' tab={this.$t('editor.editPanel.tab.action')}>{ this.activeTabKey === '动作' && <RenderActionEditor/> }</a-tab-pane> | |
| 39 | + <a-tab-pane label="脚本" key='脚本' tab={this.$t('editor.editPanel.tab.script')}><RenderScriptEditor/></a-tab-pane> | |
| 40 | + <a-tab-pane label="页面" key='页面' tab={this.$t('editor.editPanel.tab.page')}>{ this.activeTabKey === '页面' && <RenderBackgroundEditor/> }</a-tab-pane> | |
| 41 | + </a-tabs> | |
| 42 | + </a-layout-sider> | |
| 43 | + ) | |
| 44 | + }, | |
| 45 | + created () { | |
| 46 | + window.EditorApp.$on('setEditingElement', ({ name }) => { | |
| 47 | + this.setActiveTab(name === 'lbp-background' ? '页面' : '属性') | |
| 48 | + }) | |
| 49 | + } | |
| 50 | +} | ... | ... |
front-end/h5/src/components/core/editor/edit-panel/props.js renamed to front-end/h5/src/components/core/editor/right-panel/props.js
| 1 | 1 | import Vue from 'vue' |
| 2 | 2 | import { mapState, mapActions } from 'vuex' |
| 3 | -import { getVM, getComponentsForPropsEditor } from '../../../../utils/element' | |
| 4 | -import RenderGlobalWorkPropsEditor from './props/global-work.vue' | |
| 3 | +import { getVM, getComponentsForPropsEditor } from '@/utils/element' | |
| 4 | +import 'core/styles/props-config-panel.scss' | |
| 5 | 5 | |
| 6 | 6 | export default { |
| 7 | 7 | data: () => ({ |
| ... | ... | @@ -40,7 +40,7 @@ export default { |
| 40 | 40 | if (Vue.component(this.customEditorName)) { |
| 41 | 41 | this.loadCustomEditorFlag = true |
| 42 | 42 | } else { |
| 43 | - import(`../../../plugins/${this.editingElement.name}__editor`).then(component => { | |
| 43 | + import(`core/plugins/${this.editingElement.name}__editor`).then(component => { | |
| 44 | 44 | this.loadCustomEditorFlag = true |
| 45 | 45 | Vue.component(this.customEditorName, component.default) |
| 46 | 46 | }).catch(err => { |
| ... | ... | @@ -122,9 +122,8 @@ export default { |
| 122 | 122 | <a-form |
| 123 | 123 | ref="form" |
| 124 | 124 | size="mini" |
| 125 | - id="props-edit-form" | |
| 125 | + class="props-config-form" | |
| 126 | 126 | layout={this.layout} |
| 127 | - style="overflow: auto;position: absolute;top: 50px;bottom: 0;width: 100%; " | |
| 128 | 127 | > |
| 129 | 128 | { |
| 130 | 129 | // plugin-custom-editor |
| ... | ... | @@ -151,17 +150,17 @@ export default { |
| 151 | 150 | ) |
| 152 | 151 | }, |
| 153 | 152 | renderWorkGlobalPropsPanel (h) { |
| 154 | - return <RenderGlobalWorkPropsEditor /> | |
| 153 | + return <RenderWorkMode /> | |
| 155 | 154 | } |
| 156 | 155 | }, |
| 157 | 156 | render (h) { |
| 158 | 157 | const ele = this.editingElement |
| 159 | - if (!ele) return this.renderWorkGlobalPropsPanel(h) | |
| 158 | + if (!ele) return '请选择一个元素' | |
| 160 | 159 | this.mixinEnhancedPropsEditor(ele) |
| 161 | 160 | return this.renderPropsEditorPanel(h, ele) |
| 162 | 161 | }, |
| 163 | 162 | created () { |
| 164 | - window.getEditorApp.$on('setEditingElement', (ele) => { | |
| 163 | + window.EditorApp.$on('setEditingElement', (ele) => { | |
| 165 | 164 | this.loadCustomEditorForPlugin() |
| 166 | 165 | this.componentsForPropsEditor = getComponentsForPropsEditor(ele.name) |
| 167 | 166 | }) | ... | ... |
front-end/h5/src/components/core/editor/edit-panel/script.js renamed to front-end/h5/src/components/core/editor/right-panel/script.js
front-end/h5/src/components/core/editor/edit-panel/props/global-work.vue renamed to front-end/h5/src/components/core/editor/right-panel/work-mode.vue
| ... | ... | @@ -2,11 +2,11 @@ |
| 2 | 2 | * @Author: ly525 |
| 3 | 3 | * @Date: 2020-05-10 23:10:52 |
| 4 | 4 | * @LastEditors: ly525 |
| 5 | - * @LastEditTime: 2020-05-13 00:09:56 | |
| 6 | - * @FilePath: /h5/src/components/core/editor/edit-panel/props/global-work.vue | |
| 5 | + * @LastEditTime: 2020-10-10 23:32:07 | |
| 6 | + * @FilePath: /luban-h5/front-end/h5/src/components/core/editor/right-panel/work-mode.vue | |
| 7 | 7 | * @Github: https://github.com/ly525/luban-h5 |
| 8 | 8 | * @Description: Do not edit |
| 9 | - * @Copyright 2018 - 2019 luban-h5. All Rights Reserved | |
| 9 | + * @Copyright 2018 - 2020 luban-h5. All Rights Reserved | |
| 10 | 10 | --> |
| 11 | 11 | <template> |
| 12 | 12 | <a-form :layout="formLayout"> |
| ... | ... | @@ -22,7 +22,7 @@ |
| 22 | 22 | |
| 23 | 23 | <script> |
| 24 | 24 | import { mapState, mapActions } from 'vuex' |
| 25 | -import { PAGE_MODE, PAGE_MODE_LABEL } from '@/constants/work' | |
| 25 | +import { PAGE_MODE, PAGE_MODE_LABEL } from 'core/constants/work' | |
| 26 | 26 | |
| 27 | 27 | export default { |
| 28 | 28 | data () { | ... | ... |
front-end/h5/src/components/core/index.js
0 → 100644
| 1 | +import { mapState, mapActions } from 'vuex' | |
| 2 | +import Vue from 'vue' | |
| 3 | + | |
| 4 | +import 'core/support/index.js' | |
| 5 | +import 'core/styles/index.scss' | |
| 6 | +import 'animate.css' | |
| 7 | + | |
| 8 | +import FixedTools from 'core/editor/fixed-tools/index' | |
| 9 | +import EditorRightPanel from 'core/editor/right-panel/index' | |
| 10 | +import EditorCanvas from 'core/editor/canvas/index' | |
| 11 | +import EditorActionMenu from 'core/editor/header/action-menu' | |
| 12 | +import EditorLeftPanel from 'core/editor/left-panel/index' | |
| 13 | +import PreviewDialog from 'core/editor/modals/preview.vue' | |
| 14 | +import Header from '@/components/common/header/index' | |
| 15 | +import Feedback from '@/components/common/feedback/index' | |
| 16 | +import AdjustLineV from 'core/support/adjust-line/vertical' | |
| 17 | + | |
| 18 | +import store from 'core/store/index' | |
| 19 | +import router from 'core/router/index' | |
| 20 | +import i18n from '@/locales' | |
| 21 | +import '@/plugins/index' | |
| 22 | + | |
| 23 | +window.EditorApp = new Vue() // event bus | |
| 24 | +const CoreEditor = { | |
| 25 | + name: 'CoreEditor', | |
| 26 | + store, | |
| 27 | + i18n, | |
| 28 | + router, | |
| 29 | + props: { | |
| 30 | + workId: { | |
| 31 | + type: [Number, String] | |
| 32 | + } | |
| 33 | + }, | |
| 34 | + data: () => ({ | |
| 35 | + previewDialogVisible: false, | |
| 36 | + propsPanelWidth: 320 | |
| 37 | + }), | |
| 38 | + computed: { | |
| 39 | + ...mapState('editor', { | |
| 40 | + work: state => state.work | |
| 41 | + }) | |
| 42 | + }, | |
| 43 | + methods: { | |
| 44 | + ...mapActions('editor', ['fetchWork']), | |
| 45 | + handlePreview () { this.previewDialogVisible = true } | |
| 46 | + }, | |
| 47 | + render (h) { | |
| 48 | + return ( | |
| 49 | + <a-layout> | |
| 50 | + <Header> | |
| 51 | + <EditorActionMenu slot="action-menu" onPreview={this.handlePreview} /> | |
| 52 | + </Header> | |
| 53 | + <a-layout> | |
| 54 | + <EditorLeftPanel /> | |
| 55 | + <EditorCanvas /> | |
| 56 | + <AdjustLineV onLineMove={(offset) => { this.propsPanelWidth += offset }} /> | |
| 57 | + <FixedTools /> | |
| 58 | + <EditorRightPanel width={this.propsPanelWidth} /> | |
| 59 | + </a-layout> | |
| 60 | + { | |
| 61 | + <PreviewDialog | |
| 62 | + work={this.work} | |
| 63 | + visible={this.previewDialogVisible} | |
| 64 | + handleClose={() => { this.previewDialogVisible = false }} | |
| 65 | + /> | |
| 66 | + } | |
| 67 | + <Feedback /> | |
| 68 | + </a-layout> | |
| 69 | + ) | |
| 70 | + }, | |
| 71 | + created () { | |
| 72 | + if (this.workId) { | |
| 73 | + this.fetchWork(this.workId) | |
| 74 | + } else { | |
| 75 | + this.$message.error('no work id!') | |
| 76 | + } | |
| 77 | + } | |
| 78 | +} | |
| 79 | + | |
| 80 | +// Vue install, Vue.use 会调用该方法。 | |
| 81 | +CoreEditor.install = (Vue, opts = {}) => { | |
| 82 | + Vue.component(CoreEditor.name, CoreEditor) | |
| 83 | +} | |
| 84 | + | |
| 85 | +// 通过script标签引入Vue的环境 | |
| 86 | +if (typeof window !== 'undefined' && window.Vue) { | |
| 87 | + CoreEditor.install(window.Vue) | |
| 88 | +} | |
| 89 | + | |
| 90 | +export default CoreEditor | ... | ... |
front-end/h5/src/mixins/animation.js renamed to front-end/h5/src/components/core/mixins/animation.js
| 1 | 1 | /* |
| 2 | 2 | * @Author: ly525 |
| 3 | 3 | * @Date: 2019-11-24 18:51:58 |
| 4 | - * @LastEditors : ly525 | |
| 5 | - * @LastEditTime : 2020-01-09 21:57:30 | |
| 6 | - * @FilePath: /luban-h5/front-end/h5/src/mixins/animation.js | |
| 4 | + * @LastEditors: ly525 | |
| 5 | + * @LastEditTime: 2020-10-10 23:35:49 | |
| 6 | + * @FilePath: /luban-h5/front-end/h5/src/components/core/mixins/animation.js | |
| 7 | 7 | * @Github: https://github.com/ly525/luban-h5 |
| 8 | 8 | * @Description: |
| 9 | - * @Copyright 2018 - 2019 luban-h5. All Rights Reserved | |
| 9 | + * @Copyright 2018 - 2020 luban-h5. All Rights Reserved | |
| 10 | 10 | */ |
| 11 | 11 | // https://stackoverflow.com/questions/26874769/getcomputedstyle-and-csstext-in-ie-and-firefox |
| 12 | 12 | function getComputedCSSText (style) { |
| ... | ... | @@ -55,7 +55,7 @@ export default { |
| 55 | 55 | }, |
| 56 | 56 | created () { |
| 57 | 57 | const that = this |
| 58 | - window.getEditorApp && window.getEditorApp.$on('RUN_ANIMATIONS', () => { | |
| 58 | + window.EditorApp && window.EditorApp.$on('RUN_ANIMATIONS', () => { | |
| 59 | 59 | that.runAnimations() |
| 60 | 60 | // if (that.active) { |
| 61 | 61 | // that.runAnimations() | ... | ... |
front-end/h5/src/components/core/editor/drag-mixin.js renamed to front-end/h5/src/components/core/mixins/drag.js
| ... | ... | @@ -2,10 +2,10 @@ |
| 2 | 2 | * @Author: ly525 |
| 3 | 3 | * @Date: 2020-05-17 17:21:04 |
| 4 | 4 | * @LastEditors: ly525 |
| 5 | - * @LastEditTime: 2020-05-24 18:09:23 | |
| 6 | - * @FilePath: /luban-h5/front-end/h5/src/components/core/editor/drag-mixin.js | |
| 5 | + * @LastEditTime: 2020-10-11 17:20:39 | |
| 6 | + * @FilePath: /luban-h5/front-end/h5/src/components/core/mixins/drag.js | |
| 7 | 7 | * @Github: https://github.com/ly525/luban-h5 |
| 8 | - * @Copyright 2018 - 2019 luban-h5. All Rights Reserved | |
| 8 | + * @Copyright 2018 - 2020 luban-h5. All Rights Reserved | |
| 9 | 9 | * @Description: |
| 10 | 10 | * 组件拖拽至画布功能 |
| 11 | 11 | * 其中部分代码参考自:https://github.com/hakubox/haku-form-design,已经征得作者同意,目的是后续考虑做 tab 之类的嵌套容器 |
| ... | ... | @@ -50,7 +50,6 @@ class Drag { |
| 50 | 50 | } |
| 51 | 51 | |
| 52 | 52 | _mouseup (e) { |
| 53 | - console.log('mouseup') | |
| 54 | 53 | this.mouseup(e) |
| 55 | 54 | this.toggleListener('remove') |
| 56 | 55 | } | ... | ... |
front-end/h5/src/mixins/i18n.js renamed to front-end/h5/src/components/core/mixins/i18n.js
front-end/h5/src/components/core/models/element.js
front-end/h5/src/components/core/models/page.js
front-end/h5/src/components/core/models/work.js
| ... | ... | @@ -2,14 +2,14 @@ |
| 2 | 2 | * @Author: ly525 |
| 3 | 3 | * @Date: 2019-11-24 18:51:58 |
| 4 | 4 | * @LastEditors: ly525 |
| 5 | - * @LastEditTime: 2020-05-10 23:23:40 | |
| 5 | + * @LastEditTime: 2020-10-10 23:32:31 | |
| 6 | 6 | * @FilePath: /luban-h5/front-end/h5/src/components/core/models/work.js |
| 7 | 7 | * @Github: https://github.com/ly525/luban-h5 |
| 8 | 8 | * @Description: work model |
| 9 | - * @Copyright 2018 - 2019 luban-h5. All Rights Reserved | |
| 9 | + * @Copyright 2018 - 2020 luban-h5. All Rights Reserved | |
| 10 | 10 | */ |
| 11 | 11 | import Page from './page.js' |
| 12 | -import { PAGE_MODE } from '@/constants/work' | |
| 12 | +import { PAGE_MODE } from 'core/constants/work' | |
| 13 | 13 | |
| 14 | 14 | class Work { |
| 15 | 15 | constructor (work = {}) { | ... | ... |
front-end/h5/src/components/core/package.json
0 → 100644
front-end/h5/src/components/plugins/charts/chart-mixin.js renamed to front-end/h5/src/components/core/plugins/charts/chart-mixin.js
front-end/h5/src/components/plugins/charts/chart-model.js renamed to front-end/h5/src/components/core/plugins/charts/chart-model.js
front-end/h5/src/components/plugins/charts/chart-model.ts renamed to front-end/h5/src/components/core/plugins/charts/chart-model.ts
front-end/h5/src/components/plugins/charts/line.js renamed to front-end/h5/src/components/core/plugins/charts/line.js
| ... | ... | @@ -8,7 +8,7 @@ import 'echarts/lib/component/legend' |
| 8 | 8 | import 'echarts/lib/component/markLine' |
| 9 | 9 | import 'echarts/lib/component/markPoint' |
| 10 | 10 | import 'echarts/lib/component/markArea' |
| 11 | -import Parser from '../../../utils/excel-parser' | |
| 11 | +import Parser from '@/utils/excel-parser' | |
| 12 | 12 | |
| 13 | 13 | // const title = str => str.slice(0, 1).toUpperCase() + str.slice(1) |
| 14 | 14 | ... | ... |
front-end/h5/src/mixins/load-plugins.js renamed to front-end/h5/src/components/core/plugins/index.js
| 1 | 1 | import Vue from 'vue' |
| 2 | 2 | // import LbpButton from '@luban-h5/lbc-button' |
| 3 | -import LbpButton from '../components/plugins/lbp-button' | |
| 4 | -import LbpPicture from '../components/plugins/lbp-picture' | |
| 5 | -import LbpVideo from '../components/plugins/lbp-video' | |
| 6 | -import LbpText from '../components/plugins/lbp-text' | |
| 7 | -import LbpFormInput from '../components/plugins/lbp-form-input' | |
| 8 | -import LbpFormButton from '../components/plugins/lbp-form-button' | |
| 9 | -import LbpFormRadioGroup from '../components/plugins/lbp-form-radio-group' | |
| 10 | -import LbpFormCheckboxGroup from '../components/plugins/lbp-form-checkbox-group' | |
| 11 | -import LbpBackground from '../components/plugins/lbp-background' | |
| 12 | -import LbpSlide from '../components/plugins/lbp-slide' | |
| 13 | -import LbpBgMusic from '../components/plugins/lbp-bg-music' | |
| 14 | -import LbpNoticeBar from '../components/plugins/lbp-notice-bar' | |
| 15 | -import LbpRate from '../components/plugins/lbp-rate' | |
| 16 | -import LbpQQMap from '../components/plugins/lbp-qq-map/src' | |
| 17 | -import LbpLineChart from '../components/plugins/charts/line' | |
| 18 | -import LbpTable from '../components/plugins/lbp-table' | |
| 19 | -import LbpNewsList from '../components/plugins/lbp-news-list' | |
| 20 | -// import LbpTabs from '../components/plugins/lbp-tabs' | |
| 3 | +import LbpButton from 'core/plugins/lbp-button' | |
| 4 | +import LbpPicture from 'core/plugins/lbp-picture' | |
| 5 | +import LbpVideo from 'core/plugins/lbp-video' | |
| 6 | +import LbpText from 'core/plugins/lbp-text' | |
| 7 | +import LbpFormInput from 'core/plugins/lbp-form-input' | |
| 8 | +import LbpFormButton from 'core/plugins/lbp-form-button' | |
| 9 | +import LbpFormRadioGroup from 'core/plugins/lbp-form-radio-group' | |
| 10 | +import LbpFormCheckboxGroup from 'core/plugins/lbp-form-checkbox-group' | |
| 11 | +import LbpBackground from 'core/plugins/lbp-background' | |
| 12 | +import LbpSlide from 'core/plugins/lbp-slide' | |
| 13 | +import LbpBgMusic from 'core/plugins/lbp-bg-music' | |
| 14 | +import LbpNoticeBar from 'core/plugins/lbp-notice-bar' | |
| 15 | +import LbpRate from 'core/plugins/lbp-rate' | |
| 16 | +import LbpQQMap from 'core/plugins/lbp-qq-map/src' | |
| 17 | +import LbpLineChart from 'core/plugins/charts/line' | |
| 18 | +import LbpTable from 'core/plugins/lbp-table' | |
| 19 | +import LbpNewsList from 'core/plugins/lbp-news-list' | |
| 20 | +// import LbpTabs from 'core/components/plugins/lbp-tabs' | |
| 21 | 21 | |
| 22 | 22 | export const pluginsList = [ |
| 23 | 23 | { | ... | ... |
front-end/h5/src/components/plugins/lbp-background.js renamed to front-end/h5/src/components/core/plugins/lbp-background.js
| ... | ... | @@ -2,14 +2,14 @@ |
| 2 | 2 | * @Author: ly525 |
| 3 | 3 | * @Date: 2019-11-24 18:51:58 |
| 4 | 4 | * @LastEditors: ly525 |
| 5 | - * @LastEditTime: 2020-05-17 21:02:47 | |
| 6 | - * @FilePath: /luban-h5/front-end/h5/src/components/plugins/lbp-background.js | |
| 5 | + * @LastEditTime: 2020-10-10 23:32:48 | |
| 6 | + * @FilePath: /luban-h5/front-end/h5/src/components/core/plugins/lbp-background.js | |
| 7 | 7 | * @Github: https://github.com/ly525/luban-h5 |
| 8 | 8 | * @Description: luban-h5 background image/color component/plugin |
| 9 | - * @Copyright 2018 - 2019 luban-h5. All Rights Reserved | |
| 9 | + * @Copyright 2018 - 2020 luban-h5. All Rights Reserved | |
| 10 | 10 | */ |
| 11 | 11 | import PropTypes from '@luban-h5/plugin-common-props' |
| 12 | -import { renderWaterMark } from '../../utils/dom-helper' | |
| 12 | +import { renderWaterMark } from '@/utils/dom-helper' | |
| 13 | 13 | |
| 14 | 14 | export default { |
| 15 | 15 | name: 'lbp-background', | ... | ... |
front-end/h5/src/components/plugins/lbp-bg-music.js renamed to front-end/h5/src/components/core/plugins/lbp-bg-music.js
| ... | ... | @@ -2,11 +2,11 @@ |
| 2 | 2 | * @Author: ly525 |
| 3 | 3 | * @Date: 2020-01-03 23:43:34 |
| 4 | 4 | * @LastEditors: ly525 |
| 5 | - * @LastEditTime: 2020-05-17 20:58:32 | |
| 6 | - * @FilePath: /luban-h5/front-end/h5/src/components/plugins/lbp-bg-music.js | |
| 5 | + * @LastEditTime: 2020-10-10 23:32:41 | |
| 6 | + * @FilePath: /luban-h5/front-end/h5/src/components/core/plugins/lbp-bg-music.js | |
| 7 | 7 | * @Github: https://github.com/ly525/luban-h5 |
| 8 | 8 | * @Description: Do not edit |
| 9 | - * @Copyright 2018 - 2019 luban-h5. All Rights Reserved | |
| 9 | + * @Copyright 2018 - 2020 luban-h5. All Rights Reserved | |
| 10 | 10 | */ |
| 11 | 11 | import PropTypes from '@luban-h5/plugin-common-props' |
| 12 | 12 | import './styles/bg-music.scss' | ... | ... |
front-end/h5/src/components/plugins/lbp-button.js renamed to front-end/h5/src/components/core/plugins/lbp-button.js
front-end/h5/src/components/plugins/lbp-form-button.js renamed to front-end/h5/src/components/core/plugins/lbp-form-button.js
front-end/h5/src/components/plugins/lbp-form-checkbox-group.js renamed to front-end/h5/src/components/core/plugins/lbp-form-checkbox-group.js
front-end/h5/src/components/plugins/lbp-form-input.js renamed to front-end/h5/src/components/core/plugins/lbp-form-input.js
front-end/h5/src/components/plugins/lbp-form-radio-group.js renamed to front-end/h5/src/components/core/plugins/lbp-form-radio-group.js
| ... | ... | @@ -2,11 +2,11 @@ |
| 2 | 2 | * @Author: ly525 |
| 3 | 3 | * @Date: 2019-11-23 12:35:43 |
| 4 | 4 | * @LastEditors: ly525 |
| 5 | - * @LastEditTime: 2020-05-17 23:17:23 | |
| 6 | - * @FilePath: /h5/src/components/plugins/lbp-form-radio-group.js | |
| 5 | + * @LastEditTime: 2020-10-10 23:33:03 | |
| 6 | + * @FilePath: /luban-h5/front-end/h5/src/components/core/plugins/lbp-form-radio-group.js | |
| 7 | 7 | * @Github: https://github.com/ly525/luban-h5 |
| 8 | 8 | * @Description: 表单单选组组件 #!en: radio group component |
| 9 | - * @Copyright 2018 - 2019 luban-h5. All Rights Reserved | |
| 9 | + * @Copyright 2018 - 2020 luban-h5. All Rights Reserved | |
| 10 | 10 | */ |
| 11 | 11 | |
| 12 | 12 | import PropTypes from '@luban-h5/plugin-common-props' | ... | ... |
front-end/h5/src/components/plugins/lbp-form-radio.js renamed to front-end/h5/src/components/core/plugins/lbp-form-radio.js
| ... | ... | @@ -2,15 +2,15 @@ |
| 2 | 2 | * @Author: ly525 |
| 3 | 3 | * @Date: 2020-05-17 19:54:20 |
| 4 | 4 | * @LastEditors: ly525 |
| 5 | - * @LastEditTime: 2020-05-17 19:55:02 | |
| 6 | - * @FilePath: /luban-h5/front-end/h5/src/components/plugins/lbp-form-radio.js | |
| 5 | + * @LastEditTime: 2020-10-10 23:33:11 | |
| 6 | + * @FilePath: /luban-h5/front-end/h5/src/components/core/plugins/lbp-form-radio.js | |
| 7 | 7 | * @Github: https://github.com/ly525/luban-h5 |
| 8 | 8 | * @Description: Do not edit |
| 9 | - * @Copyright 2018 - 2019 luban-h5. All Rights Reserved | |
| 9 | + * @Copyright 2018 - 2020 luban-h5. All Rights Reserved | |
| 10 | 10 | */ |
| 11 | 11 | import './styles/radio.scss' |
| 12 | 12 | // https://github.com/luban-h5-components/plugin-common-props |
| 13 | -import { genUUID } from '../../utils/element.js' | |
| 13 | +import { genUUID } from '@/utils/element.js' | |
| 14 | 14 | |
| 15 | 15 | export default { |
| 16 | 16 | name: 'lbp-form-radio', | ... | ... |
front-end/h5/src/components/plugins/lbp-news-list.js renamed to front-end/h5/src/components/core/plugins/lbp-news-list.js
front-end/h5/src/components/plugins/lbp-notice-bar.js renamed to front-end/h5/src/components/core/plugins/lbp-notice-bar.js
| ... | ... | @@ -2,11 +2,11 @@ |
| 2 | 2 | * @Author: ly525 |
| 3 | 3 | * @Date: 2020-05-14 08:09:44 |
| 4 | 4 | * @LastEditors: ly525 |
| 5 | - * @LastEditTime: 2020-05-17 21:18:32 | |
| 6 | - * @FilePath: /luban-h5/front-end/h5/src/components/plugins/lbp-notice-bar.js | |
| 5 | + * @LastEditTime: 2020-10-10 23:33:19 | |
| 6 | + * @FilePath: /luban-h5/front-end/h5/src/components/core/plugins/lbp-notice-bar.js | |
| 7 | 7 | * @Github: https://github.com/ly525/luban-h5 |
| 8 | 8 | * @Description: Do not edit |
| 9 | - * @Copyright 2018 - 2019 luban-h5. All Rights Reserved | |
| 9 | + * @Copyright 2018 - 2020 luban-h5. All Rights Reserved | |
| 10 | 10 | */ |
| 11 | 11 | |
| 12 | 12 | import PropTypes from '@luban-h5/plugin-common-props' | ... | ... |
front-end/h5/src/components/plugins/lbp-picture-placeholder.png renamed to front-end/h5/src/components/core/plugins/lbp-picture-placeholder.png
23.2 KB
front-end/h5/src/components/plugins/lbp-picture.js renamed to front-end/h5/src/components/core/plugins/lbp-picture.js
front-end/h5/src/components/plugins/lbp-qq-map/README.md renamed to front-end/h5/src/components/core/plugins/lbp-qq-map/README.md
front-end/h5/src/components/plugins/lbp-qq-map/src/Map.js renamed to front-end/h5/src/components/core/plugins/lbp-qq-map/src/Map.js
front-end/h5/src/components/plugins/lbp-qq-map/src/index.vue renamed to front-end/h5/src/components/core/plugins/lbp-qq-map/src/index.vue
front-end/h5/src/components/plugins/lbp-qq-map/src/mixin.js renamed to front-end/h5/src/components/core/plugins/lbp-qq-map/src/mixin.js
front-end/h5/src/components/plugins/lbp-qq-map__editor.js renamed to front-end/h5/src/components/core/plugins/lbp-qq-map__editor.js
front-end/h5/src/components/plugins/lbp-rate.js renamed to front-end/h5/src/components/core/plugins/lbp-rate.js
| ... | ... | @@ -2,11 +2,11 @@ |
| 2 | 2 | * @Author: ly525 |
| 3 | 3 | * @Date: 2020-05-17 20:04:23 |
| 4 | 4 | * @LastEditors: ly525 |
| 5 | - * @LastEditTime: 2020-05-17 21:33:31 | |
| 6 | - * @FilePath: /luban-h5/front-end/h5/src/components/plugins/lbp-rate.js | |
| 5 | + * @LastEditTime: 2020-10-10 23:33:32 | |
| 6 | + * @FilePath: /luban-h5/front-end/h5/src/components/core/plugins/lbp-rate.js | |
| 7 | 7 | * @Github: https://github.com/ly525/luban-h5 |
| 8 | 8 | * @Description: Do not edit |
| 9 | - * @Copyright 2018 - 2019 luban-h5. All Rights Reserved | |
| 9 | + * @Copyright 2018 - 2020 luban-h5. All Rights Reserved | |
| 10 | 10 | */ |
| 11 | 11 | import PropTypes from '@luban-h5/plugin-common-props' |
| 12 | 12 | import { Rate } from 'vant' | ... | ... |
front-end/h5/src/components/plugins/lbp-slide.js renamed to front-end/h5/src/components/core/plugins/lbp-slide.js
| ... | ... | @@ -2,11 +2,11 @@ |
| 2 | 2 | * @Author: ly525 |
| 3 | 3 | * @Date: 2019-11-23 12:35:21 |
| 4 | 4 | * @LastEditors: ly525 |
| 5 | - * @LastEditTime: 2020-05-17 21:22:01 | |
| 6 | - * @FilePath: /luban-h5/front-end/h5/src/components/plugins/lbp-slide.js | |
| 5 | + * @LastEditTime: 2020-10-10 23:33:43 | |
| 6 | + * @FilePath: /luban-h5/front-end/h5/src/components/core/plugins/lbp-slide.js | |
| 7 | 7 | * @Github: https://github.com/ly525/luban-h5 |
| 8 | 8 | * @Description: #!zh: 轮播图组件 #!en slide component |
| 9 | - * @Copyright 2018 - 2019 luban-h5. All Rights Reserved | |
| 9 | + * @Copyright 2018 - 2020 luban-h5. All Rights Reserved | |
| 10 | 10 | */ |
| 11 | 11 | import PropTypes from '@luban-h5/plugin-common-props' |
| 12 | 12 | ... | ... |
front-end/h5/src/components/plugins/lbp-slide__editor.js renamed to front-end/h5/src/components/core/plugins/lbp-slide__editor.js
front-end/h5/src/components/plugins/lbp-table.js renamed to front-end/h5/src/components/core/plugins/lbp-table.js
front-end/h5/src/components/plugins/lbp-text.js renamed to front-end/h5/src/components/core/plugins/lbp-text.js
| ... | ... | @@ -2,11 +2,11 @@ |
| 2 | 2 | * @Author: ly525 |
| 3 | 3 | * @Date: 2019-11-24 18:51:58 |
| 4 | 4 | * @LastEditors: ly525 |
| 5 | - * @LastEditTime: 2020-05-17 21:11:10 | |
| 6 | - * @FilePath: /luban-h5/front-end/h5/src/components/plugins/lbp-text.js | |
| 5 | + * @LastEditTime: 2020-10-10 23:33:50 | |
| 6 | + * @FilePath: /luban-h5/front-end/h5/src/components/core/plugins/lbp-text.js | |
| 7 | 7 | * @Github: https://github.com/ly525/luban-h5 |
| 8 | 8 | * @Description: luban-h5 text component/plugin |
| 9 | - * @Copyright 2018 - 2019 luban-h5. All Rights Reserved | |
| 9 | + * @Copyright 2018 - 2020 luban-h5. All Rights Reserved | |
| 10 | 10 | */ |
| 11 | 11 | import PropTypes from '@luban-h5/plugin-common-props' |
| 12 | 12 | import { quillEditor } from 'vue-quill-editor' | ... | ... |
front-end/h5/src/components/plugins/lbp-video.js renamed to front-end/h5/src/components/core/plugins/lbp-video.js
| ... | ... | @@ -2,11 +2,11 @@ |
| 2 | 2 | * @Author: ly525 |
| 3 | 3 | * @Date: 2019-12-01 18:11:50 |
| 4 | 4 | * @LastEditors: ly525 |
| 5 | - * @LastEditTime: 2020-05-17 21:12:55 | |
| 6 | - * @FilePath: /luban-h5/front-end/h5/src/components/plugins/lbp-video.js | |
| 5 | + * @LastEditTime: 2020-10-10 23:33:57 | |
| 6 | + * @FilePath: /luban-h5/front-end/h5/src/components/core/plugins/lbp-video.js | |
| 7 | 7 | * @Github: https://github.com/ly525/luban-h5 |
| 8 | 8 | * @Description: Do not edit |
| 9 | - * @Copyright 2018 - 2019 luban-h5. All Rights Reserved | |
| 9 | + * @Copyright 2018 - 2020 luban-h5. All Rights Reserved | |
| 10 | 10 | */ |
| 11 | 11 | import PropTypes from '@luban-h5/plugin-common-props' |
| 12 | 12 | ... | ... |
front-end/h5/src/components/plugins/play.svg renamed to front-end/h5/src/components/core/plugins/play.svg
front-end/h5/src/components/plugins/styles/bg-music.scss renamed to front-end/h5/src/components/core/plugins/styles/bg-music.scss
front-end/h5/src/components/plugins/bg-music.svg renamed to front-end/h5/src/components/core/plugins/styles/bg-music.svg
front-end/h5/src/components/plugins/styles/news-list.scss renamed to front-end/h5/src/components/core/plugins/styles/news-list.scss
front-end/h5/src/components/plugins/styles/radio.scss renamed to front-end/h5/src/components/core/plugins/styles/radio.scss
front-end/h5/src/components/plugins/styles/table.scss renamed to front-end/h5/src/components/core/plugins/styles/table.scss
front-end/h5/src/components/plugins/styles/text-overwrite-quil-snow-theme.scss renamed to front-end/h5/src/components/core/plugins/styles/text-overwrite-quil-snow-theme.scss
front-end/h5/src/components/plugins/styles/video.scss renamed to front-end/h5/src/components/core/plugins/styles/video.scss
front-end/h5/src/components/preview/node-wrapper.js renamed to front-end/h5/src/components/core/preview/node-wrapper.js
front-end/h5/src/components/core/router/index.js
0 → 100644
front-end/h5/src/components/core/store/index.js
0 → 100644
| 1 | +/* | |
| 2 | + * @Author: ly525 | |
| 3 | + * @Date: 2020-10-11 10:13:51 | |
| 4 | + * @LastEditors: ly525 | |
| 5 | + * @LastEditTime: 2020-10-11 11:16:37 | |
| 6 | + * @FilePath: /luban-h5/front-end/h5/src/components/core/store/index.js | |
| 7 | + * @Github: https://github.com/ly525/luban-h5 | |
| 8 | + * @Description: Do not edit | |
| 9 | + * @Copyright 2018 - 2019 luban-h5. All Rights Reserved | |
| 10 | + */ | |
| 11 | +import Vue from 'vue' | |
| 12 | +import Vuex from 'vuex' | |
| 13 | +import undoRedoPlugin from './plugins/undo-redo/index' | |
| 14 | +import editor from './modules/editor' | |
| 15 | +import user from './modules/user' | |
| 16 | +import loading from './modules/loading' | |
| 17 | +import i18n from './modules/i18n' | |
| 18 | + | |
| 19 | +Vue.use(Vuex) | |
| 20 | + | |
| 21 | +export default new Vuex.Store({ | |
| 22 | + state: { | |
| 23 | + | |
| 24 | + }, | |
| 25 | + mutations: { | |
| 26 | + | |
| 27 | + }, | |
| 28 | + actions: { | |
| 29 | + | |
| 30 | + }, | |
| 31 | + modules: { | |
| 32 | + editor, | |
| 33 | + user, | |
| 34 | + loading, | |
| 35 | + i18n | |
| 36 | + }, | |
| 37 | + plugins: [undoRedoPlugin] | |
| 38 | +}) | ... | ... |
front-end/h5/src/components/core/store/modules/canvas.js
0 → 100644
| 1 | +// actions | |
| 2 | +export const actions = { | |
| 3 | + updateScaleRate ({ commit }, payload) { | |
| 4 | + commit('updateScaleRate', payload) | |
| 5 | + } | |
| 6 | +} | |
| 7 | + | |
| 8 | +// mutations | |
| 9 | +export const mutations = { | |
| 10 | + /** | |
| 11 | + * | |
| 12 | + * @param {*} state | |
| 13 | + * @param {Number} scaleRateDiff 放大: 0.25, 缩小: -0.25 | |
| 14 | + */ | |
| 15 | + updateScaleRate (state, scaleRateDiff) { | |
| 16 | + state.scaleRate += scaleRateDiff | |
| 17 | + } | |
| 18 | +} | ... | ... |
front-end/h5/src/components/core/store/modules/editor.js
0 → 100644
| 1 | +// initial state | |
| 2 | +import Work from 'core/models/work' | |
| 3 | +import { actions as canvasActions, mutations as canvasMutations } from './canvas' | |
| 4 | +import { actions as pageActions, mutations as pageMutations } from './page' | |
| 5 | +import { actions as elementActions, mutations as elementMutations } from './element' | |
| 6 | +import { actions as workActions, mutations as workMutations } from './work' | |
| 7 | + | |
| 8 | +const state = { | |
| 9 | + works: [], | |
| 10 | + work: new Work(), | |
| 11 | + editingPage: { elements: [] }, | |
| 12 | + editingElement: null, | |
| 13 | + formDetailOfWork: { | |
| 14 | + uuidMap2Name: {}, | |
| 15 | + formRecords: [] | |
| 16 | + }, | |
| 17 | + workTemplates: [], | |
| 18 | + scaleRate: 1 | |
| 19 | +} | |
| 20 | + | |
| 21 | +// getters | |
| 22 | +const getters = {} | |
| 23 | + | |
| 24 | +// actions | |
| 25 | +const actions = { | |
| 26 | + ...elementActions, | |
| 27 | + ...pageActions, | |
| 28 | + ...workActions, | |
| 29 | + ...canvasActions | |
| 30 | +} | |
| 31 | + | |
| 32 | +// mutations | |
| 33 | +const mutations = { | |
| 34 | + ...elementMutations, | |
| 35 | + ...pageMutations, | |
| 36 | + ...workMutations, | |
| 37 | + ...canvasMutations | |
| 38 | +} | |
| 39 | + | |
| 40 | +export default { | |
| 41 | + namespaced: true, | |
| 42 | + state, | |
| 43 | + getters, | |
| 44 | + actions, | |
| 45 | + mutations | |
| 46 | +} | ... | ... |
front-end/h5/src/store/modules/element.js renamed to front-end/h5/src/components/core/store/modules/element.js
| 1 | -import Element from '../../components/core/models/element' | |
| 2 | -import { swapZindex, getVM } from '../../utils/element' | |
| 1 | +import Element from 'core/models/element' | |
| 2 | +import { swapZindex, getVM } from '@/utils/element' | |
| 3 | 3 | |
| 4 | 4 | // actions |
| 5 | 5 | export const actions = { |
| 6 | 6 | setEditingElement ({ commit }, payload) { |
| 7 | 7 | commit('setEditingElement', payload) |
| 8 | - payload && window.getEditorApp.$emit('setEditingElement', payload) | |
| 8 | + payload && window.EditorApp.$emit('setEditingElement', payload) | |
| 9 | 9 | }, |
| 10 | 10 | setElementPosition ({ commit }, payload) { |
| 11 | 11 | commit('setElementCommonStyle', payload) | ... | ... |
front-end/h5/src/components/core/store/modules/i18n.js
0 → 100755
| 1 | +import { loadLanguageAsync } from '@/locales' | |
| 2 | + | |
| 3 | +const i18n = { | |
| 4 | + namespaced: true, | |
| 5 | + state: { | |
| 6 | + lang: 'zh-CN' | |
| 7 | + }, | |
| 8 | + mutations: { | |
| 9 | + SET_LANG: (state, lang) => { | |
| 10 | + state.lang = lang | |
| 11 | + } | |
| 12 | + }, | |
| 13 | + actions: { | |
| 14 | + // 设置界面语言 | |
| 15 | + SetLang ({ commit }, lang) { | |
| 16 | + return new Promise(resolve => { | |
| 17 | + commit('SET_LANG', lang) | |
| 18 | + loadLanguageAsync(lang) | |
| 19 | + resolve() | |
| 20 | + }) | |
| 21 | + } | |
| 22 | + } | |
| 23 | +} | |
| 24 | + | |
| 25 | +export default i18n | ... | ... |
front-end/h5/src/components/core/store/modules/loading.js
0 → 100644
| 1 | +/* | |
| 2 | + * @Author: ly525 | |
| 3 | + * @Date: 2019-11-24 18:51:58 | |
| 4 | + * @LastEditors: ly525 | |
| 5 | + * @LastEditTime: 2019-12-08 17:21:48 | |
| 6 | + * @FilePath: /luban-h5/front-end/h5/src/store/modules/loading.js | |
| 7 | + * @Github: https://github.com/ly525/luban-h5 | |
| 8 | + * @Description: loading module | |
| 9 | + * @Copyright 2018 - 2020 luban-h5. All Rights Reserved | |
| 10 | + */ | |
| 11 | +// initial state | |
| 12 | +const state = { | |
| 13 | + saveWork_loading: false, | |
| 14 | + previewWork_loading: false, | |
| 15 | + fetchWorks_loading: false, | |
| 16 | + setWorkAsTemplate_loading: false, | |
| 17 | + fetchWorkTemplates_loading: false, | |
| 18 | + useTemplate_loading: false, | |
| 19 | + uploadWorkCover_loading: false | |
| 20 | +} | |
| 21 | + | |
| 22 | +// getters | |
| 23 | +const getters = { | |
| 24 | + | |
| 25 | +} | |
| 26 | + | |
| 27 | +// actions | |
| 28 | +const actions = { | |
| 29 | + update ({ commit }, payload) { | |
| 30 | + commit('update', payload) | |
| 31 | + } | |
| 32 | +} | |
| 33 | + | |
| 34 | +// mutations | |
| 35 | +const mutations = { | |
| 36 | + update (state, { type, payload }) { | |
| 37 | + state[type] = payload | |
| 38 | + } | |
| 39 | +} | |
| 40 | + | |
| 41 | +export default { | |
| 42 | + namespaced: true, | |
| 43 | + state, | |
| 44 | + getters, | |
| 45 | + actions, | |
| 46 | + mutations | |
| 47 | +} | ... | ... |
front-end/h5/src/store/modules/page.js renamed to front-end/h5/src/components/core/store/modules/page.js
| ... | ... | @@ -2,15 +2,15 @@ |
| 2 | 2 | * @Author: ly525 |
| 3 | 3 | * @Date: 2019-12-08 17:05:09 |
| 4 | 4 | * @LastEditors: ly525 |
| 5 | - * @LastEditTime: 2019-12-15 15:41:56 | |
| 5 | + * @LastEditTime: 2020-10-10 23:34:28 | |
| 6 | 6 | * @FilePath: /luban-h5/front-end/h5/src/store/modules/page.js |
| 7 | 7 | * @Github: https://github.com/ly525/luban-h5 |
| 8 | 8 | * @Description: page module |
| 9 | - * @Copyright 2018 - 2019 luban-h5. All Rights Reserved | |
| 9 | + * @Copyright 2018 - 2020 luban-h5. All Rights Reserved | |
| 10 | 10 | */ |
| 11 | 11 | import { message } from 'ant-design-vue' |
| 12 | 12 | |
| 13 | -import Page from '../../components/core/models/page' | |
| 13 | +import Page from 'core/models/page' | |
| 14 | 14 | |
| 15 | 15 | // actions |
| 16 | 16 | export const actions = { |
| ... | ... | @@ -30,8 +30,8 @@ export const mutations = { |
| 30 | 30 | pageManager (state, { type, value }) { |
| 31 | 31 | switch (type) { |
| 32 | 32 | case 'editTitle': |
| 33 | - const { pageIndexForEditingTitle, newTitle } = value | |
| 34 | - state.work.pages[pageIndexForEditingTitle].title = newTitle | |
| 33 | + const { pageIndex, newTitle } = value | |
| 34 | + state.work.pages[pageIndex].title = newTitle | |
| 35 | 35 | break |
| 36 | 36 | case 'add': |
| 37 | 37 | const page = new Page(value) | ... | ... |
front-end/h5/src/store/modules/visible.js renamed to front-end/h5/src/components/core/store/modules/user.js
front-end/h5/src/components/core/store/modules/work.js
0 → 100644
| 1 | +import Element from 'core/models/element' | |
| 2 | +import strapi from '@/utils/strapi' | |
| 3 | +import Page from 'core/models/page' | |
| 4 | +import Work from 'core/models/work' | |
| 5 | +import { AxiosWrapper } from '@/utils/http.js' | |
| 6 | +// import router from '@/router.js' | |
| 7 | +import { takeScreenshot } from '@/utils/canvas-helper.js' | |
| 8 | + | |
| 9 | +function setLoading (commit, loadingName, isLoading) { | |
| 10 | + commit('loading/update', { type: loadingName, payload: isLoading }, { root: true }) | |
| 11 | +} | |
| 12 | + | |
| 13 | +export const actions = { | |
| 14 | + previewWork ({ commit }, payload = {}) { | |
| 15 | + commit('previewWork', payload) | |
| 16 | + }, | |
| 17 | + deployWork ({ commit }, payload = {}) { | |
| 18 | + commit('previewWork', payload) | |
| 19 | + }, | |
| 20 | + // createWork ({ commit }, payload) { | |
| 21 | + // strapi.createEntry('works', new Work()).then(entry => { | |
| 22 | + // const routeData = router.resolve({ name: 'editor', params: { workId: entry.id } }) | |
| 23 | + // window.open(routeData.href, '_blank') | |
| 24 | + // // 如果希望不打开新 tab,可以注释上面面两行,启用下面一行的代码即可,不过不推荐。将编辑器单独起一个页面更有利于 vuex 的数据管理 | |
| 25 | + // // router.replace({ name: 'editor', params: { workId: entry.id } }) | |
| 26 | + // }) | |
| 27 | + // }, | |
| 28 | + updateWork ({ commit, state }, payload = {}) { | |
| 29 | + // update work with strapi | |
| 30 | + const work = { | |
| 31 | + ...state.work, | |
| 32 | + ...payload | |
| 33 | + } | |
| 34 | + commit('setWork', work) | |
| 35 | + }, | |
| 36 | + /** | |
| 37 | + * isSaveCover {Boolean} 保存作品时,是否保存封面图 | |
| 38 | + * loadingName {String} saveWork_loading, previewWork_loading | |
| 39 | + * 预览作品之前需要先保存,但希望 用户点击保存按钮 和 点击预览按钮 loading_name 能够不同(虽然都调用了 saveWork) | |
| 40 | + * 因为 loading 效果要放在不同的按钮上 | |
| 41 | + */ | |
| 42 | + saveWork ({ commit, dispatch, state }, { isSaveCover = false, loadingName = 'saveWork_loading', successMsg = '保存作品成功' } = {}) { | |
| 43 | + const fn = (callback) => { | |
| 44 | + new AxiosWrapper({ | |
| 45 | + dispatch, | |
| 46 | + commit, | |
| 47 | + loading_name: loadingName, | |
| 48 | + successMsg, | |
| 49 | + customRequest: strapi.updateEntry.bind(strapi) | |
| 50 | + }).put('works', state.work.id, state.work).then(callback) | |
| 51 | + } | |
| 52 | + return new Promise((resolve, reject) => { | |
| 53 | + if (isSaveCover) { | |
| 54 | + setLoading(commit, 'uploadWorkCover_loading', true) | |
| 55 | + takeScreenshot().then(file => { | |
| 56 | + dispatch('uploadCover', { file }).then(() => { | |
| 57 | + setLoading(commit, 'uploadWorkCover_loading', false) | |
| 58 | + fn(resolve) | |
| 59 | + }) // uploadCover | |
| 60 | + }) // takeScreenshot | |
| 61 | + } else { | |
| 62 | + fn(resolve) | |
| 63 | + } | |
| 64 | + }) | |
| 65 | + }, | |
| 66 | + fetchWork ({ commit, state }, workId) { | |
| 67 | + return strapi.getEntry('works', workId).then(entry => { | |
| 68 | + commit('setWork', entry) | |
| 69 | + commit('setEditingPage') | |
| 70 | + }) | |
| 71 | + }, | |
| 72 | + fetchWorks ({ commit, dispatch, state }, workId) { | |
| 73 | + new AxiosWrapper({ | |
| 74 | + dispatch, | |
| 75 | + commit, | |
| 76 | + name: 'editor/setWorks', | |
| 77 | + loading_name: 'fetchWorks_loading', | |
| 78 | + successMsg: '获取作品列表成功', | |
| 79 | + customRequest: strapi.getEntries.bind(strapi) | |
| 80 | + }).get('works', { is_template: false }) | |
| 81 | + }, | |
| 82 | + fetchWorksWithForms ({ commit, dispatch, state }, workId) { | |
| 83 | + new AxiosWrapper({ | |
| 84 | + dispatch, | |
| 85 | + commit, | |
| 86 | + name: 'editor/setWorks', | |
| 87 | + loading_name: 'fetchWorks_loading', | |
| 88 | + successMsg: '获取作品列表成功', | |
| 89 | + customRequest: strapi.getEntries.bind(strapi) | |
| 90 | + }).get('works/has-forms', { is_template: false }) | |
| 91 | + }, | |
| 92 | + fetchWorkTemplates ({ commit, dispatch, state }, workId) { | |
| 93 | + new AxiosWrapper({ | |
| 94 | + dispatch, | |
| 95 | + commit, | |
| 96 | + name: 'editor/setWorkTemplates', | |
| 97 | + loading_name: 'fetchWorkTemplates_loading', | |
| 98 | + successMsg: '获取模板列表成功', | |
| 99 | + customRequest: strapi.getEntries.bind(strapi) | |
| 100 | + }).get('works', { is_template: true }) | |
| 101 | + }, | |
| 102 | + /** | |
| 103 | + * | |
| 104 | + * @param {*} workId | |
| 105 | + * response demo: | |
| 106 | + { | |
| 107 | + "uuidMap2Name": { | |
| 108 | + "1565596393441": "姓名", | |
| 109 | + "1565596397671": "学校" | |
| 110 | + }, | |
| 111 | + "formRecords": [ | |
| 112 | + { | |
| 113 | + "id": 3, | |
| 114 | + "form": { | |
| 115 | + "1565369322603": "abc" | |
| 116 | + }, | |
| 117 | + "work": 8, | |
| 118 | + "created_at": "2019-08-09T16:52:28.826Z", | |
| 119 | + "updated_at": "2019-08-09T16:52:28.832Z" | |
| 120 | + }, | |
| 121 | + { | |
| 122 | + "id": 4, | |
| 123 | + "form": { | |
| 124 | + "1565595388440": "ddd" | |
| 125 | + }, | |
| 126 | + "work": 8, | |
| 127 | + "created_at": "2019-08-11T07:36:54.521Z", | |
| 128 | + "updated_at": "2019-08-11T07:36:54.526Z" | |
| 129 | + }, | |
| 130 | + { | |
| 131 | + "id": 5, | |
| 132 | + "form": { | |
| 133 | + "1565595388440": "acd" | |
| 134 | + }, | |
| 135 | + "work": 8, | |
| 136 | + "created_at": "2019-08-11T07:45:22.000Z", | |
| 137 | + "updated_at": "2019-08-11T07:45:22.005Z" | |
| 138 | + }, | |
| 139 | + { | |
| 140 | + "id": 6, | |
| 141 | + "form": { | |
| 142 | + "1565596393441": "b", | |
| 143 | + "1565596397671": "a" | |
| 144 | + }, | |
| 145 | + "work": 8, | |
| 146 | + "created_at": "2019-08-11T07:59:00.938Z", | |
| 147 | + "updated_at": "2019-08-11T07:59:00.943Z" | |
| 148 | + }, | |
| 149 | + { | |
| 150 | + "id": 7, | |
| 151 | + "form": { | |
| 152 | + "1565596393441": "b", | |
| 153 | + "1565596397671": "a" | |
| 154 | + }, | |
| 155 | + "work": 8, | |
| 156 | + "created_at": "2019-08-11T07:59:37.065Z", | |
| 157 | + "updated_at": "2019-08-11T07:59:37.070Z" | |
| 158 | + } | |
| 159 | + ] | |
| 160 | + } | |
| 161 | + */ | |
| 162 | + fetchFormsOfWork ({ commit, state, dispatch }, workId) { | |
| 163 | + // 可以 return Promise | |
| 164 | + new AxiosWrapper({ | |
| 165 | + dispatch, | |
| 166 | + commit, | |
| 167 | + name: 'editor/formDetailOfWork', | |
| 168 | + loading_name: 'queryFormsOfWork_loading', | |
| 169 | + successMsg: '表单查询完毕' | |
| 170 | + }).get(`/works/form/query/${workId}`) | |
| 171 | + }, | |
| 172 | + setWorkAsTemplate ({ commit, state, dispatch }, workId) { | |
| 173 | + new AxiosWrapper({ | |
| 174 | + dispatch, | |
| 175 | + commit, | |
| 176 | + // name: 'editor/formDetailOfWork', | |
| 177 | + loading_name: 'setWorkAsTemplate_loading', | |
| 178 | + successMsg: '设置为模板成功' | |
| 179 | + }).post(`/works/set-as-template/${workId || state.work.id}`) | |
| 180 | + }, | |
| 181 | + useTemplate ({ commit, state, dispatch }, workId) { | |
| 182 | + return new AxiosWrapper({ | |
| 183 | + dispatch, | |
| 184 | + commit, | |
| 185 | + // name: 'editor/formDetailOfWork', | |
| 186 | + loading_name: 'useTemplate_loading', | |
| 187 | + successMsg: '使用模板成功' | |
| 188 | + }).post(`/works/use-template/${workId}`) | |
| 189 | + }, | |
| 190 | + uploadCover ({ commit, state, dispatch }, { file } = {}) { | |
| 191 | + const formData = new FormData() | |
| 192 | + formData.append('files', file, `${+new Date()}.png`) | |
| 193 | + formData.append('workId', state.work.id) | |
| 194 | + return new AxiosWrapper({ | |
| 195 | + dispatch, | |
| 196 | + commit, | |
| 197 | + name: 'editor/setWorkCover', | |
| 198 | + loading_name: 'uploadWorkCover_loading', | |
| 199 | + successMsg: '上传封面图成功!' | |
| 200 | + // }).post(`/works/uploadCover/${state.work.id}`, formData) | |
| 201 | + }).post(`/upload/`, formData) | |
| 202 | + } | |
| 203 | +} | |
| 204 | + | |
| 205 | +// mutations | |
| 206 | +export const mutations = { | |
| 207 | + /** | |
| 208 | + * | |
| 209 | + * @param {*} state | |
| 210 | + * @param {Object} payload | |
| 211 | + * | |
| 212 | + value example: [ | |
| 213 | + { | |
| 214 | + "id": 1, | |
| 215 | + "name": "1567769149231.png", | |
| 216 | + "hash": "1660b11229e7473b90f99a9f9afe7675", | |
| 217 | + "sha256": "lKl7f_csUAgOjf0VRYkBZ64EcTjvt4Dt4beNIhELpTU", | |
| 218 | + "ext": ".png", | |
| 219 | + "mime": "image/png", | |
| 220 | + "size": "6.57", | |
| 221 | + "url": "/uploads/1660b11229e7473b90f99a9f9afe7675.png", | |
| 222 | + "provider": "local", | |
| 223 | + "public_id": null, | |
| 224 | + "created_at": "2019-09-06T11:25:49.255Z", | |
| 225 | + "updated_at": "2019-09-06T11:25:49.261Z", | |
| 226 | + "related": [] | |
| 227 | + } | |
| 228 | + ] | |
| 229 | + */ | |
| 230 | + setWorkCover (state, { type, value }) { | |
| 231 | + const [cover] = value | |
| 232 | + state.work.cover_image_url = cover.url | |
| 233 | + }, | |
| 234 | + /** | |
| 235 | + * payload: { | |
| 236 | + * type: @params {String} "editor/setWorks", | |
| 237 | + * value: @params {Array} work list | |
| 238 | + * } | |
| 239 | + */ | |
| 240 | + setWorks (state, { type, value }) { | |
| 241 | + value.sort((a, b) => b.id - a.id) | |
| 242 | + state.works = value | |
| 243 | + }, | |
| 244 | + /** | |
| 245 | + * payload: { | |
| 246 | + * type: @params {String} "editor/setWorks", | |
| 247 | + * value: @params {Array} work list | |
| 248 | + * } | |
| 249 | + */ | |
| 250 | + setWorkTemplates (state, { type, value }) { | |
| 251 | + value.sort((a, b) => b.id - a.id) | |
| 252 | + state.workTemplates = value | |
| 253 | + }, | |
| 254 | + setWork (state, work) { | |
| 255 | + window.__work = work | |
| 256 | + work.pages = work.pages.map(page => { | |
| 257 | + page.elements = page.elements.map(element => new Element(element)) | |
| 258 | + return new Page(page) | |
| 259 | + }) | |
| 260 | + state.work = new Work(work) | |
| 261 | + }, | |
| 262 | + previewWork (state, { type, value }) {}, | |
| 263 | + deployWork (state, { type, value }) {}, | |
| 264 | + formDetailOfWork (state, { type, value }) { | |
| 265 | + state.formDetailOfWork = value | |
| 266 | + } | |
| 267 | +} | ... | ... |
front-end/h5/src/store/plugins/undo-redo/History.js renamed to front-end/h5/src/components/core/store/plugins/undo-redo/History.js
front-end/h5/src/store/plugins/undo-redo/index.js renamed to front-end/h5/src/components/core/store/plugins/undo-redo/index.js
front-end/h5/src/components/core/styles/index.scss
| ... | ... | @@ -6,52 +6,6 @@ |
| 6 | 6 | @import url("./page-manager.scss"); |
| 7 | 7 | @import url("./canvas-wrapper.scss"); |
| 8 | 8 | |
| 9 | -#luban-editor-layout, | |
| 10 | -#luban-work-manager-layout { | |
| 11 | - .header { | |
| 12 | - padding: 0 10px; | |
| 13 | - | |
| 14 | - .logo { | |
| 15 | - width: 120px; | |
| 16 | - height: 31px; | |
| 17 | - // background: rgba(255,255,255,.2); | |
| 18 | - margin: 16px 28px 16px 0; | |
| 19 | - float: left; | |
| 20 | - | |
| 21 | - line-height: 31px; | |
| 22 | - text-align: center; | |
| 23 | - color: white; | |
| 24 | - font-size: 16px; | |
| 25 | - } | |
| 26 | - | |
| 27 | - .lang-select-activator, | |
| 28 | - .user-avatar-activator { | |
| 29 | - float: right; | |
| 30 | - background: transparent; | |
| 31 | - margin: 0 28px 16px 0; | |
| 32 | - cursor: pointer; | |
| 33 | - | |
| 34 | - .anticon { | |
| 35 | - color: white; | |
| 36 | - } | |
| 37 | - } | |
| 38 | - } | |
| 39 | - | |
| 40 | - #props-edit-form { | |
| 41 | - .ant-form-item { | |
| 42 | - margin-bottom: 12px; | |
| 43 | - } | |
| 44 | - } | |
| 45 | - | |
| 46 | - .card-cover-wrapper { | |
| 47 | - position: relative; | |
| 48 | - height: 300px; | |
| 49 | - border: 1px dashed #eee; | |
| 50 | - color: #aaa; | |
| 51 | - padding: 4px; | |
| 52 | - } | |
| 53 | -} | |
| 54 | - | |
| 55 | 9 | .hidden { |
| 56 | 10 | display: none !important; |
| 57 | 11 | } |
| ... | ... | @@ -84,7 +38,7 @@ |
| 84 | 38 | } |
| 85 | 39 | |
| 86 | 40 | // 动画编辑面板定制 |
| 87 | -#animation-edit-panel { | |
| 41 | +#animation-right-panel { | |
| 88 | 42 | .ant-collapse-header { |
| 89 | 43 | padding: 6px 0 6px 40px; |
| 90 | 44 | } |
| ... | ... | @@ -180,7 +134,7 @@ $activeHoverColor: #1593ff; |
| 180 | 134 | |
| 181 | 135 | .adjust-line-wrapper-v { |
| 182 | 136 | position: relative; |
| 183 | - height: 100%; | |
| 137 | + height: 100vh; | |
| 184 | 138 | cursor: ew-resize; |
| 185 | 139 | |
| 186 | 140 | .adjust-button { | ... | ... |
front-end/h5/src/components/core/styles/props-config-panel.scss
0 → 100644
front-end/h5/src/components/core/support/excel.js
front-end/h5/src/components/core/support/image-gallery/tabs/personal.js
| ... | ... | @@ -2,8 +2,8 @@ |
| 2 | 2 | * https://github.com/ly525/luban-h5/issues/138 |
| 3 | 3 | */ |
| 4 | 4 | import axios from 'axios' |
| 5 | -import ImageItem from '../components/image-item.js' | |
| 6 | -import Uploader from '../components/uploader.js' | |
| 5 | +import ImageItem from 'core/support/image-gallery/components/image-item.js' | |
| 6 | +import Uploader from 'core/support/image-gallery/components/uploader.js' | |
| 7 | 7 | |
| 8 | 8 | export default { |
| 9 | 9 | data: () => ({ | ... | ... |