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

修改数据模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* @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

入口文件

1
2
3
4
5
6
const AtRelation = require('./AtRelation')

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

建立@关系

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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)
}
}

服务层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* @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. 视图路由层

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

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

  2. 控制器层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    /**
    * @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. 服务层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    /**
    * @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. 视图路由层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // @ 我的页面
    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. 控制器层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    /**
    * @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. 服务层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    /**
    * @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. 试图层

    试图层调用方法即可

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /**
    * @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. 服务层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    /**
    * @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
    }