HomePage.vue 28.9 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
<!--
 * @Date: 2025-03-20 19:55:21
 * @LastEditors: hookehuyr hookehuyr@gmail.com
 * @LastEditTime: 2025-03-24 18:10:32
 * @FilePath: /mlaj/src/views/HomePage.vue
 * @Description: 亲子学院首页组件
 *
 * 主要功能模块:
 * 1. 用户欢迎区:显示用户信息和每日打卡
 * 2. 夏令营推广:展示特色夏令营活动
 * 3. 精选课程:轮播展示推荐课程
 * 4. 内容分类:推荐、直播、精选三个标签页
 * 5. 视频播放:支持在线视频播放和切换
 *
 * 状态管理:
 * - 用户认证状态:通过useAuth hook管理
 * - 打卡状态:包括选择的打卡类型和提交状态
 * - 轮播状态:当前轮播位置和滚动控制
 * - 视频播放状态:当前播放的视频索引
 *
 * 组件依赖:
 * - AppLayout:页面布局组件
 * - FrostedGlass:毛玻璃效果容器
 * - CourseCard:课程卡片组件
 * - LiveStreamCard:直播卡片组件
 * - ActivityCard:活动卡片组件
 * - SummerCampCard:夏令营卡片组件
 * - VideoPlayer:视频播放器组件
-->

<template>
  <AppLayout title="亲子学院" :rightContent="rightContent">
    <div class="pb-16 bg-gradient-to-b from-white via-green-50/10 to-blue-50/10">
      <!-- Header Section with Welcome & Weather -->
      <div v-if="currentUser" class="px-4 pt-3 pb-4">
        <FrostedGlass class="p-4 rounded-xl mb-4">
          <div class="flex justify-between items-center mb-3">
            <div class="flex items-center">
              <div class="w-10 h-10 rounded-full overflow-hidden mr-3">
                <img
                  :src="currentUser?.avatar || 'https://cdn.ipadbiz.cn/mlaj/images/user-avatar-2.jpg'"
                  class="w-full h-full object-cover"
                  @error="handleImageError" />
              </div>
              <div>
                <h2 class="text-xl font-bold">欢迎回来,{{ currentUser.name || '登录用户' }}!</h2>
                <p class="text-sm text-gray-500">{{ formatToday() }}</p>
              </div>
            </div>
            <!-- <div class="flex items-center text-sm">
              <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-amber-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
              </svg>
              <span class="ml-1 font-medium">23°C</span>
              <span class="ml-1 text-gray-500">晴朗</span>
            </div> -->
          </div>

          <!-- User Stats -->
          <div class="flex justify-between text-center py-2">
            <div class="border-r border-gray-200 flex-1">
              <div class="text-lg font-bold">3</div>
              <div class="text-xs text-gray-500">连续打卡</div>
            </div>
            <div class="border-gray-200 flex-1">
              <div class="text-lg font-bold">12</div>
              <div class="text-xs text-gray-500">已学课程</div>
            </div>
            <!-- <div class="flex-1">
              <div class="text-lg font-bold">25</div>
              <div class="text-xs text-gray-500">积分</div>
            </div> -->
          </div>
        </FrostedGlass>

        <!-- Daily Check-in -->
        <FrostedGlass class="p-4 rounded-xl">
          <div class="flex justify-between items-center mb-3">
            <h3 class="font-medium">今日打卡</h3>
            <router-link to="/profile" class="text-green-600 text-sm">打卡记录</router-link>
          </div>

          <div v-if="checkInSuccess" class="bg-green-50 border border-green-200 rounded-lg p-4 text-center">
            <svg xmlns="http://www.w3.org/2000/svg" class="h-10 w-10 text-green-500 mx-auto mb-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
            </svg>
            <h4 class="text-green-700 font-medium mb-1">打卡成功!</h4>
            <p class="text-green-600 text-sm">+5 积分已添加到您的账户</p>
          </div>
          <template v-else>
            <div class="flex space-x-2 py-2">
              <button
                v-for="checkInType in checkInTypes"
                :key="checkInType.id"
                :class="[
                  'flex-1 flex flex-col items-center p-2 rounded-lg transition-colors',
                  selectedCheckIn?.id === checkInType.id
                    ? 'bg-green-100 border border-green-200'
                    : 'bg-white/70 border border-gray-100 hover:bg-white'
                ]"
                @click="handleCheckInSelect(checkInType)"
              >
                <div :class="[
                  'w-12 h-12 rounded-full flex items-center justify-center mb-1 transition-colors',
                  selectedCheckIn?.id === checkInType.id
                    ? 'bg-green-500 text-white'
                    : 'bg-gray-100 text-gray-500'
                ]">
                  <svg v-if="checkInType.id === 'reading'" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
                  </svg>
                  <svg v-if="checkInType.id === 'exercise'" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
                  </svg>
                  <svg v-if="checkInType.id === 'study'" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                    <path d="M12 14l9-5-9-5-9 5 9 5z" />
                    <path d="M12 14l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998a12.078 12.078 0 01.665-6.479L12 14z" />
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 14l9-5-9-5-9 5 9 5zm0 0l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998a12.078 12.078 0 01.665-6.479L12 14zm-4 6v-7.5l4-2.222" />
                  </svg>
                  <svg v-if="checkInType.id === 'reflection'" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
                  </svg>
                </div>
                <span class="text-xs">{{ checkInType.name }}</span>
              </button>
            </div>

            <div v-if="selectedCheckIn" class="mt-3">
              <textarea
                :placeholder="`请输入${selectedCheckIn.name}内容...`"
                v-model="checkInContent"
                class="w-full p-3 border border-gray-200 rounded-lg text-sm resize-none h-24"
              />
              <button
                class="mt-2 w-full bg-gradient-to-r from-green-500 to-green-600 text-white py-2 rounded-lg flex items-center justify-center"
                @click="handleCheckInSubmit"
                :disabled="isCheckingIn"
              >
                <template v-if="isCheckingIn">
                  <div class="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin mr-2"></div>
                  提交中...
                </template>
                <template v-else>提交打卡</template>
              </button>
            </div>
          </template>
        </FrostedGlass>
      </div>

      <!-- Summer Camp Promotion -->
      <div class="px-4 mb-6">
        <SummerCampCard :items="[
          {
            title: '大国少年-世界正东方',
            subtitle: '亲子夏令营',
            badge: '亲子夏令营',
            price: '¥1280',
            discount: '限时优惠',
            episodes: 16,
            subscribers: 1140,
            imageUrl: 'https://cdn.ipadbiz.cn/mlaj/images/summer-camp.jpg'
          },
          {
            title: '暑期特训营',
            subtitle: '提升学习能力',
            badge: '特训营',
            price: '¥1580',
            discount: '早鸟优惠',
            episodes: 20,
            subscribers: 980,
            imageUrl: 'https://cdn.ipadbiz.cn/mlaj/images/summer-camp-2.jpg'
          },
          {
            title: '艺术创想营',
            subtitle: '激发创造力',
            badge: '艺术营',
            price: '¥1380',
            discount: '新课优惠',
            episodes: 12,
            subscribers: 760,
            imageUrl: 'https://cdn.ipadbiz.cn/mlaj/images/summer-camp-3.jpg'
          }
        ]" />
      </div>

      <!-- Featured Courses Carousel -->
      <div class="mb-6">
        <div class="px-4 mb-2">
          <h3 class="font-medium">精选课程</h3>
        </div>
        <div class="relative">
          <div
            ref="carouselRef"
            class="flex overflow-x-scroll snap-x snap-mandatory"
            style="scrollbar-width: none; -ms-overflow-style: none;"
          >
            <div
              v-for="(course, index) in courses.slice(0, 4)"
              :key="course.id"
              class="flex-shrink-0 w-full snap-center px-4"
            >
              <div class="relative rounded-xl overflow-hidden shadow-lg h-48">
                <img
                  :src="course.imageUrl || 'https://cdn.ipadbiz.cn/mlaj/images/featured-course.jpg'"
                  :alt="course.title"
                  class="w-full h-full object-cover"
                />
                <div class="absolute inset-0 bg-gradient-to-b from-transparent via-black/20 to-black/60 flex flex-col justify-end p-4">
                  <div class="bg-amber-500/90 text-white px-2 py-1 rounded-full text-xs font-medium inline-block w-fit mb-1">
                    {{ course.category }}
                  </div>
                  <h2 class="text-2xl font-bold text-white drop-shadow-md">{{ course.title }}</h2>
                  <p class="text-white/90 text-sm drop-shadow-sm mb-1">{{ course.subtitle }}</p>
                  <div class="flex justify-between items-center">
                    <div class="flex items-center">
                      <div class="flex">
                        <svg
                          v-for="i in 5"
                          :key="i"
                          xmlns="http://www.w3.org/2000/svg"
                          :class="[`h-4 w-4`, i <= course.rating ? 'text-amber-400' : 'text-gray-300']"
                          viewBox="0 0 20 20"
                          fill="currentColor"
                        >
                          <path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
                        </svg>
                      </div>
                      <span class="text-white text-xs ml-1">{{ course.ratingCount }}人评</span>
                    </div>
                    <router-link
                      :to="`/courses/${course.id}`"
                      class="bg-white/90 text-green-600 px-3 py-1 rounded-full text-xs font-medium"
                    >
                      立即学习
                    </router-link>
                  </div>
                </div>
              </div>
            </div>
          </div>

          <!-- Carousel Indicators -->
          <div class="flex justify-center mt-4">
            <button
              v-for="(_, index) in courses.slice(0, 4)"
              :key="index"
              @click="scrollToSlide(index)"
              :class="[
                'w-2 h-2 mx-1 rounded-full',
                currentSlide === index ? 'bg-green-600' : 'bg-gray-300'
              ]"
            />
          </div>
        </div>
      </div>

      <!-- Tab Navigation -->
      <div class="px-4 border-b border-gray-200">
        <div class="flex space-x-6">
          <button
            v-for="tab in ['推荐', '直播', '精选']"
            :key="tab"
            @click="activeTab = tab"
            :class="[
              'pb-3 px-1 font-medium',
              activeTab === tab
                ? 'text-green-600 border-b-2 border-green-600'
                : 'text-gray-500'
            ]"
          >
            {{ tab }}
            <span
              v-if="tab === '直播'"
              class="ml-1 px-1.5 py-0.5 bg-red-500 text-white text-xs rounded-full"
            >
              2
            </span>
          </button>
        </div>
      </div>

      <!-- Content Based on Active Tab -->
      <div class="px-4 mt-5">
        <!-- Recommended Content -->
        <div v-if="activeTab === '推荐'">
          <!-- Personalized Recommendations -->
          <section class="mb-7">
            <div class="flex justify-between items-center mb-3">
              <h3 class="font-medium">为您推荐</h3>
              <button class="text-xs text-gray-500 flex items-center">
                换一批
                <svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3 ml-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
                </svg>
              </button>
            </div>
            <div class="grid grid-cols-2 gap-4">
              <FrostedGlass
                v-for="(item, index) in userRecommendations"
                :key="index"
                class="p-3 rounded-xl"
              >
                <div class="flex flex-col h-full">
                  <div class="h-28 mb-2 rounded-lg overflow-hidden">
                    <img
                      :src="item.image"
                      :alt="item.title"
                      class="w-full h-full object-cover"
                      @error="handleImageError"
                    />
                  </div>
                  <h4 class="font-medium text-sm mb-1 line-clamp-1">{{ item.title }}</h4>
                  <p class="text-xs text-gray-500 flex items-center mt-auto">
                    <svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
                    </svg>
                    {{ item.duration }}
                  </p>
                </div>
              </FrostedGlass>
            </div>
          </section>

          <!-- Recent Activities -->
          <section class="mb-7">
            <div class="flex justify-between items-center mb-3">
              <h3 class="font-medium">最新活动</h3>
              <a href="https://www.mlaj.com/activities" target="_blank" class="text-xs text-gray-500 flex items-center">
                更多
                <svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3 ml-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
                </svg>
              </a>
            </div>
            <div class="space-y-4">
              <div v-for="activity in activities.slice(0, 3)" :key="activity.id">
                <ActivityCard :activity="activity" />
              </div>
            </div>
          </section>

          <!-- Popular Courses -->
          <section>
            <div class="flex justify-between items-center mb-3">
              <h3 class="font-medium">热门课程</h3>
              <router-link to="/courses" class="text-xs text-gray-500 flex items-center">
                更多
                <svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3 ml-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
                </svg>
              </router-link>
            </div>
            <div class="space-y-4">
              <CourseCard
                v-for="course in courses.slice(0, 3)"
                :key="course.id"
                :course="course"
              />
            </div>
          </section>
        </div>

        <!-- Live Content -->
        <div v-if="activeTab === '直播'">
          <section>
            <div class="flex justify-between items-center mb-3">
              <h3 class="font-medium">正在直播</h3>
              <div class="text-xs text-red-500 flex items-center">
                <div class="w-2 h-2 bg-red-500 rounded-full mr-1 animate-pulse"></div>
                2个直播中
              </div>
            </div>
            <div class="grid grid-cols-2 gap-4 mb-7">
              <LiveStreamCard
                v-for="stream in liveStreams"
                :key="stream.id"
                :stream="stream"
              />
            </div>

            <div class="mb-5">
              <div class="flex justify-between items-center mb-3">
                <h3 class="font-medium">直播日历</h3>
                <router-link to="/live-calendar" class="text-xs text-blue-500">
                  查看日历
                </router-link>
              </div>
              <FrostedGlass class="p-3 rounded-xl">
                <div class="flex space-x-2 overflow-x-auto py-1">
                  <div
                    v-for="(day, i) in ['今天', '明天', '周三', '周四', '周五', '周六', '周日']"
                    :key="day"
                    :class="[
                      'flex-shrink-0 w-10 h-14 flex flex-col items-center justify-center rounded-lg',
                      i === 0 ? 'bg-green-500 text-white' : 'bg-white/50'
                    ]"
                  >
                    <div class="text-xs">{{ day }}</div>
                    <div class="font-bold mt-1">{{ new Date().getDate() + i }}</div>
                  </div>
                </div>
              </FrostedGlass>
            </div>

            <div>
              <h3 class="font-medium mb-3">直播预告</h3>
              <div class="space-y-3">
                <FrostedGlass
                  v-for="(item, index) in [
                    { title: '亲子阅读会第1期', time: '今天 19:30-20:30', image: 'https://cdn.ipadbiz.cn/mlaj/images/live-1.jpg' },
                    { title: '儿童心理健康讲座', time: '明天 20:00-21:00', image: 'https://cdn.ipadbiz.cn/mlaj/images/live-2.jpg' },
                    { title: '家庭教育经验分享', time: '周三 19:00-20:00', image: 'https://cdn.ipadbiz.cn/mlaj/images/live-3.jpg' }
                  ]"
                  :key="index"
                  class="p-3 rounded-xl"
                >
                  <div class="flex justify-between items-center">
                    <div class="flex items-center">
                      <div class="w-12 h-12 bg-green-100 rounded-lg overflow-hidden mr-3 flex-shrink-0">
                        <img
                          :src="item.image"
                          :alt="item.title"
                          class="w-full h-full object-cover"
                          @error="handleImageError"
                        />
                      </div>
                      <div>
                        <h4 class="font-medium text-sm">{{ item.title }}</h4>
                        <p class="text-xs text-gray-500 mt-1">{{ item.time }}</p>
                      </div>
                    </div>
                    <button class="bg-white text-green-600 border border-green-600 px-3 py-1 rounded-full text-xs flex-shrink-0">
                      预约
                    </button>
                  </div>
                </FrostedGlass>
              </div>
            </div>
          </section>
        </div>

        <!-- Featured Content -->
        <div v-if="activeTab === '精选'">
          <section>
            <div class="mb-5">
              <h3 class="font-medium mb-3">精选内容</h3>
              <FrostedGlass class="p-4 rounded-xl">
                <div class="flex flex-col">
                  <div class="inline-block px-2 py-1 bg-blue-100 text-blue-600 text-xs rounded-full mb-2 w-fit">
                    独家专栏
                  </div>
                  <h4 class="font-medium text-lg mb-2">《如何培养孩子的阅读习惯》</h4>
                  <p class="text-gray-600 text-sm mb-4 line-clamp-2">
                    阅读习惯的培养是一个长期过程,本文将分享如何从日常生活点滴培养孩子的阅读兴趣和习惯...
                  </p>
                  <router-link to="/articles/1" class="text-green-600 text-sm font-medium">
                    查看完整文章
                  </router-link>
                </div>
              </FrostedGlass>
            </div>

            <div>
              <h3 class="font-medium mb-3">推荐视频</h3>
              <div class="space-y-4">
                <div
                  v-for="(item, index) in [
                    { title: '亲子沟通的艺术', views: '1.2万', duration: '08:25', image: 'https://cdn.ipadbiz.cn/mlaj/images/video-1.jpg', video_url: 'https://sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-360p.mp4' },
                    { title: '如何做好家庭教育', views: '8千', duration: '12:40', image: 'https://cdn.ipadbiz.cn/mlaj/images/video-2.jpg', video_url: 'https://sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-360p.mp4' },
                    { title: '孩子营养餐制作指南', views: '5千', duration: '15:18', image: 'https://cdn.ipadbiz.cn/mlaj/images/video-3.jpg', video_url: 'https://sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-360p.mp4' }
                  ]"
                  :key="index"
                  class="relative rounded-xl overflow-hidden shadow-md h-48"
                >
                  <template v-if="activeVideoIndex !== index">
                    <img
                      :src="item.image"
                      :alt="item.title"
                      class="w-full h-full object-cover"
                      @error="handleImageError"
                    />
                    <div class="absolute inset-0 bg-gradient-to-b from-transparent to-black/70 flex flex-col justify-end p-4">
                      <h4 class="text-white font-medium mb-1">{{ item.title }}</h4>
                      <div class="flex justify-between items-center">
                        <p class="text-white/80 text-xs">{{ item.views }}次播放 · {{ item.duration }}</p>
                        <button
                          class="bg-white/20 backdrop-blur-sm p-2 rounded-full"
                          @click="playVideo(index, item.video_url)"
                        >
                          <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-white" viewBox="0 0 20 20" fill="currentColor">
                            <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z" clip-rule="evenodd" />
                          </svg>
                        </button>
                      </div>
                    </div>
                  </template>
                  <VideoPlayer
                    v-else
                    :video-url="item.video_url"
                    ref="videoPlayerRefs"
                  />
                </div>
              </div>
            </div>
          </section>
        </div>
      </div>
    </div>
  </AppLayout>
</template>

<script setup lang="jsx">
// 导入所需的Vue核心功能和组件
import { ref, onMounted, onUnmounted, defineComponent, h } from 'vue'
import { useRoute, useRouter } from 'vue-router'

// 导入布局和UI组件
import AppLayout from '@/components/layout/AppLayout.vue'
import FrostedGlass from '@/components/ui/FrostedGlass.vue'
import CourseCard from '@/components/ui/CourseCard.vue'
import LiveStreamCard from '@/components/ui/LiveStreamCard.vue'
import ActivityCard from '@/components/ui/ActivityCard.vue'
import SummerCampCard from '@/components/ui/SummerCampCard.vue'
import VideoPlayer from '@/components/ui/VideoPlayer.vue'

// 导入模拟数据和工具函数
import { courses, liveStreams, activities, checkInTypes, userRecommendations } from '@/utils/mockData'
import { useTitle } from '@vueuse/core'
import { useAuth } from '@/contexts/auth'
import { showToast } from 'vant'
import 'vant/lib/toast/style'

// 视频播放状态管理
const activeVideoIndex = ref(null); // 当前播放的视频索引
const videoPlayerRefs = ref([]); // 视频播放器组件引用数组

// 播放视频处理函数
const playVideo = (index, videoUrl) => {
  // 更新当前播放的视频索引
  activeVideoIndex.value = index;
};

// 路由相关
const $route = useRoute()
useTitle($route.meta.title) // 设置页面标题

// 获取用户认证状态
const { currentUser } = useAuth()

// 响应式状态管理
const activeTab = ref('推荐') // 当前激活的内容标签页
const selectedCheckIn = ref(null) // 选中的打卡类型
const checkInContent = ref('') // 打卡内容
const currentSlide = ref(0) // 当前轮播图索引
const isCheckingIn = ref(false) // 打卡提交状态
const checkInSuccess = ref(false) // 打卡成功状态
const carouselRef = ref(null) // 轮播图容器引用

// 右侧导航组件:搜索和消息通知

// 右侧内容组件
const RightContent = defineComponent({
  setup() {
    return () => (
      <div class="flex items-center">
        <button class="p-2 mr-1">
          <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-gray-700" fill="none" viewBox="0 0 24 24" stroke="currentColor">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
          </svg>
        </button>
        <button class="p-2">
          <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-gray-700" fill="none" viewBox="0 0 24 24" stroke="currentColor">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
          </svg>
        </button>
      </div>
    )
  }
})

const rightContent = h(RightContent)

// 工具函数:处理图片加载错误,设置默认头像
const handleImageError = (e) => {
  e.target.onerror = null // 防止循环触发错误
  e.target.src = 'https://cdn.ipadbiz.cn/mlaj/images/user-avatar-2.jpg' // 设置默认头像
}

// 工具函数:格式化今天的日期为中文格式
const formatToday = () => {
  const today = new Date()
  const options = { month: 'long', day: 'numeric', weekday: 'long' } // 设置日期格式选项
  return today.toLocaleDateString('zh-CN', options) // 返回中文格式的日期
}

// 轮播图控制:滚动到指定位置
const scrollToSlide = (index) => {
  if (carouselRef.value) {
    const slideWidth = carouselRef.value.offsetWidth // 获取轮播图容器宽度
    carouselRef.value.scrollTo({
      left: index * slideWidth, // 计算目标滚动位置
      behavior: 'smooth' // 使用平滑滚动效果
    })
    currentSlide.value = index // 更新当前轮播图索引
  }
}

// 打卡功能:处理打卡类型选择
const handleCheckInSelect = (checkInType) => {
  selectedCheckIn.value = checkInType // 更新选中的打卡类型
  checkInContent.value = '' // 清空打卡内容
}

// 打卡功能:处理打卡提交
const handleCheckInSubmit = () => {
  // 表单验证
  if (!selectedCheckIn.value) {
    showToast('请选择打卡项目')
    return
  }
  if (!checkInContent.value.trim()) {
    showToast('请输入打卡内容')
    return
  }

  isCheckingIn.value = true

  // 模拟API调用
  setTimeout(() => {
    isCheckingIn.value = false
    checkInSuccess.value = true
    selectedCheckIn.value = null
    checkInContent.value = ''

    // 3秒后重置成功提示
    setTimeout(() => {
      checkInSuccess.value = false
    }, 3000)
  }, 1500)
}

// 自动轮播
let carouselInterval
onMounted(() => {
  carouselInterval = setInterval(() => {
    if (carouselRef.value) {
      const nextSlide = (currentSlide.value + 1) % courses.slice(0, 4).length
      scrollToSlide(nextSlide)
    }
  }, 5000)
})

onUnmounted(() => {
  if (carouselInterval) {
    clearInterval(carouselInterval)
  }
})
</script>