feat: add chat message to spam rules
This commit is contained in:
+28
-6
@@ -2,7 +2,7 @@
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref } from 'vue';
|
||||
import { SButton, SButtonLoading, SCard, SConfigProvider, SInput, STag } from '@soybeanjs/ui';
|
||||
|
||||
type ChatItem = Record<string, any> & { _deleting?: boolean };
|
||||
type ChatItem = Record<string, any> & { _deleting?: boolean; _ruling?: boolean };
|
||||
type BanItem = Record<string, any> & { _loading?: boolean };
|
||||
type LogItem = { time?: string; level?: string; message?: string };
|
||||
type GroupItem = { chat_id: number; name: string };
|
||||
@@ -414,6 +414,27 @@ async function sendMessage() {
|
||||
sending.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function addChatMessageToRules(item: ChatItem) {
|
||||
const text = String(item.text || '').trim();
|
||||
if (!text) return showToast('当前消息没有可写入的文本');
|
||||
if (text.length > 500) return showToast('当前消息超过 500 字,请到规则测试页提取关键词或正则');
|
||||
if (!await askConfirm('写入拦截库', '确认将当前聊天内容作为关键词写入拦截规则库?', { confirmText: '写入', danger: false })) return;
|
||||
item._ruling = true;
|
||||
try {
|
||||
const result = await fetchJson('/api/spam-rules', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ type: 'keyword', pattern: text, score: 90 })
|
||||
});
|
||||
showToast(`已写入拦截库,关键词 ${result.rule_counts?.keywords || '-'} / 正则 ${result.rule_counts?.regex || '-'}`);
|
||||
} catch (e: any) {
|
||||
showToast(`写入失败:${e.message}`);
|
||||
} finally {
|
||||
item._ruling = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteChatMessage(item: ChatItem, ban = false) {
|
||||
const action = ban ? '删除并封禁' : '删除';
|
||||
if (!await askConfirm(action, `确认${action}这条消息?`, { confirmText: action, danger: true })) return;
|
||||
@@ -555,7 +576,7 @@ onBeforeUnmount(() => {
|
||||
<SCard id="chat" class="panel chat-panel" title="聊天记录" :description="`${chatCount} 条`">
|
||||
<div class="scroll-area chat-scroll">
|
||||
<div v-if="!chatLogs.length" class="empty">等待消息...</div>
|
||||
<article v-for="(item, i) in chatLogs" :key="item.id || i" :class="[chatItemClass(item), { deleting: item._deleting }]">
|
||||
<article v-for="(item, i) in chatLogs" :key="item.id || i" :class="[chatItemClass(item), { deleting: item._deleting || item._ruling }]">
|
||||
<div class="chat-head">
|
||||
<div class="chat-user-line">
|
||||
<STag size="xs" :color="tagColor(item)" variant="soft">{{ chatStatusText(item) }}</STag>
|
||||
@@ -572,16 +593,17 @@ onBeforeUnmount(() => {
|
||||
<STag v-if="item.spam" class="reason-tag" size="xs" color="destructive" variant="soft" :title="item.reason || item.spam_reason">{{ item.reason || item.spam_reason }}</STag>
|
||||
<span v-else />
|
||||
<div class="chat-actions">
|
||||
<SButton size="xs" variant="link" color="primary" :disabled="item._deleting || item._ruling" @click="addChatMessageToRules(item)">{{ item._ruling ? '入库中...' : '入库' }}</SButton>
|
||||
<STag v-if="item.deleted" size="xs" color="secondary" variant="soft">已删 · {{ formatTime(item.deleted_at) }}</STag>
|
||||
<template v-else>
|
||||
<SButton size="xs" variant="link" color="destructive" :disabled="item._deleting" @click="deleteChatMessage(item, false)">{{ item._deleting ? '删除中...' : '删除' }}</SButton>
|
||||
<SButton v-if="item.user_id" size="xs" variant="link" color="warning" :disabled="item._deleting" @click="deleteChatMessage(item, true)">{{ item._deleting ? '处理中...' : '删封' }}</SButton>
|
||||
<SButton size="xs" variant="link" color="destructive" :disabled="item._deleting || item._ruling" @click="deleteChatMessage(item, false)">{{ item._deleting ? '删除中...' : '删除' }}</SButton>
|
||||
<SButton v-if="item.user_id" size="xs" variant="link" color="warning" :disabled="item._deleting || item._ruling" @click="deleteChatMessage(item, true)">{{ item._deleting ? '处理中...' : '删封' }}</SButton>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="item._deleting" class="chat-loading-mask">
|
||||
<div v-if="item._deleting || item._ruling" class="chat-loading-mask">
|
||||
<span class="mini-spinner"></span>
|
||||
<strong>正在处理当前消息...</strong>
|
||||
<strong>{{ item._ruling ? '正在写入拦截库...' : '正在处理当前消息...' }}</strong>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" type="image/svg+xml" href="/static/icon.svg" />
|
||||
<title>TG Spam Guard</title>
|
||||
<script type="module" crossorigin src="/static/assets/index-C6kPOPdz.js"></script>
|
||||
<script type="module" crossorigin src="/static/assets/index-h7vFW1gU.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/static/assets/index-DfsWb80Q.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Reference in New Issue
Block a user