这篇文章 开始 编写 标签管理的页面

    首先 新建 pages/tag/index.tsx和 pages/tag/index.module.scss分别 存放 标签的 页面和样式

    这个页面 我们采用 csr的方式来渲染页面,看看和ssr渲染页面的方式有何不同

    在这个页面 我们设计成 全部标签 和关注的标签,页面效果如下:
    image.png

    首先 我们 先 编写接口, 来获取 全部标签和已关注的标签

    新建 pages/api/tag/get.ts

    1.首先 引入 数据库等的配置

    1. import { NextApiRequest, NextApiResponse } from 'next';
    2. import { withIronSessionApiRoute } from 'iron-session/next';
    3. import { ironOptions } from 'config/index';
    4. import { ISession } from 'pages/api/index';
    5. import { prepareConnection } from 'db/index';
    6. import { Tag } from 'db/entity/index';

    2.通过 session 获取 当前用户的id,因为我们需要根据用户id获取该用户的标签数据

    1. const { userId = 0 } = session;

    3.链接 标签 数据库的 配置

    1. const db = await prepareConnection();
    2. const tagRepo = db.getRepository(Tag);

    4.首先 获取 全部标签的数据,这个我们只需要 根据 关联 的用户表去 标签的 数据表 查询即可

    1. const allTags = await tagRepo.find({
    2. relations: ['users'],
    3. });

    5.接下来 获取 关注的标签,关注的标签逻辑是,根据当前用户的id去查询标签数据,这样获取的数据就是该用户关注的标签数据

    1. const followTags = await tagRepo.find({
    2. relations: ['users'],
    3. where: (qb: any) => {
    4. qb.where('user_id = :id', {
    5. id: Number(userId),
    6. });
    7. },
    8. });

    6.最后将 获取的 所有标签数据 和 关注的标签数据 返回

    1. res?.status(200)?.json({
    2. code: 0,
    3. msg: '',
    4. data: {
    5. followTags,
    6. allTags,
    7. },
    8. });

    7.接下来 我们在客户端 使用 csr的方式 来获取 全部标签和已关注的标签数据。同followTags和allTags来分别存储全部标签数据和已关注的标签数据

    1. const [followTags, setFollowTags] = useState<ITag[]>();
    2. const [allTags, setAllTags] = useState<ITag[]>();
    3. useEffect(() => {
    4. request('/api/tag/get').then((res: any) => {
    5. if (res?.code === 0) {
    6. const { followTags = [], allTags = [] } = res?.data || {};
    7. setFollowTags(followTags);
    8. setAllTags(allTags);
    9. }
    10. })
    11. }, [needRefresh]);

    8.接下来 来渲染 全部标签的数据,这里有个逻辑,就是 显示 关注 还是已关注。当 当前用户id 能够在 接口返回的users中返回的id中能够找打,则表明 当前用户 已关注了 这个标签,则页面上显示 已关注,否则显示关注。当显示已关注的时候,按钮事件则是 取消关注的逻辑,否则则是 关注的逻辑。

    1. <TabPane tab="全部标签" key="all" className={styles.tags}>
    2. {
    3. allTags?.map(tag => (
    4. <div key={tag?.title} className={styles.tagWrapper}>
    5. <div>{(ANTD_ICONS as any)[tag?.icon]?.render()}</div>
    6. <div className={styles.title}>{tag?.title}</div>
    7. <div>{tag?.follow_count} 关注 {tag?.article_count} 文章</div>
    8. {
    9. tag?.users?.find((user) => Number(user?.id) === Number(userId)) ? (
    10. <Button type='primary' onClick={() => handleUnFollow(tag?.id)}>已关注</Button>
    11. ) : (
    12. <Button onClick={() => handleFollow(tag?.id)}>关注</Button>
    13. )
    14. }
    15. </div>
    16. ))
    17. }
    18. </TabPane>

    9.首先 编写 关注 标签的逻辑,新建 pages/api/tag/follow.ts
    10.首先引入数据库配置

    1. import { NextApiRequest, NextApiResponse } from 'next';
    2. import { withIronSessionApiRoute } from 'iron-session/next';
    3. import { ironOptions } from 'config/index';
    4. import { ISession } from 'pages/api/index';
    5. import { prepareConnection } from 'db/index';
    6. import { Tag, User } from 'db/entity/index';
    7. import { EXCEPTION_USER, EXCEPTION_TAG } from 'pages/api/config/codes';
    8. export default withIronSessionApiRoute(follow, ironOptions);

    11.从session获取用户的id

    1. const session: ISession = req.session;
    2. const { userId = 0 } = session;

    12.从 body中获取 前端传过来的参数,一共两个参数,一个type,值分别是follow和unfollow,表示是取消关注还是关注,另外一个参数数标签的id

    1. const { tagId, type } = req?.body || {};

    13.链接 标签和用户的数据库

    1. const db = await prepareConnection();
    2. const tagRepo = db.getRepository(Tag);
    3. const userRepo = db.getRepository(User);

    14.根据用户id去用户表中查询该用户信息,如果没找到,则提示当前用户不存在

    1. const user = await userRepo.findOne({
    2. where: {
    3. id: userId,
    4. },
    5. });
    6. if (!user) {
    7. res?.status(200).json({
    8. ...EXCEPTION_USER?.NOT_LOGIN,
    9. });
    10. return;
    11. }

    15.根据标签id从标签的数据表中查询所有标签

    1. const tag = await tagRepo.findOne({
    2. relations: ['users'],
    3. where: {
    4. id: tagId,
    5. },
    6. });

    16.如果从标签表中查询出有用户,如果类型是follow,则表示是关注操作,则将当前用户添加到 关注该标签的用户数据中,并且将关注该标签的数据增加1,如果类型是unfollow,则表示取消关注操作,则将当前用户从 关注该标签的用户数据中剔除,并且将关注该标签的数据减1.

    1. if (tag?.users) {
    2. if (type === 'follow') {
    3. tag.users = tag?.users?.concat([user]);
    4. tag.follow_count = tag?.follow_count + 1;
    5. } else if (type === 'unfollow') {
    6. tag.users = tag?.users?.filter((user) => user.id !== userId);
    7. tag.follow_count = tag?.follow_count - 1;
    8. }
    9. }

    17.最后将 标签的数据存入 标签的数据表中,如果成功,则返回200,否则提示失败

    1. if (tag) {
    2. const resTag = await tagRepo?.save(tag);
    3. res?.status(200)?.json({
    4. code: 0,
    5. msg: '',
    6. data: resTag,
    7. });
    8. } else {
    9. res?.status(200)?.json({
    10. ...EXCEPTION_TAG?.FOLLOW_FAILED,
    11. });
    12. }

    18.在前端点击关注的时候,传入两个参数,一个参数是type,值为follw,另外一个参数是标签id,如果接口成功,在前端提示关注成功,并且重新调标签的数据,刷新页面

    1. request.post('/api/tag/follow', {
    2. type: 'follow',
    3. tagId
    4. }).then((res: any) => {
    5. if (res?.code === 0) {
    6. message.success('关注成功');
    7. setNeedRefresh(!needRefresh);
    8. } else {
    9. message.error(res?.msg || '关注失败');
    10. }
    11. })

    19.取消关注,则是将type参数的值改成 unfollow。