From a3dd704d29a3b6fda7dd36a88f9c4102279003a4 Mon Sep 17 00:00:00 2001 From: ltx <1006158920@qq.com> Date: Tue, 14 Apr 2026 16:17:38 +0800 Subject: [PATCH] =?UTF-8?q?update=EF=BC=9A=E8=B5=9B=E4=BA=8B=E8=AF=A6?= =?UTF-8?q?=E6=83=85&=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/apply/apply.js | 79 +++++++++++++----------- pages/detail/detail.js | 106 +++++++++++++++++++++++++++++--- pages/detail/detail.wxml | 11 ++-- subpackages/mine/auth/auth.js | 7 ++- subpackages/mine/auth/auth.wxml | 4 +- 5 files changed, 154 insertions(+), 53 deletions(-) diff --git a/pages/apply/apply.js b/pages/apply/apply.js index 55f57ed..2acce61 100644 --- a/pages/apply/apply.js +++ b/pages/apply/apply.js @@ -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); diff --git a/pages/detail/detail.js b/pages/detail/detail.js index baed391..1a0e21b 100644 --- a/pages/detail/detail.js +++ b/pages/detail/detail.js @@ -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; } diff --git a/pages/detail/detail.wxml b/pages/detail/detail.wxml index dc84993..c4b9c3c 100644 --- a/pages/detail/detail.wxml +++ b/pages/detail/detail.wxml @@ -19,11 +19,14 @@ 收费模式: {{feeModeLabel}} - + + {{priceDisplayText}} + + ¥ {{priceDisplay}} - i + i @@ -151,9 +154,9 @@ diff --git a/subpackages/mine/auth/auth.js b/subpackages/mine/auth/auth.js index 82e9d7a..b603c8b 100644 --- a/subpackages/mine/auth/auth.js +++ b/subpackages/mine/auth/auth.js @@ -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 }; } diff --git a/subpackages/mine/auth/auth.wxml b/subpackages/mine/auth/auth.wxml index 0c1f0b1..b96a6e6 100644 --- a/subpackages/mine/auth/auth.wxml +++ b/subpackages/mine/auth/auth.wxml @@ -59,7 +59,7 @@ 护照号码 - +