diff --git a/apps/web/@repo/ui/components/button.tsx b/apps/web/@repo/ui/components/button.tsx new file mode 100644 index 0000000..094bca6 --- /dev/null +++ b/apps/web/@repo/ui/components/button.tsx @@ -0,0 +1,59 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@repo/ui/lib/utils" + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90", + destructive: + "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50", + secondary: + "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80", + ghost: + "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2 has-[>svg]:px-3", + sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", + lg: "h-10 rounded-md px-6 has-[>svg]:px-4", + icon: "size-9", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +function Button({ + className, + variant, + size, + asChild = false, + ...props +}: React.ComponentProps<"button"> & + VariantProps & { + asChild?: boolean + }) { + const Comp = asChild ? Slot : "button" + + return ( + + ) +} + +export { Button, buttonVariants } diff --git a/apps/web/@repo/ui/components/carousel.tsx b/apps/web/@repo/ui/components/carousel.tsx new file mode 100644 index 0000000..c8afa56 --- /dev/null +++ b/apps/web/@repo/ui/components/carousel.tsx @@ -0,0 +1,241 @@ +"use client" + +import * as React from "react" +import useEmblaCarousel, { + type UseEmblaCarouselType, +} from "embla-carousel-react" +import { ArrowLeft, ArrowRight } from "lucide-react" + +import { cn } from "@repo/ui/lib/utils" +import { Button } from "@repo/ui/components/button" + +type CarouselApi = UseEmblaCarouselType[1] +type UseCarouselParameters = Parameters +type CarouselOptions = UseCarouselParameters[0] +type CarouselPlugin = UseCarouselParameters[1] + +type CarouselProps = { + opts?: CarouselOptions + plugins?: CarouselPlugin + orientation?: "horizontal" | "vertical" + setApi?: (api: CarouselApi) => void +} + +type CarouselContextProps = { + carouselRef: ReturnType[0] + api: ReturnType[1] + scrollPrev: () => void + scrollNext: () => void + canScrollPrev: boolean + canScrollNext: boolean +} & CarouselProps + +const CarouselContext = React.createContext(null) + +function useCarousel() { + const context = React.useContext(CarouselContext) + + if (!context) { + throw new Error("useCarousel must be used within a ") + } + + return context +} + +function Carousel({ + orientation = "horizontal", + opts, + setApi, + plugins, + className, + children, + ...props +}: React.ComponentProps<"div"> & CarouselProps) { + const [carouselRef, api] = useEmblaCarousel( + { + ...opts, + axis: orientation === "horizontal" ? "x" : "y", + }, + plugins + ) + const [canScrollPrev, setCanScrollPrev] = React.useState(false) + const [canScrollNext, setCanScrollNext] = React.useState(false) + + const onSelect = React.useCallback((api: CarouselApi) => { + if (!api) return + setCanScrollPrev(api.canScrollPrev()) + setCanScrollNext(api.canScrollNext()) + }, []) + + const scrollPrev = React.useCallback(() => { + api?.scrollPrev() + }, [api]) + + const scrollNext = React.useCallback(() => { + api?.scrollNext() + }, [api]) + + const handleKeyDown = React.useCallback( + (event: React.KeyboardEvent) => { + if (event.key === "ArrowLeft") { + event.preventDefault() + scrollPrev() + } else if (event.key === "ArrowRight") { + event.preventDefault() + scrollNext() + } + }, + [scrollPrev, scrollNext] + ) + + React.useEffect(() => { + if (!api || !setApi) return + setApi(api) + }, [api, setApi]) + + React.useEffect(() => { + if (!api) return + onSelect(api) + api.on("reInit", onSelect) + api.on("select", onSelect) + + return () => { + api?.off("select", onSelect) + } + }, [api, onSelect]) + + return ( + +
+ {children} +
+
+ ) +} + +function CarouselContent({ className, ...props }: React.ComponentProps<"div">) { + const { carouselRef, orientation } = useCarousel() + + return ( +
+
+
+ ) +} + +function CarouselItem({ className, ...props }: React.ComponentProps<"div">) { + const { orientation } = useCarousel() + + return ( +
+ ) +} + +function CarouselPrevious({ + className, + variant = "outline", + size = "icon", + ...props +}: React.ComponentProps) { + const { orientation, scrollPrev, canScrollPrev } = useCarousel() + + return ( + + ) +} + +function CarouselNext({ + className, + variant = "outline", + size = "icon", + ...props +}: React.ComponentProps) { + const { orientation, scrollNext, canScrollNext } = useCarousel() + + return ( + + ) +} + +export { + type CarouselApi, + Carousel, + CarouselContent, + CarouselItem, + CarouselPrevious, + CarouselNext, +} diff --git a/apps/web/components/content/jcdt/bqrx.tsx b/apps/web/components/content/jcdt/bqrx/bqrx.tsx similarity index 78% rename from apps/web/components/content/jcdt/bqrx.tsx rename to apps/web/components/content/jcdt/bqrx/bqrx.tsx index 0729f3e..300afb0 100644 --- a/apps/web/components/content/jcdt/bqrx.tsx +++ b/apps/web/components/content/jcdt/bqrx/bqrx.tsx @@ -1,6 +1,23 @@ import React from 'react'; - +import JtCarousel from '../fhjt/jtCarousel'; const BqrxPage = () => { + const carouselData = [ + { + id: 1, + image: '/header.png', + title: '军事风云第一期', + }, + { + id: 2, + image: '/header.png', + title: '军事风云第一期', + }, + { + id: 3, + image: '/header.png', + title: '军事风云第一期', + }, + ]; return (
{/* 左侧图片容器 */} @@ -8,16 +25,10 @@ const BqrxPage = () => { className="w-[1043px] h-full bg-cover bg-center relative" style={{ clipPath: 'polygon(0 0, calc(100% - 150px)-0.9%, calc(100% - 30px) 100%, 0 100%)', - backgroundImage: 'url(/header.png)', }} > -
-
-
-
-
+
- {/* 右侧烽火讲堂容器 */}
{/* 标题部分 */} @@ -35,7 +46,6 @@ const BqrxPage = () => { 首长信箱
-
{/* 奖项2 */} @@ -44,14 +54,13 @@ const BqrxPage = () => { 有问必答
- {/* 奖项3 */}
心灵树洞 - +
@@ -67,4 +76,4 @@ const BqrxPage = () => { ); }; -export default BqrxPage; \ No newline at end of file +export default BqrxPage; diff --git a/apps/web/components/content/jcdt/fhjt.tsx b/apps/web/components/content/jcdt/fhjt.tsx deleted file mode 100644 index dbea04d..0000000 --- a/apps/web/components/content/jcdt/fhjt.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import React from 'react'; - -const FhjtPage = () => { - return ( -
- {/* 左侧图片容器 */} -
-
-
-
-
-
-
-
- - {/* 右侧烽火讲堂容器 */} -
- {/* 标题部分 */} -
-

烽火讲堂

- {/* 蓝色装饰线 */} -
-
- - {/* 奖项列表 */} -
- {/* 奖项1 */} -
-
- 一等奖 - -
-

- 高级软件开发工程师王老八 -
- 王老八 -

-
- - {/* 奖项2 */} -
-
- 一等奖 - -
-

- 高级软件开发工程师王老八 -
- 王老八 -

-
- - {/* 奖项3 */} -
-
- 一等奖 - -
-

- 高级软件开发工程师王老八 -
- 王老八 -

-
-
- - {/* 更多授课按钮 */} -
- -
-
-
- ); -}; - -export default FhjtPage; \ No newline at end of file diff --git a/apps/web/components/content/jcdt/fhjt/fhjt.tsx b/apps/web/components/content/jcdt/fhjt/fhjt.tsx new file mode 100644 index 0000000..749c42e --- /dev/null +++ b/apps/web/components/content/jcdt/fhjt/fhjt.tsx @@ -0,0 +1,99 @@ +import React from 'react'; +import JtCarousel from './jtCarousel'; + +const FhjtPage = () => { + const carouselData = [ + { + id: 1, + image: '/header.png', + title: '军事风云第一期', + }, + { + id: 2, + image: '/header.png', + title: '军事风云第一期', + }, + { + id: 3, + image: '/header.png', + title: '军事风云第一期', + }, + + ]; + return ( + <> +
+ {/* 左侧图片容器 */} +
+ +
+ + {/* 右侧烽火讲堂容器 */} +
+ {/* 标题部分 */} +
+

烽火讲堂

+ {/* 蓝色装饰线 */} +
+
+ + {/* 奖项列表 */} +
+ {/* 奖项1 */} +
+
+ 一等奖 + +
+

+ 高级软件开发工程师王老八 +
+ 王老八 +

+
+ + {/* 奖项2 */} +
+
+ 一等奖 + +
+

+ 高级软件开发工程师王老八 +
+ 王老八 +

+
+ + {/* 奖项3 */} +
+
+ 一等奖 + +
+

+ 高级软件开发工程师王老八 +
+ 王老八 +

+
+
+ + {/* 更多授课按钮 */} +
+ +
+
+
+ + ); +}; + +export default FhjtPage; diff --git a/apps/web/components/content/jcdt/fhjt/jtCarousel.tsx b/apps/web/components/content/jcdt/fhjt/jtCarousel.tsx new file mode 100644 index 0000000..f88a84a --- /dev/null +++ b/apps/web/components/content/jcdt/fhjt/jtCarousel.tsx @@ -0,0 +1,72 @@ +import React, { useRef, useState, useEffect } from 'react'; +import Autoplay from 'embla-carousel-autoplay'; +import { Carousel, CarouselContent, CarouselItem, type CarouselApi } from '@repo/ui/components/carousel'; + +interface CarouselComponentProps { + carouselData: { id: number; image: string; title: string }[]; +} + +const JtCarousel: React.FC = ({ carouselData }) => { + const [carouselAPI, setCarouselAPI] = useState(null); + const [currentIndex, setCurrentIndex] = useState(0); + const plugin = useRef(Autoplay({ delay: 2000, stopOnInteraction: true })); + + // 监听轮播图变化 + useEffect(() => { + if (!carouselAPI) return; + + const updateCurrentIndex = () => { + setCurrentIndex(carouselAPI.selectedScrollSnap()); + }; + + carouselAPI.on('select', updateCurrentIndex); + + return () => { + carouselAPI.off('select', updateCurrentIndex); + }; + }, [carouselAPI]); + + // 滚动到指定索引 + const scrollToIndex = (index: number) => { + if (carouselAPI) { + carouselAPI.scrollTo(index); + setCurrentIndex(index); + } + }; + + return ( +
+ + + {carouselData.map((item) => ( + +
+ {/* 设置为100%宽高 */} + {item.title} +
+
+ ))} +
+
+ + {/* 圆点指示器 */} +
+ {carouselData.map((_, index) => ( +
+
+ ); +}; + +export default JtCarousel; diff --git a/apps/web/components/content/jcdt/fhwh/culture.tsx b/apps/web/components/content/jcdt/fhwh/culture.tsx new file mode 100644 index 0000000..8e527f2 --- /dev/null +++ b/apps/web/components/content/jcdt/fhwh/culture.tsx @@ -0,0 +1,186 @@ +import React, { useState, useEffect, useRef } from 'react'; +import { Swiper, SwiperSlide } from 'swiper/react'; +import { EffectCoverflow, Pagination, Autoplay, Navigation } from 'swiper/modules'; + +// 导入 Swiper 样式 +import 'swiper/css'; +import 'swiper/css/effect-coverflow'; +import 'swiper/css/pagination'; +import 'swiper/css/navigation'; + +// 模拟数据接口 +interface Article { + id: number; + cover: string; + title: string; + relative_link: string; +} + +interface OptionPage { + model_bg: { + url: string; + }; +} + +const CulturePage: React.FC = () => { + const [posts, setPosts] = useState([]); + const [isPostsFetching, setIsPostsFetching] = useState(true); + const [optionPage, setOptionPage] = useState(null); + const [displayItems, setDisplayItems] = useState([]); + + // 模拟数据获取 + useEffect(() => { + // 模拟异步数据加载 + const fetchData = async () => { + setIsPostsFetching(true); + + // 模拟API延迟 + await new Promise((resolve) => setTimeout(resolve, 1000)); + + // 模拟获取文章数据 + const mockPosts: Article[] = [ + { + id: 1, + cover: '/x4.png', + title: '烽火文化活动1', + relative_link: '/culture/1', + }, + { + id: 2, + cover: '/x4.png', + title: '烽火文化活动2', + relative_link: '/culture/2', + }, + { + id: 3, + cover: '/x4.png', + title: '烽火文化活动3', + relative_link: '/culture/3', + }, + { + id: 4, + cover: '/x4.png', + title: '烽火文化活动4', + relative_link: '/culture/4', + }, + { + id: 5, + cover: '/x4.png', + title: '烽火文化活动5', + relative_link: '/culture/5', + }, + ]; + + // 模拟选项页面数据 + const mockOptionPage: OptionPage = { + model_bg: { + url: '/culture-bg.jpg', + }, + }; + + setPosts(mockPosts); + setOptionPage(mockOptionPage); + setIsPostsFetching(false); + }; + + fetchData(); + }, []); + + // 监听posts变化,过滤有封面的文章 + useEffect(() => { + if (posts.length > 0) { + const filteredItems = posts.filter((post: Article) => post.cover); + setDisplayItems(filteredItems); + } + }, [posts]); + + // 空状态组件 + const EmptyState = () => ( +
+
+
📝
+

期待您的投稿!

+
+
+ ); + + return ( + <> +
+

烽火文化

+
+
+ {/* 加载状态 */} + {isPostsFetching && ( +
+
+
+

加载中...

+
+
+ )} + + {/* 空状态 */} + {!isPostsFetching && displayItems.length === 0 && } + + {/* 轮播图 */} + {!isPostsFetching && displayItems.length > 0 && ( + + )} +
+ + ); +}; + +export default CulturePage; diff --git a/apps/web/components/content/jcdt/fhwh/culturebg.tsx b/apps/web/components/content/jcdt/fhwh/culturebg.tsx new file mode 100644 index 0000000..73d97b2 --- /dev/null +++ b/apps/web/components/content/jcdt/fhwh/culturebg.tsx @@ -0,0 +1,79 @@ +import React from 'react'; + +const CultureBgPage: React.FC = () => { + // 定义logo数据 + const logos = [ + { id: 1, src: '/logo/1.png', alt: 'Logo 1' }, + { id: 2, src: '/logo/2.png', alt: 'Logo 2' }, + { id: 3, src: '/logo/3.png', alt: 'Logo 3' }, + { id: 4, src: '/logo/4.png', alt: 'Logo 4' }, + { id: 5, src: '/logo/5.png', alt: 'Logo 5' }, + { id: 6, src: '/logo/6.png', alt: 'Logo 6' }, + { id: 7, src: '/logo/7.png', alt: 'Logo 7' }, + { id: 8, src: '/logo/8.png', alt: 'Logo 8' }, + { id: 9, src: '/logo/9.png', alt: 'Logo 9' }, + { id: 10, src: '/logo/10.png', alt: 'Logo 10' }, + { id: 11, src: '/logo/11.png', alt: 'Logo 11' }, + { id: 12, src: '/logo/12.png', alt: 'Logo 12' }, + { id: 13, src: '/logo/13.png', alt: 'Logo 13' }, + { id: 14, src: '/logo/14.png', alt: 'Logo 14' }, + { id: 15, src: '/logo/15.png', alt: 'Logo 15' }, + { id: 16, src: '/logo/16.png', alt: 'Logo 16' }, + ]; + + // 分组:上排8个,下排8个 + const topRowLogos = logos.slice(0, 8); + const bottomRowLogos = logos.slice(8, 16); + + return ( +
+
+ +
+
+ + {/* 上排logo */} +
+ {topRowLogos.map((logo) => ( + {logo.alt} + ))} +
+ + {/* 下排logo */} +
+ {bottomRowLogos.map((logo) => ( + {logo.alt} + ))} +
+ +
+
+
+ ); +}; + +export default CultureBgPage; \ No newline at end of file diff --git a/apps/web/components/content/jcdt/fhws/WsCarousel.tsx b/apps/web/components/content/jcdt/fhws/WsCarousel.tsx new file mode 100644 index 0000000..c03c7d3 --- /dev/null +++ b/apps/web/components/content/jcdt/fhws/WsCarousel.tsx @@ -0,0 +1,76 @@ +import React, { useRef, useState, useEffect } from 'react'; +import Autoplay from "embla-carousel-autoplay"; +import { + Carousel, + CarouselContent, + CarouselItem, + type CarouselApi +} from "@repo/ui/components/carousel"; + +interface CarouselComponentProps { + carouselData: { id: number; image: string; title: string }[]; +} + +const WsCarousel: React.FC = ({ carouselData }) => { + const [carouselAPI, setCarouselAPI] = useState(null); + const [currentIndex, setCurrentIndex] = useState(0); + const plugin = useRef(Autoplay({ delay: 3000, stopOnInteraction: true })); + + // 监听轮播图变化 + useEffect(() => { + if (!carouselAPI) return; + + const updateCurrentIndex = () => { + setCurrentIndex(carouselAPI.selectedScrollSnap()); + }; + + carouselAPI.on("select", updateCurrentIndex); + + return () => { + carouselAPI.off("select", updateCurrentIndex); + }; + }, [carouselAPI]); + + // 滚动到指定索引 + const scrollToIndex = (index: number) => { + if (carouselAPI) { + carouselAPI.scrollTo(index); + setCurrentIndex(index); + } + }; + + return ( +
+ + + {carouselData.map((item) => ( + +
{/* 设置为100%宽高 */} + {item.title} +
+
+ ))} +
+
+ + {/* 圆点指示器 */} +
+ {carouselData.map((_, index) => ( +
+
+ ); +}; + +export default WsCarousel; \ No newline at end of file diff --git a/apps/web/components/content/jcdt/fhws.tsx b/apps/web/components/content/jcdt/fhws/fhws.tsx similarity index 60% rename from apps/web/components/content/jcdt/fhws.tsx rename to apps/web/components/content/jcdt/fhws/fhws.tsx index e46fac4..adccb64 100644 --- a/apps/web/components/content/jcdt/fhws.tsx +++ b/apps/web/components/content/jcdt/fhws/fhws.tsx @@ -1,6 +1,24 @@ import React from 'react'; - +import WsCarousel from './WsCarousel'; const FhwsPage = () => { + const carouselData = [ + { + id: 1, + image: '/header.png', + title: '军事风云第一期', + }, + { + id: 2, + image: '/header.png', + title: '军事风云第一期', + }, + { + id: 3, + image: '/header.png', + title: '军事风云第一期', + }, + + ]; return (
{/* 右侧烽火微视容器 */} @@ -16,25 +34,25 @@ const FhwsPage = () => {
{/* 视频项1 */}
- +

岗位尖兵比武视频

{/* 视频项2 */}
- +

晚会视频

{/* 视频项3 */}
- +

退伍视频

{/* 视频项4 */}
- +

共同科目尖兵比武视频

@@ -49,19 +67,13 @@ const FhwsPage = () => { {/* 左侧图片/视频容器 */}
{/* 右下角圆点指示器 */} -
-
-
-
-
-
+
); diff --git a/apps/web/components/content/jcdt/lbbz/CarouselComponent.tsx b/apps/web/components/content/jcdt/lbbz/CarouselComponent.tsx new file mode 100644 index 0000000..8256988 --- /dev/null +++ b/apps/web/components/content/jcdt/lbbz/CarouselComponent.tsx @@ -0,0 +1,76 @@ +import React, { useRef, useState, useEffect } from 'react'; +import Autoplay from "embla-carousel-autoplay"; +import { + Carousel, + CarouselContent, + CarouselItem, + type CarouselApi +} from "@repo/ui/components/carousel"; + +interface CarouselComponentProps { + carouselData: { id: number; image: string; title: string }[]; +} + +const CarouselComponent: React.FC = ({ carouselData }) => { + const [carouselAPI, setCarouselAPI] = useState(null); + const [currentIndex, setCurrentIndex] = useState(0); + const plugin = useRef(Autoplay({ delay: 2000, stopOnInteraction: true })); + + // 监听轮播图变化 + useEffect(() => { + if (!carouselAPI) return; + + const updateCurrentIndex = () => { + setCurrentIndex(carouselAPI.selectedScrollSnap()); + }; + + carouselAPI.on("select", updateCurrentIndex); + + return () => { + carouselAPI.off("select", updateCurrentIndex); + }; + }, [carouselAPI]); + + // 滚动到指定索引 + const scrollToIndex = (index: number) => { + if (carouselAPI) { + carouselAPI.scrollTo(index); + setCurrentIndex(index); + } + }; + + return ( +
{/* 添加相对定位 */} + + + {carouselData.map((item) => ( + +
+ {item.title} +
+
+ ))} +
+
+ + {/* 圆点指示器 */} +
{/* 添加绝对定位 */} + {carouselData.map((_, index) => ( +
+
+ ); +}; + +export default CarouselComponent; \ No newline at end of file diff --git a/apps/web/components/content/jcdt/lbbz/lbbz.tsx b/apps/web/components/content/jcdt/lbbz/lbbz.tsx new file mode 100644 index 0000000..01f442d --- /dev/null +++ b/apps/web/components/content/jcdt/lbbz/lbbz.tsx @@ -0,0 +1,261 @@ +import React, { useEffect, useRef, useState } from 'react'; +import Autoplay from 'embla-carousel-autoplay'; +import { + Carousel, + CarouselApi, + CarouselContent, + CarouselItem, + CarouselNext, + CarouselPrevious, +} from '@repo/ui/components/carousel'; +import CarouselComponent from './CarouselComponent'; + + +const LbbzPage: React.FC = () => { + // const plugin = useRef(Autoplay({ delay: 1000, stopOnInteraction: true })); + // const [currentIndex, setCurrentIndex] = useState(0); + // const [carouselAPI, setCarouselAPI] = useState(null); + // 模拟舆情数据 + const mockYuqingData = [ + { id: 1, title: '开源舆情2025第2期', date: '20250113' }, + { id: 2, title: '开源舆情2025第1期', date: '20250107' }, + { id: 3, title: '开源舆情2024第52期', date: '20241220' }, + { id: 4, title: '开源舆情2024第51期', date: '20241211' }, + { id: 5, title: '开源舆情2024第50期', date: '20241127' }, + { id: 6, title: '开源舆情2024第49期', date: '20241116' }, + { id: 7, title: '开源舆情2024第48期', date: '20241020' }, + { id: 8, title: '开源舆情2024第47期', date: '20241016' }, + { id: 9, title: '开源舆情2025第2期', date: '20250113' }, + { id: 10, title: '开源舆情2025第1期', date: '20250107' }, + { id: 11, title: '开源舆情2024第52期', date: '20241220' }, + { id: 12, title: '开源舆情2024第51期', date: '20241211' }, + { id: 13, title: '开源舆情2024第50期', date: '20241127' }, + { id: 14, title: '开源舆情2024第49期', date: '20241116' }, + { id: 15, title: '开源舆情2024第48期', date: '20241020' }, + { id: 16, title: '开源舆情2024第47期', date: '20241016' }, + ]; + const carouselData1= [ + { + id: 1, + image: '/header.png', + title: '军事风云第一期', + }, + { + id: 2, + image: '/book1.png', + title: '军事风云第二期 ', + }, + { + id: 3, + image: '/book2.png', + title: '军事风云第三期', + }, + { + id: 4, + image: '/x1.png', + title: '军事风云第三期', + }, + { + id: 5, + image: '/x2.png', + title: '军事风云第三期', + }, + ]; + + // // 监听幻灯片变化 + // useEffect(() => { + // if (!carouselAPI) return; + + // const updateCurrentIndex = () => { + // setCurrentIndex(carouselAPI.selectedScrollSnap()); + // }; + + // carouselAPI.on('select', updateCurrentIndex); + + // return () => { + // carouselAPI.off('select', updateCurrentIndex); + // }; + // }, [carouselAPI]); + + // 滚动到指定索引 + // const scrollToIndex = (index: number) => { + // if (carouselAPI) { + // carouselAPI.scrollTo(index); + // setCurrentIndex(index); // 更新当前索引 + // } + // }; + + // 将数据分成两列 + const leftColumnData = mockYuqingData.slice(0, 8); + const rightColumnData = mockYuqingData.slice(8, 16); + + return ( + <> +
+ {/* 上部容器 */} +
+

练兵备战

+
+ + {/* 下部容器 */} +
+ {/* 上半部分 - 三个并排的容器 */} +
+
+ + +
+ 军事风云 +
+
+
+ +
+ 演训聚焦 +
+
+
+
1
+
+ 开源舆情 +
+
+
+ + {/* 下方新增的容器 */} +
+ {/* 左侧 */} +
+ {/* 环球IOS标题 */} +
+ + 环球70S + +
+
+ + {/* 中间 - */} +
+
+
+
+
+ 2024年40期 +
+

巴格多格拉空军基地

+
+
+ + {/* 宣布亚空军基地 */} +
+
+
+
+ 2024年39期 +
+

宣布亚空军基地

+
+
+
+ + {/* 右侧 - 形势战备 */} +
+ {/* 形势战备标题 */} +
+ + 形势战备 + +
+
+ + {/* 右侧卡片区域 */} +
+ {/* 形势战备教育2024年第13期 */} +
+
+
+
+ 2024年第13期 +
+

形势战备教育2024年第13期

+
+
+ + {/* 形势战备教育2024年第12期 */} +
+
+
+
+ 2024年第12期 +
+

形势战备教育2024年第12期

+
+
+
+
+
+
+ + {/* 舆情区域 - 两列布局 */} +
+
+ {/* 左列 */} +
+ {leftColumnData.map((item) => ( +
+ {/* 左侧钻石图标和标题 */} +
+
+

{item.title}

+
+ {/* 右侧日期 */} + {item.date} +
+ ))} +
+ + {/* 右列 */} +
+ {rightColumnData.map((item) => ( +
+ {/* 左侧钻石图标和标题 */} +
+
+

{item.title}

+
+ {/* 右侧日期 */} + {item.date} +
+ ))} +
+
+
+ + ); +}; + +export default LbbzPage; diff --git a/apps/web/components/content/jcdt/page.tsx b/apps/web/components/content/jcdt/page.tsx index 810b9cf..1ae2649 100644 --- a/apps/web/components/content/jcdt/page.tsx +++ b/apps/web/components/content/jcdt/page.tsx @@ -1,8 +1,11 @@ import JcdtList from './jcdtlist'; -import FhjtPage from './fhjt'; -import FhwsPage from './fhws'; -import BqrxPage from './bqrx'; -import Integrated from '../integ/Integrated'; +import FhjtPage from './fhjt/fhjt'; +import FhwsPage from './fhws/fhws'; +import BqrxPage from './bqrx/bqrx'; +import Integrated from '../zhfw/Integrated'; +import CulturePage from './fhwh/culture'; +import CultureBgPage from './fhwh/culturebg'; +import LbbzPage from './lbbz/lbbz'; const JcdtContainer = () => { return ( <> @@ -21,17 +24,22 @@ const JcdtContainer = () => { >
+
+ +
+ +
- ); + ); }; export default JcdtContainer; diff --git a/apps/web/components/content/navbar/page.tsx b/apps/web/components/content/navbar/page.tsx index 25e2917..0cd3188 100644 --- a/apps/web/components/content/navbar/page.tsx +++ b/apps/web/components/content/navbar/page.tsx @@ -1,6 +1,7 @@ import { log } from 'console'; import React, { useState, useRef, useEffect } from 'react'; import './scroll.css'; +import JtCarousel from '../jcdt/fhjt/jtCarousel'; const Navbar: React.FC = () => { const [activeIndex, setActiveIndex] = useState(1); // 当前选中的导航项索引 @@ -83,8 +84,26 @@ const Navbar: React.FC = () => { } }, [activeIndex]); + const carouselData = [ + { + id: 1, + image: '/header.png', + title: '军事风云第一期', + }, + { + id: 2, + image: '/header.png', + title: '军事风云第二期', + }, + { + id: 3, + image: '/lanmu.png', + title: '军事风云第三期', + }, + ]; + return ( -
+
{/* 顶部导航栏区域 */}
{/* 左侧搜索框区域 */} @@ -131,55 +150,48 @@ const Navbar: React.FC = () => {
{/* 主要内容区域 */} -
- {/* 左侧内容 */} -
-

+
+ +
+ + {/* 右侧烽火要闻容器 */} +
+ {/* 标题栏 */} +
+

烽火要闻

+
- {/* 右侧烽火要闻容器 */} -
- {/* 标题栏 */} -
-

烽火要闻

- -
- - {/* 文章列表 */} -
- {articles.map((article, index) => ( -
- {/* 左侧竖线和日期 */} -
-
-
-
{article.date.month}
-
{article.date.day}
-
-
- {/* 右侧文章内容 */} -
-

{article.title}【MORE】

- + {/* 文章列表 */} +
+ {articles.map((article, index) => ( +
+ {/* 左侧竖线和日期 */} +
+
+
+
{article.date.month}
+
{article.date.day}
- ))} - -
+ {/* 右侧文章内容 */} +
+

+ {article.title} + + 【MORE】 + +

+
+
+ ))}
- {/*
-
-
-
-
-
-
*/}
); }; diff --git a/apps/web/components/content/qjsx/page.tsx b/apps/web/components/content/qjsx/page.tsx index a905bc1..f6986c4 100644 --- a/apps/web/components/content/qjsx/page.tsx +++ b/apps/web/components/content/qjsx/page.tsx @@ -34,7 +34,7 @@ const NewPage = () => {
{/* 查看更多标签 */}
-
@@ -44,8 +44,8 @@ const NewPage = () => {
{/* 左侧圆点和标题 */}
-
-

{item.title}

+
+ {item.title}
{/* 右侧日期 */} {item.date} @@ -60,7 +60,7 @@ const NewPage = () => {
{/* 查看更多标签 */}
-
@@ -71,7 +71,7 @@ const NewPage = () => { {/* 左侧圆点和标题 */}
-

{item.title}

+ {item.title}
{/* 右侧日期 */} {item.date} diff --git a/apps/web/components/content/xxjxs/carouselDemo.tsx b/apps/web/components/content/xxjxs/carouselDemo.tsx index 16a864b..2eecb23 100644 --- a/apps/web/components/content/xxjxs/carouselDemo.tsx +++ b/apps/web/components/content/xxjxs/carouselDemo.tsx @@ -1,8 +1,13 @@ -'use client'; -import React from 'react'; -import { Carousel } from 'antd'; +// ... existing code ... +import React, { useRef, useState, useEffect } from 'react'; +import Autoplay from 'embla-carousel-autoplay'; +import { Carousel, CarouselContent, CarouselItem, type CarouselApi } from '@repo/ui/components/carousel'; const CarouselDemo: React.FC = () => { + const [carouselAPI, setCarouselAPI] = useState(null); + const [currentIndex, setCurrentIndex] = useState(0); + const plugin = useRef(Autoplay({ delay: 2000, stopOnInteraction: true })); + // 轮播图数据 const slides = [ { @@ -22,20 +27,64 @@ const CarouselDemo: React.FC = () => { }, ]; + // 监听轮播图变化 + useEffect(() => { + if (!carouselAPI) return; + + const updateCurrentIndex = () => { + setCurrentIndex(carouselAPI.selectedScrollSnap()); + }; + + carouselAPI.on('select', updateCurrentIndex); + + return () => { + carouselAPI.off('select', updateCurrentIndex); + }; + }, [carouselAPI]); + + // 滚动到指定索引 + const scrollToIndex = (index: number) => { + if (carouselAPI) { + carouselAPI.scrollTo(index); + setCurrentIndex(index); + } + }; + return ( -
- - {slides.map((slide) => ( -
- {slide.content} -
- ))} +
+ + + {slides.map((slide) => ( + +
+ {slide.content} +
+
+ ))} +
+ + {/* 圆点指示器 */} +
+ {slides.map((_, index) => ( +
); }; diff --git a/apps/web/components/content/xxjxs/page.tsx b/apps/web/components/content/xxjxs/page.tsx index bb46df1..ca3f210 100644 --- a/apps/web/components/content/xxjxs/page.tsx +++ b/apps/web/components/content/xxjxs/page.tsx @@ -14,19 +14,19 @@ const LearnPage = () => { ]; return ( -
+
{/* 学习进行时图片 */}
{/* 轮播图 */} -
+
{/* 左边容器 */} -
-
+
+
-
+
diff --git a/apps/web/components/content/integ/Integrated.tsx b/apps/web/components/content/zhfw/Integrated.tsx similarity index 100% rename from apps/web/components/content/integ/Integrated.tsx rename to apps/web/components/content/zhfw/Integrated.tsx diff --git a/apps/web/package.json b/apps/web/package.json index 5fb9767..1dd7fc1 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -24,7 +24,10 @@ "@trpc/tanstack-react-query": "11.1.2", "antd": "^5.25.4", "axios": "^1.7.2", + "class-variance-authority": "^0.7.1", "dayjs": "^1.11.12", + "embla-carousel-autoplay": "^8.6.0", + "embla-carousel-react": "^8.6.0", "lucide-react": "0.511.0", "next": "15.3.2", "next-themes": "^0.4.6", @@ -32,6 +35,7 @@ "react": "^19.1.0", "react-dom": "^19.1.0", "superjson": "^2.2.2", + "swiper": "^11.2.8", "tus-js-client": "^4.3.1", "valibot": "^1.1.0" }, diff --git a/apps/web/public/culture.png b/apps/web/public/culture.png new file mode 100644 index 0000000..48c95bf Binary files /dev/null and b/apps/web/public/culture.png differ diff --git a/apps/web/public/lanmu.png b/apps/web/public/lanmu.png old mode 100644 new mode 100755 index 75a8636..dab7086 Binary files a/apps/web/public/lanmu.png and b/apps/web/public/lanmu.png differ diff --git a/apps/web/public/learn.png b/apps/web/public/learn.png index 0f975ec..db05395 100644 Binary files a/apps/web/public/learn.png and b/apps/web/public/learn.png differ diff --git a/apps/web/public/logo/1.png b/apps/web/public/logo/1.png new file mode 100644 index 0000000..e09d3d3 Binary files /dev/null and b/apps/web/public/logo/1.png differ diff --git a/apps/web/public/logo/10.png b/apps/web/public/logo/10.png new file mode 100644 index 0000000..b470bac Binary files /dev/null and b/apps/web/public/logo/10.png differ diff --git a/apps/web/public/logo/11.png b/apps/web/public/logo/11.png new file mode 100644 index 0000000..eeaa72a Binary files /dev/null and b/apps/web/public/logo/11.png differ diff --git a/apps/web/public/logo/12.png b/apps/web/public/logo/12.png new file mode 100644 index 0000000..ed04994 Binary files /dev/null and b/apps/web/public/logo/12.png differ diff --git a/apps/web/public/logo/13.png b/apps/web/public/logo/13.png new file mode 100644 index 0000000..fe4cdaa Binary files /dev/null and b/apps/web/public/logo/13.png differ diff --git a/apps/web/public/logo/14.png b/apps/web/public/logo/14.png new file mode 100644 index 0000000..4202989 Binary files /dev/null and b/apps/web/public/logo/14.png differ diff --git a/apps/web/public/logo/15.png b/apps/web/public/logo/15.png new file mode 100644 index 0000000..2441199 Binary files /dev/null and b/apps/web/public/logo/15.png differ diff --git a/apps/web/public/logo/16.png b/apps/web/public/logo/16.png new file mode 100644 index 0000000..9b32b59 Binary files /dev/null and b/apps/web/public/logo/16.png differ diff --git a/apps/web/public/logo/2.png b/apps/web/public/logo/2.png new file mode 100644 index 0000000..117c833 Binary files /dev/null and b/apps/web/public/logo/2.png differ diff --git a/apps/web/public/logo/3.png b/apps/web/public/logo/3.png new file mode 100644 index 0000000..7ce082e Binary files /dev/null and b/apps/web/public/logo/3.png differ diff --git a/apps/web/public/logo/4.png b/apps/web/public/logo/4.png new file mode 100644 index 0000000..a101523 Binary files /dev/null and b/apps/web/public/logo/4.png differ diff --git a/apps/web/public/logo/5.png b/apps/web/public/logo/5.png new file mode 100644 index 0000000..7490a4f Binary files /dev/null and b/apps/web/public/logo/5.png differ diff --git a/apps/web/public/logo/6.png b/apps/web/public/logo/6.png new file mode 100644 index 0000000..e30cd59 Binary files /dev/null and b/apps/web/public/logo/6.png differ diff --git a/apps/web/public/logo/7.png b/apps/web/public/logo/7.png new file mode 100644 index 0000000..dfc82d6 Binary files /dev/null and b/apps/web/public/logo/7.png differ diff --git a/apps/web/public/logo/8.png b/apps/web/public/logo/8.png new file mode 100644 index 0000000..85e5c63 Binary files /dev/null and b/apps/web/public/logo/8.png differ diff --git a/apps/web/public/logo/9.png b/apps/web/public/logo/9.png new file mode 100644 index 0000000..6dbf8c7 Binary files /dev/null and b/apps/web/public/logo/9.png differ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 554cf7b..9f2daab 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -95,7 +95,7 @@ importers: devDependencies: '@types/bun': specifier: latest - version: 1.2.15 + version: 1.2.16 '@types/node': specifier: ^22.15.21 version: 22.15.21 @@ -153,9 +153,18 @@ importers: axios: specifier: ^1.7.2 version: 1.7.7 + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 dayjs: specifier: ^1.11.12 version: 1.11.13 + embla-carousel-autoplay: + specifier: ^8.6.0 + version: 8.6.0(embla-carousel@8.6.0) + embla-carousel-react: + specifier: ^8.6.0 + version: 8.6.0(react@19.1.0) lucide-react: specifier: 0.511.0 version: 0.511.0(react@19.1.0) @@ -177,6 +186,9 @@ importers: superjson: specifier: ^2.2.2 version: 2.2.2 + swiper: + specifier: ^11.2.8 + version: 11.2.8 tus-js-client: specifier: ^4.3.1 version: 4.3.1 @@ -2597,8 +2609,8 @@ packages: '@types/body-parser@1.19.5': resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} - '@types/bun@1.2.15': - resolution: {integrity: sha512-U1ljPdBEphF0nw1MIk0hI7kPg7dFdPyM7EenHsp6W5loNHl7zqy6JQf/RKCgnUn2KDzUpkBwHPnEJEjII594bA==} + '@types/bun@1.2.16': + resolution: {integrity: sha512-1aCZJ/6nSiViw339RsaNhkNoEloLaPzZhxMOYEa7OzRzO41IGg5n/7I43/ZIAW/c+Q6cT12Vf7fOZOoVIzb5BQ==} '@types/command-line-args@5.2.3': resolution: {integrity: sha512-uv0aG6R0Y8WHZLTamZwtfsDLVRnOa+n+n5rEvFWL5Na5gZ8V2Teab/duDPFzIIIhs9qizDpcavCusCLJZu62Kw==} @@ -2998,8 +3010,8 @@ packages: buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - bun-types@1.2.15: - resolution: {integrity: sha512-NarRIaS+iOaQU1JPfyKhZm4AsUOrwUOqRNHY0XxI8GI8jYxiLXLcdjYMG9UKS+fwWasc1uw1htV9AX24dD+p4w==} + bun-types@1.2.16: + resolution: {integrity: sha512-ciXLrHV4PXax9vHvUrkvun9VPVGOVwbbbBF/Ev1cXz12lyEZMoJpIJABOfPcN9gDJRaiKF9MVbSygLg4NXu3/A==} bundle-require@4.2.1: resolution: {integrity: sha512-7Q/6vkyYAwOmQNRw75x+4yRtZCZJXUDmHHlFdkiV0wgv/reNjtJwpu1jPJ0w2kbEpIM0uoKI3S4/f39dU7AjSA==} @@ -3449,6 +3461,24 @@ packages: electron-to-chromium@1.5.157: resolution: {integrity: sha512-/0ybgsQd1muo8QlnuTpKwtl0oX5YMlUGbm8xyqgDU00motRkKFFbUJySAQBWcY79rVqNLWIWa87BGVGClwAB2w==} + embla-carousel-autoplay@8.6.0: + resolution: {integrity: sha512-OBu5G3nwaSXkZCo1A6LTaFMZ8EpkYbwIaH+bPqdBnDGQ2fh4+NbzjXjs2SktoPNKCtflfVMc75njaDHOYXcrsA==} + peerDependencies: + embla-carousel: 8.6.0 + + embla-carousel-react@8.6.0: + resolution: {integrity: sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA==} + peerDependencies: + react: ^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + embla-carousel-reactive-utils@8.6.0: + resolution: {integrity: sha512-fMVUDUEx0/uIEDM0Mz3dHznDhfX+znCCDCeIophYb1QGVM7YThSWX+wz11zlYwWFOr74b4QLGg0hrGPJeG2s4A==} + peerDependencies: + embla-carousel: 8.6.0 + + embla-carousel@8.6.0: + resolution: {integrity: sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -5633,6 +5663,10 @@ packages: swap-case@1.1.2: resolution: {integrity: sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==} + swiper@11.2.8: + resolution: {integrity: sha512-S5FVf6zWynPWooi7pJ7lZhSUe2snTzqLuUzbd5h5PHUOhzgvW0bLKBd2wv0ixn6/5o9vwc/IkQT74CRcLJQzeg==} + engines: {node: '>= 4.7.0'} + table-layout@4.1.1: resolution: {integrity: sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==} engines: {node: '>=12.17'} @@ -8446,9 +8480,9 @@ snapshots: '@types/connect': 3.4.38 '@types/node': 20.17.50 - '@types/bun@1.2.15': + '@types/bun@1.2.16': dependencies: - bun-types: 1.2.15 + bun-types: 1.2.16 '@types/command-line-args@5.2.3': {} @@ -8993,7 +9027,7 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 - bun-types@1.2.15: + bun-types@1.2.16: dependencies: '@types/node': 20.17.50 @@ -9454,6 +9488,22 @@ snapshots: electron-to-chromium@1.5.157: {} + embla-carousel-autoplay@8.6.0(embla-carousel@8.6.0): + dependencies: + embla-carousel: 8.6.0 + + embla-carousel-react@8.6.0(react@19.1.0): + dependencies: + embla-carousel: 8.6.0 + embla-carousel-reactive-utils: 8.6.0(embla-carousel@8.6.0) + react: 19.1.0 + + embla-carousel-reactive-utils@8.6.0(embla-carousel@8.6.0): + dependencies: + embla-carousel: 8.6.0 + + embla-carousel@8.6.0: {} + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -12047,6 +12097,8 @@ snapshots: lower-case: 1.1.4 upper-case: 1.1.3 + swiper@11.2.8: {} + table-layout@4.1.1: dependencies: array-back: 6.2.2