chore: establish V1.1 recovery baseline

This commit is contained in:
2026-09-09 22:05:00 +08:00
commit b46b48eb33
947 changed files with 155471 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
/**
* ActivityCard 活动卡片(规范 §43-46)
*
* 不变量(AGENTS.md 第 1 条):feeType=paid 仅作展示字段,前端不实现任何支付入口。
* "公益免费"作为主要视觉标识突出展示。
*/
Component({
options: { addGlobalClass: true },
properties: {
activity: { type: Object, value: null },
showStatusBadge: { type: Boolean, value: true },
compact: { type: Boolean, value: false }, // 紧凑模式(首页推荐位)
},
methods: {
onTap() {
if (!this.data.activity) return;
this.triggerEvent('tap', { activityId: this.data.activity.activityId });
},
},
});
@@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"ui-status-badge": "../status-badge/index"
}
}
@@ -0,0 +1,62 @@
<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>
</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__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="已取消"
/>
</view>
</view>
</view>
</view>
+108
View File
@@ -0,0 +1,108 @@
.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;
}