123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- import React, { useEffect, useState } from 'react';
- import { Modal, Form, Select, Button, Card, Typography, message } from 'antd';
- import { CloseOutlined, PlusOutlined, EditOutlined, CaretRightFilled } from '@ant-design/icons';
- import VideoSelectModal from '../videoSelectModal';
- import EditTitleCoverModal from '../editTitleCoverModal';
- import { VideoItem } from '../types'; // Import from common types
- import { GzhPlanDataType, GzhPlanType } from '../../hooks/useGzhPlanList';
- import { useAccountOptions } from '../../hooks/useAccountOptions';
- const { Option } = Select;
- const { Paragraph } = Typography;
- interface AddPunlishPlanModalProps {
- visible: boolean;
- onCancel: () => void;
- onOk: (values: GzhPlanDataType) => void; // Pass form values on OK
- actionType: 'add' | 'edit';
- planType: GzhPlanType;
- editPlanData?: GzhPlanDataType;
- isSubmiting?: boolean;
- }
- const AddPunlishPlanModal: React.FC<AddPunlishPlanModalProps> = ({
- visible,
- isSubmiting,
- onCancel,
- onOk,
- actionType,
- planType,
- editPlanData
- }) => {
- const [form] = Form.useForm();
- const type = Form.useWatch('type', form);
- const selectVideoType = Form.useWatch('selectVideoType', form);
- const [selectedVideos, setSelectedVideos] = useState<VideoItem[]>([]);
- const [isVideoSelectVisible, setIsVideoSelectVisible] = useState(false);
- const [playingVideo, setPlayingVideo] = useState<VideoItem | null>(null); // State for video player modal
- const [editingVideo, setEditingVideo] = useState<VideoItem | null>(null); // State for editing modal
- const { accountOptions, getAccountList } = useAccountOptions();
- useEffect(() => {
- if (actionType === 'edit') {
- form.setFieldsValue({...editPlanData, type: editPlanData?.type.toString()});
- setSelectedVideos(editPlanData?.videoList || []);
- } else {
- setSelectedVideos([]);
- form.setFieldsValue({
- id: undefined,
- type: planType,
- publishStage: 1,
- selectVideoType: 0,
- accountId: undefined,
- scene: 0,
- videoList: []
- });
- }
- }, [actionType, editPlanData, visible]);
- useEffect(() => {
- getAccountList({accountType: planType});
- }, [planType]);
- const onTypeChange = (value: string) => {
- form.setFieldsValue({ accountId: undefined });
- getAccountList({ accountType: value });
- }
- const handleOk = () => {
- form
- .validateFields()
- .then((values) => {
- // Ensure at least one video is selected before submitting
- if (selectedVideos.length === 0) {
- message.error('请至少选择一个视频'); // Use Antd message
- return;
- }
- const formData = { ...values };
- if (formData.type === GzhPlanType.自动回复) {
- formData.scene = 0;
- }
- formData.videoList = selectedVideos;
- onOk(formData);
- })
- .catch((info) => {
- console.log('Validate Failed:', info);
- });
- };
- const removeVideo = (idToRemove: number) => {
- setSelectedVideos(currentVideos => currentVideos.filter(video => video.videoId !== idToRemove));
- };
- const openVideoSelector = () => {
- setIsVideoSelectVisible(true);
- };
- const handleVideoSelectionOk = (newlySelectedVideos: VideoItem[]) => {
- // Merge existing custom data with newly selected videos
- const currentCustomData = new Map<number, Partial<VideoItem>>();
- selectedVideos.forEach(v => {
- if (v.videoId) {
- currentCustomData.set(v.videoId, { customTitle: v.customTitle, customCover: v.customCover, customCoverType: v.customCoverType });
- }
- });
- const mergedVideos = newlySelectedVideos.map(newVideo => {
- const customData = currentCustomData.get(newVideo.videoId);
- return { ...newVideo, ...customData };
- });
- setSelectedVideos(mergedVideos);
- setIsVideoSelectVisible(false);
- };
- const handleVideoSelectionCancel = () => {
- setIsVideoSelectVisible(false);
- };
- const playVideo = (video: VideoItem) => {
- setPlayingVideo(video);
- };
- const closeVideoPlayer = () => {
- setPlayingVideo(null);
- };
- const openEditModal = (video: VideoItem) => {
- setEditingVideo(video);
- };
- const handleEditOk = (updatedData: Partial<VideoItem>) => {
- console.log('updatedData', updatedData);
- setSelectedVideos(currentVideos =>
- currentVideos.map(v =>
- v.videoId === editingVideo?.videoId ? { ...v, ...updatedData } : v
- )
- );
- setEditingVideo(null); // Close modal
- };
- const handleEditCancel = () => {
- setEditingVideo(null);
- };
- return (
- <>
- <Modal
- title={actionType === 'add' ? "创建发布计划" : "编辑发布计划"}
- open={visible}
- destroyOnClose
- onCancel={onCancel}
- width={900} // Adjust width as needed
- footer={[
- <Button key="back" onClick={onCancel}>
- 取消
- </Button>,
- <Button key="submit" type="primary" loading={isSubmiting} onClick={handleOk}>
- 确定
- </Button>,
- ]}
- zIndex={10}
- >
- <Form form={form} layout="vertical">
- <Form.Item
- name="id"
- label="计划ID"
- hidden
- >
- </Form.Item>
- <Form.Item
- name="type"
- label="发布计划类型"
- layout="horizontal"
- labelCol={{ span: 4 }}
- labelAlign='left'
- required
- >
- <Select placeholder="选择计划类型" onChange={onTypeChange} className='!w-50' disabled={actionType === 'edit'}>
- <Option value={GzhPlanType.自动回复}>自动回复</Option>
- <Option value={GzhPlanType.服务号推送}>服务号推送</Option>
- </Select>
- </Form.Item>
- <Form.Item
- name="scene"
- label="发布场景"
- layout="horizontal"
- labelCol={{ span: 4 }}
- labelAlign='left'
- initialValue={0}
- hidden={type !== GzhPlanType.自动回复}
- >
- <Select
- placeholder="发布场景"
- className='!w-50'
- options={[{ label: '关注回复', value: 0 }]}>
- </Select>
- </Form.Item>
- <Form.Item
- name="publishStage"
- label="发布方式"
- labelCol={{ span: 4 }}
- labelAlign='left'
- layout="horizontal"
- rules={[{ required: true, message: '请选择发布方式' }]}
- >
- <Select placeholder="选择发布方式" allowClear className='!w-50'>
- <Option value={0} disabled={type !== GzhPlanType.自动回复}>平台发布</Option>
- <Option value={1} >用户获取路径</Option>
- </Select>
- </Form.Item>
- <Form.Item
- name="accountId"
- label="公众号名称"
- labelCol={{ span: 4 }}
- labelAlign='left'
- layout="horizontal"
- rules={[{ required: true, message: '请选择公众号' }]}
- >
- <Select
- placeholder="选择公众号"
- allowClear
- disabled={actionType === 'edit'}
- className='!w-50'
- showSearch
- filterOption={(input, option) =>
- (option?.label ?? '').toLowerCase().includes(input.toLowerCase())
- }
- options={accountOptions?.map(option => ({ label: option.name, value: option.id }))}>
- </Select>
- </Form.Item>
-
- <Form.Item
- name="selectVideoType"
- label="视频选取方式"
- labelCol={{ span: 4 }}
- labelAlign='left'
- layout="horizontal"
- rules={[{ required: true, message: '请选择视频选取方式' }]}>
- <Select placeholder="选择视频选取方式" allowClear className='!w-50'>
- <Option value={0} >手动选取</Option>
- <Option value={1} disabled>自动选取</Option>
- </Select>
- </Form.Item>
- <Form.Item label="发布内容" required>
- {
- selectVideoType === 0 ?
- (<div className="flex flex-wrap gap-4">
- {selectedVideos.map((video) => (
- <Card
- key={video.videoId}
- className="w-[240px] relative group"
- >
- <Button
- shape="circle"
- icon={<CloseOutlined />}
- className="!absolute top-1 right-1 z-10 bg-gray-400 bg-opacity-50 border-none text-white hidden group-hover:inline-flex justify-center items-center"
- size="small"
- onClick={() => removeVideo(video.videoId)}
- />
- <div className="p-0">
- <Paragraph className="mt-1 !mb-1" ellipsis={{ rows: 2, tooltip: true }} title={video.customTitle || video.title}>{video.customTitle || video.title}</Paragraph>
- </div>
- <div
- className="relative"
- style={{ paddingBottom: '79.8%' }}
- onClick={(e) => {
- e.stopPropagation(); // Prevent card selection if clicking thumbnail/play
- playVideo(video);
- }}
- >
- <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">
- <CaretRightFilled className="!text-white text-4xl bg-black/20 rounded-full p-1 pl-2" />
- </div>
- </div>
- <div className="p-3">
- <Button
- icon={<EditOutlined />}
- className="w-full mt-2"
- onClick={() => openEditModal(video)} // Open edit modal
- >
- 编辑标题/封面
- </Button>
- </div>
- </Card>
- ))}
-
- {/* Add Video Button - Conditionally Rendered */}
- {selectedVideos.length < 3 && (
- <div
- className="w-[240px] h-[316px] flex flex-col justify-center items-center border border-dashed border-gray-300 rounded cursor-pointer dark:border-gray-600 hover:border-blue-500 hover:text-blue-500"
- onClick={openVideoSelector} // Open the drawer on click
- >
- <PlusOutlined className="text-2xl mb-2" />
- <Typography.Text>添加视频</Typography.Text>
- </div>
- )}
- </div>)
- : (<div>
- <Paragraph>视频由系统自动选取,不可手动选择</Paragraph>
- </div>)
- }
-
- </Form.Item>
- </Form>
- </Modal>
- {/* Video Selection Drawer */}
- <VideoSelectModal
- visible={isVideoSelectVisible}
- onClose={handleVideoSelectionCancel}
- onOk={handleVideoSelectionOk}
- selectedVideos={selectedVideos}
- initialSelectedIds={selectedVideos.map(v => v.videoId)} // Pass current selection IDs
- />
- {/* Video Player Modal */}
- <Modal
- open={!!playingVideo}
- onCancel={closeVideoPlayer}
- title={playingVideo?.customTitle || playingVideo?.title}
- footer={null}
- destroyOnClose // Unmount video element when closed
- width={720} // Adjust as needed
- styles={{ body: { padding: 0, background: '#000' } }}
- zIndex={20}
- >
- {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>
- {/* Edit Title/Cover Modal */}
- <EditTitleCoverModal
- visible={!!editingVideo}
- onCancel={handleEditCancel}
- onOk={handleEditOk}
- video={editingVideo}
- />
- </>
- );
- };
- export default AddPunlishPlanModal;
|