Files
danyang-match/miniapp/pages/premarital-request/premarital-request.ts
T
WorkBuddy 8dee67040c fix(miniapp): 幂等键改为按操作稳定;删除指向 404 的互选死代码
1) 幂等键(配合后端机制)

原写法把 Date.now() 拼进幂等键,每次调用都生成新键,即使后端实现了幂等
也永远不会命中 —— 声明端与实现端各自都坏。

api.idempotencyKey(scope, subject):键缓存在 _pendingIdempotency(TTL 10min),
同一逻辑操作在成功之前复用同一把键,收到 200+success 才释放;失败(含网络错误)
不释放,下次重试沿用同一把键。25 处调用点(8 个 service + 2 个 TS 页面)全部替换,
Date.now 幂等键写法残留经 grep 为 0。

2) 删除死代码 submitInterests

它请求 POST /activities/{id}/interests —— 后端从未实现该端点
(Phase 16 已把表达意向合并进 /activities/{id}/feedback 的
interestTargetUserIds)。全仓确认无任何页面/组件调用方。
两个文件各留注释说明删除原因与恢复条件:若产品确认需要独立的
「提交互选」端点,应先定义语义并补后端实现,再恢复前端方法。

store 头部关于 AGENTS 第 6 条(单向意向保密)的注释同步改为引用
submitFeedback 返回的 newMutuals。
2026-09-18 16:37:33 +08:00

64 lines
3.2 KiB
TypeScript
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.
export {}
import { request } from '../../utils/requestPromise'
import api from '../../utils/api'
const app = getApp<{ globalData: { apiBase: string; token: string } }>();
Page({
data: {
name: '', phone: '', hasCompanion: false, companionName: '', companionUserId: '',
preferredTime: '', summary: '', submitting: false, errorMsg: ''
},
onNameInput(e: any) { this.setData({ name: e.detail.value }); },
onPhoneInput(e: any) { this.setData({ phone: e.detail.value }); },
onCompanionChange(e: any) { this.setData({ hasCompanion: e.detail.value }); },
onCompanionNameInput(e: any) { this.setData({ companionName: e.detail.value }); },
onCompanionIdInput(e: any) { this.setData({ companionUserId: e.detail.value }); },
onTimeInput(e: any) { this.setData({ preferredTime: e.detail.value }); },
onSummaryInput(e: any) { this.setData({ summary: e.detail.value }); },
async onSubmit() {
const { name, phone, hasCompanion, companionName, companionUserId, preferredTime, summary } = this.data;
if (!name || !phone) {
wx.showToast({ title: '请填写姓名和联系方式', icon: 'none' });
return;
}
this.setData({ submitting: true, errorMsg: '' });
// 幂等键在「一次提交」内保持稳定:网络异常后用户重试复用同一把键,
// 后端据此识别为重复投递(重放首次结果)而不是第二次申请。
const idempotencyKey = api.idempotencyKey('premarital-apply', name);
try {
const res = await request<any>({
url: `${app.globalData.apiBase}/counseling/services`,
method: 'POST',
header: { 'Authorization': `Bearer ${app.globalData.token}`, 'Content-Type': 'application/json' },
data: {
serviceType: 'premarital_guidance',
preferredTime,
// 字段名与后端 ApplyRequest 对齐(此前用 userRequestSummary 导致后端拿到 null)
summary: summary || `申请人:${name},电话:${phone}${hasCompanion ? `,伴侣:${companionName}` : ''}`,
requestSource: 'user_self',
// INV-005:伴侣须**本人**确认。此处只登记受邀伴侣 ID,确认动作由伴侣本人另行完成。
companionUserId: hasCompanion ? (companionUserId || null) : null,
// 幂等键由 api 层托管(见 onSubmit 开头的说明)
idempotencyKey
}
});
if (res.statusCode === 200 && res.data && res.data.success) {
// 提交已落地:释放幂等键,下一次申请是新的一次
api.releaseIdempotencyKey(idempotencyKey);
wx.showToast({ title: hasCompanion ? '已提交,伴侣需本人确认' : '申请已提交', icon: 'success' });
setTimeout(() => wx.redirectTo({ url: '/pages/my-counseling/my-counseling' }), 1800);
} else {
this.setData({ errorMsg: (res.data && res.data.message) || '提交失败,请重试' });
wx.showToast({ title: (res.data && res.data.message) || '提交失败', icon: 'none' });
}
} catch (e) {
this.setData({ errorMsg: '网络异常,请稍后重试' });
wx.showToast({ title: '网络异常,请稍后重试', icon: 'none' });
} finally {
this.setData({ submitting: false });
}
}
});