| 1 | /* |
| 2 | * @Author: nevin |
| 3 | * @Date: 2025-01-22 21:59:36 |
| 4 | * @LastEditTime: 2025-02-11 21:45:34 |
| 5 | * @LastEditors: nevin |
| 6 | * @Description: 选择图片 |
| 7 | */ |
| 8 | import { Button, message } from 'antd'; |
| 9 | import { FC } from 'react'; |
| 10 | import { generateUUID, getFilePathName } from '@/utils'; |
| 11 | import { icpGetFileStream } from '@/icp/view'; |
| 12 | |
| 13 | interface ImgChooseProps { |
| 14 | // 单选就使用单选方法,多选就使用单选方法 |
| 15 | |
| 16 | // 单选返回 |
| 17 | onChoose?: (_: IImgFile) => void; |
| 18 | // 多选返回方法 |
| 19 | onMultipleChoose?: (_: IImgFile[]) => void; |
| 20 | children?: React.ReactNode; |
| 21 | } |
| 22 | |
| 23 | export interface IImgFile { |
| 24 | id: string; |
| 25 | size: number; |
| 26 | file: Blob; |
| 27 | // 前端临时路径,注意不要存到数据库 |
| 28 | imgUrl: string; |
| 29 | filename: string; |
| 30 | // 图片在硬盘上的路径 |
| 31 | imgPath: string; |
| 32 | // 图片宽度 |
| 33 | width: number; |
| 34 | // 图片高度 |
| 35 | height: number; |
| 36 | } |
| 37 | |
| 38 | // 根据图片在硬盘上的路径获取文件 |
| 39 | export const getImgFile = async (path: string): Promise<IImgFile> => { |
| 40 | const file = await icpGetFileStream(path); |
| 41 | return await formatImg({ path, file }); |
| 42 | }; |
| 43 | |
| 44 | /** |
| 45 | * 根据图片的Uint8Array和路径获取文件 |
| 46 | * @param path |
| 47 | * @param file |
| 48 | * @param blob |
| 49 | */ |
| 50 | export const formatImg = async ({ |
| 51 | path, |
| 52 | file, |
| 53 | blob, |
| 54 | }: { |
| 55 | path: string; |
| 56 | file?: Uint8Array; |
| 57 | blob?: Blob; |
| 58 | }): Promise<IImgFile> => { |
| 59 | return new Promise((resolve) => { |
| 60 | const { filename, suffix } = getFilePathName(path); |
| 61 | if (!blob) { |
| 62 | blob = new Blob([file!], { |
| 63 | type: `image/${suffix}`, |
| 64 | }); |
| 65 | } |
| 66 | const imgUrl = URL.createObjectURL(blob); |
| 67 | |
| 68 | const img = new Image(); |
| 69 | img.onload = () => { |
| 70 | resolve({ |
| 71 | id: generateUUID(), |
| 72 | width: img.width, |
| 73 | height: img.height, |
| 74 | imgPath: path, |
| 75 | size: blob!.size, |
| 76 | filename, |
| 77 | file: blob!, |
| 78 | imgUrl, |
| 79 | }); |
| 80 | }; |
| 81 | img.src = imgUrl; |
| 82 | }); |
| 83 | }; |
| 84 | |
| 85 | const ImgChoose: FC<ImgChooseProps> = ({ |
| 86 | onChoose, |
| 87 | onMultipleChoose, |
| 88 | children, |
| 89 | }) => { |
| 90 | /** |
| 91 | * 发送上传的事件 |
| 92 | */ |
| 93 | const handleUploadImg = async () => { |
| 94 | try { |
| 95 | const result: { |
| 96 | path: string; |
| 97 | file: Uint8Array; |
| 98 | }[] = await window.ipcRenderer.invoke( |
| 99 | 'ICP_VIEWS_CHOSE_IMG', |
| 100 | !!onMultipleChoose, |
| 101 | ); |
| 102 | if (!result) return; |
| 103 | const tasks: Promise<IImgFile>[] = []; |
| 104 | for (const v of result) { |
| 105 | tasks.push(formatImg(v)); |
| 106 | } |
| 107 | const imgFiles = await Promise.all(tasks); |
| 108 | |
| 109 | if (onMultipleChoose) { |
| 110 | onMultipleChoose(imgFiles); |
| 111 | } else if (onChoose) { |
| 112 | onChoose(imgFiles[0]); |
| 113 | } |
| 114 | } catch (error) { |
| 115 | message.error('选择图片失败'); |
| 116 | console.error(error); |
| 117 | } |
| 118 | }; |
| 119 | |
| 120 | return ( |
| 121 | <> |
| 122 | {children ? ( |
| 123 | <div |
| 124 | className="imgChoose" |
| 125 | onClick={handleUploadImg} |
| 126 | style={{ cursor: 'pointer' }} |
| 127 | > |
| 128 | {children} |
| 129 | </div> |
| 130 | ) : ( |
| 131 | <Button type="primary" onClick={handleUploadImg}> |
| 132 | 选择图片 |
| 133 | </Button> |
| 134 | )} |
| 135 | </> |
| 136 | ); |
| 137 | }; |
| 138 | |
| 139 | export default ImgChoose; |
| 140 |