19 ~ express ~ 文章的增加 , 查看 ,修改 ,删除
一,前台
1,添加文章 /views/admin/content_add.html
{% extends 'layout.html' %}
{% block main %}
<ol class="breadcrumb">
<li><a href="/admin">管理首页</a></li>
<li><span>添加分类</span></li>
</ol>
<h3>添加分类</h3>
<form method="POST">
<div class="form-group">
<label for="category_name">分类名称</label>
<input type="text" class="form-control" name="category_name" id="category_name" placeholder="Category Name">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
{% endblock %}
2,查看文章 /views/admin/content.html
{% extends 'layout.html' %}
{% block main %}
<ol class="breadcrumb">
<li><a href="/admin/content">内容首页</a></li>
<li><span>内容列表</span></li>
</ol>
<h3>内容列表</h3>
<table class="table table-bordered">
<tr>
<th>ID</th>
<th>标题</th>
<th>分类</th>
<th>简介</th>
<th>作者</th>
<th>添加时间</th>
<th>阅读量</th>
<th>操作</th>
</tr>
<!-- 循环输出数组 . id是对象,需要转换成字符串 -->
{% for content in contents %}
<tr>
<td> {{content._id.toString()}}</td>
<td> {{content.title}}</td>
<!-- 关联的具体使用 -->
<td> {{content.category.category_name}}</td>
<td> {{content.description}}</td>
<td> {{content.user.username}}</td>
<td> {{content.addTime|date('Y-m-d h:i:s')}}</td>
<td> {{content.views}}</td>
<td>
<!-- 【 错误的案例 : 忘记加路由 】 <a href="/content/edit?id={{content._id.toString()}}">修改</a> | -->
<a href="/admin/content/edit?id={{content._id.toString()}}">修改</a> |
<a href="/admin/content/delete?id={{content._id.toString()}}">删除</a>
</td>
{% endfor %}
</tr>
</table>
<div class="btn-group" role="group" aria-label="...">
<a href="/admin/content?page={{page-1}}" class="btn btn-default">上一页</a>
<a href="/admin/content?page={{page+1}}" class="btn btn-default">下一页</a>
<li>一共有 {{count}} 条数据</li>
<li>每页显示 {{limit}} 条数据</li>
<li>一共有 {{pages}} 页</li>
<li>当前是在 {{page}} 页</li>
</div>
{% endblock %}
3, 修改文章 /views/admin/content_edit.html
{% extends 'layout.html' %}
{% block main %}
<ol class="breadcrumb">
<li><a href="/admin">管理首页</a></li>
<li><span>文章内容编辑</span></li>
</ol>
<h3>文章内容编辑 -- {{content.title}}</h3>
<hr> <h4>调试</h4>
{% for category in categories %}
{{category._id.toString()}} , {{category.category_name}}
{% endfor %}
<hr>
<form method="POST">
<div class="form-group">
<label for="category">分类</label>
<select name="category" id="category" class="form-control">
<!--
var categories = []
【 读取category表 】
Content.find().populate('category').then((rs) => {
categories = rs
-->
{% for category in categories %}
{% if category._id==content.category._id%}
<option value="{{category._id.toString()}}" selected>{{category.category_name}}</option>
{% else %}
<option value="{{category._id.toString()}}">{{category.category_name}}</option>
{% endif %}
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="title">标题</label>
<input type="text" class="form-control" value="{{content.title}}" name="title" id="title" placeholder="Title">
</div>
<!-- 自动截取简介 -->
<div class="form-group">
<label for="description">简介</label>
<textarea class="form-control" name="description" id="description" cols="30" rows="3"
placeholder="Description">{{content.description}}</textarea>
</div>
<div class="form-group">
<label for="content">内容</label>
<textarea class="form-control" name="content" id="content" placeholder="Content" cols="30" rows="6">{{content.content}}</textarea>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
{% endblock %}
二,数据库
1,定义文章表 /schemas/contents.js
var mongoose = require('mongoose')
/**
* 创建表结构
*/
module.exports =new mongoose.Schema({
// 关联字段(object) ———— 与分类表的 _id , category_name 是一样的
category:{
// 类型
type:mongoose.Schema.Types.ObjectId, //【 要指定ObjectId的类型,请在声明中使用Schema.Types.ObjectId。 】
/** 引用 【 引用另一张表的原型 】 => 实现关联
*
* 1, Category 指的是 /models/Category模型
* 2, 配合路由数据库查询的 populate('category'),
* 3, populate('category') 中的category 表示 category字段
* 4, 具体使用, 模板文件中 : {{content.category.category_name}}
*/
ref:'Category' //
},
title:String,
description:{
type:String,
default:''
},
content:{
type:String,
default:''
},
/**
* 拓展 */
/**
* 关联字段 : 用户 ID
*
* 具体使用 : 在admin/content.add 路由的数据库保存字段中添加 user:req.userInfo._id.toString() 即可
*/
user:{
type:mongoose.Schema.Types.ObjectId,
ref:'User'
},
/**
* 添加时间
*
* 具体使用 :(自动生成)
*/
addTime:{
type:Date,
default:new Date()
},
/**
* 点击量(阅读量)
*
* 具体使用 :(自动生成)
*/
views:{
type:Number,
default:0
}
})
2,定义文章数据模型 /models/Content.js
var mongoose = require('mongoose')
var contentSchema = require('../schemas/contents')
/**
* 创建模型
*/
module.exports= mongoose.model('Content',contentSchema)
三,后台路由和业务逻辑 /router/admin.js
/**内容首页 */
router.get('/content',(req,res)=>{
var page = Number(req.query.page || 1) // 如果没有传值,默认为1
var limit = 10
var pages = 1
Content.count().then((count)=>{
// 计算总页数,向上取整数,去最大值
pages = Math.ceil(count / limit)
// 页数取值不能超过总页数的值
page = Math.min(page,pages)
// 取值不能小于1
page = Math.max(page,1)
var skip = (page-1)*limit
// 排序 : sort({第一个参数表示根据什么排序 : 第二个参数只能是( 1 和 -1 : 1 表示升序 ,-1 表示降序 )})
// _id 值包含了时间戳
Content.find().sort({_id:-1}).limit(limit).skip(skip).populate(['category','user']).then((contents) => {
// console.log(contents)
res.render('admin/content',{
userInfo: req.userInfo,
contents:contents,
page:page,
pages:pages,
count:count,
limit:limit
})
})
})
})
/**文章添加 */
router.get('/content/add',(req,res)=>{
/**读取分类内容 */
Category.find().sort({_id:-1}).then(categories=>{
res.render('admin/content_add',{
userInfo:req.userInfo,
categories:categories
})
})
})
/** 文章添加 */
router.post('/content/add',(req,res)=>{
/** 一,验证 */
if(req.body.category==''){
res.render('admin/error',{
user:req.userInfo,
message:'分类不能为空'
})
return Promise.reject()
}
if(req.body.title==''){
res.render('admin/error',{
user:req.userInfo,
message:'标题不能为空'
})
return Promise.reject()
}
if(req.body.description==''){
res.render('admin/error',{
user:req.userInfo,
message:'简介不能为空'
})
return Promise.reject()
}
if(req.body.content==''){
res.render('admin/error',{
user:req.userInfo,
message:'内容不能为空'
})
return Promise.reject()
}
/** 二,保存 */
/**1,错误的示例 */
// Content.save().then(fs=>{
// if(fs){
// res.render('admin/success',{
// user:req.userInfo,
// message:'添加内容成功'
// })
// }
// })
new Content({
content:req.body.content,
title:req.body.title,
category:req.body.category,
description:req.body.description,
user:req.userInfo._id.toString()
}).save().then(fs=>{
if(fs){
res.render('admin/success',{
user:req.userInfo,
message:'添加内容成功',
url:'/admin/content'
})
}
})
})
/** 文章的修改 */
router.get('/content/edit',(req,res)=>{
var id = req.query.id || ''
// console.log('id=>'+id)
/**
* 从外部获取 categories (1)
*/
var categories = []
// 读取category表
/** ——————————————————————————————————————————————————————————————————————————【Bug】
* Content.find().sort({_id:-1}).populate('category').then((rs) => {
* —————————————————————————————————————————————————————————————————————————— 【Bug】
* */
Category.find().sort({_id:-1}).populate('category').then((rs) => {
/**
* 从外部获取 categories (2)
*/
categories = rs
return Content.findOne({
_id:id
}).populate('category')
}).then(content=>{
// console.log(('categories=>'+categories).yellow)
if(!content){
res.render('admin/error',{
user:req.userInfo,
message:'要修改的内容不存在',
url:'/admin/content'
})
}else{
res.render('admin/content_edit',{
user:req.userInfo,
content:content,
categories:categories
})
}
})
})
/**
* 保存修改的文章
*/
router.post('/content/edit',(req,res)=>{
var id = req.query.id || ''
console.log(('req.body.category=>'+req.body.description).yellow)
if(req.body.category==''){
res.render('admin/error',{
user:req.userInfo,
message:'分类不能为空'
})
return Promise.reject()
}
if(req.body.title==''){
res.render('admin/error',{
user:req.userInfo,
message:'标题不能为空'
})
return Promise.reject()
}
Content.update({
/**条件 */
_id:id
},{
/**更新的内容 */
content:req.body.content,
title:req.body.title,
category:req.body.category,
description:req.body.description,
}).then((fs)=>{
if(fs){
res.render('admin/success',{
user:req.userInfo,
message:'修改内容成功',
url:'/admin/content'
})
}
})
})
/**
* 文章删除
*/
router.get('/content/delete',(req,res)=>{
//获取要删除分类的id
var id = req.query.id || ''
//直接删除
Content.remove({
_id:id
}).then((rs)=>{
if(rs){
res.render('admin/success',{
user:req.userInfo,
message:'文章删除成功',
url:'/admin/content'
})
}
})
})