Files
WorkBuddy 69ebf33e18
CI/CD Pipeline / Backend Build & Test (push) Canceled after 0s
CI/CD Pipeline / Admin Web Build (push) Canceled after 0s
CI/CD Pipeline / Mini Program Compile Check (push) Canceled after 0s
CI/CD Pipeline / Migration Validation (push) Canceled after 0s
CI/CD Pipeline / Test Shell Guard (Phase 23 Gate) (push) Canceled after 0s
CI/CD Pipeline / UI Contracts (source-structure gates) (push) Canceled after 0s
CI/CD Pipeline / E2E (live stack) (push) Canceled after 0s
release: freeze demo v1.1.0 2026-10-19
2026-10-19 20:36:22 +08:00

244 lines
8.4 KiB
JavaScript
Raw Permalink 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.
/**
* 用户资料详情页 U21
*
* 重构要点(遵循 AGENTS.md 不变量):
* - 数据获取:recommendationService.getUserDetail(API_INVENTORY 行 43),不再直连 api 模块
* - 喜欢:matchStore.like(mutualMatch=true 时跳转会话页,AGENTS 第 3/6 条)
* - 拉黑:blockUser 跨 Store 编排(MatchStore + MessageStore 同步停用,AGENTS 第 4 条)
* - 举报:跳转 report 页,不在本页处理
* - 敏感数据:profile.birthday/身份证/手机号 仅服务端持有,前端不缓存(AGENTS 第 8 条)
* - Required 不可放宽:本页只读展示,无任何放宽择偶条件的入口(AGENTS 第 2 条)
*/
const { matchStore, appStore, blockUser } = require('../../stores');
const { recommendationService } = require('../../services');
const { to, DANGER_ACTION, RELATION_STATUS, BUSINESS_ERROR_CODE, profileLabelOf, yesNoLabel, futureDanyangLabel } = require('../../constants');
Page({
data: {
userId: '',
profile: null,
loading: true,
loadError: '',
/** @type {import('../../types').RelationStatus} */
relationStatus: RELATION_STATUS.NEUTRAL,
isLiked: false,
isMutual: false,
canChat: false,
actionLoading: false,
statusBarHeight: 20,
navBarHeight: 44,
showBlockDialog: false,
blockAction: DANGER_ACTION.BLOCK,
/** 派生的展示字段 */
displayName: '',
ageText: '',
metaLine: '',
badges: [],
basicInfo: [],
attitudeInfo: [],
assistanceSubmitted: false,
},
onLoad(options) {
const userId = options.id || '';
if (!userId) {
this.setData({ loading: false, loadError: '用户不存在' });
return;
}
// 状态栏高度由 app.js 注入到全局,这里读一次
try {
const sysInfo = wx.getSystemInfoSync ? wx.getSystemInfoSync() : null;
if (sysInfo) {
this.setData({
statusBarHeight: sysInfo.statusBarHeight || 20,
navBarHeight: 44,
});
}
} catch (e) { /* 使用默认值 */ }
this.setData({ userId });
this.loadProfile();
},
async loadProfile() {
this.setData({ loading: true, loadError: '' });
try {
const user = await recommendationService.getUserDetail(this.data.userId);
this.setData({ loading: false, profile: user });
this._deriveDisplay(user);
} catch (err) {
this.setData({
loading: false,
loadError: (err && err.message) || '加载失败',
});
appStore.toastError(err, '加载用户资料失败');
}
},
/**
* 把后端 User 字段派生为展示用结构,避免 wxml 内做条件拼接
*/
_deriveDisplay(user) {
if (!user) return;
const relationStatus = user.relationStatus || RELATION_STATUS.NEUTRAL;
const isLiked = relationStatus === RELATION_STATUS.LIKED || relationStatus === RELATION_STATUS.MUTUAL_MATCH;
const isMutual = relationStatus === RELATION_STATUS.MUTUAL_MATCH;
// AGENTS 第 3 条:只有 Mutual 后才能聊天
const canChat = isMutual && relationStatus !== RELATION_STATUS.BLOCKED;
const badges = [];
if (user.verified || user.isRealNameVerified) {
badges.push({ kind: 'success', label: '已实名' });
}
if (user.reviewed || user.profileReviewStatus === 'approved') {
badges.push({ kind: 'info', label: '资料已审核' });
}
const metaParts = [];
if (user.heightCm) metaParts.push(`${user.heightCm}cm`);
if (user.regionName) metaParts.push(user.regionName);
const eduLabel = profileLabelOf('educationCode', user.educationCode);
if (eduLabel) metaParts.push(eduLabel);
const occLabel = profileLabelOf('occupationCode', user.occupationCode);
if (occLabel) metaParts.push(occLabel);
const basicInfo = [];
const maritalLabel = profileLabelOf('maritalStatus', user.maritalStatus);
if (maritalLabel) basicInfo.push({ label: '婚姻状况', value: maritalLabel });
if (user.childrenStatus || user.hasChildren !== undefined) {
basicInfo.push({ label: '子女情况', value: user.childrenStatus ? profileLabelOf('childrenStatus', user.childrenStatus) : (user.hasChildren ? '有孩' : '无孩') });
}
if (eduLabel) basicInfo.push({ label: '学历', value: eduLabel });
if (occLabel) basicInfo.push({ label: '职业', value: occLabel });
const smokingLabel = profileLabelOf('smokingStatus', user.smokingStatus);
if (smokingLabel) basicInfo.push({ label: '吸烟', value: smokingLabel });
const drinkingLabel = profileLabelOf('drinkingStatus', user.drinkingStatus);
if (drinkingLabel) basicInfo.push({ label: '饮酒', value: drinkingLabel });
const longTermLabel = yesNoLabel(user.longTermDanyang);
if (longTermLabel) basicInfo.push({ label: '定居意愿', value: longTermLabel, full: true });
const futureLabel = futureDanyangLabel(user.futureDanyang);
if (futureLabel) basicInfo.push({ label: '未来规划', value: futureLabel, full: true });
const attitudeInfo = [];
// relationshipGoal / marriagePlan 由后端返回中文文案(结婚 / 恋爱 等),未知码原样透传
if (user.relationshipGoal) attitudeInfo.push({ label: '寻找', value: user.relationshipGoal, full: true });
if (user.marriagePlan) attitudeInfo.push({ label: '结婚计划', value: user.marriagePlan, full: true });
this.setData({
relationStatus,
isLiked,
isMutual,
canChat,
displayName: user.displayName || '用户',
ageText: user.age ? `${user.age}岁` : '',
metaLine: metaParts.join(' · '),
badges,
basicInfo,
attitudeInfo,
});
},
onBack() {
wx.navigateBack();
},
onRetry() {
this.loadProfile();
},
/**
* 喜欢(AGENTS 第 3/5/6 条:用户本人操作,mutualMatch 时跳聊天)
*/
async onLike() {
const { userId, actionLoading, isLiked } = this.data;
if (!userId || actionLoading || isLiked) return;
this.setData({ actionLoading: true });
try {
const result = await matchStore.like(userId);
// 本地派生状态更新
if (result && result.mutualMatch) {
this.setData({
isLiked: true,
isMutual: true,
canChat: true,
relationStatus: RELATION_STATUS.MUTUAL_MATCH,
actionLoading: false,
});
appStore.toastSuccess('双向意向匹配成功,可查看公益服务');
} else {
this.setData({
isLiked: true,
relationStatus: RELATION_STATUS.LIKED,
actionLoading: false,
});
appStore.toastSuccess('已表达喜欢');
}
} catch (err) {
this.setData({ actionLoading: false });
if (err && err.code === BUSINESS_ERROR_CODE.DUPLICATE_ACTION) {
appStore.toast('已表达过喜欢');
} else {
appStore.toastError(err, '操作失败');
}
}
},
onApplyMatchmaker() {
const { userId, actionLoading, assistanceSubmitted } = this.data;
if (!userId || actionLoading || assistanceSubmitted) return;
wx.navigateTo({
url: `/pages/matchmaker-authorization/matchmaker-authorization?targetUserId=${encodeURIComponent(userId)}`,
});
},
/**
* 举报:跳转 report 页,不在本页处理(AGENTS 第 7 条:举报内容不在此暴露)
*/
onReport() {
const { userId } = this.data;
if (!userId) return;
wx.navigateTo({ url: to.report(userId) });
},
/**
* 拉黑入口:弹出 DangerActionDialog 二次确认(AGENTS 第 4 条)
*/
onBlock() {
if (!this.data.userId) return;
this.setData({ showBlockDialog: true });
},
onConfirmBlock() {
this.setData({ showBlockDialog: false });
this._doBlock();
},
onCancelBlock() {
this.setData({ showBlockDialog: false });
},
/**
* 执行拉黑:调用跨 Store 编排 blockUser
* - MatchStore:从推荐/Mutual 列表移除
* - MessageStore:会话立即标记不可发消息
*/
async _doBlock() {
const { userId, actionLoading } = this.data;
if (!userId || actionLoading) return;
this.setData({ actionLoading: true });
try {
appStore.showLoading('处理中…');
await blockUser(userId, '用户主动拉黑');
appStore.hideLoading();
appStore.toastSuccess('已拉黑');
// 拉黑后离开当前页(AGENTS 第 4 条:Block 即时禁止互动)
setTimeout(() => wx.navigateBack(), 800);
} catch (err) {
appStore.hideLoading();
this.setData({ actionLoading: false });
appStore.toastError(err, '拉黑失败');
}
},
});