Commit 6e23b00197fca18fe5a5f9a7903b267369c4ea1b

Authored by ly525
1 parent 78b882b3

feat: refactor core-editor as npm package: @luban-h5/core-editor

Too many changes to show.

To preserve performance only 15 of 21 files are displayed.

front-end/h5/package.json
@@ -11,7 +11,8 @@ @@ -11,7 +11,8 @@
11 "test:e2e": "vue-cli-service test:e2e", 11 "test:e2e": "vue-cli-service test:e2e",
12 "test:unit": "vue-cli-service test:unit", 12 "test:unit": "vue-cli-service test:unit",
13 "build:editor": "cross-env PAGE=EDITOR vue-cli-service build", 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 "dependencies": { 17 "dependencies": {
17 "@luban-h5/lbc-button": "^0.0.3", 18 "@luban-h5/lbc-button": "^0.0.3",
front-end/h5/src/components/core/editor/fixed-tools/index.js
  1 +import { mapActions } from 'vuex'
1 import hotkeys from 'hotkeys-js' 2 import hotkeys from 'hotkeys-js'
2 import fixedTools from './options' 3 import fixedTools from './options'
3 4
4 export default { 5 export default {
  6 + methods: {
  7 + ...mapActions('editor', ['pageManager'])
  8 + },
5 render () { 9 render () {
6 return ( 10 return (
7 <a-layout-sider 11 <a-layout-sider
front-end/h5/src/components/core/editor/fixed-tools/options.js
1 -import undoRedoHistory from '@/store/plugins/undo-redo/History' 1 +import undoRedoHistory from 'core/store/plugins/undo-redo/History'
2 2
3 const fixedTools = [ 3 const fixedTools = [
4 { 4 {
front-end/h5/src/components/core/index.js
@@ -15,9 +15,20 @@ import Header from &#39;@/components/common/header/index&#39; @@ -15,9 +15,20 @@ import Header from &#39;@/components/common/header/index&#39;
15 import Feedback from '@/components/common/feedback/index' 15 import Feedback from '@/components/common/feedback/index'
16 import AdjustLineV from 'core/support/adjust-line/vertical' 16 import AdjustLineV from 'core/support/adjust-line/vertical'
17 17
  18 +import store from 'core/store/index'
  19 +import i18n from '@/locales'
  20 +import '@/plugins/index'
  21 +
18 window.EditorApp = new Vue() // event bus 22 window.EditorApp = new Vue() // event bus
19 -export default {  
20 - name: 'Editor', 23 +const CoreEditor = {
  24 + name: 'CoreEditor',
  25 + store,
  26 + i18n,
  27 + props: {
  28 + workId: {
  29 + type: [Number, String]
  30 + }
  31 + },
21 data: () => ({ 32 data: () => ({
22 previewDialogVisible: false, 33 previewDialogVisible: false,
23 propsPanelWidth: 320 34 propsPanelWidth: 320
@@ -56,11 +67,22 @@ export default { @@ -56,11 +67,22 @@ export default {
56 ) 67 )
57 }, 68 },
58 created () { 69 created () {
59 - let workId = this.$route.params.workId  
60 - if (workId) {  
61 - this.fetchWork(workId) 70 + if (this.workId) {
  71 + this.fetchWork(this.workId)
62 } else { 72 } else {
63 this.$message.error('no work id!') 73 this.$message.error('no work id!')
64 } 74 }
65 } 75 }
66 } 76 }
  77 +
  78 +// Vue install, Vue.use 会调用该方法。
  79 +CoreEditor.install = (Vue, opts = {}) => {
  80 + Vue.component(CoreEditor.name, CoreEditor)
  81 +}
  82 +
  83 +// 通过script标签引入Vue的环境
  84 +if (typeof window !== 'undefined' && window.Vue) {
  85 + CoreEditor.install(window.Vue)
  86 +}
  87 +
  88 +export default CoreEditor
front-end/h5/src/components/core/package.json 0 → 100644
  1 +{
  2 + "name": "@luban-h5/core-editor",
  3 + "private": false,
  4 + "version": "0.0.2",
  5 + "description": "luban-h5 core-editor",
  6 + "main": "dist/core-editor.umd.min.js",
  7 + "author": "ly525",
  8 + "license": "GPL-3.0"
  9 +}
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/editor.js 0 → 100644
  1 +// initial state
  2 +import Work from 'core/models/work'
  3 +import { actions as pageActions, mutations as pageMutations } from './page'
  4 +import { actions as elementActions, mutations as elementMutations } from './element'
  5 +import { actions as workActions, mutations as workMutations } from './work'
  6 +
  7 +const state = {
  8 + works: [],
  9 + work: new Work(),
  10 + editingPage: { elements: [] },
  11 + editingElement: null,
  12 + formDetailOfWork: {
  13 + uuidMap2Name: {},
  14 + formRecords: []
  15 + },
  16 + workTemplates: []
  17 +}
  18 +
  19 +// getters
  20 +const getters = {}
  21 +
  22 +// actions
  23 +const actions = {
  24 + ...elementActions,
  25 + ...pageActions,
  26 + ...workActions
  27 +}
  28 +
  29 +// mutations
  30 +const mutations = {
  31 + ...elementMutations,
  32 + ...pageMutations,
  33 + ...workMutations
  34 +}
  35 +
  36 +export default {
  37 + namespaced: true,
  38 + state,
  39 + getters,
  40 + actions,
  41 + mutations
  42 +}
front-end/h5/src/store/modules/element.js renamed to front-end/h5/src/components/core/store/modules/element.js
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
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