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