修改:网站管理

This commit is contained in:
jmal 2021-02-09 16:16:46 +08:00
parent 9851a297ce
commit 65aa2f7605
6 changed files with 530 additions and 451 deletions

View File

@ -5,7 +5,7 @@
import { Icon } from 'ant-design-vue' import { Icon } from 'ant-design-vue'
const IconFont = Icon.createFromIconfontCN({ const IconFont = Icon.createFromIconfontCN({
scriptUrl: '//at.alicdn.com/t/font_2024484_poicam3vg6b.js' scriptUrl: '//at.alicdn.com/t/font_2024484_64i0l9tj8gq.js'
}) })
// 把此段代码贴到iconfont项目页面的控制台中, 以获取图标列表 // 把此段代码贴到iconfont项目页面的控制台中, 以获取图标列表
@ -16,7 +16,7 @@ const IconFont = Icon.createFromIconfontCN({
// console.log(iconNames.slice(80,160)) // console.log(iconNames.slice(80,160))
export const iconFonts = { export const iconFonts = {
list: ["disk-drive", "menu-fuzhi", "iso", "zuijinhuoyue","key", "shouquan", "sort", "grid", "list", "emoji-a", "emoji-bizui", "emoji-baiyan", "emoji-aixin", "emoji-dajing", "emoji-ziya", "emoji-daxiao", "emoji-esi", "emoji-fadai", "emoji-fankun", "emoji-ganga", "emoji-fennu", "emoji-hanyan", "emoji-jingkong", "emoji-haochi", "emoji-emo", "emoji-jingsong", "emoji-jingya", "emoji-kaixin", "emoji-lengku", "emoji-danao", "emoji-liukoushui", "emoji-liulei", "emoji-mengbi", "mianwubiaoqing", "nanguo", "shuizhuo", "taoyan", "tanchi", "siliao", "tiaopi", "xiaochulei", "wuliao", "xingxingyan", "xieyan", "xiasi", "xiaolian", "ku", "shengqi", "yousiliao", "en", "bushufu", "bianbian", "fankun1", "feiwen", "ganmao", "huaixiao", "liuhan", "outu", "keshui", "renzhe", "santiaoxian", "guaiwu", "shoushang", "tianshi", "shuai", "xianwen", "xiaodiaodaya", "xiong", "yiwen", "yun", "liubixie", "shimo", "dianzan", "biti", "fendou", "huqi", "heng", "kulou", "leng", "taoyan1", "shuixing", "aini", "aixin1", "zhadan", "xinsui", list: ["wulianwang-","zuji","disk-drive", "menu-fuzhi", "iso", "zuijinhuoyue","key", "shouquan", "sort", "grid", "list", "emoji-a", "emoji-bizui", "emoji-baiyan", "emoji-aixin", "emoji-dajing", "emoji-ziya", "emoji-daxiao", "emoji-esi", "emoji-fadai", "emoji-fankun", "emoji-ganga", "emoji-fennu", "emoji-hanyan", "emoji-jingkong", "emoji-haochi", "emoji-emo", "emoji-jingsong", "emoji-jingya", "emoji-kaixin", "emoji-lengku", "emoji-danao", "emoji-liukoushui", "emoji-liulei", "emoji-mengbi", "mianwubiaoqing", "nanguo", "shuizhuo", "taoyan", "tanchi", "siliao", "tiaopi", "xiaochulei", "wuliao", "xingxingyan", "xieyan", "xiasi", "xiaolian", "ku", "shengqi", "yousiliao", "en", "bushufu", "bianbian", "fankun1", "feiwen", "ganmao", "huaixiao", "liuhan", "outu", "keshui", "renzhe", "santiaoxian", "guaiwu", "shoushang", "tianshi", "shuai", "xianwen", "xiaodiaodaya", "xiong", "yiwen", "yun", "liubixie", "shimo", "dianzan", "biti", "fendou", "huqi", "heng", "kulou", "leng", "taoyan1", "shuixing", "aini", "aixin1", "zhadan", "xinsui",
"maren", "zhutou", "qie", "youling", "apple-fill", "attachment", "android-fill", "apple", "download", "arrow-up-circle", "arrow-right-circle", "arrow-down", "ashbin", "add", "file_music", "menu", "role", "jiaoseguanli", "yemianshezhi", "drop_down", "yuandian", "tag", "service-directory", "fabu", "wailian", "bianji-", "WEBSITE", "wangzhanguanli", "Up", "up", "fenlei", "guanlizhuanjiawenzhang", "pifu", "tuichudenglu", "shezhi", "wangzhan", "huaban", "yunshezhi", "UserSettings", "blogger", "biaoqian", "myself", "guidang", "quxiaoyulan1-copy", "yulan-copy", "quxiaoyulan1", "yulan"] "maren", "zhutou", "qie", "youling", "apple-fill", "attachment", "android-fill", "apple", "download", "arrow-up-circle", "arrow-right-circle", "arrow-down", "ashbin", "add", "file_music", "menu", "role", "jiaoseguanli", "yemianshezhi", "drop_down", "yuandian", "tag", "service-directory", "fabu", "wailian", "bianji-", "WEBSITE", "wangzhanguanli", "Up", "up", "fenlei", "guanlizhuanjiawenzhang", "pifu", "tuichudenglu", "shezhi", "wangzhan", "huaban", "yunshezhi", "UserSettings", "blogger", "biaoqian", "myself", "guidang", "quxiaoyulan1-copy", "yulan-copy", "quxiaoyulan1", "yulan"]
} }

View File

@ -2,13 +2,15 @@
<div v-loading="vditorLoading"> <div v-loading="vditorLoading">
<div class="article-editor"> <div class="article-editor">
<div class="editor-left"> <div class="editor-left">
<cite v-if="currentDarft">你正在编辑的是保存于 {{ file.updateDate }} 的草稿, 你也可以 <el-button type="text" style="color: #F56C6C" @click="deleteDraft">删除它</el-button></cite> <cite v-if="currentDarft">你正在编辑的是保存于 {{ file.updateDate }} 的草稿, 你也可以
<el-button type="text" style="color: #F56C6C" @click="deleteDraft">删除它</el-button>
</cite>
<el-header> <el-header>
<div class="header-item"> <div class="header-item">
<el-input class="articles-title" placeholder="标题" v-model="filename"/> <el-input class="articles-title" placeholder="标题" v-model="filename"/>
</div> </div>
<div class="url-slug"> <div class="url-slug">
<div>{{ articleLink }}</div> <div>{{ siteUrl + (alonePage ? '/o/' : '/s/') }}</div>
<edit-element <edit-element
ref="editElement" ref="editElement"
class="mark-setting-input" class="mark-setting-input"
@ -16,6 +18,9 @@
placeholder="缩略名" placeholder="缩略名"
can-edit can-edit
></edit-element> ></edit-element>
<a v-if="isEdit" class="view-icon" :title="'预览 '+filename" :href="siteUrl + (alonePage ? '/o/':'/s/')+file.slug" target="_blank">
<svg-icon class="wailian" icon-class="eye-open"></svg-icon>预览
</a>
</div> </div>
</el-header> </el-header>
<el-main> <el-main>
@ -24,8 +29,10 @@
</div> </div>
<div class="editor-right"> <div class="editor-right">
<div class="operation"> <div class="operation">
<el-button class="release-button" type="warning" size="small" @click="saveDraft" :loading="updating">保存草稿</el-button> <el-button class="release-button" type="warning" size="small" @click="saveDraft" :loading="updating">保存草稿
<el-button class="release-button" type="primary" size="small" @click="release" :loading="updating">发布文章</el-button> </el-button>
<el-button class="release-button" type="primary" size="small" @click="release" :loading="updating">发布文章
</el-button>
</div> </div>
<div class="more-setting"> <div class="more-setting">
<p class="mark-setting-label">发布日期:</p> <p class="mark-setting-label">发布日期:</p>
@ -37,7 +44,8 @@
format="yyyy-MM-dd HH:mm:ss"> format="yyyy-MM-dd HH:mm:ss">
</el-date-picker> </el-date-picker>
<p class="mark-setting-label">文章封面:</p> <p class="mark-setting-label">文章封面:</p>
<upload-image-input v-model="file.cover" placeholder="请输入文章封面大图的url" :intput-autosize="{ minRows: 2, maxRows: 6}"/> <upload-image-input v-model="file.cover" placeholder="请输入文章封面大图的url"
:intput-autosize="{ minRows: 2, maxRows: 6}"/>
<div v-if="!alonePage"> <div v-if="!alonePage">
<p class="mark-setting-label">分类:</p> <p class="mark-setting-label">分类:</p>
<multiple-tree-select <multiple-tree-select
@ -166,6 +174,14 @@
alonePage: { alonePage: {
type: Boolean, type: Boolean,
default: false default: false
},
siteUrl: {
type: String,
default: ''
},
isEdit: {
type: Boolean,
default: false
} }
}, },
data() { data() {
@ -183,7 +199,6 @@
categories: [], categories: [],
draft: false, draft: false,
currentDarft: false, currentDarft: false,
articleLink: `${window.origin}/artiles/`,
tags: [], tags: [],
dynamicTags: [], dynamicTags: [],
inputVisible: false, inputVisible: false,
@ -212,8 +227,7 @@
this.valueHasChanged() this.valueHasChanged()
} }
}, },
computed: { computed: {},
},
methods: { methods: {
reload() { reload() {
this.getMarkdown(true) this.getMarkdown(true)
@ -370,9 +384,7 @@
}, },
fieldName: 'files', fieldName: 'files',
filename(name) { filename(name) {
return name.replace(/[^(a-zA-Z0-9\u4e00-\u9fa5\.)]/g, ''). return name.replace(/[^(a-zA-Z0-9\u4e00-\u9fa5\.)]/g, '').replace(/[\?\\/:|<>\*\[\]\(\)\$%\{\}@~]/g, '').replace('/\\s/g', '')
replace(/[\?\\/:|<>\*\[\]\(\)\$%\{\}@~]/g, '').
replace('/\\s/g', '')
}, },
format(files, responseText) { format(files, responseText) {
let response = JSON.parse(responseText) let response = JSON.parse(responseText)
@ -500,27 +512,35 @@
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import "src/styles/setting"; @import "src/styles/setting";
/deep/ .el-main { /deep/ .el-main {
padding: 35px 20px 20px 20px; padding: 35px 20px 20px 20px;
.v-note-wrapper { .v-note-wrapper {
z-index: 200; z-index: 200;
} }
} }
/deep/ .el-header { /deep/ .el-header {
height: 43px !important; height: 43px !important;
} }
/deep/ .el-input-group { /deep/ .el-input-group {
width: unset; width: unset;
} }
/deep/ .header-item { /deep/ .header-item {
line-height: 40px; line-height: 40px;
padding: 5px 0 5px 0; padding: 5px 0 5px 0;
.release-button { .release-button {
float: right; float: right;
margin-left: 10px; margin-left: 10px;
} }
.el-input { .el-input {
width: 90%; width: 90%;
input[type='text'] { input[type='text'] {
font-weight: 900; font-weight: 900;
color: #000000 !important; color: #000000 !important;
@ -530,55 +550,68 @@
border-radius: 0; border-radius: 0;
} }
} }
.title-label { .title-label {
font-size: 16px; font-size: 16px;
font-weight: 500; font-weight: 500;
} }
} }
/deep/ .el-drawer__body { /deep/ .el-drawer__body {
.more-setting { .more-setting {
padding: 15px; padding: 15px;
} }
} }
/deep/ .more-setting { /deep/ .more-setting {
margin-top: 32px; margin-top: 32px;
padding-top: 15px; padding-top: 15px;
.el-input { .el-input {
width: 100%; width: 100%;
} }
.mark-setting-label { .mark-setting-label {
font-weight: bold; font-weight: bold;
margin-top: 10px !important; margin-top: 10px !important;
margin-bottom: 5px; margin-bottom: 5px;
} }
.mark-setting-input { .mark-setting-input {
width: 100%; width: 100%;
} }
.mark-description { .mark-description {
font-size: 12px; font-size: 12px;
font-weight: 100; font-weight: 100;
} }
} }
.article-editor { .article-editor {
min-width: 1160px; min-width: 1160px;
margin: auto; margin: auto;
display: flex; display: flex;
.editor-left { .editor-left {
width: 75%; width: 75%;
} }
.editor-right { .editor-right {
margin-top: 15px; margin-top: 15px;
width: 25%; width: 25%;
.operation { .operation {
float: right; float: right;
} }
} }
} }
.setting-tags { .setting-tags {
/deep/ .el-tag { /deep/ .el-tag {
margin-left: 8px; margin-left: 8px;
margin-top: 8px; margin-top: 8px;
} }
/deep/ .button-new-tag { /deep/ .button-new-tag {
margin-left: 8px; margin-left: 8px;
margin-top: 8px; margin-top: 8px;
@ -587,21 +620,25 @@
padding-top: 0; padding-top: 0;
padding-bottom: 0; padding-bottom: 0;
} }
/deep/ .input-new-tag { /deep/ .input-new-tag {
margin-left: 8px; margin-left: 8px;
margin-top: 8px; margin-top: 8px;
max-width: 94px; max-width: 94px;
vertical-align: bottom; vertical-align: bottom;
input { input {
padding: 0 5px; padding: 0 5px;
} }
} }
} }
/deep/ .input-error { /deep/ .input-error {
input { input {
border-color: #f56c6c; border-color: #f56c6c;
} }
} }
.instruction-error { .instruction-error {
color: #F56C6C; color: #F56C6C;
font-size: 12px; font-size: 12px;
@ -610,6 +647,7 @@
position: absolute; position: absolute;
margin-left: 8px; margin-left: 8px;
} }
/deep/ .el-autocomplete-suggestion { /deep/ .el-autocomplete-suggestion {
li { li {
padding: 0; padding: 0;
@ -622,14 +660,17 @@
margin: 2px 4px; margin: 2px 4px;
text-align: center; text-align: center;
} }
li:hover { li:hover {
background-color: #3f9eff; background-color: #3f9eff;
color: #fafdff; color: #fafdff;
} }
} }
/deep/ .el-autocomplete-suggestion__wrap { /deep/ .el-autocomplete-suggestion__wrap {
padding: 2px 0; padding: 2px 0;
} }
@media (min-width: 1200px) { @media (min-width: 1200px) {
.article-editor { .article-editor {
max-width: 1200px; max-width: 1200px;
@ -640,17 +681,21 @@
&:focus > .el-tree-node__content { &:focus > .el-tree-node__content {
background-color: unset; background-color: unset;
} }
.el-tree-node__content:hover { .el-tree-node__content:hover {
background-color: unset; background-color: unset;
} }
} }
.category-tree { .category-tree {
max-height: 500px; max-height: 500px;
overflow: auto; overflow: auto;
} }
/deep/ .url-slug { /deep/ .url-slug {
display: flex; display: flex;
color: #aaaaaa; color: #aaaaaa;
.mark-setting-input { .mark-setting-input {
font-size: 14px; font-size: 14px;
padding: 0 2px; padding: 0 2px;
@ -659,18 +704,27 @@
width: fit-content; width: fit-content;
min-width: 35px; min-width: 35px;
background-color: #ecf5ff; background-color: #ecf5ff;
&:focus { &:focus {
outline: none; outline: none;
} }
} }
} }
/deep/ .vditor-toolbar--pin { /deep/ .vditor-toolbar--pin {
top: unset; top: unset;
} }
/deep/ .el-scrollbar__wrap { /deep/ .el-scrollbar__wrap {
&::-webkit-scrollbar { &::-webkit-scrollbar {
width: 0; width: 0;
height: 0; height: 0;
} }
} }
.view-icon {
margin-left: 10px;
/deep/.svg-icon{
margin-right: 2px;
}
}
</style> </style>

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="container"> <div class="container">
<article-manager :page-title="pageTitle" alone-page></article-manager> <article-manager :page-title="pageTitle" :new-article-text="newArticleText" alone-page></article-manager>
</div> </div>
</template> </template>
@ -14,6 +14,7 @@ export default {
data() { data() {
return { return {
pageTitle: '管理独立页面', pageTitle: '管理独立页面',
newArticleText: '新增页面'
} }
}, },
computed: {}, computed: {},

View File

@ -9,14 +9,14 @@
@open="openDialog" @open="openDialog"
@close="closeDialog" @close="closeDialog"
> >
<markdown-editor ref="editor" :has-change.sync="hasChange" :alone-page="alonePage" @onTitle="onTitle" @onRelease="onRelease"></markdown-editor> <markdown-editor ref="editor" :has-change.sync="hasChange" :alone-page="alonePage" :site-url="siteUrl" :is-edit="isEdit" @onTitle="onTitle" @onRelease="onRelease"></markdown-editor>
</el-dialog> </el-dialog>
<el-card class="box-card"> <el-card class="box-card">
<div slot="header"> <div slot="header">
<div class="box-card-header"> <div class="box-card-header">
<div class="clearfix card-header-back"> <div class="clearfix card-header-back">
<span>{{ alonePage ? '管理独立页面':'管理文章' }}</span> <span>{{ alonePage ? '管理独立页面':'管理文章' }}</span>
<el-button class="card-button" size="mini" type="primary" @click="newArticle">写文章</el-button> <el-button class="card-button" size="mini" type="primary" @click="newArticle">{{newArticleText}}</el-button>
</div> </div>
<div class="card-header-right" v-show="this.multipleSelection.length > 0"> <div class="card-header-right" v-show="this.multipleSelection.length > 0">
<el-button size="small" type="danger" @click="handleDelete()">删除</el-button> <el-button size="small" type="danger" @click="handleDelete()">删除</el-button>
@ -90,7 +90,7 @@
label="标题"> label="标题">
<template slot-scope="scope"> <template slot-scope="scope">
<a :title="'编辑 '+scope.row.name" @click="editArticle(scope.row.id)">{{scope.row.name}}<svg-icon icon-class="bianji-"></svg-icon></a> <a :title="'编辑 '+scope.row.name" @click="editArticle(scope.row.id)">{{scope.row.name}}<svg-icon icon-class="bianji-"></svg-icon></a>
<router-link :title="'浏览 '+scope.row.name" :to="(alonePage?'/articles/o/':'/articles/s/')+scope.row.slug" target="_blank"><svg-icon class="wailian" icon-class="wailian"></svg-icon></router-link> <a :title="'浏览 '+scope.row.name" :href="(alonePage?siteUrl+'/o/':siteUrl+'/s/')+scope.row.slug" target="_blank"><svg-icon class="wailian" icon-class="wailian"></svg-icon></a>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
@ -158,6 +158,7 @@ import MarkdownEditor from '@/views/markdown/index'
import markdownApi from "@/api/markdown-api"; import markdownApi from "@/api/markdown-api";
import categoryApi from "@/api/category"; import categoryApi from "@/api/category";
import api from "@/api/file-api"; import api from "@/api/file-api";
import {getSetting} from '@/api/setting-api'
import MultipleTreeSelect from "@/components/select/MultipleTree"; import MultipleTreeSelect from "@/components/select/MultipleTree";
export default { export default {
name: 'articleManager', name: 'articleManager',
@ -173,6 +174,10 @@ export default {
alonePage: { alonePage: {
type: Boolean, type: Boolean,
default: false default: false
},
newArticleText: {
type: String,
default: ''
} }
}, },
data() { data() {
@ -199,6 +204,8 @@ export default {
}, },
draftNums: 0, draftNums: 0,
multipleSelection: [], multipleSelection: [],
siteUrl: `${window.location.origin}/articles`,
isEdit: false,
} }
}, },
computed: {}, computed: {},
@ -215,6 +222,7 @@ export default {
mounted() { mounted() {
this.getArticleList() this.getArticleList()
this.categoryTree() this.categoryTree()
this.getWebsiteSetting()
this.newArticleDialogVisible = !!this.$route.query.operation this.newArticleDialogVisible = !!this.$route.query.operation
// 监听返回 // 监听返回
if (window.history && window.history.pushState) { if (window.history && window.history.pushState) {
@ -312,6 +320,14 @@ export default {
const operation = this.$route.query.operation const operation = this.$route.query.operation
this.newArticleDialogVisible = !!operation; this.newArticleDialogVisible = !!operation;
}, },
// 获取网站设置
getWebsiteSetting() {
getSetting({userId: this.$store.state.user.userId}).then((res) => {
if(res.data) {
this.siteUrl = res.data.siteUrl
}
})
},
// 取消筛选 // 取消筛选
cancelFilter() { cancelFilter() {
this.query.userId = '' this.query.userId = ''
@ -394,8 +410,10 @@ export default {
newArticle() { newArticle() {
this.newArticleDialogVisible = true this.newArticleDialogVisible = true
this.$router.push({query: {operation: 'new'}}) this.$router.push({query: {operation: 'new'}})
this.isEdit = false
}, },
editArticle(id) { editArticle(id) {
this.isEdit = true
this.newArticleDialogVisible = true this.newArticleDialogVisible = true
this.$router.push({query: {operation: 'editor', id: id}}) this.$router.push({query: {operation: 'editor', id: id}})
if(this.$refs.editor){ if(this.$refs.editor){
@ -431,9 +449,11 @@ export default {
if(this.alonePage){ if(this.alonePage){
this.title = '创建新页面 ' + val this.title = '创建新页面 ' + val
} }
this.isEdit = false
} }
if(operation === 'editor'){ if(operation === 'editor'){
this.title = '编辑:' + val this.title = '编辑:' + val
this.isEdit = true
} }
}, },
openDialog() { openDialog() {

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="container"> <div class="container">
<article-manager :page-title="pageTitle"></article-manager> <article-manager :page-title="pageTitle" :new-article-text="newArticleText"></article-manager>
</div> </div>
</template> </template>
@ -15,6 +15,7 @@ export default {
data() { data() {
return { return {
pageTitle: '管理文章', pageTitle: '管理文章',
newArticleText: '写文章'
} }
}, },
computed: {}, computed: {},

View File

@ -12,8 +12,10 @@
<el-tabs v-model="activeName" @tab-click="handleClick"> <el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="网站首页背景" name="1"> <el-tab-pane label="网站首页背景" name="1">
<div class="config-itme-label">站点背景大图: <div class="config-itme-label">站点地址:</div>
</div> <el-input autosize type="textarea" width="100%" v-model="form.siteUrl"></el-input>
<span class="instruction">在这里填入站点的地址或域名。例如:<a href="https://blog.jmal.top" target="_blank">https://blog.jmal.top</a></span>
<div class="config-itme-label">站点背景大图:</div>
<upload-image-input v-model="form.backgroundSite"/> <upload-image-input v-model="form.backgroundSite"/>
<span class="instruction">在这里填入图片的URL地址, 以在网站首页显示一个背景大图。</span> <span class="instruction">在这里填入图片的URL地址, 以在网站首页显示一个背景大图。</span>
<div class="config-itme-label">首页大图内文字:</div> <div class="config-itme-label">首页大图内文字:</div>
@ -95,6 +97,7 @@ export default {
activeName: '1', activeName: '1',
example: '<i class="fab fa-github">github</i>', example: '<i class="fab fa-github">github</i>',
form: { form: {
siteUrl: '',
backgroundSite: '', backgroundSite: '',
backgroundTextSite: '', backgroundTextSite: '',
backgroundDescSite: '', backgroundDescSite: '',