添加通知设置页面

This commit is contained in:
hanhh 2021-09-18 01:44:55 +08:00
parent aed08b0f59
commit 827e8571aa
8 changed files with 278 additions and 6 deletions

View File

@ -268,10 +268,38 @@ export default class AuthService {
});
}
public async updateNotificationMode(notificationInfo: NotificationInfo) {
return await this.insertDb({
type: AuthDataType.notification,
info: { notificationInfo },
private async updateNotificationDb(payload: AuthInfo): Promise<any> {
return new Promise((resolve) => {
this.authDb.update(
{ type: AuthDataType.notification },
payload,
{ upsert: true, returnUpdatedDocs: true },
(err, num, doc: any) => {
if (err) {
resolve({} as NotificationInfo);
} else {
resolve(doc.info);
}
},
);
});
}
public async updateNotificationMode(notificationInfo: NotificationInfo) {
const code = Math.random().toString().slice(-6);
const isSuccess = await this.notificationService.testNotify(
notificationInfo,
'青龙',
`【蛟龙】您本次的验证码:${code}`,
);
if (isSuccess) {
const result = await this.updateNotificationDb({
type: AuthDataType.notification,
info: { ...notificationInfo },
});
return { code: 200, data: { ...result, code } };
} else {
return { code: 400, data: '通知发送失败,请检查参数' };
}
}
}

View File

@ -16,7 +16,7 @@ export default class CronService {
private cronDb = new DataStore({ filename: config.cronDbFile });
private queue = new PQueue({
concurrency: parseInt(process.env.MaxConcurrentNum) || 5,
concurrency: parseInt(process.env.MaxConcurrentNum as string) || 5,
});
constructor(@Inject('logger') private logger: winston.Logger) {

View File

@ -39,7 +39,26 @@ export default class NotificationService {
this.content = content;
this.params = rest;
const notificationModeAction = this.modeMap.get(type);
notificationModeAction?.call(this);
try {
return await notificationModeAction?.call(this);
} catch (error: any) {
return error.message;
}
}
}
public async testNotify(
info: NotificationInfo,
title: string,
content: string,
) {
const { type, ...rest } = info;
if (type) {
this.title = title;
this.content = content;
this.params = rest;
const notificationModeAction = this.modeMap.get(type);
return await notificationModeAction?.call(this);
}
}

View File

@ -230,3 +230,14 @@ input:-webkit-autofill:active {
padding: 0 3px;
}
}
.ant-form-item-extra {
word-break: break-all;
font-size: 13px;
}
.dark {
::placeholder {
opacity: 0.5 !important;
}
}

View File

@ -93,6 +93,7 @@ export default function (props: any) {
<ProLayout
selectedKeys={[props.location.pathname]}
loading={loading}
className={theme.theme === 'vs-dark' ? 'dark' : 'white'}
title={
<>

View File

@ -30,6 +30,7 @@ import {
} from '@ant-design/icons';
import SecuritySettings from './security';
import LoginLog from './loginLog';
import NotificationSetting from './notification';
const { Text } = Typography;
const optionsWithDisabled = [
@ -112,6 +113,7 @@ const Setting = ({ headerStyle, isPhone, user, reloadUser }: any) => {
const [editedApp, setEditedApp] = useState();
const [tabActiveKey, setTabActiveKey] = useState('security');
const [loginLogData, setLoginLogData] = useState<any[]>([]);
const [notificationInfo, setNotificationInfo] = useState<any>();
const themeChange = (e: any) => {
setTheme(e.target.value);
@ -238,9 +240,22 @@ const Setting = ({ headerStyle, isPhone, user, reloadUser }: any) => {
getApps();
} else if (activeKey === 'login') {
getLoginLog();
} else if (activeKey === 'notification') {
getNotification();
}
};
const getNotification = () => {
request
.get(`${config.apiPrefix}user/notification`)
.then((data: any) => {
setNotificationInfo(data.data);
})
.catch((error: any) => {
console.log(error);
});
};
useEffect(() => {
setFetchMethod(window.fetch);
if (theme === 'dark') {
@ -289,6 +304,9 @@ const Setting = ({ headerStyle, isPhone, user, reloadUser }: any) => {
loading={loading}
/>
</Tabs.TabPane>
<Tabs.TabPane tab="通知设置" key="notification">
<NotificationSetting data={notificationInfo} />
</Tabs.TabPane>
<Tabs.TabPane tab="登陆日志" key="login">
<LoginLog data={loginLogData} />
</Tabs.TabPane>

View File

@ -0,0 +1,83 @@
import React, { useEffect, useState } from 'react';
import { Typography, Input, Form, Button, Select, message } from 'antd';
import { request } from '@/utils/http';
import config from '@/utils/config';
const { Option } = Select;
const NotificationSetting = ({ data }: any) => {
const [loading, setLoading] = useState(false);
const [notificationMode, setNotificationMode] = useState<string>('');
const [fields, setFields] = useState<any[]>([]);
const [form] = Form.useForm();
const handleOk = (values: any) => {
request
.put(`${config.apiPrefix}user/notification`, {
data: {
...values,
},
})
.then((data: any) => {
if (data && data.code === 200) {
message.success('通知发送成功');
} else {
message.error(data.data);
}
})
.catch((error: any) => {
console.log(error);
});
};
const notificationModeChange = (value: string) => {
setNotificationMode(value);
const _fields = (config.notificationModeMap as any)[value];
setFields(_fields);
};
useEffect(() => {
if (data && data.type) {
notificationModeChange(data.type);
form.setFieldsValue({ ...data });
}
}, [data]);
return (
<div>
<Form onFinish={handleOk} form={form} layout="vertical">
<Form.Item
label="通知方式"
name="type"
rules={[{ required: true }]}
style={{ maxWidth: 400 }}
initialValue={notificationMode}
>
<Select onChange={notificationModeChange}>
{config.notificationModes.map((x) => (
<Option value={x.value}>{x.label}</Option>
))}
</Select>
</Form.Item>
{fields.map((x) => (
<Form.Item
label={x.label}
name={x.label}
extra={x.tip}
rules={[{ required: x.required }]}
style={{ maxWidth: 400 }}
>
<Input.TextArea autoSize={true} placeholder={`请输入${x.label}`} />
</Form.Item>
))}
{notificationMode !== '' && (
<Button type="primary" htmlType="submit">
</Button>
)}
</Form>
</div>
);
};
export default NotificationSetting;

View File

@ -63,4 +63,116 @@ export default {
scripts: '脚本管理',
logs: '任务日志',
},
notificationModes: [
{ value: 'goCqHttpBot', label: 'GoCqHttpBot' },
{ value: 'serverChan', label: 'Server酱' },
{ value: 'bark', label: 'Bark' },
{ value: 'telegramBot', label: 'Telegram机器人' },
{ value: 'dingtalkBot', label: '钉钉机器人' },
{ value: 'weWorkBot', label: '企业微信机器人' },
{ value: 'weWorkApp', label: '企业微信应用' },
{ value: 'iGot', label: 'IGot' },
{ value: 'pushPlus', label: 'PushPlus' },
{ value: 'email', label: '邮箱' },
{ value: '', label: '已关闭' },
],
notificationModeMap: {
goCqHttpBot: [
{
label: 'goCqHttpBotUrl',
tip: '推送到个人QQ: http://127.0.0.1/send_private_msghttp://127.0.0.1/send_group_msg',
required: true,
},
{ label: 'goCqHttpBotToken', tip: '访问密钥', required: true },
{
label: 'goCqHttpBotQq',
tip: '如果GOBOT_URL设置 /send_private_msg 则需要填入 user_id=个人QQ 相反如果是 /send_group_msg 则需要填入 group_id=QQ群',
required: true,
},
],
serverChan: [
{ label: 'serverChanKey', tip: 'Server酱SENDKEY', required: true },
],
bark: [
{
label: 'barkPush',
tip: 'Bark的信息IP/设备码例如https://api.day.app/XXXXXXXX',
required: true,
},
{ label: 'barkSound', tip: 'BARK推送铃声,铃声列表去APP查看复制填写' },
{ label: 'barkGroup', tip: 'BARK推送消息的分组, 默认为qinglong' },
],
telegramBot: [
{
label: 'telegramBotToken',
tip: 'telegram机器人的token例如1077xxx4424:AAFjv0FcqxxxxxxgEMGfi22B4yh15R5uw',
required: true,
},
{
label: 'telegramBotUserId',
tip: 'telegram用户的id例如129xxx206',
required: true,
},
{ label: 'telegramBotProxyHost', tip: '代理IP' },
{ label: 'telegramBotProxyPort', tip: '代理端口' },
{ label: 'telegramBotProxyAuth', tip: 'telegram代理配置认证参数' },
{
label: 'telegramBotApiHost',
tip: 'telegram api自建的反向代理地址默认tg官方api',
},
],
dingtalkBot: [
{
label: 'dingtalkBotToken',
tip: '钉钉机器人webhook token例如5a544165465465645d0f31dca676e7bd07415asdasd',
required: true,
},
{
label: 'dingtalkBotSecret',
tip: '密钥机器人安全设置页面加签一栏下面显示的SEC开头的字符串',
},
],
weWorkBot: [
{
label: 'weWorkBotKey',
tip: '企业微信机器人的 webhook(详见文档 https://work.weixin.qq.com/api/doc/90000/90136/91770)例如693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa',
required: true,
},
],
weWorkApp: [
{
label: 'weWorkAppKey',
tip: 'corpid,corpsecret,touser(注:多个成员ID使用|隔开),agentid,消息类型(选填,不填默认文本消息类型) 注意用,号隔开(英文输入法的逗号)例如wwcfrs,B-76WERQ,qinglong,1000001,2COat',
required: true,
},
],
iGot: [
{
label: 'iGotPushKey',
tip: 'iGot的信息推送key例如https://push.hellyw.com/XXXXXXXX',
required: true,
},
],
pushPlus: [
{
label: 'pushPlusToken',
tip: '微信扫码登录后一对一推送或一对多推送下面的token(您的Token)不提供PUSH_PLUS_USER则默认为一对一推送',
required: true,
},
{
label: 'pushPlusUser',
tip: '一对多推送的“群组编码”(一对多推送下面->您的群组(如无则新建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)',
required: true,
},
],
email: [
{
label: 'emailService',
tip: '邮箱服务名称比如126、163、Gmail、QQ等支持列表https://nodemailer.com/smtp/well-known/',
required: true,
},
{ label: 'emailUser', tip: '邮箱地址', required: true },
{ label: 'emailPass', tip: '邮箱SMTP授权码', required: true },
],
},
};