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,71 @@
/**
* 账号受限页 U48
* 展示当前限制状态、原因,以及申诉入口
*/
const api = require('../../utils/api');
Page({
data: {
hasRestriction: false,
accountStatus: 'normal',
actions: [],
canAppeal: false,
appealEnabled: false,
loading: true
},
onLoad() {
this.loadStatus();
},
onShow() {
this.loadStatus();
},
async loadStatus() {
this.setData({ loading: true });
try {
const token = wx.getStorageSync('accessToken');
const res = await api.get('/appeals/account-status', {}, {
Authorization: `Bearer ${token}`
});
this.setData({
hasRestriction: res.hasRestriction,
accountStatus: res.accountStatus,
actions: res.actions || [],
canAppeal: res.canAppeal,
appealEnabled: res.appealEnabled,
loading: false
});
} catch (err) {
console.error(err);
this.setData({ loading: false });
}
},
goAppeal(e) {
const action = e.currentTarget.dataset.action;
wx.navigateTo({
url: `/pages/appeal/appeal?type=${action.appealType}&actionId=${action.id}`
});
},
goHelp() {
wx.navigateTo({ url: '/pages/help-center/help-center' });
},
statusText(s) {
const map = { banned: '已封禁', suspended: '临时暂停', limited: '功能限制' };
return map[s] || s;
},
actionTypeText(t) {
const map = { ban: '永久封禁', feature_limit: '功能限制', temporary_suspend: '临时暂停', warning: '警告' };
return map[t] || t;
},
formatTime(t) {
if (!t) return '-';
return new Date(t).toLocaleDateString('zh-CN');
}
});
@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "账号状态",
"usingComponents": {}
}
@@ -0,0 +1,47 @@
<!-- 账号受限页 U48 -->
<view class="page" wx:if="{{!loading}}">
<view class="status-banner" wx:if="{{hasRestriction}}">
<view class="banner-icon">⚠</view>
<text class="banner-title">账号受限</text>
<text class="banner-status">{{statusText(accountStatus)}}</text>
</view>
<view wx:if="{{!hasRestriction}}" class="normal-state">
<view class="normal-icon">✓</view>
<text class="normal-title">账号状态正常</text>
<text class="normal-hint">您的账号目前无限制,可以正常使用所有功能。</text>
</view>
<view class="actions-list" wx:if="{{hasRestriction && actions.length > 0}}">
<view class="action-card" wx:for="{{actions}}" wx:key="id">
<view class="action-header">
<text class="action-type">{{actionTypeText(item.actionType)}}</text>
<text class="action-time">{{formatTime(item.effectiveAt)}}</text>
</view>
<text class="action-reason">{{item.reason}}</text>
<text class="action-expiry" wx:if="{{item.expiresAt}}">
有效期至:{{formatTime(item.expiresAt)}}
</text>
<text class="action-expiry" wx:else>永久限制</text>
<button
wx:if="{{item.canAppeal && canAppeal}}"
class="btn-appeal"
data-action="{{item}}"
bindtap="goAppeal">
提交申诉
</button>
<text wx:if="{{item.canAppeal && !canAppeal && appealEnabled}}" class="appeal-hint">
该类型限制暂不支持在线申诉,请联系客服。
</text>
</view>
</view>
<view class="appeal-disabled" wx:if="{{hasRestriction && !appealEnabled}}">
<text class="disabled-hint">当前申诉功能暂未开放,如有疑问请联系客服。</text>
<button class="btn-contact" bindtap="goHelp">联系客服</button>
</view>
</view>
<view class="page loading-page" wx:if="{{loading}}">
<text>加载中...</text>
</view>
@@ -0,0 +1,156 @@
.page {
padding: 32rpx;
background: #FFF8F7;
min-height: 100vh;
}
.status-banner {
background: linear-gradient(135deg, #E96B6B 0%, #C44545 100%);
border-radius: 24rpx;
padding: 48rpx 32rpx;
text-align: center;
margin-bottom: 32rpx;
}
.banner-icon {
font-size: 72rpx;
display: block;
margin-bottom: 16rpx;
}
.banner-title {
font-size: 36rpx;
font-weight: bold;
color: #fff;
display: block;
}
.banner-status {
font-size: 26rpx;
color: rgba(255,255,255,0.85);
display: block;
margin-top: 12rpx;
}
.normal-state {
text-align: center;
padding: 80rpx 32rpx;
}
.normal-icon {
font-size: 80rpx;
color: #67C23A;
display: block;
margin-bottom: 24rpx;
}
.normal-title {
font-size: 32rpx;
font-weight: bold;
color: #1A1A1A;
display: block;
margin-bottom: 16rpx;
}
.normal-hint {
font-size: 26rpx;
color: #666;
display: block;
line-height: 1.6;
}
.actions-list {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.action-card {
background: #fff;
border-radius: 20rpx;
padding: 28rpx;
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.04);
}
.action-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16rpx;
}
.action-type {
font-size: 28rpx;
font-weight: bold;
color: #E96B6B;
}
.action-time {
font-size: 22rpx;
color: #BBB;
}
.action-reason {
font-size: 26rpx;
color: #666;
display: block;
margin-bottom: 12rpx;
line-height: 1.5;
}
.action-expiry {
font-size: 24rpx;
color: #E59A32;
display: block;
margin-bottom: 20rpx;
}
.btn-appeal {
width: 100%;
height: 72rpx;
line-height: 72rpx;
background: #FFF3F2;
color: #E96B6B;
border-radius: 36rpx;
font-size: 28rpx;
border: 1rpx solid #E96B6B;
}
.appeal-hint {
display: block;
font-size: 24rpx;
color: #999;
text-align: center;
margin-top: 16rpx;
}
.appeal-disabled {
text-align: center;
padding: 60rpx 32rpx;
background: #fff;
border-radius: 20rpx;
}
.disabled-hint {
font-size: 26rpx;
color: #999;
display: block;
margin-bottom: 24rpx;
}
.btn-contact {
width: 60%;
height: 72rpx;
line-height: 72rpx;
background: #E96B6B;
color: #fff;
border-radius: 36rpx;
font-size: 28rpx;
border: none;
}
.loading-page {
text-align: center;
padding: 100rpx;
color: #999;
}