Files
gpustack-ui/src/pages/playground/components/upload-img.tsx
T
2025-12-01 19:01:33 +08:00

188 lines
4.7 KiB
TypeScript

import { PictureOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Button, Tooltip, Upload } from 'antd';
import type { UploadFile } from 'antd/es/upload';
import { RcFile } from 'antd/es/upload';
import { debounce, round } from 'lodash';
import React, { useCallback, useRef } from 'react';
const acceptImageType = ['image/png', 'image/jpg', 'image/jpeg'];
interface UploadImgProps {
size?: 'small' | 'middle' | 'large';
height?: number;
multiple?: boolean;
drag?: boolean;
disabled?: boolean;
children?: React.ReactNode;
accept?: string;
icon?: React.ReactNode;
title?: React.ReactNode;
handleUpdateImgList: (
imgList: {
dataUrl: string;
uid: number | string;
rawWidth: number;
rawHeight: number;
}[]
) => void;
}
const UploadImg: React.FC<UploadImgProps> = ({
handleUpdateImgList,
multiple = true,
drag = false,
disabled = false,
children,
icon,
title,
accept = acceptImageType.join(','),
size = 'small'
}) => {
const intl = useIntl();
const uploadRef = useRef<any>(null);
const getImgSize = useCallback(
(url: string): Promise<{ rawWidth: number; rawHeight: number }> => {
return new Promise((resolve) => {
const img = new Image();
img.onload = () => {
resolve({
rawWidth: round(img.width, 0),
rawHeight: round(img.height, 0)
});
};
img.onerror = () => {
resolve({ rawWidth: 0, rawHeight: 0 });
};
img.src = url;
});
},
[]
);
const getBase64 = useCallback((file: RcFile): Promise<string> => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result as string);
reader.onerror = (error) => reject(error);
});
}, []);
const debouncedUpdate = useCallback(
debounce(
(
base64List: {
dataUrl: string;
uid: number | string;
rawWidth: number;
rawHeight: number;
}[]
) => {
handleUpdateImgList(base64List);
},
300
),
[handleUpdateImgList, intl]
);
const handleChange = useCallback(
async (info: any) => {
const { fileList } = info;
const newFileList = await Promise.all(
fileList.map(
async (
item: UploadFile & { rawWidth: number; rawHeight: number }
) => {
if (item.originFileObj && !item.url) {
const base64 = await getBase64(item.originFileObj as RcFile);
const { rawWidth, rawHeight } = await getImgSize(base64);
item.url = base64;
item.rawWidth = rawWidth;
item.rawHeight = rawHeight;
}
return item;
}
)
);
if (newFileList.length > 0) {
const base64List = newFileList
.filter((sitem) => sitem.url)
.map((item: UploadFile & { rawHeight: number; rawWidth: number }) => {
return {
dataUrl: item.url as string,
uid: item.uid,
rawWidth: item.rawWidth,
rawHeight: item.rawHeight
};
});
debouncedUpdate(base64List);
}
},
[debouncedUpdate, getBase64]
);
return (
<>
{drag ? (
<Upload.Dragger
ref={uploadRef}
accept={accept}
multiple={multiple}
action="/"
fileList={[]}
beforeUpload={(file) => false}
onChange={handleChange}
>
{children ?? (
<Tooltip
title={
title ?? intl.formatMessage({ id: 'playground.img.upload' })
}
>
<Button
disabled={disabled}
size={size}
type="text"
icon={icon ?? <PictureOutlined />}
></Button>
</Tooltip>
)}
</Upload.Dragger>
) : (
<Upload
ref={uploadRef}
accept={accept}
multiple={multiple}
action="/"
fileList={[]}
beforeUpload={(file) => false}
onChange={handleChange}
>
{children ?? (
<Tooltip
title={
title ?? intl.formatMessage({ id: 'playground.img.upload' })
}
>
<Button
disabled={disabled}
size={size}
type="text"
icon={icon ?? <PictureOutlined />}
></Button>
</Tooltip>
)}
</Upload>
)}
</>
);
};
export default UploadImg;