Przeglądaj źródła

Merge branch 'feature_260509_replace_upload_new_datasource' of Web/contentCooper into master

liulidong 1 dzień temu
rodzic
commit
a133b5bcc9

+ 40 - 3
src/views/publishContent/weGZH/components/videoSelectModal/index.tsx

@@ -14,6 +14,8 @@ import {
 	Tabs,
 	Popover,
 	Descriptions,
+	Input,
+	Tooltip,
 } from 'antd';
 import { CheckCircleFilled, CaretRightFilled, HeartOutlined, HistoryOutlined, FireOutlined } from '@ant-design/icons';
 import { VideoItem, VideoListResponse } from '../types';
@@ -123,6 +125,12 @@ const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ planType, visible,
 	const { uploadLogVideoListQuery, uploadLogVideoPlay, uploadLogVideoPlayEnd, uploadLogVideoCollect } = useLogger();
 	const debouncedUploadLogVideoListQuery = useMemo(() => debounce(uploadLogVideoListQuery, 500), [uploadLogVideoListQuery]);
 	const [category, setCategory] = useState<string>();
+	const [title, setTitle] = useState<string>('');
+	// 搜索框仅对自营/代理(type ∈ {2 内部, 3 代理})放开;小程序投流入口需要 crowdPackage 才能搜
+	const SEARCH_ENABLED_TYPES = new Set([2, 3]);
+	const canSeeSearch = SEARCH_ENABLED_TYPES.has(getUserInfo()?.type as number);
+	const isXcxEntry = planType === GzhPlanType.小程序投流;
+	const searchDisabledTip = isXcxEntry && !crowdPackage ? '请先选人群包再搜索' : '';
 	const sort = VideoSortType.平台推荐;
 	const PAGE_SIZE = 10;
 	const [currentPage, setCurrentPage] = useState(1);
@@ -184,13 +192,13 @@ const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ planType, visible,
 			planType: getVideoListType(planType),
 			subChannel: 'weGZH',
 			category: category ?? '',
-			title: '',
+			title: title ?? '',
 			sortType: sort,
 		});
 
 		const requestParams = {
 			category,
-			title: '',
+			title: title ?? '',
 			sort,
 			type: getVideoListType(planType),
 			pageNum,
@@ -355,6 +363,19 @@ const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ planType, visible,
 		setTimeout(() => getVideoListRef.current?.(1, 'replace'), 0);
 	};
 
+	const handleSearch = (value: string) => {
+		const next = (value ?? '').trim();
+		setTitle(next);
+		reqIdRef.current++;
+		setHasMore(true);
+		setVideoList([]);
+		setViewingPage(1);
+		setPageAnchors(new Map());
+		passedPagesRef.current.clear();
+		drawerBodyRef.current?.scrollTo({ top: 0 });
+		setTimeout(() => getVideoListRef.current?.(1, 'replace'), 0);
+	};
+
 	const handleSelectVideo = (videoId: number) => {
 		setSelectedVideoIds(prev => {
 			const newSet = new Set(prev);
@@ -456,7 +477,7 @@ const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ planType, visible,
 					items={SOURCE_TABS.map(t => ({ key: t.key, label: t.label }))}
 					className="!mb-3"
 				/>
-				<div className="flex flex-wrap gap-2 mb-6">
+				<div className="flex flex-wrap gap-2 mb-6 items-center">
 					<div className="flex items-center gap-2">
 						<span className="text-gray-600">品类:</span>
 						<Select
@@ -468,6 +489,22 @@ const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ planType, visible,
 							options={videoCategoryOptions.map(option => ({ label: option, value: option }))}
 						/>
 					</div>
+					{canSeeSearch && source !== 'hot' && (
+						<div className="flex items-center gap-2">
+							<span className="text-gray-600">搜索:</span>
+							<Tooltip title={searchDisabledTip}>
+								<Input.Search
+									placeholder="按视频标题搜索"
+									style={{ width: 240 }}
+									allowClear
+									enterButton
+									disabled={!!searchDisabledTip}
+									defaultValue={title}
+									onSearch={handleSearch}
+								/>
+							</Tooltip>
+						</div>
+					)}
 				</div>
 
 				<Spin spinning={loading}>

+ 3 - 0
src/views/publishContent/xcxTouliu/hooks/useXcxPlanList.ts

@@ -19,6 +19,7 @@ export interface XcxPlanDataType {
 interface XcxPlanListParams {
 	audiencePackage?: string;
 	title?: string;
+	remark?: string;
 	createTimestampStart?: number;
 	createTimestampEnd?: number;
 	pageNum: number;
@@ -39,6 +40,7 @@ export const useXcxPlanList = () => {
 	const getXcxPlanList = async ({
 		audiencePackage,
 		title,
+		remark,
 		createTimestampStart,
 		createTimestampEnd,
 		pageNum,
@@ -50,6 +52,7 @@ export const useXcxPlanList = () => {
 			const data = await request.post<XcxPlanListResponse>(getXcxPlanListApi, {
 				audiencePackage,
 				title,
+				remark,
 				createTimestampStart,
 				createTimestampEnd,
 				pageNum,

+ 21 - 5
src/views/publishContent/xcxTouliu/index.tsx

@@ -22,6 +22,7 @@ const TableHeight = window.innerHeight - 380;
 const XcxTouliuContent: React.FC = () => {
 	const [audiencePackage, setAudiencePackage] = useState<string>('');
 	const [videoTitle, setVideoTitle] = useState<string>('');
+	const [remark, setRemark] = useState<string>('');
 	const [dateRange, setDateRange] = useState<[Dayjs | null, Dayjs | null]>();
 	const [isShowAddPunlishPlan, setIsShowAddPunlishPlan] = useState<boolean>(false);
 	const [isSubmiting, setIsSubmiting] = useState<boolean>(false);
@@ -219,6 +220,7 @@ const XcxTouliuContent: React.FC = () => {
 		http.post<string>(xcxPlanExportApi, {
 			audiencePackage: audiencePackage || undefined,
 			title: videoTitle || undefined,
+			remark: remark || undefined,
 			createTimestampStart: exportDateRange?.[0] ? exportDateRange[0].startOf('day').valueOf() : undefined,
 			createTimestampEnd: exportDateRange?.[1] ? exportDateRange[1].add(1, 'day').startOf('day').valueOf() : undefined,
 		}).then(res => {
@@ -282,8 +284,9 @@ const XcxTouliuContent: React.FC = () => {
 			pageSize,
 			audiencePackage: audiencePackage || undefined,
 			title: videoTitle || undefined,
-			createTimestampStart: dateRange?.[0]?.unix() ? dateRange[0].unix() * 1000 : undefined,
-			createTimestampEnd: dateRange?.[1]?.unix() ? dateRange[1].unix() * 1000 : undefined,
+			remark: remark || undefined,
+			createTimestampStart: dateRange?.[0] ? dateRange[0].startOf('day').valueOf() : undefined,
+			createTimestampEnd: dateRange?.[1] ? dateRange[1].add(1, 'day').startOf('day').valueOf() : undefined,
 		});
 	};
 
@@ -331,6 +334,18 @@ const XcxTouliuContent: React.FC = () => {
 						/>
 					</div>
 
+					<div className="flex items-center gap-2">
+						<span className="text-gray-600">备注:</span>
+						<Input
+							placeholder="按备注精确筛选"
+							style={{ width: 180 }}
+							value={remark}
+							allowClear
+							onPressEnter={handleSearch}
+							onChange={(e) => setRemark(e.target.value)}
+						/>
+					</div>
+
 					<div className="flex items-center gap-2">
 						<RangePicker
 							placeholder={['开始时间', '结束时间']}
@@ -365,8 +380,9 @@ const XcxTouliuContent: React.FC = () => {
 								pageSize: size,
 								audiencePackage: audiencePackage || undefined,
 								title: videoTitle || undefined,
-								createTimestampStart: dateRange?.[0]?.unix() ? dateRange[0].unix() * 1000 : undefined,
-								createTimestampEnd: dateRange?.[1]?.unix() ? dateRange[1].unix() * 1000 : undefined,
+								remark: remark || undefined,
+								createTimestampStart: dateRange?.[0] ? dateRange[0].startOf('day').valueOf() : undefined,
+								createTimestampEnd: dateRange?.[1] ? dateRange[1].add(1, 'day').startOf('day').valueOf() : undefined,
 							});
 						},
 					}}
@@ -438,7 +454,7 @@ const XcxTouliuContent: React.FC = () => {
 						/>
 					</div>
 					<div className="text-gray-400 text-sm">
-						不选日期默认导出当天数据;最多导出 2000 条;会沿用当前页的「人群包 / 视频标题」筛选条件。
+						不选日期默认导出当天数据;最多导出 2000 条;会沿用当前页的「人群包 / 视频标题 / 备注」筛选条件。
 					</div>
 				</Modal>
 			</div>