refactor: logic of saving in the post settings modal (#476)

Signed-off-by: Ryan Wang <i@ryanc.cc>
pull/480/head
Ryan Wang 2022-03-03 18:24:36 +08:00 committed by GitHub
parent 494482e573
commit fda9915883
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 206 additions and 66 deletions

View File

@ -122,27 +122,37 @@
</a-tab-pane> </a-tab-pane>
</a-tabs> </a-tabs>
</div> </div>
<template slot="footer"> <template #footer>
<slot name="extraFooter" /> <slot name="extraFooter" />
<ReactiveButton <ReactiveButton
v-if="!form.model.id" v-if="draftSaveVisible"
:errored="form.draftSaveErrored" :errored="form.draftSaveErrored"
:loading="form.draftSaving" :loading="form.draftSaving"
:text="`${hasId ? '转为' : '保存'}草稿`"
erroredText="保存失败" erroredText="保存失败"
loadedText="保存成功" loadedText="保存成功"
text="保存草稿"
type="danger" type="danger"
@callback="handleSavedCallback" @callback="handleSavedCallback()"
@click="handleCreateOrUpdate('DRAFT')" @click="handleSaveDraft()"
></ReactiveButton>
<ReactiveButton
v-if="publishVisible"
:errored="form.publishErrored"
:loading="form.publishing"
erroredText="发布失败"
loadedText="发布成功"
text="转为发布"
@callback="handleSavedCallback()"
@click="handlePublish()"
></ReactiveButton> ></ReactiveButton>
<ReactiveButton <ReactiveButton
:errored="form.saveErrored" :errored="form.saveErrored"
:erroredText="`${form.model.id ? '保存' : '发布'}失败`" :erroredText="`${hasId ? '保存' : '发布'}失败`"
:loadedText="`${form.model.id ? '保存' : '发布'}成功`" :loadedText="`${hasId ? '保存' : '发布'}成功`"
:loading="form.saving" :loading="form.saving"
:text="`${form.model.id ? '保存' : '发布'}`" :text="`${hasId ? '保存' : '发布'}`"
@callback="handleSavedCallback" @callback="handleSavedCallback()"
@click="handleCreateOrUpdate()" @click="handleSave()"
></ReactiveButton> ></ReactiveButton>
<a-button :disabled="loading" @click="modalVisible = false">关闭</a-button> <a-button :disabled="loading" @click="modalVisible = false">关闭</a-button>
</template> </template>
@ -164,6 +174,7 @@ import { mixin, mixinDevice } from '@/mixins/mixin.js'
import { datetimeFormat } from '@/utils/datetime' import { datetimeFormat } from '@/utils/datetime'
import pinyin from 'tiny-pinyin' import pinyin from 'tiny-pinyin'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import { postStatuses } from '@/core/constant'
// apis // apis
import apiClient from '@/utils/api-client' import apiClient from '@/utils/api-client'
@ -196,12 +207,15 @@ export default {
}, },
data() { data() {
return { return {
postStatuses,
form: { form: {
model: {}, model: {},
saving: false, saving: false,
saveErrored: false, saveErrored: false,
draftSaving: false, draftSaving: false,
draftSaveErrored: false draftSaveErrored: false,
publishing: false,
publishErrored: false
}, },
templates: [], templates: [],
@ -238,29 +252,36 @@ export default {
} }
}, },
fullPath() { fullPath() {
const permalinkType = this.options.post_permalink_type const { post_permalink_type, archives_prefix, blog_url, path_suffix: path_suffix = '' } = this.options
const blogUrl = this.options.blog_url const { slug: slug = '{slug}', createTime: createTime = new Date(), id: id = '{id}' } = this.form.model
const archivesPrefix = this.options.archives_prefix
const pathSuffix = this.options.path_suffix || '' switch (post_permalink_type) {
const slug = this.form.model.slug || '{slug}'
const createTime = this.form.model.createTime || new Date()
const id = this.form.model.id || '{id}'
switch (permalinkType) {
case 'DEFAULT': case 'DEFAULT':
return `${blogUrl}/${archivesPrefix}/${slug}${pathSuffix}` return `${blog_url}/${archives_prefix}/${slug}${path_suffix}`
case 'YEAR': case 'YEAR':
return `${blogUrl}${datetimeFormat(createTime, '/YYYY/')}${slug}${pathSuffix}` return `${blog_url}${datetimeFormat(createTime, '/YYYY/')}${slug}${path_suffix}`
case 'DATE': case 'DATE':
return `${blogUrl}${datetimeFormat(createTime, '/YYYY/MM/')}${slug}${pathSuffix}` return `${blog_url}${datetimeFormat(createTime, '/YYYY/MM/')}${slug}${path_suffix}`
case 'DAY': case 'DAY':
return `${blogUrl}${datetimeFormat(createTime, '/YYYY/MM/DD/')}${slug}${pathSuffix}` return `${blog_url}${datetimeFormat(createTime, '/YYYY/MM/DD/')}${slug}${path_suffix}`
case 'ID': case 'ID':
return `${blogUrl}/?p=${id}` return `${blog_url}/?p=${id}`
case 'ID_SLUG': case 'ID_SLUG':
return `${blogUrl}/${archivesPrefix}/${id}${pathSuffix}` return `${blog_url}/${archives_prefix}/${id}${path_suffix}`
default: default:
return '' return ''
} }
},
hasId() {
return !!this.form.model.id
},
draftSaveVisible() {
const { draftSaving, publishing } = this.form
return (this.form.model.status !== postStatuses.DRAFT.value || !this.hasId || draftSaving) && !publishing
},
publishVisible() {
const { draftSaving, publishing } = this.form
return ((this.form.model.status === postStatuses.DRAFT.value && this.hasId) || publishing) && !draftSaving
} }
}, },
watch: { watch: {
@ -287,32 +308,76 @@ export default {
/** /**
* Creates or updates a post * Creates or updates a post
*/ */
async handleCreateOrUpdate(preStatus = 'PUBLISHED') { async handleCreateOrUpdate() {
if (!this.form.model.title) { if (!this.form.model.title) {
this.$notification['error']({ this.$notification['error']({
message: '提示', message: '提示',
description: '文章标题不能为空!' description: '文章标题不能为空!'
}) })
return throw new Error('文章标题不能为空!')
} }
this.form.model.status = preStatus
this.form.model.keepRaw = true this.form.model.keepRaw = true
const { id, status } = this.form.model
try { try {
this.form[status === 'PUBLISHED' ? 'saving' : 'draftSaving'] = true if (this.hasId) {
await apiClient.post.update(this.form.model.id, this.form.model)
if (id) {
await apiClient.post.update(id, this.form.model)
} else { } else {
await apiClient.post.create(this.form.model) await apiClient.post.create(this.form.model)
} }
} catch (error) { } catch (error) {
this.form[status === 'PUBLISHED' ? 'saveErrored' : 'draftSaveErrored'] = true
this.$log.error(error) this.$log.error(error)
throw new Error(error)
}
},
async handleSave() {
try {
this.form.saving = true
const { status } = this.form.model
if (!status) {
this.form.model.status = this.postStatuses.PUBLISHED.value
}
await this.handleCreateOrUpdate()
} catch (e) {
this.form.saveErrored = true
this.$log.error('Failed to save post', e)
} finally { } finally {
setTimeout(() => { setTimeout(() => {
this.form.saving = false this.form.saving = false
}, 400)
}
},
async handlePublish() {
try {
this.form.publishing = true
this.form.model.status = this.postStatuses.PUBLISHED.value
await this.handleCreateOrUpdate()
} catch (e) {
this.form.publishErrored = true
this.$log.error('Failed to publish post', e)
} finally {
setTimeout(() => {
this.form.publishing = false
}, 400)
}
},
async handleSaveDraft() {
try {
this.form.draftSaving = true
this.form.model.status = this.postStatuses.DRAFT.value
await this.handleCreateOrUpdate()
} catch (e) {
this.form.draftSaveErrored = true
this.$log.error('Failed to save draft post', e)
} finally {
setTimeout(() => {
this.form.draftSaving = false this.form.draftSaving = false
}, 400) }, 400)
} }
@ -322,9 +387,10 @@ export default {
* Handle saved callback event * Handle saved callback event
*/ */
handleSavedCallback() { handleSavedCallback() {
if (this.form.saveErrored || this.form.draftSaveErrored) { if (this.form.saveErrored || this.form.draftSaveErrored || this.form.publishErrored) {
this.form.saveErrored = false this.form.saveErrored = false
this.form.draftSaveErrored = false this.form.draftSaveErrored = false
this.form.publishErrored = false
} else { } else {
this.savedCallback && this.savedCallback() this.savedCallback && this.savedCallback()
} }

View File

@ -243,17 +243,20 @@ export const sheetStatuses = {
PUBLISHED: { PUBLISHED: {
color: 'green', color: 'green',
status: 'success', status: 'success',
text: '已发布' text: '已发布',
value: 'PUBLISHED'
}, },
DRAFT: { DRAFT: {
color: 'yellow', color: 'yellow',
status: 'warning', status: 'warning',
text: '草稿' text: '草稿',
value: 'DRAFT'
}, },
RECYCLE: { RECYCLE: {
color: 'red', color: 'red',
status: 'error', status: 'error',
text: '回收站' text: '回收站',
value: 'RECYCLE'
} }
} }

View File

@ -110,27 +110,37 @@
</a-tab-pane> </a-tab-pane>
</a-tabs> </a-tabs>
</div> </div>
<template slot="footer"> <template #footer>
<slot name="extraFooter" /> <slot name="extraFooter" />
<ReactiveButton <ReactiveButton
v-if="!form.model.id" v-if="draftSaveVisible"
:errored="form.draftSaveErrored" :errored="form.draftSaveErrored"
:loading="form.draftSaving" :loading="form.draftSaving"
:text="`${hasId ? '转为' : '保存'}草稿`"
erroredText="保存失败" erroredText="保存失败"
loadedText="保存成功" loadedText="保存成功"
text="保存草稿"
type="danger" type="danger"
@callback="handleSavedCallback" @callback="handleSavedCallback()"
@click="handleCreateOrUpdate('DRAFT')" @click="handleSaveDraft()"
></ReactiveButton>
<ReactiveButton
v-if="publishVisible"
:errored="form.publishErrored"
:loading="form.publishing"
erroredText="发布失败"
loadedText="发布成功"
text="转为发布"
@callback="handleSavedCallback()"
@click="handlePublish()"
></ReactiveButton> ></ReactiveButton>
<ReactiveButton <ReactiveButton
:errored="form.saveErrored" :errored="form.saveErrored"
:erroredText="`${form.model.id ? '保存' : '发布'}失败`" :erroredText="`${hasId ? '保存' : '发布'}失败`"
:loadedText="`${form.model.id ? '保存' : '发布'}成功`" :loadedText="`${hasId ? '保存' : '发布'}成功`"
:loading="form.saving" :loading="form.saving"
:text="`${form.model.id ? '保存' : '发布'}`" :text="`${hasId ? '保存' : '发布'}`"
@callback="handleSavedCallback" @callback="handleSavedCallback()"
@click="handleCreateOrUpdate()" @click="handleSave()"
></ReactiveButton> ></ReactiveButton>
<a-button :disabled="loading" @click="modalVisible = false">关闭</a-button> <a-button :disabled="loading" @click="modalVisible = false">关闭</a-button>
</template> </template>
@ -144,11 +154,14 @@
<script> <script>
// components // components
import MetaEditor from '@/components/Post/MetaEditor' import MetaEditor from '@/components/Post/MetaEditor'
// libs // libs
import { mixin, mixinDevice } from '@/mixins/mixin.js' import { mixin, mixinDevice } from '@/mixins/mixin.js'
import { datetimeFormat } from '@/utils/datetime' import { datetimeFormat } from '@/utils/datetime'
import pinyin from 'tiny-pinyin' import pinyin from 'tiny-pinyin'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import { sheetStatuses } from '@/core/constant'
// apis // apis
import apiClient from '@/utils/api-client' import apiClient from '@/utils/api-client'
@ -178,12 +191,15 @@ export default {
}, },
data() { data() {
return { return {
sheetStatuses,
form: { form: {
model: {}, model: {},
saving: false, saving: false,
saveErrored: false, saveErrored: false,
draftSaving: false, draftSaving: false,
draftSaveErrored: false draftSaveErrored: false,
publishing: false,
publishErrored: false
}, },
templates: [], templates: [],
attachmentSelectVisible: false attachmentSelectVisible: false
@ -210,19 +226,28 @@ export default {
return datetimeFormat(new Date(), 'YYYY-MM-DD HH:mm:ss') return datetimeFormat(new Date(), 'YYYY-MM-DD HH:mm:ss')
}, },
fullPath() { fullPath() {
const permalinkType = this.options.sheet_permalink_type const { sheet_permalink_type, blog_url, sheet_prefix, path_suffix: path_suffix = '' } = this.options
const blogUrl = this.options.blog_url const { slug: slug = '{slug}' } = this.form.model
const sheetPrefix = this.options.sheet_prefix
const pathSuffix = this.options.path_suffix ? this.options.path_suffix : '' switch (sheet_permalink_type) {
const slug = this.form.model.slug || '{slug}'
switch (permalinkType) {
case 'SECONDARY': case 'SECONDARY':
return `${blogUrl}/${sheetPrefix}/${slug}${pathSuffix}` return `${blog_url}/${sheet_prefix}/${slug}${path_suffix}`
case 'ROOT': case 'ROOT':
return `${blogUrl}/${slug}${pathSuffix}` return `${blog_url}/${slug}${path_suffix}`
default: default:
return '' return ''
} }
},
hasId() {
return !!this.form.model.id
},
draftSaveVisible() {
const { draftSaving, publishing } = this.form
return (this.form.model.status !== sheetStatuses.DRAFT.value || !this.hasId || draftSaving) && !publishing
},
publishVisible() {
const { draftSaving, publishing } = this.form
return ((this.form.model.status === sheetStatuses.DRAFT.value && this.hasId) || publishing) && !draftSaving
} }
}, },
watch: { watch: {
@ -248,30 +273,75 @@ export default {
/** /**
* Creates or updates a sheet * Creates or updates a sheet
*/ */
async handleCreateOrUpdate(preStatus = 'PUBLISHED') { async handleCreateOrUpdate() {
if (!this.form.model.title) { if (!this.form.model.title) {
this.$notification['error']({ this.$notification['error']({
message: '提示', message: '提示',
description: '页面标题不能为空!' description: '页面标题不能为空!'
}) })
return throw new Error('文章标题不能为空!')
} }
this.form.model.status = preStatus
this.form.model.keepRaw = true this.form.model.keepRaw = true
const { id, status } = this.form.model
try { try {
this.form[status === 'PUBLISHED' ? 'saving' : 'draftSaving'] = true if (this.hasId) {
if (id) { await apiClient.sheet.update(this.form.model.id, this.form.model)
await apiClient.sheet.update(id, this.form.model)
} else { } else {
await apiClient.sheet.create(this.form.model) await apiClient.sheet.create(this.form.model)
} }
} catch (error) { } catch (error) {
this.form[status === 'PUBLISHED' ? 'saveErrored' : 'draftSaveErrored'] = true
this.$log.error(error) this.$log.error(error)
throw new Error(error)
}
},
async handleSave() {
try {
this.form.saving = true
const { status } = this.form.model
if (!status) {
this.form.model.status = this.sheetStatuses.PUBLISHED.value
}
await this.handleCreateOrUpdate()
} catch (e) {
this.form.saveErrored = true
this.$log.error('Failed to save sheet', e)
} finally { } finally {
setTimeout(() => { setTimeout(() => {
this.form.saving = false this.form.saving = false
}, 400)
}
},
async handlePublish() {
try {
this.form.publishing = true
this.form.model.status = this.sheetStatuses.PUBLISHED.value
await this.handleCreateOrUpdate()
} catch (e) {
this.form.publishErrored = true
this.$log.error('Failed to publish sheet', e)
} finally {
setTimeout(() => {
this.form.publishing = false
}, 400)
}
},
async handleSaveDraft() {
try {
this.form.draftSaving = true
this.form.model.status = this.sheetStatuses.DRAFT.value
await this.handleCreateOrUpdate()
} catch (e) {
this.form.draftSaveErrored = true
this.$log.error('Failed to save draft sheet', e)
} finally {
setTimeout(() => {
this.form.draftSaving = false this.form.draftSaving = false
}, 400) }, 400)
} }
@ -280,9 +350,10 @@ export default {
* Handle saved callback event * Handle saved callback event
*/ */
handleSavedCallback() { handleSavedCallback() {
if (this.form.saveErrored || this.form.draftSaveErrored) { if (this.form.saveErrored || this.form.draftSaveErrored || this.form.publishErrored) {
this.form.saveErrored = false this.form.saveErrored = false
this.form.draftSaveErrored = false this.form.draftSaveErrored = false
this.form.publishErrored = false
} else { } else {
this.savedCallback && this.savedCallback() this.savedCallback && this.savedCallback()
} }