|
|
@@ -15,23 +15,36 @@ import {
|
|
|
Tooltip,
|
|
|
Tag,
|
|
|
Flex,
|
|
|
+ Empty,
|
|
|
} from 'antd';
|
|
|
import { CheckCircleFilled, CaretRightFilled, QuestionCircleOutlined, StarOutlined, StarFilled } from '@ant-design/icons';
|
|
|
import { VideoItem, VideoListResponse } from '@src/views/publishContent/weGZH/components/types';
|
|
|
import http from '@src/http';
|
|
|
-import { getVideoContentListApi, getUploadVideoContentListApi } from '@src/http/api';
|
|
|
+import { getVideoContentListApi, getUploadVideoContentListApi, getCollectVideoContentListApi, saveCollectVideoContentApi, getCollectContentListApi } from '@src/http/api';
|
|
|
import { useVideoCategoryOptions } from '@src/views/publishContent/weGZH/hooks/useVideoCategoryOptions';
|
|
|
import { VideoSearchPlanType } from '@src/views/publishContent/weCom/type'
|
|
|
import { enumToOptions } from '@src/utils/helper';
|
|
|
import { isNil } from 'lodash';
|
|
|
+import { CollectedStatusEnum, VideoStatusEnum } from '@src/views/publishContent/types';
|
|
|
|
|
|
export enum VideoLibraryType {
|
|
|
平台视频库 = 0,
|
|
|
我的上传 = 1,
|
|
|
+ 我的收藏 = 2,
|
|
|
}
|
|
|
|
|
|
const { Text, Paragraph } = Typography;
|
|
|
|
|
|
+interface VideoSelectContentProps {
|
|
|
+ planType: VideoSearchPlanType;
|
|
|
+ initialSelectedIds?: number[];
|
|
|
+ selectedVideos?: VideoItem[];
|
|
|
+ defaultVideoLibraryType?: VideoLibraryType;
|
|
|
+ onVideoListChange?: (videos: VideoItem[]) => void;
|
|
|
+ autoLoad?: boolean;
|
|
|
+ isCollectedPage?: boolean; // 是否是收藏页面
|
|
|
+}
|
|
|
+
|
|
|
interface VideoSelectModalProps {
|
|
|
planType: VideoSearchPlanType;
|
|
|
visible: boolean;
|
|
|
@@ -84,11 +97,18 @@ interface GetVideoListParams {
|
|
|
_videoLibraryType?: VideoLibraryType;
|
|
|
}
|
|
|
|
|
|
-const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ visible, onClose, onOk, planType, initialSelectedIds = [], selectedVideos = [], defaultVideoLibraryType }) => {
|
|
|
+export const VideoSelectContent: React.FC<VideoSelectContentProps> = ({
|
|
|
+ planType,
|
|
|
+ initialSelectedIds = [],
|
|
|
+ selectedVideos = [],
|
|
|
+ defaultVideoLibraryType,
|
|
|
+ onVideoListChange,
|
|
|
+ autoLoad = true,
|
|
|
+ isCollectedPage = false,
|
|
|
+}) => {
|
|
|
const { videoCategoryOptions } = useVideoCategoryOptions();
|
|
|
const [tagOptions, setTagOptions] = useState<TagTypeOptions[]>([]);
|
|
|
const [category, setCategory] = useState<string>();
|
|
|
- // const [sort, setSort] = useState<VideoSortType>(VideoSortType.推荐指数);
|
|
|
const [sortType, setSortType] = useState<SortTypeEnum>(SortTypeEnum.推荐指数);
|
|
|
const [recentNotUsed, setRecentNotUsed] = useState<RecentNotUsedType>();
|
|
|
const [tags, setTags] = useState<TagType[]>([]);
|
|
|
@@ -110,6 +130,28 @@ const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ visible, onClose, o
|
|
|
}
|
|
|
}, [defaultVideoLibraryType]);
|
|
|
|
|
|
+ useEffect(() => {
|
|
|
+ if (onVideoListChange) {
|
|
|
+ const selectedVideos = videoListAll.filter(video => selectedVideoIds.has(video.videoId));
|
|
|
+ const uniqueSelectedVideos = selectedVideos.filter((video, index, self) =>
|
|
|
+ index === self.findIndex((t) => t.videoId === video.videoId)
|
|
|
+ );
|
|
|
+ onVideoListChange(uniqueSelectedVideos);
|
|
|
+ }
|
|
|
+ }, [selectedVideoIds, videoListAll]);
|
|
|
+
|
|
|
+ const getVideoListUrl = (videoLibraryType: VideoLibraryType) => {
|
|
|
+ if (videoLibraryType === VideoLibraryType.平台视频库) {
|
|
|
+ return getVideoContentListApi;
|
|
|
+ } else if (videoLibraryType === VideoLibraryType.我的上传) {
|
|
|
+ return getUploadVideoContentListApi;
|
|
|
+ } else if (videoLibraryType === VideoLibraryType.我的收藏 && isCollectedPage) {
|
|
|
+ return getCollectContentListApi;
|
|
|
+ } else {
|
|
|
+ return getCollectVideoContentListApi;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
const getVideoList = async ({pageNum, _pageSize, _sortType, _recentNotUsed, _category, _tags, _videoLibraryType}: GetVideoListParams) => {
|
|
|
setLoading(true);
|
|
|
setCurrentPage(pageNum || currentPage);
|
|
|
@@ -117,7 +159,7 @@ const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ visible, onClose, o
|
|
|
|
|
|
// 根据视频库类型选择不同的API
|
|
|
const currentVideoLibraryType = isNil(_videoLibraryType) ? videoLibraryType : _videoLibraryType;
|
|
|
- const apiUrl = currentVideoLibraryType === VideoLibraryType.平台视频库 ? getVideoContentListApi : getUploadVideoContentListApi;
|
|
|
+ const apiUrl = getVideoListUrl(currentVideoLibraryType);
|
|
|
|
|
|
const requestParams = {
|
|
|
category: isNil(_category) ? category : _category,
|
|
|
@@ -139,6 +181,8 @@ const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ visible, onClose, o
|
|
|
setVideoList([...selectedVideos, ...res.data.objs.filter(v => !selectedVideos.find(ov => ov.videoId === v.videoId))]);
|
|
|
setVideoListAll(old => [...old, ...res.data.objs.filter(v => !old.find(ov => ov.videoId === v.videoId))]);
|
|
|
setTotal(res.data.totalSize);
|
|
|
+ } else {
|
|
|
+ message.error('获取视频列表失败');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -152,29 +196,18 @@ const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ visible, onClose, o
|
|
|
}
|
|
|
|
|
|
useEffect(() => {
|
|
|
- if (visible) {
|
|
|
- console.log('selectedVideos', selectedVideos);
|
|
|
+ if (autoLoad) {
|
|
|
// 初始化时设置 selectedVideos
|
|
|
setVideoList(selectedVideos);
|
|
|
setVideoListAll(selectedVideos);
|
|
|
setTagOptions(enumToOptions(TagType).map(option => ({ label: getTagLabel(option.value as TagType), value: option.value as TagType })));
|
|
|
getVideoList({});
|
|
|
- } else {
|
|
|
- setRecentNotUsed(undefined);
|
|
|
- setTags([]);
|
|
|
- setVideoLibraryType(defaultVideoLibraryType || VideoLibraryType.平台视频库);
|
|
|
- setSortType(SortTypeEnum.推荐指数);
|
|
|
- setSearchTerm('');
|
|
|
- setCategory(undefined);
|
|
|
- setCurrentPage(1);
|
|
|
}
|
|
|
- }, [visible]);
|
|
|
+ }, [autoLoad]);
|
|
|
|
|
|
useEffect(() => {
|
|
|
- if (visible) {
|
|
|
- setSelectedVideoIds(new Set(initialSelectedIds));
|
|
|
- }
|
|
|
- }, [visible, initialSelectedIds]);
|
|
|
+ setSelectedVideoIds(new Set(initialSelectedIds));
|
|
|
+ }, [initialSelectedIds]);
|
|
|
|
|
|
const handleSearch = () => {
|
|
|
console.log('Searching for:', { category, searchTerm });
|
|
|
@@ -199,17 +232,7 @@ const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ visible, onClose, o
|
|
|
});
|
|
|
};
|
|
|
|
|
|
- const handleOk = () => {
|
|
|
- const selectedVideos = videoListAll.filter(video => selectedVideoIds.has(video.videoId));
|
|
|
- // 去重
|
|
|
- const uniqueSelectedVideos = selectedVideos.filter((video, index, self) =>
|
|
|
- index === self.findIndex((t) => t.videoId === video.videoId)
|
|
|
- );
|
|
|
- console.log('uniqueSelectedVideos', uniqueSelectedVideos);
|
|
|
- onOk(uniqueSelectedVideos);
|
|
|
- };
|
|
|
-
|
|
|
-const playVideo = (video: VideoItem) => {
|
|
|
+ const playVideo = (video: VideoItem) => {
|
|
|
setPlayingVideo(video);
|
|
|
};
|
|
|
|
|
|
@@ -224,19 +247,16 @@ const playVideo = (video: VideoItem) => {
|
|
|
|
|
|
const handleSortTypeChange = (v: RadioChangeEvent) => {
|
|
|
setSortType(v.target.value as SortTypeEnum);
|
|
|
- console.log('handleSortTypeChange', v.target.value);
|
|
|
getVideoList({pageNum: 1, _sortType: v.target.value as SortTypeEnum});
|
|
|
}
|
|
|
|
|
|
const onCategoryChange = (v: string) => {
|
|
|
setCategory(v);
|
|
|
- console.log('onCategoryChange', v);
|
|
|
getVideoList({pageNum: 1, _category: v || '' as string});
|
|
|
}
|
|
|
|
|
|
const onRecentNotUsedChange = (v: RecentNotUsedType) => {
|
|
|
setRecentNotUsed(v);
|
|
|
- console.log('onRecentNotUsedChange', v);
|
|
|
if (isNil(v)) {
|
|
|
getVideoList({pageNum: 1, _recentNotUsed: ''});
|
|
|
} else {
|
|
|
@@ -250,201 +270,199 @@ const playVideo = (video: VideoItem) => {
|
|
|
getVideoList({pageNum: 1, _tags: newTags});
|
|
|
}
|
|
|
|
|
|
- const handleCollectVideo = (videoId: number) => {
|
|
|
- console.log('handleCollectVideo', videoId);
|
|
|
+ const handleCollectVideo = async (videoId: number) => {
|
|
|
const video = videoList.find(v => v.videoId === videoId);
|
|
|
if (video) {
|
|
|
- setVideoList(prev => prev.map(v => v.videoId === videoId ? {...v, isCollected: !v.isCollected} : v));
|
|
|
- message.success(video.isCollected ? '取消收藏' : '收藏成功');
|
|
|
+ const isCollected = video.collect === CollectedStatusEnum.已收藏 ? true : false;
|
|
|
+ const res = await http.post(saveCollectVideoContentApi, {
|
|
|
+ videoId: videoId,
|
|
|
+ collect: isCollected ? CollectedStatusEnum.未收藏 : CollectedStatusEnum.已收藏,
|
|
|
+ });
|
|
|
+ if (res && res.code === 0) {
|
|
|
+ setVideoList(prev => prev.map(v => v.videoId === videoId ? {...v, collect: isCollected ? CollectedStatusEnum.未收藏 : CollectedStatusEnum.已收藏} : v));
|
|
|
+ message.success(isCollected ? '取消收藏' : '收藏成功');
|
|
|
+ } else {
|
|
|
+ message.error('收藏失败');
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ const handleCreatePublish = (videoId: number) => {
|
|
|
+ window.location.href = `/publishContent/wegzh/${videoLibraryType}/${videoId}`;
|
|
|
+ }
|
|
|
+
|
|
|
return (
|
|
|
<>
|
|
|
- <Drawer
|
|
|
- title="内容选取"
|
|
|
- open={visible}
|
|
|
- onClose={onClose}
|
|
|
- width={900}
|
|
|
- placement="right"
|
|
|
- loading={loading}
|
|
|
- destroyOnClose
|
|
|
- styles={{ footer: { textAlign: 'right', padding: '10px 24px' } }}
|
|
|
- footer={
|
|
|
- <div className="flex justify-between items-center">
|
|
|
- <Pagination
|
|
|
- current={currentPage}
|
|
|
- pageSize={pageSize}
|
|
|
- total={total}
|
|
|
- onChange={(page, size) => {
|
|
|
- setCurrentPage(page);
|
|
|
- setPageSize(size);
|
|
|
- getVideoList({pageNum: page, _pageSize: 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-2 mb-2">
|
|
|
- <div className="flex items-center gap-2">
|
|
|
- <span className="text-gray-600">视频来源:</span>
|
|
|
- <Select
|
|
|
- style={{ width: 120 }}
|
|
|
- value={videoLibraryType}
|
|
|
- onChange={handleVideoLibraryTypeChange}
|
|
|
- options={enumToOptions(VideoLibraryType)}
|
|
|
- />
|
|
|
- </div>
|
|
|
-
|
|
|
- <div className="flex items-center gap-2">
|
|
|
- <span className="text-gray-600">品类:</span>
|
|
|
- <Select
|
|
|
- placeholder="选择品类"
|
|
|
- style={{ width: 120 }}
|
|
|
- value={category}
|
|
|
- allowClear
|
|
|
- onChange={onCategoryChange}
|
|
|
- options={videoCategoryOptions.map(option => ({ label: option, value: option }))}
|
|
|
- />
|
|
|
- </div>
|
|
|
- <div className="flex items-center gap-2">
|
|
|
- <span className="text-gray-600">近期未使用:</span>
|
|
|
- <Select
|
|
|
- placeholder="选择近期未使用"
|
|
|
- style={{ width: 120 }}
|
|
|
- value={recentNotUsed}
|
|
|
- allowClear
|
|
|
- onChange={onRecentNotUsedChange}
|
|
|
- options={enumToOptions(RecentNotUsedType)}
|
|
|
- />
|
|
|
- </div>
|
|
|
- <div className="flex items-center gap-2">
|
|
|
- <span className="text-gray-600">视频标题:</span>
|
|
|
- <Input
|
|
|
- placeholder="搜索视频标题"
|
|
|
- style={{ width: 130 }}
|
|
|
- value={searchTerm}
|
|
|
- allowClear
|
|
|
- onChange={e => setSearchTerm(e.target.value)}
|
|
|
- onPressEnter={handleSearch}
|
|
|
- />
|
|
|
- </div>
|
|
|
- <Button type="primary" onClick={handleSearch}>搜索</Button>
|
|
|
+ <div className="flex flex-wrap gap-2 mb-2">
|
|
|
+ {!isCollectedPage && <div className="flex items-center gap-2">
|
|
|
+ <span className="text-gray-600">视频来源:</span>
|
|
|
+ <Select
|
|
|
+ style={{ width: 120 }}
|
|
|
+ value={videoLibraryType}
|
|
|
+ onChange={handleVideoLibraryTypeChange}
|
|
|
+ options={enumToOptions(VideoLibraryType)}
|
|
|
+ />
|
|
|
+ </div>}
|
|
|
+
|
|
|
+ <div className="flex items-center gap-2">
|
|
|
+ <span className="text-gray-600">品类:</span>
|
|
|
+ <Select
|
|
|
+ placeholder="选择品类"
|
|
|
+ style={{ width: 120 }}
|
|
|
+ value={category}
|
|
|
+ allowClear
|
|
|
+ onChange={onCategoryChange}
|
|
|
+ options={videoCategoryOptions.map(option => ({ label: option, value: option }))}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div className="flex items-center gap-2">
|
|
|
+ <span className="text-gray-600">近期未使用:</span>
|
|
|
+ <Select
|
|
|
+ placeholder="选择近期未使用"
|
|
|
+ style={{ width: 140 }}
|
|
|
+ value={recentNotUsed}
|
|
|
+ allowClear
|
|
|
+ onChange={onRecentNotUsedChange}
|
|
|
+ options={enumToOptions(RecentNotUsedType)}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div className="flex items-center gap-2">
|
|
|
+ <span className="text-gray-600">视频标题:</span>
|
|
|
+ <Input
|
|
|
+ placeholder="搜索视频标题"
|
|
|
+ style={{ width: 130 }}
|
|
|
+ value={searchTerm}
|
|
|
+ allowClear
|
|
|
+ onChange={e => setSearchTerm(e.target.value)}
|
|
|
+ onPressEnter={handleSearch}
|
|
|
+ />
|
|
|
</div>
|
|
|
- <div className="flex">
|
|
|
- <div className="flex flex-wrap gap-2 mb-6 items-center">
|
|
|
- <span className="text-gray-600 ">排序选项:</span>
|
|
|
- <Radio.Group
|
|
|
- onChange={handleSortTypeChange}
|
|
|
- value={sortType}
|
|
|
- buttonStyle="solid"
|
|
|
+ <Button type="primary" onClick={handleSearch}>搜索</Button>
|
|
|
+ </div>
|
|
|
+ <div className="flex">
|
|
|
+ <div className="flex flex-wrap gap-2 mb-6 items-center">
|
|
|
+ <span className="text-gray-600 ">排序选项:</span>
|
|
|
+ <Radio.Group
|
|
|
+ onChange={handleSortTypeChange}
|
|
|
+ value={sortType}
|
|
|
+ buttonStyle="solid"
|
|
|
+ >
|
|
|
+ <Radio.Button value={SortTypeEnum.推荐指数}>推荐指数 <Tooltip title="结合视频在票圈、同业务场景、本账号下的历史表现综合得分"><QuestionCircleOutlined /></Tooltip></Radio.Button>
|
|
|
+ <Radio.Button value={SortTypeEnum.更新时间}>更新时间</Radio.Button>
|
|
|
+ </Radio.Group>
|
|
|
+ </div>
|
|
|
+ <div className="flex flex-wrap gap-2 mb-6 ml-10 items-center">
|
|
|
+ <span className="text-gray-600 ">推荐标签:</span>
|
|
|
+ {tagOptions.map<React.ReactNode>((option) => (
|
|
|
+ <Tag.CheckableTag
|
|
|
+ key={option.value}
|
|
|
+ checked={tags.includes(option.value)}
|
|
|
+ onChange={(checked) => handleTagChange(option.value, checked)}
|
|
|
>
|
|
|
- <Radio.Button value={SortTypeEnum.推荐指数}>推荐指数 <Tooltip title="结合视频在票圈、同业务场景、本账号下的历史表现综合得分"><QuestionCircleOutlined /></Tooltip></Radio.Button>
|
|
|
- <Radio.Button value={SortTypeEnum.更新时间}>更新时间</Radio.Button>
|
|
|
- </Radio.Group>
|
|
|
- </div>
|
|
|
- <div className="flex flex-wrap gap-2 mb-6 ml-10 items-center">
|
|
|
- <span className="text-gray-600 ">推荐标签:</span>
|
|
|
- {tagOptions.map<React.ReactNode>((option) => (
|
|
|
- <Tag.CheckableTag
|
|
|
- key={option.value}
|
|
|
- checked={tags.includes(option.value)}
|
|
|
- onChange={(checked) => handleTagChange(option.value, checked)}
|
|
|
- >
|
|
|
- {option.label}
|
|
|
- </Tag.CheckableTag>
|
|
|
- ))}
|
|
|
- </div>
|
|
|
+ {option.label}
|
|
|
+ </Tag.CheckableTag>
|
|
|
+ ))}
|
|
|
</div>
|
|
|
- <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
|
|
|
- {videoList.map((video) => {
|
|
|
- const isSelected = selectedVideoIds.has(video.videoId);
|
|
|
- const isDisabled = !isSelected && selectedVideoIds.size >= MAX_SELECTION;
|
|
|
- return (
|
|
|
- <Card
|
|
|
- key={video.videoId}
|
|
|
- className={`relative ${isDisabled ? 'opacity-50' : 'cursor-pointer'} ${isSelected ? 'border-2 !bg-blue-50 shadow-md' : 'hover:shadow-sm'}`}
|
|
|
- styles={{ body: { padding: 0 } }}
|
|
|
- onClick={() => !isDisabled && handleSelectVideo(video.videoId)}
|
|
|
+ </div>
|
|
|
+ <div className={`grid gap-4 ${isCollectedPage ? 'grid-cols-5' : 'grid-cols-1 sm:grid-cols-2 md:grid-cols-3'}`}>
|
|
|
+ {
|
|
|
+ !loading && total === 0 && (
|
|
|
+ <div className="col-span-full flex justify-center items-center py-8">
|
|
|
+ <Empty description="暂无数据" />
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+ }
|
|
|
+ {videoList.map((video) => {
|
|
|
+ const isSelected = selectedVideoIds.has(video.videoId);
|
|
|
+ const isDisabled = !isSelected && selectedVideoIds.size >= MAX_SELECTION;
|
|
|
+ const isInvalid = video.status === VideoStatusEnum.已下架;
|
|
|
+
|
|
|
+ return (
|
|
|
+ <Card
|
|
|
+ key={video.videoId}
|
|
|
+ className={`relative ${isDisabled || isInvalid ? 'opacity-50' : 'cursor-pointer'} ${isSelected ? 'border-2 !bg-blue-50 shadow-md' : 'hover:shadow-sm'}`}
|
|
|
+ styles={{ body: { padding: 0 } }}
|
|
|
+ onClick={() => !isDisabled && !isInvalid && handleSelectVideo(video.videoId)}
|
|
|
+ >
|
|
|
+ {isInvalid && (
|
|
|
+ <div className="absolute top-0 left-0 w-full h-full bg-black/50 flex justify-center items-center z-10">
|
|
|
+ <Text type="secondary" className="!text-2xl !text-white font-bold">视频已下架</Text>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ <div className="p-3">
|
|
|
+ <Text type="secondary" className="text-xs">票圈 | 3亿人喜欢的视频平台</Text>
|
|
|
+ <Paragraph className="mt-1 !mb-1" ellipsis={{ rows: 1, tooltip: true }} title={video.customTitle || video.title}>{video.customTitle || video.title}</Paragraph>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ className="relative"
|
|
|
+ style={{ paddingBottom: '79.8%' }}
|
|
|
+ onClick={(e) => { e.stopPropagation(); playVideo(video); }}
|
|
|
>
|
|
|
- <div className="p-3">
|
|
|
- <Text type="secondary" className="text-xs">票圈 | 3亿人喜欢的视频平台</Text>
|
|
|
- <Paragraph className="mt-1 !mb-1" ellipsis={{ rows: 1, tooltip: true }} title={video.customTitle || video.title}>{video.customTitle || video.title}</Paragraph>
|
|
|
+ <img src={video.customCover || video.cover} alt={video.customTitle || video.title} referrerPolicy="no-referrer" className="absolute inset-0 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
|
|
|
- className="relative"
|
|
|
- style={{ paddingBottom: '79.8%' }}
|
|
|
- onClick={(e) => { e.stopPropagation(); playVideo(video); }}
|
|
|
- >
|
|
|
- <img src={video.customCover || video.cover} alt={video.customTitle || video.title} referrerPolicy="no-referrer" className="absolute inset-0 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">
|
|
|
+ <div className="flex flex-1 flex-col gap-1">
|
|
|
+ <Text type="secondary" className="text-xs">推荐指数: {video.recommendScore?.toFixed(2) || '无'}</Text>
|
|
|
+ <Text type="secondary" className="text-xs">推荐标签: {'tags' in video && video.tags && video.tags.length > 0 ?
|
|
|
+ video.tags.map(tag => <Tag key={tag} className="text-xs">{getTagLabel(tag as TagType)}</Tag>) : '无'}</Text>
|
|
|
</div>
|
|
|
- <div className="p-3 flex justify-between items-center">
|
|
|
- <div className="flex flex-1 flex-col gap-1">
|
|
|
- <Text type="secondary" className="text-xs">推荐指数: {video.recommendScore?.toFixed(2) || '无'}</Text>
|
|
|
- <Text type="secondary" className="text-xs">推荐标签: {'tags' in video && video.tags && video.tags.length > 0 ?
|
|
|
- video.tags.map(tag => <Tag key={tag} className="text-xs">{getTagLabel(tag as TagType)}</Tag>) : '无'}</Text>
|
|
|
- </div>
|
|
|
- <div className="flex flex-col items-center gap-2">
|
|
|
- {
|
|
|
- video.isCollected ? (
|
|
|
+ <div className="flex flex-col items-center gap-2">
|
|
|
+ {
|
|
|
+ video.collect ? (
|
|
|
+ <Flex gap={4} onClick={(e) => { e.stopPropagation(); handleCollectVideo(video.videoId); }}>
|
|
|
+ <StarFilled className="text-xl !text-[#1890ff]" />
|
|
|
+ <Text>收藏</Text>
|
|
|
+ </Flex>
|
|
|
+ ) : (
|
|
|
<Flex gap={4} onClick={(e) => { e.stopPropagation(); handleCollectVideo(video.videoId); }}>
|
|
|
- <StarFilled className="text-xl !text-[#1890ff]" />
|
|
|
- <Text>收藏</Text>
|
|
|
+ <StarOutlined className="text-xl !text-black/50" />
|
|
|
+ <Text className="!text-black/70">收藏</Text>
|
|
|
+ </Flex>
|
|
|
+ )
|
|
|
+ }
|
|
|
+ {
|
|
|
+ isCollectedPage ?
|
|
|
+ <Button type="text" onClick={(e) => { e.stopPropagation(); handleCreatePublish(video.videoId); }}>创建发布</Button>
|
|
|
+ : <>
|
|
|
+ {isSelected ? (
|
|
|
+ <Flex gap={4}>
|
|
|
+ <CheckCircleFilled className="text-base !text-[#1890ff]" />
|
|
|
+ <Text className="!text-black/70">已选</Text>
|
|
|
</Flex>
|
|
|
) : (
|
|
|
- <Flex gap={4} onClick={(e) => { e.stopPropagation(); handleCollectVideo(video.videoId); }}>
|
|
|
- <StarOutlined className="text-xl !text-black/50" />
|
|
|
- <Text className="!text-black/70">收藏</Text>
|
|
|
- </Flex>
|
|
|
- )
|
|
|
- }
|
|
|
- {isSelected ? (
|
|
|
- <Flex gap={4}>
|
|
|
- <CheckCircleFilled className="text-base !text-[#1890ff]" />
|
|
|
- <Text className="!text-black/70">已选</Text>
|
|
|
- </Flex>
|
|
|
- ) : (
|
|
|
- <Flex gap={4} className="items-center">
|
|
|
- <div className={`w-4 h-4 border-2 ${isDisabled ? 'border-gray-200 bg-gray-100' : 'border-black/50' } rounded-full`}></div>
|
|
|
- <Text className="!text-black/70">选择</Text>
|
|
|
- </Flex>
|
|
|
- )}
|
|
|
- </div>
|
|
|
-
|
|
|
+ <Flex gap={4} className="items-center">
|
|
|
+ <div className={`w-4 h-4 border-2 ${isDisabled ? 'border-gray-200 bg-gray-100' : 'border-black/50' } rounded-full`}></div>
|
|
|
+ <Text className="!text-black/70">选择</Text>
|
|
|
+ </Flex>
|
|
|
+ )}
|
|
|
+ </>
|
|
|
+ }
|
|
|
</div>
|
|
|
- {/* {isSelected && (
|
|
|
- <div className="p-3 flex justify-between items-center relative z-10">
|
|
|
- <Select
|
|
|
- placeholder="选择场景"
|
|
|
- style={{ width: 180 }}
|
|
|
- defaultValue={video.scene || 0}
|
|
|
- value={video.scene}
|
|
|
- onChange={(value) => handleChangeSelectVideo(video.videoId, value)}
|
|
|
- options={ planType === WeComPlanType.社群 ?
|
|
|
- [{ label: '群发', value: 0 }, { label: '单发', value: 1 }]
|
|
|
- : [{ label: '关注回复', value: 0 }]
|
|
|
- }
|
|
|
- onClick={(e) => e.stopPropagation()}
|
|
|
- />
|
|
|
- </div>
|
|
|
- )} */}
|
|
|
- </Card>
|
|
|
- );
|
|
|
- })}
|
|
|
- </div>
|
|
|
- </Drawer>
|
|
|
+
|
|
|
+ </div>
|
|
|
+ </Card>
|
|
|
+ );
|
|
|
+ })}
|
|
|
+ </div>
|
|
|
+ <div className="mt-4 flex justify-center fixed bottom-3 right-50">
|
|
|
+ <Pagination
|
|
|
+ current={currentPage}
|
|
|
+ pageSize={pageSize}
|
|
|
+ total={total}
|
|
|
+ onChange={(page, size) => {
|
|
|
+ setCurrentPage(page);
|
|
|
+ setPageSize(size);
|
|
|
+ getVideoList({pageNum: page, _pageSize: size});
|
|
|
+ }}
|
|
|
+ pageSizeOptions={['10', '20', '50']}
|
|
|
+ size="small"
|
|
|
+ showSizeChanger
|
|
|
+ showTotal={(total) => `共 ${total} 条`}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
|
|
|
<Modal
|
|
|
open={!!playingVideo}
|
|
|
@@ -465,4 +483,46 @@ const playVideo = (video: VideoItem) => {
|
|
|
);
|
|
|
};
|
|
|
|
|
|
+const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ visible, onClose, onOk, planType, initialSelectedIds = [], selectedVideos = [], defaultVideoLibraryType }) => {
|
|
|
+ const [currentSelectedVideos, setCurrentSelectedVideos] = useState<VideoItem[]>([]);
|
|
|
+
|
|
|
+ const handleOk = () => {
|
|
|
+ onOk(currentSelectedVideos);
|
|
|
+ };
|
|
|
+
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <Drawer
|
|
|
+ title="内容选取"
|
|
|
+ open={visible}
|
|
|
+ onClose={onClose}
|
|
|
+ width={950}
|
|
|
+ placement="right"
|
|
|
+ destroyOnClose
|
|
|
+ styles={{ footer: { textAlign: 'right', padding: '10px 24px' } }}
|
|
|
+ footer={
|
|
|
+ <div className="flex justify-between items-center">
|
|
|
+ <Space className="justify-between w-full">
|
|
|
+ <Text>已选 {currentSelectedVideos.length} / 3 条视频</Text>
|
|
|
+ <Space>
|
|
|
+ <Button onClick={onClose}>取消</Button>
|
|
|
+ <Button type="primary" onClick={handleOk}>确定</Button>
|
|
|
+ </Space>
|
|
|
+ </Space>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ >
|
|
|
+ <VideoSelectContent
|
|
|
+ planType={planType}
|
|
|
+ initialSelectedIds={initialSelectedIds}
|
|
|
+ selectedVideos={selectedVideos}
|
|
|
+ defaultVideoLibraryType={defaultVideoLibraryType}
|
|
|
+ autoLoad={visible}
|
|
|
+ onVideoListChange={setCurrentSelectedVideos}
|
|
|
+ />
|
|
|
+ </Drawer>
|
|
|
+ </>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
export default VideoSelectModal;
|