Skip to content

Commit 4fe0bd1

Browse files
authored
feat: topic edit (#25)
* feat: add edit to topic * feat: add access control to topic edit * refactor: headerConfig * refactor: rename page component and service method * refactor: rename topic create to edit
1 parent 23b3201 commit 4fe0bd1

File tree

9 files changed

+122
-42
lines changed

9 files changed

+122
-42
lines changed

config/routes.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,19 @@ const routes: IRoute[] = [
5454
path: '/topic/create',
5555
exact: true,
5656
title: '新建话题',
57-
component: '@/page/topic/create',
57+
component: '@/page/topic/edit',
5858
access: 'canPostTopic',
5959
},
6060
{
6161
path: '/topic/:id',
6262
exact: true,
6363
component: '@/page/topic/detail',
6464
},
65+
{
66+
path: '/topic/:id/edit',
67+
exact: true,
68+
component: '@/page/topic/edit',
69+
},
6570
{
6671
path: '/user/:loginname',
6772
exact: true,

src/layout/index.tsx

+29-19
Original file line numberDiff line numberDiff line change
@@ -43,34 +43,44 @@ const Layout: React.FC<React.PropsWithChildren<Props>> = (props) => {
4343
subTitle: currentRoute?.description,
4444
};
4545

46-
const detailRegx = /\/(topic|user)\/(.*)/g;
46+
const detailPaths = location.pathname.match(/\/(topic|user)\/(\w+)(\/\w+)?/);
4747

48-
if (location.pathname.match(detailRegx)) {
49-
const paths = location.pathname.split('/');
48+
if (detailPaths) {
49+
const [, category, id, status] = detailPaths;
5050

51-
const id = paths.pop();
52-
const category = paths.pop();
51+
const isEdit = status === '/edit';
52+
53+
const routes = [
54+
{
55+
path: '/',
56+
breadcrumbName: '主页',
57+
},
58+
{
59+
path: '/',
60+
breadcrumbName: BREADCRUMB_NAME_MAP[category as 'user' | 'topic'],
61+
},
62+
{
63+
path: isEdit
64+
? location.pathname.replace(status, '')
65+
: location.pathname,
66+
breadcrumbName: id,
67+
},
68+
];
69+
70+
if (isEdit) {
71+
routes.push({
72+
path: location.pathname,
73+
breadcrumbName: '编辑',
74+
});
75+
}
5376

5477
headerConfig = {
5578
title: null,
5679
breadcrumb: {
5780
itemRender: (route: { path: string; breadcrumbName: string }) => {
5881
return <Link to={route.path}>{route.breadcrumbName}</Link>;
5982
},
60-
routes: [
61-
{
62-
path: '/',
63-
breadcrumbName: '主页',
64-
},
65-
{
66-
path: '/',
67-
breadcrumbName: BREADCRUMB_NAME_MAP[category as 'user' | 'topic'],
68-
},
69-
{
70-
path: location.pathname,
71-
breadcrumbName: id,
72-
},
73-
],
83+
routes,
7484
},
7585
};
7686
}

src/page/topic/component/SubTitle.tsx

+18-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
import React from 'react';
22
import dayjs from 'dayjs';
33

4-
import { Avatar, Divider, Space, Button } from 'antd';
5-
import { Link } from 'umi';
4+
import { Avatar, Divider, Space } from 'antd';
5+
import { Link, useModel } from 'umi';
6+
import { FormOutlined } from '@ant-design/icons';
67

78
const SubTitle: React.FC<Props> = (props) => {
8-
const { author, create_at, visit_count, reply_count } = props;
9+
const { author, create_at, visit_count, reply_count, author_id } = props;
10+
11+
const { user } = useModel('user');
12+
13+
const renderEdit = () =>
14+
user?.id === author_id && (
15+
<Link to={location.pathname + '/edit'}>
16+
<FormOutlined />
17+
</Link>
18+
);
19+
920
return (
1021
<Space size={0} split={<Divider type="vertical"></Divider>}>
1122
<Link to={`/user/${author.loginname}`}>
@@ -14,6 +25,8 @@ const SubTitle: React.FC<Props> = (props) => {
1425
<span>发布:{dayjs(create_at).format('YYYY-MM-DD hh:mm:ss')}</span>
1526
<span>浏览:{visit_count}</span>
1627
<span>回复:{reply_count}</span>
28+
29+
{renderEdit()}
1730
</Space>
1831
);
1932
};
@@ -29,4 +42,6 @@ interface Props {
2942
loginname: string;
3043
avatar_url: string;
3144
};
45+
46+
author_id: string;
3247
}

src/page/topic/detail.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const TopicDetailPage: React.FC<React.PropsWithChildren<Props>> = (props) => {
3131
return;
3232
}
3333

34-
const res = await API.queryTopicDetail({
34+
const res = await API.readTopic({
3535
id: topicId,
3636
mdrender: false,
3737
});
@@ -58,7 +58,7 @@ const TopicDetailPage: React.FC<React.PropsWithChildren<Props>> = (props) => {
5858
return;
5959
}
6060

61-
await API.postReply(topicId, {
61+
await API.createReply(topicId, {
6262
...data,
6363
accesstoken: token,
6464
});
@@ -71,7 +71,7 @@ const TopicDetailPage: React.FC<React.PropsWithChildren<Props>> = (props) => {
7171
return;
7272
}
7373

74-
await API.postReplyUps(replyId, {
74+
await API.updateReplyUps(replyId, {
7575
accesstoken: token,
7676
});
7777
};
File renamed without changes.

src/page/topic/create/index.tsx src/page/topic/edit/index.tsx

+42-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import { useModel, useHistory } from 'umi';
2+
import { useModel, useHistory, useParams, useRequest } from 'umi';
33
import { Form, Input, Select, Button, Space } from 'antd';
44
import { TABS_MAP } from '@/constants';
55

@@ -8,24 +8,59 @@ import Markdown from '@/component/Markdown';
88
import * as API from '@/service/topic';
99
import * as styles from './index.less';
1010

11-
const CreateTopic: React.FC<Props> = (props) => {
11+
const TopicEditPage: React.FC<Props> = (props) => {
1212
const history = useHistory();
1313
const [form] = Form.useForm();
1414
const { initialState } = useModel('@@initialState');
15+
const { user } = useModel('user');
1516

1617
const token = initialState?.token;
1718

19+
const { id } = useParams<{ id?: string }>();
20+
21+
useRequest(
22+
async () => {
23+
if (!id) return;
24+
const { data } = await API.readTopic({
25+
id,
26+
mdrender: false,
27+
});
28+
29+
if (data.author_id !== user?.id) {
30+
history.push(location.pathname.replace(/\/edit$/, ''));
31+
return;
32+
}
33+
34+
form.setFieldsValue({
35+
title: data.title,
36+
content: data.content,
37+
tab: data.tab,
38+
});
39+
},
40+
{
41+
ready: !!id,
42+
},
43+
);
44+
1845
const onFinish = async (values: any) => {
1946
console.debug('===create.values', values);
2047

2148
if (!token) {
2249
return;
2350
}
2451

25-
await API.postTopic({
26-
...values,
27-
accesstoken: token,
28-
});
52+
if (id) {
53+
await API.updateTopic({
54+
topic_id: id,
55+
...values,
56+
accesstoken: token,
57+
});
58+
} else {
59+
await API.createTopic({
60+
...values,
61+
accesstoken: token,
62+
});
63+
}
2964

3065
onReset();
3166

@@ -88,6 +123,6 @@ const CreateTopic: React.FC<Props> = (props) => {
88123
);
89124
};
90125

91-
export default CreateTopic;
126+
export default TopicEditPage;
92127

93128
interface Props {}

src/page/topic/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const TopicListPage: React.FC<Props> = (props) => {
3636

3737
const { loading, refresh } = useRequest(
3838
async () => {
39-
const res = await API.queryTopicList({
39+
const res = await API.listTopic({
4040
tab,
4141
page,
4242
limit,

src/page/user/index.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import { getUserInfo } from '@/service/user';
1111

1212
import * as styles from './index.less';
1313

14-
const { Text, Paragraph } = Typography;
14+
const { Text } = Typography;
1515

16-
const UserDetail: React.FC<Props> = (props) => {
16+
const UserDetailPage: React.FC<Props> = (props) => {
1717
const params: Record<string, any> = useParams();
1818

1919
const { data } = useRequest(async () => {
@@ -92,6 +92,6 @@ const UserDetail: React.FC<Props> = (props) => {
9292
);
9393
};
9494

95-
export default UserDetail;
95+
export default UserDetailPage;
9696

9797
interface Props {}

src/service/topic.ts

+20-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { request } from 'umi';
22
import { BASE_URL } from '@/constants';
33

4-
export const queryTopicList = async (params: {
4+
export const listTopic = async (params: {
55
tab?: string;
66
page?: number;
77
limit?: number;
@@ -25,7 +25,7 @@ export const queryTopicList = async (params: {
2525
return res;
2626
};
2727

28-
export const postTopic = async (data: {
28+
export const createTopic = async (data: {
2929
title: string;
3030
tab: string;
3131
content: string;
@@ -39,7 +39,22 @@ export const postTopic = async (data: {
3939
return request(`${BASE_URL}/api/v1/topics`, options);
4040
};
4141

42-
export const queryTopicDetail = async (params: {
42+
export const updateTopic = async (data: {
43+
topic_id: string;
44+
title: string;
45+
tab: string;
46+
content: string;
47+
accesstoken: string;
48+
}) => {
49+
const options: any = {
50+
method: 'POST',
51+
data,
52+
};
53+
54+
return request(`${BASE_URL}/api/v1/topics/update`, options);
55+
};
56+
57+
export const readTopic = async (params: {
4358
id: string;
4459
mdrender?: boolean;
4560
accesstoken?: boolean;
@@ -58,7 +73,7 @@ export const queryTopicDetail = async (params: {
5873
return request(`${BASE_URL}/api/v1/topic/${id}`, options);
5974
};
6075

61-
export const postReply = async (
76+
export const createReply = async (
6277
topicId: string,
6378
data: {
6479
content: string;
@@ -74,7 +89,7 @@ export const postReply = async (
7489
return request(`${BASE_URL}/api/v1/topic/${topicId}/replies`, options);
7590
};
7691

77-
export const postReplyUps = async (
92+
export const updateReplyUps = async (
7893
replyId: string,
7994
data: {
8095
accesstoken: string;

0 commit comments

Comments
 (0)