mirror of
https://github.com/MengMengCode/VoCat.git
synced 2026-08-20 23:03:44 +08:00
Merge pull request #2 from zAhYAng/feat/wecom-notifications
feat: add WeCom message push notifications
This commit is contained in:
@@ -6,7 +6,7 @@ import { Select } from "../ui/Select";
|
||||
import { Switch } from "../ui/Switch";
|
||||
import { ChannelHeader, EmptyLine, Field, UrlListEditor } from "./controls";
|
||||
import { HEADER_NAME_SUGGESTIONS, nextHeaderRowId } from "./model";
|
||||
import type { BarkForm, EmailForm, HeaderRow, WebhookForm } from "./model";
|
||||
import type { BarkForm, EmailForm, HeaderRow, WebhookForm, WecomForm } from "./model";
|
||||
|
||||
const HEADER_LIST_ID = "vocat-webhook-header-names";
|
||||
|
||||
@@ -267,3 +267,53 @@ export function WebhookTab({ value, onChange, testing, onTest }: PushChannelProp
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function WecomTab({ value, onChange, testing, onTest }: PushChannelProps<WecomForm>) {
|
||||
const { t, lang } = useI18n();
|
||||
const off = !value.enabled;
|
||||
const complete = hasAnyUrl(value.urls) && !!value.payloadTemplate.trim();
|
||||
return (
|
||||
<div className="pt-2">
|
||||
<ChannelHeader
|
||||
title={t("启用企业微信消息推送")}
|
||||
enabled={value.enabled}
|
||||
onToggle={(enabled) => onChange({ enabled })}
|
||||
actions={
|
||||
<Button size="small" variant="primary" plain loading={testing} disabled={off || !complete} onClick={onTest}>
|
||||
{t("测试通知")}
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
<SMSOnlyHint />
|
||||
<div className="space-y-4">
|
||||
<div className="rounded-lg bg-gray-50 px-3 py-2 text-xs leading-5 text-gray-500 dark:bg-gray-800/60 dark:text-gray-400">
|
||||
{t("每个企业微信消息推送 Webhook URL 单独占一行,点击添加 URL 新增一行;不使用逗号、空格或换行分隔多个 URL。")}
|
||||
</div>
|
||||
<UrlListEditor
|
||||
urls={value.urls}
|
||||
onChange={(urls) => onChange({ urls })}
|
||||
enabled={value.enabled}
|
||||
placeholder="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=..."
|
||||
emptyText={t("尚未配置任何企业微信消息推送 Webhook URL,点击右侧添加按钮。")}
|
||||
/>
|
||||
<Field
|
||||
label={t("JSON 请求体模板")}
|
||||
hint={
|
||||
<>
|
||||
{t("支持完整企业微信消息推送 JSON。变量必须作为 JSON 值使用,例如")} <code>{"{{message}}"}</code>{lang === "zh" ? "。" : "."}
|
||||
{t("可用变量:{{event}}、{{title}}、{{message}}、{{timestamp}}、{{content}}、{{number}}、{{device_id}}、{{device_name}}、{{device_label}}、{{time}}。")}
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Textarea
|
||||
value={value.payloadTemplate}
|
||||
onChange={(event) => onChange({ payloadTemplate: event.target.value })}
|
||||
disabled={off}
|
||||
rows={12}
|
||||
className="font-mono text-xs"
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -47,18 +47,32 @@ export interface EmailForm {
|
||||
}
|
||||
|
||||
export interface PushplusForm {
|
||||
enabled: boolean;
|
||||
token: string;
|
||||
topic: string;
|
||||
channel: string;
|
||||
enabled: boolean;
|
||||
token: string;
|
||||
topic: string;
|
||||
channel: string;
|
||||
}
|
||||
|
||||
export interface WecomForm {
|
||||
enabled: boolean;
|
||||
urls: string[];
|
||||
payloadTemplate: string;
|
||||
}
|
||||
|
||||
export const DEFAULT_WECOM_PAYLOAD_TEMPLATE = `{
|
||||
"msgtype": "text",
|
||||
"text": {
|
||||
"content": {{message}}
|
||||
}
|
||||
}`;
|
||||
|
||||
export interface NotifyForms {
|
||||
telegram: TelegramForm;
|
||||
webhook: WebhookForm;
|
||||
bark: BarkForm;
|
||||
email: EmailForm;
|
||||
pushplus: PushplusForm;
|
||||
email: EmailForm;
|
||||
pushplus: PushplusForm;
|
||||
wecom: WecomForm;
|
||||
}
|
||||
|
||||
// 系统保留头,自定义同名头会被忽略(品牌 vocat)
|
||||
@@ -131,8 +145,9 @@ export function formsFromNotifications(data: Partial<NotificationSettings>): Not
|
||||
const telegram = asRecord(data.telegram);
|
||||
const webhook = asRecord(data.webhook);
|
||||
const bark = asRecord(data.bark);
|
||||
const email = asRecord(data.email);
|
||||
const pushplus = asRecord(data.pushplus);
|
||||
const email = asRecord(data.email);
|
||||
const pushplus = asRecord(data.pushplus);
|
||||
const wecom = asRecord(data.wecom);
|
||||
return {
|
||||
telegram: {
|
||||
enabled: !!telegram.enabled,
|
||||
@@ -171,13 +186,18 @@ export function formsFromNotifications(data: Partial<NotificationSettings>): Not
|
||||
fromAddress: str(email.fromAddress),
|
||||
toAddresses: joinList(email.toAddresses),
|
||||
},
|
||||
pushplus: {
|
||||
enabled: !!pushplus.enabled,
|
||||
token: str(pushplus.token),
|
||||
topic: str(pushplus.topic),
|
||||
channel: str(pushplus.channel) || "wechat",
|
||||
},
|
||||
};
|
||||
pushplus: {
|
||||
enabled: !!pushplus.enabled,
|
||||
token: str(pushplus.token),
|
||||
topic: str(pushplus.topic),
|
||||
channel: str(pushplus.channel) || "wechat",
|
||||
},
|
||||
wecom: {
|
||||
enabled: !!wecom.enabled,
|
||||
urls: strList(wecom.urls),
|
||||
payloadTemplate: str(wecom.payloadTemplate ?? wecom.payload_template) || DEFAULT_WECOM_PAYLOAD_TEMPLATE,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function splitList(value: string): string[] {
|
||||
@@ -226,6 +246,15 @@ export function buildEmailPayload(form: EmailForm, forTest = false) {
|
||||
};
|
||||
}
|
||||
|
||||
export function buildWecomPayload(form: WecomForm, forTest = false) {
|
||||
const urls = Array.isArray(form.urls) ? form.urls : [];
|
||||
return {
|
||||
enabled: !!form.enabled,
|
||||
urls: forTest ? urls.map((url) => String(url || "").trim()).filter(Boolean) : urls,
|
||||
payload_template: String(form.payloadTemplate || ""),
|
||||
};
|
||||
}
|
||||
|
||||
export function buildNotificationsPayload(forms: NotifyForms) {
|
||||
return {
|
||||
telegram: {
|
||||
@@ -245,6 +274,7 @@ export function buildNotificationsPayload(forms: NotifyForms) {
|
||||
channel: forms.pushplus.channel || "",
|
||||
},
|
||||
webhook: buildWebhookPayload(forms.webhook),
|
||||
bark: buildBarkPayload(forms.bark),
|
||||
};
|
||||
bark: buildBarkPayload(forms.bark),
|
||||
wecom: buildWecomPayload(forms.wecom),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user