feat: rebuild miniapp reference home
This commit is contained in:
@@ -1,75 +1,13 @@
|
|||||||
<view class="ui-rec" wx:if="{{recommendation}}">
|
<view class="ui-rec" wx:if="{{recommendation}}" bindtap="onViewDetail">
|
||||||
<view class="ui-rec__header" bindtap="onViewDetail">
|
<ui-avatar src="{{recommendation.avatarUrl || '/assets/brand/default-avatar.png'}}" size="lg" verified="{{recommendation.verified}}" reviewed="{{recommendation.reviewed}}" default-text="{{recommendation.displayName}}" />
|
||||||
<ui-avatar
|
|
||||||
src="{{recommendation.avatarUrl}}"
|
|
||||||
size="xl"
|
|
||||||
verified="{{recommendation.verified}}"
|
|
||||||
reviewed="{{recommendation.reviewed}}"
|
|
||||||
default-text="{{recommendation.displayName}}"
|
|
||||||
/>
|
|
||||||
<view class="ui-rec__info">
|
<view class="ui-rec__info">
|
||||||
<view class="ui-rec__name-row">
|
<view class="ui-rec__name-row"><text class="ui-rec__name">{{recommendation.displayName || '善缘用户'}}</text><text wx:if="{{recommendation.age}}" class="ui-rec__age">{{recommendation.age}}岁</text><text wx:if="{{recommendation.online}}" class="ui-rec__online">在线</text></view>
|
||||||
<text class="ui-rec__name">{{recommendation.displayName}}</text>
|
<view class="ui-rec__meta"><text wx:if="{{recommendation.regionName}}">{{recommendation.regionName}}</text><text wx:if="{{recommendation.heightCm}}"> · {{recommendation.heightCm}}cm</text><text wx:if="{{recommendation.educationCode}}"> · {{recommendation.educationCode}}</text></view>
|
||||||
<text class="ui-rec__age">{{recommendation.age}}岁</text>
|
<view wx:if="{{recommendation.occupationCode}}" class="ui-rec__meta">{{recommendation.occupationCode}}</view>
|
||||||
|
<view wx:if="{{recommendation.recommendationReasons && recommendation.recommendationReasons.length}}" class="ui-rec__reasons"><text wx:for="{{recommendation.recommendationReasons}}" wx:key="*this" class="ui-rec__reason">{{item}}</text></view>
|
||||||
</view>
|
</view>
|
||||||
<view class="ui-rec__meta">
|
|
||||||
<text wx:if="{{recommendation.heightCm}}">{{recommendation.heightCm}}cm · </text>
|
|
||||||
<text>{{recommendation.regionName}}</text>
|
|
||||||
<text wx:if="{{recommendation.educationCode}}"> · {{recommendation.educationCode}}</text>
|
|
||||||
</view>
|
|
||||||
<view wx:if="{{recommendation.occupationCode}}" class="ui-rec__meta">
|
|
||||||
{{recommendation.occupationCode}}
|
|
||||||
</view>
|
|
||||||
<view wx:if="{{recommendation.maritalStatus || recommendation.hasChildren}}" class="ui-rec__meta">
|
|
||||||
<text wx:if="{{recommendation.maritalStatus}}">{{recommendation.maritalStatus}}</text>
|
|
||||||
<text wx:if="{{recommendation.hasChildren}}"> · 有孩</text>
|
|
||||||
</view>
|
|
||||||
<view wx:if="{{recommendation.photoUrls}}" class="ui-rec__photo-count">
|
|
||||||
{{recommendation.photoUrls.length}} 张生活照
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view
|
|
||||||
wx:if="{{recommendation.recommendationLevel}}"
|
|
||||||
class="ui-rec__level ui-rec__level--{{recommendation.recommendationLevel}}"
|
|
||||||
>
|
|
||||||
{{levelTextMap[recommendation.recommendationLevel]}}
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view
|
|
||||||
wx:if="{{recommendation.recommendationReasons && recommendation.recommendationReasons.length}}"
|
|
||||||
class="ui-rec__reasons"
|
|
||||||
>
|
|
||||||
<view class="ui-rec__reasons-title">为什么推荐给你</view>
|
|
||||||
<view
|
|
||||||
wx:for="{{recommendation.recommendationReasons}}"
|
|
||||||
wx:key="*this"
|
|
||||||
class="ui-rec__reason"
|
|
||||||
>✓ {{item}}</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view wx:if="{{recommendation.intro}}" class="ui-rec__intro">
|
|
||||||
{{recommendation.intro}}
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view wx:if="{{showActions}}" class="ui-rec__actions">
|
<view wx:if="{{showActions}}" class="ui-rec__actions">
|
||||||
<ui-button
|
<view class="compact-like" catchtap="onLike"><image src="/assets/brand/logo-mark.png" mode="aspectFit" /></view>
|
||||||
variant="ghost"
|
<text class="compact-pass" catchtap="onPass">暂不考虑</text>
|
||||||
size="md"
|
|
||||||
disabled="{{actionLoading}}"
|
|
||||||
class="ui-rec__btn-pass"
|
|
||||||
bindtap="onPass"
|
|
||||||
>不合适</ui-button>
|
|
||||||
<ui-button
|
|
||||||
variant="primary"
|
|
||||||
size="md"
|
|
||||||
loading="{{actionLoading}}"
|
|
||||||
class="ui-rec__btn-like"
|
|
||||||
bindtap="onLike"
|
|
||||||
>喜欢</ui-button>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="ui-rec__more">
|
|
||||||
<text class="ui-rec__more-text" catchtap="onBlock">拉黑该用户</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -1,113 +1 @@
|
|||||||
.ui-rec {
|
.ui-rec{display:flex;align-items:center;gap:16rpx;min-height:132rpx;padding:14rpx 16rpx;background:#fff;border-bottom:1rpx solid #F0F1F6}.ui-rec:last-child{border-bottom:0}.ui-rec__info{flex:1;min-width:0}.ui-rec__name-row{display:flex;align-items:center;gap:10rpx}.ui-rec__name{font-size:26rpx;font-weight:700;color:#222746}.ui-rec__age{font-size:21rpx;color:#545B76}.ui-rec__online{margin-left:auto;font-size:18rpx;color:#39A987}.ui-rec__online::before{content:'·';margin-right:4rpx}.ui-rec__meta{margin-top:5rpx;font-size:20rpx;color:#767C94;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ui-rec__reasons{display:flex;gap:7rpx;margin-top:8rpx;overflow:hidden}.ui-rec__reason{flex:none;padding:4rpx 9rpx;border-radius:12rpx;background:#F3EEFF;color:#7860AE;font-size:17rpx;white-space:nowrap}.ui-rec__actions{width:82rpx;display:flex;flex-direction:column;align-items:center;gap:7rpx}.compact-like{width:64rpx;height:64rpx;display:flex;align-items:center;justify-content:center;border-radius:32rpx;background:#FFF0F5;box-shadow:0 7rpx 18rpx rgba(255,79,145,.18)}.compact-like image{width:44rpx;height:44rpx}.compact-pass{font-size:17rpx;color:#A0A4B4;white-space:nowrap}
|
||||||
background: var(--color-bg-card);
|
|
||||||
border-radius: var(--radius-lg);
|
|
||||||
padding: var(--spacing-4);
|
|
||||||
margin-bottom: var(--spacing-3);
|
|
||||||
box-shadow: var(--shadow-card);
|
|
||||||
}
|
|
||||||
.ui-rec__header {
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.ui-rec__info {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
margin-left: var(--spacing-3);
|
|
||||||
}
|
|
||||||
.ui-rec__name-row {
|
|
||||||
display: flex;
|
|
||||||
align-items: baseline;
|
|
||||||
margin-bottom: var(--spacing-1);
|
|
||||||
}
|
|
||||||
.ui-rec__name {
|
|
||||||
font-size: var(--font-size-2xl);
|
|
||||||
font-weight: var(--font-weight-semibold);
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
margin-right: var(--spacing-2);
|
|
||||||
}
|
|
||||||
.ui-rec__age {
|
|
||||||
font-size: var(--font-size-md);
|
|
||||||
color: var(--color-text-tertiary);
|
|
||||||
}
|
|
||||||
.ui-rec__meta {
|
|
||||||
font-size: var(--font-size-sm);
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
line-height: var(--line-height-normal);
|
|
||||||
margin-top: 4rpx;
|
|
||||||
}
|
|
||||||
.ui-rec__photo-count {
|
|
||||||
margin-top: var(--spacing-2);
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
color: var(--color-primary);
|
|
||||||
}
|
|
||||||
.ui-rec__level {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
padding: 6rpx 14rpx;
|
|
||||||
border-radius: var(--radius-full);
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
font-weight: var(--font-weight-medium);
|
|
||||||
}
|
|
||||||
.ui-rec__level--high {
|
|
||||||
background: var(--color-success-light);
|
|
||||||
color: var(--color-success);
|
|
||||||
}
|
|
||||||
.ui-rec__level--medium {
|
|
||||||
background: var(--color-info-light);
|
|
||||||
color: var(--color-info);
|
|
||||||
}
|
|
||||||
.ui-rec__level--normal {
|
|
||||||
background: var(--color-warning-light);
|
|
||||||
color: var(--color-warning);
|
|
||||||
}
|
|
||||||
.ui-rec__reasons {
|
|
||||||
margin-top: var(--spacing-3);
|
|
||||||
padding: var(--spacing-3);
|
|
||||||
background: var(--color-primary-light);
|
|
||||||
border-radius: var(--radius-md);
|
|
||||||
}
|
|
||||||
.ui-rec__reasons-title {
|
|
||||||
font-size: var(--font-size-sm);
|
|
||||||
color: var(--color-primary);
|
|
||||||
font-weight: var(--font-weight-medium);
|
|
||||||
margin-bottom: var(--spacing-2);
|
|
||||||
}
|
|
||||||
.ui-rec__reason {
|
|
||||||
font-size: var(--font-size-sm);
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
line-height: var(--line-height-relaxed);
|
|
||||||
}
|
|
||||||
.ui-rec__intro {
|
|
||||||
margin-top: var(--spacing-3);
|
|
||||||
padding-top: var(--spacing-3);
|
|
||||||
border-top: 1rpx solid var(--color-divider);
|
|
||||||
font-size: var(--font-size-md);
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
line-height: var(--line-height-relaxed);
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 3;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.ui-rec__actions {
|
|
||||||
display: flex;
|
|
||||||
gap: var(--spacing-3);
|
|
||||||
margin-top: var(--spacing-4);
|
|
||||||
}
|
|
||||||
.ui-rec__btn-pass {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
.ui-rec__btn-like {
|
|
||||||
flex: 2;
|
|
||||||
}
|
|
||||||
.ui-rec__more {
|
|
||||||
margin-top: var(--spacing-3);
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.ui-rec__more .ui-rec__more-text {
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
color: var(--color-text-tertiary);
|
|
||||||
padding: var(--spacing-1) var(--spacing-2);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* 首页 - V1.1 新版(U18)
|
* 首页 - V1.1 新版(U18)
|
||||||
* 结构:品牌区 → 用户状态条 → Banner → 8入口 → 推荐 → 服务建议 → 活动 → 服务站 → 安全提醒
|
* 结构:品牌区 → 用户状态条 → Banner → 8入口 → 推荐 → 服务建议 → 活动 → 服务站 → 安全提醒
|
||||||
*/
|
*/
|
||||||
const { authStore, appStore } = require('../../stores')
|
const { authStore, appStore, matchStore } = require('../../stores')
|
||||||
const api = require('../../utils/api')
|
const api = require('../../utils/api')
|
||||||
|
|
||||||
const ENTRY_VISUALS = {
|
const ENTRY_VISUALS = {
|
||||||
@@ -129,7 +129,12 @@ Page({
|
|||||||
statusChecks: checks,
|
statusChecks: checks,
|
||||||
banners: banners || [],
|
banners: banners || [],
|
||||||
quickEntries: quickEntries?.length
|
quickEntries: quickEntries?.length
|
||||||
? quickEntries.map((entry) => ({ ...entry, ...ENTRY_VISUALS[entry.code] }))
|
? QUICK_ENTRIES.map((defaultEntry) => {
|
||||||
|
const serverEntry = quickEntries.find((entry) => entry.code === defaultEntry.code)
|
||||||
|
return serverEntry
|
||||||
|
? { ...defaultEntry, ...serverEntry, ...ENTRY_VISUALS[defaultEntry.code] }
|
||||||
|
: { ...defaultEntry, enabled: false, disabledReason: '服务暂未开放' }
|
||||||
|
})
|
||||||
: QUICK_ENTRIES,
|
: QUICK_ENTRIES,
|
||||||
recommendations: recommendations || [],
|
recommendations: recommendations || [],
|
||||||
recState: (recommendations && recommendations.length > 0) ? 'loaded' : 'empty',
|
recState: (recommendations && recommendations.length > 0) ? 'loaded' : 'empty',
|
||||||
@@ -198,18 +203,41 @@ Page({
|
|||||||
if (userId) wx.navigateTo({ url: `/pages/profile-detail/profile-detail?id=${userId}` })
|
if (userId) wx.navigateTo({ url: `/pages/profile-detail/profile-detail?id=${userId}` })
|
||||||
},
|
},
|
||||||
|
|
||||||
onLike(e) {
|
async onLike(e) {
|
||||||
const userId = e.detail?.userId
|
const userId = e.detail?.userId
|
||||||
if (!userId) return
|
if (!userId || this.data.actionLoadingUserId) return
|
||||||
this.setData({ actionLoadingUserId: userId })
|
this.setData({ actionLoadingUserId: userId })
|
||||||
setTimeout(() => this.setData({ actionLoadingUserId: '' }), 500)
|
try {
|
||||||
|
const result = await matchStore.like(userId)
|
||||||
|
this.setData({ recommendations: this.data.recommendations.filter((item) => item.userId !== userId) })
|
||||||
|
if (result?.mutualMatch) {
|
||||||
|
appStore.toastSuccess('双向喜欢!可以开始聊天了')
|
||||||
|
if (result.matchedConversationId) {
|
||||||
|
wx.navigateTo({ url: `/pages/chat/chat?id=${result.matchedConversationId}` })
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
appStore.toastSuccess('已表达喜欢')
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
appStore.toastError(err instanceof Error ? err.message : '操作失败')
|
||||||
|
} finally {
|
||||||
|
this.setData({ actionLoadingUserId: '' })
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onPass(e) {
|
async onPass(e) {
|
||||||
const userId = e.detail?.userId
|
const userId = e.detail?.userId
|
||||||
if (!userId) return
|
if (!userId || this.data.actionLoadingUserId) return
|
||||||
this.setData({ actionLoadingUserId: userId })
|
this.setData({ actionLoadingUserId: userId })
|
||||||
setTimeout(() => this.setData({ actionLoadingUserId: '' }), 500)
|
try {
|
||||||
|
await matchStore.pass(userId)
|
||||||
|
this.setData({ recommendations: this.data.recommendations.filter((item) => item.userId !== userId) })
|
||||||
|
appStore.toastSuccess('已略过')
|
||||||
|
} catch (err) {
|
||||||
|
appStore.toastError(err instanceof Error ? err.message : '操作失败')
|
||||||
|
} finally {
|
||||||
|
this.setData({ actionLoadingUserId: '' })
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onEmptyAction(e) {
|
onEmptyAction(e) {
|
||||||
|
|||||||
@@ -1,58 +1,91 @@
|
|||||||
<view class="page app-page reference-page">
|
<view class="page app-page reference-page">
|
||||||
<!-- 品牌区 -->
|
<view class="night-shell">
|
||||||
<view class="brand-bar">
|
<view class="brand-bar">
|
||||||
<view><text class="brand-name">善缘丹阳</text><text class="brand-slogan">真实相识 · 公益牵线</text></view>
|
<view class="brand-lockup">
|
||||||
<view class="brand-mark">公益服务</view>
|
<image class="brand-logo" src="/assets/brand/logo-mark.png" mode="aspectFit" />
|
||||||
<view class="bell-btn" bindtap="onMessages"><text>消息</text><text wx:if="{{unreadCount}}" class="badge">{{unreadCount}}</text></view>
|
<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>
|
||||||
<view wx:if="{{previewMode}}" class="preview-note">界面预览数据</view>
|
|
||||||
|
|
||||||
<!-- 用户状态条 -->
|
|
||||||
<view class="status-strip">
|
<view class="status-strip">
|
||||||
<view wx:if="{{isOnboarding}}" class="status-main"><text class="status-title">完善资料,开启安心相遇</text><text class="status-desc">{{onboardingMessage}}</text><view class="status-action" bindtap="onEmptyAction" data-event="{{onboardingActions[0].event}}">{{onboardingActions[0].text}}</view></view>
|
<view wx:if="{{isOnboarding}}" class="status-main">
|
||||||
<view wx:elif="{{isPaused}}" class="status-main"><text class="status-title">已暂停新的对象推荐</text><view class="status-action" bindtap="onResume">恢复寻找</view></view>
|
<view class="status-copy">
|
||||||
<view wx:elif="{{isSuccessful}}" class="status-main"><text class="status-title">祝福你们正在认真了解彼此</text><text class="status-desc">愿真诚与尊重陪伴你们继续前行</text></view>
|
<text class="status-title">完善资料,开启安心相遇</text>
|
||||||
<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>
|
<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>
|
||||||
|
|
||||||
<!-- Banner 轮播 -->
|
<view class="banner-section">
|
||||||
<view class="banner-section"><swiper class="banner-swiper" indicator-dots autoplay circular interval="4500" indicator-active-color="#E96B6B"><swiper-item wx:for="{{banners}}" wx:key="id"><view class="banner-card" bindtap="onBannerTap" data-item="{{item}}"><image wx:if="{{item.imageFileId}}" src="{{item.imageFileId}}" mode="aspectFill" class="banner-img"/><view class="banner-art"><view class="heart-line">♡</view></view><view class="banner-copy"><text class="banner-title">{{item.title}}</text><text class="banner-subtitle">{{item.subtitle}}</text><view class="banner-btn">{{item.buttonText || '查看详情'}} <text>›</text></view></view></view></swiper-item></swiper></view>
|
<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>
|
||||||
|
|
||||||
<!-- 8个核心入口 -->
|
<view class="entries-card">
|
||||||
<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}}">{{item.icon}}</view><text class="entry-label">{{item.label}}</text></view></view></view>
|
<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="{{loadError}}" class="section"><ui-error-state title="暂时无法加载首页" description="请检查网络后重试" bind:retry="onRetry"/></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>
|
<block wx:else>
|
||||||
<!-- 今日推荐 -->
|
<view class="section recommendation-section">
|
||||||
<view class="section">
|
<ui-section-header title="今日推荐" subtitle="根据双方条件,为你认真筛选" action="查看更多" bind:action="onSeeMore" />
|
||||||
<ui-section-header title="今日推荐" subtitle="根据双方条件,为你认真筛选" action="查看更多" bind:action="onSeeMore"/>
|
<ui-loading wx:if="{{loading}}" mode="skeleton" rows="2" />
|
||||||
<block wx:if="{{loading}}">
|
<view wx:elif="{{recommendations.length}}" class="recommend-list">
|
||||||
<ui-loading mode="skeleton" rows="2"/>
|
<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" />
|
||||||
</block>
|
</view>
|
||||||
<block wx:elif="{{recommendations.length}}">
|
<view wx:else class="recommend-empty">
|
||||||
<view wx:for="{{recommendations}}" wx:key="userId" class="rec-wrap">
|
<image class="empty-logo" src="/assets/brand/logo-mark.png" mode="aspectFit" />
|
||||||
<ui-recommend-card recommendation="{{item}}" action-loading="{{actionLoadingUserId === item.userId}}" bind:view="onViewDetail" bind:like="onLike" bind:pass="onPass"/>
|
<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>
|
||||||
</block>
|
|
||||||
<block wx:else>
|
|
||||||
<ui-empty illustration="heart" title="暂时没有完全符合双方条件的人" description="可以调整择偶条件,或申请公益红娘协助推荐" actions="{{emptyActions}}" bind:action="onEmptyAction"/>
|
|
||||||
</block>
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 善缘公益服务 -->
|
<view class="section"><ui-section-header title="善缘公益服务" subtitle="需要时,我们在这里陪伴你" /><view wx:if="{{serviceRecommendations.length}}"><view wx:for="{{serviceRecommendations}}" wx:key="type" class="service-card" bindtap="onServiceTap" data-type="{{item.type}}"><image class="service-cover" src="/assets/covers/counseling-default.jpg" mode="aspectFill" /><view class="service-copy"><text class="service-title">{{item.title}}</text><text class="service-desc">{{item.description}}</text><text class="text-link">{{item.ctaText}}</text></view></view></view><view wx:else class="section-empty">暂无待推荐的公益服务</view></view>
|
||||||
<view class="section"><ui-section-header title="善缘公益服务" subtitle="需要时,我们在这里陪伴你"/><view wx:for="{{serviceRecommendations}}" wx:key="type" class="service-card" bindtap="onServiceTap" data-type="{{item.type}}"><view><text class="service-title">{{item.title}}</text><text class="service-desc">{{item.description}}</text></view><view class="text-link">{{item.ctaText}} ›</view></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="近期公益活动" action="全部活动" bind:action="onSeeAllActivities"/><scroll-view scroll-x class="activity-scroll"><view wx:for="{{activities}}" wx:key="id" class="activity-card" bindtap="onActivityTap" data-id="{{item.id}}"><view class="activity-cover"><text class="activity-tag">{{item.typeLabel || '公益活动'}}</text><text class="activity-symbol">相遇</text></view><view class="activity-info"><text class="activity-title">{{item.title}}</text><text class="activity-meta">9月20日 14:00 · {{item.locationName}}</text></view></view></scroll-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="就在身边的公益婚恋服务阵地"/><view class="station-card" bindtap="onStationTap"><view class="station-pin">站</view><view class="station-info"><text class="station-name">{{serviceLocation.name}}</text><text class="station-desc">{{serviceLocation.shortName}}</text><view><text wx:for="{{serviceLocation.services}}" wx:key="*this" class="mini-tag">{{item}}</text></view></view><text class="arrow">›</text></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>
|
||||||
<view class="section"><ui-section-header title="婚恋课堂" subtitle="学会认识自己,也学会理解关系" action="更多内容" bind:action="onEntryTap" data-entry="{{quickEntries[4]}}"/><view class="article-list"><view wx:for="{{articles}}" wx:key="id" class="article-row" bindtap="onArticleTap" data-id="{{item.id}}"><view class="article-icon">读</view><view class="article-info"><text class="article-title">{{item.title}}</text><text class="article-meta">{{item.categoryName}} · {{item.readTime}}</text></view><text class="arrow">›</text></view></view></view>
|
|
||||||
|
|
||||||
<!-- 安全提醒 -->
|
<view class="section safety-card" bindtap="onSafetyTap"><image class="safety-cover" src="/assets/covers/anti-fraud-default.jpg" mode="aspectFill" /><view class="safety-info"><text class="safety-title">善缘安全提醒</text><text class="safety-body">{{safetyNotice.text}}</text><text class="safety-link">{{safetyNotice.ctaText}}</text></view></view>
|
||||||
<view class="section safety-card" bindtap="onSafetyTap"><view class="shield">安</view><view class="safety-info"><text class="safety-title">善缘提醒</text><text class="safety-body">{{safetyNotice.text}}</text><text class="safety-link">{{safetyNotice.ctaText}} ›</text></view></view>
|
|
||||||
</block>
|
</block>
|
||||||
<view class="safe-area-bottom"></view>
|
<view class="safe-area-bottom"></view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
.page{min-height:100vh;background:var(--color-bg-page);padding-bottom:var(--spacing-8)}
|
.page{min-height:100vh;background:#F4F5FA;padding-bottom:40rpx}.night-shell{padding:0 24rpx 28rpx;background:linear-gradient(160deg,var(--mini-night-start),var(--mini-night-end));border-radius:0 0 42rpx 42rpx;box-shadow:var(--mini-shadow)}
|
||||||
.brand-bar{height:104rpx;padding:12rpx var(--spacing-page-x);display:flex;align-items:center;gap:16rpx;background:var(--color-bg-card);position:sticky;top:0;z-index:var(--z-sticky);border-bottom:1rpx solid var(--color-divider)}
|
.brand-bar{height:112rpx;padding-top:env(safe-area-inset-top);display:flex;align-items:center;justify-content:space-between;color:var(--mini-text-on-night)}.brand-lockup{display:flex;align-items:center}.brand-logo{width:66rpx;height:66rpx}.brand-copy{display:flex;flex-direction:column;margin-left:12rpx}.brand-name{font-size:34rpx;font-weight:700;letter-spacing:2rpx}.brand-slogan{font-size:18rpx;letter-spacing:4rpx;color:var(--mini-text-on-night-muted)}.brand-actions{position:relative;min-width:76rpx;height:72rpx;display:flex;align-items:center;justify-content:center}.message-label{font-size:23rpx}.badge{position:absolute;right:0;top:4rpx;min-width:28rpx;height:28rpx;padding:0 4rpx;line-height:28rpx;text-align:center;font-size:18rpx;color:#fff;background:var(--mini-accent-pink);border-radius:20rpx}
|
||||||
.brand-bar>view:first-child{display:flex;flex-direction:column;flex:1}.brand-name{font-size:36rpx;font-weight:700;color:var(--color-primary);line-height:1.25}.brand-slogan{font-size:22rpx;color:var(--color-text-tertiary);margin-top:4rpx}.brand-mark{font-size:20rpx;color:var(--color-success);background:var(--color-success-light);padding:6rpx 12rpx;border-radius:var(--radius-full)}
|
.status-strip{margin:4rpx 0 16rpx;padding:18rpx 20rpx;border:1rpx solid rgba(255,255,255,.16);background:rgba(255,255,255,.09);border-radius:20rpx;color:#fff}.status-main{display:flex;align-items:center;gap:16rpx}.status-copy{flex:1;min-width:0;display:flex;flex-direction:column}.status-title{font-size:25rpx;font-weight:650}.status-desc{margin-top:5rpx;font-size:20rpx;color:var(--mini-text-on-night-muted);line-height:1.4}.status-action{flex:none;min-width:108rpx;min-height:56rpx;padding:0 18rpx;display:flex;align-items:center;justify-content:center;border-radius:28rpx;background:linear-gradient(135deg,var(--mini-accent-coral),var(--mini-accent-pink));font-size:22rpx;font-weight:650}.status-checks{display:flex;gap:10rpx;overflow:hidden}.status-check{padding:8rpx 12rpx;border-radius:20rpx;background:rgba(255,255,255,.08);font-size:19rpx;color:var(--mini-text-on-night-muted);white-space:nowrap}.status-check.done{background:rgba(90,226,184,.16);color:#A6F5D7}
|
||||||
.bell-btn{position:relative;min-width:88rpx;height:88rpx;display:flex;align-items:center;justify-content:center;font-size:24rpx;color:var(--color-text-secondary)}.badge{position:absolute;right:0;top:8rpx;min-width:28rpx;height:28rpx;padding:0 4rpx;line-height:28rpx;text-align:center;font-size:18rpx;color:var(--color-text-inverse);background:var(--color-primary);border-radius:var(--radius-full)}
|
.banner-section{width:100%}.banner-swiper,.banner-card{height:272rpx;border-radius:26rpx;overflow:hidden}.banner-card{position:relative}.banner-img{width:100%;height:100%;display:block}.banner-overlay{position:absolute;inset:0;background:linear-gradient(90deg,rgba(25,22,86,.78) 0%,rgba(43,22,101,.25) 58%,rgba(255,79,145,.08) 100%)}.banner-copy{position:absolute;left:26rpx;bottom:26rpx;width:68%;display:flex;flex-direction:column;color:#fff}.banner-kicker{font-size:18rpx;letter-spacing:3rpx;color:rgba(255,255,255,.78)}.banner-title{margin-top:9rpx;font-size:35rpx;line-height:1.2;font-weight:750;text-shadow:0 3rpx 10rpx rgba(0,0,0,.2)}.banner-subtitle{margin-top:8rpx;font-size:22rpx;color:rgba(255,255,255,.84)}
|
||||||
.preview-note{text-align:center;background:var(--color-warning-light);color:var(--color-warning);font-size:20rpx;padding:6rpx}
|
.entries-card{position:relative;z-index:2;margin:-14rpx 24rpx 0;padding:22rpx 10rpx 18rpx;background:var(--mini-card-bg);border-radius:30rpx;box-shadow:var(--mini-shadow)}.entries-grid{display:grid;grid-template-columns:repeat(4,1fr);row-gap:18rpx}.entry-item{min-height:104rpx;display:flex;flex-direction:column;align-items:center;justify-content:center}.entry-item.disabled{opacity:.4}.entry-icon{width:66rpx;height:66rpx;display:flex;align-items:center;justify-content:center;border-radius:20rpx;overflow:hidden}.entry-icon-image{width:45rpx;height:45rpx}.entry-label{margin-top:8rpx;font-size:21rpx;color:#283056;font-weight:550}.tone-rose{background:#FFF0F5}.tone-purple{background:#F0EAFE}.tone-blue{background:#EAF3FF}.tone-pink{background:#FFF0F7}.tone-amber{background:#FFF3E5}.tone-indigo{background:#ECEEFF}.tone-red{background:#FFEDEF}.tone-green{background:#EAF8F2}
|
||||||
.status-strip{margin:16rpx var(--spacing-page-x) 0;padding:20rpx 24rpx;background:var(--color-bg-card);border:1rpx solid var(--color-border);border-radius:var(--radius-md)}.status-main{display:flex;align-items:center;gap:12rpx;flex-wrap:wrap}.status-title{font-size:27rpx;font-weight:600}.status-desc{font-size:23rpx;color:var(--color-text-tertiary);flex:1}.status-action{min-height:64rpx;padding:0 22rpx;display:flex;align-items:center;color:var(--color-primary);font-size:24rpx;font-weight:600}.status-checks{display:flex;justify-content:space-between;gap:12rpx}.status-check{font-size:23rpx;color:var(--color-warning)}.status-check.done{color:var(--color-success)}
|
.preview-note{margin:16rpx 24rpx 0;text-align:center;color:#8B63BC;font-size:20rpx}.section{margin-top:34rpx;padding:0 24rpx}.recommendation-section{margin-top:30rpx}.recommend-list{margin-top:16rpx;border-radius:26rpx;overflow:hidden;box-shadow:0 8rpx 28rpx rgba(35,35,95,.07)}.recommend-empty{margin-top:16rpx;padding:22rpx;display:flex;align-items:center;gap:18rpx;background:#fff;border-radius:26rpx;box-shadow:0 8rpx 28rpx rgba(35,35,95,.07)}.empty-logo{width:76rpx;height:76rpx;flex:none}.empty-copy{flex:1;min-width:0;display:flex;flex-direction:column}.empty-title{font-size:25rpx;font-weight:650;color:#222746}.empty-desc{margin-top:6rpx;font-size:20rpx;line-height:1.4;color:#7A7F98}.empty-actions{display:flex;flex-direction:column;gap:8rpx}.empty-btn{min-width:112rpx;height:48rpx;padding:0 12rpx;display:flex;align-items:center;justify-content:center;border-radius:24rpx;font-size:20rpx}.empty-btn.secondary{color:#7C60BC;background:#F1EEFB}.empty-btn.primary{color:#fff;background:linear-gradient(135deg,var(--mini-accent-coral),var(--mini-accent-pink))}
|
||||||
.banner-section{padding:16rpx var(--spacing-page-x) 0}.banner-swiper{height:292rpx;border-radius:var(--radius-lg);overflow:hidden}.banner-card{height:100%;position:relative;background:linear-gradient(135deg,var(--color-primary-lighter),#FBE8DE)}.banner-img{width:100%;height:100%}.banner-art{position:absolute;right:-24rpx;top:-28rpx;width:260rpx;height:260rpx;border-radius:50%;background:rgba(255,255,255,.55);display:flex;align-items:center;justify-content:center}.heart-line{font-size:128rpx;color:rgba(233,107,107,.34)}.banner-copy{position:absolute;left:28rpx;top:36rpx;width:72%}.banner-title{display:block;font-size:34rpx;font-weight:700;color:#6F3A35;line-height:1.35}.banner-subtitle{display:block;margin-top:12rpx;font-size:24rpx;color:#8B5E56}.banner-btn{display:inline-flex;align-items:center;gap:8rpx;margin-top:24rpx;min-height:64rpx;padding:0 24rpx;border-radius:var(--radius-full);background:var(--color-primary);color:var(--color-text-inverse);font-size:24rpx}
|
.service-card{display:flex;align-items:stretch;margin-top:16rpx;background:#fff;border-radius:26rpx;overflow:hidden;box-shadow:0 8rpx 28rpx rgba(35,35,95,.07)}.service-cover{width:210rpx;min-height:156rpx}.service-copy{flex:1;padding:20rpx;display:flex;flex-direction:column}.service-title{font-size:25rpx;font-weight:650;color:#222746}.service-desc{margin-top:7rpx;font-size:21rpx;color:#757B91;line-height:1.45}.text-link{margin-top:auto;padding-top:10rpx;font-size:21rpx;color:var(--mini-accent-pink);font-weight:650}
|
||||||
.entries-card{margin:20rpx var(--spacing-page-x) 0;padding:24rpx 12rpx;background:var(--color-bg-card);border-radius:var(--radius-lg);box-shadow:var(--shadow-card)}.entries-grid{display:grid;grid-template-columns:repeat(4,1fr);row-gap:24rpx}.entry-item{min-height:116rpx;display:flex;flex-direction:column;align-items:center;justify-content:center}.entry-item.disabled{opacity:.45}.entry-icon{width:76rpx;height:76rpx;display:flex;align-items:center;justify-content:center;border-radius:24rpx;font-size:28rpx;font-weight:700}.entry-label{margin-top:9rpx;font-size:23rpx;color:var(--color-text-primary)}.tone-rose{background:#FFF0EF;color:#D85D62}.tone-amber{background:#FFF7E6;color:#B77B19}.tone-green{background:#ECF8F2;color:#2E8A62}.tone-blue{background:#EEF5FF;color:#4A72B8}.tone-purple{background:#F5EFFB;color:#8865A7}.tone-orange{background:#FFF2E8;color:#B9723B}.tone-indigo{background:#EEF0FB;color:#5F6FAE}.tone-teal{background:#EAF7F5;color:#31867C}
|
.activity-scroll{white-space:nowrap;margin-top:16rpx}.activity-card{display:inline-flex;width:550rpx;margin-right:18rpx;background:#fff;border-radius:24rpx;overflow:hidden;box-shadow:0 8rpx 28rpx rgba(35,35,95,.07);white-space:normal}.activity-cover{width:210rpx;height:168rpx}.activity-info{flex:1;padding:18rpx;display:flex;flex-direction:column}.activity-tag{align-self:flex-start;padding:5rpx 12rpx;border-radius:18rpx;background:#FFF0F5;color:var(--mini-accent-pink);font-size:18rpx}.activity-title{margin-top:10rpx;font-size:25rpx;font-weight:650;color:#222746;line-height:1.35}.activity-meta{margin-top:auto;font-size:20rpx;color:#81869B}
|
||||||
.section{margin-top:var(--spacing-section);padding:0 var(--spacing-page-x)}.rec-wrap{margin-top:20rpx}.service-card{display:flex;align-items:center;gap:20rpx;padding:28rpx;background:linear-gradient(135deg,var(--color-primary-lighter),#FFF9F0);border:1rpx solid #F8E3DD;border-radius:var(--radius-lg)}.service-card>view:first-child{flex:1}.service-title{display:block;font-size:30rpx;font-weight:650}.service-desc{display:block;margin-top:10rpx;font-size:24rpx;color:var(--color-text-secondary);line-height:1.55}.text-link{font-size:23rpx;font-weight:600;color:var(--color-primary);white-space:nowrap}
|
.station-card,.article-row,.safety-card{display:flex;align-items:center;background:#fff;border-radius:26rpx;overflow:hidden;box-shadow:0 8rpx 28rpx rgba(35,35,95,.07)}.station-cover{width:190rpx;height:170rpx}.station-info{flex:1;min-width:0;padding:18rpx}.station-name{display:block;font-size:26rpx;font-weight:650;color:#222746}.station-desc{display:block;margin:7rpx 0 12rpx;font-size:20rpx;color:#7A7F98}.mini-tag{display:inline-block;margin:4rpx 7rpx 0 0;padding:4rpx 9rpx;border-radius:14rpx;background:#F0EEFB;color:#6857A2;font-size:17rpx}.arrow-icon{width:28rpx;height:28rpx;margin:16rpx;flex:none}.article-list{margin-top:16rpx;display:flex;flex-direction:column;gap:12rpx}.article-row{min-height:112rpx}.article-cover{width:146rpx;height:112rpx}.article-info,.safety-info{flex:1;min-width:0;padding:16rpx}.article-title{display:block;font-size:24rpx;font-weight:600;color:#222746;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.article-meta{display:block;margin-top:6rpx;font-size:19rpx;color:#85899C}.section-empty{margin-top:16rpx;padding:30rpx 24rpx;text-align:center;color:#8A90A6;font-size:22rpx;background:#fff;border-radius:24rpx;box-shadow:0 8rpx 28rpx rgba(35,35,95,.05)}.safety-card{padding:0}.safety-cover{width:180rpx;align-self:stretch}.safety-title{display:block;font-size:25rpx;font-weight:650;color:#222746}.safety-body{display:block;margin-top:7rpx;font-size:20rpx;line-height:1.45;color:#74798E}.safety-link{display:block;margin-top:9rpx;font-size:20rpx;color:var(--mini-accent-pink);font-weight:650}
|
||||||
.activity-scroll{white-space:nowrap;margin-top:18rpx;width:100%}.activity-card{display:inline-block;width:560rpx;margin-right:20rpx;background:var(--color-bg-card);border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow-card);white-space:normal}.activity-cover{height:210rpx;padding:18rpx;background:linear-gradient(135deg,#F3D7CA,#F8ECE4);position:relative}.activity-tag{font-size:21rpx;color:#A45D50;background:rgba(255,255,255,.8);padding:7rpx 14rpx;border-radius:var(--radius-full)}.activity-symbol{position:absolute;right:28rpx;bottom:18rpx;font-size:52rpx;color:rgba(164,93,80,.32);font-weight:700}.activity-info{padding:22rpx}.activity-title{display:block;font-size:28rpx;font-weight:600}.activity-meta{display:block;margin-top:10rpx;font-size:23rpx;color:var(--color-text-tertiary)}
|
@media (max-width:340px){.entry-label{font-size:19rpx}.entry-icon{width:60rpx;height:60rpx}.banner-title{font-size:31rpx}.status-checks{overflow-x:auto}.empty-actions{display:none}}
|
||||||
.station-card{display:flex;align-items:center;gap:20rpx;padding:28rpx;background:var(--color-bg-card);border:1rpx solid var(--color-border);border-radius:var(--radius-lg)}.station-pin,.shield,.article-icon{width:72rpx;height:72rpx;flex:none;display:flex;align-items:center;justify-content:center;border-radius:22rpx;background:var(--color-success-light);color:var(--color-success);font-size:27rpx;font-weight:700}.station-info,.article-info,.safety-info{flex:1;min-width:0}.station-name{display:block;font-size:29rpx;font-weight:650}.station-desc{display:block;margin:7rpx 0 12rpx;font-size:23rpx;color:var(--color-text-tertiary)}.mini-tag{font-size:20rpx;color:var(--color-text-secondary);margin-right:10rpx;padding:5rpx 10rpx;background:var(--color-bg-page);border-radius:var(--radius-full)}.arrow{font-size:40rpx;color:var(--color-text-disabled)}
|
|
||||||
.article-list{margin-top:18rpx;background:var(--color-bg-card);border-radius:var(--radius-lg);overflow:hidden}.article-row{min-height:124rpx;padding:18rpx 24rpx;display:flex;align-items:center;gap:18rpx;border-bottom:1rpx solid var(--color-divider)}.article-row:last-child{border-bottom:0}.article-icon{background:#F5EFFB;color:#8865A7}.article-title{display:block;font-size:27rpx;font-weight:550;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.article-meta{display:block;margin-top:8rpx;font-size:22rpx;color:var(--color-text-tertiary)}
|
|
||||||
.safety-card{display:flex;gap:20rpx;margin-left:var(--spacing-page-x);margin-right:var(--spacing-page-x);padding:28rpx;background:#F3F7FC;border-radius:var(--radius-lg)}.shield{background:#E7EEF9;color:var(--color-info)}.safety-title{display:block;font-size:28rpx;font-weight:650}.safety-body{display:block;margin-top:8rpx;font-size:23rpx;color:var(--color-text-secondary);line-height:1.6}.safety-link{display:block;margin-top:12rpx;font-size:23rpx;color:var(--color-info);font-weight:600}
|
|
||||||
@media (max-width:340px){.brand-mark{display:none}.entry-label{font-size:21rpx}.entry-icon{width:68rpx;height:68rpx}.banner-title{font-size:31rpx}.status-checks{flex-wrap:wrap;justify-content:flex-start}}
|
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import assert from 'node:assert/strict'
|
||||||
|
import fs from 'node:fs'
|
||||||
|
|
||||||
|
const read = (path) => fs.readFileSync(path, 'utf8')
|
||||||
|
const home = read('backend/src/main/java/com/danyang/match/platform/home/service/HomeApplicationService.java')
|
||||||
|
const miniapp = read('miniapp/pages/index/index.ts')
|
||||||
|
const wxml = read('miniapp/pages/index/index.wxml')
|
||||||
|
const project = JSON.parse(read('project.config.json'))
|
||||||
|
|
||||||
|
const labels = ['找对象', '公益红娘', '公益活动', '婚恋咨询', '婚恋课堂', '婚前辅导', '婚恋反诈', '善缘服务站']
|
||||||
|
let previous = -1
|
||||||
|
for (const label of labels) {
|
||||||
|
const position = home.indexOf(`"${label}"`)
|
||||||
|
assert.ok(position > previous, `首页入口顺序错误: ${label}`)
|
||||||
|
previous = position
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.match(home, /userIdentityMapper\.findByUserId/, '首页实名认证状态必须来自数据库')
|
||||||
|
assert.match(home, /recommendationEngineService\.getDailyRecommendations/, '首页推荐必须来自正式推荐引擎')
|
||||||
|
assert.match(home, /contentArticleMapper\.findPublishedAll/, '首页课堂内容必须来自内容模块')
|
||||||
|
assert.match(home, /serviceLocationMapper\.selectOne/, '首页服务站必须来自服务站模块')
|
||||||
|
assert.match(home, /setDisabledReason/, '不可用入口必须返回服务端原因')
|
||||||
|
assert.match(home, /isIdentityVerified/, 'Capability 必须校验真实实名状态')
|
||||||
|
assert.match(home, /ACCOUNT_STATUS_NORMAL/, 'Capability 必须拒绝非正常账户')
|
||||||
|
assert.match(home, /\/pages\/counseling-intro\/counseling-intro/, '咨询服务建议必须跳转真实页面')
|
||||||
|
assert.match(home, /\/pages\/premarital-intro\/premarital-intro/, '婚前辅导建议必须跳转真实页面')
|
||||||
|
assert.doesNotMatch(home, /"pages\//, '服务端返回的小程序路由必须以斜杠开头')
|
||||||
|
assert.doesNotMatch(home, /setVerified\(true\)/, '禁止硬编码实名通过')
|
||||||
|
assert.doesNotMatch(home, /card\.setId\("default"\)/, '禁止硬编码服务站')
|
||||||
|
|
||||||
|
assert.deepEqual(project.setting.useCompilerPlugins, ['typescript'])
|
||||||
|
assert.ok(fs.existsSync('miniapp/pages/index/index.ts'))
|
||||||
|
assert.ok(!fs.existsSync('miniapp/pages/index/index.js'), '首页只能保留 TypeScript 运行源')
|
||||||
|
assert.ok(fs.existsSync('miniapp/pages/discover/discover.ts'))
|
||||||
|
assert.ok(!fs.existsSync('miniapp/pages/discover/discover.js'), '找对象页只能保留 TypeScript 运行源')
|
||||||
|
assert.match(miniapp, /disabledReason/, '小程序必须显示服务端 Disabled 原因')
|
||||||
|
assert.match(miniapp, /loadError: true/, '首页必须有网络错误状态')
|
||||||
|
assert.match(miniapp, /matchStore\.like\(userId\)/, '首页喜欢操作必须调用正式关系服务')
|
||||||
|
assert.match(miniapp, /matchStore\.pass\(userId\)/, '首页略过操作必须调用正式关系服务')
|
||||||
|
assert.doesNotMatch(miniapp, /setTimeout\(/, '首页不得保留演示用延时反馈')
|
||||||
|
assert.match(miniapp, /QUICK_ENTRIES\.map/, '服务端入口必须按固定业务顺序合并')
|
||||||
|
assert.match(wxml, /home-hero-v2\.jpg/, '首页默认 Banner 必须使用参考图夜景主视觉')
|
||||||
|
assert.doesNotMatch(wxml, />›</, '首页不得继续使用字符箭头')
|
||||||
|
|
||||||
|
const sections = ['brand-bar', 'status-strip', 'banner-section', 'entries-card', '今日推荐', '善缘公益服务', '近期公益活动', '善缘服务站', '婚恋课堂', '安全提醒']
|
||||||
|
previous = -1
|
||||||
|
for (const section of sections) {
|
||||||
|
const position = wxml.indexOf(section)
|
||||||
|
assert.ok(position > previous, `首页区块顺序错误: ${section}`)
|
||||||
|
previous = position
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Phase 07 home contracts passed')
|
||||||
Reference in New Issue
Block a user