Files
cunkebao_v3/Cunkebao/src/pages/content/materials/New.tsx
笔记本里的永平 92a3d407a7 feat: 本次提交更新内容如下
定版本转移2025年7月17日
2025-07-17 10:22:38 +08:00

272 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { Card } from '@/components/ui/card';
import { Button } from 'tdesign-mobile-react';
import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
import { Label } from '@/components/ui/label';
import { toast } from '@/components/ui/toast';
import Layout from '@/components/Layout';
import UnifiedHeader from '@/components/UnifiedHeader';
import { get, post } from '@/api/request';
import UploadImage from '@/components/UploadImage';
import UploadVideo from '@/components/UploadVideo';
export default function NewMaterial() {
const navigate = useNavigate();
const { id, materialId } = useParams(); // materialId 作为编辑标识
const [content, setContent] = useState('');
const [comment, setComment] = useState('');
const [contentType, setContentType] = useState<number>(1);
const [desc, setDesc] = useState('');
const [coverImage, setCoverImage] = useState('');
const [url, setUrl] = useState('');
const [videoUrl, setVideoUrl] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
const [isEdit, setIsEdit] = useState(false);
const [sendTime, setSendTime] = useState('');
const [images, setImages] = useState<string[]>([]);
const [isFirstLoad, setIsFirstLoad] = useState(true);
// 优化图片上传逻辑,确保每次选择图片后立即上传并回显
// 判断模式并拉取详情
useEffect(() => {
if (materialId) {
setIsEdit(true);
get(`/v1/content/library/get-item-detail?id=${materialId}`)
.then(res => {
if (res && res.code === 200 && res.data) {
setContent(res.data.content || '');
setComment(res.data.comment || '');
setSendTime(res.data.sendTime || '');
if (isFirstLoad && res.data.contentType) {
setContentType(Number(res.data.contentType));
setIsFirstLoad(false);
}
setDesc(res.data.desc || '');
setCoverImage(res.data.coverImage || '');
setUrl(res.data.url || '');
setVideoUrl(res.data.videoUrl || '');
setImages(res.data.resUrls || []); // 图片回显
} else {
toast({ title: '获取失败', description: res?.msg || '获取素材详情失败', variant: 'destructive' });
}
})
.catch(error => {
toast({ title: '网络错误', description: error?.message || '请检查网络连接', variant: 'destructive' });
});
} else {
setIsEdit(false);
setContent('');
setComment('');
setSendTime('');
setContentType(1);
setImages([]);
setIsFirstLoad(true);
}
}, [materialId]);
const handleSave = async () => {
if (!content) {
toast({
title: '错误',
description: '请输入素材内容',
variant: 'destructive',
});
return;
}
setIsSubmitting(true);
try {
let res;
if (isEdit) {
// 编辑模式,调用新接口,所有字段取表单值
const payload = {
id: materialId,
contentType,
content,
comment,
sendTime,
resUrls: images,
};
res = await post('/v1/content/library/update-item', payload);
} else {
// 新建模式,所有字段取表单值
const payload = {
libraryId: id,
type: contentType,
content,
comment,
sendTime,
resUrls: images,
};
res = await post('/v1/content/library/create-item', payload);
}
if (res && res.code === 200) {
toast({ title: '成功', description: isEdit ? '素材已更新' : '新素材已创建' });
navigate(-1);
} else {
toast({ title: isEdit ? '保存失败' : '创建失败', description: res?.msg || (isEdit ? '保存素材失败' : '创建新素材失败'), variant: 'destructive' });
}
} catch (error: any) {
toast({ title: '网络错误', description: error?.message || '请检查网络连接', variant: 'destructive' });
} finally {
setIsSubmitting(false);
}
};
// 移除未用的 handleUploadImage 及 uploadImage 相关代码
return (
<Layout
header={<UnifiedHeader title={isEdit ? '编辑素材' : '新建素材'} showBack onBack={() => navigate(-1)} />}
footer={
<div className='m-2'>
{/* 2. 按钮onClick绑定handleSave */}
<Button theme="primary" block onClick={handleSave} disabled={isSubmitting}>
{isSubmitting ? (isEdit ? '保存中...' : '创建中...') : (isEdit ? '保存修改' : '保存素材')}
</Button>
</div>
}
>
<div className="flex-1 bg-gray-50 min-h-screen">
<div className="p-4 max-w-lg mx-auto">
<Card className="p-8 rounded-3xl shadow-xl bg-white">
<form className="space-y-8">
{/* 基础信息分组 */}
<div className="mb-6">
<div className="text-xs text-gray-400 mb-2 tracking-widest"></div>
<Label className="font-bold flex items-center mb-2"></Label>
<Input
type="datetime-local"
value={sendTime}
onChange={e => setSendTime(e.target.value)}
className="w-full h-12 rounded-2xl border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 px-4 text-base placeholder:text-gray-300"
placeholder="请选择发布时间"
/>
<Label className="font-bold flex items-center mb-2 mt-4"><span className="text-red-500 mr-1">*</span></Label>
<select
value={contentType}
onChange={e => setContentType(Number(e.target.value))}
className="w-full h-12 border border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 px-4 text-base bg-white appearance-none"
>
<option value="" disabled></option>
<option value={1}></option>
<option value={2}></option>
<option value={3}></option>
<option value={4}></option>
<option value={5}></option>
</select>
</div>
{/* 内容信息分组 */}
<div className="mb-6">
<div className="text-xs text-gray-400 mb-2 tracking-widest"></div>
<Label htmlFor="content" className="font-bold flex items-center mb-2"><span className="text-red-500 mr-1">*</span></Label>
<Textarea
value={content}
onChange={e => setContent(e.target.value)}
placeholder="请输入内容"
className="w-full rounded-2xl border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 px-4 text-base min-h-[120px] bg-gray-50 placeholder:text-gray-300"
rows={8}
/>
{(contentType === 2 || contentType === 6) && (
<>
<Label htmlFor="desc" className="font-bold flex items-center mb-2"><span className="text-red-500 mr-1">*</span></Label>
<Input
id="desc"
value={desc}
onChange={e => setDesc(e.target.value)}
placeholder="请输入描述"
className="w-full h-12 rounded-2xl border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 px-4 text-base placeholder:text-gray-300"
/>
<Label className="font-bold mb-2 mt-4"></Label>
<div className="flex items-center gap-4">
<UploadImage
value={images}
onChange={urls => {
setCoverImage(urls[0]);
}}
max={1}
accept="image/*"
/>
</div>
<Label htmlFor="url" className="font-bold flex items-center mb-2 mt-4"><span className="text-red-500 mr-1">*</span></Label>
<Input
id="url"
value={url}
onChange={e => setUrl(e.target.value)}
placeholder="请输入链接地址"
className="w-full h-12 rounded-2xl border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 px-4 text-base placeholder:text-gray-300"
/>
</>
)}
{contentType === 3 && (
<>
<Label className="font-bold mb-2"></Label>
<div className="pt-4">
<UploadVideo
value={videoUrl}
onChange={setVideoUrl}
/>
</div>
</>
)}
</div>
{/* 素材上传分组(仅图片类型和小程序类型) */}
{([1,5].includes(contentType)) && (
<div className="mb-6">
<div className="text-xs text-gray-400 mb-2 tracking-widest">9</div>
{contentType === 1 && (
<div className="mb-6">
<UploadImage
value={images}
onChange={urls => {
setImages(urls);
}}
max={9}
accept="image/*"
/>
</div>
)}
{contentType === 5 && (
<div className="space-y-6">
<Label htmlFor="appTitle" className="font-bold mb-2"></Label>
<Input id="appTitle" placeholder="请输入小程序名称" className="w-full h-12 rounded-2xl border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 px-4 text-base placeholder:text-gray-300" />
<Label htmlFor="appId" className="font-bold mb-2">AppID</Label>
<Input id="appId" placeholder="请输入AppID" className="w-full h-12 rounded-2xl border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 px-4 text-base placeholder:text-gray-300" />
<Label className="font-bold mb-2"></Label>
<UploadImage
value={images}
onChange={urls => {
setImages(urls);
}}
max={9}
accept="image/*"
/>
</div>
)}
</div>
)}
{/* 评论/备注分组 */}
<div className="mb-6">
<div className="text-xs text-gray-400 mb-2 tracking-widest">/</div>
<Textarea
value={comment}
onChange={e => setComment(e.target.value)}
placeholder="请输入评论或备注"
className="w-full rounded-2xl border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 px-4 text-base min-h-[80px] bg-gray-50 placeholder:text-gray-300"
rows={4}
/>
</div>
</form>
</Card>
</div>
</div>
</Layout>
);
}