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 | 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 | 109 | dispatch, |
| 110 | 110 | commit, |
| 111 | 111 | name: 'editor/setWorks', |
| 112 | 112 | loading_name: 'fetchWorks_loading', |
| 113 | 113 | successMsg: '获取作品列表成功', |
| 114 | 114 | customRequest: strapi.getEntries.bind(strapi) |
| 115 | - }).get('works', { is_template: false }).catch(handleError) | |
| 115 | + }).get('works', payload).catch(handleError) | |
| 116 | 116 | }, |
| 117 | 117 | fetchWorksWithForms ({ commit, dispatch, state }, workId) { |
| 118 | 118 | new AxiosWrapper({ |
| ... | ... | @@ -124,7 +124,7 @@ export const actions = { |
| 124 | 124 | customRequest: strapi.getEntries.bind(strapi) |
| 125 | 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 | 128 | new AxiosWrapper({ |
| 129 | 129 | dispatch, |
| 130 | 130 | commit, |
| ... | ... | @@ -132,7 +132,7 @@ export const actions = { |
| 132 | 132 | loading_name: 'fetchWorkTemplates_loading', |
| 133 | 133 | successMsg: '获取模板列表成功', |
| 134 | 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 | 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 | 4 | export default { |
| 122 | - components: { | |
| 123 | - ListItemCard, | |
| 124 | - AddNewCard | |
| 125 | - }, | |
| 126 | 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 | 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 | 11 | </script> | ... | ... |
front-end/h5/src/views/work-manager/templates.vue
| 1 | 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 | 4 | export default { |
| 86 | - components: { | |
| 87 | - ListItemCard | |
| 88 | - }, | |
| 89 | 5 | data: () => ({ |
| 90 | - activeWork: null, | |
| 91 | - previewVisible: false, | |
| 6 | + isTemplate: true, | |
| 92 | 7 | useTemplateDialogVisible: false, |
| 93 | 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 | 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 | 14 | </script> | ... | ... |