diff --git a/src/api/tag.js b/src/api/tag.js
new file mode 100644
index 0000000..5ea073e
--- /dev/null
+++ b/src/api/tag.js
@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+const qs = require('qs')
+
+export default {
+ tagList(params) {
+ return request({
+ url: 'tag/list',
+ method: 'get',
+ params
+ })
+ },
+ tagInfo(params) {
+ return request({
+ url: 'tag/info',
+ method: 'get',
+ params
+ })
+ },
+ add(data) {
+ return request({
+ url: 'tag/add',
+ method: 'post',
+ data
+ })
+ },
+ update(data) {
+ return request({
+ url: 'tag/update',
+ method: 'put',
+ data
+ })
+ },
+ delete(params) {
+ return request({
+ url: 'tag/delete',
+ method: 'delete',
+ params,
+ paramsSerializer: function(params) {
+ return qs.stringify(params, { arrayFormat: 'repeat' })
+ }
+ })
+ }
+}
+
diff --git a/src/router/index.js b/src/router/index.js
index 410f7a8..6788161 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -249,6 +249,12 @@ export const constantRoutes = [
name: 'manager-categories',
component: () => import('@/views/setting/articles/categoryManager'),
meta: { title: '分类管理', icon: 'fenlei' }
+ },
+ {
+ path: 'manager-tags',
+ name: 'manager-tags',
+ component: () => import('@/views/setting/articles/tagManager'),
+ meta: { title: '标签管理', icon: 'biaoqian' }
}
]
},
diff --git a/src/styles/setting.scss b/src/styles/setting.scss
index 7312cc2..7822023 100644
--- a/src/styles/setting.scss
+++ b/src/styles/setting.scss
@@ -103,6 +103,14 @@ a:hover {
margin-top: 10px;
max-width: 300px;
}
+.el-form-item__content {
+ .instruction {
+ font-size: 12px;
+ line-height: 1;
+ padding-top: 4px;
+ position: absolute;
+ }
+}
.instruction {
color: #9a9a9a;
font-size: .8125rem;
diff --git a/src/views/markdown/index.vue b/src/views/markdown/index.vue
index 81e1772..cb4cef4 100644
--- a/src/views/markdown/index.vue
+++ b/src/views/markdown/index.vue
@@ -19,13 +19,13 @@
-
+
保存草稿
- {{ editStatus?'发布文章':'更新文章' }}
+ {{ editStatus?'更新文章':'发布文章' }}
文章封面:
@@ -55,6 +55,38 @@
clearable
@change="selectCategory"
>
+
标签:
+
+ {{tag}}
+
+
+
+
+
+
+
+
+
+
+
+
+
该标签已存在
+
+ New Tag
@@ -86,6 +118,7 @@
import Vditor from 'vditor'
import "vditor/src/assets/scss/index.scss"
import categoryApi from "@/api/category";
+ import tagApi from "@/api/tag";
let toolbar = [
'emoji',
@@ -158,12 +191,21 @@
categories: [],
categoryIdsList: [],
draft: false,
- articleLink: `${window.origin}/artiles/`
+ articleLink: `${window.origin}/artiles/`,
+ tags: [],
+ dynamicTags: [],
+ inputVisible: false,
+ inputValue: '',
+ inputValueExist: false,
+ inputNewTagClass: 'input-new-tag',
+ inputErrorClass: 'input-error',
+ vditorLoading: true,
}
},
mounted() {
this.getMarkdown()
this.categoryTree()
+ this.getTags()
const that = this
window.onresize = function temp() {
that.reHeight()
@@ -186,6 +228,20 @@
this.getMarkdown(true)
this.categoryTree()
},
+ querySearch(queryString, cb) {
+ let tags = this.tags
+ let results = queryString ? tags.filter((tag) => {
+ return (tag.name.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
+ }) : tags
+ // 调用 callback 返回建议列表的数据
+ results = results.map(res => {
+ return {value: res.name}
+ })
+ cb(results)
+ },
+ handleSelect(item){
+ this.handleInputConfirm()
+ },
valueHasChanged(){
this.$emit('update:hasChange', true)
},
@@ -195,24 +251,29 @@
markdownApi.getMarkdown({
mark: this.$route.query.id
}).then((res) => {
- this.file = res.data
- this.content = this.file.contentText
- this.filename = this.file.name.split('.md')[0]
- this.storageLocation = res.data.path
- if(this.categories && this.categories.length > 0){
- this.findCategoryIds(null, this.categories, this.file.categoryIds)
- }
// 初始化编辑器
if(isReload){
this.contentEditor.setValue(res.data.contentText)
} else {
this.vditorInit(res.data.contentText)
}
+ this.file = res.data
+ this.content = this.file.contentText
+ this.filename = this.file.name.split('.md')[0]
+ this.storageLocation = res.data.path
+ // 加载分类
+ if(this.categories && this.categories.length > 0){
+ this.findCategoryIds(null, this.categories, this.file.categoryIds)
+ }
+ // 加载标签
+ if(this.tags && this.tags.length > 0) {
+ this.loadDynamicTags()
+ }
}).then(() => {
const that = this
setTimeout(function (){
that.$emit('update:hasChange', false)
- }, 100)
+ }, 200)
})
} else {
if(isReload){
@@ -223,13 +284,46 @@
}
},
categoryTree() {
- categoryApi.categoryTree({userId: this.$store.state.user.userId}).then(res => {
+ categoryApi.categoryTree().then(res => {
this.categories = res.data
if(this.file.categoryIds && this.file.categoryIds.length > 0){
this.findCategoryIds(null, this.categories, this.file.categoryIds)
}
})
},
+ getTags() {
+ tagApi.tagList().then(res => {
+ this.tags = res.data
+ if(this.file.tagIds && this.file.tagIds.length > 0) {
+ this.loadDynamicTags()
+ }
+ })
+ },
+ loadDynamicTags() {
+ this.dynamicTags = this.tags.filter(tag => this.file.tagIds.includes(tag.id)).map(tag => tag.name)
+ },
+ handleClose(tag) {
+ this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1)
+ },
+ showInput() {
+ this.inputVisible = true
+ this.$nextTick(_ => {
+ this.$refs.saveTagInput.$refs.input.focus()
+ });
+ },
+ handleInputConfirm() {
+ let inputValue = this.inputValue
+ if (inputValue) {
+ if (this.dynamicTags.includes(inputValue)){
+ this.inputValueExist = true
+ return
+ }
+ this.dynamicTags.push(inputValue)
+ }
+ this.inputValueExist = false
+ this.inputVisible = false
+ this.inputValue = ''
+ },
findCategoryIds(parentCategory, categories, categoryIds) {
if(!categoryIds){
return
@@ -269,6 +363,7 @@
},
after: () => {
this.contentEditor.setValue(content)
+ console.log('sdf')
},
input: (val) => {
this.valueHasChanged()
@@ -374,6 +469,7 @@
isDraft: this.draft,
slug: this.file.slug ? this.file.slug : this.filename,
categoryIds: categoryIds,
+ tagNames: this.dynamicTags,
currentDirectory: this.storageLocation,
contentText: this.contentEditor.getValue()
}).then(() => {
@@ -469,7 +565,37 @@
}
}
}
-
+/deep/ .el-tag {
+ margin-left: 8px;
+ margin-top: 8px;
+}
+/deep/ .button-new-tag {
+ margin-left: 8px;
+ margin-top: 8px;
+ height: 32px;
+ line-height: 30px;
+ padding-top: 0;
+ padding-bottom: 0;
+}
+/deep/ .input-new-tag {
+ margin-left: 8px;
+ margin-top: 8px;
+ max-width: 94px;
+ vertical-align: bottom;
+}
+/deep/ .input-error {
+ input {
+ border-color: #f56c6c;
+ }
+}
+.instruction-error {
+ color: #F56C6C;
+ font-size: 12px;
+ line-height: 1;
+ padding-top: 4px;
+ position: absolute;
+ margin-left: 8px;
+}
@media (min-width: 1200px) {
.article-editor {
max-width: 1200px;
diff --git a/src/views/setting/articles/articleManager.vue b/src/views/setting/articles/articleManager.vue
index 4e49cc1..905f3f6 100644
--- a/src/views/setting/articles/articleManager.vue
+++ b/src/views/setting/articles/articleManager.vue
@@ -286,7 +286,7 @@ export default {
}
},
categoryTree() {
- categoryApi.categoryTree({userId: this.$store.state.user.userId}).then(res => {
+ categoryApi.categoryTree().then(res => {
this.categories = res.data
if(this.$route.query.categoryIds){
this.query.categoryIds = this.$route.query.categoryIds
diff --git a/src/views/setting/articles/categoryManager.vue b/src/views/setting/articles/categoryManager.vue
index ccb5c66..189265a 100644
--- a/src/views/setting/articles/categoryManager.vue
+++ b/src/views/setting/articles/categoryManager.vue
@@ -6,7 +6,8 @@
-
+
+ 分类缩略名用于创建友好的链接形式.
-
+
+ 此文字用于描述分类, 在该分类首页中它会被显示.
+
+
+
+ 在这里填入图片的URL地址, 以在分类页面显示一个背景大图.
{
this.categoryList = res.data
})
},
categoryTree() {
- categoryApi.categoryTree({userId: this.$store.state.user.userId}).then(res => {
+ categoryApi.categoryTree().then(res => {
this.categories = res.data
})
},
@@ -253,7 +259,6 @@ export default {
categoryApi.delete({categoryIds: categoryIds}).then(() => {
this.onDeleted()
}).catch(() => {
- console.log('sdf')
this.onError()
})
})
@@ -268,9 +273,6 @@ export default {
},
// 添加分类
addCategory(data) {
- if (!this.form.hasOwnProperty('userId')) {
- data.append('userId', this.$store.state.user.userId)
- }
categoryApi.add(data).then(() => {
this.onSuccess()
}).catch(() => {
diff --git a/src/views/setting/articles/tagManager.vue b/src/views/setting/articles/tagManager.vue
new file mode 100644
index 0000000..da6d7be
--- /dev/null
+++ b/src/views/setting/articles/tagManager.vue
@@ -0,0 +1,244 @@
+
+
+
+
+
+
+
+
+
+ 标签缩略名用于创建友好的链接形式, 如果留空则默认使用标签名称.
+
+
+
+ 在这里填入图片的URL地址, 以在该标签页面显示一个背景大图.
+
+
+ 保 存
+
+
+
+
+
+
+
+
+
+ {{tag.name}}
+
+
+
+
+
+
+
+
+
+
+
+