Files
danyang-match/miniapp/pages/appeal/appeal.js
T

142 lines
3.9 KiB
JavaScript
Raw Normal View History

2026-09-09 22:05:00 +08:00
/**
* 申诉提交页(重构:用 appealService.submitAppeal + ui-nav-bar + ui-textarea)
*
* 用户针对封禁/暂停处置提交申诉。类型由入口决定(ban_appeal / suspend_appeal)。
*
* 不变量(AGENTS.md):
* - 第 8 条:敏感数据默认拒绝——本页只接收申诉原因 + 证据截图 + 联系方式,
* 不接受身份证号等敏感字段;联系方式为可选。
* - 第 4 条:Block 优先级最高——申诉不会自动解封或解除拉黑,由运营人工处置。
* 幂等:appealService.submitAppeal 内部以 appealType+relatedActionId+秒级时间生成 Idempotency-Key。
*/
const { appStore } = require('../../stores');
const { appealService } = require('../../services');
const TYPE_LABELS = {
ban_appeal: '封禁申诉',
suspend_appeal: '暂停申诉',
};
const MIN_REASON_LEN = 10;
const MAX_EVIDENCE = 5;
Page({
data: {
appealType: '',
actionId: '',
typeLabel: '申诉',
reason: '',
reasonError: '',
evidenceFiles: [],
contactMethod: '',
submitting: false,
submitted: false,
statusBarHeight: 20,
navBarHeight: 44,
},
onLoad(options) {
try {
const info = (wx.getWindowInfo && wx.getWindowInfo()) || wx.getSystemInfoSync();
this.setData({
statusBarHeight: info.statusBarHeight || 20,
navBarHeight: info.platform === 'android' ? 48 : 44,
});
} catch (e) { /* 使用默认值 */ }
const appealType = options.type ? decodeURIComponent(options.type) : '';
const actionId = options.actionId ? decodeURIComponent(options.actionId) : '';
this.setData({
appealType,
actionId,
typeLabel: TYPE_LABELS[appealType] || '申诉',
});
},
onReasonInput(e) {
this.setData({ reason: e.detail.value, reasonError: '' });
},
onContactInput(e) {
this.setData({ contactMethod: e.detail.value });
},
// ============ 证据上传 ============
chooseEvidence() {
const remain = MAX_EVIDENCE - this.data.evidenceFiles.length;
if (remain <= 0) {
appStore.toast('最多上传 5 张证据');
return;
}
wx.chooseMedia({
count: remain,
mediaType: ['image'],
sourceType: ['album', 'camera'],
success: (res) => {
const files = res.tempFiles.map((f) => f.tempFilePath);
this.setData({ evidenceFiles: [...this.data.evidenceFiles, ...files] });
},
});
},
previewImage(e) {
wx.previewImage({
current: e.currentTarget.dataset.url,
urls: this.data.evidenceFiles,
});
},
removeImage(e) {
const idx = e.currentTarget.dataset.index;
const files = this.data.evidenceFiles;
files.splice(idx, 1);
this.setData({ evidenceFiles: files });
},
// ============ 提交 ============
async submitAppeal() {
const { appealType, actionId, reason, contactMethod } = this.data;
const trimmedReason = (reason || '').trim();
if (!appealType) {
appStore.toast('缺少申诉类型');
return;
}
if (!trimmedReason) {
this.setData({ reasonError: '请填写申诉原因' });
return;
}
if (trimmedReason.length < MIN_REASON_LEN) {
this.setData({ reasonError: `申诉原因请至少 ${MIN_REASON_LEN} 个字` });
return;
}
this.setData({ submitting: true });
try {
await appealService.submitAppeal({
appealType,
relatedActionId: actionId || undefined,
reason: trimmedReason,
// 证据上传至 OSS 后回填 fileId;当前阶段先以本地路径占位,由后端证据服务接入后补全
evidenceFileIds: [],
contactMethod: (contactMethod || '').trim() || undefined,
});
this.setData({ submitted: true, submitting: false });
appStore.toastSuccess('申诉已提交');
} catch (err) {
appStore.toastError(err);
this.setData({ submitting: false });
}
},
goBack() {
wx.navigateBack();
},
onBack() {
wx.navigateBack();
},
});