feat: 小程序移除管理后台入口,新增admin-web前端项目
将管理后台功能从微信小程序中剥离,独立为Vue.js前端项目admin-web Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
187
admin-web/src/views/Detect.vue
Normal file
187
admin-web/src/views/Detect.vue
Normal file
@@ -0,0 +1,187 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<section class="hero fade-up">
|
||||
<div class="hero-badge">REAL-TIME CHECK</div>
|
||||
<h1 class="hero-title">文本信息发布</h1>
|
||||
<p class="hero-sub">支持公开发布、私有发布与用户私信,提交时自动执行垃圾信息识别。</p>
|
||||
</section>
|
||||
|
||||
<section class="card fade-up fade-up-delay-1">
|
||||
<div class="card-title">发布内容</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="field-label">内容文本</label>
|
||||
<textarea class="textarea" v-model="text" placeholder="请输入要发布的文本信息" rows="4"></textarea>
|
||||
<div class="field-help">当前字数:{{ text.length }},建议不少于 2 个字符。</div>
|
||||
</div>
|
||||
|
||||
<div class="grid-2">
|
||||
<div class="field">
|
||||
<label class="field-label">发布类型</label>
|
||||
<select class="select" v-model="visibility">
|
||||
<option v-for="opt in visibilityOptions" :key="opt.value" :value="opt.value">{{ opt.label }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field" v-if="visibility === 'direct'">
|
||||
<label class="field-label">接收人用户名</label>
|
||||
<input class="input" v-model.trim="recipientUsername" placeholder="私信发送时必填" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary" :disabled="loading" @click="publish">
|
||||
{{ loading ? '检测中...' : '提交发布' }}
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<section class="card fade-up fade-up-delay-2">
|
||||
<div class="card-title">快捷示例</div>
|
||||
<div class="chip-group">
|
||||
<span
|
||||
v-for="(item, idx) in quickTexts"
|
||||
:key="idx"
|
||||
class="chip"
|
||||
@click="text = item"
|
||||
>{{ item }}</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card fade-up fade-up-delay-3" v-if="result">
|
||||
<div class="card-title">识别反馈</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">发布结果</span>
|
||||
<span :class="result.publish_allowed ? 'status-ham' : 'status-spam'">
|
||||
{{ result.publish_allowed ? '发布成功' : '已拦截,需申诉' }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="row" v-if="result.detect && result.detect.category_label">
|
||||
<span class="label">分类标签</span>
|
||||
<span class="status-spam">{{ result.detect.category_label }}</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">模型判断</span>
|
||||
<span class="value">{{ result.detect && result.detect.prediction_text }}</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">垃圾概率</span>
|
||||
<span class="value">{{ result.detect_spam_probability_text }}</span>
|
||||
</div>
|
||||
<div class="progress-track">
|
||||
<div class="progress-fill" :style="{ width: result.detect_spam_probability_text }"></div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">检测置信度</span>
|
||||
<span class="value">{{ result.detect.confidence_text }}</span>
|
||||
</div>
|
||||
<div class="progress-track">
|
||||
<div class="progress-fill-safe" :style="{ width: result.detect.confidence_text }"></div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">本次阈值</span>
|
||||
<span class="value">{{ result.post_threshold_text }}</span>
|
||||
</div>
|
||||
|
||||
<div class="field" v-if="result.detect.reason_tokens && result.detect.reason_tokens.length">
|
||||
<span class="field-label">风险关键词</span>
|
||||
<div class="chip-group">
|
||||
<span
|
||||
v-for="(tk, i) in result.detect.reason_tokens"
|
||||
:key="i"
|
||||
class="tag tag-danger"
|
||||
@click="showTokenWeight(tk)"
|
||||
>{{ tk.token }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-ghost" @click="$router.push('/history')">查看发布历史</button>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { request } from '@/utils/request'
|
||||
import { toast, confirm } from '@/utils/feedback'
|
||||
|
||||
const QUICK_TEXTS = [
|
||||
'大家好,今晚 8 点社区线上读书会,欢迎参加。',
|
||||
'恭喜中奖领取大额现金,点击链接立即到账。',
|
||||
'本周活动报名已开放,请在群里接龙。',
|
||||
'高薪兼职日结,扫码进群立刻赚钱。'
|
||||
]
|
||||
|
||||
const VISIBILITY_OPTIONS = [
|
||||
{ value: 'public', label: '公开信息发布' },
|
||||
{ value: 'private', label: '私有信息发布' },
|
||||
{ value: 'direct', label: '用户私信发布' }
|
||||
]
|
||||
|
||||
export default {
|
||||
name: 'DetectView',
|
||||
data() {
|
||||
return {
|
||||
text: '',
|
||||
loading: false,
|
||||
result: null,
|
||||
quickTexts: QUICK_TEXTS,
|
||||
visibilityOptions: VISIBILITY_OPTIONS,
|
||||
visibility: 'public',
|
||||
recipientUsername: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatPercent(value, digits = 2) {
|
||||
const num = Number(value || 0)
|
||||
return `${(num * 100).toFixed(digits)}%`
|
||||
},
|
||||
async publish() {
|
||||
if (this.loading) return
|
||||
const text = (this.text || '').trim()
|
||||
if (text.length < 2) {
|
||||
toast('请输入至少 2 个字符', 'error')
|
||||
return
|
||||
}
|
||||
const payload = { text, visibility: this.visibility }
|
||||
if (this.visibility === 'direct') {
|
||||
const receiver = (this.recipientUsername || '').trim()
|
||||
if (!receiver) {
|
||||
toast('私信请填写接收人用户名', 'error')
|
||||
return
|
||||
}
|
||||
payload.recipient_username = receiver
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
try {
|
||||
const result = await request({ url: '/content/publish', method: 'POST', data: payload })
|
||||
this.result = {
|
||||
...result,
|
||||
detect: {
|
||||
...(result.detect || {}),
|
||||
confidence_text: this.formatPercent((result.detect || {}).confidence, 2)
|
||||
},
|
||||
post_threshold_text: this.formatPercent((result.post || {}).threshold, 1),
|
||||
detect_spam_probability_text: this.formatPercent((result.detect || {}).spam_probability, 2)
|
||||
}
|
||||
toast(result.publish_allowed ? '发布成功' : '已拦截,可申诉', result.publish_allowed ? 'success' : 'error')
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
showTokenWeight(tk) {
|
||||
const weight = Number(tk.weight || 0)
|
||||
const direction = weight >= 0 ? '倾向垃圾判定' : '倾向正常判定'
|
||||
confirm({
|
||||
title: '关键词权重',
|
||||
content: `关键词「${tk.token}」\n权重贡献:${weight >= 0 ? '+' : ''}${weight.toFixed(4)}\n(${direction})`,
|
||||
showCancel: false,
|
||||
confirmText: '关闭'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user