各页面增加垃圾信息分类标签显示: - 检测结果页显示分类标签 - 批量识别页和CSV导出增加分类标签列 - 历史记录页显示分类标签 - 管理后台审核页显示分类标签 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
163 lines
4.8 KiB
JavaScript
163 lines
4.8 KiB
JavaScript
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' })
|
||
}
|
||
})
|
||
}
|
||
})
|