/** * 用户资料详情页 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: [], }, 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, '操作失败'); } } }, /** * 举报:跳转 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, '拉黑失败'); } }, });