From 56a00420114e9306d90f281d69ff2b8bfdd707eb Mon Sep 17 00:00:00 2001 From: jiangh277 Date: Fri, 25 Jul 2025 20:25:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=95=85=E4=BA=8Blogo?= =?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=8A=A0=E9=BB=98=E8=AE=A4logo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../basic-list/components/OperationModal.tsx | 246 +++++++++++++++++- src/pages/list/basic-list/data.d.ts | 1 + src/pages/list/basic-list/index.tsx | 66 ++--- src/pages/list/basic-list/service.ts | 46 ++-- src/pages/list/basic-list/style.style.ts | 14 + src/utils/commonConstant.ts | 24 +- 6 files changed, 324 insertions(+), 73 deletions(-) diff --git a/src/pages/list/basic-list/components/OperationModal.tsx b/src/pages/list/basic-list/components/OperationModal.tsx index 6f4b97b..6c8533a 100644 --- a/src/pages/list/basic-list/components/OperationModal.tsx +++ b/src/pages/list/basic-list/components/OperationModal.tsx @@ -5,10 +5,13 @@ import { ProFormText, ProFormTextArea, } from '@ant-design/pro-components'; -import { Button, Result } from 'antd'; -import React, { FC } from 'react'; -import type {StoryType} from '../data.d'; +import { Button, message, Result, Upload, Radio } from 'antd'; +import React, { FC, useState } from 'react'; +import ImgCrop from 'antd-img-crop'; +import type { StoryType } from '../data.d'; import useStyles from '../style.style'; +import { defaultIcons } from '@/utils/commonConstant'; + type OperationModalProps = { done: boolean; open: boolean; @@ -17,22 +20,106 @@ type OperationModalProps = { onSubmit: (values: StoryType) => void; children?: React.ReactNode; }; + const OperationModal: FC = (props) => { const { styles } = useStyles(); const { done, open, current, onDone, onSubmit, children } = props; + + // 图标状态管理 + const [iconType, setIconType] = useState<'default' | 'upload'>( + current?.logo ? 'upload' : 'default', + ); + const [selectedIcon, setSelectedIcon] = useState( + current?.logo || defaultIcons[0], + ); + const [iconPreview, setIconPreview] = useState( + current?.logo || null, + ); + const [fileList, setFileList] = useState([]); // 控制上传图像展示 + + // 图标上传逻辑 + const beforeUpload = (file: File) => { + const isValidType = file.type === 'image/png' || file.type === 'image/jpeg'; + + if (!isValidType) { + message.error('仅支持 PNG 或 JPEG 格式'); + return false; + } + + const reader = new FileReader(); + reader.onload = (e) => { + const img = new Image(); + img.onload = () => { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + + // 强制设置裁剪尺寸为 40x40 + canvas.width = 40; + canvas.height = 40; + ctx.drawImage(img, 0, 0, 40, 40); + + // 生成 Base64 图像 + const base64 = canvas.toDataURL('image/png'); + setSelectedIcon(base64); + setIconPreview(base64); + setFileList([ + { + uid: '-1', + name: 'icon.png', + status: 'done', + url: base64, + originFileObj: new File([dataURLtoBlob(base64)], 'icon.png', { + type: 'image/png', + }), + }, + ]); + }; + img.onerror = () => { + message.error('图像加载失败'); + }; + img.src = e.target?.result as string; + }; + reader.onerror = () => { + message.error('读取图像失败'); + }; + reader.readAsDataURL(file); + + return false; // 阻止自动上传 + }; + + // Base64 → Blob 转换工具函数 + const dataURLtoBlob = (dataurl: string) => { + const arr = dataurl.split(','); + const mime = arr[0].match(/:(.*?);/)[1]; + const bstr = atob(arr[1]); + let n = bstr.length; + const u8arr = new Uint8Array(n); + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + return new Blob([u8arr], { type: mime }); + }; + if (!open) { return null; } + return ( open={open} - title={done ? null : `任务${current ? '编辑' : '添加'}`} + title={done ? null : `故事${current ? '编辑' : '添加'}`} className={styles.standardListForm} width={640} onFinish={async (values) => { - onSubmit(values); + onSubmit({ + ...values, + logo: selectedIcon || '', + }); + }} + initialValues={{ + ...current, + logo: current?.logo ? 'upload' : 'default', }} - initialValues={current} submitter={{ render: (_, dom) => (done ? null : dom), }} @@ -42,8 +129,8 @@ const OperationModal: FC = (props) => { destroyOnClose: true, bodyStyle: done ? { - padding: '72px 0', - } + padding: '72px 0', + } : {}, }} > @@ -51,15 +138,145 @@ const OperationModal: FC = (props) => { <> + + {/* 图标选择方式 */} +