当点击 写文章的时候,先判断用户是否登录,如果没有登录,则提示用户先登录,如果已经登录,则跳到新建文章页面
<Button onClick={handleGotoEditorPage}>写文章</Button>
const handleGotoEditorPage = () => {
if (userId) {
push('/editor/new');
} else {
message.warning('请先登录');
}
};
在pages目录下创建 editor/new.tsx,表示 新建文章的页面
首先编写 markdown编辑器,这里使用 开源的一款markdown编辑器,@uiw/react-md-editor
安装
yarn add @uiw/react-md-editor
引入
const MDEditor = dynamic(() => import('@uiw/react-md-editor'), { ssr: false });
import '@uiw/react-md-editor/markdown-editor.css';
import '@uiw/react-markdown-preview/markdown.css';
<MDEditor />
定义state表示编辑器的内容
const [content, setContent] = useState('');
<MDEditor value={content} height={1080} />
添加change事件
<MDEditor value={content} height={1080} onChange={handleContentChange} />
const handleContentChange = (content: any) => {
setContent(content);
};
添加 输入标题 组件
const [title, setTitle] = useState('');
const handleTitleChange = (event: ChangeEvent<HTMLInputElement>) => {
setTitle(event?.target?.value);
};
<Input
className={styles.title}
placeholder="请输入文章标题"
value={title}
onChange={handleTitleChange}
/>
添加 标签选择 组件
<Select
className={styles.tag}
mode="multiple"
allowClear
placeholder="请选择标签"
onChange={handleSelectTag}
>{allTags?.map((tag: any) => (
<Select.Option key={tag?.id} value={tag?.id}>{tag?.title}</Select.Option>
))}</Select>
新增 state 控制 标签
const [allTags, setAllTags] = useState([]);
添加 选择 标签的 事件
const handleSelectTag = (value: []) => {
setTagIds(value);
}
新建 标签的 数据表
import { Entity, BaseEntity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from 'typeorm';
import { User } from './user'
import { Article } from './article'
@Entity({name: 'tags'})
export class Tag extends BaseEntity {
@PrimaryGeneratedColumn()
readonly id!: number;
@Column()
title!: string;
@Column()
icon!: string;
@Column()
follow_count!: number;
@Column()
article_count!: number;
@ManyToMany(() => User, {
cascade: true
})
@JoinTable({
name: 'tags_users_rel',
joinColumn: {
name: 'tag_id'
},
inverseJoinColumn: {
name: 'user_id'
}
})
users!: User[]
@ManyToMany(() => Article, (article) => article.tags)
@JoinTable({
name: 'articles_tags_rel',
joinColumn: {
name: 'tag_id'
},
inverseJoinColumn: {
name: 'article_id'
}
})
articles!: Article[]
}
新增 获取所有标签的接口,新建 api/tag/get.ts
1.从session中获取用户信息
2.从tag表 查询 所有 标签数据
3.关联users表,根据users表,查询所有标签,返回allTags
4.关联User表,根据当前登录用户的信息,查询该用户 关注的标签,返回followTags
import { NextApiRequest, NextApiResponse } from 'next';
import { withIronSessionApiRoute } from 'iron-session/next';
import { ironOptions } from 'config/index';
import { ISession } from 'pages/api/index';
import { prepareConnection } from 'db/index';
import { Tag } from 'db/entity/index';
export default withIronSessionApiRoute(get, ironOptions);
async function get(req: NextApiRequest, res: NextApiResponse) {
const session: ISession = req.session;
const { userId = 0 } = session;
const db = await prepareConnection();
const tagRepo = db.getRepository(Tag);
const followTags = await tagRepo.find({
relations: ['users'],
where: (qb: any) => {
qb.where('user_id = :id', {
id: Number(userId),
});
},
});
const allTags = await tagRepo.find({
relations: ['users'],
});
res?.status(200)?.json({
code: 0,
msg: '',
data: {
followTags,
allTags,
},
});
}
在editor/new.tsx中 调 获取 标签的接口拿到标签数据
useEffect(() => {
request.get('/api/tag/get').then((res: any) => {
if (res?.code === 0) {
setAllTags(res?.data?.allTags || [])
}
})
}, []);
最后渲染 所有标签
<Select
className={styles.tag}
mode="multiple"
allowClear
placeholder="请选择标签"
onChange={handleSelectTag}
>{allTags?.map((tag: any) => (
<Select.Option key={tag?.id} value={tag?.id}>{tag?.title}</Select.Option>
))}</Select>
这样页面就出来了,也获取到了markdown,标签,标题的数据
然后开始写发布文章,
1.先判断是否输入标题,如果没有输入标题,就提示用户输入标题
2.然后调 发布文章的接口,参数就是 标题,markdown数据,标签
3.当接口调取成功的时候,提示发布成功,并跳到用户中心 的页面
4.当接口调取失败的时候,提示发布失败
const handlePublish = () => {
if (!title) {
message.warning('请输入文章标题');
return ;
}
request.post('/api/article/publish', {
title,
content,
tagIds
}).then((res: any) => {
if (res?.code === 0) {
userId ? push(`/user/${userId}`) : push('/');
message.success('发布成功');
} else {
message.error(res?.msg || '发布失败');
}
})
};
现在写下 发布文章的接口
新建 api/artice/publish.ts
1.引入数据库和user, tag, article三张数据表
import { prepareConnection } from 'db/index';
import { User, Article, Tag } from 'db/entity/index';
2.链接三个数据表
const db = await prepareConnection();
const userRepo = db.getRepository(User);
const articleRepo = db.getRepository(Article);
const tagRepo = db.getRepository(Tag);
3.从req.body中获取传入的参数
const { title = '', content = '', tagIds = [] } = req.body;
4.从session中获取用户信息
const session: ISession = req.session;
5.根据session从user表中查询当前用户信息
const user = await userRepo.findOne({
id: session.userId,
});
6.根据传入的标签,获取所有的标签
const tags = await tagRepo.find({
where: tagIds?.map((tagId: number) => ({ id: tagId })),
});
7.将传入的数据 存入到 article表中, 如果有用户信息,将用户信息也存入表,并且标签数量增加
const article = new Article();
article.title = title;
article.content = content;
article.create_time = new Date();
article.update_time = new Date();
article.is_delete = 0;
article.views = 0;
if (user) {
article.user = user;
}
if (tags) {
const newTags = tags?.map((tag) => {
tag.article_count = tag?.article_count + 1;
return tag;
});
article.tags = newTags;
}
const resArticle = await articleRepo.save(article);
if (resArticle) {
res.status(200).json({ data: resArticle, code: 0, msg: '发布成功' });
} else {
res.status(200).json({ ...EXCEPTION_ARTICLE.PUBLISH_FAILED });
}
这样就完成了文章发布