当点击 写文章的时候,先判断用户是否登录,如果没有登录,则提示用户先登录,如果已经登录,则跳到新建文章页面

    1. <Button onClick={handleGotoEditorPage}>写文章</Button>
    2. const handleGotoEditorPage = () => {
    3. if (userId) {
    4. push('/editor/new');
    5. } else {
    6. message.warning('请先登录');
    7. }
    8. };

    在pages目录下创建 editor/new.tsx,表示 新建文章的页面

    首先编写 markdown编辑器,这里使用 开源的一款markdown编辑器,@uiw/react-md-editor
    安装

    1. yarn add @uiw/react-md-editor

    引入

    1. const MDEditor = dynamic(() => import('@uiw/react-md-editor'), { ssr: false });
    2. import '@uiw/react-md-editor/markdown-editor.css';
    3. import '@uiw/react-markdown-preview/markdown.css';
    4. <MDEditor />

    定义state表示编辑器的内容

    1. const [content, setContent] = useState('');
    2. <MDEditor value={content} height={1080} />

    添加change事件

    1. <MDEditor value={content} height={1080} onChange={handleContentChange} />
    2. const handleContentChange = (content: any) => {
    3. setContent(content);
    4. };

    添加 输入标题 组件

    1. const [title, setTitle] = useState('');
    2. const handleTitleChange = (event: ChangeEvent<HTMLInputElement>) => {
    3. setTitle(event?.target?.value);
    4. };
    5. <Input
    6. className={styles.title}
    7. placeholder="请输入文章标题"
    8. value={title}
    9. onChange={handleTitleChange}
    10. />

    添加 标签选择 组件

    1. <Select
    2. className={styles.tag}
    3. mode="multiple"
    4. allowClear
    5. placeholder="请选择标签"
    6. onChange={handleSelectTag}
    7. >{allTags?.map((tag: any) => (
    8. <Select.Option key={tag?.id} value={tag?.id}>{tag?.title}</Select.Option>
    9. ))}</Select>

    新增 state 控制 标签

    1. const [allTags, setAllTags] = useState([]);

    添加 选择 标签的 事件

    1. const handleSelectTag = (value: []) => {
    2. setTagIds(value);
    3. }

    新建 标签的 数据表

    1. import { Entity, BaseEntity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from 'typeorm';
    2. import { User } from './user'
    3. import { Article } from './article'
    4. @Entity({name: 'tags'})
    5. export class Tag extends BaseEntity {
    6. @PrimaryGeneratedColumn()
    7. readonly id!: number;
    8. @Column()
    9. title!: string;
    10. @Column()
    11. icon!: string;
    12. @Column()
    13. follow_count!: number;
    14. @Column()
    15. article_count!: number;
    16. @ManyToMany(() => User, {
    17. cascade: true
    18. })
    19. @JoinTable({
    20. name: 'tags_users_rel',
    21. joinColumn: {
    22. name: 'tag_id'
    23. },
    24. inverseJoinColumn: {
    25. name: 'user_id'
    26. }
    27. })
    28. users!: User[]
    29. @ManyToMany(() => Article, (article) => article.tags)
    30. @JoinTable({
    31. name: 'articles_tags_rel',
    32. joinColumn: {
    33. name: 'tag_id'
    34. },
    35. inverseJoinColumn: {
    36. name: 'article_id'
    37. }
    38. })
    39. articles!: Article[]
    40. }

    新增 获取所有标签的接口,新建 api/tag/get.ts

    1.从session中获取用户信息
    2.从tag表 查询 所有 标签数据
    3.关联users表,根据users表,查询所有标签,返回allTags
    4.关联User表,根据当前登录用户的信息,查询该用户 关注的标签,返回followTags

    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';
    7. export default withIronSessionApiRoute(get, ironOptions);
    8. async function get(req: NextApiRequest, res: NextApiResponse) {
    9. const session: ISession = req.session;
    10. const { userId = 0 } = session;
    11. const db = await prepareConnection();
    12. const tagRepo = db.getRepository(Tag);
    13. const followTags = await tagRepo.find({
    14. relations: ['users'],
    15. where: (qb: any) => {
    16. qb.where('user_id = :id', {
    17. id: Number(userId),
    18. });
    19. },
    20. });
    21. const allTags = await tagRepo.find({
    22. relations: ['users'],
    23. });
    24. res?.status(200)?.json({
    25. code: 0,
    26. msg: '',
    27. data: {
    28. followTags,
    29. allTags,
    30. },
    31. });
    32. }

    在editor/new.tsx中 调 获取 标签的接口拿到标签数据

    1. useEffect(() => {
    2. request.get('/api/tag/get').then((res: any) => {
    3. if (res?.code === 0) {
    4. setAllTags(res?.data?.allTags || [])
    5. }
    6. })
    7. }, []);

    最后渲染 所有标签

    1. <Select
    2. className={styles.tag}
    3. mode="multiple"
    4. allowClear
    5. placeholder="请选择标签"
    6. onChange={handleSelectTag}
    7. >{allTags?.map((tag: any) => (
    8. <Select.Option key={tag?.id} value={tag?.id}>{tag?.title}</Select.Option>
    9. ))}</Select>

    这样页面就出来了,也获取到了markdown,标签,标题的数据

    然后开始写发布文章,
    1.先判断是否输入标题,如果没有输入标题,就提示用户输入标题
    2.然后调 发布文章的接口,参数就是 标题,markdown数据,标签
    3.当接口调取成功的时候,提示发布成功,并跳到用户中心 的页面
    4.当接口调取失败的时候,提示发布失败

    1. const handlePublish = () => {
    2. if (!title) {
    3. message.warning('请输入文章标题');
    4. return ;
    5. }
    6. request.post('/api/article/publish', {
    7. title,
    8. content,
    9. tagIds
    10. }).then((res: any) => {
    11. if (res?.code === 0) {
    12. userId ? push(`/user/${userId}`) : push('/');
    13. message.success('发布成功');
    14. } else {
    15. message.error(res?.msg || '发布失败');
    16. }
    17. })
    18. };

    现在写下 发布文章的接口
    新建 api/artice/publish.ts
    1.引入数据库和user, tag, article三张数据表

    1. import { prepareConnection } from 'db/index';
    2. import { User, Article, Tag } from 'db/entity/index';

    2.链接三个数据表

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

    3.从req.body中获取传入的参数

    1. const { title = '', content = '', tagIds = [] } = req.body;

    4.从session中获取用户信息

    1. const session: ISession = req.session;

    5.根据session从user表中查询当前用户信息

    1. const user = await userRepo.findOne({
    2. id: session.userId,
    3. });

    6.根据传入的标签,获取所有的标签

    1. const tags = await tagRepo.find({
    2. where: tagIds?.map((tagId: number) => ({ id: tagId })),
    3. });

    7.将传入的数据 存入到 article表中, 如果有用户信息,将用户信息也存入表,并且标签数量增加

    1. const article = new Article();
    2. article.title = title;
    3. article.content = content;
    4. article.create_time = new Date();
    5. article.update_time = new Date();
    6. article.is_delete = 0;
    7. article.views = 0;
    8. if (user) {
    9. article.user = user;
    10. }
    11. if (tags) {
    12. const newTags = tags?.map((tag) => {
    13. tag.article_count = tag?.article_count + 1;
    14. return tag;
    15. });
    16. article.tags = newTags;
    17. }
    18. const resArticle = await articleRepo.save(article);
    19. if (resArticle) {
    20. res.status(200).json({ data: resArticle, code: 0, msg: '发布成功' });
    21. } else {
    22. res.status(200).json({ ...EXCEPTION_ARTICLE.PUBLISH_FAILED });
    23. }

    这样就完成了文章发布