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 Channel from './pages/Channel';
|
||||
import EditChannel from './pages/Channel/EditChannel';
|
||||
import EditMessage from './pages/Message/EditMessage';
|
||||
|
||||
const Home = lazy(() => import('./pages/Home'));
|
||||
const About = lazy(() => import('./pages/About'));
|
||||
@@ -141,6 +142,22 @@ function App() {
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path='/editor'
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<EditMessage />
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path='/editor/:id'
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<EditMessage />
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path='/login'
|
||||
element={
|
||||
|
||||
@@ -18,6 +18,11 @@ const headerButtons = [
|
||||
to: '/message',
|
||||
icon: 'mail',
|
||||
},
|
||||
{
|
||||
name: '编辑',
|
||||
to: '/editor',
|
||||
icon: 'edit',
|
||||
},
|
||||
{
|
||||
name: '通道',
|
||||
to: '/channel',
|
||||
|
||||
@@ -11,6 +11,7 @@ import { API, openPage, showError, showSuccess, showWarning } from '../helpers';
|
||||
|
||||
import { ITEMS_PER_PAGE } from '../constants';
|
||||
import { renderTimestamp } from '../helpers/render';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
function renderStatus(status) {
|
||||
switch (status) {
|
||||
@@ -317,6 +318,15 @@ const MessagesTable = () => {
|
||||
>
|
||||
查看
|
||||
</Button>
|
||||
<Button
|
||||
size={'small'}
|
||||
primary
|
||||
loading={loading}
|
||||
as={Link}
|
||||
to={'/editor/' + message.id}
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
<Button
|
||||
size={'small'}
|
||||
color={'yellow'}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Button, Form, Grid, Header, Message } from 'semantic-ui-react';
|
||||
import { API, showError, showSuccess, testChannel } from '../helpers';
|
||||
import { loadUser, loadUserChannels } from '../helpers/loader';
|
||||
|
||||
const PushSetting = () => {
|
||||
let [user, setUser] = useState({
|
||||
@@ -16,44 +17,19 @@ const PushSetting = () => {
|
||||
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(() => {
|
||||
loadUser().then();
|
||||
loadUserChannels().then();
|
||||
const loader = async () => {
|
||||
let user = await loadUser();
|
||||
if (user) {
|
||||
setUser(user);
|
||||
}
|
||||
let channels = await loadUserChannels();
|
||||
if (channels) {
|
||||
setChannels(channels);
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
loader().then();
|
||||
}, []);
|
||||
|
||||
const submit = async (which) => {
|
||||
@@ -106,7 +82,9 @@ const PushSetting = () => {
|
||||
<Button onClick={() => submit('general')} loading={loading}>
|
||||
保存
|
||||
</Button>
|
||||
<Button onClick={() => testChannel(user.username, user.token, '')}>测试</Button>
|
||||
<Button onClick={() => testChannel(user.username, user.token, '')}>
|
||||
测试
|
||||
</Button>
|
||||
</Form>
|
||||
</Grid.Column>
|
||||
</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