diff --git a/src/base.css b/src/base.css index 9549a92..1d113a2 100644 --- a/src/base.css +++ b/src/base.css @@ -458,7 +458,9 @@ .gn_form .ant-form-item { margin-bottom: 16px; } -.gn_form .ant-select-outlined:not(.ant-select-disabled):not(.ant-select-customize-input):not(.ant-pagination-size-changer):hover .ant-select-selector, +.gn_form .ant-select-outlined:not(.ant-select-disabled):not(.ant-select-customize-input):not( + .ant-pagination-size-changer + ):hover .ant-select-selector, .gn_form .ant-picker-outlined:focus-within { border-color: #154ddd; } @@ -624,6 +626,13 @@ .gn_proFormUploadDragger_formItem .gn_uploadfile_title a { color: #154ddd; } +.gn_dragger_formItem .ant-upload-wrapper .ant-upload { + width: 100%; +} +.gn_dragger_formItem .ant-upload-wrapper .ant-upload-drag-icon { + height: 32px !important; + line-height: 32px !important; +} .ant-table-wrapper .ant-table-pagination.ant-pagination { margin: 0; padding: 24px 0 !important; diff --git a/src/base.less b/src/base.less index f3bf74f..95cefa4 100644 --- a/src/base.less +++ b/src/base.less @@ -742,7 +742,6 @@ } /* 表单控件 */ - .gn_proFormUploadDragger_formItem { &.ant-upload-wrapper { line-height: 1; @@ -759,6 +758,17 @@ } } } +.gn_dragger_formItem { + .ant-upload-wrapper { + .ant-upload { + width: 100%; + } + .ant-upload-drag-icon { + height: 32px !important; + line-height: 32px !important; + } + } +} // 分页器 .ant-table-wrapper .ant-table-pagination.ant-pagination { diff --git a/src/components/MenuBar/index.tsx b/src/components/MenuBar/index.tsx index 68f2468..9a3b046 100644 --- a/src/components/MenuBar/index.tsx +++ b/src/components/MenuBar/index.tsx @@ -2,7 +2,7 @@ * @Author: donghao donghao@supervision.ltd * @Date: 2024-03-27 16:03:20 * @LastEditors: donghao donghao@supervision.ltd - * @LastEditTime: 2024-05-30 14:53:21 + * @LastEditTime: 2024-07-16 10:51:55 * @FilePath: \general-ai-manage\src\components\Header\index.tsx * @Description: 内层layout菜单配置 */ @@ -32,18 +32,21 @@ const MenuBar: React.FC = ({ menuData, changeMenu }) => { // 根据路径查找对应的菜单项 const findMenuByPath = (menuData: any, pathname: any) => { - for (const item of menuData) { - if (item.path === pathname) { - return item; + if (menuData) { + for (const item of menuData) { + if (item.path === pathname) { + return item; + } + // 多级菜单使用递归调用 + // if (item.children) { + // const matchedChild: any = findMenuByPath(item.children, pathname); + // if (matchedChild) { + // return matchedChild; + // } + // } } - // 多级菜单使用递归调用 - // if (item.children) { - // const matchedChild: any = findMenuByPath(item.children, pathname); - // if (matchedChild) { - // return matchedChild; - // } - // } } + return null; }; diff --git a/src/components/UploadFile/index.ts b/src/components/UploadFile/index.ts index b2023ed..8d367e3 100644 --- a/src/components/UploadFile/index.ts +++ b/src/components/UploadFile/index.ts @@ -6,8 +6,10 @@ * @FilePath: \general-ai-platform-web\src\components\UploadFile\index.ts * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ +import draggerUpload from './src/draggerUpload'; import proFormUploadDraggerToken from './src/formUploadDraggerToken'; import uploadFileForView from './src/uploadFileForView'; +export const DraggerUpload = draggerUpload; export const FormUploadDraggerToken = proFormUploadDraggerToken; export const UploadFileForView = uploadFileForView; diff --git a/src/components/UploadFile/src/draggerUpload.tsx b/src/components/UploadFile/src/draggerUpload.tsx new file mode 100644 index 0000000..297ad50 --- /dev/null +++ b/src/components/UploadFile/src/draggerUpload.tsx @@ -0,0 +1,212 @@ +/* + * @Author: donghao donghao@supervision.ltd + * @Date: 2024-07-16 13:02:35 + * @LastEditors: donghao donghao@supervision.ltd + * @LastEditTime: 2024-07-16 17:10:10 + * @FilePath: \general-ai-platform-web\src\components\UploadFile\src\draggerUpload.tsx + * @Description: 拖拽上传 + * + * @交互说明 + * 1. 拖拽上传 + * 2. 文件格式、大小限制 + * 3. 上传、删除 + * 4. 进度显示、文件展示 + * 5. 多个文件上传(拓展) + * 待验证 + */ +import { apiFileDelete, apiFileUpload } from '@/services/business/file'; +import { useIntl } from '@umijs/max'; + +import { isSuccessApi } from '@/utils/forApi'; +import { ProFormItem } from '@ant-design/pro-components'; +import { message, Upload } from 'antd'; +import React, { useState } from 'react'; +import UploadFileForView from './uploadFileForView'; + +// export const fileType = [ +// // 压缩包 +// { type: 'ZIP', value: 'application/zip' }, +// { type: 'GZIP', value: 'application/gzip' }, +// { type: 'TAR', value: 'application/x-tar' }, +// { type: 'BZIP2', value: 'application/x-bzip2' }, +// { type: '7Z', value: 'application/x-7z-compressed' }, +// { type: 'RAR', value: 'application/vnd.rar' }, +// { type: 'XZ', value: 'application/x-xz' }, +// { type: 'LZMA', value: 'application/x-lzma' }, +// { type: 'ISO', value: 'application/x-iso9660-image' }, +// { type: 'CAB', value: 'application/vnd.ms-cab-compressed' }, +// { type: 'Z', value: 'application/x-compress' }, +// // JSON 或者 YAML +// { type: 'JSON', value: 'application/json' }, +// { type: 'YAML', value: 'application/x-yaml' }, +// { type: 'YML', value: 'application/x-yaml' }, +// ]; +// const { Dragger } = Upload; + +const DraggerUpload: React.FC = (props) => { + const intl = useIntl(); + + const [fileList, setFileList] = useState(props?.proFieldProps?.initialValue || []); + const [dragOver, setDragOver] = useState(false); + const [previewFile, setPreviewFile] = useState(null); + + const defualtOptions = { + accept: props?.proFieldProps?.accept || 'application/json, application/x-yaml', // 默认使用 JSON 或者 yaml 文件类型 + max: props?.proFieldProps?.max || 1, + size: props?.proFieldProps?.size || 1024 * 1024 * 200, + }; + // const defalutOptions: UploadProps = { + // name: 'file', + // multiple: true, + // action: 'https://660d2bd96ddfa2943b33731c.mockapi.io/api/upload', + // onChange(info) { + // const { status } = info.file; + // if (status !== 'uploading') { + // console.log(info.file, info.fileList); + // } + // if (status === 'done') { + // message.success(`${info.file.name} file uploaded successfully.`); + // } else if (status === 'error') { + // message.error(`${info.file.name} file upload failed.`); + // } + // }, + // onDrop(e) { + // console.log('Dropped files', e.dataTransfer.files); + // }, + // }; + + // 文件格式和大小校验 + const validateFile = (file: UploadFile) => { + const isValidType = defualtOptions.accept.split(',').includes(file.type); + const isLt2M = file.size < defualtOptions.size; + if (!isValidType) { + message.error('文件格式不对!'); + } + if (!isLt2M) { + // TODO 暂时写死200M + message.error('文件大小不得超过200M'); + } + + return isValidType && isLt2M; + }; + + const handleDragOver = (e: React.DragEvent) => { + e.preventDefault(); + setDragOver(true); + }; + + const handleDragLeave = () => { + setDragOver(false); + }; + const handleDrop = (e: React.DragEvent) => { + e.preventDefault(); + setDragOver(false); + + const files = Array.from(e.dataTransfer.files); + files.forEach((file) => { + const isValid = validateFile(file); + if (isValid && fileList.length < defualtOptions.max) { + setFileList([...fileList, file]); + } + }); + }; + + const handleBeforeUpload = async (file: UploadFile) => { + const isValid = validateFile(file); + if (isValid) { + const formData = new FormData(); + formData.append('file', file); + const resp = await apiFileUpload(formData); + if (isSuccessApi(resp)) { + setFileList([ + { + uid: file?.uid, + name: file?.name, + status: 'done', + url: '/file/' + resp?.data?.result, + fileId: resp?.data?.result, + }, + ]); + setPreviewFile(file); + props.afterUploadFile({ resp, file, fileList }); + } + console.log(resp, 'apiFileUpload_resp'); + } + return false; // Prevent auto-upload + }; + + const handleRemove = async (file: UploadFile>) => { + console.log(file, 'onRemoveFile_file', fileList); + const currFile = fileList.find((item) => item.uid === file.uid); + const resp = await apiFileDelete({ file_md5: currFile?.fileId || file?.uid }); + console.log(resp, 'apiFileDelete_resp'); + props.afterRemoveFile(resp, file); + setPreviewFile(null); + if (isSuccessApi(resp)) { + message.success(`${file.name} 删除成功`); + setFileList(fileList.filter((item) => item.uid !== file.uid)); + } else { + message.error( + resp?.meta?.message || + intl.formatMessage({ id: 'common.action.failure', defaultMessage: '$$$' }), + ); + } + }; + + const customRequest = async ({ file, onSuccess, onError }) => { + const formData = new FormData(); + formData.append('file', file); + try { + const response = await fetch('https://your-upload-api-endpoint.com/upload', { + method: 'POST', + body: formData, + }); + + if (response.ok) { + onSuccess('ok'); + message.success('File uploaded successfully'); + } else { + throw new Error('Upload failed'); + } + } catch (error) { + onError(error); + message.error('Upload failed'); + } + }; + + return ( + +
+ + {fileList.length < defualtOptions.max && ( + +
+ +
+
{props?.proFieldProps?.icon}
+

{props?.proFieldProps?.title}

+

{props?.proFieldProps?.description}

+
+
+
+
+ )} +
+
+ + {props?.openPreviewFile && } +
+ ); +}; + +export default DraggerUpload; diff --git a/src/layouts/HomeLayout.tsx b/src/layouts/HomeLayout.tsx index b411b5d..cceab78 100644 --- a/src/layouts/HomeLayout.tsx +++ b/src/layouts/HomeLayout.tsx @@ -2,7 +2,7 @@ * @Author: donghao donghao@supervision.ltd * @Date: 2024-04-07 15:25:23 * @LastEditors: donghao donghao@supervision.ltd - * @LastEditTime: 2024-06-28 09:57:42 + * @LastEditTime: 2024-07-16 10:52:28 * @FilePath: \general-ai-manage\src\layouts\HomeLayout.tsx * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ diff --git a/src/locales/en-US.ts b/src/locales/en-US.ts index faac784..383bef8 100644 --- a/src/locales/en-US.ts +++ b/src/locales/en-US.ts @@ -1,3 +1,12 @@ +/* + * @Author: donghao donghao@supervision.ltd + * @Date: 2024-04-19 14:07:32 + * @LastEditors: donghao donghao@supervision.ltd + * @LastEditTime: 2024-07-16 10:55:09 + * @FilePath: \general-ai-platform-web\src\locales\en-US.ts + * @Description: 国际化英文入口文件 + */ +import locale_en_US from 'antd/es/locale/en_US'; import component from './en-US/component'; import globalHeader from './en-US/globalHeader'; import menu from './en-US/menu'; @@ -5,7 +14,6 @@ import pages from './en-US/pages'; import pwa from './en-US/pwa'; import settingDrawer from './en-US/settingDrawer'; import settings from './en-US/settings'; - export default { 'navBar.lang': 'Languages', 'layout.user.link.help': 'Help', @@ -14,6 +22,7 @@ export default { 'app.preview.down.block': 'Download this pageNo to your local project', 'app.welcome.link.fetch-blocks': 'Get all block', 'app.welcome.link.block-list': 'Quickly build standard, pages based on `block` development', + ...locale_en_US, ...globalHeader, ...menu, ...settingDrawer, diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index d43809e..7f69f42 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -2,10 +2,11 @@ * @Author: donghao donghao@supervision.ltd * @Date: 2024-04-01 11:20:09 * @LastEditors: donghao donghao@supervision.ltd - * @LastEditTime: 2024-05-13 10:25:25 + * @LastEditTime: 2024-07-16 10:51:00 * @FilePath: \uighur-recognition-web2\src\locales\zh-CN.ts * @Description: 国际化中文入口文件 */ +import locale_zh_CN from 'antd/es/locale/zh_CN'; // ant design 基本语言库 import * as alarms from './zh-CN/alarm'; import * as businessProject from './zh-CN/businessProject'; import common from './zh-CN/common'; @@ -29,6 +30,7 @@ export default { 'app.preview.down.block': '下载此页面到本地项目', 'app.welcome.link.fetch-blocks': '获取全部区块', 'app.welcome.link.block-list': '基于 block 开发,快速构建标准页面', + ...locale_zh_CN, ...pages, ...globalHeader, ...menu, @@ -42,7 +44,6 @@ export default { ...Object.values(businessProject), ...Object.values(model), ...Object.values(server), - // 待启用 ...Object.values(systems), ...Object.values(alarms), diff --git a/src/locales/zh-CN/component.ts b/src/locales/zh-CN/component.ts index 1f1fead..4332578 100644 --- a/src/locales/zh-CN/component.ts +++ b/src/locales/zh-CN/component.ts @@ -1,5 +1,22 @@ +/* + * @Author: donghao donghao@supervision.ltd + * @Date: 2024-04-19 14:07:32 + * @LastEditors: donghao donghao@supervision.ltd + * @LastEditTime: 2024-07-16 10:20:29 + * @FilePath: \general-ai-platform-web\src\locales\zh-CN\component.ts + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ export default { 'component.tagSelect.expand': '展开', 'component.tagSelect.collapse': '收起', 'component.tagSelect.all': '全部', + + 'pagination.total': '总共 {total} 条数据', + 'pagination.items_per_page': '每页 {size} 条', + 'pagination.jump_to': '跳至', + 'pagination.page': '页', + 'pagination.prev_page': '上一页', + 'pagination.next_page': '下一页', + 'pagination.prev_5': '向前 5 页', + 'pagination.next_5': '向后 5 页', }; diff --git a/src/pages/Model/ModelDetail/components/createForm.tsx b/src/pages/Model/ModelDetail/components/createForm.tsx index 3e1de60..5987c61 100644 --- a/src/pages/Model/ModelDetail/components/createForm.tsx +++ b/src/pages/Model/ModelDetail/components/createForm.tsx @@ -1,4 +1,4 @@ -import { FormUploadDraggerToken } from '@/components/UploadFile'; +import { DraggerUpload } from '@/components/UploadFile'; import { apiModelVersionAdd } from '@/services/business/model'; import { isSuccessApi } from '@/utils/forApi'; import { @@ -51,11 +51,11 @@ const CreateForm: React.FC = (props) => { // test 测试数据 useEffect(() => { // 初始化赋值 - setCurrFormData({ - version: '1.0.91', // 设备分类的suid 59aa3d0c3162322e190942a9cc9add10 - comment: - '测试一下备注测试一下备注测试一下备注测试一下备注测试一下备注测试一下备注测试一下备注测试一下备注测试一下备注测试一下备注测试一下备注测试一下备注', - }); + // setCurrFormData({ + // version: '1.0.91', // 设备分类的suid 59aa3d0c3162322e190942a9cc9add10 + // comment: + // '测试一下备注测试一下备注测试一下备注测试一下备注测试一下备注测试一下备注测试一下备注测试一下备注测试一下备注测试一下备注测试一下备注测试一下备注', + // }); }, [props.createModalOpen]); return ( = (props) => { return true; }} > - @@ -249,6 +249,8 @@ const CreateForm: React.FC = (props) => { icon: , name: 'model_file_arr', max: 1, + // initialValue: [], + accept: 'application/zip, application/gzip, application/x-tar', }} afterUploadFile={({ resp }) => { setCurrFormData((data) => { @@ -289,7 +291,7 @@ const CreateForm: React.FC = (props) => { return true; }} > - @@ -307,6 +309,8 @@ const CreateForm: React.FC = (props) => { icon: , name: 'config_file_arr', max: 1, + // initialValue: [], + // accept: 'application/zip, application/gzip, application/x-tar', }} afterUploadFile={({ resp }) => { setCurrFormData((data) => { @@ -320,95 +324,6 @@ const CreateForm: React.FC = (props) => { }} openPreviewFile={true} /> - {/* 模型配置文件上传} - title={ -
- 拖拽文件到这里,或 - 点此添加 -
- } - description="" - icon={} - name="config_file_name" - action={fileApiActionUrl} - fieldProps={{ - className: 'gn_proFormUploadDragger_formItem', - onChange: handleConfigFileChange, - onRemove: () => { - let index_ids = actionFormListRef.current?.getList()?.map((v, i) => { - return i; - }); - actionFormListRef.current?.remove(index_ids || []); - }, - beforeUpload: (file) => { - if ( - !file.name.endsWith('.yaml') && - !file.name.endsWith('.yml') && - !file.name.endsWith('.json') - ) { - message.error('请上传yaml或json文件').then(() => {}); - return false; - } else { - let parsedData = {}; - file - .text() - .then((text) => { - if (file.name.endsWith('.yaml') || file.name.endsWith('.yml')) { - parsedData = yaml.load(text) as Record; - } - if (file.name.endsWith('.json')) { - parsedData = JSON.parse(text) as Record; - } - if (Object.keys(parsedData).length > 0) { - dataFormListRef.current = Object.entries(parsedData).map(([key, value]) => ({ - name: key, - default: value, - })); - - dataFormListRef.current.forEach((v: any, i: number) => { - actionFormListRef.current?.add(v, i); - }); - } - return true; - }) - .catch(() => { - return false; - }); - } - }, - }} - /> -
- 请上传格式为.json.yaml.yml的模型文件 -
*/} - {/* - 模型参数 -
- 暂未上传模型配置文件,可根据业务需求手动添加参数字段~ -
- - } - actionRef={actionFormListRef} - itemContainerRender={(doms) => { - return {doms}; - }} - alwaysShowItemLabel - > - {() => { - return ( - <> - - - - ); - }} -
*/} ); diff --git a/src/pages/Model/ModelDetail/components/updateForm.tsx b/src/pages/Model/ModelDetail/components/updateForm.tsx index 1cf78e7..8baf540 100644 --- a/src/pages/Model/ModelDetail/components/updateForm.tsx +++ b/src/pages/Model/ModelDetail/components/updateForm.tsx @@ -1,5 +1,5 @@ // TODO 上传文件限制为1时,还可以上传 -import { FormUploadDraggerToken } from '@/components/UploadFile'; +import { DraggerUpload } from '@/components/UploadFile'; import { apiModelVersionEdit } from '@/services/business/model'; import { isSuccessApi } from '@/utils/forApi'; import { @@ -245,7 +245,7 @@ const UpdateForm: React.FC = (props) => { return true; }} > - @@ -273,6 +273,7 @@ const UpdateForm: React.FC = (props) => { }, ] : [], + accept: 'application/zip, application/gzip, application/x-tar', }} afterUploadFile={({ resp, file }) => { console.log(resp, file, 'afterRemoveFile'); @@ -314,7 +315,7 @@ const UpdateForm: React.FC = (props) => { return true; }} > - @@ -355,99 +356,6 @@ const UpdateForm: React.FC = (props) => { }} openPreviewFile={true} /> - {/* 模型配置文件上传} - title={ -
- 拖拽文件到这里,或 - 点此添加 -
- } - description="" - icon={} - name="config_file_name" - action={fileApiActionUrl} - fieldProps={{ - className: 'gn_proFormUploadDragger_formItem', - onChange: handleConfigFileChange, - onRemove: () => { - let index_ids = actionFormListRef.current?.getList()?.map((v, i) => { - return i; - }); - actionFormListRef.current?.remove(index_ids || []); - }, - beforeUpload: (file) => { - if ( - !file.name.endsWith('.yaml') && - !file.name.endsWith('.yml') && - !file.name.endsWith('.json') - ) { - message.error('请上传yaml或json文件').then(() => {}); - return false; - } else { - let parsedData = {}; - file - .text() - .then((text) => { - if (file.name.endsWith('.yaml') || file.name.endsWith('.yml')) { - parsedData = yaml.load(text) as Record; - } - if (file.name.endsWith('.json')) { - parsedData = JSON.parse(text) as Record; - } - if (Object.keys(parsedData).length > 0) { - dataFormListRef.current = Object.entries(parsedData).map(([key, value]) => ({ - name: key, - default: value, - })); - - dataFormListRef.current.forEach((v: any, i: number) => { - actionFormListRef.current?.add(v, i); - }); - } - return true; - }) - .catch(() => { - return false; - }); - } - }, - }} - /> -
- 请上传格式为.json.yaml.yml的模型文件 -
*/} - - {/* - 模型参数 -
- 暂未上传模型配置文件,可根据业务需求手动添加参数字段~ -
- - } - initialValue={ - isValidJson(props.values?.config_str) ? JSON.parse(props.values?.config_str) : [] - } - actionRef={actionFormListRef} - itemContainerRender={(doms) => { - return {doms}; - }} - alwaysShowItemLabel - > - {() => { - return ( - <> - - - - ); - }} -
*/} );