概述
技术团队博客系统
技术栈
Vue + Node.js + Egg/Koa + MongoDB + Pug + 语雀 API
:::
主要功能
- 用户管理
a. 管理员登录/登出
b. 游客访问(无须注册登录,匿名 ID 访问) - 文章发布(将语雀文章同步到网站)
a. 拉取全部文章清单
ⅰ. 后台点击同步按钮、手动触发拉取文章列表任务
b. 选择目标文章发布
ⅰ. 后台选择文章点击按钮,完成文章的持久化 - 文章展示
a. 网站首页
ⅰ. 放文章的列表,支持分页
ⅱ. 支持现有文章检索
ⅲ. 点击单条文章记录进入文章详情
b. 文章详情
ⅰ. 点击进入文章详情 - 后台统计
a. 每个页面的访问 PV
b. 每个页面的访问 UV
ⅰ. 用户首次进入网站时,种一个 uuid 的 cookie
技术架构
代码举例
表结构 - Schema
如用户表的设计,需要给用户密码加权加密,增加破解难度,用户表需要存储账号密码这些基本信息,以及匿名用户的访问 ID,也可以分拆成 admin 表和 user 两张表,如下以一张表来举例部分代码:
const mongoose = require('mongoose')
const bcrypt = require('bcrypt')
// 加密权重
const SALT_WORK_FACTOR = 10
const Schema = mongoose.Schema
const UserSchema = new Schema({
// user admin superAdmin
role: {
type: String,
default: 'user'
},
uuid: String,
username: String,
password: String,
meta: {
createdAt: {
type: Date,
default: Date.now()
},
updatedAt: {
type: Date,
default: Date.now()
}
}
})
// 中间件
UserSchema.pre('save', function (next) {
if (this.isNew) {
this.meta.createdAt = this.meta.updatedAt = Date.now()
} else {
this.meta.updatedAt = Date.now()
}
next()
})
UserSchema.pre('save', function (next) {
let user = this
if (!user.isModified('password')) return next()
bcrypt.genSalt(SALT_WORK_FACTOR, (err, salt) => {
if (err) return next(err)
bcrypt.hash(user.password, salt, (error, hash) => {
if (error) return next(error)
user.password = hash
next()
})
})
})
// 静态方法
UserSchema.methods = {
comparePassword: function (_password, password) {
return new Promise((resolve, reject) => {
bcrypt.compare(_password, password, function (err, isMatch) {
if (!err) resolve(isMatch)
else reject(err)
})
})
}
}
mongoose.model('User', UserSchema)
控制器 - Controller
如管理员登录的判断,是放到控制器里面
// 增加一个登录的校验/判断 signin
exports.signin = async (ctx, next) => {
const { username, password } = ctx.request.body.user
const user = await User.findOne({ username })
if (!user) return ctx.redirect('/user/signup')
const isMatch = await user.comparePassword(password, user.password)
if (isMatch) {
ctx.session.user = {
_id: user._id,
role: user.role,
nickname: user.nickname
}
ctx.redirect('/')
} else {
ctx.redirect('/user/signin')
}
}
路由 - Router
// 管理员的注册登录路由
router.get('/user/signup', User.showSignup)
router.get('/user/signin', User.showSignin)
router.post('/user/signup', User.signup)
router.post('/user/signin', User.signin)
router.get('/logout', User.logout)