Files
danyang-match/miniapp/pages/index/index.wxml
T
WorkBuddy 1fc34f1bcd fix(miniapp): 修复导航页与微信胶囊重合,并把首页两个栏目卡缩到 1/3
问题 1:五个导航页顶部与右上角胶囊按钮(··· ⊙)重合
- 根因:自定义导航用 env(safe-area-inset-top) 取的是设备物理安全区,
  在 Android 上常为 0,完全不反映胶囊位置;且右对齐元素从未为胶囊让出宽度。
- 新增 miniapp/utils/nav-metrics.js 作为唯一事实源:以
  wx.getMenuButtonBoundingClientRect() 实测胶囊矩形,反推并导出四个 CSS 变量
  --nav-status / --nav-h / --nav-right / --nav-top,并提供无接口时的兜底值。
- nav-bar 组件改为自行获取导航度量(attached + observer 双触发),
  标题按胶囊垂直居中并收窄 max-width;外部传参降级为兜底。
- index / discover / messages / activity / mine 五页根结点注入同一组变量,
  WXSS 里的 env(safe-area-inset-top)、硬编码 88rpx 与右对齐 right:0 全量替换。

问题 2:首页「善缘公益服务」「善缘安全提醒」两个栏目过宽
- 根因:封面 <image> 只声明 width 未声明 height,小程序默认按 240px 计算,
  实际把卡片撑到约 480rpx 高。
- 按「整体等比缩到 1/3」重构:两栏改为 mini-card 小卡,宽度
  calc((100% - 2*gap)/3)、高度写死 168rpx,封面 height:100%;
  公益服务一行三卡横向排布,安全提醒为「标题小卡 + 右侧文案条」,
  长文案收进详情页,安全提示原文保留。

守卫与验证
- 新增 ui-tests/miniapp-capsule-safe-contracts.mjs:
  A 层多机型断言导航行与胶囊垂直居中、右对齐让位、navTop 与兜底值;
  B 层纯函数审计五个自带导航行页面(页面清单由文件系统推导,失配直接报红);
  C 层断言首页小卡宽为 1/3 且显式声明高度,并钉住旧 service-/safety- 选择器回归。
  审计前剥离注释,避免守卫被自身示例文本误伤。
- 新增 scripts/audit-image-height.mjs:按属性名精确比对,审计全仓
  「有 width 无 height」的 <image>,当前 30 个类 0 命中。
- 负向注入 N1~N7(含 nav-safe 未接入、旧选择器回归、极小屏幕、无胶囊兜底等)
  全部被守卫咬住并 exit 1,还原后复跑通过。
- 真编译(wcc/wcsc):WXSS 88 / WXML 86,失败 0;
  tsc --noEmit 通过;UI 契约门控 21/21 PASS(新增第 21 个守卫并抬高 MIN_GUARDS)。
- 渲染探针实测:单卡 213rpx x 168rpx;五页右对齐元素右缘 423~528px,
  均在胶囊右缘 365px 之外。

未纳入本次提交:miniapp/project.config.json(微信开发者工具自动改写,
仅追加若干布尔开关并删掉文件末换行)与生成的预览页 artifacts preview.html
(约 7900 行生成产物),以免淹没代码评审视线。
2026-09-23 09:55:40 +08:00

119 lines
8.9 KiB
Plaintext
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.
<view class="page app-page reference-page" style="{{navVars}}">
<view class="night-shell">
<view class="brand-bar">
<view class="brand-lockup">
<image class="brand-logo" src="/assets/brand/logo-mark.png" mode="aspectFit" />
<view class="brand-copy">
<text class="brand-name">善缘丹阳</text>
<text class="brand-slogan">公益婚恋服务平台</text>
</view>
</view>
<view class="brand-actions" bindtap="onMessages">
<text class="message-label">消息</text>
<text wx:if="{{unreadCount}}" class="badge">{{unreadCount}}</text>
</view>
</view>
<view class="status-strip">
<view wx:if="{{isOnboarding}}" class="status-main">
<view class="status-copy">
<text class="status-title">完善资料,开启安心相遇</text>
<text class="status-desc">{{onboardingMessage}}</text>
</view>
<view class="status-action" bindtap="onEmptyAction" data-event="{{onboardingActions[0].event}}">{{onboardingActions[0].text}}</view>
</view>
<view wx:elif="{{isPaused}}" class="status-main">
<view class="status-copy"><text class="status-title">已暂停新的对象推荐</text><text class="status-desc">你的资料仍被安全保存</text></view>
<view class="status-action" bindtap="onResume">恢复寻找</view>
</view>
<view wx:elif="{{isSuccessful}}" class="status-main">
<view class="status-copy"><text class="status-title">祝福你们认真了解彼此</text><text class="status-desc">愿真诚与尊重陪伴你们继续前行</text></view>
</view>
<view wx:else class="status-checks">
<text wx:for="{{statusChecks}}" wx:key="label" class="status-check {{item.done ? 'done' : ''}}">{{item.done ? '已完成' : '待完成'}} · {{item.label}}</text>
</view>
</view>
<view class="banner-section">
<swiper wx:if="{{banners.length}}" class="banner-swiper" indicator-dots autoplay circular interval="4500" indicator-active-color="#FF4F91" bindchange="onBannerChange">
<swiper-item wx:for="{{banners}}" wx:key="id">
<view class="banner-card" bindtap="onBannerTap" data-item="{{item}}">
<image class="banner-img" src="{{item.imageFileId || '/assets/brand/home-hero-v2.jpg'}}" mode="aspectFill" />
<view class="banner-overlay"></view>
<view class="banner-copy"><text class="banner-kicker">公益 · 本地 · 真实 · 安全</text><text class="banner-title">{{item.title}}</text><text class="banner-subtitle">{{item.subtitle}}</text></view>
</view>
</swiper-item>
</swiper>
<view wx:else class="banner-card banner-fallback">
<image class="banner-img" src="/assets/brand/home-hero-v2.jpg" mode="aspectFill" />
<view class="banner-overlay"></view>
<view class="banner-copy"><text class="banner-kicker">公益 · 本地 · 真实 · 安全</text><text class="banner-title">在丹阳,遇见更好的你</text><text class="banner-subtitle">认真认识,温暖相伴</text></view>
</view>
</view>
</view>
<view class="entries-card">
<view class="entries-grid">
<view wx:for="{{quickEntries}}" wx:key="code" class="entry-item {{!item.enabled ? 'disabled' : ''}}" bindtap="onEntryTap" data-entry="{{item}}">
<view class="entry-icon tone-{{item.tone}}"><image class="entry-icon-image" src="{{item.iconAsset}}" mode="aspectFit" /></view>
<text class="entry-label">{{item.label}}</text>
</view>
</view>
</view>
<view wx:if="{{previewMode}}" class="preview-note">当前为界面预览数据</view>
<view wx:if="{{loadError}}" class="section"><ui-error-state title="暂时无法加载首页" description="请检查网络后重试" bind:retry="onRetry" /></view>
<block wx:else>
<view class="section recommendation-section">
<ui-section-header title="今日推荐" subtitle="根据双方条件,为你认真筛选" action="查看更多" bind:action="onSeeMore" />
<ui-loading wx:if="{{loading}}" mode="skeleton" rows="2" />
<view wx:elif="{{recommendations.length}}" class="recommend-list">
<ui-recommend-card wx:for="{{recommendations}}" wx:key="userId" recommendation="{{item}}" action-loading="{{actionLoadingUserId === item.userId}}" bind:view="onViewDetail" bind:like="onLike" bind:pass="onPass" />
</view>
<view wx:else class="recommend-empty">
<image class="empty-logo" src="/assets/brand/logo-mark.png" mode="aspectFit" />
<view class="empty-copy"><text class="empty-title">暂时没有完全符合双方条件的人</text><text class="empty-desc">我们坚持 Required 条件,不会为了数量降低筛选标准</text></view>
<view class="empty-actions"><view class="empty-btn secondary" bindtap="onEmptyAction" data-event="preference">调整条件</view><view class="empty-btn primary" bindtap="onEmptyAction" data-event="matchmaker">公益红娘</view></view>
</view>
</view>
<!-- 善缘公益服务:卡片宽度与高度都缩到原尺寸的 1/3(约 224rpx × 168rpx),
只留配图 + 标题 + 一个短入口,长文案交给详情页 -->
<view class="section">
<ui-section-header title="善缘公益服务" subtitle="需要时,我们在这里陪伴你" />
<view wx:if="{{serviceRecommendations.length}}" class="mini-rail">
<view wx:for="{{serviceRecommendations}}" wx:key="type" class="mini-card" bindtap="onServiceTap" data-type="{{item.type}}">
<image class="mini-card-cover" src="/assets/covers/counseling-default.jpg" mode="aspectFill" />
<view class="mini-card-scrim"></view>
<text class="mini-card-title">{{item.title}}</text>
<text class="mini-card-sub">{{item.ctaText}}</text>
</view>
</view>
<view wx:else class="section-empty">暂无待推荐的公益服务</view>
</view>
<view class="section"><ui-section-header title="近期公益活动" action="全部活动" bind:action="onSeeAllActivities" /><scroll-view wx:if="{{activities.length}}" scroll-x class="activity-scroll"><view wx:for="{{activities}}" wx:key="id" class="activity-card" bindtap="onActivityTap" data-id="{{item.id}}"><image class="activity-cover" src="{{item.coverFileId || '/assets/covers/activity-default.jpg'}}" mode="aspectFill" /><view class="activity-info"><text class="activity-tag">公益活动</text><text class="activity-title">{{item.title}}</text><text class="activity-meta">{{item.locationName}}</text></view></view></scroll-view><view wx:else class="section-empty">近期暂无可报名活动</view></view>
<view class="section"><ui-section-header title="善缘服务站" subtitle="就在身边的公益婚恋服务阵地" /><view wx:if="{{serviceLocation}}" class="station-card" bindtap="onStationTap"><image class="station-cover" src="/assets/covers/station-default.jpg" mode="aspectFill" /><view class="station-info"><text class="station-name">{{serviceLocation.name}}</text><text class="station-desc">{{serviceLocation.shortName || serviceLocation.address}}</text><view><text wx:for="{{serviceLocation.services}}" wx:key="*this" class="mini-tag">{{item}}</text></view></view><image class="arrow-icon" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view><view wx:else class="section-empty" bindtap="onStationTap">查看线下公益服务阵地</view></view>
<view class="section"><ui-section-header title="婚恋课堂" subtitle="学习成长,收获更好的自己" action="更多内容" bind:action="onEntryTap" data-entry="{{quickEntries[4]}}" /><view wx:if="{{articles.length}}" class="article-list"><view wx:for="{{articles}}" wx:key="id" class="article-row" bindtap="onArticleTap" data-id="{{item.id}}"><image class="article-cover" src="{{item.coverFileId || '/assets/covers/classroom-default.jpg'}}" mode="aspectFill" /><view class="article-info"><text class="article-title">{{item.title}}</text><text class="article-meta">善缘课堂 · 公益内容</text></view><image class="arrow-icon" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view></view><view wx:else class="section-empty">暂无新内容,稍后再来看看</view></view>
<!-- 善缘安全提醒:同样缩到 1/3 宽度的小卡,右侧用文字承载安全提示原文与入口
(安全提示文案是公益属性的一部分,不能整块丢掉) -->
<view class="section">
<view class="mini-rail">
<view class="mini-card" bindtap="onSafetyTap">
<image class="mini-card-cover" src="/assets/covers/anti-fraud-default.jpg" mode="aspectFill" />
<view class="mini-card-scrim"></view>
<text class="mini-card-title">善缘安全提醒</text>
</view>
<view class="mini-note">
<text class="mini-note-text">{{safetyNotice.text}}</text>
<text class="mini-note-link" bindtap="onSafetyTap">{{safetyNotice.ctaText}}</text>
</view>
</view>
</view>
</block>
<view class="safe-area-bottom"></view>
</view>