因为 编辑文章是编辑不同的文章,所以这里需要 使用动态 路由
    首先新建 pages/editor/[id].tsx 和 index.module.scss

    编辑文章 首先 需要 把 当前的文章详情 回显到页面上

    这里通过 url 获取 当前 文章的 id

    然后通过ssr渲染的方式进行渲染

    根据 文章 id 和 关联的 用户表,链接 文章的 数据表,查询出来 属于 当前用户发布的这篇文章
    最后将 查询出来的 文章详情返回

    1. export async function getServerSideProps({ params }: any) {
    2. const articleId = params?.id;
    3. const db = await prepareConnection();
    4. const articleRepo = db.getRepository(Article);
    5. const article = await articleRepo.findOne({
    6. where: {
    7. id: articleId,
    8. },
    9. relations: ['user'],
    10. });
    11. return {
    12. props: {
    13. article: JSON.parse(JSON.stringify(article)),
    14. },
    15. };
    16. }

    在react客户端组件中,通过props获取article数据
    将 文章标题,文章内容通过state来控制,初始值是props获取的数据

    1. const [title, setTitle] = useState(article?.title || '');
    2. const [content, setContent] = useState(article?.content || '');

    通过 useRouter hooks 获取 文章Id

    1. const { push, query } = useRouter();
    2. const articleId = Number(query?.id)

    将获取的文章数据渲染出来

    1. return (
    2. <div className={styles.container}>
    3. <div className={styles.operation}>
    4. <Input
    5. className={styles.title}
    6. placeholder="请输入文章标题"
    7. value={title}
    8. onChange={handleTitleChange}
    9. />
    10. <Select
    11. className={styles.tag}
    12. mode="multiple"
    13. allowClear
    14. placeholder="请选择标签"
    15. onChange={handleSelectTag}
    16. >{allTags?.map((tag: any) => (
    17. <Select.Option key={tag?.id} value={tag?.id}>{tag?.title}</Select.Option>
    18. ))}</Select>
    19. <Button
    20. className={styles.button}
    21. type="primary"
    22. onClick={handlePublish}
    23. >
    24. 发布
    25. </Button>
    26. </div>
    27. <MDEditor value={content} height={1080} onChange={handleContentChange} />
    28. </div>
    29. );

    修改标题,通过state控制

    1. const handleTitleChange = (event: ChangeEvent<HTMLInputElement>) => {
    2. setTitle(event?.target?.value);
    3. };

    修改 文章内容的时候,也是通过state控制

    1. const handleContentChange = (content: any) => {
    2. setContent(content);
    3. };

    这里 新增一个 获取所有标签的接口
    首先 调用 标签接口,将标签数据存到state中

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

    接下来编写下 获取标签的接口
    新建 pages/api/tag/get.ts

    1.首先通过session获取当前用户信息

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

    2.链接 标签的数据表

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

    3.根据当前关联的用户表,查询出来所有标签

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

    4.根据用户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. });

    5.最后将所有的标签 和 当前用户 关注的 标签 返回

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

    6.在客户端 拿到 所有标签数据后渲染出来

    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>

    接着开始写 更新 文章的逻辑

    1、当点击更新的时候,首先判断一下 是否 输入了标题,如果没有输入标题,则提示用户输入标题

    1. if (!title) {
    2. message.warning('请输入文章标题');
    3. return ;
    4. }

    2、然后传参数调用更新文章的接口
    3、传的参数包括 文章id、标题、内容、标签
    4、当调用更新文章接口成功的时候提示更新文章成功并跳到当前文章
    5、如果失败,则提示发布失败

    1. request.post('/api/article/update', {
    2. id: articleId,
    3. title,
    4. content,
    5. tagIds
    6. }).then((res: any) => {
    7. if (res?.code === 0) {
    8. articleId ? push(`/article/${articleId}`) : push('/');
    9. message.success('更新成功');
    10. } else {
    11. message.error(res?.msg || '发布失败');
    12. }
    13. })

    6、接着编写 更新文章的接口,新建 pages/api/article/update.ts
    7、通过body获取 前端传过来的数据

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

    8、链接文章和标签的数据库

    1. const articleRepo = db.getRepository(Article);
    2. const tagRepo = db.getRepository(Tag);

    9、根据文章的id,关联用户表和标签表,查询出来当前文章

    1. const article = await articleRepo.findOne({
    2. where: {
    3. id,
    4. },
    5. relations: ['user', 'tags'],
    6. });

    10、判断查询出来的article是否存在,如果不存在,则提示文章不存在

    1. res.status(200).json({ ...EXCEPTION_ARTICLE.NOT_FOUND });

    11、如果存在,则将传过来的文章数据 覆盖之前的数据,如果保存成功,则提示成功,否则提示失败

    1. if (article) {
    2. article.title = title;
    3. article.content = content;
    4. article.update_time = new Date();
    5. article.tags = newTags;
    6. const resArticle = await articleRepo.save(article);
    7. if (resArticle) {
    8. res.status(200).json({ data: resArticle, code: 0, msg: '更新成功' });
    9. } else {
    10. res.status(200).json({ ...EXCEPTION_ARTICLE.UPDATE_FAILED });
    11. }
    12. }

    12、这里需要根据传过来的标签id,查询出来所有标签,然后将标签数量加1

    1. const tags = await tagRepo.find({
    2. where: tagIds?.map((tagId: number) => ({ id: tagId })),
    3. });
    4. const newTags = tags?.map((tag) => {
    5. tag.article_count = tag.article_count + 1;
    6. return tag;
    7. });

    13、最后记得将 需要的 第三方库引入进来

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

    这样就完成了编辑文章的前后端开发。