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

修改数据模型

/**
 * @description: 微博艾特用户的关系
 * @author: 小康
 * @url: https://xiaokang.me
 * @Date: 2020-12-20 11:10:05
 * @LastEditTime: 2020-12-20 11:10:05
 * @LastEditors: 小康
 */
const seq = require('../seq')
const { INTEGER, BOOLEAN } = require('../type')

const AtRelation = seq.define('atRelation', {
  userId: {
    type: INTEGER,
    allowNull: false,
    comment: '用户 id'
  },
  blogId: {
    type: INTEGER,
    allowNull: false,
    comment: '微博 id'
  },
  isRead: {
    type: BOOLEAN,
    allowNull: false,
    defaultValue: false,
    comment: '是否已读'
  }
})

module.exports = AtRelation

入口文件

const AtRelation = require('./AtRelation')

Blog.hasMany(AtRelation, {
  foreignKey: 'blogId'
})

建立@关系

修改创建微博时的逻辑,应该在创建微博时创建艾特关系

const { createAtReplation } = require('../services/at-relation')
const { getUserInfo } = require('../services/user')
/**
 * @author: 小康
 * @url: https://xiaokang.me
 * @param {string} userId
 * @param {string} content
 * @param {string} image
 * @description: 创建微博
 */
async function create({ userId, content, image }) {
  // 分析并手机 content 中的@用户
  // content格式
  const atUserNameList = []
  content = content.replace(REG_FOR_AT_WHO, (matchStr, nickName, userName) => {
    // 目的是获取用户名
    atUserNameList.push(userName)
    return matchStr //替换不生效
  })
  // 根据 @ 用户名查询用户信息
  const atUserList = await Promise.all(
    atUserNameList.map((userName) => getUserInfo(userName))
  )
  // 根据用户信息 获取id
  const atUserIdList = atUserList.map((user) => user.id)
  // servers
  try {
    const blog = await createBlog({ userId, content: xss(content), image })
    // 创建at关系
    await Promise.all(
      atUserIdList.map((userId) => {
        createAtReplation(blog.id, userId)
      })
    )
    // 返回
    return new SuccessModel(blog)
  } catch (error) {
    console.error(error.message, error.stack)
    return new ErrorModel(createBlogFailInfo)
  }
}

服务层

/**
 * @description: 微博 @ 用户关系
 * @author: 小康
 * @url: https://xiaokang.me
 * @Date: 2020-12-20 11:39:05
 * @LastEditTime: 2020-12-20 11:39:06
 * @LastEditors: 小康
 */

const { AtRelation } = require('../db/model')

/**
 * @author: 小康
 * @url: https://xiaokang.me
 * @param {*} blogId
 * @param {*} userId
 * @description: 创建微博艾特用户的关系
 */
async function createAtReplation(blogId, userId) {
  const result = await AtRelation.create({
    blogId,
    userId
  })
  return result.dataValues
}

module.exports = { createAtReplation }

显示at数量

  1. 视图路由层

    // 获取 @ 数量
    const atCount = await getAtMeCount(userId)

    只需要调用控制器层的方法获取数量即可。

  2. 控制器层

    /**
     * @description: 微博 @ 关系
     * @author: 小康
     * @url: https://xiaokang.me
     * @Date: 2020-12-20 14:10:21
     * @LastEditTime: 2020-12-20 14:10:23
     * @LastEditors: 小康
     */
    
    const { getAtRelationCount } = require('../services/at-relation')
    const { SuccessModel } = require('../model/ResModel')
    /**
     * @author: 小康
     * @url: https://xiaokang.me
     * @param {*} userId
     * @description: 获取 @ 我的微博数量
     */
    async function getAtMeCount(userId) {
      const count = await getAtRelationCount(userId)
      return new SuccessModel({ count })
    }
    
    module.exports = {
      getAtMeCount
    }
    
  3. 服务层

    /**
     * @author: 小康
     * @url: https://xiaokang.me
     * @param {*} userId
     * @description: 获取at用户的微博数量(未读)
     */
    async function getAtRelationCount(userId) {
      const result = await AtRelation.findAndCountAll({
        where: {
          userId,
          isRead: false
        }
      })
      return result.count
    }

@me页面

  1. 视图路由层

    // @ 我的页面
    router.get('/at-me', loginRedirect, async (ctx, next) => {
      const { id: userId } = ctx.session.userInfo
      // 获取 @ 我的数量
      const atCountResult = await getAtMeCount(userId)
      const { count: atCount } = atCountResult.data
      // 获取第一页列表
      const result = await getAtMeBlogList(userId)
      const { isEmpty, blogList, pageSize, pageIndex, count } = result.data
      // 渲染页面
      await ctx.render('atMe', {
        blogData: {
          isEmpty,
          blogList,
          pageSize,
          pageIndex,
          count
        },
        atCount
      })
      // 标记为已读
      if (atCount > 0) {
      }
    })
  2. 控制器层

    /**
     * @author: 小康
     * @url: https://xiaokang.me
     * @param {*} userId
     * @param {*} pageIndex
     * @description: 获取@ 用户的微博列表
     */
    async function getAtMeBlogList(userId, pageIndex = 0) {
      // service
      const result = await getUserBlogList({
        userId,
        pageIndex,
        pageSize: PAGE_SIZE
      })
      const { count, blogList } = result
    
      // 返回
      return new SuccessModel({
        isEmpty: blogList.length === 0,
        blogList,
        pageSize: PAGE_SIZE,
        pageIndex,
        count
      })
    }
  3. 服务层

    /**
     * @author: 小康
     * @url: https://xiaokang.me
     * @param {*} userId
     * @param {*} pageIndex
     * @param {*} pageSize
     * @description: 获取 @ 用户的微博列表
     */
    async function getUserBlogList({ userId, pageIndex, pageSize = PAGE_SIZE }) {
      const result = await Blog.findAndCountAll({
        limit: pageSize,
        offset: pageSize * pageIndex,
        order: [['id', 'desc']],
        include: [
          // @ 关系
          {
            model: AtRelation,
            attributes: ['userId', 'blogId'],
            where: { userId }
          },
          // 用户
          {
            model: User,
            attributes: ['userName', 'nickName', 'picture']
          }
        ]
      })
      let blogList = result.rows.map((row) => row.dataValues)
      blogList = formatBlog(blogList)
      blogList = blogList.map((blogItem) => {
        blogItem.user = formatUser(blogItem.user.dataValues)
        return blogItem
      })
      return {
        count: result.count,
        blogList
      }
    }

@消息已读

  1. 试图层

    试图层调用方法即可

    if (atCount > 0) {
      markAsRead(userId)
    }
  2. 控制层

    /**
     * @author: 小康
     * @url: https://xiaokang.me
     * @param {*} userId
     * @description: 标记已读
     */
    async function markAsRead(userId) {
      try {
        await updataAtRelation({ newIsRead: true }, { userId, isRead: false })
      } catch (error) {
        console.error(error)
      }
      // 不需要返回
    }
  3. 服务层

    /**
     * @author: 小康
     * @url: https://xiaokang.me
     * @param {Object} 要更新的内容
     * @param {Object} 条件
     * @description: 更新数据
     */
    async function updataAtRelation({ newIsRead }, { userId, isRead }) {
      // 拼接更新内容
      const updataData = {}
      if (newIsRead) {
        updataData.isRead = newIsRead
      }
      // 拼接查询条件
      const whereData = {}
      if (userId) {
        whereData.userId = userId
      }
      if (isRead) {
        whereData.isRead = isRead
      }
      // 执行更新
      const result = await AtRelation.update(updataData, {
        where: whereData
      })
      return result[0] > 0
    }