jihuaqiang 1 Minggu lalu
induk
melakukan
6be78c946e

+ 1 - 0
src/http/api.ts

@@ -31,6 +31,7 @@ export const saveGzhPlanApi = `${import.meta.env.VITE_API_URL}/contentPlatform/p
 export const deleteGzhPlanApi = `${import.meta.env.VITE_API_URL}/contentPlatform/plan/gzh/delete`
 export const deleteGzhPlanApi = `${import.meta.env.VITE_API_URL}/contentPlatform/plan/gzh/delete`
 export const getQwPlanListApi = `${import.meta.env.VITE_API_URL}/contentPlatform/plan/qw/list`
 export const getQwPlanListApi = `${import.meta.env.VITE_API_URL}/contentPlatform/plan/qw/list`
 export const saveQwPlanApi = `${import.meta.env.VITE_API_URL}/contentPlatform/plan/qw/save`
 export const saveQwPlanApi = `${import.meta.env.VITE_API_URL}/contentPlatform/plan/qw/save`
+export const deleteQwPlanApi = `${import.meta.env.VITE_API_URL}/contentPlatform/plan/qw/delete`
 export const getVideoContentCategoryListApi = `${import.meta.env.VITE_API_URL}/contentPlatform/plan/videoContentCategoryList`
 export const getVideoContentCategoryListApi = `${import.meta.env.VITE_API_URL}/contentPlatform/plan/videoContentCategoryList`
 export const getVideoContentCoverFrameListApi = `${import.meta.env.VITE_API_URL}/contentPlatform/plan/videoContentCoverFrameList`
 export const getVideoContentCoverFrameListApi = `${import.meta.env.VITE_API_URL}/contentPlatform/plan/videoContentCoverFrameList`
 export const getVideoContentListApi = `${import.meta.env.VITE_API_URL}/contentPlatform/plan/videoContentList`
 export const getVideoContentListApi = `${import.meta.env.VITE_API_URL}/contentPlatform/plan/videoContentList`

+ 9 - 7
src/views/publishContent/weCom/components/videoSelectModal/index.tsx

@@ -18,7 +18,7 @@ import { getVideoContentListApi } from '@src/http/api';
 import { useVideoCategoryOptions } from '@src/views/publishContent/weGZH/hooks/useVideoCategoryOptions';
 import { useVideoCategoryOptions } from '@src/views/publishContent/weGZH/hooks/useVideoCategoryOptions';
 import { WeComPlanType, WeVideoItem } from '@src/views/publishContent/weCom/type'
 import { WeComPlanType, WeVideoItem } from '@src/views/publishContent/weCom/type'
 
 
-const { Text } = Typography;
+const { Text, Paragraph } = Typography;
 
 
 interface VideoSelectModalProps {
 interface VideoSelectModalProps {
 	planType: WeComPlanType;
 	planType: WeComPlanType;
@@ -42,14 +42,15 @@ const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ planType, visible,
 	const [playingVideo, setPlayingVideo] = useState<WeVideoItem | null>(null);
 	const [playingVideo, setPlayingVideo] = useState<WeVideoItem | null>(null);
 	const MAX_SELECTION = 3;
 	const MAX_SELECTION = 3;
 
 
-	const getVideoList = async (pageNum?: number) => {
+	const getVideoList = async (pageNum?: number, _pageSize?: number) => {
 		setLoading(true);
 		setLoading(true);
 		setCurrentPage(pageNum || currentPage);
 		setCurrentPage(pageNum || currentPage);
+		setPageSize(_pageSize || pageSize);
 		const res = await http.post<VideoListResponse>(getVideoContentListApi, {
 		const res = await http.post<VideoListResponse>(getVideoContentListApi, {
 			category,
 			category,
 			title: searchTerm,
 			title: searchTerm,
 			pageNum: pageNum || currentPage,
 			pageNum: pageNum || currentPage,
-			pageSize: pageSize,
+			pageSize: _pageSize || pageSize,
 		}).catch(() => {
 		}).catch(() => {
 			message.error('获取视频列表失败');
 			message.error('获取视频列表失败');
 		}).finally(() => {
 		}).finally(() => {
@@ -148,7 +149,7 @@ const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ planType, visible,
 							onChange={(page, size) => {
 							onChange={(page, size) => {
 								setCurrentPage(page);
 								setCurrentPage(page);
 								setPageSize(size);
 								setPageSize(size);
-								getVideoList(page);
+								getVideoList(page, size);
 							}}
 							}}
 							pageSizeOptions={['10', '20', '50']}
 							pageSizeOptions={['10', '20', '50']}
 							size="small"
 							size="small"
@@ -200,13 +201,14 @@ const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ planType, visible,
 							>
 							>
 								<div className="p-3">
 								<div className="p-3">
 									<Text type="secondary" className="text-xs">票圈 | 3亿人喜欢的视频平台</Text>
 									<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>
+									<Paragraph className="mt-1 !mb-1" ellipsis={{ rows: 2, tooltip: true }} title={video.title}>{video.title}</Paragraph>
 								</div>
 								</div>
 								<div
 								<div
-									className="relative h-[120px] bg-gray-200 group/thumb"
+									className="relative"
+									style={{ paddingBottom: '79.8%' }}
 									onClick={(e) => { e.stopPropagation(); playVideo(video); }}
 									onClick={(e) => { e.stopPropagation(); playVideo(video); }}
 								>
 								>
-									<img src={video.cover} alt={video.title} referrerPolicy="no-referrer" className="w-full h-full object-cover" />
+									<img src={video.cover} alt={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">
 									<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" />
 										<CaretRightFilled className="!text-white text-4xl bg-black/20 rounded-full p-1 pl-2" />
 									</div>
 									</div>

+ 26 - 6
src/views/publishContent/weCom/index.tsx

@@ -1,10 +1,10 @@
 import React, { useEffect, useState } from 'react';
 import React, { useEffect, useState } from 'react';
-import { Space, Table, Button, Input, Select, Tabs, message } from 'antd';
+import { Space, Table, Button, Input, Select, Tabs, message, Spin } from 'antd';
 import type { TableProps } from 'antd';
 import type { TableProps } from 'antd';
 import styles from './index.module.css';
 import styles from './index.module.css';
 import { WeComPlan, WeComPlanListResponse, WeComPlanType, WeVideoItem } from './type';
 import { WeComPlan, WeComPlanListResponse, WeComPlanType, WeVideoItem } from './type';
 import request from '@src/http/index';
 import request from '@src/http/index';
-import { getQwPlanListApi, getShareQrPic, saveQwPlanApi } from "@src/http/api"
+import { deleteQwPlanApi, getQwPlanListApi, getShareQrPic, saveQwPlanApi } from "@src/http/api"
 import VideoSelectModal from './components/videoSelectModal';
 import VideoSelectModal from './components/videoSelectModal';
 import LinkDetailModal from './components/linkDetailModal';
 import LinkDetailModal from './components/linkDetailModal';
 import PlanDetailModal from './components/planDetailModal';
 import PlanDetailModal from './components/planDetailModal';
@@ -25,7 +25,7 @@ const WeGZHContent: React.FC = () => {
 	const [tableData, setTableData] = useState<WeComPlan[]>([]);
 	const [tableData, setTableData] = useState<WeComPlan[]>([]);
 	const [totalSize, setTotalSize] = useState<number>(0);
 	const [totalSize, setTotalSize] = useState<number>(0);
 	const [pageNum, setPageNum] = useState<number>(1);
 	const [pageNum, setPageNum] = useState<number>(1);
-
+	const [isLoading, setIsLoading] = useState<boolean>(false);
 	// State for the new modal
 	// State for the new modal
 	const [isLinkDetailModalVisible, setIsLinkDetailModalVisible] = useState<boolean>(false);
 	const [isLinkDetailModalVisible, setIsLinkDetailModalVisible] = useState<boolean>(false);
 	const [createdVideoLinks, setCreatedVideoLinks] = useState<WeComPlan[]>([]);
 	const [createdVideoLinks, setCreatedVideoLinks] = useState<WeComPlan[]>([]);
@@ -89,7 +89,8 @@ const WeGZHContent: React.FC = () => {
 		{
 		{
 			title: '操作',
 			title: '操作',
 			key: 'action',
 			key: 'action',
-			width: 500,
+			width: 550,
+			fixed: 'right',
 			render: (_, record) => (
 			render: (_, record) => (
 				<Space size="middle" wrap>
 				<Space size="middle" wrap>
 					<Button type="link" onClick={() => playVideo(record)}>播放</Button>
 					<Button type="link" onClick={() => playVideo(record)}>播放</Button>
@@ -97,11 +98,30 @@ const WeGZHContent: React.FC = () => {
 					<Button type="link" onClick={() => showQrCodeModal(record.pageUrl)}>二维码</Button>
 					<Button type="link" onClick={() => showQrCodeModal(record.pageUrl)}>二维码</Button>
 					<Button type="link" onClick={() => copyToClipboard(record.pageUrl)}>复制链接</Button>
 					<Button type="link" onClick={() => copyToClipboard(record.pageUrl)}>复制链接</Button>
 					<Button type="link" onClick={() => showDetailModal(record)}>详情</Button>
 					<Button type="link" onClick={() => showDetailModal(record)}>详情</Button>
+					<Button type="link" onClick={() => deletePlan(record)}>删除</Button>
 				</Space>
 				</Space>
 			),
 			),
 		},
 		},
 	];
 	];
 
 
+	const deletePlan = (record: WeComPlan) => {
+		setIsLoading(true);
+		http.post(deleteQwPlanApi, {
+			id: record.id,
+		}).then(res => {
+			if (res.code === 0) {
+				message.success('删除成功');
+				getTableData();
+			} else {
+				message.error(res.msg || '删除失败');
+			}
+		}).catch(err => {
+			message.error(err.msg || '删除失败');
+		}).finally(() => {
+			setIsLoading(false);
+		});
+	}
+
 	const playVideo = (record: WeComPlan) => {
 	const playVideo = (record: WeComPlan) => {
 		setEditPlanData(record);
 		setEditPlanData(record);
 		setIsVideoPlayModalVisible(true);
 		setIsVideoPlayModalVisible(true);
@@ -173,7 +193,7 @@ const WeGZHContent: React.FC = () => {
 	}
 	}
 
 
 	return (
 	return (
-		<div>
+		<Spin spinning={isLoading}>
 			<div className="rounded-lg">
 			<div className="rounded-lg">
 				<div className="text-lg font-medium mb-3">企业微信内容库</div>
 				<div className="text-lg font-medium mb-3">企业微信内容库</div>
 				
 				
@@ -269,7 +289,7 @@ const WeGZHContent: React.FC = () => {
 					title={editPlanData?.title || ''}
 					title={editPlanData?.title || ''}
 				/>
 				/>
 			</div>
 			</div>
-		</div>
+		</Spin>
 	);
 	);
 };
 };
 
 

+ 5 - 4
src/views/publishContent/weGZH/components/publishPlanModal/index.tsx

@@ -8,7 +8,7 @@ import { GzhPlanType } from '../../hooks/useGzhPlanList';
 import { useAccountOptions } from '../../hooks/useAccountOptions';
 import { useAccountOptions } from '../../hooks/useAccountOptions';
 
 
 const { Option } = Select;
 const { Option } = Select;
-const { Text } = Typography;
+const { Paragraph } = Typography;
 
 
 interface AddPunlishPlanModalProps {
 interface AddPunlishPlanModalProps {
 	visible: boolean;
 	visible: boolean;
@@ -190,16 +190,17 @@ const AddPunlishPlanModal: React.FC<AddPunlishPlanModalProps> = ({ visible, isSu
 										onClick={() => removeVideo(video.videoId)}
 										onClick={() => removeVideo(video.videoId)}
 									/>
 									/>
 									<div className="p-0">
 									<div className="p-0">
-										<Text className="block mt-1 mb-2 leading-tight line-clamp-2" title={video.customTitle || video.title}>{video.customTitle || video.title}</Text>
+										<Paragraph className="mt-1 !mb-1" ellipsis={{ rows: 2, tooltip: true }} title={video.customTitle || video.title}>{video.customTitle || video.title}</Paragraph>
 									</div>
 									</div>
 									<div
 									<div
-										className="relative h-[120px] bg-gray-200 cursor-pointer group/thumb"
+										className="relative"
+										style={{ paddingBottom: '79.8%' }}
 										onClick={(e) => {
 										onClick={(e) => {
 											e.stopPropagation(); // Prevent card selection if clicking thumbnail/play
 											e.stopPropagation(); // Prevent card selection if clicking thumbnail/play
 											playVideo(video);
 											playVideo(video);
 										}}
 										}}
 									>
 									>
-										<img src={video.customCover || video.cover} referrerPolicy="no-referrer" className="w-full h-full object-cover" />
+										<img src={video.customCover || video.cover} 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">
 										<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" />
 											<CaretRightFilled className="!text-white text-4xl bg-black/20 rounded-full p-1 pl-2" />
 										</div>
 										</div>

+ 10 - 8
src/views/publishContent/weGZH/components/videoSelectModal/index.tsx

@@ -17,7 +17,7 @@ import http from '@src/http';
 import { getVideoContentListApi } from '@src/http/api';
 import { getVideoContentListApi } from '@src/http/api';
 import { useVideoCategoryOptions } from '../../hooks/useVideoCategoryOptions';
 import { useVideoCategoryOptions } from '../../hooks/useVideoCategoryOptions';
 
 
-const { Text } = Typography;
+const { Paragraph, Text } = Typography;
 
 
 interface VideoSelectModalProps {
 interface VideoSelectModalProps {
 	visible: boolean;
 	visible: boolean;
@@ -41,14 +41,15 @@ const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ visible, onClose, o
 	const [playingVideo, setPlayingVideo] = useState<VideoItem | null>(null);
 	const [playingVideo, setPlayingVideo] = useState<VideoItem | null>(null);
 	const MAX_SELECTION = 3;
 	const MAX_SELECTION = 3;
 
 
-	const getVideoList = async (pageNum?: number) => {
+	const getVideoList = async (pageNum?: number, _pageSize?: number) => {
 		setLoading(true);
 		setLoading(true);
 		setCurrentPage(pageNum || currentPage);
 		setCurrentPage(pageNum || currentPage);
+		setPageSize(_pageSize || pageSize);
 		const res = await http.post<VideoListResponse>(getVideoContentListApi, {
 		const res = await http.post<VideoListResponse>(getVideoContentListApi, {
 			category,
 			category,
 			title: searchTerm,
 			title: searchTerm,
 			pageNum: pageNum || currentPage,
 			pageNum: pageNum || currentPage,
-			pageSize: pageSize,
+			pageSize: _pageSize || pageSize,
 		}).catch(() => {
 		}).catch(() => {
 			message.error('获取视频列表失败');
 			message.error('获取视频列表失败');
 		}).finally(() => {
 		}).finally(() => {
@@ -130,7 +131,7 @@ const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ visible, onClose, o
 							onChange={(page, size) => {
 							onChange={(page, size) => {
 								setCurrentPage(page);
 								setCurrentPage(page);
 								setPageSize(size);
 								setPageSize(size);
-								getVideoList(page);
+								getVideoList(page, size);
 							}}
 							}}
 							pageSizeOptions={['10', '20', '50']}
 							pageSizeOptions={['10', '20', '50']}
 							size="small"
 							size="small"
@@ -180,15 +181,16 @@ const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ visible, onClose, o
 								styles={{ body: { padding: 0 } }}
 								styles={{ body: { padding: 0 } }}
 								onClick={() => !isDisabled && handleSelectVideo(video.videoId)}
 								onClick={() => !isDisabled && handleSelectVideo(video.videoId)}
 							>
 							>
-								<div className="p-3">
+								<div className="p-2">
 									<Text type="secondary" className="text-xs">票圈 | 3亿人喜欢的视频平台</Text>
 									<Text type="secondary" className="text-xs">票圈 | 3亿人喜欢的视频平台</Text>
-									<Text className="block mt-1 mb-2 leading-tight line-clamp-2" title={video.customTitle || video.title}>{video.customTitle || video.title}</Text>
+									<Paragraph className="mt-1 !mb-1" ellipsis={{ rows: 2, tooltip: true }} title={video.customTitle || video.title}>{video.customTitle || video.title}</Paragraph>
 								</div>
 								</div>
 								<div
 								<div
-									className="relative h-[120px] bg-gray-200 group/thumb"
+									className="relative"
+									style={{ paddingBottom: '79.8%' }}
 									onClick={(e) => { e.stopPropagation(); playVideo(video); }}
 									onClick={(e) => { e.stopPropagation(); playVideo(video); }}
 								>
 								>
-									<img src={video.customCover || video.cover} alt={video.customTitle || video.title} referrerPolicy="no-referrer" className="w-full h-full object-cover" />
+									<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">
 									<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" />
 										<CaretRightFilled className="!text-white text-4xl bg-black/20 rounded-full p-1 pl-2" />
 									</div>
 									</div>

+ 7 - 5
src/views/publishContent/weGZH/index.tsx

@@ -1,5 +1,5 @@
 import React, { useEffect, useState } from 'react';
 import React, { useEffect, useState } from 'react';
-import { Space, Table, Button, Input, Select, DatePicker, Tabs, message, Typography } from 'antd';
+import { Space, Table, Button, Input, Select, DatePicker, Tabs, message, Typography, Spin } from 'antd';
 import type { TableProps } from 'antd';
 import type { TableProps } from 'antd';
 import dayjs, { Dayjs } from 'dayjs';
 import dayjs, { Dayjs } from 'dayjs';
 import styles from './index.module.css';
 import styles from './index.module.css';
@@ -24,7 +24,7 @@ const WeGZHContent: React.FC = () => {
 	const [editPlanData, setEditPlanData] = useState<GzhPlanType>();
 	const [editPlanData, setEditPlanData] = useState<GzhPlanType>();
 	const [activeKey, setActiveKey] = useState<string>('1');
 	const [activeKey, setActiveKey] = useState<string>('1');
 	const [isSubmiting, setIsSubmiting] = useState<boolean>(false);
 	const [isSubmiting, setIsSubmiting] = useState<boolean>(false);
-
+	const [isLoading, setIsLoading] = useState<boolean>(false);
 	const { accountOptions } = useAccountOptions();
 	const { accountOptions } = useAccountOptions();
 	const { gzhPlanList, getGzhPlanList, totalSize } = useGzhPlanList();
 	const { gzhPlanList, getGzhPlanList, totalSize } = useGzhPlanList();
 
 
@@ -60,7 +60,7 @@ const WeGZHContent: React.FC = () => {
 			ellipsis: true,
 			ellipsis: true,
 			render: (_, record) => {
 			render: (_, record) => {
 				return record.videoList.map(video => {
 				return record.videoList.map(video => {
-					return <Typography.Paragraph  ellipsis={true} key={video.videoId}>{video.customTitle || video.title}</Typography.Paragraph>
+					return <Typography.Paragraph style={{ maxWidth: '300px' }} ellipsis={{ rows: 1, tooltip: true }} key={video.videoId}>{video.customTitle || video.title}</Typography.Paragraph>
 				})
 				})
 			}
 			}
 		},
 		},
@@ -97,6 +97,7 @@ const WeGZHContent: React.FC = () => {
 	];
 	];
 
 
 	const deletePlan = async (record: GzhPlanType) => {
 	const deletePlan = async (record: GzhPlanType) => {
+		setIsLoading(true);
 		const res = await http.post(deleteGzhPlanApi, {
 		const res = await http.post(deleteGzhPlanApi, {
 			id: record.id,
 			id: record.id,
 		}).catch(err => {
 		}).catch(err => {
@@ -111,6 +112,7 @@ const WeGZHContent: React.FC = () => {
 		} else {
 		} else {
 			message.error(res?.msg || '删除失败');
 			message.error(res?.msg || '删除失败');
 		}
 		}
+		setIsLoading(false);
 	}
 	}
 
 
 	const editPlan = (record: GzhPlanType) => {
 	const editPlan = (record: GzhPlanType) => {
@@ -172,7 +174,7 @@ const WeGZHContent: React.FC = () => {
 	}
 	}
 
 
 	return (
 	return (
-		<div>
+		<Spin spinning={isLoading || isSubmiting}>
 			<div className="rounded-lg">
 			<div className="rounded-lg">
 				<div className="text-lg font-medium mb-3">公众号内容</div>
 				<div className="text-lg font-medium mb-3">公众号内容</div>
 				
 				
@@ -277,7 +279,7 @@ const WeGZHContent: React.FC = () => {
 					planData={editPlanData as GzhPlanType}
 					planData={editPlanData as GzhPlanType}
 				/>
 				/>
 			</div>
 			</div>
-		</div>
+		</Spin>
 	);
 	);
 };
 };