代码仓库:https://github.com/changeclass/koa2-weibo

数据模型

  1. 模型

    /**
     * @description:用户关注关系
     * @author: 小康
     * @url: https://xiaokang.me
     * @Date: 2020-12-19 15:31:54
     * @LastEditTime: 2020-12-19 15:31:55
     * @LastEditors: 小康
     */
    
    const seq = require('../seq')
    const { INTEGER } = require('../type')
    const UserRelation = seq.define('userRelation', {
      userId: {
        type: INTEGER,
        allowNull: false,
        comment: '用户ID'
      },
      followerId: {
        type: INTEGER,
        allowNull: false,
        comment: '被关注用户的ID'
      }
    })
    module.exports = UserRelation
  2. 创建关系

    /**
     * @description 数据模型入口文件
     * @author 小康
     */
    
    const User = require('./User')
    const Blog = require('./Blog')
    const UserRelation = require('./UserRelation')
    // 创建外键
    Blog.belongsTo(User, {
      foreignKey: 'userId'
    })
    
    UserRelation.belongsTo(User, {
      foreignKey: 'followerId'
    })
    User.hasMany(UserRelation, {
      foreignKey: 'userId'
    })
    
    module.exports = {
      User,
      Blog,
      UserRelation
    }

粉丝列表

  1. 控制器层

    /**
     * @description: 用户关系的controller
     * @author: 小康
     * @url: https://xiaokang.me
     * @Date: 2020-12-19 15:49:12
     * @LastEditTime: 2020-12-19 15:49:12
     * @LastEditors: 小康
     */
    
    const { SuccessModel } = require('../model/ResModel')
    const { getUsersByFollower } = require('../services/user-relation')
    
    /**
     * @author: 小康
     * @url: https://xiaokang.me
     * @param {number} userId 用户id
     * @description: 根据用户id获取粉丝列表
     */
    async function getFans(userId) {
      // service
      const { count, userList } = await getUsersByFollower(userId)
      return new SuccessModel({ count, userList })
    }
    
    module.exports = {
      getFans
    }
    
  2. 服务层

    /**
     * @description: 用户关系 services
     * @author: 小康
     * @url: https://xiaokang.me
     * @Date: 2020-12-19 15:50:52
     * @LastEditTime: 2020-12-19 15:50:52
     * @LastEditors: 小康
     */
    const { User, UserRelation } = require('../db/model/index')
    const { formatUser } = require('./_format')
    
    /**
     * @author: 小康
     * @url: https://xiaokang.me
     * @param {number} followerId 被关注人的ID
     * @description: 获取关注该用户的用户列表
     */
    async function getUsersByFollower(followerId) {
      const result = await User.findAndCountAll({
        attributes: ['id', 'userName', 'nickName', 'picture'],
        order: [['id', 'desc']],
        include: [{ model: UserRelation, where: { followerId } }]
      })
      // 格式化
      let userList = result.rows.map((row) => row.dataValues)
      userList = formatUser(userList)
      return { count: result.count, userList }
    }
    
    module.exports = {
      getUsersByFollower
    }

判断关注状态

const { count: fansCount, userList: fansList } = fansResult.data
// 我是否关注了此人

const amIFollowed = fansList.some((item) => {
  return item.userName === myUserName
})

关注和取消关注

  1. api路由层

    // 关注用户
    router.post('/follow', loginCheck, async (ctx, next) => {
      const { id: myUserId } = ctx.session.userInfo
      const { userId: curUserId } = ctx.request.body
      // controller
      ctx.body = await follow(myUserId, curUserId)
    })
    // 取消关注
    router.post('/unFollow', loginCheck, async (ctx, next) => {
      const { id: myUserId } = ctx.session.userInfo
      const { userId: curUserId } = ctx.request.body
      // controller
      ctx.body = await unFollow(myUserId, curUserId)
    })
  2. 控制器层

    /**
     * @author: 小康
     * @url: https://xiaokang.me
     * @param {*} myUserId 我的ID
     * @param {*} curUserId 当前登录的用户ID
     * @description: 关注
     */
    async function follow(myUserId, curUserId) {
      try {
        await addFollow(myUserId, curUserId)
        return new SuccessModel()
      } catch (err) {
        return new ErrorModel(addFollowerFailInfo)
      }
    }
    
    /**
     * @author: 小康
     * @url: https://xiaokang.me
     * @param {*} myUserId 我的ID
     * @param {*} curUserId 当前登录的用户ID
     * @description: 取消关注
     */
    async function unFollow(myUserId, curUserId) {
      const result = await deleteFollow(myUserId, curUserId)
      if (result) {
        return new SuccessModel()
      } else {
        return new ErrorModel(deleteUserFailInfo)
      }
    }
  3. 服务层

    /**
     * @author: 小康
     * @url: https://xiaokang.me
     * @param {number} userId 用户ID
     * @param {number} followerId 被关注用户id
     * @description: 添加关注关系
     */
    async function addFollow(userId, followerId) {
      const result = await UserRelation.create({
        userId,
        followerId
      })
      return result.dataValues
    }
    /**
     * @author: 小康
     * @url: https://xiaokang.me
     * @param {number} userId 用户ID
     * @param {number} followerId 被关注用户id
     * @description: 取消关注关系
     */
    async function deleteFollow(userId, followerId) {
      const result = await UserRelation.destroy({
        where: { userId, followerId }
      })
      return result > 0
    }