123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- import React, { useState, useEffect } from 'react';
- import {
- Drawer,
- Button,
- Select,
- Input,
- Row,
- Col,
- Card,
- Typography,
- Pagination,
- Checkbox,
- Space,
- message,
- Modal,
- } from 'antd';
- import { EditOutlined, PlayCircleOutlined, CheckCircleFilled, CaretRightFilled } from '@ant-design/icons';
- import { VideoItem } from '../types';
- const { Option } = Select;
- const { Text } = Typography;
- interface VideoSelectModalProps {
- visible: boolean;
- onClose: () => void;
- onOk: (selectedVideos: VideoItem[]) => void;
- initialSelectedIds?: number[];
- }
- // Mock data for demonstration - Ensure videoUrl is added
- const mockVideos: VideoItem[] = Array.from({ length: 15 }, (_, i) => ({
- id: i + 100,
- source: '票圈 | 3亿人喜欢的视频平台',
- title: `最美中国——上海之海 ${i + 1},带你领略航拍风景`,
- thumbnail: 'https://gw.alipayobjects.com/zos/rmsportal/JiqGstEfoWAOHiTxclqi.png',
- spreadEfficiency: 8.56 + i * 0.1,
- videoUrl: 'https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4', // Example video URL
- }));
- const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ visible, onClose, onOk, initialSelectedIds = [] }) => {
- const [category, setCategory] = useState<string>();
- const [searchTerm, setSearchTerm] = useState<string>('');
- const [currentPage, setCurrentPage] = useState(1);
- const [pageSize, setPageSize] = useState(10);
- const [selectedVideoIds, setSelectedVideoIds] = useState<Set<number>>(new Set(initialSelectedIds));
- const [playingVideo, setPlayingVideo] = useState<VideoItem | null>(null);
- const MAX_SELECTION = 3;
- useEffect(() => {
- if (visible) {
- setSelectedVideoIds(new Set(initialSelectedIds));
- }
- }, [visible, initialSelectedIds]);
- const handleSearch = () => {
- console.log('Searching for:', { category, searchTerm });
- setCurrentPage(1);
- };
- const handleSelectVideo = (videoId: number) => {
- setSelectedVideoIds(prev => {
- const newSet = new Set(prev);
- if (newSet.has(videoId)) {
- newSet.delete(videoId);
- } else {
- if (newSet.size >= MAX_SELECTION) {
- message.warning(`最多只能选择 ${MAX_SELECTION} 条视频`);
- return prev;
- }
- newSet.add(videoId);
- }
- return newSet;
- });
- };
- const handleOk = () => {
- const selectedVideos = mockVideos.filter(video => selectedVideoIds.has(video.id));
- onOk(selectedVideos);
- onClose();
- };
- const playVideo = (video: VideoItem) => {
- setPlayingVideo(video);
- };
- const closeVideoPlayer = () => {
- setPlayingVideo(null);
- };
- const paginatedData = mockVideos.slice((currentPage - 1) * pageSize, currentPage * pageSize);
- return (
- <>
- <Drawer
- title="内容选取"
- open={visible}
- onClose={onClose}
- width={800}
- placement="right"
- footerStyle={{ textAlign: 'right', padding: '10px 24px' }}
- footer={
- <div className="flex justify-between items-center">
- <Pagination
- current={currentPage}
- pageSize={pageSize}
- total={mockVideos.length}
- onChange={(page, size) => {
- setCurrentPage(page);
- setPageSize(size);
- }}
- pageSizeOptions={['10', '20', '50']}
- size="small"
- showSizeChanger
- showTotal={(total) => `共 ${total} 条`}
- />
- <Space>
- <Text>已选 {selectedVideoIds.size} / {MAX_SELECTION} 条视频</Text>
- <Button onClick={onClose}>取消</Button>
- <Button type="primary" onClick={handleOk}>确定</Button>
- </Space>
- </div>
- }
- >
- <div className="flex flex-wrap gap-4 mb-6">
- <div className="flex items-center gap-2">
- <span className="text-gray-600">品类:</span>
- <Select
- placeholder="选择品类"
- style={{ width: 180 }}
- value={category}
- onChange={setCategory}
- options={[{ label: '品类A', value: 'A' }, { label: '品类B', value: 'B' }]}
- />
- </div>
- <div className="flex items-center gap-2">
- <span className="text-gray-600">视频标题:</span>
- <Input
- placeholder="搜索视频标题"
- style={{ width: 200 }}
- value={searchTerm}
- onChange={e => setSearchTerm(e.target.value)}
- />
- </div>
- <Button type="primary" onClick={handleSearch}>搜索</Button>
- </div>
- <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
- {paginatedData.map((video) => {
- const isSelected = selectedVideoIds.has(video.id);
- const isDisabled = !isSelected && selectedVideoIds.size >= MAX_SELECTION;
- return (
- <Card
- key={video.id}
- className={`relative ${isDisabled ? 'opacity-50' : 'cursor-pointer'} ${isSelected ? 'border-blue-500 border-2' : ''}`}
- bodyStyle={{ padding: 0 }}
- onClick={() => !isDisabled && handleSelectVideo(video.id)}
- >
- <div className="p-3">
- <Text type="secondary" className="text-xs">{video.source}</Text>
- <Text className="block mt-1 mb-2 leading-tight line-clamp-2" title={video.title}>{video.title}</Text>
- </div>
- <div
- className="relative h-[120px] bg-gray-200 group/thumb"
- onClick={(e) => { e.stopPropagation(); playVideo(video); }}
- >
- <img src={video.thumbnail} alt={video.title} className="w-full h-full object-cover" />
- <div className="absolute inset-0 flex justify-center items-center cursor-pointer">
- <CaretRightFilled className="!text-white text-4xl bg-black/20 rounded-full p-1 pl-2" />
- </div>
- </div>
- <div className="p-3 flex justify-between items-center">
- <Text type="secondary" className="text-xs">传播效率: {video.spreadEfficiency.toFixed(2)}</Text>
- {isSelected ? (
- <CheckCircleFilled className="text-green-500 text-xl" />
- ) : (
- <div className={`w-5 h-5 border-2 ${isDisabled ? 'border-gray-200 bg-gray-100' : 'border-gray-300' } rounded-full`}></div>
- )}
- </div>
- </Card>
- );
- })}
- </div>
- </Drawer>
- <Modal
- open={!!playingVideo}
- onCancel={closeVideoPlayer}
- title={playingVideo?.title}
- footer={null}
- destroyOnClose
- width={720}
- bodyStyle={{ padding: 0, background: '#000' }}
- >
- {playingVideo && (
- <video controls autoPlay className="w-full h-auto max-h-[80vh] block" src={playingVideo.videoUrl}>
- Your browser does not support the video tag.
- </video>
- )}
- </Modal>
- </>
- );
- };
- export default VideoSelectModal;
|