feat: 本次提交更新内容如下
编辑素材构建完成
This commit is contained in:
18
nkebao/src/api/upload.ts
Normal file
18
nkebao/src/api/upload.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { request } from './request';
|
||||
import type { AxiosResponse } from 'axios';
|
||||
|
||||
// 上传图片,返回图片地址
|
||||
export async function uploadImage(file: File): Promise<string> {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
const response: AxiosResponse<any> = await request.post('/v1/attachment/upload', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
});
|
||||
const res = response.data || response;
|
||||
if (res?.url) {
|
||||
return res.url;
|
||||
}
|
||||
throw new Error(res?.msg || '图片上传失败');
|
||||
}
|
||||
56
nkebao/src/components/UploadImage.tsx
Normal file
56
nkebao/src/components/UploadImage.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Upload } from 'tdesign-mobile-react';
|
||||
import type { UploadFile as TDesignUploadFile } from 'tdesign-mobile-react/es/upload/type';
|
||||
import { uploadImage } from '@/api/upload';
|
||||
|
||||
interface UploadImageProps {
|
||||
value?: string[];
|
||||
onChange?: (urls: string[]) => void;
|
||||
max?: number;
|
||||
accept?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const UploadImage: React.FC<UploadImageProps> = ({ value = [], onChange, ...props }) => {
|
||||
|
||||
// 处理上传
|
||||
const requestMethod = async (file: TDesignUploadFile) => {
|
||||
try {
|
||||
const url = await uploadImage(file.raw as File);
|
||||
return {
|
||||
status: 'success' as const,
|
||||
response: {
|
||||
url
|
||||
},
|
||||
};
|
||||
} catch (e: any) {
|
||||
return {
|
||||
status: 'fail' as const,
|
||||
error: e.message || '上传失败',
|
||||
response: {},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// 处理文件变更
|
||||
const handleChange = (newFiles: TDesignUploadFile[]) => {
|
||||
console.log(newFiles);
|
||||
|
||||
const urls = newFiles.map(f => f.url).filter((url): url is string => Boolean(url));
|
||||
onChange?.(urls);
|
||||
};
|
||||
|
||||
return (
|
||||
<Upload
|
||||
requestMethod={requestMethod}
|
||||
onChange={handleChange}
|
||||
multiple
|
||||
accept={props.accept}
|
||||
max={props.max}
|
||||
disabled={props.disabled}
|
||||
// 不传 files,Upload 组件自己管理
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default UploadImage;
|
||||
@@ -11,7 +11,9 @@ import UnifiedHeader from '@/components/UnifiedHeader';
|
||||
import { get, post } from '@/api/request';
|
||||
import { UploadCloud } from 'lucide-react';
|
||||
import { Upload } from 'tdesign-mobile-react';
|
||||
import type { UploadFile } from 'tdesign-mobile-react/es/upload/type';
|
||||
import type { UploadFile as TDesignUploadFile } from 'tdesign-mobile-react/es/upload/type';
|
||||
import { uploadImage } from '@/api/upload';
|
||||
import UploadImage from '@/components/UploadImage';
|
||||
|
||||
export default function NewMaterial() {
|
||||
const navigate = useNavigate();
|
||||
@@ -28,6 +30,8 @@ export default function NewMaterial() {
|
||||
const [sendTime, setSendTime] = useState('');
|
||||
const [images, setImages] = useState<string[]>([]);
|
||||
const [isFirstLoad, setIsFirstLoad] = useState(true);
|
||||
// 优化图片上传逻辑,确保每次选择图片后立即上传并回显
|
||||
const [uploadFiles, setUploadFiles] = useState<TDesignUploadFile[]>([]);
|
||||
|
||||
// 判断模式并拉取详情
|
||||
useEffect(() => {
|
||||
@@ -116,16 +120,14 @@ export default function NewMaterial() {
|
||||
}
|
||||
};
|
||||
|
||||
// 上传图片模拟
|
||||
const handleUploadImage = () => {
|
||||
// 这里应对接真实上传逻辑
|
||||
const mock = [
|
||||
'https://picsum.photos/id/237/200/300',
|
||||
'https://picsum.photos/id/238/200/300',
|
||||
'https://picsum.photos/id/239/200/300',
|
||||
];
|
||||
const random = mock[Math.floor(Math.random() * mock.length)];
|
||||
if (!images.includes(random)) setImages([...images, random]);
|
||||
// 上传图片,接入接口
|
||||
const handleUploadImage = async (file: File) => {
|
||||
try {
|
||||
const url = await uploadImage(file);
|
||||
setImages(prev => [...prev, url]);
|
||||
} catch (e: any) {
|
||||
toast({ title: '上传失败', description: e.message || '图片上传失败', variant: 'destructive' });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -240,12 +242,15 @@ export default function NewMaterial() {
|
||||
<div className="text-xs text-gray-400 mb-2 tracking-widest">素材上传(最多上传9张)</div>
|
||||
{contentType === 1 && (
|
||||
<div className="mb-6">
|
||||
<Upload
|
||||
files={images.map(url => ({ url }))}
|
||||
onChange={(files: UploadFile[]) => setImages(files.map((f: any) => f.url))}
|
||||
multiple
|
||||
accept="image/*"
|
||||
<UploadImage
|
||||
value={images}
|
||||
onChange={urls => {
|
||||
setImages(urls);
|
||||
setUploadFiles(urls.map(url => ({ url })));
|
||||
}}
|
||||
max={9}
|
||||
accept="image/*"
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -257,7 +262,7 @@ export default function NewMaterial() {
|
||||
<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>
|
||||
<div className="border border-dashed border-gray-300 rounded-2xl p-4 text-center bg-gray-50">
|
||||
<Button type="button" variant="outline" onClick={handleUploadImage} className="w-full py-4 flex flex-col items-center justify-center rounded-2xl border-2 border-dashed border-blue-300 bg-white hover:bg-blue-50">
|
||||
<Button type="button" variant="outline" onClick={() => handleUploadImage(new File([], ''))} className="w-full py-4 flex flex-col items-center justify-center rounded-2xl border-2 border-dashed border-blue-300 bg-white hover:bg-blue-50">
|
||||
<UploadCloud className="h-6 w-6 mb-2 text-gray-400" />
|
||||
<span>上传小程序封面图</span>
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user