diff --git a/miniapp/components/recommend-card/index.wxml b/miniapp/components/recommend-card/index.wxml index 8fd9075..966610f 100644 --- a/miniapp/components/recommend-card/index.wxml +++ b/miniapp/components/recommend-card/index.wxml @@ -1,75 +1,13 @@ - - - - - - {{recommendation.displayName}} - {{recommendation.age}}岁 - - - {{recommendation.heightCm}}cm · - {{recommendation.regionName}} - · {{recommendation.educationCode}} - - - {{recommendation.occupationCode}} - - - {{recommendation.maritalStatus}} - · 有孩 - - - {{recommendation.photoUrls.length}} 张生活照 - - - - {{levelTextMap[recommendation.recommendationLevel]}} - + + + + {{recommendation.displayName || '善缘用户'}}{{recommendation.age}}岁在线 + {{recommendation.regionName}} · {{recommendation.heightCm}}cm · {{recommendation.educationCode}} + {{recommendation.occupationCode}} + {{item}} - - - 为什么推荐给你 - ✓ {{item}} - - - - {{recommendation.intro}} - - - 不合适 - 喜欢 - - - - 拉黑该用户 + + 暂不考虑 diff --git a/miniapp/components/recommend-card/index.wxss b/miniapp/components/recommend-card/index.wxss index a64a033..0d71b01 100644 --- a/miniapp/components/recommend-card/index.wxss +++ b/miniapp/components/recommend-card/index.wxss @@ -1,113 +1 @@ -.ui-rec { - 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); -} +.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} diff --git a/miniapp/pages/index/index.ts b/miniapp/pages/index/index.ts index 1e48055..bfded39 100644 --- a/miniapp/pages/index/index.ts +++ b/miniapp/pages/index/index.ts @@ -2,7 +2,7 @@ * 首页 - V1.1 新版(U18) * 结构:品牌区 → 用户状态条 → Banner → 8入口 → 推荐 → 服务建议 → 活动 → 服务站 → 安全提醒 */ -const { authStore, appStore } = require('../../stores') +const { authStore, appStore, matchStore } = require('../../stores') const api = require('../../utils/api') const ENTRY_VISUALS = { @@ -129,7 +129,12 @@ Page({ statusChecks: checks, banners: banners || [], 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, recommendations: recommendations || [], recState: (recommendations && recommendations.length > 0) ? 'loaded' : 'empty', @@ -198,18 +203,41 @@ Page({ if (userId) wx.navigateTo({ url: `/pages/profile-detail/profile-detail?id=${userId}` }) }, - onLike(e) { + async onLike(e) { const userId = e.detail?.userId - if (!userId) return + if (!userId || this.data.actionLoadingUserId) return 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 - if (!userId) return + if (!userId || this.data.actionLoadingUserId) return 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) { diff --git a/miniapp/pages/index/index.wxml b/miniapp/pages/index/index.wxml index 4077676..c474413 100644 --- a/miniapp/pages/index/index.wxml +++ b/miniapp/pages/index/index.wxml @@ -1,58 +1,91 @@ - - - 善缘丹阳真实相识 · 公益牵线 - 公益服务 - 消息{{unreadCount}} - - 界面预览数据 - - - - 完善资料,开启安心相遇{{onboardingMessage}}{{onboardingActions[0].text}} - 已暂停新的对象推荐恢复寻找 - 祝福你们正在认真了解彼此愿真诚与尊重陪伴你们继续前行 - {{item.done ? '✓' : '○'}} {{item.label}} - - - - - - - {{item.icon}} - - - - - - - - - - - - + + + + + + 善缘丹阳 + 公益婚恋服务平台 - - - - + + + 消息 + {{unreadCount}} + - - {{item.title}}{{item.description}}{{item.ctaText}} › + + + + 完善资料,开启安心相遇 + {{onboardingMessage}} + + {{onboardingActions[0].text}} + + + 已暂停新的对象推荐你的资料仍被安全保存 + 恢复寻找 + + + 祝福你们认真了解彼此愿真诚与尊重陪伴你们继续前行 + + + {{item.done ? '已完成' : '待完成'}} · {{item.label}} + + - - {{item.typeLabel || '公益活动'}}相遇{{item.title}}9月20日 14:00 · {{item.locationName}} + + - - 站{{serviceLocation.name}}{{serviceLocation.shortName}}{{item}}› + + + + + + + + - - 读› + 当前为界面预览数据 + + + + + + + + + + + 暂时没有完全符合双方条件的人我们坚持 Required 条件,不会为了数量降低筛选标准 + 调整条件公益红娘 + + - - 安善缘提醒{{safetyNotice.text}}{{safetyNotice.ctaText}} › + {{item.title}}{{item.description}}{{item.ctaText}}暂无待推荐的公益服务 + + 公益活动{{item.title}}{{item.locationName}}近期暂无可报名活动 + + {{serviceLocation.name}}{{serviceLocation.shortName || serviceLocation.address}}{{item}}查看线下公益服务阵地 + + 暂无新内容,稍后再来看看 + + 善缘安全提醒{{safetyNotice.text}}{{safetyNotice.ctaText}} diff --git a/miniapp/pages/index/index.wxss b/miniapp/pages/index/index.wxss index 5395860..725e76e 100644 --- a/miniapp/pages/index/index.wxss +++ b/miniapp/pages/index/index.wxss @@ -1,14 +1,10 @@ -.page{min-height:100vh;background:var(--color-bg-page);padding-bottom:var(--spacing-8)} -.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>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)} -.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)} -.preview-note{text-align:center;background:var(--color-warning-light);color:var(--color-warning);font-size:20rpx;padding:6rpx} -.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)} -.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} -.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} -.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} -.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)} -.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}} \ No newline at end of file +.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: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} +.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} +.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)} +.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} +.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))} +.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} +.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} +.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} +@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}} diff --git a/ui-tests/phase07-home-contracts.mjs b/ui-tests/phase07-home-contracts.mjs new file mode 100644 index 0000000..c68729c --- /dev/null +++ b/ui-tests/phase07-home-contracts.mjs @@ -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, />› previous, `首页区块顺序错误: ${section}`) + previous = position +} + +console.log('Phase 07 home contracts passed')