feat: 退群监控增加重新发送功能

This commit is contained in:
Wxw-Gu
2026-09-09 17:58:14 +08:00
parent 0bad419150
commit c759bcd30e
5 changed files with 46 additions and 3 deletions
+3
View File
@@ -1175,6 +1175,9 @@ app.whenReady().then(async () => {
)
ipcMain.handle('group-exit-monitor:checkNow', () => groupExitMonitorService.checkNow())
ipcMain.handle('group-exit-monitor:clearEvents', () => groupExitMonitorService.clearEvents())
ipcMain.handle('group-exit-monitor:resendEvent', (_, eventId: string) =>
groupExitMonitorService.resendEvent(eventId)
)
ipcMain.handle('group-exit-monitor:markRead', (_, readAt?: number) =>
groupExitMonitorService.markRead(readAt)
)
@@ -602,7 +602,8 @@ class GroupExitMonitorService {
private async notifyGroup(
group: GroupSnapshotRecord,
event: GroupExitMonitorEvent
event: GroupExitMonitorEvent,
idempotencyKey = `member_left_notification:${event.id}`
): Promise<void> {
event.notificationStatus = 'pending'
event.notification = { status: 'pending' }
@@ -610,7 +611,7 @@ class GroupExitMonitorService {
this.broadcast()
try {
const result = await this.actionGateway.execute({
idempotencyKey: `member_left_notification:${event.id}`,
idempotencyKey,
origin: 'member_monitor',
purpose: 'member_left_notification',
triggerType: 'automation',
@@ -665,6 +666,17 @@ class GroupExitMonitorService {
}
}
async resendEvent(eventId: string): Promise<GroupExitMonitorState> {
const event = this.events.find((item) => item.id === eventId)
if (!event) throw new Error('退群动态不存在')
await this.notifyGroup(
{ roomId: event.roomId, groupName: event.groupName } as GroupSnapshotRecord,
event,
`member_left_notification:${event.id}:retry:${Date.now()}`
)
return this.getState()
}
private filePath(): string {
return path.join(app.getPath('userData'), 'group-exit-monitor.json')
}
+1
View File
@@ -275,6 +275,7 @@ declare global {
setGroupExitMonitorNotificationTemplate: (template: string) => Promise<GroupExitMonitorState>
checkGroupExitMonitorNow: () => Promise<GroupExitMonitorState>
clearGroupExitMonitorEvents: () => Promise<GroupExitMonitorState>
resendGroupExitMonitorEvent: (eventId: string) => Promise<GroupExitMonitorState>
markGroupExitMonitorRead: (readAt?: number) => Promise<GroupExitMonitorState>
listWechatActionLogs: () => Promise<ActionLogEntry[]>
onGroupExitMonitorState: (callback: (state: GroupExitMonitorState) => void) => () => void
+2
View File
@@ -155,6 +155,8 @@ const api = {
ipcRenderer.invoke('group-exit-monitor:checkNow'),
clearGroupExitMonitorEvents: (): Promise<GroupExitMonitorState> =>
ipcRenderer.invoke('group-exit-monitor:clearEvents'),
resendGroupExitMonitorEvent: (eventId: string): Promise<GroupExitMonitorState> =>
ipcRenderer.invoke('group-exit-monitor:resendEvent', eventId),
markGroupExitMonitorRead: (readAt?: number): Promise<GroupExitMonitorState> =>
ipcRenderer.invoke('group-exit-monitor:markRead', readAt),
listWechatActionLogs: (): Promise<ActionLogEntry[]> =>
@@ -85,10 +85,14 @@ const sendCapabilityTone = (capability: PersonalWechatSendCapability | null): st
function EventNotificationStatus({
event,
onOpenSendSettings
onOpenSendSettings,
onResend,
resending
}: {
event: GroupExitMonitorState['events'][number]
onOpenSendSettings?: () => void
onResend?: () => void
resending?: boolean
}): React.ReactElement {
const status = event.notificationStatus || event.notification?.status || 'not_requested'
const details =
@@ -120,6 +124,11 @@ function EventNotificationStatus({
去设置
</Button>
) : null}
{status !== 'sent' && status !== 'pending' && onResend ? (
<Button variant="link" size="sm" onClick={onResend} disabled={resending}>
{resending ? '发送中...' : '重新发送'}
</Button>
) : null}
</div>
)
}
@@ -455,6 +464,7 @@ export function GroupExitMonitorWorkspace({
const [templateError, setTemplateError] = React.useState('')
const [selectedRoomId, setSelectedRoomId] = React.useState('all')
const [view, setView] = React.useState<'events' | 'manage'>('events')
const [resendingEventId, setResendingEventId] = React.useState<string | null>(null)
const [manageKeyword, setManageKeyword] = React.useState('')
const [manageFilter, setManageFilter] = React.useState<GroupSelectionFilter>('all')
const [selectedManageRoomIds, setSelectedManageRoomIds] = React.useState<Set<string>>(
@@ -594,6 +604,19 @@ export function GroupExitMonitorWorkspace({
}
}
const resendEvent = async (eventId: string): Promise<void> => {
if (resendingEventId || typeof window.api.resendGroupExitMonitorEvent !== 'function') return
setResendingEventId(eventId)
setError('')
try {
setState(await window.api.resendGroupExitMonitorEvent(eventId))
} catch (reason) {
setError(reason instanceof Error ? reason.message : String(reason))
} finally {
setResendingEventId(null)
}
}
const saveGroups = async (): Promise<void> => {
const api = window.api
if (saving || !dbReady || typeof api.setGroupExitMonitorGroups !== 'function') return
@@ -857,6 +880,8 @@ export function GroupExitMonitorWorkspace({
<EventNotificationStatus
event={event}
onOpenSendSettings={onOpenSendSettings}
onResend={() => void resendEvent(event.id)}
resending={resendingEventId === event.id}
/>
<dl className="exit-monitor-event-details">
<div>