1. 文章管理 2. 评论管理
This commit is contained in:
parent
ca7e8e5e97
commit
25b2b81147
0
assets/weixinStore.jpg
Normal file
0
assets/weixinStore.jpg
Normal file
@ -10,6 +10,14 @@
|
||||
<i class="el-icon-s-data"></i>
|
||||
<span slot="title">Dashboard</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="admin-articles">
|
||||
<i class="el-icon-s-custom"></i>
|
||||
<span slot="title">文章管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="admin-comments">
|
||||
<i class="el-icon-s-custom"></i>
|
||||
<span slot="title">评论管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="admin-users">
|
||||
<i class="el-icon-s-custom"></i>
|
||||
<span slot="title">用户管理</span>
|
||||
|
213
pages/admin/articles.vue
Normal file
213
pages/admin/articles.vue
Normal file
@ -0,0 +1,213 @@
|
||||
<template>
|
||||
<el-row style="margin-top: 20px;">
|
||||
<el-col style="margin-bottom: 1rem;">
|
||||
<el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item :to="{ path: '/admin/dashboard' }">首页</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>文章管理</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
</el-col>
|
||||
<el-col style="margin-bottom: 1rem;">
|
||||
<el-pagination
|
||||
:hide-on-single-page="true"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="pagination.currentPage"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="pagination.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="pagination.total">
|
||||
</el-pagination>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<el-table
|
||||
:data="articles"
|
||||
style="width: 100%">
|
||||
<el-table-column
|
||||
label="#"
|
||||
width="40"
|
||||
prop="idArticle">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="标题"
|
||||
prop="articleTitle">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" @click="showArticleDetail(scope.row.articlePermalink)">{{ scope.row.articleTitle }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="标签"
|
||||
prop="articleTitle">
|
||||
<template slot-scope="scope">
|
||||
<el-tag
|
||||
style="margin-left: 0.5rem;"
|
||||
v-for="tag in scope.row.tags"
|
||||
:key="tag.idTag"
|
||||
size="mini"
|
||||
effect="plain">
|
||||
# {{ tag.tagTitle }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="作者"
|
||||
width="100"
|
||||
prop="articleAuthorName">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="最后更新时间"
|
||||
width="110"
|
||||
prop="updatedTime">
|
||||
</el-table-column>
|
||||
<el-table-column label="操作">
|
||||
<template slot-scope="scope">
|
||||
<el-button v-if="scope.row.articlePerfect === '1'" size="mini" @click="cancelPreference(scope.$index, scope.row.idArticle)" plain>取消优选</el-button>
|
||||
<el-button v-else size="mini" @click="setPreference(scope.$index, scope.row.idArticle)" plain>设为优选</el-button>
|
||||
<el-button size="mini" type="primary"
|
||||
@click="updateTags(scope.$index, scope.row)" plain>编辑标签
|
||||
</el-button>
|
||||
<el-button v-if="scope.row.articleStatus === '0'" size="mini" type="danger"
|
||||
@click="toggleStatus(scope.$index, scope.row)" plain>下架
|
||||
</el-button>
|
||||
<el-button v-else size="mini" type="success"
|
||||
@click="toggleStatus(scope.$index, scope.row)" plain>上架
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<el-pagination
|
||||
:hide-on-single-page="true"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="pagination.currentPage"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="pagination.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="pagination.total">
|
||||
</el-pagination>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<el-dialog :visible.sync="dialogVisible">
|
||||
<edit-tags
|
||||
:idArticle="idArticle"
|
||||
:tags="articleTags"
|
||||
@closeDialog="closeTagsDialog">
|
||||
</edit-tags>
|
||||
</el-dialog>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex';
|
||||
import EditTags from '~/components/widget/tags';
|
||||
|
||||
export default {
|
||||
name: "articles",
|
||||
components: {
|
||||
EditTags
|
||||
},
|
||||
fetch({store, params, error}) {
|
||||
return Promise.all([
|
||||
store
|
||||
.dispatch('admin/fetchArticles', params)
|
||||
.catch(err => error({statusCode: 404}))
|
||||
])
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
articles: state => state.admin.article.articles,
|
||||
pagination: state => state.admin.article.pagination
|
||||
})
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
order: 'desc',
|
||||
idRole: 0,
|
||||
idUser: 0,
|
||||
dialogVisible: false,
|
||||
index: Number,
|
||||
idArticle: Number,
|
||||
articleTags: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSizeChange(pageSize) {
|
||||
let _ts = this;
|
||||
_ts.$store.dispatch('admin/fetchArticles', {
|
||||
page: _ts.pagination.currentPage,
|
||||
rows: pageSize
|
||||
})
|
||||
},
|
||||
handleCurrentChange(page) {
|
||||
let _ts = this;
|
||||
_ts.$store.dispatch('admin/fetchArticles', {
|
||||
page: page,
|
||||
rows: _ts.pagination.pageSize
|
||||
})
|
||||
},
|
||||
toggleStatus() {},
|
||||
setPreference(index, idArticle) {
|
||||
let _ts = this;
|
||||
_ts.$axios.$patch("/api/article/update-perfect", {
|
||||
idArticle: idArticle,
|
||||
articlePerfect: '1'
|
||||
}).then(function (res) {
|
||||
if (res) {
|
||||
if (res.success) {
|
||||
_ts.$store.commit('admin/updateArticlePreference', {
|
||||
index: index,
|
||||
idArticle: idArticle,
|
||||
articlePerfect: '1'
|
||||
})
|
||||
_ts.$message.success("设置成功!");
|
||||
} else {
|
||||
_ts.$message.error(_ts.message);
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
cancelPreference(index, idArticle) {
|
||||
let _ts = this;
|
||||
_ts.$axios.$patch("/api/article/update-perfect", {
|
||||
idArticle: idArticle,
|
||||
articlePerfect: '0'
|
||||
}).then(function (res) {
|
||||
if (res) {
|
||||
if (res.success) {
|
||||
_ts.$store.commit('admin/updateArticlePreference', {
|
||||
index: index,
|
||||
idArticle: idArticle,
|
||||
articlePerfect: '0'
|
||||
})
|
||||
_ts.$message.success("取消成功!");
|
||||
} else {
|
||||
_ts.$message.error(_ts.message);
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
updateTags(index, article) {
|
||||
let _ts = this
|
||||
_ts.$set(_ts, 'index', index);
|
||||
_ts.$set(_ts, 'idArticle', article.idArticle);
|
||||
_ts.$set(_ts, 'articleTags', article.articleTags);
|
||||
_ts.$set(_ts, 'dialogVisible', true);
|
||||
},
|
||||
closeTagsDialog() {
|
||||
this.$set(this, 'dialogVisible', false);
|
||||
},
|
||||
showArticleDetail(articlePermalink) {
|
||||
window.open(articlePermalink);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$store.commit("setActiveMenu", "admin-articles");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
164
pages/admin/comments.vue
Normal file
164
pages/admin/comments.vue
Normal file
@ -0,0 +1,164 @@
|
||||
<template>
|
||||
<el-row class="article__wrapper" style="margin-top: 20px;">
|
||||
<el-col style="margin-bottom: 1rem;">
|
||||
<el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item :to="{ path: '/admin/dashboard' }">首页</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>评论管理</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<el-pagination
|
||||
:hide-on-single-page="true"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="pagination.currentPage"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="pagination.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="pagination.total">
|
||||
</el-pagination>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<el-col v-for="comment in comments" :key="comment.idComment">
|
||||
<el-card style="margin-top: 1rem;" :id="'comment-' + comment.idComment">
|
||||
<el-col :xs="3" :sm="1" :xl="1">
|
||||
<el-avatar v-show="comment.commenter.userAvatarURL" :src="comment.commenter.userAvatarURL"></el-avatar>
|
||||
<el-avatar v-show="!comment.commenter.userAvatarURL"
|
||||
src="https://static.rymcu.com/article/1578475481946.png"></el-avatar>
|
||||
</el-col>
|
||||
<el-col :xs="21" :sm="23" :xl="23">
|
||||
<el-col style="margin-left: 1rem;">
|
||||
<el-col v-show="comment.commentOriginalCommentId">
|
||||
<el-col :span="16">
|
||||
<el-link rel="nofollow" @click="onRouter('user', comment.commenter.userAccount)" :underline="false"
|
||||
class="text-default">{{ comment.commenter.userNickname }}
|
||||
</el-link>
|
||||
<small class="text-default" style="margin: 0 0.2rem">回复了</small><span style="font-weight: bold;"> {{comment.commentOriginalAuthorNickname}}</span>
|
||||
</el-col>
|
||||
<el-col :span="8" class="text-right" style="padding-right: 1rem;">
|
||||
<el-link rel="nofollow" :underline="false" title="查看原评论"
|
||||
@click.native="toggleShowOriginalComment(comment.commentOriginalCommentId)"><i
|
||||
class="el-icon-reading"></i> 查看原评论</el-link>
|
||||
</el-col>
|
||||
</el-col>
|
||||
<el-col v-show="!comment.commentOriginalCommentId">
|
||||
<el-col :span="16">
|
||||
<el-link rel="nofollow" @click="onRouter('user', comment.commenter.userAccount)" :underline="false"
|
||||
class="text-default">{{ comment.commenter.userNickname }}
|
||||
</el-link>
|
||||
</el-col>
|
||||
</el-col>
|
||||
</el-col>
|
||||
<el-col style="padding: 1rem;">
|
||||
<el-col>
|
||||
<div class="vditor-reset comment-content" v-html="comment.commentContent"></div>
|
||||
</el-col>
|
||||
</el-col>
|
||||
<el-col :span="16" style="padding-left: 1rem;">
|
||||
<el-link rel="nofollow" :underline="false" class="text-default">{{ comment.timeAgo }}</el-link>
|
||||
</el-col>
|
||||
</el-col>
|
||||
</el-card>
|
||||
<el-col :id="'original-' + comment.commentOriginalCommentId" style="background-color: #d9d9d9;padding-left: 1.5rem;
|
||||
margin-top: 0.3rem;border-radius: 0.5rem;cursor: pointer;display: none;">
|
||||
<el-col v-show="comment.commentOriginalCommentId" :span="2">
|
||||
<p>
|
||||
<span>{{comment.commentOriginalAuthorNickname}} :</span>
|
||||
</p>
|
||||
</el-col>
|
||||
<el-col v-show="comment.commentOriginalCommentId" :span="20">
|
||||
<div class="vditor-reset comment-content" v-html="comment.commentOriginalContent"></div>
|
||||
</el-col>
|
||||
</el-col>
|
||||
</el-col>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<el-pagination
|
||||
:hide-on-single-page="true"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="pagination.currentPage"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="pagination.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="pagination.total">
|
||||
</el-pagination>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex';
|
||||
|
||||
export default {
|
||||
name: "comments",
|
||||
fetch({store, params, error}) {
|
||||
return Promise.all([
|
||||
store
|
||||
.dispatch('admin/fetchComments', params)
|
||||
.catch(err => error({statusCode: 404}))
|
||||
])
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
comments: state => state.admin.comment.comments,
|
||||
pagination: state => state.admin.comment.pagination
|
||||
})
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
order: 'desc',
|
||||
idRole: 0,
|
||||
idUser: 0,
|
||||
dialogVisible: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onRouter(name, data) {
|
||||
this.$router.push(
|
||||
{
|
||||
path: '/user/' + data
|
||||
}
|
||||
)
|
||||
},
|
||||
toggleShowOriginalComment(commentId) {
|
||||
let ele = document.getElementById('original-' + commentId);
|
||||
if (ele.style.display === 'none') {
|
||||
ele.style.display = 'block';
|
||||
} else {
|
||||
ele.style.display = 'none';
|
||||
}
|
||||
},
|
||||
handleSizeChange(pageSize) {
|
||||
let _ts = this;
|
||||
_ts.$store.dispatch('admin/fetchComments', {
|
||||
page: _ts.pagination.currentPage,
|
||||
rows: pageSize
|
||||
})
|
||||
},
|
||||
handleCurrentChange(page) {
|
||||
let _ts = this;
|
||||
_ts.$store.dispatch('admin/fetchComments', {
|
||||
page: page,
|
||||
rows: _ts.pagination.pageSize
|
||||
})
|
||||
},
|
||||
toggleStatus() {}
|
||||
},
|
||||
mounted() {
|
||||
this.$store.commit("setActiveMenu", "admin-comments");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "~vditor/src/assets/scss/index.scss";
|
||||
|
||||
.article__wrapper {
|
||||
margin: 20px auto;
|
||||
display: block;
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
@ -21,18 +21,64 @@
|
||||
<el-input v-model="topic.topicUri"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="图标">
|
||||
<el-upload
|
||||
class="avatar-uploader"
|
||||
:action="tokenURL.URL"
|
||||
:multiple="true"
|
||||
:with-credentials="true"
|
||||
:headers="uploadHeaders"
|
||||
:show-file-list="false"
|
||||
:on-success="handleAvatarSuccess"
|
||||
:before-upload="beforeAvatarUpload">
|
||||
<img v-if="topicIconPath" class="topic-brand-img" :src="topicIconPath">
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<vue-cropper
|
||||
ref="cropper"
|
||||
:aspect-ratio="1 / 1"
|
||||
:src="topicIconPath"
|
||||
:checkCrossOrigin="false"
|
||||
:checkOrientation="false"
|
||||
:imgStyle="{width: '480px', height: '480px'}"
|
||||
:autoCropArea="1"
|
||||
:autoCrop="autoCrop"
|
||||
preview=".preview"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="24" style="margin-top: 2rem;">
|
||||
<el-col :span="8">
|
||||
<el-card>
|
||||
<div class="card-body d-flex flex-column">
|
||||
<el-col :span="4" style="text-align: right;">
|
||||
<div v-if="topicIconPath" class="preview preview-large topic-brand-img"/>
|
||||
<el-image v-else class="topic-brand-img" />
|
||||
</el-col>
|
||||
<el-col :span="20">
|
||||
<el-col>
|
||||
<el-col>
|
||||
<el-link rel="nofollow" :underline="false">
|
||||
<h4>{{ topic.topicTitle }}</h4>
|
||||
</el-link>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<div class="text-muted article-summary-md">{{ topic.topicDescription }}</div>
|
||||
</el-col>
|
||||
</el-col>
|
||||
</el-col>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-col>
|
||||
<el-col :span="24" style="margin-top: 2rem;">
|
||||
<el-upload
|
||||
class="avatar-uploader"
|
||||
action=""
|
||||
:multiple="true"
|
||||
:show-file-list="false"
|
||||
:on-success="handleAvatarSuccess"
|
||||
:before-upload="beforeAvatarUpload">
|
||||
<div>
|
||||
<el-button type="primary" round plain>上传</el-button>
|
||||
</div>
|
||||
</el-upload>
|
||||
<el-button style="margin-top: 1rem;" type="primary" round plain @click.prevent="reset">重置</el-button>
|
||||
<el-button type="primary" round plain @click.prevent="cropImage">裁剪</el-button>
|
||||
<el-col>
|
||||
<span style="color: red;padding-right: 5px;">*</span>
|
||||
<span>上传图片调整至最佳效果后,请点击裁剪按钮截取</span>
|
||||
</el-col>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item label="导航主题">
|
||||
<el-switch
|
||||
@ -71,14 +117,21 @@
|
||||
|
||||
<script>
|
||||
import Vue from 'vue';
|
||||
import {mapState} from 'vuex';
|
||||
import VueCropper from 'vue-cropperjs';
|
||||
import 'cropperjs/dist/cropper.css';
|
||||
|
||||
export default {
|
||||
name: "adminTopicPost",
|
||||
components: {
|
||||
VueCropper
|
||||
},
|
||||
computed: {
|
||||
uploadHeaders() {
|
||||
let token = this.$store.getters.uploadHeaders;
|
||||
return {'X-Upload-Token': token}
|
||||
}
|
||||
...mapState({
|
||||
uploadHeaders: state => {
|
||||
return {'X-Upload-Token': state.uploadHeaders}
|
||||
}
|
||||
})
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -107,6 +160,7 @@ export default {
|
||||
},
|
||||
topicIconPath: '',
|
||||
isEdit: false,
|
||||
autoCrop: true,
|
||||
notificationFlag: true
|
||||
}
|
||||
},
|
||||
@ -114,44 +168,44 @@ export default {
|
||||
_initEditor(data) {
|
||||
let _ts = this;
|
||||
|
||||
let toolbar = [
|
||||
'emoji',
|
||||
'headings',
|
||||
'bold',
|
||||
'italic',
|
||||
'strike',
|
||||
'link',
|
||||
'|',
|
||||
'list',
|
||||
'ordered-list',
|
||||
'check',
|
||||
'outdent',
|
||||
'indent',
|
||||
'|',
|
||||
'quote',
|
||||
'line',
|
||||
'code',
|
||||
'inline-code',
|
||||
'insert-before',
|
||||
'insert-after',
|
||||
'|',
|
||||
'upload',
|
||||
// 'record',
|
||||
'table',
|
||||
'|',
|
||||
'undo',
|
||||
'redo',
|
||||
'|',
|
||||
'edit-mode',
|
||||
{
|
||||
name: 'more',
|
||||
toolbar: [
|
||||
'fullscreen',
|
||||
'both',
|
||||
'preview',
|
||||
'info'
|
||||
],
|
||||
}]
|
||||
let toolbar = [
|
||||
'emoji',
|
||||
'headings',
|
||||
'bold',
|
||||
'italic',
|
||||
'strike',
|
||||
'link',
|
||||
'|',
|
||||
'list',
|
||||
'ordered-list',
|
||||
'check',
|
||||
'outdent',
|
||||
'indent',
|
||||
'|',
|
||||
'quote',
|
||||
'line',
|
||||
'code',
|
||||
'inline-code',
|
||||
'insert-before',
|
||||
'insert-after',
|
||||
'|',
|
||||
'upload',
|
||||
// 'record',
|
||||
'table',
|
||||
'|',
|
||||
'undo',
|
||||
'redo',
|
||||
'|',
|
||||
'edit-mode',
|
||||
{
|
||||
name: 'more',
|
||||
toolbar: [
|
||||
'fullscreen',
|
||||
'both',
|
||||
'preview',
|
||||
'info'
|
||||
],
|
||||
}]
|
||||
return new Vue.Vditor(data.id, {
|
||||
toolbar,
|
||||
mode: 'sv',
|
||||
@ -191,9 +245,7 @@ export default {
|
||||
url: this.tokenURL.URL,
|
||||
linkToImgUrl: this.tokenURL.linkToImageURL,
|
||||
token: this.tokenURL.token,
|
||||
filename: name => name.replace(/[^(a-zA-Z0-9\u4e00-\u9fa5\.)]/g, '').
|
||||
replace(/[\?\\/:|<>\*\[\]\(\)\$%\{\}@~]/g, '').
|
||||
replace('/\\s/g', '')
|
||||
filename: name => name.replace(/[^(a-zA-Z0-9\u4e00-\u9fa5\.)]/g, '').replace(/[\?\\/:|<>\*\[\]\(\)\$%\{\}@~]/g, '').replace('/\\s/g', '')
|
||||
},
|
||||
height: data.height,
|
||||
counter: 102400,
|
||||
@ -222,11 +274,24 @@ export default {
|
||||
|
||||
if (!(isJPG || isPNG)) {
|
||||
this.$message.error('上传图标只能是 JPG 或者 PNG 格式!');
|
||||
return false;
|
||||
}
|
||||
if (!isLt2M) {
|
||||
this.$message.error('上传图标大小不能超过 2MB!');
|
||||
return false;
|
||||
}
|
||||
|
||||
this.fileToBase64(file);
|
||||
return false;
|
||||
},
|
||||
fileToBase64(file) {
|
||||
let _ts = this;
|
||||
let reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = function () {
|
||||
_ts.$set(_ts, 'topicIconPath', this.result);
|
||||
_ts.$refs.cropper.replace(this.result);
|
||||
}
|
||||
return (isJPG || isPNG) && isLt2M;
|
||||
},
|
||||
async updateTopic() {
|
||||
let _ts = this;
|
||||
@ -254,6 +319,24 @@ export default {
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
reset() {
|
||||
this.$refs.cropper.reset();
|
||||
},
|
||||
// get image data for post processing, e.g. upload or setting image src
|
||||
cropImage() {
|
||||
let _ts = this;
|
||||
try {
|
||||
_ts.cropImg = _ts.$refs.cropper.getCroppedCanvas().toDataURL();
|
||||
let topic = _ts.topic;
|
||||
topic.topicIconPath = _ts.cropImg;
|
||||
_ts.$set(_ts, 'topic', topic);
|
||||
_ts.$set(_ts, 'topicIconPath', _ts.cropImg);
|
||||
_ts.$message.success('已裁剪 !');
|
||||
} catch (e) {
|
||||
_ts.$message.error('图片获取失败 !');
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeRouteLeave(to, from, next) {
|
||||
@ -306,7 +389,7 @@ export default {
|
||||
const responseData = await _ts.$axios.$get('/api/admin/topic/detail/' + _ts.$route.params.topic_id);
|
||||
_ts.$set(_ts, 'topic', responseData);
|
||||
if (responseData.topicIconPath) {
|
||||
_ts.$set(_ts,'topicIconPath',responseData.topicIconPath);
|
||||
_ts.$set(_ts, 'topicIconPath', responseData.topicIconPath);
|
||||
}
|
||||
} else {
|
||||
_ts.$set(_ts, 'isEdit', false);
|
||||
@ -329,5 +412,41 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "~vditor/src/assets/scss/index.scss";
|
||||
@import "~vditor/src/assets/scss/index.scss";
|
||||
|
||||
.preview-area {
|
||||
width: 16rem;
|
||||
}
|
||||
|
||||
.preview-area p {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.preview-area p:last-of-type {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.crop-placeholder {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background: #ccc;
|
||||
}
|
||||
|
||||
.cropped-image img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.img-cropper {
|
||||
width: 480px;
|
||||
min-height: 480px;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC);
|
||||
}
|
||||
|
||||
.preview-large {
|
||||
width: 100%;
|
||||
height: 144px;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
|
||||
background-color: #ffffff;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
@ -97,7 +97,6 @@
|
||||
<script>
|
||||
import Vue from 'vue';
|
||||
import {mapState} from 'vuex';
|
||||
import saveSvg from 'save-svg-as-png';
|
||||
import VueCropper from 'vue-cropperjs';
|
||||
import 'cropperjs/dist/cropper.css';
|
||||
|
||||
|
0
pages/tag/_tag_uri.vue
Normal file
0
pages/tag/_tag_uri.vue
Normal file
@ -14,11 +14,27 @@ const getDefaultRolesData = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const getDefaultArticlesData = () => {
|
||||
return {
|
||||
articles: [],
|
||||
pagination: {}
|
||||
}
|
||||
}
|
||||
|
||||
const getDefaultCommentsData = () => {
|
||||
return {
|
||||
comments: [],
|
||||
pagination: {}
|
||||
}
|
||||
}
|
||||
|
||||
export const state = () => {
|
||||
return {
|
||||
fetching: false,
|
||||
user: getDefaultUsersData(),
|
||||
role: getDefaultRolesData()
|
||||
role: getDefaultRolesData(),
|
||||
article: getDefaultArticlesData(),
|
||||
comment: getDefaultCommentsData()
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,6 +49,20 @@ export const mutations = {
|
||||
updateRolesData(state, action) {
|
||||
state.role.roles = action.roles
|
||||
state.role.pagination = action.pagination
|
||||
},
|
||||
updateArticlesData(state, action) {
|
||||
state.article.articles = action.articles
|
||||
state.article.pagination = action.pagination
|
||||
},
|
||||
updateCommentsData(state, action) {
|
||||
state.comment.comments = action.comments
|
||||
state.comment.pagination = action.pagination
|
||||
},
|
||||
updateArticlePreference(state, action) {
|
||||
let article = state.article.articles[action.index]
|
||||
if (article.idArticle === action.idArticle) {
|
||||
article.articlePerfect = action.articlePerfect
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,5 +112,52 @@ export const actions = {
|
||||
console.log(error);
|
||||
commit('updateFetching', false);
|
||||
});
|
||||
},
|
||||
fetchArticles({commit}, params = {}) {
|
||||
// 清空已有数据
|
||||
commit('updateArticlesData', getDefaultArticlesData())
|
||||
commit('updateFetching', true)
|
||||
|
||||
let data = {
|
||||
page: params.page || 1,
|
||||
rows: params.rows || 10,
|
||||
topicUri: 'news'
|
||||
}
|
||||
|
||||
return this.$axios
|
||||
.$get(`${ADMIN_API_PATH}/articles`, {
|
||||
params: data
|
||||
})
|
||||
.then(response => {
|
||||
commit('updateFetching', false);
|
||||
commit('updateArticlesData', response);
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
commit('updateFetching', false);
|
||||
});
|
||||
},
|
||||
fetchComments({commit}, params = {}) {
|
||||
// 清空已有数据
|
||||
commit('updateCommentsData', getDefaultArticlesData())
|
||||
commit('updateFetching', true)
|
||||
|
||||
let data = {
|
||||
page: params.page || 1,
|
||||
rows: params.rows || 10
|
||||
}
|
||||
|
||||
return this.$axios
|
||||
.$get(`${ADMIN_API_PATH}/comments`, {
|
||||
params: data
|
||||
})
|
||||
.then(response => {
|
||||
commit('updateFetching', false);
|
||||
commit('updateCommentsData', response);
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
commit('updateFetching', false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user