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
+34
View File
@@ -0,0 +1,34 @@
/**
* Avatar 头像(规范 §22 用户卡片)
*
* 显示用户头像 + 已实名 / 已审核徽标。
* 不变量(AGENTS 第 8 条):头像 URL 来自 OSS 公开链接,不携带任何敏感身份字段。
* 用法:
* <ui-avatar src="{{user.avatarUrl}}" size="lg"
* verified="{{user.verified}}" reviewed="{{user.reviewed}}" />
*/
Component({
options: { addGlobalClass: true },
properties: {
src: { type: String, value: '' },
size: { type: String, value: 'md' }, // sm|md|lg|xl
shape: { type: String, value: 'circle' }, // circle|square
verified: { type: Boolean, value: false },
reviewed: { type: Boolean, value: false },
showBadge: { type: Boolean, value: true },
// 兜底默认头像(不依赖外部资源)
defaultText: { type: String, value: '' }, // 没图时显示首字(如"王")
},
data: {
loadError: false,
},
methods: {
onError() {
this.setData({ loadError: true });
this.triggerEvent('error', {});
},
onTap() {
this.triggerEvent('tap', {});
},
},
});
+4
View File
@@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}
+20
View File
@@ -0,0 +1,20 @@
<view
class="ui-avatar ui-avatar--{{size}} ui-avatar--{{shape}}"
bindtap="onTap"
>
<image
wx:if="{{src && !loadError}}"
class="ui-avatar__img"
src="{{src}}"
mode="aspectFill"
binderror="onError"
/>
<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>
</view>
<view wx:if="{{showBadge && (verified || reviewed)}}" class="ui-avatar__badges">
<view wx:if="{{verified}}" class="ui-avatar__badge ui-avatar__badge--verified">实名</view>
<view wx:if="{{reviewed}}" class="ui-avatar__badge ui-avatar__badge--reviewed">审核</view>
</view>
</view>
+62
View File
@@ -0,0 +1,62 @@
.ui-avatar {
position: relative;
flex-shrink: 0;
background: var(--color-bg-disabled);
overflow: hidden;
}
.ui-avatar--circle { border-radius: 50%; }
.ui-avatar--square { border-radius: var(--radius-md); }
/* 尺寸:sm 60 / md 88 / lg 120 / xl 160 */
.ui-avatar--sm { width: 60rpx; height: 60rpx; }
.ui-avatar--md { width: 88rpx; height: 88rpx; }
.ui-avatar--lg { width: 120rpx; height: 120rpx; }
.ui-avatar--xl { width: 160rpx; height: 160rpx; }
.ui-avatar__img {
width: 100%;
height: 100%;
display: block;
}
.ui-avatar__fallback {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: var(--color-primary-light);
}
.ui-avatar__fallback-text {
font-size: var(--font-size-lg);
color: var(--color-primary);
font-weight: var(--font-weight-semibold);
}
.ui-avatar__fallback-icon {
width: 50%;
height: 50%;
border-radius: 50%;
background: var(--color-primary);
opacity: 0.6;
}
.ui-avatar__badges {
position: absolute;
bottom: -4rpx;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 6rpx;
}
.ui-avatar__badge {
font-size: 16rpx;
line-height: 1;
padding: 4rpx 8rpx;
border-radius: var(--radius-full);
color: #FFFFFF;
font-weight: var(--font-weight-medium);
white-space: nowrap;
}
.ui-avatar__badge--verified { background: var(--color-success); }
.ui-avatar__badge--reviewed { background: var(--color-info); }
/* 小尺寸时隐藏徽标避免溢出 */
.ui-avatar--sm .ui-avatar__badges { display: none; }