release: freeze 2026-10-15 validated release baseline
CI/CD Pipeline / UI Contracts (source-structure gates) (push) Canceled after 0s
CI/CD Pipeline / E2E (live stack) (push) Canceled after 0s
CI/CD Pipeline / Backend Build & Test (push) Canceled after 0s
CI/CD Pipeline / Admin Web Build (push) Canceled after 0s
CI/CD Pipeline / Mini Program Compile Check (push) Canceled after 0s
CI/CD Pipeline / Migration Validation (push) Canceled after 0s
CI/CD Pipeline / Test Shell Guard (Phase 23 Gate) (push) Canceled after 0s

This commit is contained in:
WorkBuddy
2026-10-15 09:47:31 +08:00
parent 827c23db1d
commit 3c2b967274
149 changed files with 4324 additions and 348 deletions
@@ -0,0 +1,52 @@
const { referralService } = require('../../services');
const STATUS_LABEL = {
submitted: '待您确认',
pending_confirmation: '待您确认',
confirmed: '已确认',
cancelled: '已取消',
completed: '已完成',
};
Page({
data: { loading: true, error: '', referrals: [], confirmingId: '' },
onShow() { this.load(); },
async load() {
this.setData({ loading: true, error: '' });
try {
const list = await referralService.getMyReferralHistory();
this.setData({
referrals: (list || []).map((item) => ({
id: item.id,
referralDisplayId: item.referralDisplayId,
targetType: item.type,
title: item.type === 'activity' ? '公益活动转介' : '服务站转介',
detail: item.type === 'activity' ? (item.activityDisplayId || '公益活动') : (item.serviceType || '公益服务'),
status: item.userConfirmedAt ? 'confirmed' : (item.status || 'pending_confirmation'),
statusText: item.userConfirmedAt ? '已确认' : (STATUS_LABEL[item.status] || '待您确认'),
createdAt: item.createdAt || item.registeredAt || '',
})),
loading: false,
});
} catch (error) {
this.setData({ loading: false, error: (error && error.message) || '加载失败,请稍后重试' });
}
},
async confirm(e) {
const item = this.data.referrals[Number(e.currentTarget.dataset.index)];
if (!item || item.status === 'confirmed' || this.data.confirmingId) return;
this.setData({ confirmingId: item.id });
try {
await referralService.confirmReferral(item.id, item.targetType);
wx.showToast({ title: '已确认', icon: 'success' });
await this.load();
} catch (error) {
wx.showToast({ title: (error && error.message) || '确认失败,请重试', icon: 'none' });
} finally {
this.setData({ confirmingId: '' });
}
},
});
@@ -0,0 +1 @@
{"navigationBarTitleText":"公益服务确认","usingComponents":{}}
@@ -0,0 +1,12 @@
<view class="page">
<view class="hero"><text class="title">待确认的公益服务</text><text class="desc">红娘提供的服务建议,需要由你本人确认后才会生效。</text></view>
<view wx:if="{{loading}}" class="empty">正在加载</view>
<view wx:elif="{{error}}" class="empty">{{error}}</view>
<view wx:elif="{{referrals.length}}" class="list">
<view wx:for="{{referrals}}" wx:key="id" class="item">
<view class="item-main"><text class="item-title">{{item.title}}</text><text class="item-detail">转介编号:{{item.referralDisplayId}}</text><text class="item-detail">{{item.detail}}</text><text class="item-date">{{item.createdAt}}</text></view>
<view class="item-action"><text class="status">{{item.statusText}}</text><button wx:if="{{item.status !== 'confirmed'}}" size="mini" data-index="{{index}}" bindtap="confirm" loading="{{confirmingId === item.id}}">确认转介</button></view>
</view>
</view>
<view wx:else class="empty">暂无待确认的转介</view>
</view>
@@ -0,0 +1,11 @@
.page { min-height: 100vh; padding: 32rpx; background: var(--color-primary-lighter); box-sizing: border-box; }
.hero, .item { background: var(--color-bg-card); border-radius: 24rpx; padding: 28rpx; }
.hero { margin-bottom: 24rpx; }
.title, .item-title { display: block; color: var(--color-text-strong); font-weight: bold; font-size: 32rpx; }
.desc, .item-detail, .item-date, .status, .empty { display: block; color: var(--color-text-tertiary); font-size: 26rpx; line-height: 1.6; }
.desc { margin-top: 12rpx; }
.item { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20rpx; }
.item-detail, .item-date { margin-top: 8rpx; }
.item-action { display: flex; flex-direction: column; align-items: flex-end; gap: 12rpx; margin-left: 20rpx; }
.status { color: var(--color-primary-solid); white-space: nowrap; }
.empty { padding: 120rpx 20rpx; text-align: center; }