From 721feafa7d7656ab39a322c3678a6aa3b03d2d7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=AC=94=E8=AE=B0=E6=9C=AC=E9=87=8C=E7=9A=84=E6=B0=B8?= =?UTF-8?q?=E5=B9=B3?= Date: Tue, 15 Jul 2025 14:51:02 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9C=AC=E6=AC=A1=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=86=85=E5=AE=B9=E5=A6=82=E4=B8=8B=20?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E7=B4=A0=E6=9D=90=E6=9E=84=E5=BB=BA=E5=AE=8C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nkebao/src/api/upload.ts | 18 +++++++ nkebao/src/components/UploadImage.tsx | 56 ++++++++++++++++++++++ nkebao/src/pages/content/materials/New.tsx | 39 ++++++++------- 3 files changed, 96 insertions(+), 17 deletions(-) create mode 100644 nkebao/src/api/upload.ts create mode 100644 nkebao/src/components/UploadImage.tsx diff --git a/nkebao/src/api/upload.ts b/nkebao/src/api/upload.ts new file mode 100644 index 000000000..7fd2fcd50 --- /dev/null +++ b/nkebao/src/api/upload.ts @@ -0,0 +1,18 @@ +import { request } from './request'; +import type { AxiosResponse } from 'axios'; + +// 上传图片,返回图片地址 +export async function uploadImage(file: File): Promise { + const formData = new FormData(); + formData.append('file', file); + const response: AxiosResponse = 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 || '图片上传失败'); +} \ No newline at end of file diff --git a/nkebao/src/components/UploadImage.tsx b/nkebao/src/components/UploadImage.tsx new file mode 100644 index 000000000..726f3dfa6 --- /dev/null +++ b/nkebao/src/components/UploadImage.tsx @@ -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 = ({ 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 ( + + ); +}; + +export default UploadImage; \ No newline at end of file diff --git a/nkebao/src/pages/content/materials/New.tsx b/nkebao/src/pages/content/materials/New.tsx index a7011f204..43cbb938d 100644 --- a/nkebao/src/pages/content/materials/New.tsx +++ b/nkebao/src/pages/content/materials/New.tsx @@ -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([]); const [isFirstLoad, setIsFirstLoad] = useState(true); + // 优化图片上传逻辑,确保每次选择图片后立即上传并回显 + const [uploadFiles, setUploadFiles] = useState([]); // 判断模式并拉取详情 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() {
素材上传(最多上传9张)
{contentType === 1 && (
- ({ url }))} - onChange={(files: UploadFile[]) => setImages(files.map((f: any) => f.url))} - multiple - accept="image/*" + { + setImages(urls); + setUploadFiles(urls.map(url => ({ url }))); + }} max={9} + accept="image/*" + disabled={isSubmitting} />
)} @@ -257,7 +262,7 @@ export default function NewMaterial() {
-