Commit 6e23b00197fca18fe5a5f9a7903b267369c4ea1b
1 parent
78b882b3
feat: refactor core-editor as npm package: @luban-h5/core-editor
Showing
15 changed files
with
462 additions
and
7 deletions
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 | 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/src/components/core/editor/fixed-tools/index.js
front-end/h5/src/components/core/editor/fixed-tools/options.js
front-end/h5/src/components/core/index.js
| ... | ... | @@ -15,9 +15,20 @@ import Header from '@/components/common/header/index' |
| 15 | 15 | import Feedback from '@/components/common/feedback/index' |
| 16 | 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 | 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 | 32 | data: () => ({ |
| 22 | 33 | previewDialogVisible: false, |
| 23 | 34 | propsPanelWidth: 320 |
| ... | ... | @@ -56,11 +67,22 @@ export default { |
| 56 | 67 | ) |
| 57 | 68 | }, |
| 58 | 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 | 72 | } else { |
| 63 | 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
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