jihuaqiang 1 тиждень тому
батько
коміт
76ca7094a1

+ 150 - 0
src/views/publishContent/weCom/components/linkDetailModal/index.tsx

@@ -0,0 +1,150 @@
+import React from 'react';
+import { Modal, Table, Button, Space, Tooltip, message, Typography } from 'antd';
+import { CopyOutlined, PlayCircleOutlined, DownloadOutlined, LinkOutlined, QrcodeOutlined } from '@ant-design/icons';
+import { WeVideoItem } from '@src/views/publishContent/weCom/type'; // Assuming type location
+import copy from 'copy-to-clipboard';
+// import QRCode from 'qrcode.react'; // Consider adding this dependency if not present
+
+const { Text } = Typography;
+
+interface LinkDetailModalProps {
+  visible: boolean;
+  onClose: () => void;
+  videos: WeVideoItem[]; // Use the appropriate type for your video data
+}
+
+// --- Placeholder Functions (Implement actual logic later) ---
+const playVideo = (video: WeVideoItem) => {
+  message.info(`Playing: ${video.title}`);
+  // Add actual video playback logic, perhaps reusing the player modal
+  if (video.video) {
+     window.open(video.video, '_blank');
+  } else {
+    message.warning('No video URL available.');
+  }
+};
+
+const downloadCover = (video: WeVideoItem) => {
+  message.info(`Downloading cover for: ${video.title}`);
+  if (video.cover) {
+    const link = document.createElement('a');
+    link.href = video.cover;
+    // Attempt to infer filename, might need refinement
+    const filename = video.cover.substring(video.cover.lastIndexOf('/') + 1) || `cover_${video.videoId}.jpg`;
+    link.download = filename;
+    link.target = '_blank'; // Open in new tab might be safer for some browsers
+    link.rel = 'noopener noreferrer';
+    document.body.appendChild(link);
+    link.click();
+    document.body.removeChild(link);
+  } else {
+     message.warning('No cover image URL available.');
+  }
+};
+
+const copyPushLink = (video: WeVideoItem & { pushLink?: string }) => {
+  // Assuming video object might have a 'pushLink' property added by the parent component
+  const linkToCopy = video.pushLink || 'Push link not available'; // Updated placeholder
+  if (video.pushLink && copy(linkToCopy)) {
+    message.success('推送链接已复制');
+  } else if (!video.pushLink) {
+    message.warning('没有可复制的推送链接');
+  } else {
+    message.error('复制失败');
+  }
+};
+
+const showQRCode = (video: WeVideoItem) => {
+  message.info(`Showing QR Code for: ${video.title}`);
+  // Add logic to show QR code, e.g., in another modal or popover
+  // const pushLink = video.pushLink || '';
+  // if (pushLink) {
+  //   Modal.info({
+  //     title: '推送链接二维码',
+  //     content: (
+  //       <div style={{ textAlign: 'center', marginTop: '20px' }}>
+  //         {/* <QRCode value={pushLink} size={200} /> */}
+  //         <p>Scan the QR code</p> {}
+  //       </div>
+  //     ),
+  //     okText: '关闭',
+  //   });
+  // } else {
+  //    message.warning('No push link available for QR code.');
+  // }
+   message.warning('QR Code functionality not yet fully implemented.'); // Placeholder
+};
+// --- End Placeholder Functions ---
+
+
+const LinkDetailModal: React.FC<LinkDetailModalProps> = ({ visible, onClose, videos }) => {
+
+  const columns = [
+    {
+      title: '视频标题',
+      dataIndex: 'title',
+      key: 'title',
+      render: (title: string) => (
+        <Space>
+          <Text style={{ maxWidth: 200 }} ellipsis={{ tooltip: title }}>{title}</Text>
+          <Tooltip title="复制标题">
+            <Button
+              type="text"
+              icon={<CopyOutlined />}
+              onClick={() => {
+                if (copy(title)) {
+                  message.success('标题已复制');
+                } else {
+                  message.error('复制失败');
+                }
+              }}
+              size="small"
+            />
+          </Tooltip>
+        </Space>
+      ),
+    },
+    {
+      title: '场景',
+      dataIndex: 'scene',
+      key: 'scene',
+      render: (scene: number | undefined) => (scene === 0 ? '群发' : scene === 1 ? '单发' : '未知'), // Adjust based on your scene values
+    },
+    {
+      title: '操作',
+      key: 'action',
+      render: (_: any, record: WeVideoItem) => (
+        <Space wrap size="small">
+          <Button type="link" icon={<PlayCircleOutlined />} onClick={() => playVideo(record)} size="small">播放</Button>
+          <Button type="link" icon={<DownloadOutlined />} onClick={() => downloadCover(record)} size="small">下载封面</Button>
+          <Button type="link" icon={<LinkOutlined />} onClick={() => copyPushLink(record)} size="small">复制推送链接</Button>
+          <Button type="link" icon={<QrcodeOutlined />} onClick={() => showQRCode(record)} size="small">二维码</Button>
+        </Space>
+      ),
+    },
+  ];
+
+  return (
+    <Modal
+      title="链接详情"
+      open={visible}
+      onCancel={onClose}
+      footer={[
+        <Button key="close" onClick={onClose}>
+          关闭
+        </Button>,
+      ]}
+      width={800} // Adjust width as needed
+      destroyOnClose
+    >
+      <Table
+        columns={columns}
+        dataSource={videos.map(v => ({ ...v, key: v.videoId }))} // Ensure each item has a unique key
+        pagination={false} // Disable pagination if the list is expected to be short
+        size="small"
+      />
+    </Modal>
+  );
+};
+
+export default LinkDetailModal; 

+ 249 - 0
src/views/publishContent/weCom/components/videoSelectModal/index.tsx

@@ -0,0 +1,249 @@
+import React, { useState, useEffect } from 'react';
+import {
+	Drawer,
+	Button,
+	Select,
+	Input,
+	Card,
+	Typography,
+	Pagination,
+	Space,
+	message,
+	Modal,
+} from 'antd';
+import { CheckCircleFilled, CaretRightFilled } from '@ant-design/icons';
+import { VideoListResponse } from '@src/views/publishContent/weGZH/components/types';
+import http from '@src/http';
+import { getVideoContentListApi } from '@src/http/api';
+import { useVideoCategoryOptions } from '@src/views/publishContent/weGZH/hooks/useVideoCategoryOptions';
+import { WeComPlanType, WeVideoItem } from '@src/views/publishContent/weCom/type'
+
+const { Text } = Typography;
+
+interface VideoSelectModalProps {
+	planType: WeComPlanType;
+	visible: boolean;
+	onClose: () => void;
+	onOk: (selectedVideos: WeVideoItem[]) => void;
+	initialSelectedIds?: number[];
+}
+
+const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ planType, visible, onClose, onOk, initialSelectedIds = [] }) => {
+	const { videoCategoryOptions } = useVideoCategoryOptions();
+	const [category, setCategory] = useState<string>();
+	const [searchTerm, setSearchTerm] = useState<string>('');
+	const [currentPage, setCurrentPage] = useState(1);
+	const [pageSize, setPageSize] = useState(10);
+	const [total, setTotal] = useState(0);
+	const [loading, setLoading] = useState(false);
+	const [videoList, setVideoList] = useState<WeVideoItem[]>([]);
+	const [selectedVideoIds, setSelectedVideoIds] = useState<Set<number>>(new Set(initialSelectedIds));
+	const [playingVideo, setPlayingVideo] = useState<WeVideoItem | null>(null);
+	const MAX_SELECTION = 3;
+
+	const getVideoList = async (pageNum?: number) => {
+		setLoading(true);
+		setCurrentPage(pageNum || currentPage);
+		const res = await http.post<VideoListResponse>(getVideoContentListApi, {
+			category,
+			title: searchTerm,
+			pageNum: pageNum || currentPage,
+			pageSize: pageSize,
+		}).catch(() => {
+			message.error('获取视频列表失败');
+		}).finally(() => {
+			setLoading(false);
+		});
+		if (res && res.code === 0) {
+			setVideoList(res.data.objs);
+			setTotal(res.data.totalSize);
+		}
+	}
+
+	useEffect(() => {
+		getVideoList();
+	}, []);
+
+	useEffect(() => {
+		if (visible) {
+			setSelectedVideoIds(new Set(initialSelectedIds));
+		}
+	}, [visible, initialSelectedIds]);
+
+	const handleSearch = () => {
+		console.log('Searching for:', { category, searchTerm });
+		setCurrentPage(1);
+		getVideoList();
+	};
+
+	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 = videoList.filter(video => selectedVideoIds.has(video.videoId));
+		onOk(selectedVideos);
+	};
+
+	const playVideo = (video: WeVideoItem) => {
+		setPlayingVideo(video);
+	};
+
+	const closeVideoPlayer = () => {
+		setPlayingVideo(null);
+	};
+
+	const handleChangeSelectVideo = (videoId: number, scene: number) => {
+		setVideoList((prev: WeVideoItem[]) => {
+			const newList = prev.map(video => {
+				if (video.videoId === videoId) {
+					return { ...video, scene: scene as 0 | 1 };
+				}
+				return video;
+			});
+			return newList;
+		});
+	}
+
+	return (
+		<>
+			<Drawer
+				title="内容选取"
+				open={visible}
+				onClose={onClose}
+				width={800}
+				placement="right"
+				loading={loading}
+				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(page);
+							}}
+							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={videoCategoryOptions.map(option => ({ label: option, value: option }))}
+						/>
+					</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">
+					{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-blue-500 border-2 bg-blue-50 shadow-md' : 'hover:shadow-sm'}`}
+								styles={{ body: { padding: 0 } }}
+								onClick={() => !isDisabled && handleSelectVideo(video.videoId)}
+							>
+								<div className="p-3">
+									<Text type="secondary" className="text-xs">票圈 | 3亿人喜欢的视频平台</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.cover} alt={video.title} referrerPolicy="no-referrer" 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.score?.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>
+								{isSelected && (
+									<div className="p-3 flex justify-between items-center relative z-10">
+										<Select
+											placeholder="选择场景"
+											style={{ width: 180 }}
+											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>
+
+			<Modal
+				open={!!playingVideo}
+				onCancel={closeVideoPlayer}
+				title={playingVideo?.title}
+				footer={null}
+				destroyOnClose
+				width={720}
+				styles={{ body: { padding: 0, background: '#000' } }}
+			>
+				{playingVideo && (
+					<video controls autoPlay className="w-full h-auto max-h-[80vh] block" src={playingVideo.video}>
+						Your browser does not support the video tag.
+					</video>
+				)}
+			</Modal>
+		</>
+	);
+};
+
+export default VideoSelectModal;

+ 165 - 106
src/views/publishContent/weCom/index.tsx

@@ -1,102 +1,168 @@
-import React, { useState } from 'react';
-import { Space, Table, Button, Input, Select, Tabs } from 'antd';
+import React, { useEffect, useState } from 'react';
+import { Space, Table, Button, Input, Select, Tabs, message } from 'antd';
 import type { TableProps } from 'antd';
 import styles from './index.module.css';
-import PunlishPlanModal from '../weGZH/components/publishPlanModal';
-import { wxPlanType } from './type';
+import { WeComPlan, WeComPlanListResponse, WeComPlanType, WeVideoItem } from './type';
+import request from '@src/http/index';
+import { getQwPlanListApi, saveQwPlanApi } from "@src/http/api"
+import VideoSelectModal from './components/videoSelectModal';
+import LinkDetailModal from './components/linkDetailModal';
+import http from '@src/http/index';
+
+// Define a type for the expected API response (adjust if needed based on actual API)
+interface SaveQwPlanResponse {
+	// Assuming the response has a data field containing the created items
+	// And each item is like WeVideoItem but includes a pageUrl
+	createdLinks: (WeVideoItem & { pageUrl: string })[];
+}
 
 const WeGZHContent: React.FC = () => {
 	// 状态管理
 	const [videoTitle, setVideoTitle] = useState<string>('');
 	const [selectedPublisher, setSelectedPublisher] = useState<string>();
 	const [isShowAddPunlishPlan, setIsShowAddPunlishPlan] = useState<boolean>(false);
-	const [actionType, setActionType] = useState<'add' | 'edit'>('add');
-	const [editPlanData, setEditPlanData] = useState<wxPlanType>();
-	const [activeKey, setActiveKey] = useState<string>('1');
+	const [editPlanData, setEditPlanData] = useState<WeComPlan>();
+	const [activeKey, setActiveKey] = useState<WeComPlanType>(WeComPlanType.每日推送);
+
+	const [tableData, setTableData] = useState<WeComPlan[]>([]);
+	const [totalSize, setTotalSize] = useState<number>(0);
+	const [pageNum, setPageNum] = useState<number>(1);
+
+	// State for the new modal
+	const [isLinkDetailModalVisible, setIsLinkDetailModalVisible] = useState<boolean>(false);
+	// State to hold data for the new modal (adjust type if needed)
+	const [createdVideoLinks, setCreatedVideoLinks] = useState<(WeVideoItem & { pushLink?: string })[]>([]);
+
+	const getTableData = (_pageNum?: number) => {
+		setPageNum(_pageNum || 1);
+		request.post<WeComPlanListResponse>(getQwPlanListApi, {
+				pageNum: _pageNum || pageNum,
+				pageSize: 10,
+				scene: selectedPublisher,
+				title: videoTitle,
+				type: +activeKey,
+			}
+		).then(res => {
+			setTableData(res.data.objs || []);
+			setTotalSize(res.data.totalSize);
+		}).catch(err => {
+			message.error(err.msg || '获取数据失败');
+		});
+	}
+
+	useEffect(() => {
+		getTableData(1);
+	}, [activeKey]);
 
 	// 表格列配置
-	const columns: TableProps<wxPlanType>['columns'] = [
-		{
-			title: '公众号名称',
-			dataIndex: 'officialAccount',
-			key: 'officialAccount',
-		},
-		{
-			title: '场景',
-			dataIndex: 'scene',
-			key: 'scene',
-		},
+	const columns: TableProps<WeComPlan>['columns'] = [
 		{
-			title: '视频数量',
-			dataIndex: 'videoCount',
-			key: 'videoCount',
+			title: '创建时间',
+			dataIndex: 'createTimestamp',
+			key: 'createTimestamp',
+			render: (_, record) => {
+				return record.createTimestamp ? new Date(record.createTimestamp).toLocaleString() : '';
+			}
 		},
 		{
 			title: '视频标题',
-			dataIndex: 'videoTitle',
-			key: 'videoTitle',
+			dataIndex: 'title',
+			key: 'title',
 			ellipsis: true,
 		},
 		{
-			title: '计划创建时间',
-			dataIndex: 'planPublishTime',
-			key: 'planPublishTime',
-		},
-		{
-			title: '发布方',
-			dataIndex: 'publisher',
-			key: 'publisher',
+			title: '场景',
+			dataIndex: 'scene',
+			key: 'scene',
+			render: (_, record) => {
+				if (activeKey === WeComPlanType.每日推送) {
+					return record.scene === 0 ? '群发' : '单发';
+				} else {
+					return '自动回复';
+				}
+			}
 		},
 		{
 			title: '操作',
 			key: 'action',
 			render: (_, record) => (
-				<Space size="middle">
-					<Button type="link" onClick={() => editPlan(record)}>编辑</Button>
-					<Button type="link">详情</Button>
+				<Space size="middle" wrap>
+					<Button type="link" onClick={() => window.open(record.video, '_blank')}>播放</Button>
+					<Button type="link" onClick={() => downloadFile(record.cover, record.title + '_cover')}>下载封面</Button>
+					<Button type="link" onClick={() => showQrCodeModal(record.pageUrl, record.title)}>二维码</Button>
+					<Button type="link" onClick={() => copyToClipboard(record.pageUrl)}>复制链接</Button>
 				</Space>
 			),
 		},
 	];
 
-	const editPlan = (record: wxPlanType) => {
-		console.log(editPlanData)
-		setEditPlanData(record);
-		setActionType('edit');
-		setIsShowAddPunlishPlan(true);
+	const copyToClipboard = (text: string) => {
+		if (text && navigator.clipboard) {
+			navigator.clipboard.writeText(text).then(() => {
+				message.success('链接已复制');
+			}, (err) => {
+				message.error('复制失败: ' + err);
+			});
+		} else {
+			message.warning('无链接可复制或浏览器不支持');
+		}
 	};
 
-	// 模拟数据
-	const data: wxPlanType[] = [
-		{
-			officialAccount: '小慧爱厨房',
-			scene: 1,
-			videoCount: 3,
-			videoTitle: '养老金最新规定,快来看看...',
-			planPublishTime: '2024-08-13 13:32:07',
-			publisher: '平台发布',
-			videoList: [],
-		},
-		{
-			officialAccount: '小阳看天下',
-			scene: 1,
-			videoCount: 1,
-			videoTitle: '养老金最新规定,快来看看...',
-			planPublishTime: '2024-08-13 13:32:07',
-			publisher: '用户发布',
-			videoList: [],
-		},
-	];
+	const downloadFile = (url: string, filename: string) => {
+		if (!url) {
+			message.warning('无可用文件下载');
+			return;
+		}
+		const link = document.createElement('a');
+		link.href = url;
+		link.download = filename || url.substring(url.lastIndexOf('/') + 1);
+		link.target = '_blank';
+		link.rel = 'noopener noreferrer';
+		document.body.appendChild(link);
+		link.click();
+		document.body.removeChild(link);
+		message.success('开始下载...');
+	};
+
+	const showQrCodeModal = (url: string, title: string) => {
+		if (!url) {
+			message.warning('无链接生成二维码');
+			return;
+		}
+		message.info(`显示 ${title} 的二维码 (功能待实现)`);
+	};
 
 	const addPunlishPlan = () => {
-		setActionType('add');
 		setIsShowAddPunlishPlan(true);
 	}
 
+	const handleOk = (selectedVideos: WeVideoItem[]) => {
+		http.post<SaveQwPlanResponse>(saveQwPlanApi, {
+			type: +activeKey,
+			videoList: selectedVideos,
+		}).then(res => {			
+			if (res.code === 0 &&res.data && Array.isArray(res.data.createdLinks) && res.data.createdLinks.length > 0) {
+				const linksForModal = res.data.createdLinks.map(item => ({
+					...item,
+					pushLink: item.pageUrl
+				}));
+				message.success('创建成功');
+				setCreatedVideoLinks(linksForModal);
+				setIsLinkDetailModalVisible(true);
+				setIsShowAddPunlishPlan(false);
+				getTableData();
+			} else {
+				message.error(res.msg || '创建失败');
+			}
+		}).catch(err => {
+			message.error(err.msg || '创建失败');
+		});
+	}
+
 	return (
 		<div>
-			<div className="rounded-lg">
-				<div className="text-lg font-medium mb-3">公众号内容</div>
+			<div className="rounded-lg bg-white p-4">
+				<div className="text-lg font-medium mb-3">企业微信内容库</div>
 				
 				{/* 搜索区域 */}
 				<div className="flex flex-wrap gap-4 mb-3">
@@ -113,72 +179,65 @@ const WeGZHContent: React.FC = () => {
 					</div>
 
 					<div className="flex items-center gap-2">
-						<span className="text-gray-600">发布方:</span>
+						<span className="text-gray-600">场景:</span>
 						<Select
 							placeholder="筛选场景"
 							style={{ width: 200 }}
 							value={selectedPublisher}
 							onChange={setSelectedPublisher}
 							allowClear
-							options={[
-								{ label: '关注回复', value: 'platform' },
-								{ label: '用户发布', value: 'user' },
+							options={activeKey === WeComPlanType.每日推送 ? [
+								{ label: '群发', value: 0 },
+								{ label: '单发', value: 1 },
+							] : [
+								{ label: '关注回复', value: 0 },
 							]}
 						/>
 					</div>
 
-					<Button type="primary" className="ml-2">搜索</Button>
+					<Button type="primary" className="ml-2" onClick={() => getTableData(1)}>搜索</Button>
 				</div>
 				<Tabs
 					defaultActiveKey="1"
 					type="card"
 					size="large"
 					items={[
-						{ label: '每日推送', key: '1' },
-						{ label: '自动回复', key: '2' },
+						{ label: '每日推送', key: WeComPlanType.每日推送 },
+						{ label: '自动回复', key: WeComPlanType.自动回复 },
 					]}
 					activeKey={activeKey}
-					onChange={setActiveKey}
+					onChange={(key: string) => setActiveKey(key as WeComPlanType)}
 					tabBarExtraContent={
 						{ right: <Button type="primary" onClick={addPunlishPlan}>+ 创建发布</Button> }}
 				/>		
 				{/* 表格区域 */}
-				{ 
-					activeKey === '1' && (
-						<Table
-							rowKey={(record) => record.officialAccount}
-							className={styles.antTable}
-							columns={columns}
-							dataSource={data}
-							pagination={{
-								total: data.length,
-								pageSize: 10,
-								showTotal: (total) => `共 ${total} 条`,
-							}}
-						/>
-					)
-				}
-				{ 
-					activeKey === '2' && (
-						<Table
-							rowKey={(record) => record.officialAccount}
-							className={styles.antTable}
-							columns={columns}
-							dataSource={data}
-							pagination={{
-								total: data.length,
-								pageSize: 10,
-								showTotal: (total) => `共 ${total} 条`,
-							}}
-						/>
-					)
-				}
-				<PunlishPlanModal
+				<Table
+					rowKey={(record) => record.id}
+					className={styles.antTable}
+					columns={columns}
+					dataSource={tableData}
+					pagination={{
+						current: pageNum,
+						total: totalSize,
+						pageSize: 10,
+						showTotal: (total) => `共 ${total} 条`,
+						onChange: (page) => getTableData(page),
+					}}
+				/>
+				<VideoSelectModal
 					visible={isShowAddPunlishPlan}
-					onCancel={() => setIsShowAddPunlishPlan(false)}
-					onOk={() => setIsShowAddPunlishPlan(false)}
-					actionType={actionType}
-					editPlanData={undefined}
+					onClose={() => {
+						setIsShowAddPunlishPlan(false);
+						setEditPlanData(undefined);
+					}}
+					onOk={handleOk}
+					initialSelectedIds={editPlanData ? [editPlanData.id] : []}
+					planType={activeKey}
+				/>
+				<LinkDetailModal
+					visible={isLinkDetailModalVisible}
+					onClose={() => setIsLinkDetailModalVisible(false)}
+					videos={createdVideoLinks}
 				/>
 			</div>
 		</div>

+ 27 - 9
src/views/publishContent/weCom/type.ts

@@ -1,11 +1,29 @@
-import { VideoItem } from "../weGZH/components/types";
-
-export interface wxPlanType {
-	officialAccount: string;
-	videoCount: number;
-	videoTitle: string;
-	planPublishTime: string;
-	publisher: string;
-	videoList: VideoItem[];
+export interface WeComPlan {
+	cover: string;
+	createTimestamp: number;
+	id: number;
+	pageUrl: string;
 	scene: number;
+	title: string;
+	type: number;
+	video: string;
+}
+
+export interface WeComPlanListResponse {
+	objs: WeComPlan[];
+	totalSize: number;
+}
+
+export enum WeComPlanType {
+	自动回复 = '0',
+	每日推送 = '1',
+}
+
+export interface WeVideoItem {
+	videoId: number;
+	video: string;
+	title: string;
+	cover: string;
+	score: number,
+	scene?: 0 | 1;
 }

+ 13 - 1
src/views/publishContent/weGZH/components/publishPlanModal/index.tsx

@@ -1,5 +1,5 @@
 import React, { useEffect, useState } from 'react';
-import { Modal, Form, Select, Button, Card, Typography, message } from 'antd';
+import { Modal, Form, Select, Button, Card, Typography, message, Input } from 'antd';
 import { CloseOutlined, PlusOutlined, EditOutlined, CaretRightFilled } from '@ant-design/icons';
 import VideoSelectModal from '../videoSelectModal';
 import EditTitleCoverModal from '../editTitleCoverModal';
@@ -27,6 +27,8 @@ const AddPunlishPlanModal: React.FC<AddPunlishPlanModalProps> = ({ visible, isSu
 	const [editingVideo, setEditingVideo] = useState<VideoItem | null>(null); // State for editing modal
 	const { accountOptions } = useAccountOptions();
 
+	const publishStageValue = Form.useWatch('publishStage', form);
+
 	useEffect(() => {
 		if (actionType === 'edit') {
 			form.setFieldsValue(editPlanData);
@@ -144,6 +146,16 @@ const AddPunlishPlanModal: React.FC<AddPunlishPlanModalProps> = ({ visible, isSu
 							<Option value={1}>用户发布</Option>
 						</Select>
 					</Form.Item>
+					<Form.Item
+						name="testInput"
+						label="发布场景"
+						layout="horizontal"
+						labelCol={{ span: 4 }}
+						labelAlign='left'
+						hidden={publishStageValue === 1}
+					>
+						<Input placeholder="请输入" />
+					</Form.Item>
 					<Form.Item
 						name="accountId"
 						label="公众号名称"