Commit bc747db80900204f58827a0f577d801a912e339e
1 parent
d6787783
feat: set up cover when saving work
Showing
7 changed files
with
118 additions
and
27 deletions
front-end/h5/package.json
| @@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
| 15 | "core-js": "^2.6.5", | 15 | "core-js": "^2.6.5", |
| 16 | "element-ui": "^2.9.1", | 16 | "element-ui": "^2.9.1", |
| 17 | "font-awesome": "4.7.0", | 17 | "font-awesome": "4.7.0", |
| 18 | + "html2canvas": "^1.0.0-rc.3", | ||
| 18 | "node-sass": "^4.12.0", | 19 | "node-sass": "^4.12.0", |
| 19 | "proxy-agent": "^3.1.0", | 20 | "proxy-agent": "^3.1.0", |
| 20 | "qrcode": "^1.4.1", | 21 | "qrcode": "^1.4.1", |
front-end/h5/src/components/core/editor/index.js
| @@ -99,10 +99,7 @@ export default { | @@ -99,10 +99,7 @@ export default { | ||
| 99 | pages: state => state.work.pages, | 99 | pages: state => state.work.pages, |
| 100 | work: state => state.work | 100 | work: state => state.work |
| 101 | }), | 101 | }), |
| 102 | - ...mapState('loading', { | ||
| 103 | - saveWork_loading: state => state.saveWork_loading, | ||
| 104 | - setWorkAsTemplate_loading: state => state.setWorkAsTemplate_loading | ||
| 105 | - }) | 102 | + ...mapState('loading', ['saveWork_loading', 'setWorkAsTemplate_loading', 'uploadWorkCover_loading']) |
| 106 | }, | 103 | }, |
| 107 | methods: { | 104 | methods: { |
| 108 | ...mapActions('editor', [ | 105 | ...mapActions('editor', [ |
| @@ -170,7 +167,7 @@ export default { | @@ -170,7 +167,7 @@ export default { | ||
| 170 | style={{ lineHeight: '64px', float: 'right', background: 'transparent' }} | 167 | style={{ lineHeight: '64px', float: 'right', background: 'transparent' }} |
| 171 | > | 168 | > |
| 172 | <a-menu-item key="1" class="transparent-bg"><a-button type="primary" size="small" onClick={() => { this.previewVisible = true }}>预览</a-button></a-menu-item> | 169 | <a-menu-item key="1" class="transparent-bg"><a-button type="primary" size="small" onClick={() => { this.previewVisible = true }}>预览</a-button></a-menu-item> |
| 173 | - <a-menu-item key="2" class="transparent-bg"><a-button size="small" onClick={() => this.saveWork()} loading={this.saveWork_loading}>保存</a-button></a-menu-item> | 170 | + <a-menu-item key="2" class="transparent-bg"><a-button size="small" onClick={() => this.saveWork({ isSaveCover: true })} loading={this.saveWork_loading || this.uploadWorkCover_loading}>保存</a-button></a-menu-item> |
| 174 | {/* <a-menu-item key="3" class="transparent-bg"><a-button size="small">发布</a-button></a-menu-item> */} | 171 | {/* <a-menu-item key="3" class="transparent-bg"><a-button size="small">发布</a-button></a-menu-item> */} |
| 175 | <a-menu-item key="3" class="transparent-bg"> | 172 | <a-menu-item key="3" class="transparent-bg"> |
| 176 | <a-dropdown-button onClick={() => {}} size="small"> | 173 | <a-dropdown-button onClick={() => {}} size="small"> |
front-end/h5/src/store/modules/loading.js
| @@ -4,7 +4,8 @@ const state = { | @@ -4,7 +4,8 @@ const state = { | ||
| 4 | fetchWorks_loading: false, | 4 | fetchWorks_loading: false, |
| 5 | setWorkAsTemplate_loading: false, | 5 | setWorkAsTemplate_loading: false, |
| 6 | fetchWorkTemplates_loading: false, | 6 | fetchWorkTemplates_loading: false, |
| 7 | - useTemplate_loading: false | 7 | + useTemplate_loading: false, |
| 8 | + uploadWorkCover_loading: false | ||
| 8 | } | 9 | } |
| 9 | 10 | ||
| 10 | // getters | 11 | // getters |
front-end/h5/src/store/modules/work.js
| @@ -4,6 +4,7 @@ import Page from '../../components/core/models/page' | @@ -4,6 +4,7 @@ import Page from '../../components/core/models/page' | ||
| 4 | import Work from '../../components/core/models/work' | 4 | import Work from '../../components/core/models/work' |
| 5 | import { AxiosWrapper } from '../../utils/http.js' | 5 | import { AxiosWrapper } from '../../utils/http.js' |
| 6 | import router from '@/router.js' | 6 | import router from '@/router.js' |
| 7 | +import { takeScreenshot } from '../../utils/helper.js' | ||
| 7 | 8 | ||
| 8 | export const actions = { | 9 | export const actions = { |
| 9 | previewWork ({ commit }, payload = {}) { | 10 | previewWork ({ commit }, payload = {}) { |
| @@ -30,20 +31,30 @@ export const actions = { | @@ -30,20 +31,30 @@ export const actions = { | ||
| 30 | } | 31 | } |
| 31 | commit('setWork', work) | 32 | commit('setWork', work) |
| 32 | }, | 33 | }, |
| 33 | - saveWork ({ commit, dispatch, state }, payload = {}) { | ||
| 34 | - // update work with strapi | ||
| 35 | - const work = { | ||
| 36 | - ...state.work, | ||
| 37 | - ...payload | 34 | + /** |
| 35 | + * isSaveCover {Boolean} 保存作品时,是否保存封面图 | ||
| 36 | + */ | ||
| 37 | + saveWork ({ commit, dispatch, state }, { isSaveCover = false } = {}) { | ||
| 38 | + const fn = (callback) => { | ||
| 39 | + new AxiosWrapper({ | ||
| 40 | + dispatch, | ||
| 41 | + commit, | ||
| 42 | + loading_name: 'saveWork_loading', | ||
| 43 | + successMsg: '保存作品成功', | ||
| 44 | + customRequest: strapi.updateEntry.bind(strapi) | ||
| 45 | + }).put('works', state.work.id, state.work).then(callback) | ||
| 38 | } | 46 | } |
| 39 | - | ||
| 40 | - return new AxiosWrapper({ | ||
| 41 | - dispatch, | ||
| 42 | - commit, | ||
| 43 | - loading_name: 'saveWork_loading', | ||
| 44 | - successMsg: '保存作品成功', | ||
| 45 | - customRequest: strapi.updateEntry.bind(strapi) | ||
| 46 | - }).put('works', state.work.id, work) | 47 | + return new Promise((resolve, reject) => { |
| 48 | + if (isSaveCover) { | ||
| 49 | + takeScreenshot().then(file => { | ||
| 50 | + dispatch('uploadCover', { file }).then(() => { | ||
| 51 | + fn(resolve) | ||
| 52 | + }) // uploadCover | ||
| 53 | + }) // takeScreenshot | ||
| 54 | + } else { | ||
| 55 | + fn(resolve) | ||
| 56 | + } | ||
| 57 | + }) | ||
| 47 | }, | 58 | }, |
| 48 | fetchWork ({ commit, state }, workId) { | 59 | fetchWork ({ commit, state }, workId) { |
| 49 | strapi.getEntry('works', workId).then(entry => { | 60 | strapi.getEntry('works', workId).then(entry => { |
| @@ -158,12 +169,52 @@ export const actions = { | @@ -158,12 +169,52 @@ export const actions = { | ||
| 158 | loading_name: 'useTemplate_loading', | 169 | loading_name: 'useTemplate_loading', |
| 159 | successMsg: '使用模板成功' | 170 | successMsg: '使用模板成功' |
| 160 | }).post(`/works/use-template/${workId}`) | 171 | }).post(`/works/use-template/${workId}`) |
| 172 | + }, | ||
| 173 | + uploadCover ({ commit, state, dispatch }, { file } = {}) { | ||
| 174 | + const formData = new FormData() | ||
| 175 | + formData.append('files', file, `${+new Date()}.png`) | ||
| 176 | + formData.append('workId', state.work.id) | ||
| 177 | + return new AxiosWrapper({ | ||
| 178 | + dispatch, | ||
| 179 | + commit, | ||
| 180 | + name: 'editor/setWorkCover', | ||
| 181 | + loading_name: 'uploadWorkCover_loading', | ||
| 182 | + successMsg: '上传封面图成功!' | ||
| 183 | + // }).post(`/works/uploadCover/${state.work.id}`, formData) | ||
| 184 | + }).post(`/upload/`, formData) | ||
| 161 | } | 185 | } |
| 162 | } | 186 | } |
| 163 | 187 | ||
| 164 | // mutations | 188 | // mutations |
| 165 | export const mutations = { | 189 | export const mutations = { |
| 166 | /** | 190 | /** |
| 191 | + * | ||
| 192 | + * @param {*} state | ||
| 193 | + * @param {Object} payload | ||
| 194 | + * | ||
| 195 | + value example: [ | ||
| 196 | + { | ||
| 197 | + "id": 1, | ||
| 198 | + "name": "1567769149231.png", | ||
| 199 | + "hash": "1660b11229e7473b90f99a9f9afe7675", | ||
| 200 | + "sha256": "lKl7f_csUAgOjf0VRYkBZ64EcTjvt4Dt4beNIhELpTU", | ||
| 201 | + "ext": ".png", | ||
| 202 | + "mime": "image/png", | ||
| 203 | + "size": "6.57", | ||
| 204 | + "url": "/uploads/1660b11229e7473b90f99a9f9afe7675.png", | ||
| 205 | + "provider": "local", | ||
| 206 | + "public_id": null, | ||
| 207 | + "created_at": "2019-09-06T11:25:49.255Z", | ||
| 208 | + "updated_at": "2019-09-06T11:25:49.261Z", | ||
| 209 | + "related": [] | ||
| 210 | + } | ||
| 211 | + ] | ||
| 212 | + */ | ||
| 213 | + setWorkCover (state, { type, value }) { | ||
| 214 | + const [cover] = value | ||
| 215 | + state.work.cover_image_url = cover.url | ||
| 216 | + }, | ||
| 217 | + /** | ||
| 167 | * payload: { | 218 | * payload: { |
| 168 | * type: @params {String} "editor/setWorks", | 219 | * type: @params {String} "editor/setWorks", |
| 169 | * value: @params {Array} work list | 220 | * value: @params {Array} work list |
front-end/h5/src/utils/helper.js
0 → 100644
| 1 | +import html2canvas from 'html2canvas' | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * 生成作品封面图(截图) | ||
| 5 | + * @param {String} selector | ||
| 6 | + * @param {文件名} fileName | ||
| 7 | + */ | ||
| 8 | +export function takeScreenshot (selector = '.canvas-wrapper', fileName = `${+new Date()}`) { | ||
| 9 | + const el = document.querySelector(selector) | ||
| 10 | + return new Promise((resolve, reject) => { | ||
| 11 | + // html2canvas document: https://html2canvas.hertzen.com/configuration | ||
| 12 | + // allowTaint: Whether to allow cross-origin images to taint the canvas | ||
| 13 | + // if you use allowTaint: true, the cors image will taint the canvas, and canvas.toDataURL won't work | ||
| 14 | + // 会对canvas造成污染,导致 canvas.toDataURL 无效 | ||
| 15 | + html2canvas(el, { allowTaint: true }).then(canvas => { | ||
| 16 | + // document.body.appendChild(canvas) use this line to test the generated canvas | ||
| 17 | + canvas.toBlob(blob => { | ||
| 18 | + const file = new window.File([blob], fileName, { type: 'image/png' }) | ||
| 19 | + resolve(file) | ||
| 20 | + }) | ||
| 21 | + }) | ||
| 22 | + }) | ||
| 23 | +} |
front-end/h5/vue.config.js
| 1 | -// const ProxyAgent = require('proxy-agent') | ||
| 2 | const isProd = process.env.NODE_ENV === 'production' | 1 | const isProd = process.env.NODE_ENV === 'production' |
| 3 | - | ||
| 4 | -const PROD_API_ORIGIN = 'https://luban-h5-api.herokuapp.com' | ||
| 5 | -const DEV_API_ORIGIN = 'http://localhost:1337' | ||
| 6 | -// const DEV_API_ORIGIN = 'https://luban-h5-api.herokuapp.com' | ||
| 7 | - | 2 | +const target = 'http://localhost:1337' |
| 8 | module.exports = { | 3 | module.exports = { |
| 9 | runtimeCompiler: true, | 4 | runtimeCompiler: true, |
| 10 | // 因为需要部署到 github pages,所以需要将 publicPath 设为 "/< GitHub Repo Name>/" | 5 | // 因为需要部署到 github pages,所以需要将 publicPath 设为 "/< GitHub Repo Name>/" |
| @@ -14,8 +9,12 @@ module.exports = { | @@ -14,8 +9,12 @@ module.exports = { | ||
| 14 | // proxy: API_ORIGIN | 9 | // proxy: API_ORIGIN |
| 15 | proxy: { | 10 | proxy: { |
| 16 | '/works': { | 11 | '/works': { |
| 17 | - // agent: new ProxyAgent('socks5://127.0.0.1:1086'), | ||
| 18 | - target: isProd ? PROD_API_ORIGIN : DEV_API_ORIGIN, | 12 | + target, |
| 13 | + changeOrigin: true, | ||
| 14 | + ws: false | ||
| 15 | + }, | ||
| 16 | + '/upload': { | ||
| 17 | + target, | ||
| 19 | changeOrigin: true, | 18 | changeOrigin: true, |
| 20 | ws: false | 19 | ws: false |
| 21 | } | 20 | } |
front-end/h5/yarn.lock
| @@ -1974,6 +1974,11 @@ balanced-match@^1.0.0: | @@ -1974,6 +1974,11 @@ balanced-match@^1.0.0: | ||
| 1974 | resolved "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" | 1974 | resolved "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" |
| 1975 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= | 1975 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= |
| 1976 | 1976 | ||
| 1977 | +base64-arraybuffer@^0.2.0: | ||
| 1978 | + version "0.2.0" | ||
| 1979 | + resolved "https://registry.npm.taobao.org/base64-arraybuffer/download/base64-arraybuffer-0.2.0.tgz#4b944fac0191aa5907afe2d8c999ccc57ce80f45" | ||
| 1980 | + integrity sha1-S5RPrAGRqlkHr+LYyZnMxXzoD0U= | ||
| 1981 | + | ||
| 1977 | base64-js@^1.0.2: | 1982 | base64-js@^1.0.2: |
| 1978 | version "1.3.0" | 1983 | version "1.3.0" |
| 1979 | resolved "https://registry.npm.taobao.org/base64-js/download/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" | 1984 | resolved "https://registry.npm.taobao.org/base64-js/download/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" |
| @@ -3027,6 +3032,13 @@ css-declaration-sorter@^4.0.1: | @@ -3027,6 +3032,13 @@ css-declaration-sorter@^4.0.1: | ||
| 3027 | postcss "^7.0.1" | 3032 | postcss "^7.0.1" |
| 3028 | timsort "^0.3.0" | 3033 | timsort "^0.3.0" |
| 3029 | 3034 | ||
| 3035 | +css-line-break@1.1.1: | ||
| 3036 | + version "1.1.1" | ||
| 3037 | + resolved "https://registry.npm.taobao.org/css-line-break/download/css-line-break-1.1.1.tgz#d5e9bdd297840099eb0503c7310fd34927a026ef" | ||
| 3038 | + integrity sha1-1em90peEAJnrBQPHMQ/TSSegJu8= | ||
| 3039 | + dependencies: | ||
| 3040 | + base64-arraybuffer "^0.2.0" | ||
| 3041 | + | ||
| 3030 | css-loader@^1.0.1: | 3042 | css-loader@^1.0.1: |
| 3031 | version "1.0.1" | 3043 | version "1.0.1" |
| 3032 | resolved "https://registry.npm.taobao.org/css-loader/download/css-loader-1.0.1.tgz#6885bb5233b35ec47b006057da01cc640b6b79fe" | 3044 | resolved "https://registry.npm.taobao.org/css-loader/download/css-loader-1.0.1.tgz#6885bb5233b35ec47b006057da01cc640b6b79fe" |
| @@ -5286,6 +5298,13 @@ html-webpack-plugin@^3.2.0: | @@ -5286,6 +5298,13 @@ html-webpack-plugin@^3.2.0: | ||
| 5286 | toposort "^1.0.0" | 5298 | toposort "^1.0.0" |
| 5287 | util.promisify "1.0.0" | 5299 | util.promisify "1.0.0" |
| 5288 | 5300 | ||
| 5301 | +html2canvas@^1.0.0-rc.3: | ||
| 5302 | + version "1.0.0-rc.3" | ||
| 5303 | + resolved "https://registry.npm.taobao.org/html2canvas/download/html2canvas-1.0.0-rc.3.tgz#1de88b073f6bcaa6954ca1edfb46da13b258b038" | ||
| 5304 | + integrity sha1-HeiLBz9ryqaVTKHt+0baE7JYsDg= | ||
| 5305 | + dependencies: | ||
| 5306 | + css-line-break "1.1.1" | ||
| 5307 | + | ||
| 5289 | htmlparser2@^3.3.0: | 5308 | htmlparser2@^3.3.0: |
| 5290 | version "3.10.1" | 5309 | version "3.10.1" |
| 5291 | resolved "https://registry.npm.taobao.org/htmlparser2/download/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" | 5310 | resolved "https://registry.npm.taobao.org/htmlparser2/download/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" |