diff --git a/backend/config/settings.py b/backend/config/settings.py index 954dc43..664f04c 100644 --- a/backend/config/settings.py +++ b/backend/config/settings.py @@ -101,19 +101,7 @@ DATABASES = { #从环境变量获取数据库配置 (Docker 环境会自动注入这些变量。 -DB_HOST = os.environ.get('DB_HOST', '6.6.6.66') -if DB_HOST: - DATABASES['default'] = { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': os.environ.get('DB_NAME', 'market'), - 'USER': os.environ.get('DB_USER', 'market'), - 'PASSWORD': os.environ.get('DB_PASSWORD', '123market'), - 'HOST': DB_HOST, - 'PORT': os.environ.get('DB_PORT', '5432'), - } - - -# DB_HOST = os.environ.get('DB_HOST', '121.43.104.161') +# DB_HOST = os.environ.get('DB_HOST', '6.6.6.66') # if DB_HOST: # DATABASES['default'] = { # 'ENGINE': 'django.db.backends.postgresql', @@ -121,10 +109,22 @@ if DB_HOST: # 'USER': os.environ.get('DB_USER', 'market'), # 'PASSWORD': os.environ.get('DB_PASSWORD', '123market'), # 'HOST': DB_HOST, -# 'PORT': os.environ.get('DB_PORT', '6433'), +# 'PORT': os.environ.get('DB_PORT', '5432'), # } +DB_HOST = os.environ.get('DB_HOST', '121.43.104.161') +if DB_HOST: + DATABASES['default'] = { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': os.environ.get('DB_NAME', 'market'), + 'USER': os.environ.get('DB_USER', 'market'), + 'PASSWORD': os.environ.get('DB_PASSWORD', '123market'), + 'HOST': DB_HOST, + 'PORT': os.environ.get('DB_PORT', '6433'), + } + + # Password validation # https://docs.djangoproject.com/en/6.0/ref/settings/#auth-password-validators diff --git a/backend/shop/admin.py b/backend/shop/admin.py index 04e8ccf..f822092 100644 --- a/backend/shop/admin.py +++ b/backend/shop/admin.py @@ -235,6 +235,10 @@ class VCCourseAdmin(OrderableAdminMixin, ModelAdmin): ('基本信息', { 'fields': ('title', 'description', 'course_type', 'tag', 'price') }), + ('课程安排', { + 'fields': ('is_fixed_schedule', 'start_time', 'end_time'), + 'description': '勾选“是否固定时间课程”后,请设置开始和结束时间' + }), ('讲师信息', { 'fields': ('instructor', 'instructor_title', 'instructor_desc', 'instructor_avatar', 'instructor_avatar_url'), 'description': '讲师头像上传和URL二选一,优先使用URL' diff --git a/backend/shop/migrations/0033_vccourse_is_fixed_schedule_vccourse_schedule_time.py b/backend/shop/migrations/0033_vccourse_is_fixed_schedule_vccourse_schedule_time.py new file mode 100644 index 0000000..e529428 --- /dev/null +++ b/backend/shop/migrations/0033_vccourse_is_fixed_schedule_vccourse_schedule_time.py @@ -0,0 +1,23 @@ +# Generated by Django 6.0.1 on 2026-02-23 15:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('shop', '0032_order_activity'), + ] + + operations = [ + migrations.AddField( + model_name='vccourse', + name='is_fixed_schedule', + field=models.BooleanField(default=False, help_text='勾选后,前端将显示具体的开课时间', verbose_name='是否固定时间课程'), + ), + migrations.AddField( + model_name='vccourse', + name='schedule_time', + field=models.CharField(blank=True, help_text='例如:每周六晚 20:00', max_length=100, null=True, verbose_name='课程具体时间'), + ), + ] diff --git a/backend/shop/migrations/0034_remove_vccourse_schedule_time_vccourse_end_time_and_more.py b/backend/shop/migrations/0034_remove_vccourse_schedule_time_vccourse_end_time_and_more.py new file mode 100644 index 0000000..c5a9d49 --- /dev/null +++ b/backend/shop/migrations/0034_remove_vccourse_schedule_time_vccourse_end_time_and_more.py @@ -0,0 +1,27 @@ +# Generated by Django 6.0.1 on 2026-02-23 16:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('shop', '0033_vccourse_is_fixed_schedule_vccourse_schedule_time'), + ] + + operations = [ + migrations.RemoveField( + model_name='vccourse', + name='schedule_time', + ), + migrations.AddField( + model_name='vccourse', + name='end_time', + field=models.DateTimeField(blank=True, null=True, verbose_name='结束时间'), + ), + migrations.AddField( + model_name='vccourse', + name='start_time', + field=models.DateTimeField(blank=True, null=True, verbose_name='开始时间'), + ), + ] diff --git a/backend/shop/models.py b/backend/shop/models.py index 3447f8c..361e771 100644 --- a/backend/shop/models.py +++ b/backend/shop/models.py @@ -348,6 +348,11 @@ class VCCourse(models.Model): instructor_desc = models.TextField(blank=True, verbose_name="讲师简介", default="拥有多年开发经验,擅长...") tag = models.CharField(max_length=20, blank=True, verbose_name="标签", help_text="例如: 热门, 推荐, 进阶") + + # 课程时间安排 + is_fixed_schedule = models.BooleanField(default=False, verbose_name="是否固定时间课程", help_text="勾选后,前端将显示具体的开课时间") + start_time = models.DateTimeField(blank=True, null=True, verbose_name="开始时间") + end_time = models.DateTimeField(blank=True, null=True, verbose_name="结束时间") price = models.DecimalField(max_digits=10, decimal_places=2, default=0, verbose_name="价格", help_text="0表示免费") content = models.TextField(blank=True, verbose_name="详细内容", help_text="支持Markdown或HTML") diff --git a/backend/shop/serializers.py b/backend/shop/serializers.py index 173a07b..e25b3d7 100644 --- a/backend/shop/serializers.py +++ b/backend/shop/serializers.py @@ -92,7 +92,7 @@ class CourseEnrollmentSerializer(serializers.ModelSerializer): 课程报名序列化器 """ course_title = serializers.CharField(source='course.title', read_only=True) - ref_code = serializers.CharField(write_only=True, required=False, allow_blank=True) + ref_code = serializers.CharField(write_only=True, required=False, allow_blank=True, allow_null=True) class Meta: model = CourseEnrollment @@ -124,7 +124,7 @@ class ServiceOrderSerializer(serializers.ModelSerializer): """ service_name = serializers.CharField(source='service.title', read_only=True) # 接收前端传来的 ref_code - ref_code = serializers.CharField(write_only=True, required=False, allow_blank=True) + ref_code = serializers.CharField(write_only=True, required=False, allow_blank=True, allow_null=True) class Meta: model = ServiceOrder @@ -212,7 +212,7 @@ class OrderSerializer(serializers.ModelSerializer): salesperson_name = serializers.CharField(source='salesperson.name', read_only=True) salesperson_code = serializers.CharField(source='salesperson.code', read_only=True) # 接收前端传来的 ref_code,用于查找 Salesperson - ref_code = serializers.CharField(write_only=True, required=False, allow_blank=True) + ref_code = serializers.CharField(write_only=True, required=False, allow_blank=True, allow_null=True) class Meta: model = Order diff --git a/backend/shop/views.py b/backend/shop/views.py index 12efe9c..bf4b02d 100644 --- a/backend/shop/views.py +++ b/backend/shop/views.py @@ -268,8 +268,8 @@ def pay(request): product = None if order_type == 'course': try: - product = VBCourse.objects.get(id=good_id) - except VBCourse.DoesNotExist: + product = VCCourse.objects.get(id=good_id) + except VCCourse.DoesNotExist: print(f"课程不存在: {good_id}") return Response({'error': f'找不到 ID 为 {good_id} 的课程'}, status=status.HTTP_404_NOT_FOUND) else: @@ -355,7 +355,8 @@ def pay(request): print(f"微信支付 V3 Native 下单成功!") print(f"订单 ID: {order.id}") print(f"商户订单号: {out_trade_no}") - print(f"商品: {product.name} x {quantity}") + product_name = getattr(product, 'name', getattr(product, 'title', 'Unknown Product')) + print(f"商品: {product_name} x {quantity}") print(f"总额: {total_price} 元") print(f"code_url: {code_url}") print(f"========================================") @@ -596,6 +597,16 @@ class OrderViewSet(viewsets.ModelViewSet): return queryset.filter(wechat_user=user).order_by('-created_at') return queryset.order_by('-created_at') + def create(self, request, *args, **kwargs): + print(f"Creating order with data: {request.data}") + serializer = self.get_serializer(data=request.data) + if not serializer.is_valid(): + print(f"Order validation failed: {serializer.errors}") + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + self.perform_create(serializer) + headers = self.get_success_headers(serializer.data) + return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) + def perform_create(self, serializer): """ 创建订单时自动关联当前微信用户 diff --git a/frontend/src/pages/MyOrders.jsx b/frontend/src/pages/MyOrders.jsx index 90722a4..0ee9250 100644 --- a/frontend/src/pages/MyOrders.jsx +++ b/frontend/src/pages/MyOrders.jsx @@ -1,8 +1,7 @@ import React, { useState, useEffect } from 'react'; import { Form, Input, Button, Card, List, Tag, Typography, message, Space, Statistic, Divider, Modal, Descriptions, Tabs } from 'antd'; import { MobileOutlined, LockOutlined, SearchOutlined, CarOutlined, InboxOutlined, SafetyCertificateOutlined, CheckCircleOutlined, ClockCircleOutlined, CloseCircleOutlined, UserOutlined, EnvironmentOutlined, PhoneOutlined, CalendarOutlined } from '@ant-design/icons'; -import { queryMyOrders, getMySignups } from '../api'; -import { motion } from 'framer-motion'; +import { getMySignups } from '../api'; import LoginModal from '../components/LoginModal'; import { useAuth } from '../context/AuthContext'; import { useNavigate } from 'react-router-dom'; @@ -75,6 +74,24 @@ const MyOrders = () => { } }; + const getOrderTypeTag = (order) => { + if (order.config) return 硬件; + if (order.course) return VC课程; + if (order.activity) return 活动; + return 其他; + }; + + const getOrderTitle = (order) => { + if (order.config_name) return order.config_name; + if (order.course_title) return order.course_title; + if (order.activity_title) return order.activity_title; + // Fallback to ID if no name/title + if (order.config) return `硬件 ID: ${order.config}`; + if (order.course) return `课程 ID: ${order.course}`; + if (order.activity) return `活动 ID: ${order.activity}`; + return '未知商品'; + }; + return (
{
) : ( - +
当前登录用户: {user.nickname}
)}
-
{order.config_name || `商品 ID: ${order.config}`}
+
{getOrderTitle(order)}
数量: x{order.quantity}
@@ -277,7 +294,7 @@ const MyOrders = () => { ) } ]} /> - +
)} { {currentOrder.id} - {currentOrder.config_name} + {getOrderTypeTag(currentOrder)} + {getOrderTitle(currentOrder)} {new Date(currentOrder.created_at).toLocaleString()} {new Date(currentOrder.updated_at).toLocaleString()} {getStatusTag(currentOrder.status)} @@ -344,7 +362,7 @@ const MyOrders = () => { onLoginSuccess={(userData) => { login(userData); if (userData.phone_number) { - handleQueryOrders(userData.phone_number); + handleQueryData(); } }} /> diff --git a/frontend/src/pages/VCCourseDetail.jsx b/frontend/src/pages/VCCourseDetail.jsx index 341d4cb..16529d4 100644 --- a/frontend/src/pages/VCCourseDetail.jsx +++ b/frontend/src/pages/VCCourseDetail.jsx @@ -1,10 +1,10 @@ import React, { useEffect, useState } from 'react'; import { useParams, useNavigate, useSearchParams } from 'react-router-dom'; import { Typography, Button, Spin, Empty, Descriptions, Tag, Row, Col, Modal, Form, Input, message } from 'antd'; -import { ArrowLeftOutlined, ClockCircleOutlined, UserOutlined, BookOutlined, FormOutlined } from '@ant-design/icons'; -import { getVCCourseDetail, createOrder } from '../api'; -import { motion } from 'framer-motion'; +import { ArrowLeftOutlined, ClockCircleOutlined, UserOutlined, BookOutlined, FormOutlined, CalendarOutlined } from '@ant-design/icons'; +import { getVCCourseDetail, createOrder, nativePay, queryOrderStatus } from '../api'; import { useAuth } from '../context/AuthContext'; +import { QRCodeSVG } from 'qrcode.react'; const { Title, Paragraph } = Typography; @@ -19,6 +19,12 @@ const VCCourseDetail = () => { const [submitting, setSubmitting] = useState(false); const [form] = Form.useForm(); + // Payment states + const [payMode, setPayMode] = useState(false); + const [qrCodeUrl, setQrCodeUrl] = useState(null); + const [currentOrderId, setCurrentOrderId] = useState(null); + const [paySuccess, setPaySuccess] = useState(false); + // 优先从 URL 获取,如果没有则从 localStorage 获取 const refCode = searchParams.get('ref') || localStorage.getItem('ref_code'); @@ -37,33 +43,85 @@ const VCCourseDetail = () => { }, [id]); useEffect(() => { - if (isModalOpen && user && user.phone_number) { - form.setFieldsValue({ - phone_number: user.phone_number - }); + if (isModalOpen) { + // Reset payment state when modal opens + setPayMode(false); + setQrCodeUrl(null); + setCurrentOrderId(null); + setPaySuccess(false); + + if (user && user.phone_number) { + form.setFieldsValue({ + phone_number: user.phone_number + }); + } } }, [isModalOpen, user, form]); + // Polling for payment status + useEffect(() => { + let timer; + if (payMode && !paySuccess && currentOrderId) { + timer = setInterval(async () => { + try { + const response = await queryOrderStatus(currentOrderId); + if (response.data.status === 'paid') { + setPaySuccess(true); + message.success('支付成功!报名已完成。'); + setTimeout(() => { + setIsModalOpen(false); + }, 2000); // Wait 2 seconds before closing + clearInterval(timer); + } + } catch (error) { + console.error('Check payment status failed:', error); + } + }, 3000); + } + return () => clearInterval(timer); + }, [payMode, paySuccess, currentOrderId]); + const handleEnroll = async (values) => { setSubmitting(true); try { - const orderData = { - course: course.id, - customer_name: values.customer_name, - phone_number: values.phone_number, - ref_code: refCode, - quantity: 1, - // 将其他信息放入收货地址字段中 - shipping_address: `[课程报名] 微信号: ${values.wechat_id || '无'}, 邮箱: ${values.email || '无'}, 备注: ${values.message || '无'}` - }; + const isFree = course.price === 0 || parseFloat(course.price) === 0; - await createOrder(orderData); - if (course.price === 0 || parseFloat(course.price) === 0) { + if (isFree) { + const orderData = { + course: course.id, + customer_name: values.customer_name, + phone_number: values.phone_number, + ref_code: refCode || "", + quantity: 1, + // 将其他信息放入收货地址字段中 + shipping_address: `[课程报名] 微信号: ${values.wechat_id || '无'}, 邮箱: ${values.email || '无'}, 备注: ${values.message || '无'}` + }; + + await createOrder(orderData); message.success('报名成功!您已成功加入课程。'); + setIsModalOpen(false); } else { - message.success('报名咨询已提交,我们的课程顾问将尽快与您联系!'); + // Paid course - use nativePay to generate QR code + const orderData = { + goodid: course.id, + type: 'course', + quantity: 1, + customer_name: values.customer_name, + phone_number: values.phone_number, + ref_code: refCode || "", + shipping_address: `[课程报名] 微信号: ${values.wechat_id || '无'}, 邮箱: ${values.email || '无'}, 备注: ${values.message || '无'}` + }; + + const response = await nativePay(orderData); + if (response.data && response.data.code_url) { + setQrCodeUrl(response.data.code_url); + setCurrentOrderId(response.data.order_id); + setPayMode(true); + message.success('订单创建成功,请扫码支付'); + } else { + throw new Error('Failed to generate payment QR code'); + } } - setIsModalOpen(false); } catch (error) { console.error(error); message.error('提交失败,请重试'); @@ -103,11 +161,7 @@ const VCCourseDetail = () => { 返回课程列表 - +
@@ -168,6 +222,14 @@ const VCCourseDetail = () => { 课时}> {course.lesson_count} 课时 + {course.is_fixed_schedule && (course.start_time || course.end_time) && ( + 开课时间}> +
+ {course.start_time &&
开始:{new Date(course.start_time).toLocaleString('zh-CN', {year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit'})}
} + {course.end_time &&
结束:{new Date(course.end_time).toLocaleString('zh-CN', {year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit'})}
} +
+
+ )} {/* 讲师简介 */} @@ -255,43 +317,75 @@ const VCCourseDetail = () => {
- +
{/* Enroll Modal */} setIsModalOpen(false)} footer={null} destroyOnHidden + width={payMode ? 400 : 520} > -

请填写您的联系方式,我们将为您安排课程顾问。

-
- - - - - - - - - - - - - - - - -
- - -
-
+ {payMode ? ( +
+ {paySuccess ? ( +
+
🎉
+

支付成功!

+

正在跳转...

+
+ ) : ( + <> +
+ {qrCodeUrl ? ( + + ) : ( + + )} +
+

¥{course.price}

+

请使用微信扫一扫支付

+
+ 支付完成后将自动完成报名 +
+ + )} +
+ ) : ( + <> +

请填写您的联系方式,我们将为您安排课程顾问。

+
+ + + + + + + + + + + + + + + + +
+ + +
+
+ + )}
); diff --git a/miniprogram/src/pages/courses/detail.scss b/miniprogram/src/pages/courses/detail.scss index fb0e3e9..6ccdb86 100644 --- a/miniprogram/src/pages/courses/detail.scss +++ b/miniprogram/src/pages/courses/detail.scss @@ -185,6 +185,36 @@ } } +.schedule-section { + .schedule-box { + background: #111; + padding: 30px; + border-radius: 16px; + border: 1px solid rgba(0, 240, 255, 0.2); + + .time-row { + display: flex; + margin-bottom: 16px; + font-size: 28px; + + &:last-child { + margin-bottom: 0; + } + + .label { + color: #888; + width: 160px; + } + + .value { + color: #00f0ff; + flex: 1; + font-weight: bold; + } + } + } +} + .desc-text { color: #aaa; font-size: 28px; diff --git a/miniprogram/src/pages/courses/detail.tsx b/miniprogram/src/pages/courses/detail.tsx index 85bc403..2d35f16 100644 --- a/miniprogram/src/pages/courses/detail.tsx +++ b/miniprogram/src/pages/courses/detail.tsx @@ -56,6 +56,17 @@ export default function CourseDetail() { if (loading) return Loading... if (!detail) return Not Found + const formatDateTime = (dateStr: string) => { + if (!dateStr) return '' + const date = new Date(dateStr) + const year = date.getFullYear() + const month = (date.getMonth() + 1).toString().padStart(2, '0') + const day = date.getDate().toString().padStart(2, '0') + const hour = date.getHours().toString().padStart(2, '0') + const minute = date.getMinutes().toString().padStart(2, '0') + return `${year}/${month}/${day} ${hour}:${minute}` + } + return ( @@ -109,6 +120,27 @@ export default function CourseDetail() { + {/* 开课时间 */} + {detail.is_fixed_schedule && (detail.start_time || detail.end_time) && ( + + 开课时间 + + {detail.start_time && ( + + 开始时间: + {formatDateTime(detail.start_time)} + + )} + {detail.end_time && ( + + 结束时间: + {formatDateTime(detail.end_time)} + + )} + + + )} + {/* 课程简介 */} 课程简介 diff --git a/miniprogram/src/pages/order/checkout.tsx b/miniprogram/src/pages/order/checkout.tsx index 63bfe2a..32dee6d 100644 --- a/miniprogram/src/pages/order/checkout.tsx +++ b/miniprogram/src/pages/order/checkout.tsx @@ -92,9 +92,31 @@ export default function Checkout() { }, [items]) const submitOrder = async () => { - if (!address) { - Taro.showToast({ title: '请选择收货地址', icon: 'none' }) - return + // 免费课程不需要地址 + const isFreeCourse = params.type === 'course' && items.length > 0 && Number(items[0].price) === 0 + + if (!address && !isFreeCourse) { + // 尝试调用 chooseAddress + try { + await chooseAddress() + if (!address) { + Taro.showToast({ title: '请选择收货地址', icon: 'none' }) + return + } + } catch (e) { + Taro.showToast({ title: '请选择收货地址', icon: 'none' }) + return + } + } + + // 如果是免费课程且没有地址,使用默认值 + const orderAddress = address || { + userName: '免费课程学员', + telNumber: '13800000000', + provinceName: '', + cityName: '', + countyName: '', + detailInfo: '线上课程' } Taro.showLoading({ title: '提交中...' }) @@ -102,11 +124,13 @@ export default function Checkout() { try { const orderPromises = items.map(item => { const type = params.type || 'config' + + // 构造订单数据 const orderData: any = { quantity: item.quantity, - customer_name: address.userName, - phone_number: address.telNumber, - shipping_address: `${address.provinceName}${address.cityName}${address.countyName}${address.detailInfo}`, + customer_name: orderAddress.userName, + phone_number: orderAddress.telNumber, + shipping_address: `${orderAddress.provinceName}${orderAddress.cityName}${orderAddress.countyName}${orderAddress.detailInfo}`, ref_code: Taro.getStorageSync('ref_code') || '' } diff --git a/miniprogram/src/pages/order/payment.tsx b/miniprogram/src/pages/order/payment.tsx index f5777bf..2083ed7 100644 --- a/miniprogram/src/pages/order/payment.tsx +++ b/miniprogram/src/pages/order/payment.tsx @@ -23,7 +23,19 @@ export default function Payment() { const handlePay = async () => { if (!order) return + setLoading(true) + + // 如果是免费订单,直接显示成功并跳转 + if (parseFloat(order.total_price) <= 0) { + Taro.showToast({ title: '报名成功', icon: 'success' }) + setTimeout(() => { + Taro.redirectTo({ url: '/pages/order/list' }) + }, 1500) + setLoading(false) + return + } + try { const params = await prepayMiniprogram(order.id) @@ -81,7 +93,9 @@ export default function Payment() { - + ) diff --git a/miniprogram/src/subpackages/forum/activity/detail.scss b/miniprogram/src/subpackages/forum/activity/detail.scss index 5e52af7..ddf2cf2 100644 --- a/miniprogram/src/subpackages/forum/activity/detail.scss +++ b/miniprogram/src/subpackages/forum/activity/detail.scss @@ -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; + } + } + } +} diff --git a/miniprogram/src/subpackages/forum/activity/detail.tsx b/miniprogram/src/subpackages/forum/activity/detail.tsx index f4a012c..8f9eed0 100644 --- a/miniprogram/src/subpackages/forum/activity/detail.tsx +++ b/miniprogram/src/subpackages/forum/activity/detail.tsx @@ -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 */} - 免费 + + {Number(activity.price) > 0 ? `¥${activity.price}` : '免费'} + 限时活动