Files
c/miniprogram/pages/batch/index.js
刘正航 2dcd7ce9f6 feat: 小程序前端显示分类标签
各页面增加垃圾信息分类标签显示:
- 检测结果页显示分类标签
- 批量识别页和CSV导出增加分类标签列
- 历史记录页显示分类标签
- 管理后台审核页显示分类标签

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-22 21:52:17 +08:00

163 lines
4.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const { request } = require('../../utils/request')
Page({
data: {
inputText: '',
loading: false,
summary: null,
items: []
},
formatPercent(value, digits = 2) {
const num = Number(value || 0)
return `${(num * 100).toFixed(digits)}%`
},
onInput(e) {
this.setData({ inputText: e.detail.value || '' })
},
parseLines() {
return (this.data.inputText || '')
.split('\n')
.map((line) => line.trim())
.filter((line) => line.length >= 2)
},
async submit() {
if (this.data.loading) return
const items = this.parseLines()
if (!items.length) {
wx.showToast({ title: '请至少输入一条有效文本', icon: 'none' })
return
}
this.setData({ loading: true })
try {
const data = await request({
url: '/spam/predict/batch',
method: 'POST',
data: { items }
})
const summary = {
...(data.summary || {}),
spam_ratio_text: this.formatPercent((data.summary || {}).spam_ratio, 2),
blocked_ratio_text: this.formatPercent((data.summary || {}).blocked_ratio, 2)
}
const normalizedItems = (data.items || []).map((item) => ({
...item,
confidence_text: this.formatPercent(item.confidence, 2)
}))
this.setData({ summary, items: normalizedItems })
} finally {
this.setData({ loading: false })
}
},
fillDemo() {
this.setData({
inputText: [
'点击链接领取购物补贴,名额有限。',
'明天下午三点上线前演练。',
'高薪兼职日结,扫码进群。',
'测试报告我已经同步到项目群。'
].join('\n')
})
},
showTokenWeight(e) {
const token = e.currentTarget.dataset.token
const weight = e.currentTarget.dataset.weight
const weightNum = Number(weight || 0)
const direction = weightNum >= 0 ? '倾向垃圾判定' : '倾向正常判定'
wx.showModal({
title: '关键词权重',
content: `关键词"${token}"\n权重贡献:${weightNum >= 0 ? '+' : ''}${weightNum.toFixed(4)}\n(${direction})`,
showCancel: false,
confirmText: '关闭'
})
},
generateCSV() {
const items = this.data.items
if (!items.length) return ''
const headers = ['文本', '判定结果', '分类标签', '置信度', '垃圾概率', '正常概率', '风险关键词']
const rows = items.map((item) => {
const prediction = item.prediction === 'spam' ? '垃圾信息' : '正常信息'
const categoryLabel = item.category_label || ''
const confidence = item.confidence_text || '0%'
const spamProb = this.formatPercent(item.spam_probability, 4)
const hamProb = this.formatPercent(item.ham_probability, 4)
const tokens = (item.reason_tokens || []).map((t) => t.token || t).join('; ')
// CSV 转义:文本中的逗号和换行需要处理
const text = (item.text || '').replace(/"/g, '""')
const tokensEscaped = tokens.replace(/"/g, '""')
return `"${text}","${prediction}","${categoryLabel}","${confidence}","${spamProb}","${hamProb}","${tokensEscaped}"`
})
return [headers.join(','), ...rows].join('\n')
},
exportCSV() {
const items = this.data.items
if (!items.length) {
wx.showToast({ title: '暂无识别结果可导出', icon: 'none' })
return
}
const csvContent = this.generateCSV()
const timestamp = new Date().toISOString().slice(0, 19).replace(/[T:]/g, '-')
const filename = `batch_detect_${timestamp}.csv`
// 写入临时文件
const fs = wx.getFileSystemManager()
const tempPath = `${wx.env.USER_DATA_PATH}/${filename}`
try {
fs.writeFileSync(tempPath, csvContent, 'utf8')
wx.showModal({
title: '导出成功',
content: `CSV文件已生成是否打开查看\n文件名:${filename}`,
confirmText: '打开',
cancelText: '关闭',
success: (res) => {
if (res.confirm) {
wx.openDocument({
filePath: tempPath,
fileType: 'csv',
showMenu: true,
fail: (err) => {
console.error('打开文件失败', err)
wx.showToast({ title: '打开失败,请检查文件管理器', icon: 'none' })
}
})
}
}
})
} catch (err) {
console.error('写入文件失败', err)
wx.showToast({ title: '导出失败', icon: 'none' })
}
},
copyCSVToClipboard() {
const items = this.data.items
if (!items.length) {
wx.showToast({ title: '暂无识别结果可复制', icon: 'none' })
return
}
const csvContent = this.generateCSV()
wx.setClipboardData({
data: csvContent,
success: () => {
wx.showToast({ title: 'CSV内容已复制到剪贴板', icon: 'success' })
}
})
}
})