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

142 lines
3.9 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.
/**
* 申诉提交页(重构:用 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();
},
});