diff --git a/backend/shop/serializers.py b/backend/shop/serializers.py index 98de22e..59074fa 100644 --- a/backend/shop/serializers.py +++ b/backend/shop/serializers.py @@ -176,6 +176,7 @@ class VCCourseSerializer(serializers.ModelSerializer): display_detail_image = serializers.SerializerMethodField() course_type_display = serializers.CharField(source='get_course_type_display', read_only=True) video_url = serializers.SerializerMethodField() + is_purchased = serializers.SerializerMethodField() class Meta: model = VCCourse @@ -195,6 +196,30 @@ class VCCourseSerializer(serializers.ModelSerializer): return obj.detail_image.url return None + def _check_purchased(self, obj): + request = self.context.get('request') + if not request: + return False + + # 尝试获取当前用户 + user = get_current_wechat_user(request) + if not user: + return False + + # 如果是管理员,视为已购买 + if user.user and user.user.is_staff: + return True + + # 检查是否已购买/报名 (通过已支付的订单) + return Order.objects.filter( + wechat_user=user, + course=obj, + status__in=['paid', 'shipped', 'completed'] + ).exists() + + def get_is_purchased(self, obj): + return self._check_purchased(obj) + def get_video_url(self, obj): """ 仅当用户已付费/报名时返回视频URL @@ -202,27 +227,7 @@ class VCCourseSerializer(serializers.ModelSerializer): if not obj.is_video_course: return None - request = self.context.get('request') - if not request: - return None - - # 尝试获取当前用户 - user = get_current_wechat_user(request) - if not user: - return None - - # 如果是管理员,直接返回 - if user.user and user.user.is_staff: - return obj.video_url - - # 检查是否已购买/报名 (通过已支付的订单) - has_paid = Order.objects.filter( - wechat_user=user, - course=obj, - status__in=['paid', 'shipped', 'completed'] # 包含所有已完成状态 - ).exists() - - if has_paid: + if self._check_purchased(obj): return obj.video_url return None diff --git a/frontend/src/pages/VCCourseDetail.jsx b/frontend/src/pages/VCCourseDetail.jsx index a05d87f..123f418 100644 --- a/frontend/src/pages/VCCourseDetail.jsx +++ b/frontend/src/pages/VCCourseDetail.jsx @@ -425,22 +425,26 @@ const VCCourseDetail = () => { size="large" block icon={course.is_video_course ? : } + disabled={course.is_purchased} style={{ height: 50, - background: '#00f0ff', - borderColor: '#00f0ff', - color: '#000', + background: course.is_purchased ? '#333' : '#00f0ff', + borderColor: course.is_purchased ? '#444' : '#00f0ff', + color: course.is_purchased ? '#888' : '#000', fontWeight: 'bold', - fontSize: '16px' + fontSize: '16px', + cursor: course.is_purchased ? 'not-allowed' : 'pointer' }} - onClick={() => setIsModalOpen(true)} + onClick={() => !course.is_purchased && setIsModalOpen(true)} > - {course.is_video_course ? '购买视频课程' : '立即报名 / 咨询'} + {course.is_purchased ? '已购买' : (course.is_video_course ? '购买视频课程' : '立即报名 / 咨询')}

- {course.is_video_course - ? '* 支付成功后自动解锁视频内容' - : '* 提交后我们的顾问将尽快与您联系确认'} + {course.is_purchased + ? '* 您已拥有该课程,可直接观看视频' + : (course.is_video_course + ? '* 支付成功后自动解锁视频内容' + : '* 提交后我们的顾问将尽快与您联系确认')}

diff --git a/miniprogram/src/pages/courses/detail.scss b/miniprogram/src/pages/courses/detail.scss index 3ee85db..baabb2e 100644 --- a/miniprogram/src/pages/courses/detail.scss +++ b/miniprogram/src/pages/courses/detail.scss @@ -352,6 +352,11 @@ border: none; margin: 0; + &.disabled { + background: #333; + color: #666; + } + &::after { border: none; } diff --git a/miniprogram/src/pages/courses/detail.tsx b/miniprogram/src/pages/courses/detail.tsx index 932ae35..6e04ae8 100644 --- a/miniprogram/src/pages/courses/detail.tsx +++ b/miniprogram/src/pages/courses/detail.tsx @@ -196,8 +196,12 @@ export default function CourseDetail() { 总价: ¥{detail.price} - diff --git a/miniprogram/src/pages/services/index.scss b/miniprogram/src/pages/services/index.scss index eb68f1a..d7cfaee 100644 --- a/miniprogram/src/pages/services/index.scss +++ b/miniprogram/src/pages/services/index.scss @@ -377,3 +377,38 @@ 0% { transform: scale(1); opacity: 0.5; } 100% { transform: scale(1.15); opacity: 0; } } + +.ai-badge { + background: rgba(0, 185, 107, 0.1); + border: 1px solid rgba(0, 185, 107, 0.3); + padding: 8px 20px; + border-radius: 30px; + margin: 15px auto; + display: inline-block; + backdrop-filter: blur(5px); + box-shadow: 0 0 10px rgba(0, 185, 107, 0.1); + + text { + color: #00b96b; + font-size: 24px; + font-weight: bold; + letter-spacing: 1px; + text-shadow: 0 0 5px rgba(0, 185, 107, 0.3); + } +} + +.compliance-footer { + text-align: center; + padding: 30px 20px 50px; + margin-top: 40px; + border-top: 1px solid rgba(255, 255, 255, 0.05); + background: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.5)); + + .compliance-text { + color: #444; + font-size: 22px; + display: block; + margin-bottom: 5px; + letter-spacing: 1px; + } +} diff --git a/miniprogram/src/pages/services/index.tsx b/miniprogram/src/pages/services/index.tsx index e421c64..fff0017 100644 --- a/miniprogram/src/pages/services/index.tsx +++ b/miniprogram/src/pages/services/index.tsx @@ -48,6 +48,10 @@ export default function ServicesIndex() { AI 全栈解决方案 + + 生成式AI生成内容 + + 从数据处理到模型部署,我们为您提供一站式 AI 基础设施服务。 @@ -130,6 +134,10 @@ export default function ServicesIndex() { ))} + + + 深度合成-AI问答类目 + ) }