feat: redesign activity and profile tabs
This commit is contained in:
@@ -14,7 +14,7 @@ Component({
|
||||
methods: {
|
||||
onTap() {
|
||||
if (!this.data.activity) return;
|
||||
this.triggerEvent('tap', { activityId: this.data.activity.activityId });
|
||||
this.triggerEvent('tap', { activityId: this.data.activity.activityId || this.data.activity.id });
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,62 +1,19 @@
|
||||
<view class="ui-act {{compact ? 'ui-act--compact' : ''}}" bindtap="onTap">
|
||||
<view class="ui-act__cover">
|
||||
<image
|
||||
wx:if="{{activity.coverUrl}}"
|
||||
class="ui-act__cover-img"
|
||||
src="{{activity.coverUrl}}"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<view wx:else class="ui-act__cover-placeholder">
|
||||
<view class="ui-act__cover-icon"></view>
|
||||
</view>
|
||||
<view class="ui-act__fee-badge {{activity.feeType === 'paid' ? 'ui-act__fee-badge--paid' : 'ui-act__fee-badge--free'}}">
|
||||
{{activity.feeType === 'paid' ? '付费' : '公益免费'}}
|
||||
</view>
|
||||
<image class="ui-act__cover-img" src="{{activity.coverUrl || activity.coverImageUrl || '/assets/covers/activity-default.jpg'}}" mode="aspectFill" />
|
||||
<view class="ui-act__fee-badge">公益活动</view>
|
||||
</view>
|
||||
<view class="ui-act__body">
|
||||
<view class="ui-act__title">{{activity.title}}</view>
|
||||
<view class="ui-act__meta">
|
||||
<text class="ui-act__time">{{activity.startAtText || activity.startAt}}</text>
|
||||
<text wx:if="{{activity.location}}"> · {{activity.location}}</text>
|
||||
</view>
|
||||
<view wx:if="{{activity.organizer}}" class="ui-act__meta ui-act__organizer">
|
||||
主办:{{activity.organizer}}
|
||||
</view>
|
||||
<view wx:if="{{activity.suitableFor}}" class="ui-act__meta">
|
||||
适合:{{activity.suitableFor}}
|
||||
</view>
|
||||
<view wx:if="{{!compact}}" class="ui-act__intro">{{activity.intro}}</view>
|
||||
<view class="ui-act__meta"><text>{{activity.startAtText || activity.activityStartAt || activity.startAt}}</text></view>
|
||||
<view class="ui-act__meta"><text>{{activity.locationName || activity.location || activity.address}}</text></view>
|
||||
<view wx:if="{{activity.suitableFor}}" class="ui-act__meta">适合:{{activity.suitableFor}}</view>
|
||||
<view wx:if="{{!compact && (activity.intro || activity.description)}}" class="ui-act__intro">{{activity.intro || activity.description}}</view>
|
||||
<view class="ui-act__footer">
|
||||
<view class="ui-act__capacity">
|
||||
<text wx:if="{{activity.capacity}}">容量 {{activity.capacity}}</text>
|
||||
</view>
|
||||
<view wx:if="{{showStatusBadge}}">
|
||||
<ui-status-badge
|
||||
wx:if="{{activity.status === 'registration_open'}}"
|
||||
kind="success"
|
||||
label="报名中"
|
||||
/>
|
||||
<ui-status-badge
|
||||
wx:elif="{{activity.status === 'registration_closed'}}"
|
||||
kind="warning"
|
||||
label="报名截止"
|
||||
/>
|
||||
<ui-status-badge
|
||||
wx:elif="{{activity.status === 'ongoing'}}"
|
||||
kind="info"
|
||||
label="进行中"
|
||||
/>
|
||||
<ui-status-badge
|
||||
wx:elif="{{activity.status === 'ended'}}"
|
||||
kind="disabled"
|
||||
label="已结束"
|
||||
/>
|
||||
<ui-status-badge
|
||||
wx:elif="{{activity.status === 'cancelled'}}"
|
||||
kind="danger"
|
||||
label="已取消"
|
||||
/>
|
||||
<text wx:if="{{activity.capacity || activity.totalLimit}}">报名人数 {{activity.registeredCount !== undefined ? activity.registeredCount : ((activity.currentMaleCount || 0) + (activity.currentFemaleCount || 0))}}/{{activity.capacity || activity.totalLimit}}</text>
|
||||
</view>
|
||||
<view class="ui-act__status-action {{activity.status !== 'registration_open' ? 'disabled' : ''}}">{{activity.status === 'registration_open' ? '立即报名' : (activity.status === 'ongoing' ? '进行中' : '查看详情')}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -1,108 +1 @@
|
||||
.ui-act {
|
||||
background: var(--color-bg-card);
|
||||
border-radius: var(--radius-lg);
|
||||
overflow: hidden;
|
||||
box-shadow: var(--shadow-card);
|
||||
margin-bottom: var(--spacing-3);
|
||||
}
|
||||
.ui-act__cover {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 240rpx;
|
||||
background: var(--color-bg-disabled);
|
||||
}
|
||||
.ui-act__cover-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
.ui-act__cover-placeholder {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--color-primary-light);
|
||||
}
|
||||
.ui-act__cover-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
background: var(--color-primary);
|
||||
opacity: 0.4;
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
.ui-act__fee-badge {
|
||||
position: absolute;
|
||||
top: var(--spacing-2);
|
||||
right: var(--spacing-2);
|
||||
padding: 6rpx 14rpx;
|
||||
border-radius: var(--radius-full);
|
||||
font-size: var(--font-size-xs);
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.ui-act__fee-badge--free {
|
||||
background: var(--color-success);
|
||||
}
|
||||
.ui-act__fee-badge--paid {
|
||||
background: var(--color-text-tertiary);
|
||||
}
|
||||
.ui-act__body {
|
||||
padding: var(--spacing-3) var(--spacing-4);
|
||||
}
|
||||
.ui-act__title {
|
||||
font-size: var(--font-size-lg);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--color-text-primary);
|
||||
line-height: var(--line-height-tight);
|
||||
margin-bottom: var(--spacing-1);
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.ui-act__meta {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--color-text-tertiary);
|
||||
line-height: var(--line-height-normal);
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
.ui-act__organizer {
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
.ui-act__intro {
|
||||
margin-top: var(--spacing-2);
|
||||
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: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
.ui-act__footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: var(--spacing-3);
|
||||
}
|
||||
.ui-act__capacity {
|
||||
font-size: var(--font-size-xs);
|
||||
color: var(--color-text-tertiary);
|
||||
}
|
||||
.ui-act--compact {
|
||||
display: flex;
|
||||
height: 200rpx;
|
||||
}
|
||||
.ui-act--compact .ui-act__cover {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ui-act--compact .ui-act__body {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding: var(--spacing-2) var(--spacing-3);
|
||||
}
|
||||
.ui-act--compact .ui-act__intro {
|
||||
display: none;
|
||||
}
|
||||
.ui-act{overflow:hidden;border-radius:28rpx;background:#fff;box-shadow:0 10rpx 32rpx rgba(34,35,91,.08)}.ui-act__cover{position:relative;width:100%;height:240rpx;background:#F0F1F6}.ui-act__cover-img{display:block;width:100%;height:100%}.ui-act__fee-badge{position:absolute;top:18rpx;right:18rpx;padding:7rpx 15rpx;border-radius:22rpx;background:linear-gradient(135deg,var(--mini-accent-coral),var(--mini-accent-pink));color:#fff;font-size:18rpx;font-weight:600}.ui-act__body{padding:22rpx 24rpx}.ui-act__title{overflow:hidden;color:#222746;font-size:28rpx;font-weight:700;line-height:1.35;white-space:nowrap;text-overflow:ellipsis}.ui-act__meta{margin-top:7rpx;color:#767C94;font-size:20rpx;line-height:1.45}.ui-act__intro{display:-webkit-box;overflow:hidden;margin-top:12rpx;color:#626981;font-size:21rpx;line-height:1.55;-webkit-box-orient:vertical;-webkit-line-clamp:2}.ui-act__footer{display:flex;align-items:center;justify-content:space-between;margin-top:18rpx}.ui-act__capacity{color:#858A9E;font-size:19rpx}.ui-act__status-action{min-width:126rpx;height:56rpx;display:flex;align-items:center;justify-content:center;border-radius:28rpx;background:linear-gradient(135deg,var(--mini-accent-coral),var(--mini-accent-pink));color:#fff;font-size:21rpx;font-weight:650}.ui-act__status-action.disabled{background:#EFF0F5;color:#8E93A6}.ui-act--compact{display:flex;height:200rpx}.ui-act--compact .ui-act__cover{width:200rpx;height:200rpx;flex-shrink:0}.ui-act--compact .ui-act__body{flex:1;min-width:0;padding:16rpx 18rpx}.ui-act--compact .ui-act__intro{display:none}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
/>
|
||||
<view wx:else class="ui-avatar__fallback">
|
||||
<text wx:if="{{defaultText}}" class="ui-avatar__fallback-text">{{defaultText}}</text>
|
||||
<view wx:else class="ui-avatar__fallback-icon"></view>
|
||||
<image wx:else class="ui-avatar__fallback-icon" src="/assets/brand/default-avatar.png" mode="aspectFill" />
|
||||
</view>
|
||||
<view wx:if="{{showBadge && (verified || reviewed)}}" class="ui-avatar__badges">
|
||||
<view wx:if="{{verified}}" class="ui-avatar__badge ui-avatar__badge--verified">实名</view>
|
||||
|
||||
@@ -32,11 +32,8 @@
|
||||
font-weight: var(--font-weight-semibold);
|
||||
}
|
||||
.ui-avatar__fallback-icon {
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
border-radius: 50%;
|
||||
background: var(--color-primary);
|
||||
opacity: 0.6;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.ui-avatar__badges {
|
||||
position: absolute;
|
||||
|
||||
@@ -18,6 +18,13 @@ Page({
|
||||
loadingMore: false,
|
||||
hasMore: true,
|
||||
firstLoaded: false,
|
||||
activeCategory: 'all',
|
||||
categories: [
|
||||
{ code: 'all', label: '全部' },
|
||||
{ code: 'matchmaking', label: '公益联谊' },
|
||||
{ code: 'classroom', label: '婚恋课堂' },
|
||||
{ code: 'anti_fraud', label: '反诈宣传' },
|
||||
],
|
||||
/** @type {{title:string, description:string, illustration:string, actions:Array}} */
|
||||
emptyConfig: {
|
||||
title: '暂无进行中的活动',
|
||||
@@ -56,6 +63,7 @@ Page({
|
||||
this.setData({ loading: true });
|
||||
try {
|
||||
await activityStore.fetchActivities();
|
||||
this.applyActivityFilter();
|
||||
this.setData({
|
||||
loading: false,
|
||||
firstLoaded: true,
|
||||
@@ -73,6 +81,7 @@ Page({
|
||||
this.setData({ loadingMore: true });
|
||||
try {
|
||||
await activityStore.loadMoreActivities();
|
||||
this.applyActivityFilter();
|
||||
this.setData({
|
||||
loadingMore: false,
|
||||
hasMore: activityStore.state.activitiesHasMore,
|
||||
@@ -93,6 +102,21 @@ Page({
|
||||
this.loadMore();
|
||||
},
|
||||
|
||||
onCategoryTap(e) {
|
||||
this.setData({ activeCategory: e.currentTarget.dataset.code });
|
||||
this.applyActivityFilter();
|
||||
},
|
||||
|
||||
applyActivityFilter() {
|
||||
const source = activityStore.state.activities || [];
|
||||
const { activeCategory } = this.data;
|
||||
this.setData({
|
||||
activities: activeCategory === 'all'
|
||||
? source
|
||||
: source.filter((item) => (item.activityType || item.category) === activeCategory),
|
||||
});
|
||||
},
|
||||
|
||||
/** 点击活动卡片 → 跳转详情 */
|
||||
onActivityTap(e) {
|
||||
const activityId = e.detail.activityId;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"navigationBarTitleText": "公益活动",
|
||||
"navigationStyle": "custom",
|
||||
"enablePullDownRefresh": true,
|
||||
"usingComponents": {
|
||||
"ui-section-header": "/components/section-header/index",
|
||||
|
||||
@@ -1,43 +1,35 @@
|
||||
<!-- 公益活动列表页 U31 -->
|
||||
<view class="act-page reference-page">
|
||||
<!-- 顶部区:标题 + 我的活动入口 -->
|
||||
<view class="act-page__topbar">
|
||||
<ui-section-header
|
||||
title="公益活动"
|
||||
subtitle="丹阳本地公益组织主办"
|
||||
action="我的活动"
|
||||
bind:action="onMyActivities"
|
||||
/>
|
||||
<!-- 公益活动列表页:仅展示与报名,不在列表创建 Match 或聊天 -->
|
||||
<view class="act-page app-page reference-page">
|
||||
<view class="activity-hero">
|
||||
<view class="activity-nav">
|
||||
<text class="activity-title">公益活动</text>
|
||||
<view class="activity-calendar" bindtap="onMyActivities">
|
||||
<image src="/assets/icons/home/activity.png" mode="aspectFit" />
|
||||
</view>
|
||||
</view>
|
||||
<scroll-view scroll-x class="activity-categories">
|
||||
<view class="activity-category-row">
|
||||
<view wx:for="{{categories}}" wx:key="code" class="activity-category {{activeCategory === item.code ? 'active' : ''}}" data-code="{{item.code}}" bindtap="onCategoryTap">{{item.label}}</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<view class="activity-heading">
|
||||
<view><text class="heading-title">丹阳公益活动</text><text class="heading-subtitle">丰富活动,连接更多可能</text></view>
|
||||
<text class="my-activity-link" bindtap="onMyActivities">我的活动</text>
|
||||
</view>
|
||||
|
||||
<!-- 首次加载 -->
|
||||
<view wx:if="{{loading && !firstLoaded}}" class="act-loading">
|
||||
<ui-loading mode="skeleton" rows="3" />
|
||||
</view>
|
||||
|
||||
<!-- 列表 -->
|
||||
<view wx:elif="{{activities.length}}" class="act-list">
|
||||
<ui-activity-card
|
||||
wx:for="{{activities}}"
|
||||
wx:key="activityId"
|
||||
activity="{{item}}"
|
||||
bind:tap="onActivityTap"
|
||||
/>
|
||||
<!-- 加载更多 -->
|
||||
<view wx:if="{{loadingMore}}" class="act-list__more">
|
||||
<ui-loading mode="spinner" inline text="加载更多活动…" />
|
||||
</view>
|
||||
<view wx:elif="{{!hasMore}}" class="act-list__end">已到底部</view>
|
||||
<ui-activity-card wx:for="{{activities}}" wx:key="activityId" activity="{{item}}" bind:tap="onActivityTap" />
|
||||
<view wx:if="{{loadingMore}}" class="act-list__more"><ui-loading mode="spinner" inline text="加载更多活动" /></view>
|
||||
<view wx:elif="{{!hasMore}}" class="act-list__end">更多公益活动正在筹备</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view wx:else class="act-empty">
|
||||
<ui-empty
|
||||
title="{{emptyConfig.title}}"
|
||||
description="{{emptyConfig.description}}"
|
||||
illustration="{{emptyConfig.illustration}}"
|
||||
actions="{{emptyConfig.actions}}"
|
||||
bind:action="onEmptyAction"
|
||||
/>
|
||||
<ui-empty title="{{emptyConfig.title}}" description="{{emptyConfig.description}}" illustration="{{emptyConfig.illustration}}" actions="{{emptyConfig.actions}}" bind:action="onEmptyAction" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -1,44 +1 @@
|
||||
/**
|
||||
* 公益活动列表页 U31
|
||||
*/
|
||||
|
||||
.act-page {
|
||||
min-height: 100vh;
|
||||
background: var(--color-bg-page);
|
||||
padding-bottom: var(--spacing-section);
|
||||
}
|
||||
|
||||
.act-page__topbar {
|
||||
padding: var(--spacing-3) var(--spacing-page-x) var(--spacing-1);
|
||||
}
|
||||
|
||||
/* ============ 加载骨架 ============ */
|
||||
.act-loading {
|
||||
padding: var(--spacing-3) var(--spacing-page-x);
|
||||
}
|
||||
|
||||
/* ============ 列表 ============ */
|
||||
.act-list {
|
||||
padding: var(--spacing-2) var(--spacing-page-x) 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-3);
|
||||
}
|
||||
|
||||
.act-list__more {
|
||||
padding: var(--spacing-3) 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.act-list__end {
|
||||
padding: var(--spacing-3) 0;
|
||||
text-align: center;
|
||||
font-size: var(--font-size-xs);
|
||||
color: var(--color-text-placeholder);
|
||||
}
|
||||
|
||||
/* ============ 空状态 ============ */
|
||||
.act-empty {
|
||||
padding-top: 160rpx;
|
||||
}
|
||||
.act-page{min-height:100vh;padding-bottom:40rpx;background:#F4F5FA}.activity-hero{padding:env(safe-area-inset-top) 24rpx 26rpx;border-radius:0 0 36rpx 36rpx;background:linear-gradient(160deg,var(--mini-night-start),var(--mini-night-end));box-shadow:var(--mini-shadow)}.activity-nav{position:relative;display:flex;align-items:center;justify-content:center;height:88rpx}.activity-title{color:#fff;font-size:31rpx;font-weight:700}.activity-calendar{position:absolute;right:0;display:flex;align-items:center;justify-content:center;width:62rpx;height:62rpx;border:1rpx solid rgba(255,255,255,.18);border-radius:31rpx;background:rgba(255,255,255,.1)}.activity-calendar image{width:34rpx;height:34rpx;filter:brightness(0) invert(1)}.activity-categories{white-space:nowrap}.activity-category-row{display:inline-flex;gap:12rpx}.activity-category{padding:11rpx 22rpx;border-radius:25rpx;background:rgba(255,255,255,.1);color:rgba(255,255,255,.72);font-size:20rpx}.activity-category.active{background:#fff;color:var(--mini-accent-pink);font-weight:650}.activity-heading{display:flex;align-items:flex-end;justify-content:space-between;padding:32rpx 28rpx 16rpx}.activity-heading>view{display:flex;flex-direction:column}.heading-title{color:#252A49;font-size:30rpx;font-weight:700}.heading-subtitle{margin-top:5rpx;color:#8A8FA4;font-size:20rpx}.my-activity-link{color:var(--mini-accent-pink);font-size:21rpx}.act-loading{padding:12rpx 24rpx}.act-list{display:flex;flex-direction:column;gap:20rpx;padding:8rpx 24rpx 0}.act-list__more{display:flex;justify-content:center;padding:24rpx 0}.act-list__end{text-align:center;padding:24rpx 0;color:#9A9EB0;font-size:20rpx}.act-empty{padding-top:70rpx}
|
||||
|
||||
@@ -32,11 +32,12 @@ Page({
|
||||
canPause: false,
|
||||
canResume: false,
|
||||
likersCount: 0,
|
||||
matchCount: 0,
|
||||
showLogoutDialog: false,
|
||||
logoutAction: DANGER_ACTION.LOGOUT,
|
||||
loginActions: [{ text: '微信登录', event: 'login', variant: 'primary' }],
|
||||
hasOperatorToken: false,
|
||||
profileCompleteness: 78,
|
||||
profileCompleteness: 0,
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
@@ -44,7 +45,12 @@ Page({
|
||||
this._unsubUser = userStore.subscribe((state) => this._syncFromUserStore(state));
|
||||
this._syncFromUserStore(userStore.state);
|
||||
// 绑定 matchStore.likersCount(驱动"喜欢我"徽标)
|
||||
this._unsubMatch = matchStore.bindToPage(this, { likersCount: 'likersCount' });
|
||||
this._unsubMatch = matchStore.subscribe((state) => {
|
||||
this.setData({
|
||||
likersCount: state.likersCount || 0,
|
||||
matchCount: Array.isArray(state.mutualList) ? state.mutualList.length : 0,
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
onShow() {
|
||||
@@ -54,6 +60,7 @@ Page({
|
||||
userStore.fetchProfile().catch(() => {});
|
||||
userStore.fetchVerificationStatus().catch(() => {});
|
||||
matchStore.fetchLikersCount().catch(() => {});
|
||||
matchStore.fetchMutualList().catch(() => {});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -94,6 +101,7 @@ Page({
|
||||
relationshipText,
|
||||
canPause,
|
||||
canResume,
|
||||
profileCompleteness: state.profile?.profileCompletion || 0,
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"navigationBarTitleText": "我的",
|
||||
"navigationStyle": "custom",
|
||||
"usingComponents": {
|
||||
"ui-section-header": "/components/section-header/index",
|
||||
"ui-avatar": "/components/avatar/index",
|
||||
|
||||
@@ -1,22 +1,60 @@
|
||||
<view class="page reference-page">
|
||||
<ui-empty wx:if="{{!isLoggedIn}}" illustration="default" title="登录后查看我的服务" description="管理资料、缘分与公益服务记录" actions="{{loginActions}}" bind:action="onLoginAction"/>
|
||||
<view class="page app-page reference-page">
|
||||
<view wx:if="{{!isLoggedIn}}" class="mine-guest">
|
||||
<view class="guest-brand"><image src="/assets/brand/logo-mark.png" mode="aspectFit" /><text>善缘丹阳</text><text class="guest-subtitle">公益婚恋服务平台</text></view>
|
||||
<ui-empty illustration="default" title="登录后查看我的服务" description="管理资料、缘分与公益服务记录" actions="{{loginActions}}" bind:action="onLoginAction" />
|
||||
</view>
|
||||
<ui-loading wx:elif="{{loadStatus === 'loading' && !profile}}" mode="skeleton" rows="6" />
|
||||
<block wx:else>
|
||||
<view class="profile-card"><ui-avatar src="{{profile.avatarUrl || ''}}" size="xl" default-text="{{profile.displayName || ''}}" verified="{{isRealNameVerified}}" reviewed="{{isProfileApproved}}"/><view class="profile-info"><view class="profile-name">{{profile.displayName || '未填写昵称'}}</view><view class="profile-complete">资料完整度 {{profileCompleteness}}%</view><view class="profile-progress"><view style="width:{{profileCompleteness}}%"></view></view><view class="profile-badges"><ui-status-badge kind="{{isRealNameVerified ? 'success' : 'warning'}}" label="{{isRealNameVerified ? '已实名' : '未实名'}}"/><ui-status-badge kind="success" label="本地资格"/><ui-status-badge kind="{{isProfileApproved ? 'success' : 'warning'}}" label="{{isProfileApproved ? '资料已审核' : '资料待审核'}}"/></view></view></view>
|
||||
<view class="profile-hero">
|
||||
<view class="mine-nav"><text>我的</text><image src="/assets/icons/home/service-station.png" mode="aspectFit" bindtap="onGoSettings" /></view>
|
||||
<view class="profile-main">
|
||||
<ui-avatar src="{{profile.avatarUrl || ''}}" size="xl" default-text="{{profile.displayName || '善缘用户'}}" verified="{{isRealNameVerified}}" reviewed="{{isProfileApproved}}" />
|
||||
<view class="profile-copy">
|
||||
<view class="profile-name-row"><text class="profile-name">{{profile.displayName || '未填写昵称'}}</text><text class="profile-status">{{relationshipText}}</text></view>
|
||||
<text class="profile-meta">资料完整度 {{profileCompleteness}}%</text>
|
||||
<view class="profile-progress"><view style="width:{{profileCompleteness}}%"></view></view>
|
||||
<view class="profile-badges"><ui-status-badge kind="{{isRealNameVerified ? 'success' : 'warning'}}" label="{{isRealNameVerified ? '已实名' : '未实名'}}" /><ui-status-badge kind="{{isProfileApproved ? 'success' : 'warning'}}" label="{{isProfileApproved ? '资料已审核' : '资料待审核'}}" /></view>
|
||||
</view>
|
||||
<text class="edit-profile" bindtap="onEditProfile">编辑资料</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<ui-section-header title="我的" subtitle="资料与缘分"/>
|
||||
<view class="list-group"><view class="list-row" bindtap="onEditProfile"><text class="list-label">我的资料</text><text class="list-value">{{reviewStatusText}}</text><text class="list-arrow">›</text></view><view class="list-row" bindtap="onEditPreference"><text class="list-label">择偶条件</text><text class="list-arrow">›</text></view><view class="list-row" bindtap="onGoFate"><text class="list-label">我的缘分</text><text class="list-arrow">›</text></view></view>
|
||||
<view class="profile-stats">
|
||||
<view class="profile-stat"><text class="stat-value">{{profileCompleteness}}%</text><text class="stat-label">资料完整</text></view>
|
||||
<view class="profile-stat" bindtap="onGoLikers"><text class="stat-value">{{likersCount}}</text><text class="stat-label">喜欢我的</text></view>
|
||||
<view class="profile-stat" bindtap="onGoFate"><text class="stat-value">{{matchCount}}</text><text class="stat-label">当前缘分</text></view>
|
||||
<view class="profile-stat"><text class="stat-value stat-value--text">{{reviewStatusText}}</text><text class="stat-label">资料状态</text></view>
|
||||
</view>
|
||||
|
||||
<ui-section-header title="公益服务"/>
|
||||
<view class="list-group"><view class="list-row" bindtap="onGoMatchmaker"><text class="list-label">我的红娘</text><text class="list-arrow">›</text></view><view class="list-row" bindtap="onGoCounseling"><text class="list-label">我的咨询</text><text class="list-arrow">›</text></view><view class="list-row" bindtap="onGoActivities"><text class="list-label">我的活动</text><text class="list-arrow">›</text></view><view class="list-row" bindtap="onGoAppointments"><text class="list-label">我的预约</text><text class="list-arrow">›</text></view><view class="list-row" bindtap="onGoServiceHistory"><text class="list-label">公益服务记录</text><text class="list-arrow">›</text></view></view>
|
||||
<view class="public-identity-card" bindtap="onEditProfile">
|
||||
<image src="/assets/brand/logo-mark.png" mode="aspectFit" />
|
||||
<view><text class="identity-title">我在善缘丹阳</text><text class="identity-desc">用真诚遇见美好,让爱在丹阳绽放</text></view>
|
||||
<image class="identity-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" />
|
||||
</view>
|
||||
|
||||
<ui-section-header title="安全与隐私"/>
|
||||
<view class="list-group"><view class="list-row" bindtap="onGoPrivacy"><text class="list-label">隐私设置</text><text class="list-arrow">›</text></view><view class="list-row" bindtap="onGoBlacklist"><text class="list-label">黑名单</text><text class="list-arrow">›</text></view><view class="list-row" bindtap="onGoSafety"><text class="list-label">举报与安全</text><text class="list-arrow">›</text></view><view class="list-row" bindtap="onGoSettings"><text class="list-label">账号设置</text><text class="list-arrow">›</text></view></view>
|
||||
<ui-section-header title="我的公益服务" subtitle="服务进度与预约记录" />
|
||||
<view class="service-grid">
|
||||
<view class="service-entry" bindtap="onGoMatchmaker"><view class="service-icon rose"><image src="/assets/icons/home/matchmaker.png" mode="aspectFit" /></view><text>我的红娘</text></view>
|
||||
<view class="service-entry" bindtap="onGoCounseling"><view class="service-icon blue"><image src="/assets/icons/home/counseling.png" mode="aspectFit" /></view><text>我的咨询</text></view>
|
||||
<view class="service-entry" bindtap="onGoActivities"><view class="service-icon amber"><image src="/assets/icons/home/activity.png" mode="aspectFit" /></view><text>我的活动</text></view>
|
||||
<view class="service-entry" bindtap="onGoAppointments"><view class="service-icon green"><image src="/assets/icons/home/service-station.png" mode="aspectFit" /></view><text>我的预约</text></view>
|
||||
</view>
|
||||
|
||||
<ui-section-header title="公益信息"/>
|
||||
<view class="list-group"><view class="list-row" bindtap="onGoClassroom"><text class="list-label">婚恋课堂</text><text class="list-arrow">›</text></view><view class="list-row" bindtap="onGoAntiFraud"><text class="list-label">婚恋反诈</text><text class="list-arrow">›</text></view><view class="list-row" bindtap="onGoStation"><text class="list-label">善缘服务站</text><text class="list-arrow">›</text></view><view class="list-row" bindtap="onGoAbout"><text class="list-label">关于善缘丹阳</text><text class="list-arrow">›</text></view></view>
|
||||
<view class="list-group">
|
||||
<view class="list-row" bindtap="onEditProfile"><text class="list-label">我的资料</text><text class="list-value">{{reviewStatusText}}</text><image class="list-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view>
|
||||
<view class="list-row" bindtap="onEditPreference"><text class="list-label">择偶条件</text><image class="list-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view>
|
||||
<view class="list-row" bindtap="onGoFate"><text class="list-label">我的缘分</text><image class="list-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view>
|
||||
<view class="list-row" bindtap="onGoServiceHistory"><text class="list-label">公益服务记录</text><image class="list-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view>
|
||||
<view class="list-row" bindtap="onGoSettings"><text class="list-label">账号设置</text><image class="list-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view>
|
||||
</view>
|
||||
|
||||
<view class="list-group"><view class="list-row danger" bindtap="onLogout"><text class="list-label">退出登录</text></view></view>
|
||||
<view class="list-group secondary-list">
|
||||
<view class="list-row" bindtap="onGoPrivacy"><text class="list-label">隐私设置</text><image class="list-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view>
|
||||
<view class="list-row" bindtap="onGoSafety"><text class="list-label">举报与安全</text><image class="list-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view>
|
||||
<view class="list-row" bindtap="onGoAntiFraud"><text class="list-label">婚恋反诈</text><image class="list-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view>
|
||||
</view>
|
||||
|
||||
<view class="logout-row" bindtap="onLogout">退出登录</view>
|
||||
<ui-danger-action-dialog visible="{{showLogoutDialog}}" action="{{logoutAction}}" bind:confirm="onConfirmLogout" bind:cancel="onCancelLogout" />
|
||||
</block>
|
||||
</view>
|
||||
|
||||
@@ -1,101 +1 @@
|
||||
/**
|
||||
* 我的页样式(Design Token,中低密度留白)
|
||||
*/
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: var(--color-bg-page);
|
||||
padding-bottom: var(--spacing-8);
|
||||
}
|
||||
|
||||
/* ============ 个人资料卡 ============ */
|
||||
.profile-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-4);
|
||||
background: var(--color-bg-card);
|
||||
padding: var(--spacing-5) var(--spacing-page-x);
|
||||
border-bottom: var(--border-width) solid var(--color-divider);
|
||||
}
|
||||
|
||||
.profile-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.profile-name {
|
||||
font-size: var(--font-size-xl);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--color-text-primary);
|
||||
margin-bottom: var(--spacing-1);
|
||||
}
|
||||
|
||||
.profile-meta {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--color-text-tertiary);
|
||||
margin-bottom: var(--spacing-2);
|
||||
}
|
||||
|
||||
.profile-badges {
|
||||
display: flex;
|
||||
gap: var(--spacing-2);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* ============ 操作行 ============ */
|
||||
.action-row {
|
||||
background: var(--color-bg-card);
|
||||
padding: var(--spacing-3) var(--spacing-page-x);
|
||||
border-bottom: var(--border-width) solid var(--color-divider);
|
||||
}
|
||||
|
||||
.action-hint {
|
||||
text-align: center;
|
||||
color: var(--color-text-tertiary);
|
||||
font-size: var(--font-size-sm);
|
||||
padding: var(--spacing-2) 0;
|
||||
}
|
||||
|
||||
/* ============ 列表组 ============ */
|
||||
.list-group {
|
||||
background: var(--color-bg-card);
|
||||
margin-bottom: var(--spacing-section);
|
||||
}
|
||||
|
||||
.list-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: var(--spacing-4) var(--spacing-page-x);
|
||||
border-bottom: var(--border-width) solid var(--color-divider);
|
||||
background: var(--color-bg-card);
|
||||
}
|
||||
|
||||
.list-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.list-label {
|
||||
flex: 1;
|
||||
font-size: var(--font-size-base);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.list-value {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--color-text-tertiary);
|
||||
margin-right: var(--spacing-2);
|
||||
}
|
||||
|
||||
.list-arrow {
|
||||
font-size: var(--font-size-lg);
|
||||
color: var(--color-text-disabled);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.list-row.danger .list-label {
|
||||
color: var(--color-danger);
|
||||
text-align: center;
|
||||
flex: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.profile-complete{font-size:22rpx;color:var(--color-text-tertiary);margin-top:4rpx}.profile-progress{height:8rpx;margin:10rpx 0 14rpx;border-radius:999rpx;background:var(--color-divider);overflow:hidden}.profile-progress view{height:100%;background:var(--color-primary);border-radius:999rpx}.list-row{min-height:88rpx;box-sizing:border-box}.page ui-section-header{display:block;padding:0 var(--spacing-page-x)}
|
||||
.page{min-height:100vh;padding-bottom:48rpx;background:#F4F5FA}.mine-guest{min-height:100vh;background:linear-gradient(160deg,var(--mini-night-start) 0,var(--mini-night-end) 34%,#F4F5FA 34%)}.guest-brand{display:flex;flex-direction:column;align-items:center;padding:calc(env(safe-area-inset-top) + 70rpx) 0 80rpx;color:#fff}.guest-brand image{width:92rpx;height:92rpx}.guest-brand>text{margin-top:12rpx;font-size:34rpx;font-weight:700}.guest-brand .guest-subtitle{margin-top:5rpx;color:rgba(255,255,255,.72);font-size:20rpx;font-weight:400;letter-spacing:4rpx}.profile-hero{padding:env(safe-area-inset-top) 24rpx 54rpx;border-radius:0 0 42rpx 42rpx;background:linear-gradient(160deg,var(--mini-night-start),var(--mini-night-end));box-shadow:var(--mini-shadow)}.mine-nav{position:relative;display:flex;align-items:center;justify-content:center;height:88rpx;color:#fff;font-size:31rpx;font-weight:700}.mine-nav image{position:absolute;right:12rpx;width:36rpx;height:36rpx;filter:brightness(0) invert(1)}.profile-main{position:relative;display:flex;align-items:center}.profile-copy{flex:1;min-width:0;margin-left:20rpx;color:#fff}.profile-name-row{display:flex;align-items:center;gap:12rpx}.profile-name{font-size:31rpx;font-weight:700}.profile-status{padding:5rpx 10rpx;border-radius:15rpx;background:rgba(255,255,255,.12);color:rgba(255,255,255,.78);font-size:17rpx}.profile-meta{display:block;margin-top:8rpx;color:rgba(255,255,255,.72);font-size:20rpx}.profile-progress{width:78%;height:7rpx;margin:10rpx 0 13rpx;overflow:hidden;border-radius:8rpx;background:rgba(255,255,255,.14)}.profile-progress view{height:100%;border-radius:8rpx;background:linear-gradient(90deg,#FF8C9C,#FF5C82)}.profile-badges{display:flex;gap:8rpx}.edit-profile{position:absolute;right:0;top:4rpx;color:rgba(255,255,255,.82);font-size:19rpx}.profile-stats{position:relative;z-index:2;display:grid;grid-template-columns:repeat(4,1fr);margin:-24rpx 24rpx 0;padding:24rpx 8rpx;border-radius:28rpx;background:#fff;box-shadow:var(--mini-shadow)}.profile-stat{display:flex;flex-direction:column;align-items:center;border-right:1rpx solid #EFF0F5}.profile-stat:last-child{border-right:0}.stat-value{color:#283056;font-size:29rpx;font-weight:700}.stat-value--text{font-size:22rpx}.stat-label{margin-top:5rpx;color:#8A8FA4;font-size:18rpx}.public-identity-card{display:flex;align-items:center;margin:24rpx;padding:22rpx;border-radius:26rpx;background:linear-gradient(135deg,#FFF0F5,#F7EEFF);box-shadow:0 8rpx 26rpx rgba(87,62,145,.08)}.public-identity-card>image:first-child{width:72rpx;height:72rpx}.public-identity-card>view{flex:1;display:flex;flex-direction:column;margin-left:16rpx}.identity-title{color:#F14D79;font-size:26rpx;font-weight:700}.identity-desc{margin-top:5rpx;color:#8A6F91;font-size:19rpx}.public-identity-card .identity-arrow{width:26rpx;height:26rpx}.service-grid{display:grid;grid-template-columns:repeat(4,1fr);margin:0 24rpx 28rpx;padding:24rpx 8rpx;border-radius:26rpx;background:#fff;box-shadow:0 8rpx 28rpx rgba(35,35,95,.07)}.service-entry{display:flex;flex-direction:column;align-items:center;color:#343957;font-size:20rpx}.service-icon{display:flex;align-items:center;justify-content:center;width:64rpx;height:64rpx;margin-bottom:10rpx;border-radius:20rpx}.service-icon image{width:42rpx;height:42rpx}.service-icon.rose{background:#FFF0F5}.service-icon.blue{background:#EAF3FF}.service-icon.amber{background:#FFF3E5}.service-icon.green{background:#EAF8F2}.list-group{overflow:hidden;margin:0 24rpx 22rpx;border-radius:26rpx;background:#fff;box-shadow:0 8rpx 28rpx rgba(35,35,95,.06)}.list-row{display:flex;align-items:center;min-height:88rpx;padding:0 24rpx;border-bottom:1rpx solid #EFF0F5}.list-row:last-child{border-bottom:0}.list-label{flex:1;color:#2B304E;font-size:23rpx}.list-value{margin-right:12rpx;color:#8A8FA4;font-size:19rpx}.list-arrow{width:24rpx;height:24rpx}.secondary-list{margin-top:0}.logout-row{margin:26rpx 24rpx 0;padding:24rpx;text-align:center;color:#D95561;font-size:23rpx;background:#fff;border-radius:26rpx}
|
||||
|
||||
@@ -67,6 +67,23 @@ assert.match(messagesTemplate, /ui-conv__badge|unreadTotal/, '消息页缺少未
|
||||
assert.match(messagesTemplate, /互相喜欢后/, '消息页缺少无 Mutual 状态说明')
|
||||
assert.match(messagesLogic, /canSendMessage/, '消息页进入聊天前必须校验服务端会话能力')
|
||||
|
||||
const activityTemplate = read('miniapp/pages/activity/activity.wxml')
|
||||
const activityCard = read('miniapp/components/activity-card/index.wxml')
|
||||
const activityLogic = read('miniapp/pages/activity/activity.js')
|
||||
assert.match(activityTemplate, /activity-categories/, '活动页缺少活动分类')
|
||||
assert.match(activityTemplate, /activity-calendar/, '活动页缺少日历入口')
|
||||
assert.match(activityCard, /ui-act__capacity/, '活动卡缺少人数和容量')
|
||||
assert.match(activityCard, /ui-act__status-action/, '活动卡缺少状态按钮')
|
||||
assert.doesNotMatch(activityLogic, /matchStore|to\.chat/, '活动列表不得直接创建 Match 或进入聊天')
|
||||
|
||||
const mineTemplate = read('miniapp/pages/mine/mine.wxml')
|
||||
assert.match(mineTemplate, /profile-hero/, '我的页缺少个人头部')
|
||||
assert.match(mineTemplate, /profile-stats/, '我的页缺少四项统计')
|
||||
assert.match(mineTemplate, /我在善缘丹阳/, '我的页缺少公益身份卡')
|
||||
for (const label of ['我的红娘', '我的咨询', '我的活动', '我的预约', '账号设置']) {
|
||||
assert.ok(mineTemplate.includes(label), `我的页缺少入口 ${label}`)
|
||||
}
|
||||
|
||||
const theme = read('miniapp/app.wxss')
|
||||
for (const token of [
|
||||
'--mini-night-start',
|
||||
|
||||
Reference in New Issue
Block a user