Commit 56b22e8b9b7cf9d38c652e7f92882c49262007d2
1 parent
656a956c
refactor: fetch works&work-templates; #!zh: 重构作品和模板列表
Showing
6 changed files
with
293 additions
and
346 deletions
front-end/h5/src/components/common/work/card-item.js
0 → 100644
| 1 | +import QRCode from 'qrcode' | ||
| 2 | +import CardCover from './card-cover' | ||
| 3 | + | ||
| 4 | +export default { | ||
| 5 | + props: { | ||
| 6 | + isTemplate: { | ||
| 7 | + type: Boolean, | ||
| 8 | + default: false | ||
| 9 | + }, | ||
| 10 | + work: { | ||
| 11 | + type: Object, | ||
| 12 | + default: () => ({}) | ||
| 13 | + } | ||
| 14 | + }, | ||
| 15 | + data: () => ({ | ||
| 16 | + qrcodeUrl: '' | ||
| 17 | + }), | ||
| 18 | + methods: { | ||
| 19 | + timeFmt (date) { | ||
| 20 | + const dateTime = new Date(date) | ||
| 21 | + const displayTime = `${dateTime.getFullYear()}-${dateTime.getMonth() + | ||
| 22 | + 1}-${dateTime.getDate()}` | ||
| 23 | + return displayTime | ||
| 24 | + }, | ||
| 25 | + genQRCodeUrl (work) { | ||
| 26 | + const url = `${window.location.origin}/works/preview/${work.id}` | ||
| 27 | + QRCode.toDataURL(url, (err, url) => { | ||
| 28 | + if (err) console.log(err) | ||
| 29 | + this.qrcodeUrl = url | ||
| 30 | + }) | ||
| 31 | + } | ||
| 32 | + }, | ||
| 33 | + render (h) { | ||
| 34 | + return ( | ||
| 35 | + <a-card hoverable> | ||
| 36 | + <CardCover | ||
| 37 | + slot="cover" | ||
| 38 | + qrcodeUrl={this.qrcodeUrl} | ||
| 39 | + coverImageUrl={this.work.cover_image_url} | ||
| 40 | + /> | ||
| 41 | + <template class="ant-card-actions" slot="actions"> | ||
| 42 | + { | ||
| 43 | + // 编辑 | ||
| 44 | + this.isTemplate | ||
| 45 | + ? <a-tooltip effect="dark" placement="bottom" title={this.$t('workCard.useNow')}> | ||
| 46 | + <a-icon | ||
| 47 | + type="plus-square" | ||
| 48 | + title={this.$t('workCard.useNow')} | ||
| 49 | + onClick={() => this.$emit('useTemplate', this.work)} | ||
| 50 | + /> | ||
| 51 | + </a-tooltip> | ||
| 52 | + : <a-tooltip effect="dark" placement="bottom" title={this.$t('workCard.edit')}> | ||
| 53 | + <router-link | ||
| 54 | + to={{ name: 'editor', params: { workId: this.work.id } }} | ||
| 55 | + target="_blank" | ||
| 56 | + > | ||
| 57 | + <a-icon type="edit" title={this.$t('workCard.edit')}/> | ||
| 58 | + </router-link> | ||
| 59 | + </a-tooltip> | ||
| 60 | + } | ||
| 61 | + {/** 预览 */} | ||
| 62 | + <a-tooltip effect="dark" placement="bottom" title={this.$t('workCard.preview')}> | ||
| 63 | + <a-icon type="eye" title={this.$t('workCard.preview')} onClick={() => this.$emit('preview')} /> | ||
| 64 | + </a-tooltip> | ||
| 65 | + <a-tooltip effect="dark" placement="bottom" title={this.$t('workCard.delete')}> | ||
| 66 | + <a-icon type="delete" title={this.$t('workCard.delete')} onClick={() => this.$emit('delete') } /> | ||
| 67 | + </a-tooltip> | ||
| 68 | + { | ||
| 69 | + this.qrcodeUrl | ||
| 70 | + ? <a-icon type="close-circle" onClick={() => { this.qrcodeUrl = '' }} /> | ||
| 71 | + : <a-icon type="qrcode" onClick={() => this.genQRCodeUrl(this.work)} /> | ||
| 72 | + } | ||
| 73 | + </template> | ||
| 74 | + <a-card-meta | ||
| 75 | + > | ||
| 76 | + <div slot="title" class="ant-card-meta-title" style="font-size: 14px;"> | ||
| 77 | + {this.work.title}({this.work.id}) | ||
| 78 | + </div> | ||
| 79 | + <div slot="description" style="font-size: 12px;"> | ||
| 80 | + {/** 描述 时间 */} | ||
| 81 | + <div>{this.$t('workCard.description')}: {this.work.description}</div> | ||
| 82 | + <div>{this.$t('workCard.createTime')}: {this.timeFmt(this.work.created_at)}</div> | ||
| 83 | + </div> | ||
| 84 | + </a-card-meta> | ||
| 85 | + </a-card> | ||
| 86 | + ) | ||
| 87 | + } | ||
| 88 | +} | ||
| 89 | + | ||
| 90 | +export const AddNewCard = { | ||
| 91 | + functional: true, | ||
| 92 | + render (h, { props, parent }) { | ||
| 93 | + return ( | ||
| 94 | + <a-card hoverable> | ||
| 95 | + <div slot="cover" class="flex-center" style="height: 405px;background: #f7f5f557;" onClick={props.handleCreate}> | ||
| 96 | + <a-icon type="plus" /> | ||
| 97 | + </div> | ||
| 98 | + <template class="ant-card-actions" slot="actions"> | ||
| 99 | + {/** 创建新作品 */} | ||
| 100 | + {/** https://kazupon.github.io/vue-i18n/guide/component.html#translation-in-functional-component */} | ||
| 101 | + <span onClick={props.handleCreate}>{parent.$t('workCard.createNewWork')}</span> | ||
| 102 | + </template> | ||
| 103 | + </a-card> | ||
| 104 | + ) | ||
| 105 | + } | ||
| 106 | +} |
front-end/h5/src/store/modules/work.js
| @@ -104,15 +104,15 @@ export const actions = { | @@ -104,15 +104,15 @@ export const actions = { | ||
| 104 | commit('setEditingPage') | 104 | commit('setEditingPage') |
| 105 | }) | 105 | }) |
| 106 | }, | 106 | }, |
| 107 | - fetchWorks ({ commit, dispatch, state }, workId) { | ||
| 108 | - new AxiosWrapper({ | 107 | + fetchWorks ({ commit, dispatch, state }, payload = { is_template: false, _limit: 10 }) { |
| 108 | + return new AxiosWrapper({ | ||
| 109 | dispatch, | 109 | dispatch, |
| 110 | commit, | 110 | commit, |
| 111 | name: 'editor/setWorks', | 111 | name: 'editor/setWorks', |
| 112 | loading_name: 'fetchWorks_loading', | 112 | loading_name: 'fetchWorks_loading', |
| 113 | successMsg: '获取作品列表成功', | 113 | successMsg: '获取作品列表成功', |
| 114 | customRequest: strapi.getEntries.bind(strapi) | 114 | customRequest: strapi.getEntries.bind(strapi) |
| 115 | - }).get('works', { is_template: false }).catch(handleError) | 115 | + }).get('works', payload).catch(handleError) |
| 116 | }, | 116 | }, |
| 117 | fetchWorksWithForms ({ commit, dispatch, state }, workId) { | 117 | fetchWorksWithForms ({ commit, dispatch, state }, workId) { |
| 118 | new AxiosWrapper({ | 118 | new AxiosWrapper({ |
| @@ -124,7 +124,7 @@ export const actions = { | @@ -124,7 +124,7 @@ export const actions = { | ||
| 124 | customRequest: strapi.getEntries.bind(strapi) | 124 | customRequest: strapi.getEntries.bind(strapi) |
| 125 | }).get('works/has-forms', { is_template: false }).catch(handleError) | 125 | }).get('works/has-forms', { is_template: false }).catch(handleError) |
| 126 | }, | 126 | }, |
| 127 | - fetchWorkTemplates ({ commit, dispatch, state }, workId) { | 127 | + fetchWorkTemplates ({ commit, dispatch, state }, payload = { is_template: true, _limit: 10 }) { |
| 128 | new AxiosWrapper({ | 128 | new AxiosWrapper({ |
| 129 | dispatch, | 129 | dispatch, |
| 130 | commit, | 130 | commit, |
| @@ -132,7 +132,7 @@ export const actions = { | @@ -132,7 +132,7 @@ export const actions = { | ||
| 132 | loading_name: 'fetchWorkTemplates_loading', | 132 | loading_name: 'fetchWorkTemplates_loading', |
| 133 | successMsg: '获取模板列表成功', | 133 | successMsg: '获取模板列表成功', |
| 134 | customRequest: strapi.getEntries.bind(strapi) | 134 | customRequest: strapi.getEntries.bind(strapi) |
| 135 | - }).get('works', { is_template: true }).catch(handleError) | 135 | + }).get('works', payload).catch(handleError) |
| 136 | }, | 136 | }, |
| 137 | /** | 137 | /** |
| 138 | * | 138 | * |
front-end/h5/src/views/work-manager/list-mixin.js
0 → 100644
| 1 | +import { mapState, mapActions } from 'vuex' | ||
| 2 | +import ListItemCard, { AddNewCard } from '@/components/common/work/card-item.js' | ||
| 3 | +import PreviewDialog from '@/components/core/editor/modals/preview.vue' | ||
| 4 | +import './list.scss' | ||
| 5 | + | ||
| 6 | +export default { | ||
| 7 | + components: { | ||
| 8 | + ListItemCard, | ||
| 9 | + AddNewCard | ||
| 10 | + }, | ||
| 11 | + props: { | ||
| 12 | + isTemplate: { | ||
| 13 | + type: Boolean, | ||
| 14 | + default: false | ||
| 15 | + } | ||
| 16 | + }, | ||
| 17 | + data: () => ({ | ||
| 18 | + activeWork: null, | ||
| 19 | + previewVisible: false, | ||
| 20 | + pagination: { | ||
| 21 | + pageSize: 10, | ||
| 22 | + pageNum: 1 | ||
| 23 | + } | ||
| 24 | + }), | ||
| 25 | + computed: { | ||
| 26 | + ...mapState('editor', ['works', 'workTemplates']), | ||
| 27 | + ...mapState('loading', ['fetchWorks_loading', 'fetchWorkTemplates_loading']), | ||
| 28 | + workList () { | ||
| 29 | + const workList = this.isTemplate ? this.workTemplates : this.works | ||
| 30 | + return workList.sort((a, b) => a.id - b.id) | ||
| 31 | + }, | ||
| 32 | + loading () { | ||
| 33 | + return this.isTemplate ? this.fetchWorkTemplates_loading : this.fetchWorks_loading | ||
| 34 | + } | ||
| 35 | + }, | ||
| 36 | + methods: { | ||
| 37 | + ...mapActions('editor', [ | ||
| 38 | + 'fetchWorks', | ||
| 39 | + 'createWork', | ||
| 40 | + 'deleteWork', | ||
| 41 | + 'useTemplate', | ||
| 42 | + 'fetchWorkTemplates' | ||
| 43 | + ]), | ||
| 44 | + handleDeleteWork (work) { | ||
| 45 | + this.deleteWork(work.id).then(res => { | ||
| 46 | + const index = this.workList.findIndex(item => item.id === work.id) | ||
| 47 | + this.workList.splice(index, 1) | ||
| 48 | + }) | ||
| 49 | + }, | ||
| 50 | + handleSearch () { | ||
| 51 | + const { pageSize, pageNum } = this.pagination | ||
| 52 | + const payload = { | ||
| 53 | + is_template: this.isTemplate, | ||
| 54 | + _limit: pageSize, | ||
| 55 | + _start: (pageNum - 1) * pageSize | ||
| 56 | + } | ||
| 57 | + debugger | ||
| 58 | + this.isTemplate ? this.fetchWorkTemplates(payload) : this.fetchWorks(payload) | ||
| 59 | + } | ||
| 60 | + }, | ||
| 61 | + render (h) { | ||
| 62 | + return ( | ||
| 63 | + <div class="works-wrapper"> | ||
| 64 | + <a-row gutter={12}> | ||
| 65 | + { | ||
| 66 | + !this.isTemplate && | ||
| 67 | + <a-col span={6} style="margin-bottom: 10px;"> | ||
| 68 | + <AddNewCard handleCreate={this.createWork} /> | ||
| 69 | + </a-col> | ||
| 70 | + } | ||
| 71 | + { | ||
| 72 | + this.loading | ||
| 73 | + ? <a-col span={18} class="loading-col"> | ||
| 74 | + <a-spin tip="作品列表获取中..."/> | ||
| 75 | + </a-col> | ||
| 76 | + : this.workList.map(work => ( | ||
| 77 | + <a-col span={6} key={work.id} class="mb-3"> | ||
| 78 | + <ListItemCard | ||
| 79 | + isTemplate={this.isTemplate} | ||
| 80 | + work={work} | ||
| 81 | + onPreview={e => { | ||
| 82 | + this.previewVisible = true | ||
| 83 | + this.activeWork = work | ||
| 84 | + }} | ||
| 85 | + onUseTemplate={work => { | ||
| 86 | + this.useTemplateDialogVisible = true | ||
| 87 | + this.useTemplate(work.id).then((clonedWork) => { | ||
| 88 | + this.clonedWorkFromTemplate = clonedWork | ||
| 89 | + }) | ||
| 90 | + }} | ||
| 91 | + onDelete={() => this.handleDeleteWork(work)} | ||
| 92 | + /> | ||
| 93 | + </a-col> | ||
| 94 | + )) | ||
| 95 | + } | ||
| 96 | + </a-row> | ||
| 97 | + <a-row gutter={12} class="pb-3"> | ||
| 98 | + <a-col span={24} style="text-align:center;"> | ||
| 99 | + <a-pagination | ||
| 100 | + show-size-changer | ||
| 101 | + default-current={1} | ||
| 102 | + total={500} | ||
| 103 | + current={this.pagination.pageNum} | ||
| 104 | + onShowSizeChange={(pageNum, pageSize) => { | ||
| 105 | + this.pagination.pageNum = 1 | ||
| 106 | + this.pagination.pageSize = pageSize | ||
| 107 | + this.handleSearch() | ||
| 108 | + }} | ||
| 109 | + onChange={(currentPageNum, pageSize) => { | ||
| 110 | + this.pagination.pageNum = currentPageNum | ||
| 111 | + this.pagination.pageSize = pageSize | ||
| 112 | + this.handleSearch() | ||
| 113 | + }} | ||
| 114 | + /> | ||
| 115 | + </a-col> | ||
| 116 | + </a-row> | ||
| 117 | + { | ||
| 118 | + <PreviewDialog | ||
| 119 | + work={this.activeWork || {}} | ||
| 120 | + visible={this.previewVisible} | ||
| 121 | + handleClose={() => { this.previewVisible = false }} | ||
| 122 | + /> | ||
| 123 | + } | ||
| 124 | + { | ||
| 125 | + this.isTemplate && | ||
| 126 | + this.useTemplateDialogVisible && | ||
| 127 | + <a-modal | ||
| 128 | + visible={true} | ||
| 129 | + // onOk={() => { this.useTemplateDialogVisible = true }} | ||
| 130 | + // onCancel={() => { this.useTemplateDialogVisible = false }} | ||
| 131 | + width="240px" | ||
| 132 | + okText="保存" | ||
| 133 | + footer={null} | ||
| 134 | + closable={false} | ||
| 135 | + centered | ||
| 136 | + > | ||
| 137 | + <div style="text-align: center;"> | ||
| 138 | + { | ||
| 139 | + this.clonedWorkFromTemplate | ||
| 140 | + ? <div> | ||
| 141 | + <div style={{ margin: '12px' }}> | ||
| 142 | + <a-icon type="check-circle" theme="twoTone" twoToneColor="#52c41a" /> | ||
| 143 | + 模板已保存至"我的作品"中 | ||
| 144 | + </div> | ||
| 145 | + <a-button onClick={() => { | ||
| 146 | + this.useTemplateDialogVisible = false | ||
| 147 | + this.clonedWorkFromTemplate = null | ||
| 148 | + }}>我再逛逛</a-button> | ||
| 149 | + <a-button type="primary" | ||
| 150 | + onClick={() => { | ||
| 151 | + const routeData = this.$router.resolve({ name: 'editor', params: { workId: this.clonedWorkFromTemplate.id } }) | ||
| 152 | + window.open(routeData.href, '_blank') | ||
| 153 | + }} | ||
| 154 | + style={{ marginLeft: '12px' }} | ||
| 155 | + >立即查看</a-button> | ||
| 156 | + </div> | ||
| 157 | + : <a-spin tip="复制中" /> | ||
| 158 | + } | ||
| 159 | + </div> | ||
| 160 | + </a-modal> | ||
| 161 | + } | ||
| 162 | + </div> | ||
| 163 | + ) | ||
| 164 | + }, | ||
| 165 | + created () { | ||
| 166 | + this.handleSearch() | ||
| 167 | + // this.isTemplate ? this.fetchWorkTemplates() : this.fetchWorks() | ||
| 168 | + } | ||
| 169 | +} |
front-end/h5/src/views/work-manager/list.scss
0 → 100644
front-end/h5/src/views/work-manager/list.vue
| 1 | <script> | 1 | <script> |
| 2 | -import { mapState, mapActions } from 'vuex' | ||
| 3 | -import QRCode from 'qrcode' | ||
| 4 | - | ||
| 5 | -import PreviewDialog from 'core/editor/modals/preview.vue' | ||
| 6 | -import CardCover from '@/components/common/work/card-cover.js' | ||
| 7 | - | ||
| 8 | -const ListItemCard = { | ||
| 9 | - props: { | ||
| 10 | - work: { | ||
| 11 | - type: Object, | ||
| 12 | - default: () => {} | ||
| 13 | - }, | ||
| 14 | - handleClickEdit: { | ||
| 15 | - type: Function, | ||
| 16 | - default: () => {} | ||
| 17 | - }, | ||
| 18 | - handleClickPreview: { | ||
| 19 | - type: Function, | ||
| 20 | - default: () => {} | ||
| 21 | - } | ||
| 22 | - }, | ||
| 23 | - data: () => ({ | ||
| 24 | - qrcodeUrl: '' | ||
| 25 | - }), | ||
| 26 | - methods: { | ||
| 27 | - ...mapActions('editor', [ | ||
| 28 | - 'deleteWork' | ||
| 29 | - ]), | ||
| 30 | - timeFmt (date) { | ||
| 31 | - const dateTime = new Date(date) | ||
| 32 | - const displayTime = `${dateTime.getFullYear()}-${dateTime.getMonth() + | ||
| 33 | - 1}-${dateTime.getDate()}` | ||
| 34 | - return displayTime | ||
| 35 | - }, | ||
| 36 | - genQRCodeUrl (work) { | ||
| 37 | - const url = `${window.location.origin}/works/preview/${work.id}` | ||
| 38 | - QRCode.toDataURL(url, (err, url) => { | ||
| 39 | - if (err) console.log(err) | ||
| 40 | - this.qrcodeUrl = url | ||
| 41 | - }) | ||
| 42 | - }, | ||
| 43 | - handleDeleteWork () { | ||
| 44 | - const { title, id } = this.work | ||
| 45 | - this.$confirm({ | ||
| 46 | - title: this.$t('workCard.confirmDeleteTip', { tip: `${title}(${id})` }), | ||
| 47 | - // content: 'Bla bla ...', | ||
| 48 | - okText: 'Confirm', | ||
| 49 | - cancelText: 'Cancel', | ||
| 50 | - onOk: async () => { | ||
| 51 | - await this.deleteWork(this.work.id) | ||
| 52 | - this.$emit('deleteSuccess') | ||
| 53 | - }, | ||
| 54 | - onCancel: () => {} | ||
| 55 | - }) | ||
| 56 | - } | ||
| 57 | - }, | ||
| 58 | - render (h) { | ||
| 59 | - return ( | ||
| 60 | - <a-card hoverable > | ||
| 61 | - <CardCover slot="cover" qrcodeUrl={this.qrcodeUrl} coverImageUrl={this.work.cover_image_url} /> | ||
| 62 | - <template class="ant-card-actions" slot="actions"> | ||
| 63 | - {/** 编辑 */} | ||
| 64 | - <a-tooltip effect="dark" placement="bottom" title={this.$t('workCard.edit')}> | ||
| 65 | - <router-link to={{ name: 'editor', params: { workId: this.work.id } }} target="_blank"> | ||
| 66 | - <a-icon type="edit" title={this.$t('workCard.edit')}/> | ||
| 67 | - </router-link> | ||
| 68 | - </a-tooltip> | ||
| 69 | - {/** 预览 */} | ||
| 70 | - <a-tooltip effect="dark" placement="bottom" title={this.$t('workCard.preview')}> | ||
| 71 | - <a-icon type="eye" title={this.$t('workCard.preview')} onClick={this.handleClickPreview} /> | ||
| 72 | - </a-tooltip> | ||
| 73 | - {/** 删除 */} | ||
| 74 | - <a-tooltip effect="dark" placement="bottom" title={this.$t('workCard.delete')}> | ||
| 75 | - <a-icon type="delete" title={this.$t('workCard.delete')} onClick={this.handleDeleteWork} /> | ||
| 76 | - </a-tooltip> | ||
| 77 | - { | ||
| 78 | - this.qrcodeUrl | ||
| 79 | - ? <a-icon type="close-circle" onClick={() => { this.qrcodeUrl = '' }} /> | ||
| 80 | - : <a-icon type="qrcode" onClick={() => this.genQRCodeUrl(this.work)} /> | ||
| 81 | - } | ||
| 82 | - {/** | ||
| 83 | - <a-icon type="setting" /> | ||
| 84 | - <a-icon type="ellipsis" /> | ||
| 85 | - */} | ||
| 86 | - </template> | ||
| 87 | - <a-card-meta | ||
| 88 | - > | ||
| 89 | - <div slot="title" class="ant-card-meta-title" style="font-size: 14px;"> | ||
| 90 | - {this.work.title}({this.work.id}) | ||
| 91 | - </div> | ||
| 92 | - <div slot="description" style="font-size: 12px;"> | ||
| 93 | - {/** 描述 时间 */} | ||
| 94 | - <div>{this.$t('workCard.description')}: {this.work.description}</div> | ||
| 95 | - <div>{this.$t('workCard.createTime')}: {this.timeFmt(this.work.created_at)}</div> | ||
| 96 | - </div> | ||
| 97 | - </a-card-meta> | ||
| 98 | - </a-card> | ||
| 99 | - ) | ||
| 100 | - } | ||
| 101 | -} | ||
| 102 | - | ||
| 103 | -const AddNewCard = { | ||
| 104 | - functional: true, | ||
| 105 | - render (h, { props, parent }) { | ||
| 106 | - return ( | ||
| 107 | - <a-card hoverable> | ||
| 108 | - <div slot="cover" class="flex-center" style="height: 405px;background: #f7f5f557;" onClick={props.handleCreate}> | ||
| 109 | - <a-icon type="plus" /> | ||
| 110 | - </div> | ||
| 111 | - <template class="ant-card-actions" slot="actions"> | ||
| 112 | - {/** 创建新作品 */} | ||
| 113 | - {/** https://kazupon.github.io/vue-i18n/guide/component.html#translation-in-functional-component */} | ||
| 114 | - <span onClick={props.handleCreate}>{parent.$t('workCard.createNewWork')}</span> | ||
| 115 | - </template> | ||
| 116 | - </a-card> | ||
| 117 | - ) | ||
| 118 | - } | ||
| 119 | -} | 2 | +import WorkList from './list-mixin' |
| 120 | 3 | ||
| 121 | export default { | 4 | export default { |
| 122 | - components: { | ||
| 123 | - ListItemCard, | ||
| 124 | - AddNewCard | ||
| 125 | - }, | ||
| 126 | data: () => ({ | 5 | data: () => ({ |
| 127 | - activeWork: null, | ||
| 128 | - previewVisible: false | ||
| 129 | }), | 6 | }), |
| 130 | - computed: { | ||
| 131 | - ...mapState('editor', ['works']), | ||
| 132 | - ...mapState('loading', ['fetchWorks_loading']) | ||
| 133 | - }, | ||
| 134 | - methods: { | ||
| 135 | - ...mapActions('editor', [ | ||
| 136 | - 'fetchWorks', | ||
| 137 | - 'createWork' | ||
| 138 | - ]) | ||
| 139 | - }, | ||
| 140 | render (h) { | 7 | render (h) { |
| 141 | - return ( | ||
| 142 | - <div class="works-wrapper"> | ||
| 143 | - <a-row gutter={12}> | ||
| 144 | - <a-col span={6} style="margin-bottom: 10px;"> | ||
| 145 | - <AddNewCard handleCreate={this.createWork} /> | ||
| 146 | - </a-col> | ||
| 147 | - { | ||
| 148 | - this.fetchWorks_loading | ||
| 149 | - ? <a-col span={18} style="margin-bottom: 10px;text-align: center;height: 355px;line-height: 355px;border-bottom: 1px solid #ebedf0;background: rgba(255, 255, 255, 0.5);"> | ||
| 150 | - <a-spin tip="作品列表获取中..."/> | ||
| 151 | - </a-col> | ||
| 152 | - : this.works.map(work => ( | ||
| 153 | - <a-col span={6} key={work.id} style="margin-bottom: 20px;"> | ||
| 154 | - <ListItemCard | ||
| 155 | - work={work} | ||
| 156 | - handleClickPreview={e => { | ||
| 157 | - this.previewVisible = true | ||
| 158 | - this.activeWork = work | ||
| 159 | - }} | ||
| 160 | - onDeleteSuccess={this.fetchWorks} | ||
| 161 | - /> | ||
| 162 | - </a-col> | ||
| 163 | - )) | ||
| 164 | - } | ||
| 165 | - </a-row> | ||
| 166 | - { | ||
| 167 | - <PreviewDialog | ||
| 168 | - work={this.activeWork || {}} | ||
| 169 | - visible={this.previewVisible} | ||
| 170 | - handleClose={() => { this.previewVisible = false }} | ||
| 171 | - /> | ||
| 172 | - } | ||
| 173 | - </div> | ||
| 174 | - ) | ||
| 175 | - }, | ||
| 176 | - created () { | ||
| 177 | - this.fetchWorks() | 8 | + return <WorkList isTemplate={false} /> |
| 178 | } | 9 | } |
| 179 | } | 10 | } |
| 180 | </script> | 11 | </script> |
front-end/h5/src/views/work-manager/templates.vue
| 1 | <script> | 1 | <script> |
| 2 | -import { mapState, mapActions } from 'vuex' | ||
| 3 | -import QRCode from 'qrcode' | ||
| 4 | - | ||
| 5 | -import PreviewDialog from 'core/editor/modals/preview.vue' | ||
| 6 | -import CardCover from '@/components/common/work/card-cover.js' | ||
| 7 | - | ||
| 8 | -const ListItemCard = { | ||
| 9 | - props: { | ||
| 10 | - work: { | ||
| 11 | - type: Object, | ||
| 12 | - default: () => {} | ||
| 13 | - }, | ||
| 14 | - handleClickEdit: { | ||
| 15 | - type: Function, | ||
| 16 | - default: () => {} | ||
| 17 | - }, | ||
| 18 | - handleClickPreview: { | ||
| 19 | - type: Function, | ||
| 20 | - default: () => {} | ||
| 21 | - }, | ||
| 22 | - handleUseTemplate: { | ||
| 23 | - type: Function, | ||
| 24 | - default: () => {} | ||
| 25 | - } | ||
| 26 | - }, | ||
| 27 | - data: () => ({ | ||
| 28 | - qrcodeUrl: '' | ||
| 29 | - }), | ||
| 30 | - methods: { | ||
| 31 | - timeFmt (date) { | ||
| 32 | - const dateTime = new Date(date) | ||
| 33 | - const displayTime = `${dateTime.getFullYear()}-${dateTime.getMonth() + | ||
| 34 | - 1}-${dateTime.getDate()}` | ||
| 35 | - return displayTime | ||
| 36 | - }, | ||
| 37 | - genQRCodeUrl (work) { | ||
| 38 | - const url = `${window.location.origin}/works/preview/${work.id}` | ||
| 39 | - QRCode.toDataURL(url, (err, url) => { | ||
| 40 | - if (err) console.log(err) | ||
| 41 | - this.qrcodeUrl = url | ||
| 42 | - }) | ||
| 43 | - } | ||
| 44 | - }, | ||
| 45 | - render (h) { | ||
| 46 | - return ( | ||
| 47 | - <a-card hoverable > | ||
| 48 | - <CardCover slot="cover" qrcodeUrl={this.qrcodeUrl} coverImageUrl={this.work.cover_image_url} /> | ||
| 49 | - <template class="ant-card-actions" slot="actions"> | ||
| 50 | - <a-tooltip effect="dark" placement="bottom" title={this.$t('workCard.useNow')}> | ||
| 51 | - <a-icon type="plus-square" title={this.$t('workCard.useNow')} onClick={() => { | ||
| 52 | - this.handleUseTemplate(this.work) | ||
| 53 | - }} /> | ||
| 54 | - </a-tooltip> | ||
| 55 | - {/** 预览 */} | ||
| 56 | - <a-tooltip effect="dark" placement="bottom" title={this.$t('workCard.preview')}> | ||
| 57 | - <a-icon type="eye" title={this.$t('workCard.preview')} onClick={this.handleClickPreview} /> | ||
| 58 | - </a-tooltip> | ||
| 59 | - { | ||
| 60 | - this.qrcodeUrl | ||
| 61 | - ? <a-icon type="close-circle" onClick={() => { this.qrcodeUrl = '' }} /> | ||
| 62 | - : <a-icon type="qrcode" onClick={() => this.genQRCodeUrl(this.work)} /> | ||
| 63 | - } | ||
| 64 | - {/** | ||
| 65 | - <a-icon type="setting" /> | ||
| 66 | - <a-icon type="ellipsis" /> | ||
| 67 | - */} | ||
| 68 | - </template> | ||
| 69 | - <a-card-meta | ||
| 70 | - > | ||
| 71 | - <div slot="title" class="ant-card-meta-title" style="font-size: 14px;"> | ||
| 72 | - {this.work.title}({this.work.id}) | ||
| 73 | - </div> | ||
| 74 | - <div slot="description" style="font-size: 12px;"> | ||
| 75 | - {/** 描述 时间 */} | ||
| 76 | - <div>{this.$t('workCard.description')}: {this.work.description}</div> | ||
| 77 | - <div>{this.$t('workCard.createTime')}: {this.timeFmt(this.work.created_at)}</div> | ||
| 78 | - </div> | ||
| 79 | - </a-card-meta> | ||
| 80 | - </a-card> | ||
| 81 | - ) | ||
| 82 | - } | ||
| 83 | -} | 2 | +import WorkList from './list-mixin' |
| 84 | 3 | ||
| 85 | export default { | 4 | export default { |
| 86 | - components: { | ||
| 87 | - ListItemCard | ||
| 88 | - }, | ||
| 89 | data: () => ({ | 5 | data: () => ({ |
| 90 | - activeWork: null, | ||
| 91 | - previewVisible: false, | 6 | + isTemplate: true, |
| 92 | useTemplateDialogVisible: false, | 7 | useTemplateDialogVisible: false, |
| 93 | clonedWorkFromTemplate: null // 从某个模板复制出来的作品 | 8 | clonedWorkFromTemplate: null // 从某个模板复制出来的作品 |
| 94 | }), | 9 | }), |
| 95 | - computed: { | ||
| 96 | - ...mapState('editor', ['works', 'workTemplates']), | ||
| 97 | - ...mapState('loading', ['fetchWorkTemplates_loading']) | ||
| 98 | - }, | ||
| 99 | - methods: { | ||
| 100 | - ...mapActions('editor', [ | ||
| 101 | - 'fetchWorks', | ||
| 102 | - 'fetchWorkTemplates', | ||
| 103 | - 'useTemplate' | ||
| 104 | - ]) | ||
| 105 | - }, | ||
| 106 | render (h) { | 10 | render (h) { |
| 107 | - return ( | ||
| 108 | - <div class="works-wrapper"> | ||
| 109 | - <a-row gutter={12}> | ||
| 110 | - { | ||
| 111 | - this.fetchWorkTemplates_loading | ||
| 112 | - ? <a-col span={24} style="margin-bottom: 10px;text-align: center;height: 355px;line-height: 355px;border-bottom: 1px solid #ebedf0;background: rgba(255, 255, 255, 0.5);"> | ||
| 113 | - <a-spin tip="作品列表获取中..."/> | ||
| 114 | - </a-col> | ||
| 115 | - : this.workTemplates.map(work => ( | ||
| 116 | - <a-col span={6} key={work.id} style="margin-bottom: 20px;"> | ||
| 117 | - <ListItemCard work={work} | ||
| 118 | - handleClickPreview={e => { | ||
| 119 | - this.previewVisible = true | ||
| 120 | - this.activeWork = work | ||
| 121 | - }} | ||
| 122 | - handleUseTemplate={templateWork => { | ||
| 123 | - this.useTemplateDialogVisible = true | ||
| 124 | - this.useTemplate(templateWork.id).then((clonedWork) => { | ||
| 125 | - this.clonedWorkFromTemplate = clonedWork | ||
| 126 | - }) | ||
| 127 | - }} | ||
| 128 | - /> | ||
| 129 | - </a-col> | ||
| 130 | - )) | ||
| 131 | - } | ||
| 132 | - </a-row> | ||
| 133 | - { | ||
| 134 | - <PreviewDialog | ||
| 135 | - work={this.activeWork || {}} | ||
| 136 | - visible={this.previewVisible} | ||
| 137 | - handleClose={() => { this.previewVisible = false }} | ||
| 138 | - /> | ||
| 139 | - } | ||
| 140 | - { | ||
| 141 | - this.useTemplateDialogVisible && | ||
| 142 | - <a-modal | ||
| 143 | - visible={true} | ||
| 144 | - // onOk={() => { this.useTemplateDialogVisible = true }} | ||
| 145 | - // onCancel={() => { this.useTemplateDialogVisible = false }} | ||
| 146 | - width="240px" | ||
| 147 | - okText="保存" | ||
| 148 | - footer={null} | ||
| 149 | - closable={false} | ||
| 150 | - centered | ||
| 151 | - > | ||
| 152 | - <div style="text-align: center;"> | ||
| 153 | - { | ||
| 154 | - this.clonedWorkFromTemplate | ||
| 155 | - ? <div> | ||
| 156 | - <div style={{ margin: '12px' }}><a-icon type="check-circle" theme="twoTone" twoToneColor="#52c41a" /> 模板已保存至"我的作品"中</div> | ||
| 157 | - <a-button onClick={() => { | ||
| 158 | - this.useTemplateDialogVisible = false | ||
| 159 | - this.clonedWorkFromTemplate = null | ||
| 160 | - }}>我再逛逛</a-button> | ||
| 161 | - <a-button type="primary" | ||
| 162 | - onClick={() => { | ||
| 163 | - const routeData = this.$router.resolve({ name: 'editor', params: { workId: this.clonedWorkFromTemplate.id } }) | ||
| 164 | - window.open(routeData.href, '_blank') | ||
| 165 | - }} | ||
| 166 | - style={{ marginLeft: '12px' }} | ||
| 167 | - >立即查看</a-button> | ||
| 168 | - </div> | ||
| 169 | - : <a-spin tip="复制中" /> | ||
| 170 | - } | ||
| 171 | - </div> | ||
| 172 | - </a-modal> | ||
| 173 | - } | ||
| 174 | - </div> | ||
| 175 | - ) | ||
| 176 | - }, | ||
| 177 | - created () { | ||
| 178 | - this.fetchWorkTemplates() | 11 | + return <WorkList isTemplate={this.isTemplate} /> |
| 179 | } | 12 | } |
| 180 | } | 13 | } |
| 181 | </script> | 14 | </script> |