文章模块
创建子引用
cd renranapi/apps
python ../../manage.py startapp article
注册子应用
INSTALLED_APPS = [
# ....
'article',
]
模型代码
aricle./models.py,代码:
from django.db import models
from renranapi.utils.models import BaseModel
from users.models import User
# create your models here.
class ArticleCollection(BaseModel):
"""文集模型"""
user = models.ForeignKey(User, on_delete=models.DO_NOTHING, verbose_name="用户")
class Meta:
db_table = "rr_article_collection"
verbose_name = "文集"
verbose_name_plural = verbose_name
class Special(BaseModel):
"""专题模型"""
image = models.ImageField(null=True, blank=True, verbose_name="封面图片")
notice = models.TextField(null=True, blank=True, verbose_name="专题公告")
article_count = models.IntegerField(default=0, null=True, blank=True, verbose_name="文章总数")
follow_count = models.IntegerField(default=0, null=True, blank=True, verbose_name="关注数量")
user = models.ForeignKey(User, on_delete=models.DO_NOTHING, verbose_name="创建人")
class Meta:
db_table = "rr_special"
verbose_name = "专题"
verbose_name_plural = verbose_name
class Article(BaseModel):
"""文章模型"""
content = models.TextField(null=True, blank=True, verbose_name="文章内容")
html_content = models.TextField(null=True, blank=True, verbose_name="html内容")
user = models.ForeignKey(User, on_delete=models.DO_NOTHING, verbose_name="作者")
collection = models.ForeignKey(ArticleCollection, on_delete=models.CASCADE, verbose_name="文集ID")
pub_date = models.DateTimeField(null=True, default=None, verbose_name="发布时间")
access_pwd = models.CharField(max_length=15, null=True, blank=True, verbose_name="访问密码")
read_count = models.IntegerField(default=0, null=True, blank=True, verbose_name="阅读量")
like_count = models.IntegerField(default=0, null=True, blank=True, verbose_name="点赞量")
collect_count = models.IntegerField(default=0, null=True, blank=True, verbose_name="收藏量")
comment_count = models.IntegerField(default=0, null=True, blank=True, verbose_name="评论量")
reward_count = models.IntegerField(default=0, null=True, blank=True, verbose_name="赞赏量")
is_public = models.BooleanField(default=False, verbose_name="是否公开")
class Meta:
db_table = "rr_article"
verbose_name = "文章"
verbose_name_plural = verbose_name
class SpecialArticle(BaseModel):
"""文章和专题的绑定关系"""
STATUS_OPTION = (
(0, "未审核"),
(1, "审核中"),
(2, "审核通过"),
(3, "审核不通过"),
)
article = models.ForeignKey(Article, on_delete=models.CASCADE, verbose_name="文章")
special = models.ForeignKey(Special, on_delete=models.CASCADE, verbose_name="专题")
status = models.SmallIntegerField(choices=STATUS_OPTION, default=0, verbose_name="审核状态")
user = models.ForeignKey(User,null=True,blank=True, on_delete=models.DO_NOTHING, verbose_name="审核管理员ID")
class Meta:
db_table = "rr_special_article"
verbose_name = "专题的文章"
verbose_name_plural = verbose_name
class SpecialManager(BaseModel):
"""专题管理员"""
user = models.ForeignKey(User, on_delete=models.DO_NOTHING, verbose_name="管理员")
special = models.ForeignKey(Special, on_delete=models.CASCADE, verbose_name="专题")
class Meta:
db_table = "rr_special_manager"
verbose_name = "专题的管理员"
verbose_name_plural = verbose_name
class SpecialFocus(BaseModel):
"""专题关注"""
user = models.ForeignKey(User, on_delete=models.DO_NOTHING, verbose_name="管理员")
special = models.ForeignKey(Special, on_delete=models.CASCADE, verbose_name="专题")
class Meta:
db_table = "rr_special_focus"
verbose_name = "专题的关注"
verbose_name_plural = verbose_name
class ArticleImage(BaseModel):
"""文章图片"""
group = models.CharField(max_length=15, null=True, blank=True, verbose_name="组名")
image = models.ImageField(null=True, blank=True, verbose_name="图片地址")
class Meta:
db_table = "rr_article_image"
verbose_name = "文章图片"
verbose_name_plural = verbose_name
数据迁移
python manage.py makemigrations
python manage.py migrate
相关依赖
在vue中引入集成markdown富文本编辑器
这里我们使用 mavonEditor,链接:https://github.com/hinesboy/mavonEditor
安装
cd renran_pc
npm install mavon-editor --save
在main.js中注册编辑器组件
import mavonEditor from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
// 注册mavon-editor组件
Vue.use(mavonEditor);
写文章页面
创建Writer.vue组件,提供给用户编写文章
<template>
<div class="write">
<div class="_2v5v5">
<div class="_3zibT"><a href="/">回首页</a></div>
<div class="_1iZMb">
<div class="_33Zlg" @click="collection_form=true"><i class="fa fa-plus"></i><span>新建文集</span></div>
<div class="_2G97m">
<form class="M8J6Q" :class="collection_form?'_2a1Rp':'_1mU5v'">
<input type="text" placeholder="请输入文集名..." name="name" class="_1CtV4">
<button type="submit" class="dwU8Q _3zXcJ _3QfkW"><span>提 交</span></button>
<button type="button" class="vIzwB _3zXcJ" @click="collection_form=false"><span>取 消</span></button>
</form>
</div>
</div>
<ul class="_3MbJ4 _3t059">
<li class="_3DM7w _31PCv" title="日记本">
<div class="_3P4JX _2VLy-">
<i class="fa fa-gear"></i>
<span>
<ul class="_2V8zt _3FcHm _2w9pn" :class="true?'':'NvfK4'">
<li class="_2po2r cRfUr" title="">
<span class=""><i class="fa fa-pencil-square-o _22XWG"></i>修改文集</span>
</li>
<li class="_2po2r cRfUr" title="">
<span class=""><i class="fa fa-trash-o _22XWG"></i>删除文集</span>
</li>
</ul>
</span>
</div>
<span>日记本</span>
</li>
<li class="_3DM7w" title="随笔"><span>随笔</span></li>
</ul>
<div style="height: 50px;"></div>
<div role="button" class="h-5Am">
<span class="ant-dropdown-trigger"><i class="fa fa-bars"></i><span>设置</span></span>
<span class="Yv5Zx">遇到问题<i class="fa fa-question-circle-o"></i></span>
</div>
</div>
<div class="rQQG7">
<div class="_3revO _2mnPN">
<div class="_3br9T">
<div>
<div class="_1GsW5"><i class="fa fa-plus-circle"></i><span> 新建文章</span></div>
<ul class="_2TxA-">
<li class="_25Ilv _33nt7" title="ABC">
<i class="_13kgp _2m93u"></i>
<div class="_3P4JX poOXI">
<i class="fa fa-gear"></i>
<span>
<ul class="_2V8zt _3FcHm _2w9pn">
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-share _22XWG"></i>直接发布</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-clock-o _22XWG"></i>定时发布</span></li>
<li class="_2po2r cRfUr" title=""><span class="_20tIi"><i class="iconfont ic-paid _22XWG"></i>发布为付费文章</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="iconfont ic-set _22XWG"></i>设置发布样式</span></li>
<li class="_3nZXj _2_WAp _3df2u _2po2r cRfUr" title=""><span class=""><i class="fa fa-folder-open _22XWG"></i>移动文章
<div class="_3x4X_">
<ul class="_2KzJx oGKRI _3DXDE _2w9pn">
<li class="_2po2r cRfUr" title="随笔"><span class="">随笔</span></li>
</ul>
</div>
</span>
</li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-history _22XWG"></i>历史版本</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-trash-o _22XWG"></i>删除文章</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-ban _22XWG"></i>设置禁止转载</span></li>
</ul>
</span>
</div>
<span class="NariC">ABC</span>
<span class="hLzJv">题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?
题目:企业发放的奖金根据利润提成</span>
<span class="_29C-V">字数:905</span>
</li>
<li class="_25Ilv" title="2020-01-12">
<i class="_13kgp"></i>
<span class="NariC">2020-01-12</span>
<span class="hLzJv">题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?
题目:企业发放的奖金根据利润提成</span>
</li>
</ul>
<div class="_2cVn3"><i class="fa fa-plus"></i><span> 在下方新建文章</span></div>
</div>
</div>
</div>
<input type="text" class="_24i7u" value="2020-01-12">
<div id="editor">
<mavon-editor
style="height: 100%"
v-model="editorContent"
:ishljs="true"
ref=md
@imgAdd="imgAdd"
@imgDel="imgDel"
></mavon-editor>
</div>
</div>
</div>
</template>
<script>
import { mavonEditor } from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
export default {
name: "Writer",
data(){
return {
editorContent:"",
img_file:[],
collection_form:false,
}
},
watch:{
editorContent(){
console.log(this.editorContent)
}
},
mounted(){
document.querySelector("#editor").style.height = document.documentElement.clientHeight-document.querySelector("._24i7u").clientHeight+"px";
},
components: {
mavonEditor
},
methods:{
// 绑定@imgAdd event
imgAdd(pos, $file){
// 添加文件
},
imgDel(pos) {
// 删除文件
}
}
}
</script>
<style scoped>
body *{
box-sizing: border-box;
}
.write{
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
margin: 0;
}
._2v5v5 {
position: relative;
height: 100%;
overflow-y: auto;
background-color: #404040;
color: #f2f2f2;
z-index: 100;
width: 16.66666667%;
display: block;
flex: 0 0 auto;
float: left;
padding-right: 0;
padding-left: 0;
min-height: 1px;
}
._3zibT {
padding: 30px 18px 5px;
text-align: center;
font-size: 14px;
}
._3zibT a {
display: block;
font-size: 15px;
padding: 9px 0;
color: #ec7259;
border: 1px solid rgba(236,114,89,.8);
border-radius: 20px;
-webkit-transition: border-color .2s ease-in;
-o-transition: border-color .2s ease-in;
transition: border-color .2s ease-in;
}
._1iZMb {
padding: 0 15px;
margin-top: 20px;
margin-bottom: 10px;
font-size: 14px;
line-height: 1.5;
}
._1iZMb ._33Zlg {
cursor: pointer;
color: #f2f2f2;
transition: color .2s cubic-bezier(.645,.045,.355,1);
font-size: 14px;
}
._1iZMb ._33Zlg .fa+span {
margin-left: 4px;
}
._1iZMb ._2G97m {
overflow: hidden;
}
._1iZMb ._2a1Rp {
height: 85px;
opacity: 1;
margin-top: 10px;
transition: all .2s ease-out;
overflow: hidden;
}
._1CtV4 {
width: 100%;
height: 35px;
color: #ccc;
background-color: #595959;
border: 1px solid #333;
padding: 4px 6px;
font-size: 14px;
line-height: 20px;
outline: 0;
overflow: visible;
margin: 10px 0 0;
margin-bottom: 10px;
}
._3zXcJ {
position: relative;
display: inline-block;
text-align: center;
height: 30px;
line-height: 20px;
padding: 4px 12px;
border: 1px solid transparent;
border-radius: 15px;
font-size: 14px;
font-weight: 500;
-ms-touch-action: manipulation;
touch-action: manipulation;
cursor: pointer;
background-image: none;
white-space: nowrap;
user-select: none;
transition: all .2s cubic-bezier(.645,.045,.355,1);
text-transform: none;
color: #42c02e;
border-color: #42c02e;
margin-left: 4px;
background-color: #404040;
}
.vIzwB {
color: #999;
outline: 0;
}
._1iZMb ._1mU5v {
height: 0;
opacity: 0;
margin-top: 0;
}
._1iZMb ._2a1Rp {
height: 85px;
opacity: 1;
margin-top: 10px;
}
._1iZMb ._1mU5v, ._1iZMb ._2a1Rp {
transition: all .2s ease-out;
}
.vIzwB, .vIzwB:focus, .vIzwB:hover {
background-color: #404040;
border-color: transparent;
}
.dwU8Q {
margin-left: 4px;
background-color: #404040;
}
._3t059 {
position: relative;
z-index: 0;
background-color: #8c8c8c;
}
._3MbJ4 {
margin-bottom: 0;
}
._3DM7w {
position: relative;
line-height: 40px;
list-style: none;
font-size: 15px;
color: #f2f2f2;
background-color: #404040;
padding: 0 15px;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
._31PCv {
background-color: #666;
border-left: 3px solid #ec7259;
padding-left: 12px;
}
._3DM7w ._2VLy- {
float: right;
}
._3P4JX {
font-size: 16px;
width: 40px;
text-align: center;
position: relative;
min-height: 30px;
max-height: 50px;
}
._3DM7w span {
display: block;
margin-right: 20px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
._2w9pn {
font-size: 14px;
-webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2);
box-shadow: 0 5px 10px rgba(0,0,0,.2);
list-style: none;
background-color: #fff;
color: #595959;
border-radius: 6px;
}
._3P4JX ul._2V8zt {
display: none;
position: absolute;
z-index: 99;
right: 0;
}
._3P4JX ul._3FcHm {
top: 100%;
}
._2po2r {
padding: 10px 20px;
line-height: 20px;
white-space: nowrap;
text-align: left;
position: relative;
border-bottom: 1px solid #d9d9d9;
}
._3DM7w:hover, .JUBSP {
background-color: #666;
}
.h-5Am {
display: block;
width: 16.66666667%;
position: fixed;
bottom: 0;
height: 50px;
line-height: 50px;
font-size: 15px;
padding-left: 15px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
z-index: 150;
background-color: #404040;
}
.cRfUr {
border-bottom: 1px solid #d9d9d9;
}
._2po2r:last-child {
border-radius: 0 0 4px 4px;
border-bottom: 0;
}
._2po2r:first-child {
border-radius: 4px 4px 0 0;
}
._2po2r ._22XWG {
margin-right: 5px;
}
._2po2r:hover {
background-color: #666;
color: #fff;
}
._3DM7w span {
display: block;
margin-right: 20px;
overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
white-space: nowrap;
}
._3P4JX ul.NvfK4 {
display: block;
}
._3P4JX ul._2V8zt:before {
position: absolute;
right: 12px;
content: "";
display: inline-block;
}
._3P4JX ul._3FcHm:before {
border-left: 9px solid transparent;
border-right: 9px solid transparent;
border-bottom: 9px solid #fff;
top: -9px;
}
.h-5Am .ant-dropdown-trigger {
display: inline-block;
color: #999;
cursor: pointer;
-webkit-transition: color .2s cubic-bezier(.645,.045,.355,1);
-o-transition: color .2s cubic-bezier(.645,.045,.355,1);
transition: color .2s cubic-bezier(.645,.045,.355,1);
}
.h-5Am .fa+span {
margin-left: 4px;
}
.h-5Am .Yv5Zx {
float: right;
margin-right: 15px;
color: #999;
cursor: pointer;
}
.h-5Am .Yv5Zx i {
margin-left: 5px;
}
.rQQG7{
height: 100%;
display: block;
width: 33.33333%;
border-right: 1px solid #d9d9d9;
}
._3revO {
overflow-y: scroll;
height: 100%;
position: relative;
}
._3br9T {
position: relative;
transition: opacity .3s cubic-bezier(.645,.045,.355,1);
opacity: 1;
}
._1GsW5 {
line-height: 20px;
font-size: 15px;
font-weight: 400;
padding: 20px 0 20px 25px;
cursor: pointer;
color: #595959;
}
._1GsW5:hover {
color: #262626;
}
._2TxA- {
position: relative;
margin-bottom: 0;
background-color: #efe9d9;
border-top: 1px solid #d9d9d9;
}
._25Ilv {
position: relative;
height: 90px;
color: #595959;
background-color: #fff;
margin-bottom: 0;
padding: 15px 10px 15px 60px;
box-shadow: 0 0 0 1px #d9d9d9;
border-left: 5px solid transparent;
list-style: none;
line-height: 60px;
cursor: pointer;
user-select: none;
}
._25Ilv ._2m93u {
background: url(/static/image/sprite.9d24217.png) no-repeat -50px -25px;
background-size: 250px;
position: absolute;
top: 30px;
left: 20px;
width: 22px;
height: 30px;
}
._1tqbw, ._25Ilv:hover, ._33nt7 {
background-color: #e6e6e6;
}
._25Ilv ._2m93u {
background: url(/static/image/sprite.9d24217.png) no-repeat -50px -25px;
background-size: 250px;
position: absolute;
top: 30px;
left: 20px;
width: 22px;
height: 30px;
}
._3P4JX {
font-size: 16px;
width: 40px;
text-align: center;
position: relative;
min-height: 30px;
max-height: 50px;
}
._25Ilv .poOXI {
float: right;
}
._33nt7 {
border-left-color: #ec7259;
}
._25Ilv .hLzJv, ._25Ilv .NariC {
display: block;
height: 30px;
line-height: 30px;
margin-right: 40px;
overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 18px;
font-family: sans-serif;
}
._2TxA- {
position: relative;
margin-bottom: 0;
background-color: #efe9d9;
border-top: 1px solid #d9d9d9;
}
._3P4JX ul._2V8zt {
display: none;
position: absolute;
z-index: 99;
right: 0;
}
._3P4JX ul._3FcHm {
top: 100%;
}
._2w9pn {
font-size: 14px;
box-shadow: 0 5px 10px rgba(0,0,0,.2);
list-style: none;
background-color: #fff;
color: #595959;
border-radius: 6px;
}
._3P4JX ul.NvfK4 {
display: block;
}
._3P4JX ul._3FcHm:before {
border-left: 9px solid transparent;
border-right: 9px solid transparent;
border-bottom: 9px solid #fff;
top: -9px;
}
._3P4JX ul._2V8zt:before {
position: absolute;
right: 12px;
content: "";
display: inline-block;
}
._25Ilv ._13kgp {
position: absolute;
top: 30px;
left: 20px;
width: 22px;
height: 30px;
background: url(/static/image/sprite.9d24217.png) no-repeat 0 -25px;
background-size: 250px;
}
._25Ilv ._13kgp {
position: absolute;
top: 30px;
left: 20px;
width: 22px;
height: 30px;
background: url(/static/image/sprite.9d24217.png) no-repeat 0 -25px;
background-size: 250px;
}
._25Ilv ._2m93u {
background: url(/static/image/sprite.9d24217.png) no-repeat -50px -25px;
background-size: 250px;
}
._25Ilv ._29C-V {
position: absolute;
bottom: 2px;
left: 5px;
font-size: 9px;
line-height: 16px;
color: #595959;
}
._2cVn3 {
line-height: 30px;
padding: 20px 0 20px 25px;
cursor: pointer;
color: #999;
margin-bottom: 80px;
}
._24i7u {
flex-shrink: 0;
padding: 0 80px 10px 40px;
margin-bottom: 0;
border: none;
font-size: 30px;
font-weight: 400;
line-height: 30px;
box-shadow: none;
color: #595959;
background-color: transparent;
outline: none;
border-radius: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
position: absolute;
top: 0;
right: 0;
width: 66.666666%;
}
#editor {
margin: auto;
width: 66.666666%;
position: absolute;
right: 0;
top: 44px;
height: 580px;
}
</style>
路由代码:
// 。。。
import Write from "@/components/Writer"
export default new Router({
mode: "history",
routes: [
// ....
{
name:"Writer",
path:"/writer",
component: Writer,
},
]
})
在 Header.vue提供跳转链接
<router-link class="btn write-btn" to="/writer"><img class="icon-write" src="/static/image/write.svg">写文章</router-link>
判断用户是否已经登录
<template>
<div class="write" v-if="is_show_page">
<div class="_2v5v5">
<div class="_3zibT"><router-link to="/">回首页</router-link></div>
<div class="_1iZMb">
<div class="_33Zlg" @click="collection_form=true"><i class="fa fa-plus"></i><span>新建文集</span></div>
<div class="_2G97m">
<form class="M8J6Q" :class="collection_form?'_2a1Rp':'_1mU5v'">
<input type="text" placeholder="请输入文集名..." name="name" class="_1CtV4">
<button type="submit" class="dwU8Q _3zXcJ _3QfkW"><span>提 交</span></button>
<button type="button" class="vIzwB _3zXcJ" @click="collection_form=false"><span>取 消</span></button>
</form>
</div>
</div>
<ul class="_3MbJ4 _3t059">
<li class="_3DM7w _31PCv" title="日记本">
<div class="_3P4JX _2VLy-">
<i class="fa fa-gear"></i>
<span>
<ul class="_2V8zt _3FcHm _2w9pn" :class="true?'':'NvfK4'">
<li class="_2po2r cRfUr" title="">
<span class=""><i class="fa fa-pencil-square-o _22XWG"></i>修改文集</span>
</li>
<li class="_2po2r cRfUr" title="">
<span class=""><i class="fa fa-trash-o _22XWG"></i>删除文集</span>
</li>
</ul>
</span>
</div>
<span>日记本</span>
</li>
<li class="_3DM7w" title="随笔"><span>随笔</span></li>
</ul>
<div style="height: 50px;"></div>
<div role="button" class="h-5Am">
<span class="ant-dropdown-trigger"><i class="fa fa-bars"></i><span>设置</span></span>
<span class="Yv5Zx">遇到问题<i class="fa fa-question-circle-o"></i></span>
</div>
</div>
<div class="rQQG7">
<div class="_3revO _2mnPN">
<div class="_3br9T">
<div>
<div class="_1GsW5"><i class="fa fa-plus-circle"></i><span> 新建文章</span></div>
<ul class="_2TxA-">
<li class="_25Ilv _33nt7" title="ABC">
<i class="_13kgp _2m93u"></i>
<div class="_3P4JX poOXI">
<i class="fa fa-gear"></i>
<span>
<ul class="_2V8zt _3FcHm _2w9pn">
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-share _22XWG"></i>直接发布</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-clock-o _22XWG"></i>定时发布</span></li>
<li class="_2po2r cRfUr" title=""><span class="_20tIi"><i class="iconfont ic-paid _22XWG"></i>发布为付费文章</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="iconfont ic-set _22XWG"></i>设置发布样式</span></li>
<li class="_3nZXj _2_WAp _3df2u _2po2r cRfUr" title=""><span class=""><i class="fa fa-folder-open _22XWG"></i>移动文章
<div class="_3x4X_">
<ul class="_2KzJx oGKRI _3DXDE _2w9pn">
<li class="_2po2r cRfUr" title="随笔"><span class="">随笔</span></li>
</ul>
</div>
</span>
</li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-history _22XWG"></i>历史版本</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-trash-o _22XWG"></i>删除文章</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-ban _22XWG"></i>设置禁止转载</span></li>
</ul>
</span>
</div>
<span class="NariC">ABC</span>
<span class="hLzJv">题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?
题目:企业发放的奖金根据利润提成</span>
<span class="_29C-V">字数:905</span>
</li>
<li class="_25Ilv" title="2020-01-12">
<i class="_13kgp"></i>
<span class="NariC">2020-01-12</span>
<span class="hLzJv">题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?
题目:企业发放的奖金根据利润提成</span>
</li>
</ul>
<div class="_2cVn3"><i class="fa fa-plus"></i><span> 在下方新建文章</span></div>
</div>
</div>
</div>
<input type="text" class="_24i7u" value="2020-01-12">
<div id="editor">
<mavon-editor
style="height: 100%"
v-model="editorContent"
:ishljs="true"
ref=md
@imgAdd="imgAdd"
@imgDel="imgDel"
></mavon-editor>
</div>
</div>
</div>
</template>
<script>
import { mavonEditor } from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
export default {
name: "Writer",
data(){
return {
is_show_page: false, // 是否显示页面
editorContent:"",
img_file:[],
collection_form:false,
}
},
watch:{
editorContent(){
console.log(this.editorContent);
}
},
created(){
// 判断登录
this.$settings.check_user_login(this,"警告","您尚未登录!", "跳转到登录", "/login");
if(this.token){
this.is_show_page = true;
}
},
mounted(){
if(this.is_show_page){
document.querySelector("#editor").style.height = document.documentElement.clientHeight - document.querySelector("._24i7u").clientHeight + "px";
}
},
components: {
mavonEditor
},
methods:{
// 绑定@imgAdd event
imgAdd(pos, $file){
// 添加文件
},
imgDel(pos) {
// 删除文件
}
}
}
</script>
settings.py,代码:
export default {
Host:"http://api.renran.cn:8000", // ajax的服务端地址
Website: "荏苒网",
TC_captcha:{ // 防水墙验证码配置
app_id: "2072894469",
},
check_user_login(vm,title="警告",content="您尚未登录!", confirm_text="跳转到首页", confirm_url="/"){
// 验证用户是否已经登录了
vm.token = localStorage.user_token || sessionStorage.user_token;
if(vm.token){
// 已经登录
return vm.token;
}else{
// 没有登录
vm.$confirm(content, title, {
confirmButtonText: confirm_text,
cancelButtonText: '返回上一页',
type: 'warnning'
}).then(() => {
vm.$router.push(confirm_url);
}).catch(() => {
vm.$router.go(-1);
});
}
}
}
显示当前登录用户的所有文集
视图,代码:
# Create your views here.
from rest_framework.generics import ListAPIView
from rest_framework.permissions import IsAuthenticated
from .models import ArticleCollection
from .serializers import CollectionModelSerializer
class CollecionListAPIView(ListAPIView):
serializer_class = CollectionModelSerializer
permission_classes = [IsAuthenticated] # 必须是登陆用户才能访问过来
def get_queryset(self):
user = self.request.user
ret = ArticleCollection.objects.filter(user=user).order_by("orders", "-id")
if len(ret) < 1:
# 如果没有文集, 给用户默认创建2个文集
collection1 = ArticleCollection.objects.create(
user=user,
name="日记本",
orders=1,
)
collection2 = ArticleCollection.objects.create(
user=user,
name="随笔",
orders=2,
)
ret = [
collection1,
collection2,
]
return ret
序列化器,代码:
from rest_framework import serializers
from .models import ArticleCollection
class CollectionModelSerializer(serializers.ModelSerializer):
"""文集序列化器"""
class Meta:
model = ArticleCollection
fields = ["id","name"]
路由,代码:
from django.urls import path
from . import views
urlpatterns = [
path("collection/", views.CollecionListAPIView.as_view()),
]
总路由,代码:
path('article/', include("article.urls")),
客户端中展示所有文集,代码:
<template>
<div class="write" v-show="is_show_page">
<div class="_2v5v5">
<div class="_3zibT"><a href="/">回首页</a></div>
<div class="_1iZMb">
<div class="_33Zlg" @click="collection_form=true"><i class="fa fa-plus"></i><span>新建文集</span></div>
<div class="_2G97m">
<form class="M8J6Q" :class="collection_form?'_2a1Rp':'_1mU5v'">
<input type="text" placeholder="请输入文集名..." name="name" class="_1CtV4">
<button type="submit" class="dwU8Q _3zXcJ _3QfkW"><span>提 交</span></button>
<button type="button" class="vIzwB _3zXcJ" @click="collection_form=false"><span>取 消</span></button>
</form>
</div>
</div>
<ul class="_3MbJ4 _3t059">
<li class="_3DM7w" :class="current_collection==key?'_31PCv':''" :title="collection.name" v-for="collection,key in collection_list" :key="key">
<div class="_3P4JX _2VLy-">
<i class="fa fa-gear"></i>
<span>
<ul class="_2V8zt _3FcHm _2w9pn" :class="true?'':'NvfK4'">
<li class="_2po2r cRfUr" title="">
<span class=""><i class="fa fa-pencil-square-o _22XWG"></i>修改文集</span>
</li>
<li class="_2po2r cRfUr" title="">
<span class=""><i class="fa fa-trash-o _22XWG"></i>删除文集</span>
</li>
</ul>
</span>
</div>
<span @click="current_collection=key">{{collection.name}}</span>
</li>
</ul>
<div style="height: 50px;"></div>
<div role="button" class="h-5Am">
<span class="ant-dropdown-trigger"><i class="fa fa-bars"></i><span>设置</span></span>
<span class="Yv5Zx">遇到问题<i class="fa fa-question-circle-o"></i></span>
</div>
</div>
<div class="rQQG7">
<div class="_3revO _2mnPN">
<div class="_3br9T">
<div>
<div class="_1GsW5"><i class="fa fa-plus-circle"></i><span> 新建文章</span></div>
<ul class="_2TxA-">
<li class="_25Ilv _33nt7" title="ABC">
<i class="_13kgp _2m93u"></i>
<div class="_3P4JX poOXI">
<i class="fa fa-gear"></i>
<span>
<ul class="_2V8zt _3FcHm _2w9pn">
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-share _22XWG"></i>直接发布</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-clock-o _22XWG"></i>定时发布</span></li>
<li class="_2po2r cRfUr" title=""><span class="_20tIi"><i class="iconfont ic-paid _22XWG"></i>发布为付费文章</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="iconfont ic-set _22XWG"></i>设置发布样式</span></li>
<li class="_3nZXj _2_WAp _3df2u _2po2r cRfUr" title=""><span class=""><i class="fa fa-folder-open _22XWG"></i>移动文章
<div class="_3x4X_">
<ul class="_2KzJx oGKRI _3DXDE _2w9pn">
<li class="_2po2r cRfUr" title="随笔"><span class="">随笔</span></li>
</ul>
</div>
</span>
</li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-history _22XWG"></i>历史版本</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-trash-o _22XWG"></i>删除文章</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-ban _22XWG"></i>设置禁止转载</span></li>
</ul>
</span>
</div>
<span class="NariC">ABC</span>
<span class="hLzJv">题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?
题目:企业发放的奖金根据利润提成</span>
<span class="_29C-V">字数:905</span>
</li>
<li class="_25Ilv" title="2020-01-12">
<i class="_13kgp"></i>
<span class="NariC">2020-01-12</span>
<span class="hLzJv">题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?
题目:企业发放的奖金根据利润提成</span>
</li>
</ul>
<div class="_2cVn3"><i class="fa fa-plus"></i><span> 在下方新建文章</span></div>
</div>
</div>
</div>
<input type="text" class="_24i7u" value="2020-01-12">
<div id="editor">
<mavon-editor
style="height: 100%"
v-model="editorContent"
:ishljs="true"
ref=md
@imgAdd="imgAdd"
@imgDel="imgDel"
></mavon-editor>
</div>
</div>
</div>
</template>
<script>
import { mavonEditor } from 'mavon-editor'
import 'mavon-editor/dist/css/index.css';
import "../../static/font-awesome/css/font-awesome.css";
export default {
name: "Write",
data(){
return {
is_show_page: false,
editorContent:"",
img_file:[],
collection_form:false,
token: "",
collection_list:[],
current_collection: 0, // 默认让用户选中的文集的下标为0
}
},
watch:{
editorContent(){
console.log(this.editorContent);
}
},
created(){
this.token = this.$settings.check_user_login(this);
if(this.token){
this.is_show_page = true;
}
this.get_collection();
},
mounted(){
document.querySelector("#editor").style.height = document.documentElement.clientHeight-document.querySelector("._24i7u").clientHeight+"px";
},
components: {
mavonEditor
},
methods:{
// 绑定@imgAdd event
imgAdd(pos, $file){
// 添加文件
},
imgDel(pos) {
// 删除文件
},
get_collection(){
// 获取当前登陆用户的文集
this.$axios.get(`${this.$settings.Host}/article/collection/`,{
headers:{
Authorization: "jwt " + this.token,
}
}).then(response=>{
this.collection_list = response.data;
}).catch(error=>{
this.$message.error("对不起,无法获取当前用户的文集列表!");
});
}
}
}
</script>
对于文集列表中的图标丢失,我们需要把 font-awesome 目录放到项目的static目录下即可。
添加文集
在原来文集列表的视图接口基础上,把CollectionListAPIView改成CollectionAPIView,代码:
# Create your views here.
from rest_framework.generics import ListAPIView
from rest_framework.permissions import IsAuthenticated
from .models import ArticleCollection
from .serializers import CollectionModelSerializer
from rest_framework.generics import CreateAPIView
class CollecionAPIView(ListAPIView,CreateAPIView):
serializer_class = CollectionModelSerializer
permission_classes = [IsAuthenticated] # 必须是登陆用户才能访问过来
def get_queryset(self):
user = self.request.user
ret = ArticleCollection.objects.filter(user=user).order_by("orders", "-id")
if len(ret) < 1:
# 如果没有文集, 给用户默认创建2个文集
collection1 = ArticleCollection.objects.create(
user=user,
name="日记本",
orders=1,
)
collection2 = ArticleCollection.objects.create(
user=user,
name="随笔",
orders=2,
)
ret = [
collection1,
collection2,
]
return ret
序列化器增加验证和create方法,代码:
from rest_framework import serializers
from .models import ArticleCollection
class CollectionModelSerializer(serializers.ModelSerializer):
class Meta:
model = ArticleCollection
fields = ["id","name"]
def validate_name(self, name):
"""验证数据"""
# 如果当前有用户曾经过同一个文集,则报错
print(self.context) # 字典 {request:对象,view:对象,data_format: 字符串}
user = self.context["request"].user
try:
ArticleCollection.objects.get(user=user,name=name)
raise serializers.ValidationError("对不起, 当前文集名称已经被使用!~")
except:
pass
return name
def create(self, validated_data):
"""保存数据"""
try:
collection = ArticleCollection.objects.create(
name=validated_data.get("name"),
user=self.context["request"].user,
orders=0,
)
return collection
except:
raise serializers.ValidationError("对不起, 添加文集失败!~")
路由代码调整:
from django.urls import path
from . import views
urlpatterns = [
path("collection/", views.CollectionAPIView.as_view()),
]
客户端发起请求添加文集
<template>
<div class="write" v-if="is_show_page">
<div class="_2v5v5">
<div class="_3zibT"><router-link to="/">回首页</router-link></div>
<div class="_1iZMb">
<div class="_33Zlg" @click="collection_form=true"><i class="fa fa-plus"></i><span>新建文集</span></div>
<div class="_2G97m">
<form class="M8J6Q" :class="collection_form?'_2a1Rp':'_1mU5v'">
<input type="text" placeholder="请输入文集名..." v-model="collection_name" class="_1CtV4">
<button type="submit" class="dwU8Q _3zXcJ _3QfkW" @click.stop.prevent="add_collection"><span>提 交</span></button>
<button type="button" class="vIzwB _3zXcJ" @click.stop.prevent="collection_form=false"><span>取 消</span></button>
</form>
</div>
</div>
<ul class="_3MbJ4 _3t059">
<li class="_3DM7w" :class="{_31PCv:current_collection==key}" @click.stop="current_collection=key" :title="collection.name" v-for="collection,key in collection_list">
<div class="_3P4JX _2VLy-">
<i class="fa fa-gear"></i>
<span>
<ul class="_2V8zt _3FcHm _2w9pn" :class="true?'':'NvfK4'">
<li class="_2po2r cRfUr" title="">
<span class=""><i class="fa fa-pencil-square-o _22XWG"></i>修改文集</span>
</li>
<li class="_2po2r cRfUr" title="">
<span class=""><i class="fa fa-trash-o _22XWG"></i>删除文集</span>
</li>
</ul>
</span>
</div>
<span>{{collection.name}}</span>
</li>
<!-- <li class="_3DM7w" title="随笔"><span>随笔</span></li>-->
</ul>
<div style="height: 50px;"></div>
<div role="button" class="h-5Am">
<span class="ant-dropdown-trigger"><i class="fa fa-bars"></i><span>设置</span></span>
<span class="Yv5Zx">遇到问题<i class="fa fa-question-circle-o"></i></span>
</div>
</div>
<div class="rQQG7">
<div class="_3revO _2mnPN">
<div class="_3br9T">
<div>
<div class="_1GsW5"><i class="fa fa-plus-circle"></i><span> 新建文章</span></div>
<ul class="_2TxA-">
<li class="_25Ilv _33nt7" title="ABC">
<i class="_13kgp _2m93u"></i>
<div class="_3P4JX poOXI">
<i class="fa fa-gear"></i>
<span>
<ul class="_2V8zt _3FcHm _2w9pn">
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-share _22XWG"></i>直接发布</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-clock-o _22XWG"></i>定时发布</span></li>
<li class="_2po2r cRfUr" title=""><span class="_20tIi"><i class="iconfont ic-paid _22XWG"></i>发布为付费文章</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="iconfont ic-set _22XWG"></i>设置发布样式</span></li>
<li class="_3nZXj _2_WAp _3df2u _2po2r cRfUr" title=""><span class=""><i class="fa fa-folder-open _22XWG"></i>移动文章
<div class="_3x4X_">
<ul class="_2KzJx oGKRI _3DXDE _2w9pn">
<li class="_2po2r cRfUr" title="随笔"><span class="">随笔</span></li>
</ul>
</div>
</span>
</li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-history _22XWG"></i>历史版本</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-trash-o _22XWG"></i>删除文章</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-ban _22XWG"></i>设置禁止转载</span></li>
</ul>
</span>
</div>
<span class="NariC">ABC</span>
<span class="hLzJv">题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?
题目:企业发放的奖金根据利润提成</span>
<span class="_29C-V">字数:905</span>
</li>
<li class="_25Ilv" title="2020-01-12">
<i class="_13kgp"></i>
<span class="NariC">2020-01-12</span>
<span class="hLzJv">题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?
题目:企业发放的奖金根据利润提成</span>
</li>
</ul>
<div class="_2cVn3"><i class="fa fa-plus"></i><span> 在下方新建文章</span></div>
</div>
</div>
</div>
<input type="text" class="_24i7u" value="2020-01-12">
<div id="editor">
<mavon-editor
style="height: 100%"
v-model="editorContent"
:ishljs="true"
ref=md
@imgAdd="imgAdd"
@imgDel="imgDel"
></mavon-editor>
</div>
</div>
</div>
</template>
<script>
import { mavonEditor } from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
import "../../static/font-awesome/css/font-awesome.css";
export default {
name: "Writer",
data(){
return {
is_show_page: false, // 是否显示页面
collection_list:[], // 文集列表
current_collection: 0, // 默认选中的文集ID
editorContent:"",
img_file:[],
collection_form:false,
collection_name:"",
}
},
watch:{
editorContent(){
console.log(this.editorContent);
}
},
created(){
// 判断登录
this.$settings.check_user_login(this,"警告","您尚未登录!", "跳转到登录", "/login");
if(this.token){
// 显示页面
this.is_show_page = true;
// 获取当前用户的文集列表
this.get_collection();
}
},
mounted(){
if(this.is_show_page){
document.querySelector("#editor").style.height = document.documentElement.clientHeight - document.querySelector("._24i7u").clientHeight + "px";
}
},
components: {
mavonEditor
},
methods:{
add_collection(){
// 添加文集
if(this.collection_name.length<1){
this.$message.error("文集名称不能为空!");
return;
}
// 发送ajax请求
this.$axios.post(`${this.$settings.Host}/article/collection/`,{
name: this.collection_name
},{
headers:{
Authorization: "jwt " + this.token,
}
}).then(response=>{
this.$message.success("添加文集成功!");
this.collection_name = "";
this.collection_form = false; // 隐藏添加文集的表单
// 把服务端中添加返回的文集信息,保存到collection_list中
this.collection_list.unshift(response.data);
}).catch(error=>{
this.$message.error(error.response.data);
});
},
get_collection(){
// 获取用户的文集列表
this.$axios.get(`${this.$settings.Host}/article/collection/`,{
headers:{
Authorization: "jwt " + this.token, // 必须在左边加上 "jwt ",空格!!!
}
}).then(response=>{
this.collection_list = response.data;
}).catch(error=>{
this.$message.error("对不起,无法获取当前用户的文集列表!");
});
},
// 绑定@imgAdd event
imgAdd(pos, $file){
// 添加文件
},
imgDel(pos) {
// 删除文件
}
}
}
</script>
控制文集菜单的显示隐藏[扩展]
<template>
<div class="write" v-if="is_show_page">
<div class="_2v5v5">
<div class="_3zibT"><router-link to="/">回首页</router-link></div>
<div class="_1iZMb">
<div class="_33Zlg" @click="collection_form=true"><i class="fa fa-plus"></i><span>新建文集</span></div>
<div class="_2G97m">
<form class="M8J6Q" :class="collection_form?'_2a1Rp':'_1mU5v'">
<input type="text" placeholder="请输入文集名..." v-model="collection_name" class="_1CtV4">
<button type="submit" class="dwU8Q _3zXcJ _3QfkW" @click.stop.prevent="add_collection"><span>提 交</span></button>
<button type="button" class="vIzwB _3zXcJ" @click.stop.prevent="collection_form=false"><span>取 消</span></button>
</form>
</div>
</div>
<ul class="_3MbJ4 _3t059">
<li class="_3DM7w" :class="{_31PCv:current_collection==key}" @click.stop="current_collection=key;is_show_collection_menu=false;" :title="collection.name" v-for="collection,key in collection_list">
<div class="_3P4JX _2VLy-" v-if="current_collection==key" @click.stop="is_show_collection_menu=!is_show_collection_menu">
<i class="fa fa-gear"></i>
<span>
<ul class="_2V8zt _3FcHm _2w9pn" :class="{NvfK4:is_show_collection_menu}">
<li class="_2po2r cRfUr" title="">
<span class=""><i class="fa fa-pencil-square-o _22XWG"></i>修改文集</span>
</li>
<li class="_2po2r cRfUr" title="">
<span class=""><i class="fa fa-trash-o _22XWG"></i>删除文集</span>
</li>
</ul>
</span>
</div>
<span>{{collection.name}}</span>
</li>
<!-- <li class="_3DM7w" title="随笔"><span>随笔</span></li>-->
</ul>
<div style="height: 50px;"></div>
<div role="button" class="h-5Am">
<span class="ant-dropdown-trigger"><i class="fa fa-bars"></i><span>设置</span></span>
<span class="Yv5Zx">遇到问题<i class="fa fa-question-circle-o"></i></span>
</div>
</div>
<div class="rQQG7">
<div class="_3revO _2mnPN">
<div class="_3br9T">
<div>
<div class="_1GsW5"><i class="fa fa-plus-circle"></i><span> 新建文章</span></div>
<ul class="_2TxA-">
<li class="_25Ilv _33nt7" title="ABC">
<i class="_13kgp _2m93u"></i>
<div class="_3P4JX poOXI">
<i class="fa fa-gear"></i>
<span>
<ul class="_2V8zt _3FcHm _2w9pn">
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-share _22XWG"></i>直接发布</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-clock-o _22XWG"></i>定时发布</span></li>
<li class="_2po2r cRfUr" title=""><span class="_20tIi"><i class="iconfont ic-paid _22XWG"></i>发布为付费文章</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="iconfont ic-set _22XWG"></i>设置发布样式</span></li>
<li class="_3nZXj _2_WAp _3df2u _2po2r cRfUr" title=""><span class=""><i class="fa fa-folder-open _22XWG"></i>移动文章
<div class="_3x4X_">
<ul class="_2KzJx oGKRI _3DXDE _2w9pn">
<li class="_2po2r cRfUr" title="随笔"><span class="">随笔</span></li>
</ul>
</div>
</span>
</li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-history _22XWG"></i>历史版本</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-trash-o _22XWG"></i>删除文章</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-ban _22XWG"></i>设置禁止转载</span></li>
</ul>
</span>
</div>
<span class="NariC">ABC</span>
<span class="hLzJv">题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?
题目:企业发放的奖金根据利润提成</span>
<span class="_29C-V">字数:905</span>
</li>
<li class="_25Ilv" title="2020-01-12">
<i class="_13kgp"></i>
<span class="NariC">2020-01-12</span>
<span class="hLzJv">题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?
题目:企业发放的奖金根据利润提成</span>
</li>
</ul>
<div class="_2cVn3"><i class="fa fa-plus"></i><span> 在下方新建文章</span></div>
</div>
</div>
</div>
<input type="text" class="_24i7u" value="2020-01-12">
<div id="editor">
<mavon-editor
style="height: 100%"
v-model="editorContent"
:ishljs="true"
ref=md
@imgAdd="imgAdd"
@imgDel="imgDel"
></mavon-editor>
</div>
</div>
</div>
</template>
<script>
import { mavonEditor } from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
import "../../static/font-awesome/css/font-awesome.css";
export default {
name: "Writer",
data(){
return {
is_show_page: false, // 是否显示页面
collection_list:[], // 文集列表
current_collection: 0, // 默认选中的文集ID
editorContent:"",
img_file:[],
collection_form:false,
collection_name:"",
is_show_collection_menu: false, // 是否显示文集的菜单
}
},
watch:{
editorContent(){
console.log(this.editorContent);
}
},
created(){
// 判断登录
this.$settings.check_user_login(this,"警告","您尚未登录!", "跳转到登录", "/login");
if(this.token){
// 显示页面
this.is_show_page = true;
// 获取当前用户的文集列表
this.get_collection();
}
},
mounted(){
if(this.is_show_page){
document.querySelector("#editor").style.height = document.documentElement.clientHeight - document.querySelector("._24i7u").clientHeight + "px";
// 点选页面其他位置,关闭菜单
document.onclick = (event)=>{
// 关闭文集菜单
this.is_show_collection_menu = false;
}
}
},
components: {
mavonEditor
},
methods:{
add_collection(){
// 添加文集
if(this.collection_name.length<1){
this.$message.error("文集名称不能为空!");
return;
}
// 发送ajax请求
this.$axios.post(`${this.$settings.Host}/article/collection/`,{
name: this.collection_name
},{
headers:{
Authorization: "jwt " + this.token,
}
}).then(response=>{
this.$message.success("添加文集成功!");
this.collection_name = "";
this.collection_form = false; // 隐藏添加文集的表单
// 把服务端中添加返回的文集信息,保存到collection_list中
this.collection_list.unshift(response.data);
}).catch(error=>{
this.$message.error(error.response.data);
});
},
get_collection(){
// 获取用户的文集列表
this.$axios.get(`${this.$settings.Host}/article/collection/`,{
headers:{
Authorization: "jwt " + this.token, // 必须在左边加上 "jwt ",空格!!!
}
}).then(response=>{
this.collection_list = response.data;
}).catch(error=>{
this.$message.error("对不起,无法获取当前用户的文集列表!");
});
},
// 绑定@imgAdd event
imgAdd(pos, $file){
// 添加文件
},
imgDel(pos) {
// 删除文件
}
}
}
</script>
删除文集[作业]
思路:
-
客户端根据current_collection来获取当前文集的id
-
通过ajax把文集id和jwt发送到服务端,服务端实现根据ID删除文集的操作
修改文集
文件的api视图新增集成UpdateAPIView,代码:
# Create your views here.
from rest_framework.generics import ListAPIView, CreateAPIView, UpdateAPIView
from rest_framework.permissions import IsAuthenticated
from .models import ArticleCollection
from .serializers import CollectionModelSerializer
class CollecionAPIView(ListAPIView,CreateAPIView, UpdateAPIView):
serializer_class = CollectionModelSerializer
permission_classes = [IsAuthenticated] # 必须是登陆用户才能访问过来
def get_queryset(self):
user = self.request.user
ret = ArticleCollection.objects.filter(user=user).order_by("orders", "-id")
if len(ret) < 1:
# 如果没有文集, 给用户默认创建2个文集
collection1 = ArticleCollection.objects.create(
user=user,
name="日记本",
orders=1,
)
collection2 = ArticleCollection.objects.create(
user=user,
name="随笔",
orders=2,
)
ret = [
collection1,
collection2,
]
return ret
序列化器,代码:
from rest_framework import serializers
from .models import ArticleCollection
class CollectionModelSerializer(serializers.ModelSerializer):
"""文集序列化器"""
class Meta:
model = ArticleCollection
fields = ["id","name"]
def validate_name(self, name):
"""验证数据"""
# 如果当前有用户曾经过同一个文集,则报错
# print(self.context) # 字典 {request:对象,view:对象,data_format: 字符串}
user = self.context["request"].user
try:
ArticleCollection.objects.get(user=user, name=name)
raise serializers.ValidationError("对不起, 当前文集名称已经被使用!~")
except:
pass
return name
def create(self, validated_data):
"""添加数据"""
try:
collection = ArticleCollection.objects.create(
name=validated_data.get("name"),
user=self.context["request"].user,
orders=0,
)
return collection
except:
raise serializers.ValidationError("对不起, 添加文集失败!~")
def update(self, instance, validated_data):
"""更新数据"""
instance.name = validated_data.get("name")
instance.save()
return instance
路由代码:
from django.urls import path,re_path
from . import views
urlpatterns = [
path("collection/", views.CollecionAPIView.as_view()),
re_path("^collection/(?P<pk>\d+)/$", views.CollecionAPIView.as_view()),
]
客户端使用ElementUI提供的弹窗,提供输入框给用户输入新的文集名称,并发送ajax提交数据到服务端。
<template>
<div class="write" v-if="is_show_page">
<div class="_2v5v5">
<div class="_3zibT"><router-link to="/">回首页</router-link></div>
<div class="_1iZMb">
<div class="_33Zlg" @click="collection_form=true"><i class="fa fa-plus"></i><span>新建文集</span></div>
<div class="_2G97m">
<form class="M8J6Q" :class="collection_form?'_2a1Rp':'_1mU5v'">
<input type="text" placeholder="请输入文集名..." v-model="collection_name" class="_1CtV4">
<button type="submit" class="dwU8Q _3zXcJ _3QfkW" @click.stop.prevent="add_collection"><span>提 交</span></button>
<button type="button" class="vIzwB _3zXcJ" @click.stop.prevent="collection_form=false"><span>取 消</span></button>
</form>
</div>
</div>
<ul class="_3MbJ4 _3t059">
<li class="_3DM7w" :class="{_31PCv:current_collection==key}" @click.stop="current_collection=key;is_show_collection_menu=false;" :title="collection.name" v-for="collection,key in collection_list">
<div class="_3P4JX _2VLy-" v-if="current_collection==key" @click.stop="is_show_collection_menu=!is_show_collection_menu">
<i class="fa fa-gear"></i>
<span>
<ul class="_2V8zt _3FcHm _2w9pn" :class="{NvfK4:is_show_collection_menu}">
<li class="_2po2r cRfUr" title="">
<span class="" @click.stop="edit_collection"><i class="fa fa-pencil-square-o _22XWG"></i>修改文集</span>
</li>
<li class="_2po2r cRfUr" title="">
<span class=""><i class="fa fa-trash-o _22XWG"></i>删除文集</span>
</li>
</ul>
</span>
</div>
<span>{{collection.name}}</span>
</li>
</ul>
<div style="height: 50px;"></div>
<div role="button" class="h-5Am">
<span class="ant-dropdown-trigger"><i class="fa fa-bars"></i><span>设置</span></span>
<span class="Yv5Zx">遇到问题<i class="fa fa-question-circle-o"></i></span>
</div>
</div>
<div class="rQQG7">
<div class="_3revO _2mnPN">
<div class="_3br9T">
<div>
<div class="_1GsW5"><i class="fa fa-plus-circle"></i><span> 新建文章</span></div>
<ul class="_2TxA-">
<li class="_25Ilv _33nt7" title="ABC">
<i class="_13kgp _2m93u"></i>
<div class="_3P4JX poOXI">
<i class="fa fa-gear"></i>
<span>
<ul class="_2V8zt _3FcHm _2w9pn">
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-share _22XWG"></i>直接发布</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-clock-o _22XWG"></i>定时发布</span></li>
<li class="_2po2r cRfUr" title=""><span class="_20tIi"><i class="iconfont ic-paid _22XWG"></i>发布为付费文章</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="iconfont ic-set _22XWG"></i>设置发布样式</span></li>
<li class="_3nZXj _2_WAp _3df2u _2po2r cRfUr" title=""><span class=""><i class="fa fa-folder-open _22XWG"></i>移动文章
<div class="_3x4X_">
<ul class="_2KzJx oGKRI _3DXDE _2w9pn">
<li class="_2po2r cRfUr" title="随笔"><span class="">随笔</span></li>
</ul>
</div>
</span>
</li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-history _22XWG"></i>历史版本</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-trash-o _22XWG"></i>删除文章</span></li>
<li class="_2po2r cRfUr" title=""><span class=""><i class="fa fa-ban _22XWG"></i>设置禁止转载</span></li>
</ul>
</span>
</div>
<span class="NariC">ABC</span>
<span class="hLzJv">题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?
题目:企业发放的奖金根据利润提成</span>
<span class="_29C-V">字数:905</span>
</li>
<li class="_25Ilv" title="2020-01-12">
<i class="_13kgp"></i>
<span class="NariC">2020-01-12</span>
<span class="hLzJv">题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?
题目:企业发放的奖金根据利润提成</span>
</li>
</ul>
<div class="_2cVn3"><i class="fa fa-plus"></i><span> 在下方新建文章</span></div>
</div>
</div>
</div>
<input type="text" class="_24i7u" value="2020-01-12">
<div id="editor">
<mavon-editor
style="height: 100%"
v-model="editorContent"
:ishljs="true"
ref=md
@imgAdd="imgAdd"
@imgDel="imgDel"
></mavon-editor>
</div>
</div>
</div>
</template>
<script>
import { mavonEditor } from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
import "../../static/font-awesome/css/font-awesome.css";
export default {
name: "Writer",
data(){
return {
is_show_page: false, // 是否显示页面
collection_list:[], // 文集列表
current_collection: 0, // 默认选中的文集ID
editorContent:"",
img_file:[],
collection_form:false,
collection_name:"",
is_show_collection_menu: false, // 是否显示文集的菜单
}
},
watch:{
editorContent(){
console.log(this.editorContent);
}
},
created(){
// 判断登录
this.$settings.check_user_login(this,"警告","您尚未登录!", "跳转到登录", "/login");
if(this.token){
// 显示页面
this.is_show_page = true;
// 获取当前用户的文集列表
this.get_collection();
}
},
mounted(){
if(this.is_show_page){
document.querySelector("#editor").style.height = document.documentElement.clientHeight - document.querySelector("._24i7u").clientHeight + "px";
// 点选页面其他位置,关闭菜单
document.onclick = (event)=>{
// 关闭文集菜单
this.is_show_collection_menu = false;
}
}
},
components: {
mavonEditor
},
methods:{
edit_collection(){
// 修改文集
this.is_show_collection_menu=false; // 关闭文集的操作菜单
this.$prompt('请输入新文集名', '提示', {
confirmButtonText: '保存',
cancelButtonText: '取消',
inputPattern: /.{1,}/,
inputErrorMessage: '文集名称不能为空!',
inputValue: this.collection_list[this.current_collection].name,
}).then(({ value }) => {
// 点击确定,需要把当前文集名称提交到服务端进行修改
let collection_id = this.collection_list[this.current_collection].id;
this.$axios.put(`${this.$settings.Host}/article/collection/${collection_id}/`,{
name: value,
},{
headers:{
Authorization:"jwt " + this.token,
}
}).then(response=>{
// 服务端ajax请求操作成功,则客户端的name也要发生改变
this.collection_list[this.current_collection].name = value;
}).catch(error=>{
this.$message.error(error.response.data);
})
}).catch(() => {
});
},
add_collection(){
// 添加文集
if(this.collection_name.length<1){
this.$message.error("文集名称不能为空!");
return;
}
// 发送ajax请求
this.$axios.post(`${this.$settings.Host}/article/collection/`,{
name: this.collection_name
},{
headers:{
Authorization: "jwt " + this.token,
}
}).then(response=>{
this.$message.success("添加文集成功!");
this.collection_name = "";
this.collection_form = false; // 隐藏添加文集的表单
// 把服务端中添加返回的文集信息,保存到collection_list中
this.collection_list.unshift(response.data);
}).catch(error=>{
this.$message.error(error.response.data);
});
},
get_collection(){
// 获取用户的文集列表
this.$axios.get(`${this.$settings.Host}/article/collection/`,{
headers:{
Authorization: "jwt " + this.token, // 必须在左边加上 "jwt ",空格!!!
}
}).then(response=>{
this.collection_list = response.data;
}).catch(error=>{
this.$message.error("对不起,无法获取当前用户的文集列表!");
});
},
// 绑定@imgAdd event
imgAdd(pos, $file){
// 添加文件
},
imgDel(pos) {
// 删除文件
}
}
}
</script>