Skip to content
Snippets Groups Projects
Commit ae04ecb5 authored by 汤绍坚's avatar 汤绍坚
Browse files

tsj: 1、实现专项服务需求; 2、实现视频获取接口列表及后面的逻辑,暂不播放视频

parent 9e999fec
Branches
Tags
No related merge requests found
......@@ -28,9 +28,6 @@ const UrlCard: React.FC<UrlCardProps> = ({
const handleClick = () => {
// 调用onClick传递id
onClick?.(id);
// 打开新窗口
// window.open(targetUrl, '_blank');
};
const handleMouseEnter =()=>{
setIsHover(true);
......
......@@ -26,6 +26,7 @@ interface UrlCardConfig {
logoSrc: string;
titleSrc: string;
targetUrl: string;
action?: 'refresh' | 'newTab'; // 新增动作类型
}
const RightBottom: React.FC = () => {
......@@ -37,54 +38,75 @@ const RightBottom: React.FC = () => {
id: 'card1',
logoSrc: logo1,
titleSrc: title1,
targetUrl: 'https://example.com/target1',
targetUrl: '', // 指挥调度,暂无链接
action: 'newTab',
},
{
id: 'card2',
logoSrc: logo2,
titleSrc: title2,
targetUrl: 'https://example.com/target2',
targetUrl: '',
action: 'refresh', // 众智成城,刷新首页
},
{
id: 'card3',
logoSrc: logo3,
titleSrc: title3,
targetUrl: 'https://example.com/target3',
targetUrl: '', // 诚管24,暂无链接
action: 'newTab',
},
{
id: 'card4',
logoSrc: logo4,
titleSrc: title4,
targetUrl: 'https://example.com/target4',
targetUrl: '', // 体征指数,暂无链接
action: 'newTab',
},
{
id: 'card5',
logoSrc: logo5,
titleSrc: title5,
targetUrl: 'https://example.com/target5',
targetUrl: 'https://10.1.174.34:13600/gridManage', // 网格基座
action: 'newTab',
},
{
id: 'card6',
logoSrc: logo6,
titleSrc: title6,
targetUrl: 'https://example.com/target6',
targetUrl: 'https://10.1.214.173:8688/autoLogin', // 数据底座
action: 'newTab',
},
{
id: 'card7',
logoSrc: logo7,
titleSrc: title7,
targetUrl: 'https://example.com/target7',
targetUrl: 'https://10.1.174.34:13600/gridManageOther', // 感知治理
action: 'newTab',
},
{
id: 'card8',
logoSrc: logo8,
titleSrc: title8,
targetUrl: 'https://example.com/target8',
targetUrl: '', // 信息安全,暂无链接
action: 'newTab',
},
];
const handleCardClick = (id: string) => {
setActiveCardId(id);
// 找到对应的卡片配置
const card = cardConfigs.find(card => card.id === id);
if (!card) return;
// 根据卡片动作类型执行不同操作
if (card.action === 'refresh') {
// 刷新页面
window.location.reload();
} else if (card.action === 'newTab' && card.targetUrl) {
// 在新标签页打开链接
window.open(card.targetUrl, '_blank');
}
};
// 将卡片分成两行
......
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useCallback } from 'react';
import classNames from 'classnames';
import { message } from 'antd';
import VideoPlayer from '../VideoPlayer';
import styles from './index.less';
import services from '@/services';
// Define types
// 视频分类类型定义
type VideoType = '1' | '2' | '3' | '4'; // 分类(1-农贸市场,2-背街小巷,3-重点区域,4-地铁口)
type VideoTypeMap = Record<VideoType, string>;
// 视频分类名称映射
const videoTypeNames: VideoTypeMap = {
'1': '农贸市场',
'2': '背街小巷',
'3': '重点区域',
'4': '地铁口'
};
// 定义视频项接口
interface VideoItem {
id: string;
title: string;
deviceId: string;
deviceId: string; // cameraIndexCode
type: VideoType;
}
const VideoCarousel: React.FC = () => {
// 视频设备 ID
const videoItems: VideoItem[] = [
{ id: '1', title: '重点区域', deviceId: '000732AFDC7D' },
{ id: '2', title: '背街小巷', deviceId: '000732BD46DE' },
{ id: '3', title: '农贸市场', deviceId: '000732AFDC7D' },
{ id: '4', title: '地铁口', deviceId: '000732BD46DE' },
];
// 后端返回的视频数据接口
interface CameraClassificationVO {
cameraIndexCode: string;
cameraName: string;
cameraPinyin: string;
directoryName: string;
directoryPath: string;
type: string;
}
// 分类后的视频列表类型
type CategoryVideos = Record<VideoType, VideoItem[]>;
const [activeVideoId, setActiveVideoId] = useState<string>(videoItems[0].id);
const VideoCarousel: React.FC = () => {
// 所有视频数据(分类后)
const [categoryVideos, setCategoryVideos] = useState<CategoryVideos>({
'1': [],
'2': [],
'3': [],
'4': []
});
const showVideo = false;
// 当前活动的设备ID
const [activeDeviceId, setActiveDeviceId] = useState<string>('');
// 当前类型下的活动视频索引
const [activeVideoIndices, setActiveVideoIndices] = useState<Record<VideoType, number>>({
'1': 0,
'2': 0,
'3': 0,
'4': 0
});
const [playerInitialized, setPlayerInitialized] = useState<boolean>(false);
const [autoRotate, setAutoRotate] = useState<boolean>(true);
// 获取视频列表数据
const getVideoData = useCallback(async () => {
try {
const res = await services.DataBase.getGzInfoData({
typeCode: 'gz-spsbxx',
"data": {
"current": 1,
"size": 100, // 获取更多数据
// 不指定type,获取所有类型
}
});
if (res.code === 200) {
console.log('获取视频数据成功:', res.data);
// 初始化分类视频数据
const categorized: CategoryVideos = {
'1': [],
'2': [],
'3': [],
'4': []
};
// 处理并分类视频数据
if (res.data && res.data.records && Array.isArray(res.data.records)) {
res.data.records.forEach((item: CameraClassificationVO, index: number) => {
// 确保类型是合法的视频类型
const videoType = item.type as VideoType;
if (['1', '2', '3', '4'].includes(videoType)) {
categorized[videoType].push({
id: `${videoType}-${index}`,
title: item.cameraName || videoTypeNames[videoType],
deviceId: item.cameraIndexCode,
type: videoType
});
}
});
}
console.log('分类后的视频数据:', categorized);
setCategoryVideos(categorized);
// 设置初始活动视频
Object.keys(categorized).forEach((type) => {
const typedType = type as VideoType;
if (categorized[typedType].length > 0 && !activeDeviceId) {
setActiveDeviceId(categorized[typedType][0].deviceId);
}
});
} else {
message.error('获取视频数据失败');
}
} catch (error) {
console.error('获取视频数据异常:', error);
message.error('获取视频数据发生异常');
}
}, [activeDeviceId]);
// 自动旋转视频
// 初始化时获取视频数据
useEffect(() => {
getVideoData();
}, [getVideoData]);
// 自动旋转各类型的视频
useEffect(() => {
if (!autoRotate || !playerInitialized) return;
// 为每种类型的视频设置自动轮播
const rotationInterval = setInterval(() => {
setActiveVideoId(prevId => {
const currentIndex = videoItems.findIndex(item => item.id === prevId);
const nextIndex = (currentIndex + 1) % videoItems.length;
return videoItems[nextIndex].id;
setActiveVideoIndices(prevIndices => {
const newIndices = { ...prevIndices };
// 对每个类型,如果该类型有视频,则切换到下一个
Object.keys(categoryVideos).forEach((type) => {
const typedType = type as VideoType;
const videos = categoryVideos[typedType];
if (videos.length > 0) {
newIndices[typedType] = (newIndices[typedType] + 1) % videos.length;
}
});
return newIndices;
});
// 更新当前活动设备ID为当前正在播放的视频设备ID
const typeKeys = Object.keys(categoryVideos) as VideoType[];
for (const type of typeKeys) {
const videos = categoryVideos[type];
if (videos.length > 0) {
const currentIndex = activeVideoIndices[type];
setActiveDeviceId(videos[currentIndex].deviceId);
break;
}
}
}, 30000); // 30秒切换一次
return () => clearInterval(rotationInterval);
}, [videoItems, autoRotate, playerInitialized]);
}, [categoryVideos, autoRotate, playerInitialized, activeVideoIndices]);
// 处理视频初始化完成
const handlePlayerInitialized = (success: boolean) => {
......@@ -47,9 +169,20 @@ const VideoCarousel: React.FC = () => {
}
};
// 处理点击视频项
const handleVideoItemClick = (videoId: string) => {
setActiveVideoId(videoId);
// 处理点击视频
const handleVideoClick = (deviceId: string, type: VideoType) => {
console.log('视频点击:', deviceId, type);
setActiveDeviceId(deviceId);
// 找到对应类型中的视频索引
const index = categoryVideos[type].findIndex(video => video.deviceId === deviceId);
if (index !== -1) {
setActiveVideoIndices(prev => ({
...prev,
[type]: index
}));
}
// 点击后暂停自动旋转一段时间
setAutoRotate(false);
// 60秒后恢复自动旋转
......@@ -58,34 +191,150 @@ const VideoCarousel: React.FC = () => {
}, 60000);
};
// 获取每种类型的第一个视频(用于四宫格展示)
const getTypeVideo = (type: VideoType): VideoItem | null => {
const videos = categoryVideos[type];
if (!videos || videos.length === 0) return null;
const index = activeVideoIndices[type];
return videos[index];
};
// 四个类型的视频
const video1 = getTypeVideo('1');
const video2 = getTypeVideo('2');
const video3 = getTypeVideo('3');
const video4 = getTypeVideo('4');
return (
<div className={styles.container}>
{videoItems.map((video) => (
<div
key={video.id}
{/* 四宫格视频展示 */}
{/* <div className={styles.videoGrid}> */}
{/* 重点区域 */}
<div
className={classNames(styles.videoItem, {
[styles.active]: video.id === activeVideoId,
[styles.active]: video3 && video3.deviceId === activeDeviceId
})}
onClick={() => handleVideoItemClick(video.id)}
onClick={() => video3 && handleVideoClick(video3.deviceId, '3')}
>
<div className={styles.videoThumbnail}>
{/* 这里放置视频播放器,但只有活动项才显示 */}
{/* <VideoPlayer
deviceId={video.deviceId}
visible={video.id === activeVideoId}
onInitialized={handlePlayerInitialized}
onError={(err) => console.error('Video player error:', err)}
/> */}
{/* 视频标题 */}
<div className={styles.videoThumbnail}>
<div className={styles.videoPlaceholder}>
<div className={styles.videoTitle}>
{video.title}
{videoTypeNames['3']}
</div>
</div>
{showVideo && video3 && (
<>
<VideoPlayer
deviceId={video3.deviceId}
visible={true}
onInitialized={handlePlayerInitialized}
onError={(err) => console.error('Video player error:', err)}
/>
</>
)}
{!video3 && (
<div className={styles.noVideo}>
暂无{videoTypeNames['3']}视频
</div>
)}
</div>
</div>
{/* 背街小巷 */}
<div
className={classNames(styles.videoItem, {
[styles.active]: video2 && video2.deviceId === activeDeviceId
})}
onClick={() => video2 && handleVideoClick(video2.deviceId, '2')}
>
<div className={styles.videoThumbnail}>
<div className={styles.videoPlaceholder}>
<div className={styles.videoTitle}>
{videoTypeNames['2']}
</div>
</div>
{showVideo && video2 && (
<>
<VideoPlayer
deviceId={video2.deviceId}
visible={true}
onInitialized={handlePlayerInitialized}
onError={(err) => console.error('Video player error:', err)}
/>
</>
)}
{!video2 && (
<div className={styles.noVideo}>
暂无{videoTypeNames['2']}视频
</div>
)}
</div>
</div>
{/* 农贸市场 */}
<div
className={classNames(styles.videoItem, {
[styles.active]: video1 && video1.deviceId === activeDeviceId
})}
onClick={() => video1 && handleVideoClick(video1.deviceId, '1')}
>
<div className={styles.videoThumbnail}>
<div className={styles.videoPlaceholder}>
<div className={styles.videoTitle}>
{videoTypeNames['1']}
</div>
</div>
{showVideo && video1 && (
<>
<VideoPlayer
deviceId={video1.deviceId}
visible={true}
onInitialized={handlePlayerInitialized}
onError={(err) => console.error('Video player error:', err)}
/>
</>
)}
{!video1 && (
<div className={styles.noVideo}>
暂无{videoTypeNames['1']}视频
</div>
)}
</div>
</div>
{/* 地铁口 */}
<div
className={classNames(styles.videoItem, {
[styles.active]: video4 && video4.deviceId === activeDeviceId
})}
onClick={() => video4 && handleVideoClick(video4.deviceId, '4')}
>
<div className={styles.videoThumbnail}>
<div className={styles.videoPlaceholder}>
<div className={styles.videoTitle}>
{videoTypeNames['4']}
</div>
</div>
{showVideo && video4 && (
<>
<VideoPlayer
deviceId={video4.deviceId}
visible={true}
onInitialized={handlePlayerInitialized}
onError={(err) => console.error('Video player error:', err)}
/>
</>
)}
{!video4 && (
<div className={styles.noVideo}>
暂无{videoTypeNames['4']}视频
</div>
)}
</div>
</div>
))}
{/* </div> */}
</div>
);
};
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment