style: compact rule detection panel
This commit is contained in:
+24
-18
@@ -854,31 +854,37 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
|
||||
<section v-show="activePage === 'rules'" class="tab-page rule-manage-page">
|
||||
<SCard class="panel page-panel rule-detect-card" title="🧪 规则检测" description="输入聊天内容,检测是否为广告 / 垃圾 / 灰产信息,并可一键写入规则库">
|
||||
<div class="rule-test-grid">
|
||||
<div class="rule-editor-block">
|
||||
<label>聊天内容<textarea v-model="spamTestText" class="form-input rule-textarea" placeholder="粘贴可疑聊天内容,系统会给出规则评分和命中原因"></textarea></label>
|
||||
<label class="switch-line"><input v-model="spamUseAi" type="checkbox" /> 同时调用 AI 最终检测</label>
|
||||
<div class="form-actions">
|
||||
<SButtonLoading color="primary" :loading="spamTesting" :disabled="spamTesting" @click="testSpamText">开始检测</SButtonLoading>
|
||||
<SButtonLoading variant="outline" color="warning" :loading="ruleSaving" :disabled="ruleSaving || !spamTestText.trim()" @click="ruleForm.pattern = spamTestText; ruleForm.type = 'keyword'; ruleForm.score = 90; saveSpamRule()">将内容写入规则库</SButtonLoading>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rule-result-card">
|
||||
<div v-if="!spamTestResult" class="empty">暂无检测结果</div>
|
||||
<SCard class="panel page-panel rule-detect-card compact-detect-card" title="🧪 规则检测" description="粘贴聊天内容,快速判断广告 / 垃圾 / 灰产,并可写入规则库">
|
||||
<div class="rule-detect-compact">
|
||||
<label class="rule-text-field">
|
||||
<span>聊天内容</span>
|
||||
<textarea v-model="spamTestText" class="form-input rule-textarea compact" placeholder="粘贴可疑聊天内容,例如:点击 https://xxx 领取福利"></textarea>
|
||||
</label>
|
||||
<div class="rule-result-card compact" :class="{ danger: spamTestResult?.final_is_spam, ok: spamTestResult && spamTestResult.final_is_spam === false }">
|
||||
<div v-if="!spamTestResult" class="compact-empty">暂无检测结果</div>
|
||||
<template v-else>
|
||||
<div class="rule-result-head"><STag :color="spamTestResult.final_is_spam ? 'destructive' : spamTestResult.final_is_spam === null ? 'warning' : 'success'" variant="soft">{{ spamTestResult.final_is_spam ? '广告/垃圾/灰产' : spamTestResult.final_is_spam === null ? '需 AI 判断' : '正常' }}</STag><strong>评分:{{ spamTestResult.score }}</strong></div>
|
||||
<div class="rule-reason"><b>本地命中</b><span>{{ spamTestResult.reason }}</span></div>
|
||||
<div v-if="spamTestResult.ai_reason" class="rule-reason"><b>AI 结果</b><span>{{ spamTestResult.ai_reason }}</span></div>
|
||||
<div class="rule-counts">规则库:关键词 {{ spamTestResult.rule_counts?.keywords }} 条 / 正则 {{ spamTestResult.rule_counts?.regex }} 条 / Adblock 域名 {{ spamTestResult.rule_counts?.adblock_domains || spamRules.counts.adblock_domains || 0 }} 条</div>
|
||||
<div class="compact-result-top">
|
||||
<STag :color="spamTestResult.final_is_spam ? 'destructive' : spamTestResult.final_is_spam === null ? 'warning' : 'success'" variant="soft">
|
||||
{{ spamTestResult.final_is_spam ? '广告/垃圾/灰产' : spamTestResult.final_is_spam === null ? '需 AI 判断' : '正常' }}
|
||||
</STag>
|
||||
<strong>评分 {{ spamTestResult.score }}</strong>
|
||||
</div>
|
||||
<div class="compact-reason" :title="spamTestResult.reason">{{ spamTestResult.reason }}</div>
|
||||
<div v-if="spamTestResult.ai_reason" class="compact-reason muted" :title="spamTestResult.ai_reason">AI:{{ spamTestResult.ai_reason }}</div>
|
||||
<div class="compact-counts">关键词 {{ spamTestResult.rule_counts?.keywords }} / 正则 {{ spamTestResult.rule_counts?.regex }} / 域名 {{ spamTestResult.rule_counts?.adblock_domains || spamRules.counts.adblock_domains || 0 }}</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rule-write-grid inline-rule-writer">
|
||||
<div class="rule-action-bar">
|
||||
<label class="switch-line compact"><input v-model="spamUseAi" type="checkbox" /> AI 兜底</label>
|
||||
<SButtonLoading color="primary" :loading="spamTesting" :disabled="spamTesting" @click="testSpamText">开始检测</SButtonLoading>
|
||||
<SButtonLoading variant="outline" color="warning" :loading="ruleSaving" :disabled="ruleSaving || !spamTestText.trim()" @click="ruleForm.pattern = spamTestText; ruleForm.type = 'keyword'; ruleForm.score = 90; saveSpamRule()">内容入库</SButtonLoading>
|
||||
</div>
|
||||
<div class="rule-write-grid inline-rule-writer compact-rule-writer">
|
||||
<label>类型<select v-model="ruleForm.type" class="form-select"><option value="keyword">关键词</option><option value="regex">正则</option></select></label>
|
||||
<label>分数<SInput v-model="ruleForm.score" type="number" placeholder="75" /></label>
|
||||
<label class="rule-pattern-field">规则条目<SInput v-model="ruleForm.pattern" :placeholder="ruleForm.type === 'keyword' ? '如 黑U' : '如 (?:黑\s*[uU]).{0,20}(?:联系|项目)'" /></label>
|
||||
<SButtonLoading color="primary" :loading="ruleSaving" :disabled="ruleSaving" @click="saveSpamRule">写入规则</SButtonLoading>
|
||||
<SButtonLoading color="primary" :loading="ruleSaving" :disabled="ruleSaving" @click="saveSpamRule">写入</SButtonLoading>
|
||||
</div>
|
||||
</SCard>
|
||||
|
||||
|
||||
@@ -513,3 +513,28 @@ body { background: #f3f6fb; }
|
||||
.overview-ban-panel .s-card__content { flex: 1 1 auto; min-height: 0; height: auto !important; overflow: hidden; }
|
||||
.overview-ban-panel .v-overflow,
|
||||
.overview-ban-list.v-overflow { display: block; height: 100%; max-height: 100%; min-height: 0; overflow-y: auto !important; overflow-x: hidden; padding-right: 6px; overscroll-behavior: contain; scrollbar-gutter: stable; }
|
||||
|
||||
|
||||
/* Compact rule detection redesign */
|
||||
.compact-detect-card .s-card__content { display: grid; gap: 10px; }
|
||||
.rule-detect-compact { display: grid; grid-template-columns: minmax(0, 1fr) minmax(280px, 360px); gap: 12px; align-items: stretch; }
|
||||
.rule-text-field { display: grid; gap: 6px; font-weight: 700; color: #0f172a; }
|
||||
.rule-textarea.compact { min-height: 104px; max-height: 150px; height: 104px; padding: 12px 14px; border-radius: 14px; font-size: 14px; line-height: 1.45; resize: vertical; }
|
||||
.rule-result-card.compact { min-height: 104px; padding: 12px; border-radius: 14px; border: 1px solid #dbe3ef; background: linear-gradient(180deg, #f8fafc 0%, #fff 100%); display: grid; align-content: center; gap: 8px; }
|
||||
.rule-result-card.compact.danger { border-color: #fecaca; background: #fff7f7; }
|
||||
.rule-result-card.compact.ok { border-color: #bbf7d0; background: #f7fff9; }
|
||||
.compact-empty { color: #94a3b8; text-align: center; font-weight: 700; }
|
||||
.compact-result-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
|
||||
.compact-result-top strong { font-size: 18px; color: #0f172a; }
|
||||
.compact-reason { font-size: 13px; line-height: 1.35; color: #334155; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
||||
.compact-reason.muted { color: #64748b; -webkit-line-clamp: 1; }
|
||||
.compact-counts { font-size: 12px; color: #64748b; padding: 6px 8px; border-radius: 10px; background: #eef2ff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.rule-action-bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
||||
.switch-line.compact { margin-right: auto; font-weight: 700; color: #334155; }
|
||||
.compact-rule-writer { margin-top: 0; padding-top: 10px; grid-template-columns: 120px 110px minmax(220px, 1fr) 76px !important; gap: 10px; border-top: 1px solid #e2e8f0; align-items: end; }
|
||||
.compact-rule-writer label { display: grid; gap: 5px; font-size: 13px; font-weight: 700; color: #334155; }
|
||||
.compact-rule-writer .form-select { height: 36px; }
|
||||
@media (max-width: 980px) {
|
||||
.rule-detect-compact, .compact-rule-writer { grid-template-columns: 1fr !important; }
|
||||
.switch-line.compact { margin-right: 0; }
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -5,8 +5,8 @@
|
||||
<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-CtGHELCH.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/static/assets/index-Dookq5Ju.css">
|
||||
<script type="module" crossorigin src="/static/assets/index-B6Gkvk5q.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/static/assets/index-DB2vPoNK.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
Reference in New Issue
Block a user