xiangqinxiaochengxu/miniprogram/pages/match/match.wxml
taiyi a8e6edf296 更新功能修改完版本提交:
功能需求:活动分享与嘉宾匹配系统
1. 活动分享入口
每个活动配置独立的分享链接和二维码,支持扫码或点击链接进入小程序。
2. 用户绑定流程
用户通过分享链接/二维码打开小程序,填写个人信息并绑定至对应活动。
若用户曾参与过历史活动,系统自动复用其历史信息并完成绑定,无需重复填写。
绑定成功后,在活动正式开始前,用户无法查看其他参与者的信息。
3. 信息可见性规则
活动开始前:仅允许查看自己的信息,其他用户信息不可见。
活动开始后:开放本活动内异性嘉宾资料查看与匹配,其他活动的用户信息完全隔离,不可见。
资料展示:男嘉宾、女嘉宾资料分开展示,用户仅可浏览异性嘉宾信息。
4. 嘉宾选择规则
每位用户最多可选择 3 位心仪嘉宾。
确认提交后不可再新增选择,但支持修改或撤销已选嘉宾。
管理员可设置匹配截止时间,到达截止时间后系统自动锁定,禁止任何修改。
5. 匹配判定规则
双向互选:若双方恰好互选,则判定为匹配成功,双方均可查看匹配结果。
多向匹配:用户同时与多位嘉宾匹配成功,全部同时展示。
单向选择:A选择B但B未选择A,A可在"谁选了我"页面看到B。
6. 用户页面说明
异性嘉宾列表:展示所有异性嘉宾资料,支持选择/取消选择。
我的选择:展示当前已选的3位嘉宾,支持修改/撤销(截止前)。
谁选了我:展示所有选择了自己的嘉宾(无论自己是否选择了对方)。
匹配成功:展示所有双向互选的匹配对象,支持查看对方完整资料。
2026-05-17 10:23:02 +08:00

105 lines
6.3 KiB
Plaintext

<view class="page match-page">
<view class="hero-box">
<view>
<view class="hero-title">{{source === 'activity' ? (activityTitle || '活动专属推荐') : '今日推荐'}}</view>
<view class="hero-desc">{{source === 'activity' ? '仅展示当前活动内的异性嘉宾,右滑加入我的选择。' : '优先展示同城、兴趣重叠和价值观更接近的候选人。'}}</view>
</view>
<button wx:if="{{source !== 'activity'}}" class="ai-btn {{aiMatching ? 'ai-btn-loading' : ''}}" bindtap="triggerAi" disabled="{{aiMatching}}">{{aiMatching ? '匹配中...' : '匹配推荐'}}</button>
</view>
<view wx:if="{{source === 'activity' && selectionSummaryText}}" class="activity-banner">{{selectionSummaryText}}</view>
<view wx:if="{{source === 'activity' && activityMatchText}}" class="activity-banner secondary-banner">{{activityMatchText}}</view>
<view class="swipe-tip">左滑跳过 · 右滑选择 · 点击卡片查看资料</view>
<view class="ai-status">{{getAiStatusText()}}<text wx:if="{{aiSuggestionCount}}"> · 共 {{aiSuggestionCount}} 人</text></view>
<view wx:if="{{source === 'activity' && activityId}}" class="quick-actions">
<button class="ghost-btn quick-btn" bindtap="goMyMatches">我的选择与结果</button>
</view>
<view wx:if="{{loading}}" class="loading-tip">正在加载推荐候选人...</view>
<view wx:if="{{currentCandidate}}" class="deck-area">
<view wx:if="{{nextCandidate}}" class="match-card match-card-shadow {{swipeActive ? 'match-card-shadow-active' : ''}}">
<view class="match-cover shadow-cover">
<image wx:if="{{nextCandidate.avatar_blur_url}}" class="cover-image" src="{{nextCandidate.avatar_blur_url}}" mode="aspectFill" />
<view wx:else class="cover-image avatar-placeholder">用户</view>
</view>
</view>
<view class="match-card match-card-active {{swipeActive ? 'match-card-moving' : ''}} {{cardExitClass}}" style="transform: translateX({{dragOffsetX}}px) rotate({{dragRotation}}deg);">
<view class="swipe-badge swipe-badge-like" wx:if="{{swipeHint === 'like'}}">感兴趣</view>
<view class="swipe-badge swipe-badge-skip" wx:if="{{swipeHint === 'skip'}}">跳过</view>
<view class="match-cover" data-id="{{currentCandidate.user_id}}" bindtap="openCard" catchtouchstart="handleTouchStart" catchtouchmove="handleTouchMove" catchtouchend="handleTouchEnd" catchtouchcancel="handleTouchCancel">
<image wx:if="{{currentCandidate.avatar_blur_url}}" class="cover-image" src="{{currentCandidate.avatar_blur_url}}" mode="aspectFill" />
<view wx:else class="cover-image avatar-placeholder">用户</view>
<view class="cover-overlay">
<view class="cover-top">
<view class="score-chip score-chip--{{currentCandidate.matchScoreLevel}}" wx:if="{{currentCandidate.hasMatchScore}}">
<text class="score-chip-value">{{currentCandidate.matchScoreText}}</text>
<text class="score-chip-label">匹配度</text>
</view>
</view>
<view class="cover-bottom">
<view class="name-row">
<text class="name">{{currentCandidate.nicknameText}}</text>
</view>
<view class="meta">{{currentCandidate.birthYearRangeText}} · {{currentCandidate.cityText}}</view>
</view>
</view>
</view>
<view class="card-main">
<view class="card-main-header">
<view class="card-caption-row">
<view class="card-caption-title">推荐印象</view>
<view class="card-caption-status">{{canOperate ? '可滑动操作' : '当前不可操作'}}</view>
</view>
<view class="card-summary">
<view class="card-summary-name">{{currentCandidate.nicknameText}}</view>
<view class="card-summary-meta">{{currentCandidate.birthYearRangeText}} · {{currentCandidate.cityText}}</view>
</view>
</view>
<view class="card-main-body">
<view class="tags">
<text wx:for="{{currentCandidate.personality_tags}}" wx:key="*this" class="tag">{{item}}</text>
</view>
<view wx:if="{{currentCandidate.hasMatchReasons}}" class="reasons">
<view class="reasons-title">推荐理由</view>
<view class="reasons-text">{{currentCandidate.matchReasonsText}}</view>
</view>
<view wx:if="{{!currentCandidate.personality_tags.length && !currentCandidate.hasMatchReasons}}" class="card-empty-state">系统正在补全该候选人的资料与推荐理由。</view>
</view>
</view>
</view>
</view>
<view wx:else class="empty-card">
<view class="empty-title">{{source === 'activity' ? '本活动可匹配的候选人已看完' : '今天的推荐已经看完啦'}}</view>
<view class="empty-desc">{{source === 'activity' ? '该活动内没有更多可匹配对象,或你的可选人数已达上限。' : '稍后再来看看,或者点击匹配获取新的候选人。'}}</view>
</view>
<view wx:if="{{activeCandidate}}" class="mask" bindtap="closeCard">
<view class="sheet" catchtap="noop">
<view class="sheet-title">候选人信息</view>
<view class="sheet-text">昵称:{{activeCandidate.nicknameText}}</view>
<view class="sheet-text">年龄范围:{{activeCandidate.birthYearRangeText}}</view>
<view class="sheet-text">城市:{{activeCandidate.cityText}}</view>
<view class="sheet-text">性格:{{activeCandidatePersonalityText}}</view>
<view wx:if="{{activeCandidate.hasMatchReasons}}" class="sheet-reasons">{{activeCandidate.matchReasonsText}}</view>
<button class="primary-btn" data-id="{{activeCandidate.user_id}}" bindtap="likeUser">加入我的选择</button>
</view>
</view>
<view wx:if="{{mutualMatchVisible}}" class="success-mask" bindtap="closeMutualMatch">
<view class="success-card" catchtap="noop">
<view class="success-badge">MATCH</view>
<view class="success-title">匹配成功</view>
<view class="success-desc">你和 {{mutualMatchName}} 互相感兴趣,快去“我的选择与结果”查看更完整的信息吧。</view>
<view class="success-actions">
<button class="ghost-btn success-ghost-btn" bindtap="closeMutualMatch">稍后查看</button>
<button class="primary-btn" bindtap="goMyMatches">查看结果</button>
</view>
</view>
</view>
</view>