244 lines
6.8 KiB
JavaScript
244 lines
6.8 KiB
JavaScript
const { request, uploadFile } = require('../../utils/request')
|
|
|
|
const STATUS_OPTIONS = [
|
|
{ value: '', label: '全部状态' },
|
|
{ value: 'published', label: '发布成功' },
|
|
{ value: 'blocked', label: '已拦截' }
|
|
]
|
|
|
|
const VISIBILITY_OPTIONS = [
|
|
{ value: '', label: '全部类型' },
|
|
{ value: 'public', label: '公开' },
|
|
{ value: 'private', label: '私有' },
|
|
{ value: 'direct', label: '私信' }
|
|
]
|
|
|
|
const VIS_LABEL = {
|
|
public: '公开信息',
|
|
private: '私有信息',
|
|
direct: '用户私信'
|
|
}
|
|
|
|
const APPEAL_STATUS_TEXT = {
|
|
none: '未发起',
|
|
pending: '处理中',
|
|
approved: '已通过',
|
|
rejected: '已驳回'
|
|
}
|
|
|
|
const CATEGORY_LABELS = {
|
|
fraud: '疑似诈骗',
|
|
harassment: '疑似骚扰',
|
|
advertisement: '疑似广告',
|
|
spam: '疑似垃圾'
|
|
}
|
|
|
|
const REASON_TYPE_OPTIONS = [
|
|
{ value: '', label: '请选择申诉理由类型' },
|
|
{ value: '正常活动文案', label: '正常活动文案' },
|
|
{ value: '正常社区通知', label: '正常社区通知' },
|
|
{ value: '私信沟通内容', label: '私信沟通内容' },
|
|
{ value: '其他', label: '其他(需手动填写)' }
|
|
]
|
|
|
|
Page({
|
|
data: {
|
|
loading: false,
|
|
list: [],
|
|
statusOptions: STATUS_OPTIONS,
|
|
statusIndex: 0,
|
|
visibilityOptions: VISIBILITY_OPTIONS,
|
|
visibilityIndex: 0,
|
|
appealPostId: null,
|
|
appealReasonType: '',
|
|
appealReasonTypeOptions: REASON_TYPE_OPTIONS,
|
|
appealReasonTypeIndex: 0,
|
|
appealReason: '',
|
|
appealEvidenceUrls: [],
|
|
appealEvidenceFiles: []
|
|
},
|
|
|
|
formatPercent(value, digits = 2) {
|
|
const num = Number(value || 0)
|
|
return `${(num * 100).toFixed(digits)}%`
|
|
},
|
|
|
|
onShow() {
|
|
this.fetchList()
|
|
},
|
|
|
|
onPullDownRefresh() {
|
|
this.fetchList(true)
|
|
},
|
|
|
|
onStatusChange(e) {
|
|
this.setData({ statusIndex: Number(e.detail.value || 0) })
|
|
this.fetchList()
|
|
},
|
|
|
|
onVisibilityChange(e) {
|
|
this.setData({ visibilityIndex: Number(e.detail.value || 0) })
|
|
this.fetchList()
|
|
},
|
|
|
|
async fetchList(fromPullDown = false) {
|
|
this.setData({ loading: true })
|
|
try {
|
|
const status = this.data.statusOptions[this.data.statusIndex].value
|
|
const visibility = this.data.visibilityOptions[this.data.visibilityIndex].value
|
|
const query = `status=${encodeURIComponent(status)}&visibility=${encodeURIComponent(visibility)}&page=1&page_size=80`
|
|
const data = await request({ url: `/content/posts/history?${query}` })
|
|
const list = (data.items || []).map((item) => ({
|
|
...item,
|
|
created_text: (item.created_at || '').replace('T', ' ').slice(0, 19),
|
|
spam_probability_text: this.formatPercent(item.spam_probability, 2),
|
|
visibility_text: VIS_LABEL[item.visibility] || item.visibility,
|
|
appeal_status_text: APPEAL_STATUS_TEXT[item.appeal_status] || item.appeal_status,
|
|
category_label: CATEGORY_LABELS[item.category] || ''
|
|
}))
|
|
this.setData({ list })
|
|
} finally {
|
|
this.setData({ loading: false })
|
|
if (fromPullDown) wx.stopPullDownRefresh()
|
|
}
|
|
},
|
|
|
|
startAppeal(e) {
|
|
const postId = Number(e.currentTarget.dataset.id)
|
|
this.setData({
|
|
appealPostId: postId,
|
|
appealReasonType: '',
|
|
appealReasonTypeIndex: 0,
|
|
appealReason: '',
|
|
appealEvidenceUrls: [],
|
|
appealEvidenceFiles: []
|
|
})
|
|
},
|
|
|
|
onReasonTypeChange(e) {
|
|
const idx = Number(e.detail.value || 0)
|
|
const reasonType = this.data.appealReasonTypeOptions[idx].value
|
|
this.setData({ appealReasonTypeIndex: idx, appealReasonType: reasonType })
|
|
// 如果选择"其他",清空快捷理由,让用户手动输入
|
|
if (reasonType === '其他') {
|
|
this.setData({ appealReasonType: '' })
|
|
}
|
|
},
|
|
|
|
onAppealInput(e) {
|
|
this.setData({ appealReason: e.detail.value || '' })
|
|
},
|
|
|
|
chooseEvidence() {
|
|
wx.chooseMedia({
|
|
count: 3,
|
|
mediaType: ['image'],
|
|
sourceType: ['album', 'camera'],
|
|
success: (res) => {
|
|
const files = res.tempFiles.map((f) => f.tempFilePath)
|
|
this.setData({
|
|
appealEvidenceFiles: [...this.data.appealEvidenceFiles, ...files].slice(0, 3)
|
|
})
|
|
}
|
|
})
|
|
},
|
|
|
|
removeEvidence(e) {
|
|
const idx = Number(e.currentTarget.dataset.index || 0)
|
|
const files = this.data.appealEvidenceFiles.filter((_, i) => i !== idx)
|
|
const urls = this.data.appealEvidenceUrls.filter((_, i) => i !== idx)
|
|
this.setData({ appealEvidenceFiles: files, appealEvidenceUrls: urls })
|
|
},
|
|
|
|
async uploadAllEvidence() {
|
|
const files = this.data.appealEvidenceFiles
|
|
if (!files.length) return []
|
|
|
|
const urls = []
|
|
for (const filePath of files) {
|
|
try {
|
|
const result = await uploadFile(filePath)
|
|
urls.push(result.url)
|
|
} catch (err) {
|
|
console.error('上传失败', filePath, err)
|
|
}
|
|
}
|
|
return urls
|
|
},
|
|
|
|
cancelAppeal() {
|
|
this.setData({
|
|
appealPostId: null,
|
|
appealReasonType: '',
|
|
appealReasonTypeIndex: 0,
|
|
appealReason: '',
|
|
appealEvidenceUrls: [],
|
|
appealEvidenceFiles: []
|
|
})
|
|
},
|
|
|
|
async submitAppeal() {
|
|
const postId = this.data.appealPostId
|
|
if (!postId) return
|
|
|
|
const reasonType = (this.data.appealReasonType || '').trim()
|
|
const reason = (this.data.appealReason || '').trim()
|
|
|
|
// 如果没有选择快捷理由类型,必须手动填写理由
|
|
if (!reasonType && reason.length < 2) {
|
|
wx.showToast({ title: '申诉理由至少 2 个字符', icon: 'none' })
|
|
return
|
|
}
|
|
|
|
// 上传证据图片
|
|
const evidenceUrls = await this.uploadAllEvidence()
|
|
|
|
await request({
|
|
url: `/content/posts/${postId}/appeal`,
|
|
method: 'POST',
|
|
data: {
|
|
reason_type: reasonType,
|
|
reason,
|
|
evidence_urls: evidenceUrls
|
|
}
|
|
})
|
|
wx.showToast({ title: '申诉提交成功', icon: 'success' })
|
|
this.setData({
|
|
appealPostId: null,
|
|
appealReasonType: '',
|
|
appealReasonTypeIndex: 0,
|
|
appealReason: '',
|
|
appealEvidenceUrls: [],
|
|
appealEvidenceFiles: []
|
|
})
|
|
this.fetchList()
|
|
},
|
|
|
|
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: '关闭'
|
|
})
|
|
},
|
|
|
|
removeItem(e) {
|
|
const id = Number(e.currentTarget.dataset.id)
|
|
wx.showModal({
|
|
title: '删除确认',
|
|
content: '确定删除这条发布记录吗?',
|
|
success: async (res) => {
|
|
if (!res.confirm) return
|
|
await request({ url: `/content/posts/${id}`, method: 'DELETE' })
|
|
wx.showToast({ title: '删除成功', icon: 'success' })
|
|
this.fetchList()
|
|
}
|
|
})
|
|
}
|
|
})
|