mini
All checks were successful
Deploy to Server / deploy (push) Successful in 40s

This commit is contained in:
jeremygan2021
2026-02-24 00:31:57 +08:00
parent 0d01a5f2a8
commit 441e080328
15 changed files with 535 additions and 106 deletions

View File

@@ -373,3 +373,49 @@
}
}
}
/* Signup Form Styles */
.signup-form {
.form-field-wrapper {
&.custom-field {
padding: 12px 24px;
position: relative;
background-color: #fff; /* Ensure white background inside modal */
&::after {
content: '';
position: absolute;
bottom: 0;
left: 24px;
right: 0;
height: 1px;
background-color: #f0f0f0;
transform: scaleY(0.5);
}
.field-label {
font-size: 28px;
color: #333;
margin-bottom: 16px;
.required {
color: #ff4949;
margin-right: 4px;
}
}
.at-radio::before, .at-radio::after,
.at-checkbox::before, .at-checkbox::after,
.at-textarea::after {
display: none;
}
.at-textarea {
padding: 0;
background: transparent;
border: none;
}
}
}
}

View File

@@ -1,7 +1,7 @@
import React, { useState, useEffect } from 'react'
import Taro, { useRouter, useShareAppMessage, useShareTimeline, useDidShow } from '@tarojs/taro'
import { View, Text, Image, Button, RichText } from '@tarojs/components'
import { AtIcon, AtProgress, AtModal, AtModalHeader, AtModalContent, AtModalAction, AtInput } from 'taro-ui'
import { View, Text, Image, Button, RichText, Picker } from '@tarojs/components'
import { AtIcon, AtProgress, AtModal, AtModalHeader, AtModalContent, AtModalAction, AtInput, AtTextarea, AtRadio, AtCheckbox } from 'taro-ui'
import { getActivityDetail, signupActivity } from '../../../api'
import { marked } from 'marked'
import './detail.scss'
@@ -79,6 +79,12 @@ const ActivityDetail = () => {
setShowSignupModal(true)
return
}
// Check if already unpaid (resume payment)
if (activity.my_signup_status === 'unpaid' && activity.my_order_id) {
Taro.navigateTo({ url: `/pages/order/payment?id=${activity.my_order_id}` })
return
}
// Direct signup if no config
submitSignup({})
@@ -87,7 +93,18 @@ const ActivityDetail = () => {
const submitSignup = async (data: any) => {
setSubmitting(true)
try {
await signupActivity(Number(id), { signup_info: data })
const res = await signupActivity(Number(id), { signup_info: data })
// Handle payment if order_id is returned
if (res.order_id) {
Taro.showToast({ title: '即将跳转支付', icon: 'none' })
setShowSignupModal(false)
setTimeout(() => {
Taro.navigateTo({ url: `/pages/order/payment?id=${res.order_id}` })
}, 1500)
return
}
Taro.showToast({ title: '报名成功', icon: 'success' })
setShowSignupModal(false)
fetchDetail() // Refresh status
@@ -224,7 +241,9 @@ const ActivityDetail = () => {
{/* Footer Action Bar */}
<View className='footer-action-bar'>
<View className='left-info'>
<Text className='price'></Text>
<Text className='price'>
{Number(activity.price) > 0 ? `¥${activity.price}` : '免费'}
</Text>
<Text className='desc'></Text>
</View>
<Button
@@ -251,18 +270,100 @@ const ActivityDetail = () => {
<AtModalHeader></AtModalHeader>
<AtModalContent>
<View className='signup-form'>
{activity.signup_form_config && activity.signup_form_config.map((field, idx) => (
<AtInput
key={idx}
name={field.name}
title={field.label}
type={field.type || 'text'}
placeholder={`请输入${field.label}`}
value={formData[field.name]}
onChange={(val) => handleFormChange(field.name, val)}
required={field.required}
/>
))}
{activity.signup_form_config && activity.signup_form_config.map((field, idx) => {
if (field.type === 'select') {
const currentOption = field.options?.find(opt => opt.value === formData[field.name])
return (
<View key={idx} className='form-field-wrapper'>
<Picker
mode='selector'
range={field.options || []}
rangeKey='label'
onChange={(e) => {
const index = e.detail.value
const selected = field.options?.[index]
if (selected) {
handleFormChange(field.name, selected.value)
}
}}
>
<AtInput
name={field.name}
title={field.label}
type='text'
placeholder={field.placeholder || `请选择${field.label}`}
value={currentOption ? currentOption.label : ''}
editable={false}
required={field.required}
/>
</Picker>
</View>
)
}
if (field.type === 'radio') {
return (
<View key={idx} className='form-field-wrapper custom-field'>
<View className='field-label'>
{field.required && <Text className='required'>*</Text>}
{field.label}
</View>
<AtRadio
options={field.options || []}
value={formData[field.name]}
onClick={(val) => handleFormChange(field.name, val)}
/>
</View>
)
}
if (field.type === 'checkbox') {
return (
<View key={idx} className='form-field-wrapper custom-field'>
<View className='field-label'>
{field.required && <Text className='required'>*</Text>}
{field.label}
</View>
<AtCheckbox
options={field.options || []}
selectedList={formData[field.name] || []}
onChange={(val) => handleFormChange(field.name, val)}
/>
</View>
)
}
if (field.type === 'textarea') {
return (
<View key={idx} className='form-field-wrapper custom-field'>
<View className='field-label'>
{field.required && <Text className='required'>*</Text>}
{field.label}
</View>
<AtTextarea
value={formData[field.name] || ''}
onChange={(val) => handleFormChange(field.name, val)}
placeholder={field.placeholder || `请输入${field.label}`}
maxLength={500}
/>
</View>
)
}
return (
<View key={idx} className='form-field-wrapper'>
<AtInput
name={field.name}
title={field.label}
type={field.type === 'tel' ? 'phone' : (field.type === 'number' ? 'number' : 'text')}
placeholder={field.placeholder || `请输入${field.label}`}
value={formData[field.name]}
onChange={(val) => handleFormChange(field.name, val)}
required={field.required}
/>
</View>
)
})}
</View>
</AtModalContent>
<AtModalAction>