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
@@ -0,0 +1,108 @@
/**
* DangerActionDialog 危险动作确认弹窗(规范 §107 DANGER_ACTION)
*
* 用于:拉黑 / 解除匹配 / 暂停寻找 / 退出服务 / 关闭账号
* 不变量(AGENTS.md):
* - 第 4 条:Block 前必须二次确认,本弹窗为唯一确认入口;
* - 第 6 条:解除匹配/退出服务这类不可逆动作同样需要确认。
*
* 用法:
* <ui-danger-action-dialog
* visible="{{showBlockDialog}}"
* action="block"
* target-name="王女士"
* bind:confirm="onConfirmBlock"
* bind:cancel="onCancelBlock" />
*/
const { DANGER_ACTION } = require('../../constants');
const ACTION_CONFIG = {
[DANGER_ACTION.BLOCK]: {
title: '拉黑该用户',
confirmText: '确认拉黑',
danger: true,
buildContent: (name) => `拉黑后 ${name || '该用户'} 将无法与你互动,你也不会再收到对方的推荐与消息。此操作可由你随时解除。`,
},
[DANGER_ACTION.UNBLOCK]: {
title: '解除拉黑',
confirmText: '确认解除',
danger: false,
buildContent: (name) => `解除拉黑后,${name || '对方'} 将可以重新看到你并向你发起互动。请确认你已准备好重新与对方接触。`,
},
[DANGER_ACTION.UNMATCH]: {
title: '解除匹配',
confirmText: '确认解除',
danger: true,
buildContent: (name) => `解除与 ${name || '对方'} 的匹配后,你们的会话将立即停用,历史记录保留但不可继续发送消息。此操作不可撤销。`,
},
[DANGER_ACTION.PAUSE]: {
title: '暂停寻找',
confirmText: '暂停寻找',
danger: false,
buildContent: () => '暂停后你将不再被推荐给他人,也无法收到新的喜欢提示。可随时恢复。',
},
[DANGER_ACTION.SUCCESS_MATCH]: {
title: '成功牵手',
confirmText: '发起牵手请求',
danger: false,
buildContent: (name) => `发起牵手请求后,${name || '对方'} 需在 7 天内确认。双方均确认后关系将置为"成功牵手",平台将不再为你推荐其他人。`,
},
[DANGER_ACTION.LOGOUT]: {
title: '退出登录',
confirmText: '确认退出',
danger: false,
buildContent: () => '退出后需重新通过微信登录。本地未同步的草稿可能丢失。',
},
[DANGER_ACTION.CLOSE_ACCOUNT]: {
title: '关闭账号',
confirmText: '申请关闭',
danger: true,
buildContent: () => '关闭账号后你的资料将进入 30 天冷静期,期间可联系客服恢复;超过冷静期将永久删除并不可恢复。',
},
};
Component({
options: { addGlobalClass: true },
properties: {
visible: { type: Boolean, value: false },
action: { type: String, value: 'block' },
targetName: { type: String, value: '' },
},
data: {
config: null,
},
observers: {
action(action) {
this.setData({ config: ACTION_CONFIG[action] || ACTION_CONFIG[DANGER_ACTION.BLOCK] });
},
'targetName'(name) {
// 重新计算 content
const cfg = this.data.config;
if (cfg && cfg.buildContent) {
this.setData({
config: { ...cfg, content: cfg.buildContent(name) },
});
}
},
},
lifetimes: {
attached() {
const action = this.data.action;
const cfg = ACTION_CONFIG[action] || ACTION_CONFIG[DANGER_ACTION.BLOCK];
this.setData({
config: { ...cfg, content: cfg.buildContent(this.data.targetName) },
});
},
},
methods: {
onConfirm() {
this.triggerEvent('confirm', { action: this.data.action });
},
onCancel() {
this.triggerEvent('cancel', { action: this.data.action });
},
onStop() {
// 阻止冒泡到 mask
},
},
});
@@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"ui-button": "../button/index"
}
}
@@ -0,0 +1,20 @@
<view wx:if="{{visible}}" class="ui-dialog-mask" catchtap="onCancel">
<view class="ui-dialog" catchtap="onStop">
<view class="ui-dialog__title">{{config.title}}</view>
<view class="ui-dialog__content">{{config.content}}</view>
<view class="ui-dialog__actions">
<ui-button
variant="ghost"
size="md"
class="ui-dialog__btn"
bindtap="onCancel"
>取消</ui-button>
<ui-button
variant="{{config.danger ? 'danger' : 'primary'}}"
size="md"
class="ui-dialog__btn"
bindtap="onConfirm"
>{{config.confirmText}}</ui-button>
</view>
</view>
</view>
@@ -0,0 +1,47 @@
.ui-dialog-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-dialog {
width: 100%;
max-width: 600rpx;
background: var(--color-bg-card);
border-radius: var(--radius-lg);
padding: var(--spacing-5) var(--spacing-4) var(--spacing-4);
box-shadow: var(--shadow-popup);
animation: ui-dialog-in var(--motion-normal) var(--ease-standard);
}
@keyframes ui-dialog-in {
from { transform: scale(0.92); opacity: 0; }
to { transform: scale(1); opacity: 1; }
}
.ui-dialog__title {
font-size: var(--font-size-xl);
font-weight: var(--font-weight-semibold);
color: var(--color-text-primary);
text-align: center;
margin-bottom: var(--spacing-3);
}
.ui-dialog__content {
font-size: var(--font-size-md);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
text-align: center;
margin-bottom: var(--spacing-5);
}
.ui-dialog__actions {
display: flex;
gap: var(--spacing-2);
}
.ui-dialog__btn {
flex: 1;
}