mirror of https://github.com/halo-dev/halo
Add rich text editor. (halo-dev/console#76)
* refactor: pull out the editor component. * feat: support rich text editor.pull/3445/head
parent
5da3f267b7
commit
50af584f1f
|
@ -48,6 +48,16 @@ sheetApi.update = (sheetId, sheetToUpdate, autoSave) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sheetApi.updateDraft = (sheetId, content) => {
|
||||||
|
return service({
|
||||||
|
url: `${baseUrl}/${sheetId}/status/draft/content`,
|
||||||
|
method: 'put',
|
||||||
|
data: {
|
||||||
|
content: content
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
sheetApi.updateStatus = (sheetId, status) => {
|
sheetApi.updateStatus = (sheetId, status) => {
|
||||||
return service({
|
return service({
|
||||||
url: `${baseUrl}/${sheetId}/${status}`,
|
url: `${baseUrl}/${sheetId}/${status}`,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<div>
|
<div>
|
||||||
<halo-editor
|
<halo-editor
|
||||||
ref="md"
|
ref="md"
|
||||||
v-model="originalContentData"
|
v-model="originalContent"
|
||||||
:boxShadow="false"
|
:boxShadow="false"
|
||||||
:toolbars="toolbars"
|
:toolbars="toolbars"
|
||||||
:ishljs="true"
|
:ishljs="true"
|
||||||
|
@ -40,7 +40,7 @@ export default {
|
||||||
this.originalContentData = val
|
this.originalContentData = val
|
||||||
},
|
},
|
||||||
originalContentData(val) {
|
originalContentData(val) {
|
||||||
this.$emit('onChange', val)
|
this.$emit('onContentChange', val)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<a-input
|
||||||
|
type="textarea"
|
||||||
|
v-model="originalContent"
|
||||||
|
:rows="16"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'RichTextEditor',
|
||||||
|
props: {
|
||||||
|
originalContent: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
originalContentData: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
originalContent(val) {
|
||||||
|
this.originalContentData = val
|
||||||
|
},
|
||||||
|
originalContentData(val) {
|
||||||
|
this.$emit('onContentChange', val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -12,7 +12,8 @@ const keys = [
|
||||||
'sheet_prefix',
|
'sheet_prefix',
|
||||||
'post_permalink_type',
|
'post_permalink_type',
|
||||||
'archives_prefix',
|
'archives_prefix',
|
||||||
'path_suffix'
|
'path_suffix',
|
||||||
|
'default_editor'
|
||||||
]
|
]
|
||||||
const option = {
|
const option = {
|
||||||
state: {
|
state: {
|
||||||
|
|
|
@ -12,9 +12,16 @@
|
||||||
|
|
||||||
<div id="editor">
|
<div id="editor">
|
||||||
<MarkdownEditor
|
<MarkdownEditor
|
||||||
|
v-if="postToStage.editorType=='MARKDOWN'"
|
||||||
:originalContent="postToStage.originalContent"
|
:originalContent="postToStage.originalContent"
|
||||||
@onSaveDraft="handleSaveDraft(true)"
|
@onSaveDraft="handleSaveDraft(true)"
|
||||||
@onChange="onContentChange"
|
@onContentChange="onContentChange"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<RichTextEditor
|
||||||
|
v-else
|
||||||
|
:originalContent="postToStage.originalContent"
|
||||||
|
@onContentChange="onContentChange"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
@ -69,6 +76,7 @@ import PostSettingDrawer from './components/PostSettingDrawer'
|
||||||
import AttachmentDrawer from '../attachment/components/AttachmentDrawer'
|
import AttachmentDrawer from '../attachment/components/AttachmentDrawer'
|
||||||
import FooterToolBar from '@/components/FooterToolbar'
|
import FooterToolBar from '@/components/FooterToolbar'
|
||||||
import MarkdownEditor from '@/components/editor/MarkdownEditor'
|
import MarkdownEditor from '@/components/editor/MarkdownEditor'
|
||||||
|
import RichTextEditor from '@/components/editor/RichTextEditor'
|
||||||
|
|
||||||
import postApi from '@/api/post'
|
import postApi from '@/api/post'
|
||||||
export default {
|
export default {
|
||||||
|
@ -77,7 +85,8 @@ export default {
|
||||||
PostSettingDrawer,
|
PostSettingDrawer,
|
||||||
FooterToolBar,
|
FooterToolBar,
|
||||||
AttachmentDrawer,
|
AttachmentDrawer,
|
||||||
MarkdownEditor
|
MarkdownEditor,
|
||||||
|
RichTextEditor
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -151,6 +160,9 @@ export default {
|
||||||
}
|
}
|
||||||
return '当前页面数据未保存,确定要离开吗?'
|
return '当前页面数据未保存,确定要离开吗?'
|
||||||
}
|
}
|
||||||
|
if (!this.postToStage.editorType) {
|
||||||
|
this.postToStage.editorType = this.options.default_editor
|
||||||
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
temporaryContent: function(newValue, oldValue) {
|
temporaryContent: function(newValue, oldValue) {
|
||||||
|
@ -190,6 +202,7 @@ export default {
|
||||||
.then(response => {
|
.then(response => {
|
||||||
this.$log.debug('Updated post', response.data.data)
|
this.$log.debug('Updated post', response.data.data)
|
||||||
this.$message.success('保存草稿成功!')
|
this.$message.success('保存草稿成功!')
|
||||||
|
this.postToStage = response.data.data
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.saving = false
|
this.saving = false
|
||||||
|
|
|
@ -9,11 +9,19 @@
|
||||||
placeholder="请输入页面标题"
|
placeholder="请输入页面标题"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="editor">
|
<div id="editor">
|
||||||
<MarkdownEditor
|
<MarkdownEditor
|
||||||
|
v-if="sheetToStage.editorType=='MARKDOWN'"
|
||||||
:originalContent="sheetToStage.originalContent"
|
:originalContent="sheetToStage.originalContent"
|
||||||
@onSaveDraft="handleSaveDraft"
|
@onSaveDraft="handleSaveDraft(true)"
|
||||||
@onChange="onContentChange"
|
@onContentChange="onContentChange"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<RichTextEditor
|
||||||
|
v-else
|
||||||
|
:originalContent="sheetToStage.originalContent"
|
||||||
|
@onContentChange="onContentChange"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
@ -33,7 +41,7 @@
|
||||||
<footer-tool-bar :style="{ width: isSideMenu() && isDesktop() ? `calc(100% - ${sidebarOpened ? 256 : 80}px)` : '100%'}">
|
<footer-tool-bar :style="{ width: isSideMenu() && isDesktop() ? `calc(100% - ${sidebarOpened ? 256 : 80}px)` : '100%'}">
|
||||||
<a-button
|
<a-button
|
||||||
type="danger"
|
type="danger"
|
||||||
@click="handleSaveDraft"
|
@click="handleSaveDraft(false)"
|
||||||
:disabled="saving"
|
:disabled="saving"
|
||||||
>保存草稿</a-button>
|
>保存草稿</a-button>
|
||||||
<a-button
|
<a-button
|
||||||
|
@ -63,13 +71,16 @@ import SheetSettingDrawer from './components/SheetSettingDrawer'
|
||||||
import AttachmentDrawer from '../attachment/components/AttachmentDrawer'
|
import AttachmentDrawer from '../attachment/components/AttachmentDrawer'
|
||||||
import FooterToolBar from '@/components/FooterToolbar'
|
import FooterToolBar from '@/components/FooterToolbar'
|
||||||
import MarkdownEditor from '@/components/editor/MarkdownEditor'
|
import MarkdownEditor from '@/components/editor/MarkdownEditor'
|
||||||
|
import RichTextEditor from '@/components/editor/RichTextEditor'
|
||||||
|
|
||||||
import sheetApi from '@/api/sheet'
|
import sheetApi from '@/api/sheet'
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
FooterToolBar,
|
FooterToolBar,
|
||||||
AttachmentDrawer,
|
AttachmentDrawer,
|
||||||
SheetSettingDrawer,
|
SheetSettingDrawer,
|
||||||
MarkdownEditor
|
MarkdownEditor,
|
||||||
|
RichTextEditor
|
||||||
},
|
},
|
||||||
mixins: [mixin, mixinDevice],
|
mixins: [mixin, mixinDevice],
|
||||||
data() {
|
data() {
|
||||||
|
@ -140,6 +151,9 @@ export default {
|
||||||
}
|
}
|
||||||
return '当前页面数据未保存,确定要离开吗?'
|
return '当前页面数据未保存,确定要离开吗?'
|
||||||
}
|
}
|
||||||
|
if (!this.sheetToStage.editorType) {
|
||||||
|
this.sheetToStage.editorType = this.options.default_editor
|
||||||
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
temporaryContent: function(newValue, oldValue) {
|
temporaryContent: function(newValue, oldValue) {
|
||||||
|
@ -155,22 +169,35 @@ export default {
|
||||||
...mapGetters(['options'])
|
...mapGetters(['options'])
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleSaveDraft() {
|
handleSaveDraft(draftOnly = false) {
|
||||||
|
this.$log.debug('Draft only: ' + draftOnly)
|
||||||
this.sheetToStage.status = 'DRAFT'
|
this.sheetToStage.status = 'DRAFT'
|
||||||
this.saving = true
|
|
||||||
if (!this.sheetToStage.title) {
|
if (!this.sheetToStage.title) {
|
||||||
this.sheetToStage.title = moment(new Date()).format('YYYY-MM-DD-HH-mm-ss')
|
this.sheetToStage.title = moment(new Date()).format('YYYY-MM-DD-HH-mm-ss')
|
||||||
}
|
}
|
||||||
|
this.saving = true
|
||||||
if (this.sheetToStage.id) {
|
if (this.sheetToStage.id) {
|
||||||
|
if (draftOnly) {
|
||||||
sheetApi
|
sheetApi
|
||||||
.update(this.sheetToStage.id, this.sheetToStage, false)
|
.updateDraft(this.sheetToStage.id, this.sheetToStage.originalContent)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
this.$log.debug('Updated sheet', response.data.data)
|
|
||||||
this.$message.success('保存草稿成功!')
|
this.$message.success('保存草稿成功!')
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.saving = false
|
this.saving = false
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
sheetApi
|
||||||
|
.update(this.sheetToStage.id, this.sheetToStage, false)
|
||||||
|
.then(response => {
|
||||||
|
this.$log.debug('Updated sheet', response.data.data)
|
||||||
|
this.$message.success('保存草稿成功!')
|
||||||
|
this.sheetToStage = response.data.data
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.saving = false
|
||||||
|
})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
sheetApi
|
sheetApi
|
||||||
.create(this.sheetToStage, false)
|
.create(this.sheetToStage, false)
|
||||||
|
|
|
@ -103,6 +103,12 @@
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
:wrapperCol="wrapperCol"
|
:wrapperCol="wrapperCol"
|
||||||
>
|
>
|
||||||
|
<a-form-item label="默认编辑器:">
|
||||||
|
<a-select v-model="options.default_editor">
|
||||||
|
<a-select-option value="MARKDOWN">Markdown 编辑器</a-select-option>
|
||||||
|
<a-select-option value="RICHTEXT">富文本编辑器</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
<a-form-item label="首页文章排序:">
|
<a-form-item label="首页文章排序:">
|
||||||
<a-select v-model="options.post_index_sort">
|
<a-select v-model="options.post_index_sort">
|
||||||
<a-select-option value="createTime">创建时间</a-select-option>
|
<a-select-option value="createTime">创建时间</a-select-option>
|
||||||
|
|
Loading…
Reference in New Issue