123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- import React, { useState, useEffect } from 'react';
- import {
- Modal,
- Form,
- Radio,
- Input,
- Upload,
- Image,
- Space,
- message,
- } from 'antd';
- import { PlusOutlined, CheckCircleFilled } from '@ant-design/icons';
- import type { RadioChangeEvent } from 'antd';
- import type { UploadFile, UploadProps } from 'antd/es/upload/interface';
- import { VideoItem } from '../types';
- import { getAccessToken } from '@src/http/sso';
- import { adFileUpload, getVideoContentCoverFrameListApi } from '@src/http/api';
- import http from '@src/http';
- const { TextArea } = Input;
- interface EditTitleCoverModalProps {
- visible: boolean;
- onCancel: () => void;
- onOk: (updatedVideoData: Partial<VideoItem>) => void;
- video: VideoItem | null;
- }
- const EditTitleCoverModal: React.FC<EditTitleCoverModalProps> = ({ visible, onCancel, onOk, video }) => {
- const [form] = Form.useForm();
- const [titleType, setTitleType] = useState<'original' | 'custom'>('original');
- const [coverType, setCoverType] = useState<'original' | 'screenshot' | 'upload'>('original');
- const [selectedScreenshot, setSelectedScreenshot] = useState<string | null>(null);
- const [fileList, setFileList] = useState<UploadFile[]>([]);
- const [screenshotImagesList, setScreenshotImagesList] = useState<string[]>([]);
- useEffect(() => {
- if (visible) {
- getScreenshotImagesList()
- }
- }, [visible])
- useEffect(() => {
- if (video && visible) {
- // Reset form based on incoming video data
- const hasCustomTitle = video.customTitle && video.customTitle !== '';
- const isCustomCover = video.customCoverType === 1 || video.customCoverType === 2;
- const isScreenshotCover = video.customCoverType === 1;
- const initialTitleType = hasCustomTitle ? 'custom' : 'original';
- let initialCoverType: 'original' | 'screenshot' | 'upload' = 'original';
- if (isCustomCover) {
- if (isScreenshotCover) {
- initialCoverType = 'screenshot';
- setSelectedScreenshot(video.customCover || null);
- setFileList([]);
- } else {
- initialCoverType = 'upload';
- setSelectedScreenshot(null);
- // Assume customThumbnail for upload is a URL, create UploadFile structure
- setFileList([{ uid: '-1', name: 'custom_cover.png', status: 'done', url: video.customCover }]);
- }
- } else {
- initialCoverType = 'original';
- setSelectedScreenshot(null);
- setFileList([]);
- }
- setTitleType(initialTitleType);
- setCoverType(initialCoverType);
- form.setFieldsValue({
- titleType: initialTitleType,
- title: video.title,
- cover: video.cover,
- coverType: initialCoverType,
- customCover: video.customCover,
- customCoverType: video.customCoverType,
- customTitle: video.customTitle,
- });
- } else {
- // Reset form when modal closes or no video
- form.resetFields();
- setTitleType('original');
- setCoverType('original');
- setSelectedScreenshot(null);
- setFileList([]);
- }
- }, [video, visible, form, screenshotImagesList]);
- const getScreenshotImagesList = async () => {
- const res = await http.post<string[]>(getVideoContentCoverFrameListApi, {
- videoId: video?.videoId
- })
- if (res.code === 0) {
- setScreenshotImagesList(res.data || [])
- }
- }
- const handleOk = () => {
- form.validateFields().then(values => {
- const updatedData: Partial<VideoItem> = {};
- // Handle Title
- if (values.titleType === 'custom') {
- updatedData.customTitle = values.customTitle || '';
- } else {
- updatedData.customTitle = '';
- updatedData.title = video?.title; // Revert to original if selected
- }
- // Handle Cover
- if (values.coverType === 'screenshot') {
- if (!selectedScreenshot) {
- message.error('请选择一个视频截图作为封面');
- return;
- }
- updatedData.customCoverType = 1;
- updatedData.customCover = selectedScreenshot;
- } else if (values.coverType === 'upload') {
- if (fileList.length === 0 || !fileList[0].url) {
- // If using status, check for 'done' status and response URL
- message.error('请上传自定义封面图片');
- return;
- }
- // Assuming the upload process directly provides the final URL in fileList[0].url
- // In a real app, you might get this from upload response
- updatedData.customCover = fileList[0].url;
- updatedData.customCoverType = 2;
- } else { // Original
- updatedData.customCover = '';
- updatedData.customCoverType = 0;
- updatedData.cover = video?.cover; // Revert to original
- }
- onOk(updatedData);
- }).catch(info => {
- console.log('Validate Failed:', info);
- });
- };
- const handleUploadChange: UploadProps['onChange'] = ({ fileList: newFileList }) => {
- // Only keep the latest file
- setFileList(newFileList.slice(-1));
- // If upload is successful, manually set coverType to 'upload'
- if (newFileList.length > 0 && newFileList[0].status === 'done') {
- setCoverType('upload');
- form.setFieldsValue({ coverType: 'upload' });
- // In a real app, you would get the URL from the response
- // For demo: assuming the file object gets a url property after upload
- if (!newFileList[0].url) {
- newFileList[0].url = newFileList[0].response.data.fileUrl; // Placeholder URL
- }
- }
- };
- const handleTitleTypeChange = (e: RadioChangeEvent) => {
- setTitleType(e.target.value);
- };
- const handleCoverTypeChange = (e: RadioChangeEvent) => {
- setCoverType(e.target.value);
- // Reset other cover selections when type changes
- if (e.target.value !== 'screenshot') setSelectedScreenshot(null);
- if (e.target.value !== 'upload') setFileList([]);
- };
- const handleSelectScreenshot = (imgUrl: string) => {
- setSelectedScreenshot(imgUrl);
- setCoverType('screenshot');
- form.setFieldsValue({ coverType: 'screenshot' });
- setFileList([]); // Clear upload list if screenshot selected
- };
- const uploadButton = (
- <button style={{ border: 0, background: 'none' }} type="button">
- <PlusOutlined />
- <div style={{ marginTop: 8 }}>上传封面</div>
- </button>
- );
- const checkFile = (file:UploadFile) => {
- if ((file.size || 0) > 5 * 1024 * 1024) {
- message.error('图片大小不能超过5MB')
- return Upload.LIST_IGNORE // 阻止上传,如果返回false,该文件还是会出现在fileList中
- }
-
- return true // 允许上传
- }
-
- const headers = {
- token: getAccessToken()
- }
- return (
- <Modal
- title="编辑标题/封面"
- open={visible}
- onCancel={onCancel}
- onOk={handleOk}
- okText="确定"
- cancelText="取消"
- width={600}
- destroyOnClose
- zIndex={20}
- forceRender // Keep form instance even when closed
- >
- <Form form={form} layout="horizontal" labelCol={{ span: 4 }} wrapperCol={{ span: 20 }} labelAlign="left">
- {/* Title Section */}
- <Form.Item label="标题" name="titleType" initialValue="original">
- <Radio.Group onChange={handleTitleTypeChange}>
- <Radio value="original">原始标题</Radio>
- <Radio value="custom">自定义标题</Radio>
- </Radio.Group>
- </Form.Item>
- {titleType === 'custom' ? (
- <Form.Item
- label="自定义标题"
- name="customTitle"
- rules={[{ required: true, message: '请输入自定义标题' }]}
- >
- <TextArea rows={2} maxLength={50} showCount placeholder="请输入标题" />
- </Form.Item>
- ) : (
- <Form.Item
- label="自定义标题"
- name="title"
- rules={[{ required: true, message: '请输入自定义标题' }]}
- >
- <TextArea disabled rows={2} maxLength={50} showCount placeholder="请输入标题" />
- </Form.Item>
- )}
- {/* Cover Section */}
- <Form.Item label="封面" name="coverType" initialValue="original">
- <Radio.Group onChange={handleCoverTypeChange}>
- <Radio value="original">原始封面</Radio>
- <Radio value="screenshot">视频截图</Radio>
- <Radio value="upload">自定义上传</Radio>
- </Radio.Group>
- </Form.Item>
- {
- coverType === 'original' && (
- <img src={video?.cover} referrerPolicy="no-referrer" className="w-200 h-100 object-cover" />
- )
- }
- {/* Screenshot Selection */}
- {coverType === 'screenshot' && (
- <Form.Item label="视频截图" wrapperCol={{ offset: 4, span: 20 }}>
- <Space wrap>
- {screenshotImagesList.map((imgUrl, index) => (
- <div
- key={index}
- className={`relative w-24 h-24 border-2 cursor-pointer ${selectedScreenshot === imgUrl ? 'border-blue-500' : 'border-transparent'}`}
- onClick={() => handleSelectScreenshot(imgUrl)}
- >
- <Image width="100%" height="100%" src={imgUrl} preview={false} style={{ objectFit: 'cover' }} />
- {selectedScreenshot === imgUrl && (
- <CheckCircleFilled className="absolute top-1 right-1 text-green-500 bg-white rounded-full text-lg" />
- )}
- </div>
- ))}
- </Space>
- </Form.Item>
- )}
- {/* Custom Upload */}
- {coverType === 'upload' && (
- <Form.Item label="自定义上传" wrapperCol={{ offset: 4, span: 20 }}>
- <Upload
- // Replace with your actual upload endpoint
- action={adFileUpload}
- headers={headers}
- accept="image/*"
- listType="picture-card"
- beforeUpload={checkFile}
- onChange={handleUploadChange}
- fileList={fileList}
- showUploadList={{ showPreviewIcon: false }}
- maxCount={1}
- data={{ fileType: 'PICTURE' }}
- >
- {fileList.length >= 1 ? null : uploadButton}
- </Upload>
- </Form.Item>
- )}
- </Form>
- </Modal>
- );
- };
- export default EditTitleCoverModal;
|