chore: establish V1.1 recovery baseline
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* SuccessConfirmDialog 成功牵手双确认弹窗(AGENTS.md 第 6 条)
|
||||
*
|
||||
* 双角色:
|
||||
* - 发起方(请求方):mode="request" → 显示"发起牵手请求"
|
||||
* - 被请求方(确认方):mode="confirm" → 显示"对方请求与你成功牵手"
|
||||
*
|
||||
* 不变量(AGENTS.md):
|
||||
* - 第 6 条:成功牵手必须双确认——本组件是用户侧的唯一确认入口,
|
||||
* 点击确认后由调用方调用 stores.confirmSuccess(matchId)(内部触发 matchService.confirmSuccess)。
|
||||
* - 第 6 条(隐式):发起方 7 天内未确认则请求过期,本组件显示过期倒计时(如有 expiresAt)。
|
||||
*/
|
||||
Component({
|
||||
options: { addGlobalClass: true },
|
||||
properties: {
|
||||
visible: { type: Boolean, value: false },
|
||||
mode: { type: String, value: 'request' }, // request | confirm
|
||||
targetName: { type: String, value: '' },
|
||||
expiresAt: { type: Number, value: 0 }, // 过期时间戳(mode=confirm 时由调用方传入)
|
||||
},
|
||||
data: {
|
||||
titleText: '',
|
||||
contentText: '',
|
||||
confirmText: '',
|
||||
expiresInText: '',
|
||||
},
|
||||
observers: {
|
||||
'mode, targetName, expiresAt'(mode, name, expiresAt) {
|
||||
let title = '';
|
||||
let content = '';
|
||||
let confirm = '';
|
||||
if (mode === 'request') {
|
||||
title = '发起成功牵手';
|
||||
content = `发起后 ${name || '对方'} 需在 7 天内确认。双方均确认后,关系将置为"成功牵手",平台不再为你推荐其他人。`;
|
||||
confirm = '发起牵手请求';
|
||||
} else {
|
||||
title = '对方发起牵手请求';
|
||||
content = `${name || '对方'} 希望与你确认成功牵手。确认后你们的关系将置为"成功牵手",平台不再为你们推荐其他人。`;
|
||||
confirm = '我同意';
|
||||
}
|
||||
let expiresInText = '';
|
||||
if (expiresAt > 0) {
|
||||
const remain = expiresAt - Date.now();
|
||||
if (remain > 0) {
|
||||
const days = Math.floor(remain / (24 * 3600 * 1000));
|
||||
const hours = Math.floor((remain % (24 * 3600 * 1000)) / (3600 * 1000));
|
||||
expiresInText = days > 0 ? `剩余 ${days} 天 ${hours} 小时` : `剩余 ${hours} 小时`;
|
||||
} else {
|
||||
expiresInText = '已过期';
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
titleText: title,
|
||||
contentText: content,
|
||||
confirmText: confirm,
|
||||
expiresInText,
|
||||
});
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onConfirm() {
|
||||
this.triggerEvent('confirm', { mode: this.data.mode });
|
||||
},
|
||||
onCancel() {
|
||||
this.triggerEvent('cancel', {});
|
||||
},
|
||||
onStop() {},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"ui-button": "../button/index"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<view wx:if="{{visible}}" class="ui-success-mask" catchtap="onCancel">
|
||||
<view class="ui-success" catchtap="onStop">
|
||||
<view class="ui-success__heart">
|
||||
<view class="ui-success__heart-icon"></view>
|
||||
</view>
|
||||
<view class="ui-success__title">{{titleText}}</view>
|
||||
<view class="ui-success__content">{{contentText}}</view>
|
||||
<view wx:if="{{expiresInText}}" class="ui-success__expires">{{expiresInText}}</view>
|
||||
<view class="ui-success__actions">
|
||||
<ui-button variant="ghost" size="md" class="ui-success__btn" bindtap="onCancel">再想想</ui-button>
|
||||
<ui-button variant="primary" size="md" class="ui-success__btn" bindtap="onConfirm">{{confirmText}}</ui-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -0,0 +1,67 @@
|
||||
.ui-success-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: var(--color-bg-overlay);
|
||||
z-index: var(--z-modal);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 var(--spacing-6);
|
||||
}
|
||||
.ui-success {
|
||||
width: 100%;
|
||||
max-width: 600rpx;
|
||||
background: var(--color-bg-card);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--spacing-6) var(--spacing-4) var(--spacing-4);
|
||||
text-align: center;
|
||||
box-shadow: var(--shadow-popup);
|
||||
animation: ui-success-in var(--motion-normal) var(--ease-standard);
|
||||
}
|
||||
@keyframes ui-success-in {
|
||||
from { transform: scale(0.92); opacity: 0; }
|
||||
to { transform: scale(1); opacity: 1; }
|
||||
}
|
||||
.ui-success__heart {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
margin: 0 auto var(--spacing-3);
|
||||
background: var(--color-primary-light);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.ui-success__heart-icon {
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
background: var(--color-primary);
|
||||
clip-path: polygon(50% 100%, 0 38%, 18% 18%, 50% 38%, 82% 18%, 100% 38%);
|
||||
}
|
||||
.ui-success__title {
|
||||
font-size: var(--font-size-xl);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--color-text-primary);
|
||||
margin-bottom: var(--spacing-2);
|
||||
}
|
||||
.ui-success__content {
|
||||
font-size: var(--font-size-md);
|
||||
color: var(--color-text-secondary);
|
||||
line-height: var(--line-height-relaxed);
|
||||
margin-bottom: var(--spacing-2);
|
||||
}
|
||||
.ui-success__expires {
|
||||
font-size: var(--font-size-xs);
|
||||
color: var(--color-warning);
|
||||
margin-bottom: var(--spacing-4);
|
||||
}
|
||||
.ui-success__actions {
|
||||
display: flex;
|
||||
gap: var(--spacing-2);
|
||||
}
|
||||
.ui-success__btn {
|
||||
flex: 1;
|
||||
}
|
||||
Reference in New Issue
Block a user