概述
技术团队博客系统
技术栈
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 = 10const Schema = mongoose.Schemaconst UserSchema = new Schema({// user admin superAdminrole: {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 = thisif (!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 = hashnext()})})})// 静态方法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
如管理员登录的判断,是放到控制器里面
// 增加一个登录的校验/判断 signinexports.signin = async (ctx, next) => {const { username, password } = ctx.request.body.userconst 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)

