feat: add message editor (close #59)
This commit is contained in:
@@ -18,6 +18,7 @@ import { StatusContext } from './context/Status';
|
|||||||
import Message from './pages/Message';
|
import Message from './pages/Message';
|
||||||
import Channel from './pages/Channel';
|
import Channel from './pages/Channel';
|
||||||
import EditChannel from './pages/Channel/EditChannel';
|
import EditChannel from './pages/Channel/EditChannel';
|
||||||
|
import EditMessage from './pages/Message/EditMessage';
|
||||||
|
|
||||||
const Home = lazy(() => import('./pages/Home'));
|
const Home = lazy(() => import('./pages/Home'));
|
||||||
const About = lazy(() => import('./pages/About'));
|
const About = lazy(() => import('./pages/About'));
|
||||||
@@ -141,6 +142,22 @@ function App() {
|
|||||||
</PrivateRoute>
|
</PrivateRoute>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path='/editor'
|
||||||
|
element={
|
||||||
|
<PrivateRoute>
|
||||||
|
<EditMessage />
|
||||||
|
</PrivateRoute>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path='/editor/:id'
|
||||||
|
element={
|
||||||
|
<PrivateRoute>
|
||||||
|
<EditMessage />
|
||||||
|
</PrivateRoute>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Route
|
<Route
|
||||||
path='/login'
|
path='/login'
|
||||||
element={
|
element={
|
||||||
|
|||||||
@@ -18,6 +18,11 @@ const headerButtons = [
|
|||||||
to: '/message',
|
to: '/message',
|
||||||
icon: 'mail',
|
icon: 'mail',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: '编辑',
|
||||||
|
to: '/editor',
|
||||||
|
icon: 'edit',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: '通道',
|
name: '通道',
|
||||||
to: '/channel',
|
to: '/channel',
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { API, openPage, showError, showSuccess, showWarning } from '../helpers';
|
|||||||
|
|
||||||
import { ITEMS_PER_PAGE } from '../constants';
|
import { ITEMS_PER_PAGE } from '../constants';
|
||||||
import { renderTimestamp } from '../helpers/render';
|
import { renderTimestamp } from '../helpers/render';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
function renderStatus(status) {
|
function renderStatus(status) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@@ -317,6 +318,15 @@ const MessagesTable = () => {
|
|||||||
>
|
>
|
||||||
查看
|
查看
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
size={'small'}
|
||||||
|
primary
|
||||||
|
loading={loading}
|
||||||
|
as={Link}
|
||||||
|
to={'/editor/' + message.id}
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size={'small'}
|
size={'small'}
|
||||||
color={'yellow'}
|
color={'yellow'}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Button, Form, Grid, Header, Message } from 'semantic-ui-react';
|
import { Button, Form, Grid, Header, Message } from 'semantic-ui-react';
|
||||||
import { API, showError, showSuccess, testChannel } from '../helpers';
|
import { API, showError, showSuccess, testChannel } from '../helpers';
|
||||||
|
import { loadUser, loadUserChannels } from '../helpers/loader';
|
||||||
|
|
||||||
const PushSetting = () => {
|
const PushSetting = () => {
|
||||||
let [user, setUser] = useState({
|
let [user, setUser] = useState({
|
||||||
@@ -16,44 +17,19 @@ const PushSetting = () => {
|
|||||||
setUser((inputs) => ({ ...inputs, [name]: value }));
|
setUser((inputs) => ({ ...inputs, [name]: value }));
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadUser = async () => {
|
|
||||||
let res = await API.get(`/api/user/self`);
|
|
||||||
const { success, message, data } = res.data;
|
|
||||||
if (success) {
|
|
||||||
if (data.channel === '') {
|
|
||||||
data.channel = 'email';
|
|
||||||
}
|
|
||||||
if (data.token === ' ') {
|
|
||||||
data.token = '';
|
|
||||||
}
|
|
||||||
setUser(data);
|
|
||||||
} else {
|
|
||||||
showError(message);
|
|
||||||
}
|
|
||||||
setLoading(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const loadUserChannels = async () => {
|
|
||||||
let res = await API.get(`/api/channel?brief=true`);
|
|
||||||
const { success, message, data } = res.data;
|
|
||||||
if (success) {
|
|
||||||
data.forEach((channel) => {
|
|
||||||
channel.key = channel.name;
|
|
||||||
channel.text = channel.name;
|
|
||||||
channel.value = channel.name;
|
|
||||||
if (channel.description === '') {
|
|
||||||
channel.description = '无备注信息';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setChannels(data);
|
|
||||||
} else {
|
|
||||||
showError(message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadUser().then();
|
const loader = async () => {
|
||||||
loadUserChannels().then();
|
let user = await loadUser();
|
||||||
|
if (user) {
|
||||||
|
setUser(user);
|
||||||
|
}
|
||||||
|
let channels = await loadUserChannels();
|
||||||
|
if (channels) {
|
||||||
|
setChannels(channels);
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
};
|
||||||
|
loader().then();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const submit = async (which) => {
|
const submit = async (which) => {
|
||||||
@@ -106,7 +82,9 @@ const PushSetting = () => {
|
|||||||
<Button onClick={() => submit('general')} loading={loading}>
|
<Button onClick={() => submit('general')} loading={loading}>
|
||||||
保存
|
保存
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={() => testChannel(user.username, user.token, '')}>测试</Button>
|
<Button onClick={() => testChannel(user.username, user.token, '')}>
|
||||||
|
测试
|
||||||
|
</Button>
|
||||||
</Form>
|
</Form>
|
||||||
</Grid.Column>
|
</Grid.Column>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { API } from './api';
|
||||||
|
import { showError } from './utils';
|
||||||
|
|
||||||
|
export const loadUser = async () => {
|
||||||
|
let res = await API.get(`/api/user/self`);
|
||||||
|
const { success, message, data } = res.data;
|
||||||
|
if (success) {
|
||||||
|
if (data.channel === '') {
|
||||||
|
data.channel = 'email';
|
||||||
|
}
|
||||||
|
if (data.token === ' ') {
|
||||||
|
data.token = '';
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
showError(message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const loadUserChannels = async () => {
|
||||||
|
let res = await API.get(`/api/channel?brief=true`);
|
||||||
|
const { success, message, data } = res.data;
|
||||||
|
if (success) {
|
||||||
|
data.forEach((channel) => {
|
||||||
|
channel.key = channel.name;
|
||||||
|
channel.text = channel.name;
|
||||||
|
channel.value = channel.name;
|
||||||
|
if (channel.description === '') {
|
||||||
|
channel.description = '无备注信息';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
showError(message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { Button, Form, Segment } from 'semantic-ui-react';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { API, showError, showSuccess } from '../../helpers';
|
||||||
|
import { loadUser, loadUserChannels } from '../../helpers/loader';
|
||||||
|
|
||||||
|
const EditMessage = () => {
|
||||||
|
const params = useParams();
|
||||||
|
const messageId = params.id;
|
||||||
|
const isEditing = messageId !== undefined;
|
||||||
|
let [user, setUser] = useState({
|
||||||
|
id: '',
|
||||||
|
username: '',
|
||||||
|
channel: '',
|
||||||
|
token: '',
|
||||||
|
});
|
||||||
|
let [channels, setChannels] = useState([]);
|
||||||
|
const [loading, setLoading] = useState(isEditing);
|
||||||
|
const originInputs = {
|
||||||
|
title: '',
|
||||||
|
description: '',
|
||||||
|
content: '',
|
||||||
|
url: '',
|
||||||
|
channel: '',
|
||||||
|
to: '',
|
||||||
|
async: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const [inputs, setInputs] = useState(originInputs);
|
||||||
|
const { title, description, content, url, channel, to, async } = inputs;
|
||||||
|
|
||||||
|
const handleInputChange = (e, { name, value }) => {
|
||||||
|
setInputs((inputs) => ({ ...inputs, [name]: value }));
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadMessage = async () => {
|
||||||
|
let res = await API.get(`/api/message/${messageId}`);
|
||||||
|
const { success, message, data } = res.data;
|
||||||
|
if (success) {
|
||||||
|
data.id = 0;
|
||||||
|
setInputs(data);
|
||||||
|
} else {
|
||||||
|
showError(message);
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isEditing) {
|
||||||
|
loadMessage().then();
|
||||||
|
}
|
||||||
|
const loader = async () => {
|
||||||
|
let user = await loadUser();
|
||||||
|
if (user) {
|
||||||
|
setUser(user);
|
||||||
|
}
|
||||||
|
let channels = await loadUserChannels();
|
||||||
|
if (channels) {
|
||||||
|
setChannels(channels);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
loader().then();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const send = async () => {
|
||||||
|
if (!description && !content) return;
|
||||||
|
let res = await API.post(`/push/${user.username}/`, {
|
||||||
|
...inputs,
|
||||||
|
token: user.token,
|
||||||
|
});
|
||||||
|
const { success, message } = res.data;
|
||||||
|
if (success) {
|
||||||
|
if (isEditing) {
|
||||||
|
showSuccess('消息重发成功!');
|
||||||
|
} else {
|
||||||
|
showSuccess('消息发送成功!');
|
||||||
|
setInputs(originInputs);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showError(message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Segment loading={loading} className={'clearing'}>
|
||||||
|
<Form>
|
||||||
|
<Form.Group widths='equal'>
|
||||||
|
<Form.Input
|
||||||
|
label='标题'
|
||||||
|
placeholder='请输入消息标题'
|
||||||
|
value={inputs.title}
|
||||||
|
name='title'
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
<Form.Input
|
||||||
|
label='接收者'
|
||||||
|
placeholder='请输入接收者,不填使用默认接收者'
|
||||||
|
value={inputs.to}
|
||||||
|
name='to'
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
<Form.Select
|
||||||
|
label='推送方式'
|
||||||
|
placeholder='请选择推送方式,否则使用默认方式'
|
||||||
|
name='channel'
|
||||||
|
options={channels}
|
||||||
|
value={inputs.channel}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
</Form.Group>
|
||||||
|
<Form.Group widths='equal'>
|
||||||
|
<Form.Input
|
||||||
|
label='描述'
|
||||||
|
placeholder='请输入消息描述'
|
||||||
|
value={inputs.description}
|
||||||
|
name='description'
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
</Form.Group>
|
||||||
|
<Form.Group widths='equal'>
|
||||||
|
<Form.TextArea
|
||||||
|
label='内容'
|
||||||
|
placeholder='请输入消息内容'
|
||||||
|
value={inputs.content}
|
||||||
|
name='content'
|
||||||
|
onChange={handleInputChange}
|
||||||
|
style={{ minHeight: 200, fontFamily: 'JetBrains Mono, Consolas' }}
|
||||||
|
/>
|
||||||
|
</Form.Group>
|
||||||
|
<Form.Group widths='equal'>
|
||||||
|
<Form.Input
|
||||||
|
label='链接'
|
||||||
|
placeholder='请输入消息链接'
|
||||||
|
value={inputs.url}
|
||||||
|
type={'url'}
|
||||||
|
name='content'
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
</Form.Group>
|
||||||
|
<Button type='submit' floated='right' onClick={send}>
|
||||||
|
发送
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
floated='right'
|
||||||
|
onClick={() => {
|
||||||
|
handleInputChange(null, { name: 'async', value: !async });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{async ? '异步' : '同步'}
|
||||||
|
</Button>
|
||||||
|
</Form>
|
||||||
|
</Segment>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditMessage;
|
||||||
Reference in New Issue
Block a user