update:赛事详情&提示
This commit is contained in:
parent
00a157e7b5
commit
a3dd704d29
@ -257,7 +257,7 @@ Page({
|
||||
})
|
||||
.then((detail) => {
|
||||
const es = getEventStatus(detail);
|
||||
console.log( 'es', es);
|
||||
console.log('es', es);
|
||||
if (es !== null && es !== 1) {
|
||||
wx.showToast({ title: toastForBlockedEventStatus(es), icon: 'none' });
|
||||
setTimeout(() => {
|
||||
@ -292,16 +292,15 @@ Page({
|
||||
.then((res) => {
|
||||
const d = res && typeof res === 'object' ? res : null;
|
||||
const birthDate = d ? (d.birthDate || d.birthday || '') : '';
|
||||
console.log('birthDate', birthDate);
|
||||
if (!birthDate) {
|
||||
wx.showModal({
|
||||
title: '需先完成认证',
|
||||
content: '报名个人项目需要先完成身份认证(用于校验年龄与性别限制)。',
|
||||
confirmText: '去个人中心',
|
||||
cancelText: '取消',
|
||||
success: (r) => {
|
||||
content: '报名个人项目需要先完成身份认证。',
|
||||
success(r) {
|
||||
if (r.confirm) wx.switchTab({ url: '/pages/mine/mine' });
|
||||
}
|
||||
});
|
||||
})
|
||||
this.setData({ myAuth: null });
|
||||
return null;
|
||||
}
|
||||
@ -312,7 +311,6 @@ Page({
|
||||
wx.showModal({
|
||||
title: '获取认证信息失败',
|
||||
content: '请稍后重试,或前往个人中心完成认证。',
|
||||
confirmText: '去个人中心',
|
||||
cancelText: '取消',
|
||||
success: (r) => {
|
||||
if (r.confirm) wx.switchTab({ url: '/pages/mine/mine' });
|
||||
@ -392,7 +390,7 @@ Page({
|
||||
wx.showModal({
|
||||
title: '换取 openid 失败',
|
||||
content: `请确认后端接口路径:${API.wechatOpenidByJsCode}\n\n可临时复制 code 给服务端调试:\n${code}`,
|
||||
confirmText: '复制 code',
|
||||
confirmText: '复制',
|
||||
cancelText: '关闭',
|
||||
success: (r) => {
|
||||
if (r.confirm) wx.setClipboardData({ data: code });
|
||||
@ -412,8 +410,15 @@ Page({
|
||||
onGroupTap(e) {
|
||||
const { projectId, groupId } = e.currentTarget.dataset;
|
||||
if (!this.data.myAuth) {
|
||||
wx.showToast({ title: '请先完成身份认证', icon: 'none' });
|
||||
wx.switchTab({ url: '/pages/mine/mine' });
|
||||
console.log('myAuth', this.data.myAuth);
|
||||
wx.showModal({
|
||||
title: '需先完成认证',
|
||||
content: '报名个人项目需要先完成身份认证。',
|
||||
cancelText: '取消',
|
||||
success: (r) => {
|
||||
if (r.confirm) wx.switchTab({ url: '/pages/mine/mine' });
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@ -506,7 +511,7 @@ Page({
|
||||
_recalcAmountNow() {
|
||||
const items = buildCalculateAmountItems(this.data.projectGroups);
|
||||
if (!items.length) {
|
||||
this.setData({
|
||||
this.setData({
|
||||
totalPrice: 0,
|
||||
originalPrice: 0,
|
||||
discountPrice: 0,
|
||||
@ -529,11 +534,11 @@ Page({
|
||||
})
|
||||
.then((res) => {
|
||||
if (seq !== this._calcSeq) return;
|
||||
|
||||
|
||||
let totalAmount = null;
|
||||
let originalPrice = 0;
|
||||
let discountPrice = 0;
|
||||
|
||||
|
||||
if (typeof res === 'number') {
|
||||
totalAmount = res;
|
||||
originalPrice = res;
|
||||
@ -543,23 +548,23 @@ Page({
|
||||
originalPrice = totalAmount || 0;
|
||||
} else if (res && typeof res === 'object') {
|
||||
// 从统一的 CalculateAmountOutput 中获取数据
|
||||
totalAmount = res.totalAmount != null ? Number(res.totalAmount) :
|
||||
(res.amount != null ? Number(res.amount) :
|
||||
(res.payAmount != null ? Number(res.payAmount) : null));
|
||||
totalAmount = res.totalAmount != null ? Number(res.totalAmount) :
|
||||
(res.amount != null ? Number(res.amount) :
|
||||
(res.payAmount != null ? Number(res.payAmount) : null));
|
||||
originalPrice = res.originalAmount != null ? Number(res.originalAmount) : totalAmount || 0;
|
||||
discountPrice = res.discountAmount != null ? Number(res.discountAmount) : 0;
|
||||
}
|
||||
|
||||
|
||||
if (totalAmount == null) {
|
||||
// fallback:仍然展示前端计算的费用,避免空白
|
||||
const fallbackPrice = calcTotalPrice(this.data.projectGroups);
|
||||
this.setData({
|
||||
this.setData({
|
||||
totalPrice: fallbackPrice,
|
||||
originalPrice: fallbackPrice,
|
||||
discountPrice: 0
|
||||
});
|
||||
} else {
|
||||
this.setData({
|
||||
this.setData({
|
||||
totalPrice: totalAmount,
|
||||
originalPrice: originalPrice || totalAmount,
|
||||
discountPrice: discountPrice || 0
|
||||
@ -569,7 +574,7 @@ Page({
|
||||
.catch(() => {
|
||||
if (seq !== this._calcSeq) return;
|
||||
const fallbackPrice = calcTotalPrice(this.data.projectGroups);
|
||||
this.setData({
|
||||
this.setData({
|
||||
totalPrice: fallbackPrice,
|
||||
originalPrice: fallbackPrice,
|
||||
discountPrice: 0
|
||||
@ -617,9 +622,9 @@ Page({
|
||||
wx.showToast({ title: res.invalidReason || '优惠券无效', icon: 'none' });
|
||||
}
|
||||
} catch (error) {
|
||||
wx.showToast({
|
||||
title: error && error.message ? error.message : '验证失败,请稍后重试',
|
||||
icon: 'none'
|
||||
wx.showToast({
|
||||
title: error && error.message ? error.message : '验证失败,请稍后重试',
|
||||
icon: 'none'
|
||||
});
|
||||
} finally {
|
||||
wx.hideLoading();
|
||||
@ -699,21 +704,21 @@ Page({
|
||||
// 2. 提交报名
|
||||
this.setData({ submitting: true });
|
||||
const registrationId = await this._submitApplyForPayment(payload);
|
||||
|
||||
|
||||
// 3. 选择支付方式并获取支付参数
|
||||
await this._selectPaymentMethod(registrationId, openid, 2);
|
||||
|
||||
|
||||
// 4. 获取支付信息
|
||||
const paymentInfo = await this._getPaymentInfo(registrationId, openid);
|
||||
|
||||
|
||||
// 5. 调起微信支付
|
||||
await this._invokeWeChatPay(paymentInfo.wechatPayParams, registrationId);
|
||||
|
||||
|
||||
} catch (error) {
|
||||
console.error('支付流程异常:', error);
|
||||
wx.showToast({
|
||||
title: error && error.message ? error.message : '支付失败,请稍后重试',
|
||||
icon: 'none'
|
||||
wx.showToast({
|
||||
title: error && error.message ? error.message : '支付失败,请稍后重试',
|
||||
icon: 'none'
|
||||
});
|
||||
} finally {
|
||||
this.setData({ submitting: false });
|
||||
@ -737,7 +742,7 @@ Page({
|
||||
reject(new Error('未获取到 code'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
request({
|
||||
path: API.wechatOpenidByJsCode,
|
||||
method: 'POST',
|
||||
@ -799,8 +804,8 @@ Page({
|
||||
path: '/api/eventclient/payment-info',
|
||||
method: 'POST',
|
||||
needAuth: true,
|
||||
data: {
|
||||
registrationId,
|
||||
data: {
|
||||
registrationId,
|
||||
openId: openid,
|
||||
couponId: this.data.usedCouponId
|
||||
},
|
||||
@ -823,7 +828,7 @@ Page({
|
||||
data: {},
|
||||
contentType: 'application/json'
|
||||
});
|
||||
|
||||
|
||||
wx.showToast({ title: '支付成功', icon: 'success' });
|
||||
setTimeout(() => {
|
||||
wx.switchTab({ url: '/pages/mine/mine' });
|
||||
@ -847,9 +852,9 @@ Page({
|
||||
if (err.errMsg && err.errMsg.includes('cancel')) {
|
||||
wx.showToast({ title: '支付已取消', icon: 'none' });
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: err.errMsg || '支付失败,请稍后重试',
|
||||
icon: 'none'
|
||||
wx.showToast({
|
||||
title: err.errMsg || '支付失败,请稍后重试',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
reject(err);
|
||||
|
||||
@ -61,6 +61,19 @@ function parseEventStatus(rawDetail) {
|
||||
return Number.isNaN(n) ? null : n;
|
||||
}
|
||||
|
||||
/**
|
||||
* registrationType(产品定义)
|
||||
* 0: 只允许团队报名
|
||||
* 1: 只允许团队报名(需从用户后台报名,本端不可报名)
|
||||
* 2: 个人/团队报名
|
||||
*/
|
||||
function parseRegistrationType(rawDetail) {
|
||||
const v = pick(rawDetail, ['registrationType', 'RegistrationType']);
|
||||
if (v == null || v === '') return null;
|
||||
const n = Number(v);
|
||||
return Number.isNaN(n) ? null : n;
|
||||
}
|
||||
|
||||
function applyUiFromEventStatus(es) {
|
||||
if (es == null) {
|
||||
return { canApply: true, applyButtonText: '报名' };
|
||||
@ -99,6 +112,14 @@ function registrationModeText(mode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function registrationTypeText(regType) {
|
||||
const m = regType === undefined || regType === null ? null : Number(regType);
|
||||
if (m === 0) return '只允许个人报名';
|
||||
if (m === 1) return '只允许团队报名(后台报名)';
|
||||
if (m === 2) return '个人/团队报名';
|
||||
return null;
|
||||
}
|
||||
|
||||
function formatRange(start, end) {
|
||||
const a = formatDateTime(start);
|
||||
const b = formatDateTime(end);
|
||||
@ -203,15 +224,27 @@ function normalizeEventDetail(raw) {
|
||||
const d = raw && typeof raw === 'object' ? raw : {};
|
||||
const projects = Array.isArray(d.projects) ? d.projects : Array.isArray(d.Projects) ? d.Projects : [];
|
||||
|
||||
const registrationType = pick(d, ['registrationType', 'RegistrationType']);
|
||||
const registrationMethodText =
|
||||
pick(d, [
|
||||
'registrationMethodText',
|
||||
'RegistrationMethodText',
|
||||
'registrationMethodDescription',
|
||||
'RegistrationMethodDescription'
|
||||
]) || registrationModeText(pick(d, ['registrationMode', 'RegistrationMode']));
|
||||
]) ||
|
||||
registrationTypeText(registrationType) ||
|
||||
registrationModeText(pick(d, ['registrationMode', 'RegistrationMode']));
|
||||
|
||||
const feeModeLabel =d.chargeMode == 0 ? '免费' : d.chargeMode == 1 ? '定价模式(赛事)' : d.chargeMode == 2 ? '单价(赛事)' : '单价(项目)';
|
||||
const chargeModeRaw = pick(d, ['chargeMode', 'ChargeMode']);
|
||||
const chargeMode = chargeModeRaw == null || chargeModeRaw === '' ? null : Number(chargeModeRaw);
|
||||
const feeModeLabel =
|
||||
chargeMode === 0
|
||||
? '免费'
|
||||
: chargeMode === 1
|
||||
? '定价模式(赛事)'
|
||||
: chargeMode === 2
|
||||
? '单价(赛事)'
|
||||
: '单价(项目)';
|
||||
let priceDisplay = d && d.feeConfig ? d.feeConfig.price : null;
|
||||
if (priceDisplay == null && projects.length) {
|
||||
const fees = projects.map((p) => p.fee).filter((f) => f != null && f !== '');
|
||||
@ -221,6 +254,13 @@ function normalizeEventDetail(raw) {
|
||||
}
|
||||
}
|
||||
|
||||
// chargeMode=3 单价(项目):价格展示固定为提示文案
|
||||
let priceDisplayText = null;
|
||||
if (chargeMode === 3) {
|
||||
priceDisplayText = '价格见下方项目详情';
|
||||
priceDisplay = null;
|
||||
}
|
||||
|
||||
const materialRangeText =
|
||||
pick(d, ['materialUploadDeadlineText', 'MaterialUploadDeadlineText']) ||
|
||||
formatRange(
|
||||
@ -313,6 +353,7 @@ function normalizeEventDetail(raw) {
|
||||
registrationMethodText,
|
||||
feeModeLabel: feeModeLabel || '定价模式(赛事)',
|
||||
priceDisplay,
|
||||
priceDisplayText,
|
||||
materialRangeText,
|
||||
refundRulesText,
|
||||
participationPointsLabel,
|
||||
@ -340,6 +381,7 @@ Page({
|
||||
registrationMethodText: '',
|
||||
feeModeLabel: '',
|
||||
priceDisplay: null,
|
||||
priceDisplayText: '',
|
||||
materialRangeText: '',
|
||||
refundRulesText: '',
|
||||
participationPointsLabel: '',
|
||||
@ -357,7 +399,13 @@ Page({
|
||||
unitGroups: [],
|
||||
/** 0未开始 1报名中 2报名结束 3比赛中 4已结束;null 表示接口未返回 */
|
||||
eventStatus: null,
|
||||
canApply: true,
|
||||
registrationType: null,
|
||||
/** 是否灰态展示(不等同于 disabled) */
|
||||
applyGrey: false,
|
||||
/** 是否原生禁用(禁用后无法点击) */
|
||||
applyDisabled: false,
|
||||
/** 是否被“需后台报名”规则拦截(按钮灰但可点,点后弹窗引导) */
|
||||
applyBlockedByAdmin: false,
|
||||
applyButtonText: '报名'
|
||||
},
|
||||
|
||||
@ -444,6 +492,7 @@ Page({
|
||||
var registrationMethodText = n.registrationMethodText || fb.registrationMethodText;
|
||||
var feeModeLabel = n.feeModeLabel || fb.feeModeLabel;
|
||||
var priceDisplay = n.priceDisplay != null ? n.priceDisplay : fb.priceDisplay;
|
||||
var priceDisplayText = n.priceDisplayText || '';
|
||||
|
||||
var materialRangeText = n.materialRangeText || fb.materialRangeText;
|
||||
|
||||
@ -496,6 +545,34 @@ Page({
|
||||
|
||||
const eventStatus = parseEventStatus(detail);
|
||||
const { canApply, applyButtonText } = applyUiFromEventStatus(eventStatus);
|
||||
const registrationType = parseRegistrationType(detail);
|
||||
|
||||
// 报名按钮逻辑:eventStatus 先拦截;再按 registrationType 决定是否可在小程序端报名
|
||||
let applyDisabled = !canApply; // 原生禁用:不可点
|
||||
let applyGrey = !canApply; // 灰态:视觉置灰
|
||||
let applyBlockedByAdmin = false;
|
||||
let finalApplyButtonText = applyButtonText;
|
||||
|
||||
// 只有 registrationType 为 0 或 2 才允许报名;为 1 时灰态但可点,点击引导去后台
|
||||
if (canApply) {
|
||||
if (registrationType === 1) {
|
||||
applyDisabled = false;
|
||||
applyGrey = true;
|
||||
applyBlockedByAdmin = true;
|
||||
finalApplyButtonText = '报名';
|
||||
} else if (registrationType === 0 || registrationType === 2 || registrationType == null) {
|
||||
applyDisabled = false;
|
||||
applyGrey = false;
|
||||
applyBlockedByAdmin = false;
|
||||
finalApplyButtonText = '报名';
|
||||
} else {
|
||||
// 未知值:保守拦截
|
||||
applyDisabled = true;
|
||||
applyGrey = true;
|
||||
applyBlockedByAdmin = false;
|
||||
finalApplyButtonText = '暂不可报名';
|
||||
}
|
||||
}
|
||||
|
||||
this.setData({
|
||||
eventDetail: detail,
|
||||
@ -512,6 +589,7 @@ Page({
|
||||
registrationMethodText,
|
||||
feeModeLabel,
|
||||
priceDisplay,
|
||||
priceDisplayText,
|
||||
materialRangeText,
|
||||
uploadMaterialRemark,
|
||||
refundRulesText,
|
||||
@ -524,15 +602,20 @@ Page({
|
||||
projectTableRows,
|
||||
unitGroups,
|
||||
eventStatus,
|
||||
canApply,
|
||||
applyButtonText
|
||||
registrationType,
|
||||
applyGrey,
|
||||
applyDisabled,
|
||||
applyBlockedByAdmin,
|
||||
applyButtonText: finalApplyButtonText
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
// wx.showToast({ title: err.Error, icon: 'none' });
|
||||
// console.log('Detail fetchDetail error:', err);
|
||||
this.setData({
|
||||
canApply: false,
|
||||
applyGrey: true,
|
||||
applyDisabled: true,
|
||||
applyBlockedByAdmin: false,
|
||||
applyButtonText: '暂不可报名'
|
||||
});
|
||||
});
|
||||
@ -541,7 +624,16 @@ Page({
|
||||
onApplyTap() {
|
||||
const id = this.data.id;
|
||||
if (!id) return;
|
||||
if (!this.data.canApply) {
|
||||
if (this.data.applyBlockedByAdmin) {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '该赛事需从用户后台进行报名',
|
||||
showCancel: false,
|
||||
confirmText: '我知道了'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (this.data.applyDisabled) {
|
||||
wx.showToast({ title: toastForEventStatus(this.data.eventStatus), icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
@ -19,11 +19,14 @@
|
||||
<text class="info-label">收费模式:</text>
|
||||
<view class="info-value info-value--fee">
|
||||
<text class="info-value-txt">{{feeModeLabel}}</text>
|
||||
<view wx:if="{{priceDisplay != null}}" class="fee-inline">
|
||||
<view wx:if="{{priceDisplayText}}" class="fee-inline">
|
||||
<text class="fee-digits">{{priceDisplayText}}</text>
|
||||
</view>
|
||||
<view wx:elif="{{priceDisplay != null}}" class="fee-inline">
|
||||
<text class="fee-currency">¥</text>
|
||||
<text class="fee-digits">{{priceDisplay}}</text>
|
||||
</view>
|
||||
<view class="info-i" wx:if="{{priceDisplay != null}}">i</view>
|
||||
<view class="info-i" wx:if="{{priceDisplay != null || priceDisplayText}}">i</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
@ -151,9 +154,9 @@
|
||||
|
||||
<view class="bottom-bar">
|
||||
<button
|
||||
class="apply-btn {{canApply ? '' : 'apply-btn--disabled'}}"
|
||||
class="apply-btn {{applyGrey ? 'apply-btn--disabled' : ''}}"
|
||||
type="primary"
|
||||
disabled="{{!canApply}}"
|
||||
disabled="{{applyDisabled}}"
|
||||
bindtap="onApplyTap"
|
||||
>{{applyButtonText}}</button>
|
||||
</view>
|
||||
|
||||
@ -215,7 +215,7 @@ Page({
|
||||
name: (ocr && ocr.name) || '',
|
||||
passportNumber: (ocr && ocr.passportNumber) || '',
|
||||
nationality: (ocr && ocr.nationality) || '',
|
||||
birthDate: (ocr && (ocr.birthDate || ocr.birthDateYmd)) || '',
|
||||
birthDate: (ocr && (ocr.birthDateYmd || ocr.birthDate)) || '',
|
||||
issueDate: (ocr && (ocr.issueDate || ocr.issueDateYmd)) || '',
|
||||
expiryDate: (ocr && (ocr.expiryDate || ocr.validToDate)) || '',
|
||||
genderIndex,
|
||||
@ -292,7 +292,7 @@ Page({
|
||||
const {
|
||||
activeTab, idCardImageUrl, passportImageUrl,
|
||||
name, idCardNumber, birthDate,
|
||||
genderOptions, genderIndex, mobile, verificationCode,idCardBackImageUrl
|
||||
genderOptions, genderIndex, mobile, verificationCode,idCardBackImageUrl,passportNumber
|
||||
} = this.data;
|
||||
|
||||
if (!name) {
|
||||
@ -347,7 +347,8 @@ Page({
|
||||
smsCode: verificationCode,
|
||||
gender: genderValue,
|
||||
birthDate,
|
||||
passportPhotoUrl: passportImageUrl
|
||||
passportPhotoUrl: passportImageUrl,
|
||||
idCardNumber:passportNumber
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -59,7 +59,7 @@
|
||||
<text class="label">护照号码</text>
|
||||
<input class="input readonly" value="{{passportNumber}}" placeholder="上传护照后自动识别" disabled="{{true}}" />
|
||||
</view>
|
||||
<view class="form-row">
|
||||
<!-- <view class="form-row">
|
||||
<text class="label">国籍</text>
|
||||
<input class="input readonly" value="{{nationality}}" placeholder="上传护照后自动识别" disabled="{{true}}" />
|
||||
</view>
|
||||
@ -70,7 +70,7 @@
|
||||
<view class="form-row">
|
||||
<text class="label">有效期至</text>
|
||||
<input class="input readonly" value="{{expiryDate}}" placeholder="上传护照后自动识别" disabled="{{true}}" />
|
||||
</view>
|
||||
</view> -->
|
||||
</block>
|
||||
<!-- 通用字段 -->
|
||||
<view class="form-row">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user