mirror of https://github.com/halo-dev/halo
pref: created ReactiveButton component. (halo-dev/console#216)
* pref: created ReactiveButton component. * refactor: ReactiveButton. * refactor: Profile page. * feat: add form validate for comment reply. * refactor: PostSettingsDrawer.pull/3445/head
parent
23768f1d18
commit
88867e6957
|
@ -17,7 +17,7 @@
|
|||
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but vue-antd-pro doesn't work properly without JavaScript enabled. Please enable it to
|
||||
<strong>We're sorry but halo admin client doesn't work properly without JavaScript enabled. Please enable it to
|
||||
continue.</strong>
|
||||
</noscript>
|
||||
<div id="app">
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
align="middle"
|
||||
>
|
||||
<a-input-search
|
||||
placeholder="搜索附件"
|
||||
placeholder="搜索"
|
||||
v-model="queryParam.keyword"
|
||||
@search="handleQuery()"
|
||||
enterButton
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
<template>
|
||||
<a-button
|
||||
:type="computedType"
|
||||
@click="handleClick"
|
||||
:icon="computedIcon"
|
||||
:loading="loading"
|
||||
>{{ computedText }}</a-button>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'ReactiveButton',
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'primary'
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
errored: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
loadedText: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
erroredText: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loaded: false,
|
||||
hasError: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
loading(value) {
|
||||
if (!value) {
|
||||
this.loaded = true
|
||||
if (this.errored) {
|
||||
this.hasError = true
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.loaded = false
|
||||
this.hasError = false
|
||||
this.$emit('callback')
|
||||
}, 800)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
computedType() {
|
||||
if (this.loaded) {
|
||||
return this.hasError ? 'danger' : this.type
|
||||
}
|
||||
return this.type
|
||||
},
|
||||
computedIcon() {
|
||||
if (this.loaded) {
|
||||
return this.hasError ? 'close-circle' : 'check-circle'
|
||||
}
|
||||
return this.icon
|
||||
},
|
||||
computedText() {
|
||||
if (this.loaded) {
|
||||
return this.hasError ? this.erroredText : this.loadedText
|
||||
}
|
||||
return this.text
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick() {
|
||||
this.$emit('click')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -51,7 +51,6 @@ export default {
|
|||
var responseObject = response.data
|
||||
var HaloEditor = this.$refs.md
|
||||
HaloEditor.$img2Url(pos, encodeURI(responseObject.data.path))
|
||||
this.$message.success('图片上传成功!')
|
||||
})
|
||||
},
|
||||
handleSaveDraft() {
|
||||
|
|
|
@ -80,7 +80,7 @@ const updateTheme = primaryColor => {
|
|||
javascriptEnabled: true
|
||||
};
|
||||
`
|
||||
lessScriptNode.src = 'https://cdnjs.loli.net/ajax/libs/less.js/3.8.1/less.min.js'
|
||||
lessScriptNode.src = 'https://cdn.jsdelivr.net/npm/less@3.8.1/dist/less.min.js'
|
||||
lessScriptNode.async = true
|
||||
lessScriptNode.onload = () => {
|
||||
buildIt()
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
:allow-multiple="multiple"
|
||||
:allowRevert="false"
|
||||
:accepted-file-types="accept"
|
||||
:maxParallelUploads="loadOptions?options.attachment_upload_max_parallel_uploads:1"
|
||||
:allowImagePreview="loadOptions?options.attachment_upload_image_preview_enable:false"
|
||||
:maxFiles="loadOptions?options.attachment_upload_max_files:1"
|
||||
:maxParallelUploads="maxParallelUploads"
|
||||
:allowImagePreview="allowImagePreview"
|
||||
:maxFiles="maxFiles"
|
||||
labelFileProcessing="上传中"
|
||||
labelFileProcessingComplete="上传完成"
|
||||
labelFileProcessingAborted="取消上传"
|
||||
|
@ -77,6 +77,27 @@ export default {
|
|||
default: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['options']),
|
||||
maxParallelUploads() {
|
||||
if (this.options && this.options.length > 0) {
|
||||
return this.options.attachment_upload_max_parallel_uploads
|
||||
}
|
||||
return 1
|
||||
},
|
||||
allowImagePreview() {
|
||||
if (this.options && this.options.length > 0) {
|
||||
return this.options.attachment_upload_image_preview_enable
|
||||
}
|
||||
return false
|
||||
},
|
||||
maxFiles() {
|
||||
if (this.options && this.options.length > 0) {
|
||||
return this.options.attachment_upload_max_files
|
||||
}
|
||||
return 1
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
server: {
|
||||
|
@ -120,9 +141,6 @@ export default {
|
|||
fileList: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['options'])
|
||||
},
|
||||
methods: {
|
||||
handleFilePondInit() {
|
||||
this.$log.debug('FilePond has initialized')
|
||||
|
|
|
@ -4,12 +4,14 @@ import Ellipsis from '@/components/Ellipsis'
|
|||
import FooterToolbar from '@/components/FooterToolbar'
|
||||
import FilePondUpload from '@/components/Upload/FilePondUpload'
|
||||
import AttachmentSelectDrawer from './Attachment/AttachmentSelectDrawer'
|
||||
import ReactiveButton from './Button/ReactiveButton'
|
||||
|
||||
const _components = {
|
||||
Ellipsis,
|
||||
FooterToolbar,
|
||||
FilePondUpload,
|
||||
AttachmentSelectDrawer
|
||||
AttachmentSelectDrawer,
|
||||
ReactiveButton
|
||||
}
|
||||
|
||||
const components = {}
|
||||
|
|
|
@ -40,3 +40,7 @@ export function timeAgo(time) {
|
|||
export function isObject(value) {
|
||||
return value && typeof value === 'object' && value.constructor === Object
|
||||
}
|
||||
|
||||
export function datetimeFormat(value, pattern = 'YYYY-MM-DD HH:mm') {
|
||||
return moment(value).format(pattern)
|
||||
}
|
||||
|
|
|
@ -327,7 +327,7 @@ export default {
|
|||
this.$contextmenu({
|
||||
items: [
|
||||
{
|
||||
label: '复制图片链接',
|
||||
label: `${this.handleJudgeMediaType(item) ? '复制图片链接' : '复制文件链接'}`,
|
||||
onClick: () => {
|
||||
const text = `${encodeURI(item.path)}`
|
||||
this.$copyText(text)
|
||||
|
@ -343,6 +343,7 @@ export default {
|
|||
divided: true
|
||||
},
|
||||
{
|
||||
disabled: !this.handleJudgeMediaType(item),
|
||||
label: '复制 Markdown 格式链接',
|
||||
onClick: () => {
|
||||
const text = `![${item.name}](${encodeURI(item.path)})`
|
||||
|
|
|
@ -144,7 +144,15 @@
|
|||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<a-button type="danger">删除</a-button>
|
||||
<ReactiveButton
|
||||
type="danger"
|
||||
@callback="handleDeletedCallback"
|
||||
:loading="deleting"
|
||||
:errored="deleteErrored"
|
||||
text="删除"
|
||||
loadedText="删除成功"
|
||||
erroredText="删除失败"
|
||||
></ReactiveButton>
|
||||
</a-popconfirm>
|
||||
</div>
|
||||
</a-drawer>
|
||||
|
@ -173,6 +181,8 @@ export default {
|
|||
videoPreviewVisible: false,
|
||||
nonsupportPreviewVisible: false,
|
||||
player: {},
|
||||
deleting: false,
|
||||
deleteErrored: false,
|
||||
videoOptions: {
|
||||
lang: 'zh-cn',
|
||||
video: {
|
||||
|
@ -214,11 +224,22 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
handleDeleteAttachment() {
|
||||
attachmentApi.delete(this.attachment.id).then(response => {
|
||||
this.$message.success('删除成功!')
|
||||
this.$emit('delete', this.attachment)
|
||||
this.onClose()
|
||||
})
|
||||
this.deleting = true
|
||||
attachmentApi
|
||||
.delete(this.attachment.id)
|
||||
.catch(() => {
|
||||
this.deleteErrored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
this.deleting = false
|
||||
}, 400)
|
||||
})
|
||||
},
|
||||
handleDeletedCallback() {
|
||||
this.$emit('delete', this.attachment)
|
||||
this.deleteErrored = false
|
||||
this.onClose()
|
||||
},
|
||||
doUpdateAttachment() {
|
||||
if (!this.attachment.name) {
|
||||
|
|
|
@ -402,23 +402,31 @@
|
|||
destroyOnClose
|
||||
>
|
||||
<template slot="footer">
|
||||
<a-button
|
||||
key="submit"
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
@click="handleCreateClick"
|
||||
>
|
||||
回复
|
||||
</a-button>
|
||||
@callback="handleRepliedCallback"
|
||||
:loading="replying"
|
||||
:errored="replyErrored"
|
||||
text="回复"
|
||||
loadedText="回复成功"
|
||||
erroredText="回复失败"
|
||||
></ReactiveButton>
|
||||
</template>
|
||||
<a-form layout="vertical">
|
||||
<a-form-item>
|
||||
<a-form-model
|
||||
ref="replyCommentForm"
|
||||
:model="replyComment"
|
||||
:rules="replyCommentRules"
|
||||
layout="vertical"
|
||||
>
|
||||
<a-form-model-item prop="content">
|
||||
<a-input
|
||||
type="textarea"
|
||||
:autoSize="{ minRows: 8 }"
|
||||
v-model.trim="replyComment.content"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-modal>
|
||||
<!-- <CommentDetail
|
||||
v-model="commentDetailVisible"
|
||||
|
@ -551,9 +559,14 @@ export default {
|
|||
comments: [],
|
||||
selectedComment: {},
|
||||
replyComment: {},
|
||||
replyCommentRules: {
|
||||
content: [{ required: true, message: '* 内容不能为空', trigger: ['change', 'blur'] }]
|
||||
},
|
||||
loading: false,
|
||||
commentStatus: commentApi.commentStatus,
|
||||
commentDetailVisible: false
|
||||
commentDetailVisible: false,
|
||||
replying: false,
|
||||
replyErrored: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
@ -625,24 +638,32 @@ export default {
|
|||
}
|
||||
},
|
||||
handleCreateClick() {
|
||||
if (!this.replyComment.content) {
|
||||
this.$notification['error']({
|
||||
message: '提示',
|
||||
description: '评论内容不能为空!'
|
||||
})
|
||||
return
|
||||
const _this = this
|
||||
_this.$refs.replyCommentForm.validate(valid => {
|
||||
if (valid) {
|
||||
_this.replying = true
|
||||
commentApi
|
||||
.create(_this.type, _this.replyComment)
|
||||
.catch(() => {
|
||||
_this.replyErrored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
_this.replying = false
|
||||
}, 400)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleRepliedCallback() {
|
||||
if (this.replyErrored) {
|
||||
this.replyErrored = false
|
||||
} else {
|
||||
this.replyComment = {}
|
||||
this.selectedComment = {}
|
||||
this.replyCommentVisible = false
|
||||
this.handleListComments()
|
||||
}
|
||||
commentApi
|
||||
.create(this.type, this.replyComment)
|
||||
.then(response => {
|
||||
this.$message.success('回复成功!')
|
||||
this.replyComment = {}
|
||||
this.selectedComment = {}
|
||||
this.replyCommentVisible = false
|
||||
})
|
||||
.finally(() => {
|
||||
this.handleListComments()
|
||||
})
|
||||
},
|
||||
handlePaginationChange(page, pageSize) {
|
||||
this.$log.debug(`Current: ${page}, PageSize: ${pageSize}`)
|
||||
|
|
|
@ -206,36 +206,7 @@
|
|||
:xs="24"
|
||||
class="mb-3"
|
||||
>
|
||||
<a-card
|
||||
:bordered="false"
|
||||
:bodyStyle="{ padding: '16px' }"
|
||||
>
|
||||
<template slot="title">
|
||||
速记
|
||||
<a-tooltip
|
||||
slot="action"
|
||||
title="内容将保存到页面/所有页面/日志页面"
|
||||
>
|
||||
<a-icon type="info-circle-o" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-form layout="vertical">
|
||||
<a-form-item>
|
||||
<a-input
|
||||
type="textarea"
|
||||
:autoSize="{ minRows: 8 }"
|
||||
v-model="journal.sourceContent"
|
||||
placeholder="写点什么吧..."
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-button
|
||||
type="primary"
|
||||
@click="handleCreateJournalClick"
|
||||
>保存</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-card>
|
||||
<JournalPublishCard />
|
||||
</a-col>
|
||||
<a-col
|
||||
:xl="8"
|
||||
|
@ -295,6 +266,7 @@
|
|||
<script>
|
||||
import { PageView } from '@/layouts'
|
||||
import AnalysisCard from './components/AnalysisCard'
|
||||
import JournalPublishCard from './components/JournalPublishCard'
|
||||
import RecentCommentTab from './components/RecentCommentTab'
|
||||
import LogListDrawer from './components/LogListDrawer'
|
||||
import countTo from 'vue-count-to'
|
||||
|
@ -302,12 +274,12 @@ import countTo from 'vue-count-to'
|
|||
import postApi from '@/api/post'
|
||||
import logApi from '@/api/log'
|
||||
import statisticsApi from '@/api/statistics'
|
||||
import journalApi from '@/api/journal'
|
||||
export default {
|
||||
name: 'Dashboard',
|
||||
components: {
|
||||
PageView,
|
||||
AnalysisCard,
|
||||
JournalPublishCard,
|
||||
RecentCommentTab,
|
||||
countTo,
|
||||
LogListDrawer
|
||||
|
@ -403,22 +375,6 @@ export default {
|
|||
}, 200)
|
||||
})
|
||||
},
|
||||
handleEditPostClick(post) {
|
||||
this.$router.push({ name: 'PostEdit', query: { postId: post.id } })
|
||||
},
|
||||
handleCreateJournalClick() {
|
||||
if (!this.journal.sourceContent) {
|
||||
this.$notification['error']({
|
||||
message: '提示',
|
||||
description: '内容不能为空!'
|
||||
})
|
||||
return
|
||||
}
|
||||
journalApi.create(this.journal).then(response => {
|
||||
this.$message.success('发表成功!')
|
||||
this.journal = {}
|
||||
})
|
||||
},
|
||||
handlePostPreview(postId) {
|
||||
postApi.preview(postId).then(response => {
|
||||
window.open(response.data, '_blank')
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
<template>
|
||||
<a-card
|
||||
:bordered="false"
|
||||
:bodyStyle="{ padding: '16px' }"
|
||||
>
|
||||
<template slot="title">
|
||||
速记
|
||||
<a-tooltip
|
||||
slot="action"
|
||||
title="内容将保存到页面/所有页面/日志页面"
|
||||
>
|
||||
<a-icon type="info-circle-o" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-form-model
|
||||
ref="journalForm"
|
||||
:model="form.model"
|
||||
:rules="form.rules"
|
||||
layout="vertical"
|
||||
>
|
||||
<a-form-model-item prop="sourceContent">
|
||||
<a-input
|
||||
type="textarea"
|
||||
:autoSize="{ minRows: 8 }"
|
||||
v-model="form.model.sourceContent"
|
||||
placeholder="写点什么吧..."
|
||||
/>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item>
|
||||
<ReactiveButton
|
||||
@click="handleCreateJournalClick"
|
||||
@callback="() => {
|
||||
if(!form.errored) form.model = {}
|
||||
form.errored = false
|
||||
}"
|
||||
:loading="form.saving"
|
||||
:errored="form.errored"
|
||||
text="发布"
|
||||
loadedText="发布成功"
|
||||
erroredText="发布失败"
|
||||
></ReactiveButton>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-card>
|
||||
</template>
|
||||
<script>
|
||||
import journalApi from '@/api/journal'
|
||||
export default {
|
||||
name: 'JournalPublishCard',
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
model: {},
|
||||
rules: {
|
||||
sourceContent: [{ required: true, message: '* 内容不能为空', trigger: ['change', 'blur'] }]
|
||||
},
|
||||
saving: false,
|
||||
errored: false
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleCreateJournalClick() {
|
||||
const _this = this
|
||||
_this.$refs.journalForm.validate(valid => {
|
||||
if (valid) {
|
||||
_this.form.saving = true
|
||||
journalApi
|
||||
.create(_this.form.model)
|
||||
.catch(() => {
|
||||
this.form.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
_this.form.saving = false
|
||||
}, 400)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -85,18 +85,28 @@
|
|||
</a-select>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
v-if="!isUpdateMode"
|
||||
type="primary"
|
||||
@click="handleCreateOrUpdateMenu"
|
||||
v-if="!isUpdateMode"
|
||||
@callback="handleSavedCallback"
|
||||
:loading="form.saving"
|
||||
>保存</a-button>
|
||||
:errored="form.errored"
|
||||
text="保存"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
<a-button-group v-else>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
@click="handleCreateOrUpdateMenu"
|
||||
@callback="handleSavedCallback"
|
||||
:loading="form.saving"
|
||||
>更新</a-button>
|
||||
:errored="form.errored"
|
||||
text="更新"
|
||||
loadedText="更新成功"
|
||||
erroredText="更新失败"
|
||||
></ReactiveButton>
|
||||
<a-button
|
||||
type="dashed"
|
||||
@click="form.model = {}"
|
||||
|
@ -266,6 +276,7 @@ export default {
|
|||
target: '_self'
|
||||
},
|
||||
saving: false,
|
||||
errored: false,
|
||||
rules: {
|
||||
name: [
|
||||
{ required: true, message: '* 菜单名称不能为空', trigger: ['change', 'blur'] },
|
||||
|
@ -338,34 +349,38 @@ export default {
|
|||
if (_this.isUpdateMode) {
|
||||
menuApi
|
||||
.update(_this.form.model.id, _this.form.model)
|
||||
.then(response => {
|
||||
_this.$message.success('更新成功!')
|
||||
_this.form.model = { target: '_self' }
|
||||
.catch(() => {
|
||||
_this.form.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
_this.form.saving = false
|
||||
}, 400)
|
||||
_this.handleListMenus()
|
||||
_this.handleListTeams()
|
||||
})
|
||||
} else {
|
||||
menuApi
|
||||
.create(_this.form.model)
|
||||
.then(response => {
|
||||
_this.$message.success('保存成功!')
|
||||
_this.form.model = { target: '_self' }
|
||||
.catch(() => {
|
||||
_this.form.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
_this.form.saving = false
|
||||
}, 400)
|
||||
_this.handleListMenus()
|
||||
_this.handleListTeams()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
handleSavedCallback() {
|
||||
const _this = this
|
||||
if (_this.form.errored) {
|
||||
_this.form.errored = false
|
||||
} else {
|
||||
_this.form.model = { target: '_self' }
|
||||
_this.handleListMenus()
|
||||
_this.handleListTeams()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,12 +55,16 @@
|
|||
></codemirror>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-button
|
||||
type="primary"
|
||||
<ReactiveButton
|
||||
@click="handlerSaveContent"
|
||||
:disabled="buttonDisabled"
|
||||
@callback="saveErrored=false"
|
||||
:loading="saving"
|
||||
>保存</a-button>
|
||||
:errored="saveErrored"
|
||||
:disabled="buttonDisabled"
|
||||
text="保存"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-card>
|
||||
|
@ -95,7 +99,8 @@ export default {
|
|||
themes: [],
|
||||
themesLoading: false,
|
||||
selectedTheme: {},
|
||||
saving: false
|
||||
saving: false,
|
||||
saveErrored: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
@ -186,8 +191,8 @@ export default {
|
|||
this.saving = true
|
||||
themeApi
|
||||
.saveContent(this.selectedTheme.id, this.file.path, this.content)
|
||||
.then(response => {
|
||||
this.$message.success('保存成功!')
|
||||
.catch(() => {
|
||||
this.saveErrored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
</div>
|
||||
<div
|
||||
v-else
|
||||
@click="handleActivateClick(item)"
|
||||
@click="handleActiveTheme(item)"
|
||||
>
|
||||
<a-icon
|
||||
type="lock"
|
||||
|
@ -350,15 +350,10 @@ export default {
|
|||
}, 200)
|
||||
})
|
||||
},
|
||||
activeTheme(themeId) {
|
||||
themeApi
|
||||
.active(themeId)
|
||||
.then(response => {
|
||||
this.$message.success('设置成功!')
|
||||
})
|
||||
.finally(() => {
|
||||
this.handleListThemes()
|
||||
})
|
||||
handleActiveTheme(theme) {
|
||||
themeApi.active(theme.id).finally(() => {
|
||||
this.handleListThemes()
|
||||
})
|
||||
},
|
||||
handleUpdateTheme(themeId) {
|
||||
const hide = this.$message.loading('更新中...', 0)
|
||||
|
@ -397,9 +392,6 @@ export default {
|
|||
handleEditClick(theme) {
|
||||
this.settingDrawer(theme)
|
||||
},
|
||||
handleActivateClick(theme) {
|
||||
this.activeTheme(theme.id)
|
||||
},
|
||||
handleFetching() {
|
||||
if (!this.fetchingUrl) {
|
||||
this.$notification['error']({
|
||||
|
@ -447,14 +439,9 @@ export default {
|
|||
})
|
||||
},
|
||||
handleReload() {
|
||||
themeApi
|
||||
.reload()
|
||||
.then(response => {
|
||||
this.$message.success('刷新成功!')
|
||||
})
|
||||
.finally(() => {
|
||||
this.handleListThemes()
|
||||
})
|
||||
themeApi.reload().finally(() => {
|
||||
this.handleListThemes()
|
||||
})
|
||||
},
|
||||
handleShowUpdateNewThemeModal(item) {
|
||||
this.prepareUpdateTheme = item
|
||||
|
|
|
@ -220,11 +220,16 @@
|
|||
@click="toggleViewMode"
|
||||
class="mr-2"
|
||||
>预览模式</a-button>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
@click="handleSaveSettings"
|
||||
@callback="saveErrored=false"
|
||||
:loading="saving"
|
||||
>保存</a-button>
|
||||
:errored="saveErrored"
|
||||
text="保存"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
</footer-tool-bar>
|
||||
</a-drawer>
|
||||
</template>
|
||||
|
@ -258,7 +263,8 @@ export default {
|
|||
viewMode: false,
|
||||
formColValue: 12,
|
||||
clientHeight: document.documentElement.clientHeight,
|
||||
saving: false
|
||||
saving: false,
|
||||
saveErrored: false
|
||||
}
|
||||
},
|
||||
model: {
|
||||
|
@ -311,11 +317,13 @@ export default {
|
|||
themeApi
|
||||
.saveSettings(this.theme.id, this.themeSettings)
|
||||
.then(response => {
|
||||
this.$message.success('保存成功!')
|
||||
if (this.viewMode) {
|
||||
document.getElementById('themeViewIframe').contentWindow.location.reload(true)
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.saveErrored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
this.saving = false
|
||||
|
|
|
@ -69,18 +69,28 @@
|
|||
/>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
v-if="!isUpdateMode"
|
||||
type="primary"
|
||||
@click="handleCreateOrUpdateCategory"
|
||||
v-if="!isUpdateMode"
|
||||
@callback="handleSavedCallback"
|
||||
:loading="form.saving"
|
||||
>保存</a-button>
|
||||
:errored="form.errored"
|
||||
text="保存"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
<a-button-group v-else>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
@click="handleCreateOrUpdateCategory"
|
||||
@callback="handleSavedCallback"
|
||||
:loading="form.saving"
|
||||
>更新</a-button>
|
||||
:errored="form.errored"
|
||||
text="更新"
|
||||
loadedText="更新成功"
|
||||
erroredText="更新失败"
|
||||
></ReactiveButton>
|
||||
<a-button
|
||||
type="dashed"
|
||||
@click="form.model = {}"
|
||||
|
@ -295,6 +305,7 @@ export default {
|
|||
form: {
|
||||
model: {},
|
||||
saving: false,
|
||||
errored: false,
|
||||
rules: {
|
||||
name: [
|
||||
{ required: true, message: '* 分类名称不能为空', trigger: ['change', 'blur'] },
|
||||
|
@ -361,33 +372,38 @@ export default {
|
|||
if (_this.isUpdateMode) {
|
||||
categoryApi
|
||||
.update(_this.form.model.id, _this.form.model)
|
||||
.then(response => {
|
||||
_this.$message.success('更新成功!')
|
||||
_this.form.model = {}
|
||||
.catch(() => {
|
||||
this.form.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
_this.form.saving = false
|
||||
}, 400)
|
||||
_this.handleListCategories()
|
||||
})
|
||||
} else {
|
||||
categoryApi
|
||||
.create(this.form.model)
|
||||
.then(response => {
|
||||
_this.$message.success('保存成功!')
|
||||
_this.form.model = {}
|
||||
.catch(() => {
|
||||
this.form.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
_this.form.saving = false
|
||||
}, 400)
|
||||
_this.handleListCategories()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
handleSavedCallback() {
|
||||
if (this.form.errored) {
|
||||
this.form.errored = false
|
||||
} else {
|
||||
const _this = this
|
||||
_this.form.model = {}
|
||||
_this.handleListCategories()
|
||||
}
|
||||
},
|
||||
handleCreateMenuByCategory(category) {
|
||||
const menu = {
|
||||
name: category.name,
|
||||
|
|
|
@ -43,12 +43,17 @@
|
|||
<AttachmentDrawer v-model="attachmentDrawerVisible" />
|
||||
|
||||
<footer-tool-bar :style="{ width: isSideMenu() && isDesktop() ? `calc(100% - ${sidebarOpened ? 256 : 80}px)` : '100%'}">
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="danger"
|
||||
class="mr-2"
|
||||
@click="handleSaveDraft(false)"
|
||||
@callback="draftSavederrored = false"
|
||||
:loading="draftSaving"
|
||||
>保存草稿</a-button>
|
||||
:errored="draftSavederrored"
|
||||
text="保存草稿"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
<a-button
|
||||
@click="handlePreview"
|
||||
class="mr-2"
|
||||
|
@ -98,7 +103,8 @@ export default {
|
|||
isSaved: false,
|
||||
contentChanges: 0,
|
||||
draftSaving: false,
|
||||
previewSaving: false
|
||||
previewSaving: false,
|
||||
draftSavederrored: false
|
||||
}
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
|
@ -190,8 +196,8 @@ export default {
|
|||
if (draftOnly) {
|
||||
postApi
|
||||
.updateDraft(this.postToStage.id, this.postToStage.originalContent)
|
||||
.then(response => {
|
||||
this.$message.success('保存草稿成功!')
|
||||
.catch(() => {
|
||||
this.draftSavederrored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
|
@ -201,9 +207,10 @@ export default {
|
|||
} else {
|
||||
postApi
|
||||
.update(this.postToStage.id, this.postToStage, false)
|
||||
.catch(() => {
|
||||
this.draftSavederrored = true
|
||||
})
|
||||
.then(response => {
|
||||
this.$log.debug('Updated post', response.data.data)
|
||||
this.$message.success('保存草稿成功!')
|
||||
this.postToStage = response.data.data
|
||||
})
|
||||
.finally(() => {
|
||||
|
@ -216,15 +223,16 @@ export default {
|
|||
// Create the post
|
||||
postApi
|
||||
.create(this.postToStage, false)
|
||||
.catch(() => {
|
||||
this.draftSavederrored = true
|
||||
})
|
||||
.then(response => {
|
||||
this.$log.debug('Created post', response.data.data)
|
||||
this.$message.success('保存草稿成功!')
|
||||
this.postToStage = response.data.data
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
this.draftSaving = false
|
||||
}, 200)
|
||||
}, 400)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
|
|
@ -49,18 +49,28 @@
|
|||
</a-input>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
v-if="!isUpdateMode"
|
||||
type="primary"
|
||||
@click="handleCreateOrUpdateTag"
|
||||
v-if="!isUpdateMode"
|
||||
@callback="handleSavedCallback"
|
||||
:loading="form.saving"
|
||||
>保存</a-button>
|
||||
:errored="form.errored"
|
||||
text="保存"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
<a-button-group v-else>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
@click="handleCreateOrUpdateTag"
|
||||
@callback="handleSavedCallback"
|
||||
:loading="form.saving"
|
||||
>更新</a-button>
|
||||
:errored="form.errored"
|
||||
text="更新"
|
||||
loadedText="更新成功"
|
||||
erroredText="更新失败"
|
||||
></ReactiveButton>
|
||||
<a-button
|
||||
type="dashed"
|
||||
@click="form.model = {}"
|
||||
|
@ -137,6 +147,7 @@ export default {
|
|||
form: {
|
||||
model: {},
|
||||
saving: false,
|
||||
errored: false,
|
||||
rules: {
|
||||
name: [
|
||||
{ required: true, message: '* 标签名称不能为空', trigger: ['change', 'blur'] },
|
||||
|
@ -180,15 +191,10 @@ export default {
|
|||
})
|
||||
},
|
||||
handleDeleteTag(tagId) {
|
||||
tagApi
|
||||
.delete(tagId)
|
||||
.then(response => {
|
||||
this.$message.success('删除成功!')
|
||||
this.form.model = {}
|
||||
})
|
||||
.finally(() => {
|
||||
this.handleListTags()
|
||||
})
|
||||
tagApi.delete(tagId).finally(() => {
|
||||
this.form.model = {}
|
||||
this.handleListTags()
|
||||
})
|
||||
},
|
||||
handleCreateOrUpdateTag() {
|
||||
const _this = this
|
||||
|
@ -198,33 +204,38 @@ export default {
|
|||
if (_this.isUpdateMode) {
|
||||
tagApi
|
||||
.update(_this.form.model.id, _this.form.model)
|
||||
.then(response => {
|
||||
_this.$message.success('更新成功!')
|
||||
_this.form.model = {}
|
||||
.catch(() => {
|
||||
this.form.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
_this.form.saving = false
|
||||
}, 400)
|
||||
_this.handleListTags()
|
||||
})
|
||||
} else {
|
||||
tagApi
|
||||
.create(_this.form.model)
|
||||
.then(response => {
|
||||
_this.$message.success('保存成功!')
|
||||
_this.form.model = {}
|
||||
.catch(() => {
|
||||
this.form.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
_this.form.saving = false
|
||||
}, 400)
|
||||
_this.handleListTags()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
handleSavedCallback() {
|
||||
const _this = this
|
||||
if (_this.form.errored) {
|
||||
_this.form.errored = false
|
||||
} else {
|
||||
_this.form.model = {}
|
||||
_this.handleListTags()
|
||||
}
|
||||
},
|
||||
handleSelectThumbnail(data) {
|
||||
this.$set(this.form.model, 'thumbnail', encodeURI(data.path))
|
||||
this.thumbnailDrawer.visible = false
|
||||
|
|
|
@ -20,13 +20,10 @@
|
|||
>
|
||||
<a-input v-model="selectedPost.title" />
|
||||
</a-form-item>
|
||||
<a-form-item label="文章别名:">
|
||||
<template slot="help">
|
||||
<span v-if="options.post_permalink_type === 'DEFAULT'">{{ options.blog_url }}/{{ options.archives_prefix }}/{{ selectedPost.slug?selectedPost.slug:'${slug}' }}{{ (options.path_suffix?options.path_suffix:'') }}</span>
|
||||
<span v-else-if="options.post_permalink_type === 'DATE'">{{ options.blog_url }}{{ selectedPost.createTime?selectedPost.createTime:new Date() | moment_post_date }}{{ selectedPost.slug?selectedPost.slug:'${slug}' }}{{ (options.path_suffix?options.path_suffix:'') }}</span>
|
||||
<span v-else-if="options.post_permalink_type === 'DAY'">{{ options.blog_url }}{{ selectedPost.createTime?selectedPost.createTime:new Date() | moment_post_day }}{{ selectedPost.slug?selectedPost.slug:'${slug}' }}{{ (options.path_suffix?options.path_suffix:'') }}</span>
|
||||
<span v-else-if="options.post_permalink_type === 'ID'">{{ options.blog_url }}/?p={{ selectedPost.id?selectedPost.id:'${id}' }}</span>
|
||||
</template>
|
||||
<a-form-item
|
||||
label="文章别名:"
|
||||
:help="fullPath"
|
||||
>
|
||||
<a-input v-model="selectedPost.slug" />
|
||||
</a-form-item>
|
||||
|
||||
|
@ -284,17 +281,27 @@
|
|||
type="dashed"
|
||||
@click="advancedVisible = true"
|
||||
>高级</a-button>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="danger"
|
||||
v-if="saveDraftButton"
|
||||
class="mr-2"
|
||||
@click="handleDraftClick"
|
||||
v-if="saveDraftButton"
|
||||
@callback="handleSavedCallback"
|
||||
:loading="draftSaving"
|
||||
>保存草稿</a-button>
|
||||
<a-button
|
||||
:errored="draftSavedErrored"
|
||||
text="保存草稿"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
<ReactiveButton
|
||||
@click="handlePublishClick"
|
||||
type="primary"
|
||||
@callback="handleSavedCallback"
|
||||
:loading="saving"
|
||||
> {{ selectedPost.id?'保存':'发布' }} </a-button>
|
||||
:errored="savedErrored"
|
||||
:text="`${selectedPost.id?'保存':'发布'}`"
|
||||
:loadedText="`${selectedPost.id?'保存':'发布'}成功`"
|
||||
:erroredText="`${selectedPost.id?'保存':'发布'}失败`"
|
||||
></ReactiveButton>
|
||||
</div>
|
||||
</a-drawer>
|
||||
</template>
|
||||
|
@ -308,6 +315,7 @@ import { mapGetters } from 'vuex'
|
|||
import categoryApi from '@/api/category'
|
||||
import postApi from '@/api/post'
|
||||
import themeApi from '@/api/theme'
|
||||
import { datetimeFormat } from '@/utils/util'
|
||||
export default {
|
||||
name: 'PostSettingDrawer',
|
||||
mixins: [mixin, mixinDevice],
|
||||
|
@ -328,7 +336,9 @@ export default {
|
|||
categoryToCreate: {},
|
||||
customTpls: [],
|
||||
saving: false,
|
||||
draftSaving: false
|
||||
savedErrored: false,
|
||||
draftSaving: false,
|
||||
draftSavedErrored: false
|
||||
}
|
||||
},
|
||||
props: {
|
||||
|
@ -388,9 +398,8 @@ export default {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['options']),
|
||||
selectedMetas() {
|
||||
// 不能将selectedMetas直接定义在data里
|
||||
// 还没有获取到值就渲染视图,可以直接使用metas
|
||||
return this.metas
|
||||
},
|
||||
pickerDefaultValue() {
|
||||
|
@ -400,7 +409,32 @@ export default {
|
|||
}
|
||||
return moment(new Date(), 'YYYY-MM-DD HH:mm:ss')
|
||||
},
|
||||
...mapGetters(['options'])
|
||||
fullPath() {
|
||||
const permalinkType = this.options.post_permalink_type
|
||||
const blogUrl = this.options.blog_url
|
||||
const archivesPrefix = this.options.archives_prefix
|
||||
const pathSuffix = this.options.path_suffix ? this.options.path_suffix : ''
|
||||
switch (permalinkType) {
|
||||
case 'DEFAULT':
|
||||
return `${blogUrl}/${archivesPrefix}/${
|
||||
this.selectedPost.slug ? this.selectedPost.slug : '{slug}'
|
||||
}${pathSuffix}`
|
||||
case 'DATE':
|
||||
return `${blogUrl}${datetimeFormat(
|
||||
this.selectedPost.createTime ? this.selectedPost.createTime : new Date(),
|
||||
'/YYYY/MM/'
|
||||
)}${this.selectedPost.slug ? this.selectedPost.slug : '{slug}'}${pathSuffix}`
|
||||
case 'DAY':
|
||||
return `${blogUrl}${datetimeFormat(
|
||||
this.selectedPost.createTime ? this.selectedPost.createTime : new Date(),
|
||||
'/YYYY/MM/DD/'
|
||||
)}${this.selectedPost.slug ? this.selectedPost.slug : '{slug}'}${pathSuffix}`
|
||||
case 'ID':
|
||||
return `${blogUrl}/?p=${this.selectedPost.id ? this.selectedPost.id : '{id}'}`
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleAfterVisibleChanged(visible) {
|
||||
|
@ -491,17 +525,12 @@ export default {
|
|||
// Update the post
|
||||
postApi
|
||||
.update(this.selectedPost.id, this.selectedPost, false)
|
||||
.then(response => {
|
||||
this.$log.debug('Updated post', response.data.data)
|
||||
|
||||
.catch(() => {
|
||||
if (this.selectedPost.status === 'DRAFT') {
|
||||
this.$message.success('草稿保存成功!')
|
||||
this.draftSavedErrored = true
|
||||
} else {
|
||||
this.$message.success('文章更新成功!')
|
||||
this.savedErrored = true
|
||||
}
|
||||
|
||||
this.$emit('onSaved', true)
|
||||
this.$router.push({ name: 'PostList' })
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
|
@ -513,17 +542,14 @@ export default {
|
|||
// Create the post
|
||||
postApi
|
||||
.create(this.selectedPost, false)
|
||||
.then(response => {
|
||||
this.$log.debug('Created post', response.data.data)
|
||||
|
||||
.catch(() => {
|
||||
if (this.selectedPost.status === 'DRAFT') {
|
||||
this.$message.success('草稿保存成功!')
|
||||
this.draftSavedErrored = true
|
||||
} else {
|
||||
this.$message.success('文章发布成功!')
|
||||
this.savedErrored = true
|
||||
}
|
||||
|
||||
this.$emit('onSaved', true)
|
||||
this.$router.push({ name: 'PostList' })
|
||||
})
|
||||
.then(response => {
|
||||
this.selectedPost = response.data.data
|
||||
})
|
||||
.finally(() => {
|
||||
|
@ -534,6 +560,15 @@ export default {
|
|||
})
|
||||
}
|
||||
},
|
||||
handleSavedCallback() {
|
||||
if (this.draftSavedErrored || this.savedErrored) {
|
||||
this.draftSavedErrored = false
|
||||
this.savedErrored = false
|
||||
} else {
|
||||
this.$emit('onSaved', true)
|
||||
this.$router.push({ name: 'PostList' })
|
||||
}
|
||||
},
|
||||
onClose() {
|
||||
this.$emit('close', false)
|
||||
},
|
||||
|
|
|
@ -38,12 +38,17 @@
|
|||
|
||||
<AttachmentDrawer v-model="attachmentDrawerVisible" />
|
||||
<footer-tool-bar :style="{ width: isSideMenu() && isDesktop() ? `calc(100% - ${sidebarOpened ? 256 : 80}px)` : '100%'}">
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="danger"
|
||||
class="mr-2"
|
||||
@click="handleSaveDraft(false)"
|
||||
@callback="draftSavederrored = false"
|
||||
:loading="draftSaving"
|
||||
>保存草稿</a-button>
|
||||
:errored="draftSavederrored"
|
||||
text="保存草稿"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
<a-button
|
||||
@click="handlePreview"
|
||||
class="mr-2"
|
||||
|
@ -91,6 +96,7 @@ export default {
|
|||
isSaved: false,
|
||||
contentChanges: 0,
|
||||
draftSaving: false,
|
||||
draftSavederrored: false,
|
||||
previewSaving: false
|
||||
}
|
||||
},
|
||||
|
@ -180,8 +186,8 @@ export default {
|
|||
if (draftOnly) {
|
||||
sheetApi
|
||||
.updateDraft(this.sheetToStage.id, this.sheetToStage.originalContent)
|
||||
.then(response => {
|
||||
this.$message.success('保存草稿成功!')
|
||||
.catch(() => {
|
||||
this.draftSavederrored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
|
@ -191,9 +197,10 @@ export default {
|
|||
} else {
|
||||
sheetApi
|
||||
.update(this.sheetToStage.id, this.sheetToStage, false)
|
||||
.catch(() => {
|
||||
this.draftSavederrored = true
|
||||
})
|
||||
.then(response => {
|
||||
this.$log.debug('Updated sheet', response.data.data)
|
||||
this.$message.success('保存草稿成功!')
|
||||
this.sheetToStage = response.data.data
|
||||
})
|
||||
.finally(() => {
|
||||
|
@ -205,15 +212,16 @@ export default {
|
|||
} else {
|
||||
sheetApi
|
||||
.create(this.sheetToStage, false)
|
||||
.catch(() => {
|
||||
this.draftSavederrored = true
|
||||
})
|
||||
.then(response => {
|
||||
this.$log.debug('Created sheet', response.data.data)
|
||||
this.$message.success('保存草稿成功!')
|
||||
this.sheetToStage = response.data.data
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
this.draftSaving = false
|
||||
}, 200)
|
||||
}, 400)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
</a-form-item>
|
||||
<a-form-item
|
||||
label="页面别名:"
|
||||
:help="options.blog_url+'/'+options.sheet_prefix+'/'+ (selectedSheet.slug ? selectedSheet.slug : '{slug}')+(options.path_suffix?options.path_suffix:'')"
|
||||
:help="fullPath"
|
||||
>
|
||||
<a-input v-model="selectedSheet.slug" />
|
||||
</a-form-item>
|
||||
|
@ -197,17 +197,27 @@
|
|||
type="dashed"
|
||||
@click="advancedVisible = true"
|
||||
>高级</a-button>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="danger"
|
||||
v-if="saveDraftButton"
|
||||
class="mr-2"
|
||||
@click="handleDraftClick"
|
||||
@callback="handleSavedCallback"
|
||||
:loading="draftSaving"
|
||||
>保存草稿</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
:errored="draftSavedErrored"
|
||||
text="保存草稿"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
<ReactiveButton
|
||||
@click="handlePublishClick"
|
||||
@callback="handleSavedCallback"
|
||||
:loading="saving"
|
||||
>{{ selectedSheet.id?'保存':'发布' }}</a-button>
|
||||
:errored="savedErrored"
|
||||
:text="`${selectedSheet.id?'保存':'发布'}`"
|
||||
:loadedText="`${selectedSheet.id?'保存':'发布'}成功`"
|
||||
:erroredText="`${selectedSheet.id?'保存':'发布'}失败`"
|
||||
></ReactiveButton>
|
||||
</div>
|
||||
</a-drawer>
|
||||
</template>
|
||||
|
@ -228,7 +238,9 @@ export default {
|
|||
selectedSheet: this.sheet,
|
||||
customTpls: [],
|
||||
saving: false,
|
||||
draftSaving: false
|
||||
savedErrored: false,
|
||||
draftSaving: false,
|
||||
draftSavedErrored: false
|
||||
}
|
||||
},
|
||||
props: {
|
||||
|
@ -268,6 +280,7 @@ export default {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['options']),
|
||||
selectedMetas() {
|
||||
return this.metas
|
||||
},
|
||||
|
@ -278,7 +291,12 @@ export default {
|
|||
}
|
||||
return moment(new Date(), 'YYYY-MM-DD HH:mm:ss')
|
||||
},
|
||||
...mapGetters(['options'])
|
||||
fullPath() {
|
||||
const blogUrl = this.options.blog_url
|
||||
const sheetPrefix = this.options.sheet_prefix
|
||||
const pathSuffix = this.options.path_suffix ? this.options.path_suffix : ''
|
||||
return `${blogUrl}/${sheetPrefix}/${this.selectedSheet.slug ? this.selectedSheet.slug : '{slug}'}${pathSuffix}`
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleAfterVisibleChanged(visible) {
|
||||
|
@ -344,17 +362,12 @@ export default {
|
|||
if (this.selectedSheet.id) {
|
||||
sheetApi
|
||||
.update(this.selectedSheet.id, this.selectedSheet, false)
|
||||
.then(response => {
|
||||
this.$log.debug('Updated sheet', response.data.data)
|
||||
|
||||
.catch(() => {
|
||||
if (this.selectedSheet.status === 'DRAFT') {
|
||||
this.$message.success('草稿保存成功!')
|
||||
this.draftSavedErrored = true
|
||||
} else {
|
||||
this.$message.success('页面更新成功!')
|
||||
this.savedErrored = true
|
||||
}
|
||||
|
||||
this.$emit('onSaved', true)
|
||||
this.$router.push({ name: 'SheetList', query: { activeKey: 'custom' } })
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
|
@ -365,17 +378,14 @@ export default {
|
|||
} else {
|
||||
sheetApi
|
||||
.create(this.selectedSheet, false)
|
||||
.then(response => {
|
||||
this.$log.debug('Created sheet', response.data.data)
|
||||
|
||||
.catch(() => {
|
||||
if (this.selectedSheet.status === 'DRAFT') {
|
||||
this.$message.success('草稿保存成功!')
|
||||
this.draftSavedErrored = true
|
||||
} else {
|
||||
this.$message.success('页面发布成功!')
|
||||
this.savedErrored = true
|
||||
}
|
||||
|
||||
this.$emit('onSaved', true)
|
||||
this.$router.push({ name: 'SheetList', query: { activeKey: 'custom' } })
|
||||
})
|
||||
.then(response => {
|
||||
this.selectedSheet = response.data.data
|
||||
})
|
||||
.finally(() => {
|
||||
|
@ -386,6 +396,15 @@ export default {
|
|||
})
|
||||
}
|
||||
},
|
||||
handleSavedCallback() {
|
||||
if (this.draftSavedErrored || this.savedErrored) {
|
||||
this.draftSavedErrored = false
|
||||
this.savedErrored = false
|
||||
} else {
|
||||
this.$emit('onSaved', true)
|
||||
this.$router.push({ name: 'SheetList', query: { activeKey: 'custom' } })
|
||||
}
|
||||
},
|
||||
onClose() {
|
||||
this.$emit('close', false)
|
||||
},
|
||||
|
|
|
@ -209,11 +209,16 @@
|
|||
type="dashed"
|
||||
@click="attachmentDrawerVisible = true"
|
||||
>附件库</a-button>
|
||||
<a-button
|
||||
key="submit"
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
@click="createOrUpdateJournal"
|
||||
>发布</a-button>
|
||||
@callback="handleSavedCallback"
|
||||
:loading="saving"
|
||||
:errored="errored"
|
||||
text="发布"
|
||||
loadedText="发布成功"
|
||||
erroredText="发布失败"
|
||||
></ReactiveButton>
|
||||
</template>
|
||||
<a-form layout="vertical">
|
||||
<a-form-item>
|
||||
|
@ -283,7 +288,9 @@ export default {
|
|||
journal: {},
|
||||
isPublic: true,
|
||||
replyComment: {},
|
||||
options: []
|
||||
options: [],
|
||||
saving: false,
|
||||
errored: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
@ -355,29 +362,39 @@ export default {
|
|||
})
|
||||
return
|
||||
}
|
||||
|
||||
this.saving = true
|
||||
if (this.journal.id) {
|
||||
journalApi
|
||||
.update(this.journal.id, this.journal)
|
||||
.then(response => {
|
||||
this.$message.success('更新成功!')
|
||||
this.isPublic = true
|
||||
.catch(() => {
|
||||
this.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
this.hanldeListJournals()
|
||||
setTimeout(() => {
|
||||
this.saving = false
|
||||
}, 400)
|
||||
})
|
||||
} else {
|
||||
journalApi
|
||||
.create(this.journal)
|
||||
.then(response => {
|
||||
this.$message.success('发表成功!')
|
||||
this.isPublic = true
|
||||
.catch(() => {
|
||||
this.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
this.hanldeListJournals()
|
||||
setTimeout(() => {
|
||||
this.saving = false
|
||||
}, 400)
|
||||
})
|
||||
}
|
||||
this.visible = false
|
||||
},
|
||||
handleSavedCallback() {
|
||||
if (this.errored) {
|
||||
this.errored = false
|
||||
} else {
|
||||
this.isPublic = true
|
||||
this.visible = false
|
||||
this.hanldeListJournals()
|
||||
}
|
||||
},
|
||||
handlePaginationChange(page, pageSize) {
|
||||
this.$log.debug(`Current: ${page}, PageSize: ${pageSize}`)
|
||||
|
|
|
@ -77,18 +77,28 @@
|
|||
/>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
v-if="!isUpdateMode"
|
||||
type="primary"
|
||||
@click="handleCreateOrUpdateLink"
|
||||
v-if="!isUpdateMode"
|
||||
@callback="handleSavedCallback"
|
||||
:loading="form.saving"
|
||||
>保存</a-button>
|
||||
:errored="form.errored"
|
||||
text="保存"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
<a-button-group v-else>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
@click="handleCreateOrUpdateLink"
|
||||
@callback="handleSavedCallback"
|
||||
:loading="form.saving"
|
||||
>更新</a-button>
|
||||
:errored="form.errored"
|
||||
text="更新"
|
||||
loadedText="更新成功"
|
||||
erroredText="更新失败"
|
||||
></ReactiveButton>
|
||||
<a-button
|
||||
type="dashed"
|
||||
@click="form.model = {}"
|
||||
|
@ -298,6 +308,7 @@ export default {
|
|||
form: {
|
||||
model: {},
|
||||
saving: false,
|
||||
errored: false,
|
||||
rules: {
|
||||
name: [
|
||||
{ required: true, message: '* 友情链接名称不能为空', trigger: ['change', 'blur'] },
|
||||
|
@ -385,35 +396,39 @@ export default {
|
|||
if (_this.isUpdateMode) {
|
||||
linkApi
|
||||
.update(_this.form.model.id, _this.form.model)
|
||||
.then(response => {
|
||||
_this.$message.success('更新成功!')
|
||||
_this.form.model = {}
|
||||
.catch(() => {
|
||||
this.form.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
_this.form.saving = false
|
||||
}, 400)
|
||||
_this.handleListLinks()
|
||||
_this.handleListLinkTeams()
|
||||
})
|
||||
} else {
|
||||
linkApi
|
||||
.create(_this.form.model)
|
||||
.then(response => {
|
||||
_this.$message.success('保存成功!')
|
||||
_this.form.model = {}
|
||||
.catch(() => {
|
||||
this.form.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
_this.form.saving = false
|
||||
}, 400)
|
||||
_this.handleListLinks()
|
||||
_this.handleListLinkTeams()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
handleSavedCallback() {
|
||||
const _this = this
|
||||
if (_this.form.errored) {
|
||||
_this.form.errored = false
|
||||
} else {
|
||||
_this.form.model = {}
|
||||
_this.handleListLinks()
|
||||
_this.handleListLinkTeams()
|
||||
}
|
||||
},
|
||||
handleSaveOptions() {
|
||||
optionApi
|
||||
.save(this.optionsModal.data)
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
@onChange="onOptionsChange"
|
||||
@onSave="onSaveOptions"
|
||||
:saving="saving"
|
||||
:errored="errored"
|
||||
@callback="errored=false"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="seo">
|
||||
|
@ -28,6 +30,8 @@
|
|||
@onChange="onOptionsChange"
|
||||
@onSave="onSaveOptions"
|
||||
:saving="saving"
|
||||
:errored="errored"
|
||||
@callback="errored=false"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="post">
|
||||
|
@ -39,6 +43,8 @@
|
|||
@onChange="onOptionsChange"
|
||||
@onSave="onSaveOptions"
|
||||
:saving="saving"
|
||||
:errored="errored"
|
||||
@callback="errored=false"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="comment">
|
||||
|
@ -50,6 +56,8 @@
|
|||
@onChange="onOptionsChange"
|
||||
@onSave="onSaveOptions"
|
||||
:saving="saving"
|
||||
:errored="errored"
|
||||
@callback="errored=false"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="attachment">
|
||||
|
@ -61,6 +69,8 @@
|
|||
@onChange="onOptionsChange"
|
||||
@onSave="onSaveOptions"
|
||||
:saving="saving"
|
||||
:errored="errored"
|
||||
@callback="errored=false"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="smtp">
|
||||
|
@ -72,6 +82,8 @@
|
|||
@onChange="onOptionsChange"
|
||||
@onSave="onSaveOptions"
|
||||
:saving="saving"
|
||||
:errored="errored"
|
||||
@callback="errored=false"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="other">
|
||||
|
@ -83,6 +95,8 @@
|
|||
@onChange="onOptionsChange"
|
||||
@onSave="onSaveOptions"
|
||||
:saving="saving"
|
||||
:errored="errored"
|
||||
@callback="errored=false"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
|
@ -101,6 +115,8 @@
|
|||
@onChange="onOptionsChange"
|
||||
@onSave="onSaveOptions"
|
||||
:saving="saving"
|
||||
:errored="errored"
|
||||
@callback="errored=false"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="api">
|
||||
|
@ -112,6 +128,8 @@
|
|||
@onChange="onOptionsChange"
|
||||
@onSave="onSaveOptions"
|
||||
:saving="saving"
|
||||
:errored="errored"
|
||||
@callback="errored=false"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="advanced-other">
|
||||
|
@ -123,6 +141,8 @@
|
|||
@onChange="onOptionsChange"
|
||||
@onSave="onSaveOptions"
|
||||
:saving="saving"
|
||||
:errored="errored"
|
||||
@callback="errored=false"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
|
@ -177,7 +197,8 @@ export default {
|
|||
return {
|
||||
options: {},
|
||||
advancedOptions: false,
|
||||
saving: false
|
||||
saving: false,
|
||||
errored: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
@ -197,8 +218,8 @@ export default {
|
|||
this.saving = true
|
||||
optionApi
|
||||
.save(this.options)
|
||||
.then(response => {
|
||||
this.$message.success('保存成功!')
|
||||
.catch(() => {
|
||||
this.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
|
|
|
@ -56,13 +56,18 @@
|
|||
</a-row>
|
||||
<a-divider class="divider-transparent" />
|
||||
<div class="bottom-control">
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
icon="download"
|
||||
class="mr-2"
|
||||
:loading="backuping"
|
||||
icon="download"
|
||||
@click="handleBackupClick"
|
||||
>备份</a-button>
|
||||
@callback="handleBackupedCallback"
|
||||
:loading="backuping"
|
||||
:errored="backupErrored"
|
||||
text="备份"
|
||||
loadedText="备份成功"
|
||||
erroredText="备份失败"
|
||||
></ReactiveButton>
|
||||
<a-button
|
||||
type="dashed"
|
||||
icon="reload"
|
||||
|
@ -82,6 +87,7 @@ export default {
|
|||
return {
|
||||
backuping: false,
|
||||
loading: false,
|
||||
backupErrored: false,
|
||||
backups: []
|
||||
}
|
||||
},
|
||||
|
@ -119,29 +125,30 @@ export default {
|
|||
this.backuping = true
|
||||
backupApi
|
||||
.backupWorkDir()
|
||||
.then(response => {
|
||||
this.$message.success('备份成功!')
|
||||
.catch(() => {
|
||||
this.backupErrored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
this.backuping = false
|
||||
}, 400)
|
||||
this.handleListBackups()
|
||||
})
|
||||
},
|
||||
handleBackupedCallback() {
|
||||
if (this.backupErrored) {
|
||||
this.backupErrored = false
|
||||
} else {
|
||||
this.handleListBackups()
|
||||
}
|
||||
},
|
||||
handleBackupDeleteClick(backup) {
|
||||
backup.deleting = true
|
||||
backupApi
|
||||
.deleteWorkDirBackup(backup.filename)
|
||||
.then(response => {
|
||||
this.$message.success('删除成功!')
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
backup.deleting = false
|
||||
}, 400)
|
||||
this.handleListBackups()
|
||||
})
|
||||
backupApi.deleteWorkDirBackup(backup.filename).finally(() => {
|
||||
setTimeout(() => {
|
||||
backup.deleting = false
|
||||
}, 400)
|
||||
this.handleListBackups()
|
||||
})
|
||||
},
|
||||
onClose() {
|
||||
this.$emit('close', false)
|
||||
|
|
|
@ -56,13 +56,18 @@
|
|||
</a-row>
|
||||
<a-divider class="divider-transparent" />
|
||||
<div class="bottom-control">
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
icon="download"
|
||||
class="mr-2"
|
||||
:loading="backuping"
|
||||
icon="download"
|
||||
@click="handleExportClick"
|
||||
>备份</a-button>
|
||||
@callback="handleBackupedCallback"
|
||||
:loading="backuping"
|
||||
:errored="backupErrored"
|
||||
text="备份"
|
||||
loadedText="备份成功"
|
||||
erroredText="备份失败"
|
||||
></ReactiveButton>
|
||||
<a-button
|
||||
type="dashed"
|
||||
icon="reload"
|
||||
|
@ -82,6 +87,7 @@ export default {
|
|||
return {
|
||||
backuping: false,
|
||||
loading: false,
|
||||
backupErrored: false,
|
||||
files: []
|
||||
}
|
||||
},
|
||||
|
@ -119,29 +125,30 @@ export default {
|
|||
this.backuping = true
|
||||
backupApi
|
||||
.exportData()
|
||||
.then(response => {
|
||||
this.$message.success('导出成功!')
|
||||
.catch(() => {
|
||||
this.backupErrored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
this.backuping = false
|
||||
}, 400)
|
||||
this.handleListBackups()
|
||||
})
|
||||
},
|
||||
handleBackupedCallback() {
|
||||
if (this.backupErrored) {
|
||||
this.backupErrored = false
|
||||
} else {
|
||||
this.handleListBackups()
|
||||
}
|
||||
},
|
||||
handleFileDeleteClick(file) {
|
||||
file.deleting = true
|
||||
backupApi
|
||||
.deleteExportedData(file.filename)
|
||||
.then(response => {
|
||||
this.$message.success('删除成功!')
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
file.deleting = false
|
||||
}, 400)
|
||||
this.handleListBackups()
|
||||
})
|
||||
backupApi.deleteExportedData(file.filename).finally(() => {
|
||||
setTimeout(() => {
|
||||
file.deleting = false
|
||||
}, 400)
|
||||
this.handleListBackups()
|
||||
})
|
||||
},
|
||||
onClose() {
|
||||
this.$emit('close', false)
|
||||
|
|
|
@ -7,10 +7,16 @@
|
|||
<a-switch v-model="options.developer_mode" />
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
@click="handleSaveOptions"
|
||||
>保存</a-button>
|
||||
@callback="errored=false"
|
||||
:loading="saving"
|
||||
:errored="errored"
|
||||
text="保存"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
|
@ -27,28 +33,38 @@ export default {
|
|||
lg: { span: 8 },
|
||||
sm: { span: 12 },
|
||||
xs: { span: 24 }
|
||||
}
|
||||
},
|
||||
saving: false,
|
||||
errored: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadFormOptions()
|
||||
this.handleListOptions()
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['refreshOptionsCache']),
|
||||
loadFormOptions() {
|
||||
handleListOptions() {
|
||||
optionApi.listAll().then(response => {
|
||||
this.options = response.data.data
|
||||
})
|
||||
},
|
||||
handleSaveOptions() {
|
||||
optionApi.save(this.options).then(response => {
|
||||
this.loadFormOptions()
|
||||
this.refreshOptionsCache()
|
||||
this.$message.success('保存成功!')
|
||||
if (!this.options.developer_mode) {
|
||||
this.$router.push({ name: 'ToolList' })
|
||||
}
|
||||
})
|
||||
this.saving = true
|
||||
optionApi
|
||||
.save(this.options)
|
||||
.catch(() => {
|
||||
this.errored = false
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
this.saving = false
|
||||
}, 400)
|
||||
this.handleListOptions()
|
||||
this.refreshOptionsCache()
|
||||
if (!this.options.developer_mode) {
|
||||
this.$router.push({ name: 'ToolList' })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,11 +14,16 @@
|
|||
<a-switch v-model="options.global_absolute_path_enabled" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
@click="handleSaveOptions"
|
||||
@callback="$emit('callback')"
|
||||
:loading="saving"
|
||||
>保存</a-button>
|
||||
:errored="errored"
|
||||
text="保存"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</div>
|
||||
|
@ -34,6 +39,10 @@ export default {
|
|||
saving: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
errored: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -17,11 +17,16 @@
|
|||
/>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
@click="handleSaveOptions"
|
||||
@callback="$emit('callback')"
|
||||
:loading="saving"
|
||||
>保存</a-button>
|
||||
:errored="errored"
|
||||
text="保存"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</div>
|
||||
|
@ -37,6 +42,10 @@ export default {
|
|||
saving: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
errored: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -373,11 +373,16 @@
|
|||
</a-form-model-item>
|
||||
</div>
|
||||
<a-form-model-item>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
@click="handleSaveOptions"
|
||||
@callback="$emit('callback')"
|
||||
:loading="saving"
|
||||
>保存</a-button>
|
||||
:errored="errored"
|
||||
text="保存"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</div>
|
||||
|
@ -446,6 +451,10 @@ export default {
|
|||
saving: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
errored: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -61,11 +61,16 @@
|
|||
/>
|
||||
</a-form-model-item> -->
|
||||
<a-form-model-item>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
@click="handleSaveOptions"
|
||||
@callback="$emit('callback')"
|
||||
:loading="saving"
|
||||
>保存</a-button>
|
||||
:errored="errored"
|
||||
text="保存"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</div>
|
||||
|
@ -81,6 +86,10 @@ export default {
|
|||
saving: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
errored: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -62,11 +62,16 @@
|
|||
/>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
@click="handleSaveOptions"
|
||||
@callback="$emit('callback')"
|
||||
:loading="saving"
|
||||
>保存</a-button>
|
||||
:errored="errored"
|
||||
text="保存"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
|
||||
|
@ -89,6 +94,10 @@ export default {
|
|||
saving: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
errored: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -31,23 +31,17 @@
|
|||
placeholder="第三方网站统计的代码,如:Google Analytics、百度统计、CNZZ 等"
|
||||
/>
|
||||
</a-form-model-item>
|
||||
<!-- <a-form-model-item
|
||||
label="黑名单 IP:"
|
||||
|
||||
>
|
||||
<a-input
|
||||
type="textarea"
|
||||
:autoSize="{ minRows: 5 }"
|
||||
v-model="options.blog_ip_blacklist"
|
||||
placeholder="多个 IP 地址换行隔开"
|
||||
/>
|
||||
</a-form-model-item> -->
|
||||
<a-form-model-item>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
@click="handleSaveOptions"
|
||||
@callback="$emit('callback')"
|
||||
:loading="saving"
|
||||
>保存</a-button>
|
||||
:errored="errored"
|
||||
text="保存"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</div>
|
||||
|
@ -63,6 +57,10 @@ export default {
|
|||
saving: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
errored: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
>
|
||||
<a-form-model-item label="文章固定链接类型:">
|
||||
<template slot="help">
|
||||
<span v-if="options.post_permalink_type === 'DEFAULT'">{{ options.blog_url }}/{{ options.archives_prefix }}/${slug}{{ options.path_suffix }}</span>
|
||||
<span v-else-if="options.post_permalink_type === 'DATE'">{{ options.blog_url }}{{ new Date() | moment_post_date }}${slug}{{ options.path_suffix }}</span>
|
||||
<span v-else-if="options.post_permalink_type === 'DAY'">{{ options.blog_url }}{{ new Date() | moment_post_day }}${slug}{{ options.path_suffix }}</span>
|
||||
<span v-else-if="options.post_permalink_type === 'ID'">{{ options.blog_url }}/?p=${id}</span>
|
||||
<span v-if="options.post_permalink_type === 'DEFAULT'">{{ options.blog_url }}/{{ options.archives_prefix }}/{slug}{{ options.path_suffix }}</span>
|
||||
<span v-else-if="options.post_permalink_type === 'DATE'">{{ options.blog_url }}{{ new Date() | moment_post_date }}{slug}{{ options.path_suffix }}</span>
|
||||
<span v-else-if="options.post_permalink_type === 'DAY'">{{ options.blog_url }}{{ new Date() | moment_post_day }}{slug}{{ options.path_suffix }}</span>
|
||||
<span v-else-if="options.post_permalink_type === 'ID'">{{ options.blog_url }}/?p={id}</span>
|
||||
</template>
|
||||
<a-select v-model="options.post_permalink_type">
|
||||
<a-select-option
|
||||
|
@ -24,7 +24,7 @@
|
|||
</a-form-model-item>
|
||||
<a-form-model-item label="自定义页面前缀:">
|
||||
<template slot="help">
|
||||
<span>{{ options.blog_url }}/{{ options.sheet_prefix }}/${slug}{{ options.path_suffix }}</span>
|
||||
<span>{{ options.blog_url }}/{{ options.sheet_prefix }}/{slug}{{ options.path_suffix }}</span>
|
||||
</template>
|
||||
<a-input v-model="options.sheet_prefix" />
|
||||
</a-form-model-item>
|
||||
|
@ -54,28 +54,33 @@
|
|||
</a-form-model-item>
|
||||
<a-form-model-item label="分类前缀:">
|
||||
<template slot="help">
|
||||
<span>{{ options.blog_url }}/{{ options.categories_prefix }}/${slug}{{ options.path_suffix }}</span>
|
||||
<span>{{ options.blog_url }}/{{ options.categories_prefix }}/{slug}{{ options.path_suffix }}</span>
|
||||
</template>
|
||||
<a-input v-model="options.categories_prefix" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="标签前缀:">
|
||||
<template slot="help">
|
||||
<span>{{ options.blog_url }}/{{ options.tags_prefix }}/${slug}{{ options.path_suffix }}</span>
|
||||
<span>{{ options.blog_url }}/{{ options.tags_prefix }}/{slug}{{ options.path_suffix }}</span>
|
||||
</template>
|
||||
<a-input v-model="options.tags_prefix" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="路径后缀:">
|
||||
<template slot="help">
|
||||
<span>* 格式为:<code>.${suffix}</code>,仅对内建路径有效</span>
|
||||
<span>* 格式为:<code>.{suffix}</code>,仅对内建路径有效</span>
|
||||
</template>
|
||||
<a-input v-model="options.path_suffix" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
@click="handleSaveOptions"
|
||||
@callback="$emit('callback')"
|
||||
:loading="saving"
|
||||
>保存</a-button>
|
||||
:errored="errored"
|
||||
text="保存"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</div>
|
||||
|
@ -92,6 +97,10 @@ export default {
|
|||
saving: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
errored: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -51,11 +51,16 @@
|
|||
/>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
@click="handleSaveOptions"
|
||||
@callback="$emit('callback')"
|
||||
:loading="saving"
|
||||
>保存</a-button>
|
||||
:errored="errored"
|
||||
text="保存"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</div>
|
||||
|
@ -71,6 +76,10 @@ export default {
|
|||
saving: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
errored: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -33,11 +33,16 @@
|
|||
/>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
@click="handleSaveOptions"
|
||||
@callback="$emit('callback')"
|
||||
:loading="saving"
|
||||
>保存</a-button>
|
||||
:errored="errored"
|
||||
text="保存"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</div>
|
||||
|
@ -53,6 +58,10 @@ export default {
|
|||
saving: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
errored: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -38,11 +38,16 @@
|
|||
<a-input v-model="options.email_from_name" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
@click="handleSaveOptions"
|
||||
@callback="$emit('callback')"
|
||||
:loading="saving"
|
||||
>保存</a-button>
|
||||
:errored="errored"
|
||||
text="保存"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-tab-pane>
|
||||
|
@ -68,11 +73,16 @@
|
|||
/>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item>
|
||||
<a-button
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
@click="handleTestMailClick"
|
||||
@callback="sendErrored=false"
|
||||
:loading="sending"
|
||||
>发送</a-button>
|
||||
:errored="sendErrored"
|
||||
text="发送"
|
||||
loadedText="发送成功"
|
||||
erroredText="发送失败"
|
||||
></ReactiveButton>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-tab-pane>
|
||||
|
@ -91,6 +101,10 @@ export default {
|
|||
saving: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
errored: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
@ -103,6 +117,7 @@ export default {
|
|||
},
|
||||
mailParam: {},
|
||||
sending: false,
|
||||
sendErrored: false,
|
||||
rules: {}
|
||||
}
|
||||
},
|
||||
|
@ -193,6 +208,9 @@ export default {
|
|||
.then(response => {
|
||||
this.$message.info(response.data.message)
|
||||
})
|
||||
.catch(() => {
|
||||
this.sendErrored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
this.sending = false
|
||||
|
|
|
@ -18,16 +18,16 @@
|
|||
>
|
||||
<a-avatar
|
||||
:size="104"
|
||||
:src="user.avatar || '//cn.gravatar.com/avatar/?s=256&d=mm'"
|
||||
@click="attachmentDrawerVisible = true"
|
||||
:src="userForm.model.avatar || '//cn.gravatar.com/avatar/?s=256&d=mm'"
|
||||
@click="attachmentDrawer.visible = true"
|
||||
class="cursor-pointer"
|
||||
/>
|
||||
</a-tooltip>
|
||||
<div
|
||||
class="text-xl leading-5 font-medium mt-4 mb-1"
|
||||
style="color: rgba(0, 0, 0, 0.85);"
|
||||
>{{ user.nickname }}</div>
|
||||
<div>{{ user.description }}</div>
|
||||
>{{ userForm.model.nickname }}</div>
|
||||
<div>{{ userForm.model.description }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-3">
|
||||
|
@ -43,27 +43,27 @@
|
|||
<a-icon
|
||||
type="mail"
|
||||
class="mr-3"
|
||||
/>{{ user.email }}
|
||||
/>{{ userForm.model.email }}
|
||||
</p>
|
||||
<p class="mb-3">
|
||||
<a-icon
|
||||
type="calendar"
|
||||
class="mr-3"
|
||||
/>{{ statistics.establishDays || 0 }} 天
|
||||
/>{{ statistics.data.establishDays || 0 }} 天
|
||||
</p>
|
||||
</div>
|
||||
<a-divider />
|
||||
<div>
|
||||
<a-list
|
||||
:loading="statisticsLoading"
|
||||
:loading="statistics.loading"
|
||||
itemLayout="horizontal"
|
||||
>
|
||||
<a-list-item>累计发表了 {{ statistics.postCount || 0 }} 篇文章。</a-list-item>
|
||||
<a-list-item>累计创建了 {{ statistics.categoryCount || 0 }} 个分类。</a-list-item>
|
||||
<a-list-item>累计创建了 {{ statistics.tagCount || 0 }} 个标签。</a-list-item>
|
||||
<a-list-item>累计获得了 {{ statistics.commentCount || 0 }} 条评论。</a-list-item>
|
||||
<a-list-item>累计添加了 {{ statistics.linkCount || 0 }} 个友链。</a-list-item>
|
||||
<a-list-item>文章总阅读 {{ statistics.visitCount || 0 }} 次。</a-list-item>
|
||||
<a-list-item>累计发表了 {{ statistics.data.postCount || 0 }} 篇文章。</a-list-item>
|
||||
<a-list-item>累计创建了 {{ statistics.data.categoryCount || 0 }} 个分类。</a-list-item>
|
||||
<a-list-item>累计创建了 {{ statistics.data.tagCount || 0 }} 个标签。</a-list-item>
|
||||
<a-list-item>累计获得了 {{ statistics.data.commentCount || 0 }} 条评论。</a-list-item>
|
||||
<a-list-item>累计添加了 {{ statistics.data.linkCount || 0 }} 个友链。</a-list-item>
|
||||
<a-list-item>文章总阅读 {{ statistics.data.visitCount || 0 }} 次。</a-list-item>
|
||||
<a-list-item></a-list-item>
|
||||
</a-list>
|
||||
</div>
|
||||
|
@ -85,138 +85,182 @@
|
|||
<span slot="tab">
|
||||
<a-icon type="idcard" />基本资料
|
||||
</span>
|
||||
<a-form layout="vertical">
|
||||
<a-form-item label="用户名:">
|
||||
<a-input v-model="user.username" />
|
||||
</a-form-item>
|
||||
<a-form-item label="昵称:">
|
||||
<a-input v-model="user.nickname" />
|
||||
</a-form-item>
|
||||
<a-form-item label="邮箱:">
|
||||
<a-input v-model="user.email" />
|
||||
</a-form-item>
|
||||
<a-form-item label="个人说明:">
|
||||
<a-form-model
|
||||
ref="userForm"
|
||||
:model="userForm.model"
|
||||
:rules="userForm.rules"
|
||||
layout="vertical"
|
||||
>
|
||||
<a-form-model-item
|
||||
label="用户名:"
|
||||
prop="username"
|
||||
>
|
||||
<a-input v-model="userForm.model.username" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item
|
||||
label="昵称:"
|
||||
prop="nickname"
|
||||
>
|
||||
<a-input v-model="userForm.model.nickname" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item
|
||||
label="电子邮箱:"
|
||||
prop="email"
|
||||
>
|
||||
<a-input v-model="userForm.model.email" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item
|
||||
label="个人说明:"
|
||||
prop="description"
|
||||
>
|
||||
<a-input
|
||||
:autoSize="{ minRows: 5 }"
|
||||
type="textarea"
|
||||
v-model="user.description"
|
||||
v-model="userForm.model.description"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-button
|
||||
@click="handleUpdateProfile"
|
||||
</a-form-model-item>
|
||||
<a-form-model-item>
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
>保存</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
@click="handleUpdateProfile"
|
||||
@callback="handleUpdatedProfileCallback"
|
||||
:loading="userForm.saving"
|
||||
:errored="userForm.errored"
|
||||
text="保存"
|
||||
loadedText="保存成功"
|
||||
erroredText="保存失败"
|
||||
></ReactiveButton>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="2">
|
||||
<span slot="tab">
|
||||
<a-icon type="lock" />密码
|
||||
</span>
|
||||
<a-form layout="vertical">
|
||||
<a-form-item label="原密码:">
|
||||
<a-form-model
|
||||
ref="passwordForm"
|
||||
:model="passwordForm.model"
|
||||
:rules="passwordForm.rules"
|
||||
layout="vertical"
|
||||
>
|
||||
<a-form-model-item
|
||||
label="原密码:"
|
||||
prop="oldPassword"
|
||||
>
|
||||
<a-input-password
|
||||
v-model="passwordParam.oldPassword"
|
||||
v-model="passwordForm.model.oldPassword"
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="新密码:">
|
||||
</a-form-model-item>
|
||||
<a-form-model-item
|
||||
label="新密码:"
|
||||
prop="newPassword"
|
||||
>
|
||||
<a-input-password
|
||||
v-model="passwordParam.newPassword"
|
||||
v-model="passwordForm.model.newPassword"
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="确认密码:">
|
||||
</a-form-model-item>
|
||||
<a-form-model-item
|
||||
label="确认密码:"
|
||||
prop="confirmPassword"
|
||||
>
|
||||
<a-input-password
|
||||
v-model="passwordParam.confirmPassword"
|
||||
v-model="passwordForm.model.confirmPassword"
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-button
|
||||
:disabled="passwordUpdateButtonDisabled"
|
||||
@click="handleUpdatePassword"
|
||||
</a-form-model-item>
|
||||
<a-form-model-item>
|
||||
<ReactiveButton
|
||||
type="primary"
|
||||
>确认更改</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
@click="handleUpdatePassword"
|
||||
@callback="handleUpdatedPasswordCallback"
|
||||
:loading="passwordForm.saving"
|
||||
:errored="passwordForm.errored"
|
||||
text="确认更改"
|
||||
loadedText="更改成功"
|
||||
erroredText="更改失败"
|
||||
></ReactiveButton>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="3">
|
||||
<span slot="tab">
|
||||
<a-icon type="safety-certificate" />两步验证
|
||||
</span>
|
||||
<a-form-item label="两步验证:">
|
||||
<a-switch
|
||||
v-model="mfaParam.switch.checked"
|
||||
:loading="mfaParam.switch.loading"
|
||||
@change="handleMFASwitch"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="两步验证应用:">
|
||||
<a-list itemLayout="horizontal">
|
||||
<a-list-item>
|
||||
<b>Authy</b> 功能丰富 专为两步验证码
|
||||
<a-divider type="vertical" />
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://authy.com/download/"
|
||||
>
|
||||
iOS/Android/Windows/Mac/Linux
|
||||
<a-icon type="link" />
|
||||
</a>
|
||||
<a-divider type="vertical" />
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://chrome.google.com/webstore/detail/authy/gaedmjdfmmahhbjefcbgaolhhanlaolb?hl=cn"
|
||||
>
|
||||
Chrome 扩展
|
||||
<a-icon type="link" />
|
||||
</a>
|
||||
</a-list-item>
|
||||
<a-list-item>
|
||||
<b>Google Authenticator</b> 简单易用,但不支持密钥导出备份
|
||||
<a-divider type="vertical" />
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://apps.apple.com/us/app/google-authenticator/id388497605"
|
||||
>
|
||||
iOS
|
||||
<a-icon type="link" />
|
||||
</a>
|
||||
<a-divider type="vertical" />
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=cn"
|
||||
>
|
||||
Android
|
||||
<a-icon type="link" />
|
||||
</a>
|
||||
</a-list-item>
|
||||
<a-list-item>
|
||||
<b>Microsoft Authenticator</b> 使用微软全家桶的推荐
|
||||
<a-divider type="vertical" />
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://www.microsoft.com/zh-cn/account/authenticator"
|
||||
>
|
||||
iOS/Android
|
||||
<a-icon type="link" />
|
||||
</a>
|
||||
</a-list-item>
|
||||
<a-list-item>
|
||||
<b>1Password</b> 强大安全的密码管理付费应用
|
||||
<a-divider type="vertical" />
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://1password.com/zh-cn/downloads/"
|
||||
>
|
||||
iOS/Android/Windows/Mac/Linux/ChromeOS
|
||||
<a-icon type="link" />
|
||||
</a>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
</a-form-item>
|
||||
<a-form-model layout="vertical">
|
||||
<a-form-model-item label="两步验证:">
|
||||
<a-switch
|
||||
v-model="mfaParam.switch.checked"
|
||||
:loading="mfaParam.switch.loading"
|
||||
@change="handleMFASwitch"
|
||||
/>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="两步验证应用:">
|
||||
<a-list itemLayout="horizontal">
|
||||
<a-list-item>
|
||||
<b>Authy</b> 功能丰富 专为两步验证码
|
||||
<a-divider type="vertical" />
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://authy.com/download/"
|
||||
>
|
||||
iOS/Android/Windows/Mac/Linux
|
||||
<a-icon type="link" />
|
||||
</a>
|
||||
<a-divider type="vertical" />
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://chrome.google.com/webstore/detail/authy/gaedmjdfmmahhbjefcbgaolhhanlaolb?hl=cn"
|
||||
>
|
||||
Chrome 扩展
|
||||
<a-icon type="link" />
|
||||
</a>
|
||||
</a-list-item>
|
||||
<a-list-item>
|
||||
<b>Google Authenticator</b> 简单易用,但不支持密钥导出备份
|
||||
<a-divider type="vertical" />
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://apps.apple.com/us/app/google-authenticator/id388497605"
|
||||
>
|
||||
iOS
|
||||
<a-icon type="link" />
|
||||
</a>
|
||||
<a-divider type="vertical" />
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=cn"
|
||||
>
|
||||
Android
|
||||
<a-icon type="link" />
|
||||
</a>
|
||||
</a-list-item>
|
||||
<a-list-item>
|
||||
<b>Microsoft Authenticator</b> 使用微软全家桶的推荐
|
||||
<a-divider type="vertical" />
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://www.microsoft.com/zh-cn/account/authenticator"
|
||||
>
|
||||
iOS/Android
|
||||
<a-icon type="link" />
|
||||
</a>
|
||||
</a-list-item>
|
||||
<a-list-item>
|
||||
<b>1Password</b> 强大安全的密码管理付费应用
|
||||
<a-divider type="vertical" />
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://1password.com/zh-cn/downloads/"
|
||||
>
|
||||
iOS/Android/Windows/Mac/Linux/ChromeOS
|
||||
<a-icon type="link" />
|
||||
</a>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
|
@ -225,7 +269,7 @@
|
|||
</a-row>
|
||||
|
||||
<AttachmentSelectDrawer
|
||||
v-model="attachmentDrawerVisible"
|
||||
v-model="attachmentDrawer.visible"
|
||||
@listenToSelect="handleSelectAvatar"
|
||||
@listenToSelectGravatar="handleSelectGravatar"
|
||||
title="选择头像"
|
||||
|
@ -235,9 +279,7 @@
|
|||
<a-modal
|
||||
:title="mfaParam.modal.title"
|
||||
:visible="mfaParam.modal.visible"
|
||||
@ok="handleSetMFAuth"
|
||||
:confirmLoading="false"
|
||||
@cancel="handleCloseMFAuthModal"
|
||||
:closable="false"
|
||||
icon="safety-certificate"
|
||||
:keyboard="false"
|
||||
|
@ -245,10 +287,37 @@
|
|||
:destroyOnClose="true"
|
||||
:width="400"
|
||||
>
|
||||
<a-form v-if="mfaUsed">
|
||||
<a-form-item extra="* 需要验证两步验证码">
|
||||
<template slot="footer">
|
||||
<a-button
|
||||
key="back"
|
||||
@click="handleCloseMFAuthModal"
|
||||
>
|
||||
取消
|
||||
</a-button>
|
||||
<ReactiveButton
|
||||
key="submit"
|
||||
type="primary"
|
||||
@click="handleSetMFAuth"
|
||||
@callback="handleSetMFAuthCallback"
|
||||
:loading="mfaParam.saving"
|
||||
:errored="mfaParam.errored"
|
||||
text="确定"
|
||||
loadedText="设置成功"
|
||||
erroredText="设置失败"
|
||||
></ReactiveButton>
|
||||
</template>
|
||||
<a-form-model
|
||||
ref="mfaForm"
|
||||
:model="mfaParam"
|
||||
:rules="mfaParam.rules"
|
||||
layout="vertical"
|
||||
>
|
||||
<a-form-model-item
|
||||
v-if="mfaUsed"
|
||||
label="两步验证码"
|
||||
prop="authcode"
|
||||
>
|
||||
<a-input
|
||||
placeholder="两步验证码"
|
||||
v-model="mfaParam.authcode"
|
||||
:maxLength="6"
|
||||
>
|
||||
|
@ -258,11 +327,9 @@
|
|||
style="color: rgba(0,0,0,.25)"
|
||||
/>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<a-form v-else>
|
||||
<a-form-item
|
||||
</a-form-model-item>
|
||||
<a-form-model-item
|
||||
v-if="!mfaUsed"
|
||||
label="1. 请扫描二维码或导入 key"
|
||||
:help="`MFAKey:${mfaParam.mfaKey}`"
|
||||
>
|
||||
|
@ -273,10 +340,13 @@
|
|||
width="100%"
|
||||
:src="mfaParam.qrImage"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="2. 验证两步验证码">
|
||||
</a-form-model-item>
|
||||
<a-form-model-item
|
||||
v-if="!mfaUsed"
|
||||
label="2. 验证两步验证码"
|
||||
prop="authcode"
|
||||
>
|
||||
<a-input
|
||||
placeholder="两步验证码"
|
||||
v-model="mfaParam.authcode"
|
||||
:maxLength="6"
|
||||
>
|
||||
|
@ -286,8 +356,8 @@
|
|||
style="color: rgba(0,0,0,.25)"
|
||||
/>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -300,15 +370,64 @@ import MD5 from 'md5.js'
|
|||
|
||||
export default {
|
||||
data() {
|
||||
const validateConfirmPassword = (rule, value, callback) => {
|
||||
if (value && this.passwordForm.model.newPassword !== value) {
|
||||
callback(new Error('确认密码与新密码不一致'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
return {
|
||||
statisticsLoading: false,
|
||||
attachmentDrawerVisible: false,
|
||||
user: {},
|
||||
statistics: {},
|
||||
passwordParam: {
|
||||
oldPassword: null,
|
||||
newPassword: null,
|
||||
confirmPassword: null
|
||||
attachmentDrawer: {
|
||||
visible: false
|
||||
},
|
||||
userForm: {
|
||||
model: {},
|
||||
saving: false,
|
||||
errored: false,
|
||||
rules: {
|
||||
username: [
|
||||
{ required: true, message: '* 用户名不能为空', trigger: ['change', 'blur'] },
|
||||
{ max: 50, message: '* 用户名的字符长度不能超过 50', trigger: ['change', 'blur'] }
|
||||
],
|
||||
nickname: [
|
||||
{ required: true, message: '* 用户昵称不能为空', trigger: ['change', 'blur'] },
|
||||
{ max: 255, message: '* 用户昵称的字符长度不能超过 255', trigger: ['change', 'blur'] }
|
||||
],
|
||||
email: [
|
||||
{ required: true, message: '* 电子邮箱地址不能为空', trigger: ['change', 'blur'] },
|
||||
{ type: 'email', message: '* 电子邮箱地址格式不正确', trigger: ['change', 'blur'] },
|
||||
{ max: 127, message: '* 电子邮箱的字符长度不能超过 255', trigger: ['change', 'blur'] }
|
||||
],
|
||||
description: [{ max: 1023, message: '* 个人说明的字符长度不能超过 1023', trigger: ['change', 'blur'] }]
|
||||
}
|
||||
},
|
||||
statistics: {
|
||||
data: {},
|
||||
loading: false
|
||||
},
|
||||
passwordForm: {
|
||||
model: {
|
||||
oldPassword: null,
|
||||
newPassword: null,
|
||||
confirmPassword: null
|
||||
},
|
||||
saving: false,
|
||||
errored: false,
|
||||
rules: {
|
||||
oldPassword: [
|
||||
{ required: true, message: '* 原密码不能为空', trigger: ['change', 'blur'] },
|
||||
{ max: 100, min: 8, message: '* 密码的字符长度必须在 8 - 100 之间', trigger: ['blur'] }
|
||||
],
|
||||
newPassword: [
|
||||
{ required: true, message: '* 新密码不能为空', trigger: ['change', 'blur'] },
|
||||
{ max: 100, min: 8, message: '* 密码的字符长度必须在 8 - 100 之间', trigger: ['change', 'blur'] }
|
||||
],
|
||||
confirmPassword: [
|
||||
{ required: true, message: '* 确认密码不能为空', trigger: ['change', 'blur'] },
|
||||
{ validator: validateConfirmPassword, trigger: ['change', 'blur'] }
|
||||
]
|
||||
}
|
||||
},
|
||||
mfaParam: {
|
||||
mfaKey: null,
|
||||
|
@ -323,15 +442,16 @@ export default {
|
|||
switch: {
|
||||
loading: false,
|
||||
checked: false
|
||||
}
|
||||
},
|
||||
attachment: {}
|
||||
},
|
||||
rules: {
|
||||
authcode: [{ required: true, message: '* 两步验证码不能为空', trigger: ['change', 'blur'] }]
|
||||
},
|
||||
saving: false,
|
||||
errored: false
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
passwordUpdateButtonDisabled() {
|
||||
return !(this.passwordParam.oldPassword && this.passwordParam.newPassword)
|
||||
},
|
||||
...mapGetters(['options']),
|
||||
mfaType() {
|
||||
return this.mfaParam.mfaType
|
||||
|
@ -356,68 +476,82 @@ export default {
|
|||
methods: {
|
||||
...mapMutations({ setUser: 'SET_USER' }),
|
||||
handleLoadStatistics() {
|
||||
this.statisticsLoading = true
|
||||
this.statistics.loading = true
|
||||
statisticsApi
|
||||
.statisticsWithUser()
|
||||
.then(response => {
|
||||
this.user = response.data.data.user
|
||||
this.statistics = response.data.data
|
||||
this.mfaParam.mfaType = this.user.mfaType && this.user.mfaType
|
||||
this.userForm.model = response.data.data.user
|
||||
this.statistics.data = response.data.data
|
||||
this.mfaParam.mfaType = this.userForm.model.mfaType && this.userForm.model.mfaType
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
this.statisticsLoading = false
|
||||
this.statistics.loading = false
|
||||
}, 200)
|
||||
})
|
||||
},
|
||||
handleUpdatePassword() {
|
||||
// Check confirm password
|
||||
if (this.passwordParam.newPassword !== this.passwordParam.confirmPassword) {
|
||||
this.$message.error('确认密码和新密码不匹配!')
|
||||
return
|
||||
}
|
||||
userApi.updatePassword(this.passwordParam.oldPassword, this.passwordParam.newPassword).then(response => {
|
||||
this.$message.success('密码修改成功!')
|
||||
this.passwordParam.oldPassword = null
|
||||
this.passwordParam.newPassword = null
|
||||
this.passwordParam.confirmPassword = null
|
||||
const _this = this
|
||||
_this.$refs.passwordForm.validate(valid => {
|
||||
if (valid) {
|
||||
this.passwordForm.saving = true
|
||||
userApi
|
||||
.updatePassword(this.passwordForm.model.oldPassword, this.passwordForm.model.newPassword)
|
||||
.catch(() => {
|
||||
this.passwordForm.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
this.passwordForm.saving = false
|
||||
}, 400)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleUpdatedPasswordCallback() {
|
||||
if (this.passwordForm.errored) {
|
||||
this.passwordForm.errored = false
|
||||
} else {
|
||||
this.passwordForm.model.oldPassword = null
|
||||
this.passwordForm.model.newPassword = null
|
||||
this.passwordForm.model.confirmPassword = null
|
||||
}
|
||||
},
|
||||
handleUpdateProfile() {
|
||||
if (!this.user.username) {
|
||||
this.$notification['error']({
|
||||
message: '提示',
|
||||
description: '用户名不能为空!'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!this.user.nickname) {
|
||||
this.$notification['error']({
|
||||
message: '提示',
|
||||
description: '用户昵称不能为空!'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!this.user.email) {
|
||||
this.$notification['error']({
|
||||
message: '提示',
|
||||
description: '邮箱不能为空!'
|
||||
})
|
||||
return
|
||||
}
|
||||
userApi.updateProfile(this.user).then(response => {
|
||||
this.user = response.data.data
|
||||
this.setUser(Object.assign({}, this.user))
|
||||
this.$message.success('资料更新成功!')
|
||||
const _this = this
|
||||
_this.$refs.userForm.validate(valid => {
|
||||
if (valid) {
|
||||
this.userForm.saving = true
|
||||
userApi
|
||||
.updateProfile(this.userForm.model)
|
||||
.then(response => {
|
||||
this.userForm.model = response.data.data
|
||||
this.setUser(Object.assign({}, this.userForm.model))
|
||||
})
|
||||
.catch(() => {
|
||||
this.userForm.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
this.userForm.saving = false
|
||||
}, 400)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleUpdatedProfileCallback() {
|
||||
if (this.userForm.errored) {
|
||||
this.userForm.errored = false
|
||||
}
|
||||
},
|
||||
handleSelectAvatar(data) {
|
||||
this.user.avatar = encodeURI(data.path)
|
||||
this.attachmentDrawerVisible = false
|
||||
this.userForm.model.avatar = encodeURI(data.path)
|
||||
this.attachmentDrawer.visible = false
|
||||
},
|
||||
handleSelectGravatar() {
|
||||
this.user.avatar = '//cn.gravatar.com/avatar/' + new MD5().update(this.user.email).digest('hex') + '&d=mm'
|
||||
this.attachmentDrawerVisible = false
|
||||
this.userForm.model.avatar =
|
||||
'//cn.gravatar.com/avatar/' + new MD5().update(this.userForm.model.email).digest('hex') + '&d=mm'
|
||||
this.attachmentDrawer.visible = false
|
||||
},
|
||||
handleMFASwitch(useMFAuth) {
|
||||
// loding
|
||||
|
@ -440,19 +574,34 @@ export default {
|
|||
}
|
||||
},
|
||||
handleSetMFAuth() {
|
||||
var mfaType = this.mfaUsed ? 'NONE' : 'TFA_TOTP'
|
||||
if (mfaType === 'NONE') {
|
||||
if (!this.mfaParam.authcode) {
|
||||
this.$message.warn('两步验证码不能为空!')
|
||||
return
|
||||
const _this = this
|
||||
var mfaType = _this.mfaUsed ? 'NONE' : 'TFA_TOTP'
|
||||
_this.$refs.mfaForm.validate(valid => {
|
||||
if (valid) {
|
||||
_this.mfaParam.saving = true
|
||||
userApi
|
||||
.mfaUpdate(mfaType, _this.mfaParam.mfaKey, _this.mfaParam.authcode)
|
||||
.catch(() => {
|
||||
_this.mfaParam.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
_this.mfaParam.saving = false
|
||||
}, 400)
|
||||
})
|
||||
}
|
||||
}
|
||||
userApi.mfaUpdate(mfaType, this.mfaParam.mfaKey, this.mfaParam.authcode).then(response => {
|
||||
this.handleCloseMFAuthModal()
|
||||
this.mfaParam.mfaType = response.data.data.mfaType
|
||||
this.$message.success(this.mfaUsed ? '两步验证已关闭!' : '两步验证已开启,下次登陆生效!')
|
||||
})
|
||||
},
|
||||
handleSetMFAuthCallback() {
|
||||
const _this = this
|
||||
if (_this.mfaParam.errored) {
|
||||
_this.mfaParam.errored = false
|
||||
} else {
|
||||
_this.handleCloseMFAuthModal()
|
||||
_this.handleLoadStatistics()
|
||||
_this.$message.success(_this.mfaUsed ? '两步验证已关闭!' : '两步验证已开启,下次登陆生效!')
|
||||
}
|
||||
},
|
||||
handleCloseMFAuthModal() {
|
||||
this.mfaParam.modal.visible = false
|
||||
this.mfaParam.switch.loading = false
|
||||
|
|
Loading…
Reference in New Issue