diff --git a/react-ui/config/defaultSettings.ts b/react-ui/config/defaultSettings.ts index 7c1cfbd5..65b0fcf5 100644 --- a/react-ui/config/defaultSettings.ts +++ b/react-ui/config/defaultSettings.ts @@ -19,7 +19,7 @@ const Settings: ProLayoutProps & { title: '智能软件开发平台', pwa: true, logo: '/assets/images/left-top-logo.png', - iconfontUrl: '//at.alicdn.com/t/c/font_4511326_1cmi0j3dj1x.js', + iconfontUrl: '//at.alicdn.com/t/c/font_4511326_a182r7rksx5.js', token: { // 参见ts声明,demo 见文档,通过token 修改样式 //https://procomponents.ant.design/components/layout#%E9%80%9A%E8%BF%87-token-%E4%BF%AE%E6%94%B9%E6%A0%B7%E5%BC%8F diff --git a/react-ui/src/app.tsx b/react-ui/src/app.tsx index a4642589..66005f50 100644 --- a/react-ui/src/app.tsx +++ b/react-ui/src/app.tsx @@ -17,9 +17,10 @@ import { patchRouteWithRemoteMenus, setRemoteMenu, } from './services/session'; +import './styles/menu.less'; export { requestConfig as request } from './requestConfig'; // const isDev = process.env.NODE_ENV === 'development'; - +import { menuItemRender } from '@/utils/menuRender'; /** * @see https://umijs.org/zh-CN/plugins/plugin-initial-state * */ @@ -139,10 +140,8 @@ export const layout: RuntimeConfig['layout'] = ({ initialState }) => { onClick: () => { // 点击菜单项,删除所有的页面 state 缓存 removeAllPageCacheState(); + // console.log('click menu'); }, - // onSelect: (e) => { - // console.log(e); - // }, }, ...initialState?.settings, token: { @@ -150,51 +149,36 @@ export const layout: RuntimeConfig['layout'] = ({ initialState }) => { colorTextMenu: themes['textColor'], colorTextMenuSelected: themes['primaryColor'], colorTextMenuActive: themes['primaryColor'], + colorTextMenuItemHover: themes['primaryColor'], colorBgMenuItemSelected: 'rgba(197, 232, 255, 0.8)', colorMenuBackground: themes['siderBGColor'], }, }, - // menuItemRender: (itemProps, defaultDom, props) => { - // console.log('menuItemProps', itemProps); - // console.log('defaultDom', defaultDom); - // console.log('props', props); - - // const { pathname } = window.location; - // const isSelected = pathname === itemProps.path; - - // // 根据菜单项的状态动态显示不同的 icon - // const icon = isSelected ? 'icon-developmentEnvironment-icon' : 'icon-kaifahuanjing'; - // return ( - // - // - // {itemProps.name} - // - // ); - // }, + menuItemRender: menuItemRender(false), + subMenuItemRender: menuItemRender(true), }; }; export const onRouteChange: RuntimeConfig['onRouteChange'] = async (e) => { const { location } = e; const menus = getRemoteMenu(); - console.log('onRouteChange', e); + // console.log('onRouteChange', e); if (menus === null && location.pathname !== PageEnum.LOGIN) { - console.log('refresh'); history.go(0); } }; export const patchRoutes: RuntimeConfig['patchRoutes'] = (e) => { - console.log('patchRoutes', e); + //console.log('patchRoutes', e); }; export const patchClientRoutes: RuntimeConfig['patchClientRoutes'] = (e) => { - console.log('patchClientRoutes', e); + //console.log('patchClientRoutes', e); patchRouteWithRemoteMenus(e.routes); }; export function render(oldRender: () => void) { - console.log('render'); + //console.log('render'); const token = getAccessToken(); if (!token || token?.length === 0) { oldRender(); @@ -215,6 +199,7 @@ export const antd: RuntimeAntdConfig = (memo) => { colorError: themes['errorColor'], colorWarning: themes['warningColor'], colorLink: themes['primaryColor'], + colorText: themes['textColor'], }; memo.theme.components ??= {}; memo.theme.components.Tabs = {}; @@ -229,10 +214,11 @@ export const antd: RuntimeAntdConfig = (memo) => { defaultActiveBorderColor: 'rgba(22, 100, 255, 0.75)', defaultActiveColor: themes['primaryColor'], contentFontSize: parseInt(themes['fontSize']), - controlHeight: 34, }; memo.theme.components.Input = { - inputFontSize: parseInt(themes['fontSize']), + inputFontSize: parseInt(themes['fontSizeInput']), + inputFontSizeLG: parseInt(themes['fontSizeInputLg']), + paddingBlockLG: 10, }; memo.theme.components.Table = { headerBg: 'rgba(242, 244, 247, 0.36)', @@ -241,6 +227,11 @@ export const antd: RuntimeAntdConfig = (memo) => { memo.theme.components.Tabs = { titleFontSize: 16, }; + + memo.theme.components.Form = { + labelColor: 'rgba(29, 29, 32, 0.8);', + }; + memo.theme.cssVar = true; // memo.theme.hashed = false; diff --git a/react-ui/src/components/KFModal/index.less b/react-ui/src/components/KFModal/index.less index 57153a58..5e1f1239 100644 --- a/react-ui/src/components/KFModal/index.less +++ b/react-ui/src/components/KFModal/index.less @@ -23,8 +23,6 @@ border-radius: 10px; } .ant-btn-default { - color: @text-color; - background: rgba(22, 100, 255, 0.06); border-color: transparent; } .ant-btn + .ant-btn { diff --git a/react-ui/src/components/KFRadio/index.less b/react-ui/src/components/KFRadio/index.less index aff74e90..455492a4 100644 --- a/react-ui/src/components/KFRadio/index.less +++ b/react-ui/src/components/KFRadio/index.less @@ -23,6 +23,11 @@ &--active { color: @primary-color; border: 1px solid @primary-color; + + &:hover { + color: @primary-color; + border: 1px solid @primary-color; + } } & + & { diff --git a/react-ui/src/components/PageTitle/index.less b/react-ui/src/components/PageTitle/index.less index 80d18169..8ab36193 100644 --- a/react-ui/src/components/PageTitle/index.less +++ b/react-ui/src/components/PageTitle/index.less @@ -3,5 +3,5 @@ align-items: center; height: 50px; padding-left: 30px; - background-image: url('../../assets/img/page-title-bg.png'); + background-image: url(@/assets/img/page-title-bg.png); } diff --git a/react-ui/src/hooks/index.ts b/react-ui/src/hooks/index.ts index 1d56a24d..4dccabb7 100644 --- a/react-ui/src/hooks/index.ts +++ b/react-ui/src/hooks/index.ts @@ -126,3 +126,13 @@ export const useResetFormOnCloseModal = (form: FormInstance, open: boolean) => { } }, [form, prevOpen, open]); }; + +export const useInputModel = (initialValue: T) => { + const [value, setValue] = useState(initialValue); + + const updateValue = useCallback((e: any) => { + setValue(e.target?.value); + }, []); + + return [value, updateValue]; +}; diff --git a/react-ui/src/iconfont/iconfont.js b/react-ui/src/iconfont/iconfont.js index 77f8486f..80008ba1 100644 --- a/react-ui/src/iconfont/iconfont.js +++ b/react-ui/src/iconfont/iconfont.js @@ -1 +1 @@ -window._iconfont_svg_string_4511447='',function(t){var a=(a=document.getElementsByTagName("script"))[a.length-1],h=a.getAttribute("data-injectcss"),a=a.getAttribute("data-disable-injectsvg");if(!a){var l,i,v,o,z,m=function(a,h){h.parentNode.insertBefore(a,h)};if(h&&!t.__iconfont__svg__cssinject__){t.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}l=function(){var a,h=document.createElement("div");h.innerHTML=t._iconfont_svg_string_4511447,(h=h.getElementsByTagName("svg")[0])&&(h.setAttribute("aria-hidden","true"),h.style.position="absolute",h.style.width=0,h.style.height=0,h.style.overflow="hidden",h=h,(a=document.body).firstChild?m(h,a.firstChild):a.appendChild(h))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(l,0):(i=function(){document.removeEventListener("DOMContentLoaded",i,!1),l()},document.addEventListener("DOMContentLoaded",i,!1)):document.attachEvent&&(v=l,o=t.document,z=!1,p(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,n())})}function n(){z||(z=!0,v())}function p(){try{o.documentElement.doScroll("left")}catch(a){return void setTimeout(p,50)}n()}}(window); \ No newline at end of file +window._iconfont_svg_string_4511447='',function(t){var a=(a=document.getElementsByTagName("script"))[a.length-1],h=a.getAttribute("data-injectcss"),a=a.getAttribute("data-disable-injectsvg");if(!a){var v,l,i,z,o,m=function(a,h){h.parentNode.insertBefore(a,h)};if(h&&!t.__iconfont__svg__cssinject__){t.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}v=function(){var a,h=document.createElement("div");h.innerHTML=t._iconfont_svg_string_4511447,(h=h.getElementsByTagName("svg")[0])&&(h.setAttribute("aria-hidden","true"),h.style.position="absolute",h.style.width=0,h.style.height=0,h.style.overflow="hidden",h=h,(a=document.body).firstChild?m(h,a.firstChild):a.appendChild(h))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(v,0):(l=function(){document.removeEventListener("DOMContentLoaded",l,!1),v()},document.addEventListener("DOMContentLoaded",l,!1)):document.attachEvent&&(i=v,z=t.document,o=!1,n(),z.onreadystatechange=function(){"complete"==z.readyState&&(z.onreadystatechange=null,p())})}function p(){o||(o=!0,i())}function n(){try{z.documentElement.doScroll("left")}catch(a){return void setTimeout(n,50)}p()}}(window); \ No newline at end of file diff --git a/react-ui/src/overrides.less b/react-ui/src/overrides.less index e962088a..61102f12 100644 --- a/react-ui/src/overrides.less +++ b/react-ui/src/overrides.less @@ -57,11 +57,6 @@ overflow-y: auto; } -// Input -.ant-input-textarea-affix-wrapper.ant-input-affix-wrapper { - padding: 0; -} - // Modal .ant-modal { .ant-modal-close { @@ -81,18 +76,24 @@ } } + .ant-form-item .ant-form-item-label > label { + font-size: @font-size; + } + + // 输入框高度为46px .ant-input-affix-wrapper { - height: 46px; - padding: 1px 11px; + padding-top: 2px; + padding-bottom: 2px; + + .ant-input { + height: 40px; + } } + // 选择框高度为46px .ant-select-single { height: 46px; } - - .ant-select-single .ant-select-selector .ant-select-selection-placeholder { - line-height: 46px; - } } // Confirm Modal @@ -128,8 +129,6 @@ border-radius: 10px; } .ant-btn-default { - color: @text-color; - background: rgba(22, 100, 255, 0.06); border-color: transparent; } .ant-btn + .ant-btn { @@ -137,3 +136,20 @@ } } } + +// 表单类型为large时,font-size为15px +.ant-form-large { + .ant-form-item-label { + label { + font-size: @font-size; + } + } +} + +// 取消 hover 颜色变化 +.ant-menu .ant-menu-title-content { + transition: color 0s; + a { + transition: color 0s; + } +} diff --git a/react-ui/src/pages/Dataset/components/AddDatasetModal/index.less b/react-ui/src/pages/Dataset/components/AddDatasetModal/index.less new file mode 100644 index 00000000..529521af --- /dev/null +++ b/react-ui/src/pages/Dataset/components/AddDatasetModal/index.less @@ -0,0 +1,9 @@ +.upload-tip { + margin-top: 5px; + color: @error-color; +} + +.upload-button { + height: 48px; + font-size: 15px; +} diff --git a/react-ui/src/pages/Dataset/components/AddDatasetModal/index.tsx b/react-ui/src/pages/Dataset/components/AddDatasetModal/index.tsx new file mode 100644 index 00000000..c83d5143 --- /dev/null +++ b/react-ui/src/pages/Dataset/components/AddDatasetModal/index.tsx @@ -0,0 +1,202 @@ +import { getAccessToken } from '@/access'; +import { DictValueEnumObj } from '@/components/DictTag'; +import KFIcon from '@/components/KFIcon'; +import KFModal from '@/components/KFModal'; +import { addDatesetAndVesion } from '@/services/dataset/index.js'; +import { getDictSelectOption } from '@/services/system/dict'; +import { to } from '@/utils/promise'; +import { getFileListFromEvent, validateUploadFiles } from '@/utils/ui'; +import { + Button, + Form, + Input, + Radio, + Select, + Upload, + UploadFile, + message, + type ModalProps, + type UploadProps, +} from 'antd'; +import { omit } from 'lodash'; +import { useEffect, useState } from 'react'; +import { CategoryData } from '../../type'; +import styles from './index.less'; + +interface AddDatasetModalProps extends ModalProps { + typeList: CategoryData[]; + tagList: CategoryData[]; + onOk: () => void; +} + +function AddDatasetModal({ typeList, tagList, onOk, ...rest }: AddDatasetModalProps) { + const [uuid] = useState(Date.now()); + const [clusterOptions, setClusterOptions] = useState([]); + + useEffect(() => { + getClusterOptions(); + }, []); + + // 上传组件参数 + const uploadProps: UploadProps = { + action: '/api/mmp/dataset/upload', + headers: { + Authorization: getAccessToken() || '', + }, + defaultFileList: [], + }; + + // 获取集群版本数据 + const getClusterOptions = async () => { + const [res] = await to(getDictSelectOption('available_cluster')); + if (res) { + setClusterOptions(res); + } + }; + + // 上传请求 + const createDataset = async (params: any) => { + const [res] = await to(addDatesetAndVesion(params)); + if (res) { + message.success('创建成功'); + onOk?.(); + } + }; + + // 提交 + const onFinish = (formData: any) => { + const fileList: UploadFile[] = formData['fileList'] ?? []; + if (validateUploadFiles(fileList)) { + const params = { + ...omit(formData, ['fileList']), + dataset_version_vos: fileList.map((item) => { + const data = item.response?.data?.[0] ?? {}; + return { + file_name: data.fileName, + file_size: data.fileSize, + url: data.url, + }; + }), + }; + createDataset(params); + } + }; + + return ( + +
+ + + + + + + + + + + - - - - - - { - return { value: item.id, label: item.name }; - })} - /> - - - - - - - 仅自己可见 - 工作空间可见 - - - - - -
只允许上传.zip,.tgz格式文件
-
-
-
- - - ); -}); -export default PublicData; diff --git a/react-ui/src/pages/Dataset/publicData.jsx b/react-ui/src/pages/Dataset/publicData.jsx deleted file mode 100644 index bf5980d4..00000000 --- a/react-ui/src/pages/Dataset/publicData.jsx +++ /dev/null @@ -1,284 +0,0 @@ -import clock from '@/assets/img/clock.png'; -import creatByImg from '@/assets/img/creatBy.png'; -import deleteIcon from '@/assets/img/delete-icon.png'; -import { deleteDataset, getAssetIcon, getDatasetList } from '@/services/dataset/index.js'; -import { modalConfirm } from '@/utils/ui'; -import { Form, Input, Pagination } from 'antd'; -import moment from 'moment'; -import { useEffect, useState } from 'react'; -import { useNavigate } from 'react-router-dom'; -import Styles from './index.less'; -const { Search } = Input; -const leftdataList = [1, 2, 3]; - -const PublicData = () => { - const [queryFlow, setQueryFlow] = useState({ - page: 0, - size: 10, - name: null, - available_range: 1, - }); - const [iconParams, setIconParams] = useState({ - name: null, - page: 0, - size: 10000, - }); - const navgite = useNavigate(); - const [datasetTypeList, setDatasetTypeList] = useState([]); - const [datasetDirectionList, setDatasetDirectionList] = useState([]); - const [activeType, setActiveType] = useState(null); - const [activeTag, setActiveTag] = useState(null); - const [isModalOpen, setIsModalOpen] = useState(false); - const [datasetList, setDatasetList] = useState([]); - const [total, setTotal] = useState(0); - const [form] = Form.useForm(); - const [dialogTitle, setDialogTitle] = useState('新建数据'); - const getDatasetlist = (queryFlow) => { - getDatasetList(queryFlow).then((ret) => { - console.log(ret); - if (ret.code == 200) { - setDatasetList(ret.data.content); - setTotal(ret.data.totalElements); - } - }); - }; - const onSearch = (values) => { - console.log(values); - getAssetIconList({ ...iconParams, name: values }); - }; - const getAssetIconList = (params) => { - getAssetIcon(params).then((ret) => { - console.log(ret); - if (ret.code == 200 && ret.data.content && ret.data.content.length > 0) { - setDatasetTypeList(ret.data.content.filter((item) => item.category_id == 1)); - setDatasetDirectionList(ret.data.content.filter((item) => item.category_id == 2)); - } else { - setDatasetTypeList([]); - setDatasetDirectionList([]); - } - }); - }; - const nameSearch = (values) => { - console.log(values); - getDatasetlist({ ...queryFlow, name: values }); - }; - const showModal = () => { - form.resetFields(); - setDialogTitle('新建数据集'); - setIsModalOpen(true); - }; - const handleOk = () => { - console.log(1111); - setIsModalOpen(false); - }; - const handleCancel = () => { - setIsModalOpen(false); - }; - const chooseDatasetType = (val, item) => { - console.log(val, item); - if (item.id == queryFlow.data_type) { - setActiveType(''); - setQueryFlow({ ...queryFlow, data_type: null }); - getDatasetlist({ ...queryFlow, data_type: null }); - } else { - setActiveType(item.id); - setQueryFlow({ ...queryFlow, data_type: item.id }); - getDatasetlist({ ...queryFlow, data_type: item.id }); - } - // setQueryFlow({...queryFlow,data_type:item.path},()=>{ - // getDatasetlist() - // }) - }; - const chooseDatasetTag = (val, item) => { - console.log(val, item); - if (item.id == queryFlow.data_tag) { - setActiveTag(''); - setQueryFlow({ ...queryFlow, data_tag: null }); - getDatasetlist({ ...queryFlow, data_tag: null }); - } else { - setActiveTag(item.id); - setQueryFlow({ ...queryFlow, data_tag: item.id }); - getDatasetlist({ ...queryFlow, data_tag: item.id }); - } - // setQueryFlow({...queryFlow,data_type:item.path},()=>{ - // getDatasetlist() - // }) - }; - - const routeToIntro = (e, record) => { - e.stopPropagation(); - console.log(record); - navgite({ pathname: `/dataset/dataset/${record.id}` }); - }; - const onFinishFailed = (errorInfo) => { - console.log('Failed:', errorInfo); - }; - const onPageChange = (pageNum, pageSize) => { - console.log(pageNum, pageSize); - setQueryFlow({ ...queryFlow, page: pageNum - 1, size: pageSize }); - getDatasetlist({ ...queryFlow, page: pageNum - 1, size: pageSize }); - }; - useEffect(() => { - getAssetIconList(iconParams); - getDatasetlist(queryFlow); - return () => {}; - }, []); - return ( - <> -
-
-
- -
分类
-
- {datasetTypeList && datasetTypeList.length > 0 - ? datasetTypeList.map((item) => { - return ( -
-
{ - chooseDatasetType(e, item); - }} - > - - - {item.name} -
-
- ); - }) - : ''} -
-
研究方向/应用领域
-
- {datasetDirectionList && datasetDirectionList.length > 0 - ? datasetDirectionList.map((item) => { - return ( -
-
{ - chooseDatasetTag(e, item); - }} - > - - - {item.name} -
-
- ); - }) - : ''} -
-
-
-
-
- 数据总数:{total}个 -
- -
-
-
- {datasetList && datasetList.length > 0 - ? datasetList.map((item) => { - return ( -
routeToIntro(e, item)}> - {item.name} - { - e.stopPropagation(); - modalConfirm({ - title: '确定删除该条数据集实例吗?', - onOk: () => { - deleteDataset(item.id).then((ret) => { - if (ret.code === 200) { - message.success('删除成功'); - getModelLists(queryFlow); - } else { - message.error(ret.msg); - } - }); - }, - }); - }} - className={Styles.dropdown} - style={{ width: '17px', marginRight: '6px' }} - src={deleteIcon} - alt="" - /> -
{item.description}
-
- - {item.create_by} -
-
- - 最近更新: {moment(item.update_time).format('YYYY-MM-DD')} -
-
- ); - }) - : ''} - {/* Demo */} -
- -
-
- - ); -}; -export default PublicData; diff --git a/react-ui/src/pages/Dataset/type.tsx b/react-ui/src/pages/Dataset/type.tsx new file mode 100644 index 00000000..91808ea2 --- /dev/null +++ b/react-ui/src/pages/Dataset/type.tsx @@ -0,0 +1,118 @@ +import KFIcon from '@/components/KFIcon'; +import { CommonTabKeys } from '@/enums'; +import { + deleteDataset, + deleteModel, + getDatasetList, + getDatasetVersionIdList, + getDatasetVersionsById, + getModelList, + getModelVersionIdList, + getModelVersionsById, +} from '@/services/dataset/index.js'; +import type { TabsProps } from 'antd'; + +export enum ResourceType { + Model = 'Model', // 模型 + Dataset = 'Dataset', // 数据集 +} + +type ResourceTypeKeys = keyof typeof ResourceType; +type ResourceTypeValues = (typeof ResourceType)[ResourceTypeKeys]; + +export type ResourceTypeInfo = { + getList: (params: any) => Promise; + getVersions: (params: any) => Promise; + getFiles: (params: any) => Promise; + deleteRecord: (params: any) => Promise; + name: string; + typeParamKey: string; + tagParamKey: string; + fileReqParamKey: 'models_id' | 'dataset_id'; + tabItems: TabsProps['items']; + typeTitle: string; + tagTitle: string; + typeValue: number; // 从 getAssetIcon 接口获取特定值的数据为 type 分类 (category_id === typeValue) + tagValue: number; // 从 getAssetIcon 接口获取特定值的数据为 tag 分类(category_id === tagValue) + iconPathPrefix: string; // 图标路径前缀 + deleteModalTitle: string; // 删除弹框的title + addBtnTitle: string; // 新增按钮的title +}; + +export const resourceConfig: Record = { + [ResourceType.Dataset]: { + getList: getDatasetList, + getVersions: getDatasetVersionsById, + getFiles: getDatasetVersionIdList, + deleteRecord: deleteDataset, + name: '数据集', + typeParamKey: 'data_type', + tagParamKey: 'data_tag', + fileReqParamKey: 'dataset_id', + tabItems: [ + { + key: CommonTabKeys.Public, + label: '数据广场', + icon: , + }, + { + key: CommonTabKeys.Private, + label: '个人数据', + icon: , + }, + ], + typeTitle: '分类', + tagTitle: '研究方向/应用领域', + typeValue: 1, + tagValue: 2, + iconPathPrefix: 'dataset', + deleteModalTitle: '确定删除该条数据集实例吗?', + addBtnTitle: '新建数据集', + }, + [ResourceType.Model]: { + getList: getModelList, + getVersions: getModelVersionsById, + getFiles: getModelVersionIdList, + deleteRecord: deleteModel, + name: '模型', + typeParamKey: 'model_type', + tagParamKey: 'model_tag', + fileReqParamKey: 'models_id', + tabItems: [ + { + key: CommonTabKeys.Public, + label: '模型广场', + icon: , + }, + { + key: CommonTabKeys.Private, + label: '个人模型', + icon: , + }, + ], + typeTitle: '模型框架', + tagTitle: '模型能力', + typeValue: 3, + tagValue: 4, + iconPathPrefix: 'model', + deleteModalTitle: '确定删除该条模型实例吗?', + addBtnTitle: '新建模型', + }, +}; + +// 分类数据 +export type CategoryData = { + id: number; + category_id: number; + name: string; + path: string; +}; + +// 数据类型 +export type ResourceData = { + id: number; + name: string; + description: string; + create_by: string; + update_time: string; +}; diff --git a/react-ui/src/pages/Experiment/experimentText/addExperimentModal.less b/react-ui/src/pages/Experiment/experimentText/addExperimentModal.less index e8be2e5f..eec152a7 100644 --- a/react-ui/src/pages/Experiment/experimentText/addExperimentModal.less +++ b/react-ui/src/pages/Experiment/experimentText/addExperimentModal.less @@ -1,17 +1,4 @@ .modal { - :global { - // .ant-input { - // height: 30px; - // border-color: #e6e6e6; - // } - // .ant-select-single { - // height: 40px; - // } - .ant-form-item .ant-form-item-label > label { - color: rgba(29, 29, 32, 0.8); - } - } - .global_param_item { max-height: 230px; padding: 24px 12px 0; diff --git a/react-ui/src/pages/Experiment/experimentText/props.jsx b/react-ui/src/pages/Experiment/experimentText/props.jsx index d5ac7999..7683c833 100644 --- a/react-ui/src/pages/Experiment/experimentText/props.jsx +++ b/react-ui/src/pages/Experiment/experimentText/props.jsx @@ -246,8 +246,8 @@ const Props = forwardRef(({ onParentChange }, ref) => { > 下载 - 导出到模型库 - 导出到数据集 + {/* 导出到模型库 + 导出到数据集 */}
diff --git a/react-ui/src/pages/Mirror/create.less b/react-ui/src/pages/Mirror/create.less index 902e2875..84f4c197 100644 --- a/react-ui/src/pages/Mirror/create.less +++ b/react-ui/src/pages/Mirror/create.less @@ -9,9 +9,9 @@ background-color: white; border-radius: 10px; - &__title { - display: flex; - align-items: center; + &__type { + color: @text-color; + font-size: @font-size-input-lg; } } } diff --git a/react-ui/src/pages/Mirror/create.tsx b/react-ui/src/pages/Mirror/create.tsx index 8ac38f6c..f2d1f86f 100644 --- a/react-ui/src/pages/Mirror/create.tsx +++ b/react-ui/src/pages/Mirror/create.tsx @@ -12,7 +12,7 @@ import { CommonTabKeys } from '@/enums'; import { createMirrorReq } from '@/services/mirror'; import { to } from '@/utils/promise'; import { getSessionItemThenRemove, mirrorNameKey } from '@/utils/sessionStorage'; -import { getFileListFromEvent } from '@/utils/ui'; +import { getFileListFromEvent, validateUploadFiles } from '@/utils/ui'; import { useNavigate } from '@umijs/max'; import { Button, Col, Form, Input, Row, Upload, UploadFile, message, type UploadProps } from 'antd'; import { omit } from 'lodash'; @@ -75,30 +75,16 @@ function MirrorCreate() { }; } else { const fileList = formData['fileList'] ?? []; - if (fileList.length === 0) { - message.error('请上传文件'); - return; + if (validateUploadFiles(fileList)) { + const file = fileList[0]; + params = { + ...omit(formData, ['fileList', 'upload_type']), + path: file.response.data.url, + file_size: file.response.data.fileSize, + upload_type: 1, + image_type: 0, + }; } - const file = fileList[0]; - if (file.status === 'uploading') { - message.error('请等待文件上传完成'); - return; - } else if (file.status === 'error') { - message.error('文件上传失败,请重新上传文件'); - return; - } - if (!file.response || !file.response.data) { - message.error('文件上传失败,请重新上传文件'); - return; - } - - params = { - ...omit(formData, ['fileList', 'upload_type']), - path: file.response.data.url, - file_size: file.response.data.fileSize, - upload_type: 1, - image_type: 0, - }; } const [res] = await to(createMirrorReq(params)); @@ -118,6 +104,7 @@ function MirrorCreate() { navgite(-1); }; + // 上传前认证 const beforeUpload: UploadProps['beforeUpload'] = () => { const fileList = form.getFieldValue('fileList'); if (Array.isArray(fileList) && fileList.length >= 1) { @@ -134,12 +121,13 @@ function MirrorCreate() {
- 公网 + 公网 diff --git a/react-ui/src/pages/Mirror/list.less b/react-ui/src/pages/Mirror/list.less index 9eb8009a..9f2905e9 100644 --- a/react-ui/src/pages/Mirror/list.less +++ b/react-ui/src/pages/Mirror/list.less @@ -3,7 +3,7 @@ &__tabs-container { height: 50px; padding-left: 27px; - background-image: url('../../assets/img/page-title-bg.png'); + background-image: url(@/assets/img/page-title-bg.png); } &__content { @@ -20,7 +20,7 @@ } &__table { - height: calc(100% - 34px - 28px); + height: calc(100% - 32px - 28px); margin-top: 28px; } } diff --git a/react-ui/src/pages/Mirror/list.tsx b/react-ui/src/pages/Mirror/list.tsx index 06685548..24932f6d 100644 --- a/react-ui/src/pages/Mirror/list.tsx +++ b/react-ui/src/pages/Mirror/list.tsx @@ -54,6 +54,7 @@ function MirrorList() { const [cacheState, setCacheState] = useCacheState(); const [activeTab, setActiveTab] = useState(cacheState?.activeTab ?? CommonTabKeys.Public); const [searchText, setSearchText] = useState(cacheState?.searchText); + const [inputText, setInputText] = useState(cacheState?.searchText); const [tableData, setTableData] = useState([]); const [total, setTotal] = useState(0); const [pagination, setPagination] = useState( @@ -65,11 +66,12 @@ function MirrorList() { useEffect(() => { getMirrorList(); - }, [activeTab, pagination]); + }, [activeTab, pagination, searchText]); // 切换 Tab,重置数据 const hanleTabChange: TabsProps['onChange'] = (value) => { setSearchText(''); + setInputText(''); setPagination({ current: 1, pageSize: 10, @@ -78,16 +80,16 @@ function MirrorList() { setTableData([]); setActiveTab(value); }; + // 获取镜像列表 - const getMirrorList = async (params?: Record) => { - const reqParams = { + const getMirrorList = async () => { + const params: Record = { page: pagination.current! - 1, size: pagination.pageSize, name: searchText, image_type: activeTab === CommonTabKeys.Public ? 1 : 0, - ...params, }; - const [res] = await to(getMirrorListReq(reqParams)); + const [res] = await to(getMirrorListReq(params)); if (res && res.data) { const { content = [], totalElements = 0 } = res.data; setTableData(content); @@ -116,10 +118,7 @@ function MirrorList() { // 搜索 const onSearch: SearchProps['onSearch'] = (value) => { - // 带参数是为了点清除时,searchText 更新不及时的问题 - getMirrorList({ - name: value, - }); + setSearchText(value); }; // 查看详情 @@ -233,12 +232,7 @@ function MirrorList() { return (
- +
@@ -246,9 +240,9 @@ function MirrorList() { placeholder="按数据集名称筛选" allowClear onSearch={onSearch} - onChange={(e) => setSearchText(e.target.value)} + onChange={(e) => setInputText(e.target.value)} style={{ width: 300 }} - value={searchText} + value={inputText} /> {activeTab === CommonTabKeys.Private && ( + + + + + ); +} + +export default AddModelModal; diff --git a/react-ui/src/pages/Model/index.jsx b/react-ui/src/pages/Model/index.jsx index 310823f4..f8add51f 100644 --- a/react-ui/src/pages/Model/index.jsx +++ b/react-ui/src/pages/Model/index.jsx @@ -1,89 +1,7 @@ -import { Form, Input, Tabs } from 'antd'; -import { useEffect, useState } from 'react'; -import { useNavigate } from 'react-router-dom'; -import Styles from './index.less'; -import PersonalData from './personalData'; -import PublicData from './publicData'; -// import {getModelList} from '@/services/dataset/index.js' -const { Search } = Input; -const { TabPane } = Tabs; -const leftdataList = [1, 2, 3]; +import ResourcePage from '@/pages/Dataset/components/ResourcePage'; +import { ResourceType } from '@/pages/Dataset/type'; -const Dataset = () => { - const [queryFlow, setQueryFlow] = useState({ - page: 0, - size: 10, - name: null, - }); - const navgite = useNavigate(); - const [isModalOpen, setIsModalOpen] = useState(false); - const [datasetList, setDatasetList] = useState([]); - const [total, setTotal] = useState(0); - const [form] = Form.useForm(); - const [dialogTitle, setDialogTitle] = useState('新建数据'); - // const getModelLists=()=>{ - // getModelList(queryFlow).then(ret=>{ - // console.log(ret); - // if(ret.code==200){ - // setDatasetList(ret.data.content) - // setTotal(ret.data.totalElements) - // } - // }) - // } - - const showModal = () => { - form.resetFields(); - setDialogTitle('新建数据集'); - setIsModalOpen(true); - }; - const handleOk = () => { - console.log(1111); - setIsModalOpen(false); - }; - const handleCancel = () => { - setIsModalOpen(false); - }; - const onFinish = (values) => {}; - const routeToIntro = (e, record) => { - e.stopPropagation(); - navgite({ pathname: '/dataset/dataset' }); - }; - const onFinishFailed = (errorInfo) => { - console.log('Failed:', errorInfo); - }; - useEffect(() => { - return () => {}; - }, []); - return ( -
-
-
- - - - -
-
- ); +const ModelPage = () => { + return ; }; -export default Dataset; +export default ModelPage; diff --git a/react-ui/src/pages/Model/index.less b/react-ui/src/pages/Model/index.less index defa446f..596c64d7 100644 --- a/react-ui/src/pages/Model/index.less +++ b/react-ui/src/pages/Model/index.less @@ -1,13 +1,3 @@ -.datasetTopBox { - display: flex; - align-items: center; - width: 100%; - height: 49px; - padding: 0 30px; - padding-right: 30px; - background-image: url(/assets/images/pipeline-back.png); - background-size: 100% 100%; -} .datasetIntroTopBox { display: flex; flex-direction: column; @@ -78,250 +68,11 @@ } } } -.datasetAllBox { - :global { - .ant-tabs-nav .ant-tabs-nav-wrap { - margin: -48px 0 0 30px; - } - } -} .plusButton { margin: 0 18px 0 20px; } -.datasetCneterBox { - display: flex; - justify-content: space-between; - width: 100%; - height: 87.5vh; - - .datasetCneterLeftBox { - width: 340px; - height: 100%; - margin-right: 10px; - padding-top: 15px; - background: #ffffff; - box-shadow: 0px 3px 6px rgba(146, 146, 146, 0.09); - .custTab { - display: flex; - height: 32px; - border-bottom: 1px solid #e0eaff; - .tabItem { - width: 52px; - height: 100%; - color: #808080; - font-size: 15px; - text-align: center; - cursor: pointer; - } - } - .leftContentBox { - max-height: 80vh; - padding: 15px 20px; - overflow-x: hidden; - overflow-y: auto; - .itemTitle { - margin-bottom: 15px; - color: #1d1d20; - font-size: 14px; - } - .itemBox { - display: flex; - flex-wrap: wrap; - align-content: start; - width: 110%; - .messageBox { - display: flex; - flex-direction: column; - align-items: center; - justify-content: space-between; - width: 92px; - height: 62px; - margin: 0 12px 20px 0; - padding: 11px 0px 7px 0px; - color: #1d1d20; - font-size: 12px; - border: 1px solid; - border-color: rgba(22, 100, 255, 0.05); - border-radius: 4px; - cursor: pointer; - .ptIcon { - display: block; - } - .hoverIcon { - display: none; - } - .messageText { - width: 65px; - overflow: hidden; - white-space: nowrap; - text-align: center; - text-overflow: ellipsis; - transition: all 0.2s; - } - } - .messageBox:hover { - background: rgba(22, 100, 255, 0.03); - border: 1px solid; - border-color: #1664ff; - .ptIcon { - display: none; - } - .hoverIcon { - display: block; - } - } - .active { - background: rgba(22, 100, 255, 0.03) !important; - border: 1px solid !important; - border-color: #1664ff !important; - .ptIcon { - display: none !important; - } - .hoverIcon { - display: block !important; - } - } - } - } - } - .datasetCneterRightBox { - display: flex; - flex: 1; - flex-direction: column; - height: 100%; - overflow-y: auto; - padding: 22px 30px 26px 30px; - background: #ffffff; - box-shadow: 0px 3px 6px rgba(146, 146, 146, 0.09); - .dataSource { - display: flex; - align-items: center; - justify-content: space-between; - height: 32px; - margin-bottom: 30px; - color: rgba(29, 29, 32, 0.8); - font-size: 15px; - } - .dataContent { - display: flex; - flex: 1; - flex-wrap: wrap; - align-content: flex-start; - width: 100%; - .dataItem { - position: relative; - width: 23.8%; - height:164px; - margin: 0 20px 25px 0; - background: #ffffff; - border: 1px solid; - border-color: #eaeaea; - border-radius: 4px; - cursor: pointer; - .dropdown{ - position: absolute; - right: 20px; - top: 15px; - } - .itemText { - position: absolute; - top: 20px; - left: 20px; - height: 6px; - color: #1d1d20; - font-size: 16px; - font-family: 'Alibaba'; - line-height: 0px; - background: linear-gradient( - to right, - rgba(22, 100, 255, 0.3) 0, - rgba(22, 100, 255, 0) 100% - ); - } - .itemDescripition { - position: absolute; - top: 57px; - left: 20px; - display: -webkit-box; - padding-right: 28px; - overflow: hidden; - color: #575757; - font-size: 14px; - word-break: break-all; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - } - .itemTime { - position: absolute; - bottom: 22px; - left: 20px; - display: flex; - align-items: center; - color: #808080; - font-size: 13px; - } - .itemIcon { - position: absolute; - right: 20px; - bottom: 22px; - display: flex; - align-items: center; - color: #808080; - font-size: 13px; - } - } - .dataItem:hover { - border-color: #1664ff; - box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.1); - } - .dataItem:hover .itemText { - color: #1664ff; - } - } - } -} -.tipContent{ - color: #c73131; +.tipContent { margin-top: 5px; -} -.modal { - :global { - .ant-modal-content { - width: 825px; - padding: 20px 67px; - background-image: url(/assets/images/modal-back.png); - background-repeat: no-repeat; - background-position: top center; - background-size: 100%; - border-radius: 21px; - } - .ant-modal-header { - margin: 20px 0; - background-color: transparent; - } - .ant-input { - height: 40px; - border-color: #e6e6e6; - } - .ant-form-item .ant-form-item-label > label { - color: rgba(29, 29, 32, 0.8); - } - .ant-modal-footer { - display: flex; - justify-content: center; - margin: 40px 0 30px 0; - } - .ant-btn { - width: 110px; - height: 40px; - font-size: 18px; - background: rgba(22, 100, 255, 0.06); - border-color: transparent; - border-radius: 10px; - } - .ant-btn-primary { - background: #1664ff; - } - } + color: #c73131; } diff --git a/react-ui/src/pages/Model/modelIntro.jsx b/react-ui/src/pages/Model/modelIntro.jsx index 5cc9477d..d978f15e 100644 --- a/react-ui/src/pages/Model/modelIntro.jsx +++ b/react-ui/src/pages/Model/modelIntro.jsx @@ -1,5 +1,6 @@ import { getAccessToken } from '@/access'; import KFIcon from '@/components/KFIcon'; +import KFModal from '@/components/KFModal'; import { addModelsVersionDetail, deleteModelVersion, @@ -8,18 +9,19 @@ import { getModelVersionsById, } from '@/services/dataset/index.js'; import { downLoadZip } from '@/utils/downloadfile'; +import { modalConfirm } from '@/utils/ui'; import { UploadOutlined } from '@ant-design/icons'; -import { Button, Form, Input, Modal, Select, Table, Tabs, Upload, message } from 'antd'; +import { useParams, useSearchParams } from '@umijs/max'; +import { Button, Form, Input, Select, Table, Tabs, Upload, message } from 'antd'; import moment from 'moment'; import { useEffect, useRef, useState } from 'react'; -import { useParams } from 'react-router-dom'; import Styles from './index.less'; const { Search } = Input; const { TabPane } = Tabs; const Dataset = () => { const props = { - action: '/api/mmp/dataset/upload', + action: '/api/mmp/models/upload', // headers: { // 'X-Requested-With': null // }, @@ -53,9 +55,11 @@ const Dataset = () => { const [version, setVersion] = useState(null); const [versionList, setVersionList] = useState([]); const locationParams = useParams(); //新版本获取路由参数接口 + const [searchParams] = useSearchParams(); console.log(locationParams); const [wordList, setWordList] = useState([]); const [uuid, setUuid] = useState(Date.now()); + const isPublic = searchParams.get('isPublic') === 'true'; const getModelByDetail = () => { getModelById(locationParams.id).then((ret) => { console.log(ret); @@ -76,6 +80,9 @@ const Dataset = () => { ); setVersion(ret.data[0]); getModelVersions({ version: ret.data[0], models_id: locationParams.id }); + } else { + setVersion(null); + setWordList([]); } }); }; @@ -96,18 +103,9 @@ const Dataset = () => { setIsModalOpen(false); }; const deleteDataset = () => { - Modal.confirm({ - title: ( -
- -
删除后,该模型版本将不可恢复
-
- ), - content:
是否确认删除?
, + modalConfirm({ + title: '删除后,该版本将不可恢复', + content: '是否确认删除?', okText: '确认', cancelText: '取消', @@ -262,15 +260,18 @@ const Dataset = () => {
- + {!isPublic && ( + + )} +
- - - {dialogTitle} -
- } + { - +
); }; diff --git a/react-ui/src/pages/Model/personalData.jsx b/react-ui/src/pages/Model/personalData.jsx deleted file mode 100644 index e951e741..00000000 --- a/react-ui/src/pages/Model/personalData.jsx +++ /dev/null @@ -1,525 +0,0 @@ -import { getAccessToken } from '@/access'; -import clock from '@/assets/img/clock.png'; -import creatByImg from '@/assets/img/creatBy.png'; -import deleteIcon from '@/assets/img/delete-icon.png'; -import KFIcon from '@/components/KFIcon'; -import { addModel, deleteModel, getAssetIcon, getModelList } from '@/services/dataset/index.js'; -import { modalConfirm } from '@/utils/ui'; -import { UploadOutlined } from '@ant-design/icons'; -import { Button, Form, Input, Modal, Pagination, Select, Upload, message } from 'antd'; -import moment from 'moment'; -import { useEffect, useState } from 'react'; -import { useNavigate } from 'react-router-dom'; -import Styles from './index.less'; -const { Search } = Input; - -const leftdataList = [1, 2, 3]; - -const PublicData = () => { - const props = { - action: '/api/mmp/dataset/upload', - // headers: { - // 'X-Requested-With': null - // }, - headers: { - Authorization: getAccessToken(), - 'X-Requested-With': null, - }, - onChange({ file, fileList }) { - if (file.status !== 'uploading') { - console.log(file, fileList); - form.setFieldsValue({ - models_version_vos: fileList.map((item) => { - const data = item.response.data[0]; - return { - file_name: data.fileName, - file_size: data.fileSize, - url: data.url, - }; - }), - }); - } - }, - defaultFileList: [], - }; - const [queryFlow, setQueryFlow] = useState({ - page: 0, - size: 20, - name: null, - available_range: 0, - }); - const navgite = useNavigate(); - const [iconParams, setIconParams] = useState({ - name: null, - page: 0, - size: 10000, - }); - const [activeType, setActiveType] = useState(null); - const [activeTag, setActiveTag] = useState(null); - const [modelTypeList, setmodelTypeList] = useState([]); - const [modelDirectionList, setmodelDirectionList] = useState([]); - const [isModalOpen, setIsModalOpen] = useState(false); - const [datasetList, setDatasetList] = useState([]); - const [total, setTotal] = useState(0); - const [form] = Form.useForm(); - const [dialogTitle, setDialogTitle] = useState('新建模型'); - const [uuid, setUuid] = useState(Date.now()); - const getModelLists = (queryFlow) => { - getModelList(queryFlow).then((ret) => { - console.log(ret); - if (ret.code == 200) { - setDatasetList(ret.data.content); - setTotal(ret.data.totalElements); - } - }); - }; - - const showModal = () => { - form.resetFields(); - setDialogTitle('新建模型'); - setUuid(Date.now()); - setIsModalOpen(true); - }; - const getAssetIconList = (params) => { - getAssetIcon(params).then((ret) => { - console.log(ret); - if (ret.code == 200 && ret.data.content && ret.data.content.length > 0) { - setmodelTypeList(ret.data.content.filter((item) => item.category_id == 3)); - setmodelDirectionList(ret.data.content.filter((item) => item.category_id == 4)); - } else { - setmodelTypeList([]); - setmodelDirectionList([]); - } - }); - }; - const onSearch = (values) => { - console.log(values); - getAssetIconList({ ...iconParams, name: values }); - }; - const nameSearch = (values) => { - console.log(values); - getModelLists({ ...queryFlow, name: values }); - }; - const handleOk = () => { - console.log(1111); - setIsModalOpen(false); - }; - const handleCancel = () => { - setIsModalOpen(false); - }; - const onFinish = (values) => { - const params = { - ...values, - available_range: 0, - }; - addModel(values).then((ret) => { - console.log(ret); - getModelLists(queryFlow); - setIsModalOpen(false); - }); - }; - - const chooseModelType = (val, item) => { - console.log(val, item); - if (item.id == queryFlow.model_type) { - setActiveType(''); - setQueryFlow({ ...queryFlow, model_type: null }); - getModelLists({ ...queryFlow, model_type: null }); - } else { - setActiveType(item.id); - setQueryFlow({ ...queryFlow, model_type: item.id }); - getModelLists({ ...queryFlow, model_type: item.id }); - } - - // setQueryFlow({...queryFlow,data_type:item.path},()=>{ - // getDatasetlist() - // }) - }; - const chooseModelTag = (val, item) => { - if (item.id == queryFlow.model_tag) { - setActiveTag(''); - setQueryFlow({ ...queryFlow, model_tag: null }); - getModelLists({ ...queryFlow, model_tag: null }); - } else { - setActiveTag(item.id); - setQueryFlow({ ...queryFlow, model_tag: item.id }); - getModelLists({ ...queryFlow, model_tag: item.id }); - } - // setQueryFlow({...queryFlow,data_type:item.path},()=>{ - // getDatasetlist() - // }) - }; - const routeToIntro = (e, record) => { - e.stopPropagation(); - console.log(record); - navgite({ pathname: `/dataset/model/${record.id}` }); - }; - const onFinishFailed = (errorInfo) => { - console.log('Failed:', errorInfo); - }; - const onPageChange = (pageNum, pageSize) => { - console.log(pageNum, pageSize); - setQueryFlow({ ...queryFlow, page: pageNum - 1, size: pageSize }); - getModelLists({ ...queryFlow, page: pageNum - 1, size: pageSize }); - }; - useEffect(() => { - getAssetIconList(iconParams); - getModelLists(queryFlow); - return () => {}; - }, []); - return ( - <> -
-
-
- -
模型框架
-
- {modelTypeList && modelTypeList.length > 0 - ? modelTypeList.map((item) => { - return ( -
-
{ - chooseModelType(e, item); - }} - > - - - { - chooseModelTag(e, item); - }} - > - {item.name} - -
-
- ); - }) - : ''} -
-
模型能力
-
- {modelDirectionList && modelDirectionList.length > 0 - ? modelDirectionList.map((item) => { - return ( -
-
{ - chooseModelTag(e, item); - }} - > - - - {item.name} -
-
- ); - }) - : ''} -
-
-
-
-
- 数据总数:{total}个 -
- - -
-
-
- {datasetList && datasetList.length > 0 - ? datasetList.map((item) => { - return ( -
{ - routeToIntro(e, item); - }} - > - {item.name} - { - e.stopPropagation(); - modalConfirm({ - title: '确定删除该条模型实例吗?', - onOk: () => { - deleteModel(item.id).then((ret) => { - if (ret.code === 200) { - message.success('删除成功'); - getModelLists(queryFlow); - } else { - message.error(ret.msg); - } - }); - }, - }); - }} - className={Styles.dropdown} - style={{ width: '17px', marginRight: '6px' }} - src={deleteIcon} - alt="" - /> - {/* { - console.log(e); - if (e.key === 'detail') { - routeToIntro(e, item); - } else if (e.key === 'delete') { - modalConfirm({ - title: '确定删除该条模型实例吗?', - onOk: () => { - deleteModel(item.id).then((ret) => { - if (ret.code === 200) { - message.success('删除成功'); - getModelLists(queryFlow); - } else { - message.error(ret.msg); - } - }); - }, - }); - } - }, - }} - > -
- -
-
*/} - ,
{item.description}
-
- - {item.create_by} -
-
- - 最近更新: {moment(item.update_time).format('YYYY-MM-DD')} -
-
- ); - }) - : ''} - {/* Demo */} -
- -
-
- - - {dialogTitle} -
- } - open={isModalOpen} - className={Styles.modal} - okButtonProps={{ - htmlType: 'submit', - form: 'form', - }} - onCancel={handleCancel} - > -
- - - - - - - - - - - - {/* - - 仅自己可见 - 工作空间可见 - - */} - - { - return { value: item.id, label: item.name }; - })} - /> - - - - - - -
- - - ); -}; -export default PublicData; diff --git a/react-ui/src/pages/Model/publicData.jsx b/react-ui/src/pages/Model/publicData.jsx deleted file mode 100644 index 5cb7082e..00000000 --- a/react-ui/src/pages/Model/publicData.jsx +++ /dev/null @@ -1,384 +0,0 @@ -import clock from '@/assets/img/clock.png'; -import creatByImg from '@/assets/img/creatBy.png'; -import deleteIcon from '@/assets/img/delete-icon.png'; -import { deleteModel, getAssetIcon, getModelList } from '@/services/dataset/index.js'; -import { modalConfirm } from '@/utils/ui'; -import { Form, Input, Modal, Pagination, Radio, message } from 'antd'; -import moment from 'moment'; -import { useEffect, useState } from 'react'; -import { useNavigate } from 'react-router-dom'; -import Styles from './index.less'; -const { Search } = Input; -const leftdataList = [1, 2, 3]; - -const PublicData = () => { - const [queryFlow, setQueryFlow] = useState({ - page: 0, - size: 20, - name: null, - available_range: 1, - }); - const [iconParams, setIconParams] = useState({ - name: null, - page: 0, - size: 10000, - }); - const [activeType, setActiveType] = useState(null); - const [activeTag, setActiveTag] = useState(null); - const [datasetTypeList, setDatasetTypeList] = useState([]); - const [datasetDirectionList, setDatasetDirectionList] = useState([]); - const navgite = useNavigate(); - const [isModalOpen, setIsModalOpen] = useState(false); - const [datasetList, setDatasetList] = useState([]); - const [total, setTotal] = useState(0); - const [form] = Form.useForm(); - const [dialogTitle, setDialogTitle] = useState('新建数据'); - const getModelLists = (queryFlow) => { - getModelList(queryFlow).then((ret) => { - console.log(ret); - if (ret.code == 200) { - setDatasetList(ret.data.content); - setTotal(ret.data.totalElements); - } - }); - }; - - const showModal = () => { - form.resetFields(); - setDialogTitle('新建数据集'); - setIsModalOpen(true); - }; - const nameSearch = (values) => { - console.log(values); - getModelLists({ ...queryFlow, name: values }); - }; - const getAssetIconList = (params) => { - getAssetIcon(params).then((ret) => { - console.log(ret); - if (ret.code == 200 && ret.data.content && ret.data.content.length > 0) { - setDatasetTypeList(ret.data.content.filter((item) => item.category_id == 3)); - setDatasetDirectionList(ret.data.content.filter((item) => item.category_id == 4)); - } else { - setDatasetTypeList([]); - setDatasetDirectionList([]); - } - }); - }; - const onSearch = (values) => { - console.log(values); - getAssetIconList({ ...iconParams, name: values }); - }; - const handleOk = () => { - console.log(1111); - setIsModalOpen(false); - }; - const handleCancel = () => { - setIsModalOpen(false); - }; - const chooseModelType = (val, item) => { - console.log(val, item); - if (item.id == queryFlow.model_type) { - setActiveType(''); - setQueryFlow({ ...queryFlow, model_type: null }); - getModelLists({ ...queryFlow, model_type: null }); - } else { - setActiveType(item.id); - setQueryFlow({ ...queryFlow, model_type: item.id }); - getModelLists({ ...queryFlow, model_type: item.id }); - } - - // setQueryFlow({...queryFlow,data_type:item.path},()=>{ - // getDatasetlist() - // }) - }; - const chooseModelTag = (val, item) => { - if (item.id == queryFlow.model_tag) { - setActiveTag(''); - setQueryFlow({ ...queryFlow, model_tag: null }); - getModelLists({ ...queryFlow, model_tag: null }); - } else { - setActiveTag(item.id); - setQueryFlow({ ...queryFlow, model_tag: item.id }); - getModelLists({ ...queryFlow, model_tag: item.id }); - } - // setQueryFlow({...queryFlow,data_type:item.path},()=>{ - // getDatasetlist() - // }) - }; - const onFinish = (values) => {}; - const routeToIntro = (e, record) => { - e.stopPropagation(); - console.log(record); - navgite({ pathname: `/dataset/model/${record.id}` }); - }; - const onFinishFailed = (errorInfo) => { - console.log('Failed:', errorInfo); - }; - const onPageChange = (pageNum, pageSize) => { - console.log(pageNum, pageSize); - setQueryFlow({ ...queryFlow, page: pageNum - 1, size: pageSize }); - getModelLists({ ...queryFlow, page: pageNum - 1, size: pageSize }); - }; - useEffect(() => { - getAssetIconList(iconParams); - getModelLists(queryFlow); - return () => {}; - }, []); - return ( - <> -
-
-
- -
模型框架
-
- {datasetTypeList && datasetTypeList.length > 0 - ? datasetTypeList.map((item) => { - return ( -
-
{ - chooseModelType(e, item); - }} - > - - - {item.name} -
-
- ); - }) - : ''} -
-
模型能力
-
- {datasetDirectionList && datasetDirectionList.length > 0 - ? datasetDirectionList.map((item) => { - return ( -
-
{ - chooseModelTag(e, item); - }} - > - - - {item.name} -
-
- ); - }) - : ''} -
-
-
-
-
- 数据总数:{total}个 -
- -
-
-
- {datasetList && datasetList.length > 0 - ? datasetList.map((item) => { - return ( -
{ - routeToIntro(e, item); - }} - > - {item.name} - { - e.stopPropagation(); - modalConfirm({ - title: '确定删除该条模型实例吗?', - onOk: () => { - deleteModel(item.id).then((ret) => { - if (ret.code === 200) { - message.success('删除成功'); - getModelLists(queryFlow); - } else { - message.error(ret.msg); - } - }); - }, - }); - }} - className={Styles.dropdown} - style={{ width: '17px', marginRight: '6px' }} - src={deleteIcon} - alt="" - /> -
{item.description}
-
- - {item.create_by} -
-
- - 最近更新: {moment(item.update_time).format('YYYY-MM-DD')} -
-
- ); - }) - : ''} - {/* Demo */} -
- -
-
- - - {dialogTitle} -
- } - open={isModalOpen} - className={Styles.modal} - okButtonProps={{ - htmlType: 'submit', - form: 'form', - }} - onCancel={handleCancel} - > -
- - - - - - - - - - - - 仅自己可见 - 工作空间可见 - - - - - -
- - - ); -}; -export default PublicData; diff --git a/react-ui/src/pages/Pipeline/components/ResourceSelectorModal/index.tsx b/react-ui/src/pages/Pipeline/components/ResourceSelectorModal/index.tsx index e073a449..20c265f2 100644 --- a/react-ui/src/pages/Pipeline/components/ResourceSelectorModal/index.tsx +++ b/react-ui/src/pages/Pipeline/components/ResourceSelectorModal/index.tsx @@ -40,7 +40,6 @@ export type SelectorTypeInfo = { getFiles: (params: any) => Promise; handleVersionResponse: (res: any) => any[]; modalIcon: string; - buttonIcon: string; name: string; litReqParamKey: 'available_range' | 'image_type'; fileReqParamKey: 'models_id' | 'dataset_id'; @@ -71,7 +70,6 @@ export const selectorTypeData: Record res.data || [], name: '模型', modalIcon: modelImg, - buttonIcon: 'local:model-select-button', litReqParamKey: 'available_range', fileReqParamKey: 'models_id', tabItems: [ @@ -92,7 +90,6 @@ export const selectorTypeData: Record res.data || [], name: '数据集', modalIcon: datasetImg, - buttonIcon: 'local:dataset-select-button', litReqParamKey: 'available_range', fileReqParamKey: 'dataset_id', tabItems: [ @@ -115,7 +112,6 @@ export const selectorTypeData: Record - {/* //{contextHolder} */} ); }, diff --git a/react-ui/src/pages/Pipeline/editPipeline/props.jsx b/react-ui/src/pages/Pipeline/editPipeline/props.jsx index 58127381..df77d981 100644 --- a/react-ui/src/pages/Pipeline/editPipeline/props.jsx +++ b/react-ui/src/pages/Pipeline/editPipeline/props.jsx @@ -142,41 +142,37 @@ const Props = forwardRef(({ onParentChange }, ref) => { type = ResourceSelectorType.Mirror; break; } - const { close } = openAntdModal( - ResourceSelectorModal, - { - type, - defaultExpandedKeys: resource ? [resource.id] : [], - defaultCheckedKeys: resource ? [`${resource.id}-${resource.version}`] : [], - defaultActiveTab: resource?.activeTab, - onOk: (res) => { - if (res) { - if (type === ResourceSelectorType.Mirror) { - form.setFieldValue(name, res); - } else { - const jsonObj = pick(res, ['id', 'version', 'path']); - const value = JSON.stringify(jsonObj); - form.setFieldValue(name, value); - } - - if (type === ResourceSelectorType.Dataset) { - setSelectedDataset(res); - } else if (type === ResourceSelectorType.Model) { - setSelectedModel(res); - } + const { close } = openAntdModal(ResourceSelectorModal, { + type, + defaultExpandedKeys: resource ? [resource.id] : [], + defaultCheckedKeys: resource ? [`${resource.id}-${resource.version}`] : [], + defaultActiveTab: resource?.activeTab, + onOk: (res) => { + if (res) { + if (type === ResourceSelectorType.Mirror) { + form.setFieldValue(name, res); } else { - if (type === ResourceSelectorType.Dataset) { - setSelectedDataset(null); - } else if (type === ResourceSelectorType.Model) { - setSelectedModel(null); - } - form.setFieldValue(name, ''); + const jsonObj = pick(res, ['id', 'version', 'path']); + const value = JSON.stringify(jsonObj); + form.setFieldValue(name, value); + } + + if (type === ResourceSelectorType.Dataset) { + setSelectedDataset(res); + } else if (type === ResourceSelectorType.Model) { + setSelectedModel(res); } - close(); - }, + } else { + if (type === ResourceSelectorType.Dataset) { + setSelectedDataset(null); + } else if (type === ResourceSelectorType.Model) { + setSelectedModel(null); + } + form.setFieldValue(name, ''); + } + close(); }, - true, - ); + }); }; // 获取选择数据集、模型后面按钮 icon diff --git a/react-ui/src/pages/Pipeline/index.jsx b/react-ui/src/pages/Pipeline/index.jsx index 883b10ff..fcbdc03e 100644 --- a/react-ui/src/pages/Pipeline/index.jsx +++ b/react-ui/src/pages/Pipeline/index.jsx @@ -1,4 +1,5 @@ import KFIcon from '@/components/KFIcon'; +import KFModal from '@/components/KFModal'; import { addWorkflow, cloneWorkflow, @@ -9,12 +10,13 @@ import { } from '@/services/pipeline/index.js'; import themes from '@/styles/theme.less'; import { modalConfirm } from '@/utils/ui'; -import { Button, ConfigProvider, Form, Input, Modal, Space, Table, message } from 'antd'; +import { Button, ConfigProvider, Form, Input, Space, Table, message } from 'antd'; import classNames from 'classnames'; import momnet from 'moment'; import { useEffect, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import Styles from './index.less'; + const { TextArea } = Input; const Pipeline = () => { const [form] = Form.useForm(); @@ -168,7 +170,7 @@ const Pipeline = () => { key="clone" icon={} onClick={async () => { - Modal.confirm({ + modalConfirm({ title: '复制', content: '确定复制该条流水线吗?', okText: '确认', @@ -254,17 +256,10 @@ const Pipeline = () => { scroll={{ y: 'calc(100% - 55px)' }} />
- - - {dialogTitle} - - } + { /> - +
); }; diff --git a/react-ui/src/pages/Pipeline/index.less b/react-ui/src/pages/Pipeline/index.less index bff7318c..102a37ef 100644 --- a/react-ui/src/pages/Pipeline/index.less +++ b/react-ui/src/pages/Pipeline/index.less @@ -8,60 +8,17 @@ padding-right: 30px; background-image: url(/assets/images/pipeline-back.png); background-size: 100% 100%; - } -.modal { - :global { - .ant-modal-content { - width: 825px; - padding: 20px 67px; - background-image: url(/assets/images/modal-back.png); - background-repeat: no-repeat; - background-position: top center; - background-size: 100%; - border-radius: 21px; - } - .ant-modal-header { - margin: 20px 0; - background-color: transparent; - } - .ant-input { - height: 40px; - border-color: #e6e6e6; - } - .ant-form-item .ant-form-item-label > label { - color: rgba(29, 29, 32, 0.8); - } - .ant-modal-footer { - display: flex; - justify-content: center; - margin: 40px 0 30px 0; - } - .ant-btn { - width: 110px; - height: 40px; - font-size: 18px; - background: rgba(22, 100, 255, 0.06); - border-color: transparent; - border-radius: 10px; - } - .ant-btn-primary { - background: #1664ff; - } - } -} -.PipelineBox{ +.PipelineBox { height: calc(100% - 20px); - .PipelineTable{ + .PipelineTable { height: calc(100% - 60px); - :global{ - .ant-table-wrapper .ant-table{ + :global { + .ant-table-wrapper .ant-table { // overflow-y: auto; height: calc(100% - 48px); } } } - } - diff --git a/react-ui/src/pages/Workspace/components/AssetsManagement/index.tsx b/react-ui/src/pages/Workspace/components/AssetsManagement/index.tsx index dc1af6c9..1a734e57 100644 --- a/react-ui/src/pages/Workspace/components/AssetsManagement/index.tsx +++ b/react-ui/src/pages/Workspace/components/AssetsManagement/index.tsx @@ -35,10 +35,10 @@ function AssetsManagement() { title: '组件', value: component, }, - { - title: '代码配置', - value: 0, - }, + // { + // title: '代码配置', + // value: 0, + // }, { title: '流水线模版', value: workflow, @@ -64,9 +64,8 @@ function AssetsManagement() { ]} /> - -
今日新增数量:5
- + {/*
今日新增数量:5
*/} + {assetCounts.map((item, index) => (
{item.title}
diff --git a/react-ui/src/pages/Workspace/components/ExperimentChart/index.less b/react-ui/src/pages/Workspace/components/ExperimentChart/index.less index 3891b3f4..a723c650 100644 --- a/react-ui/src/pages/Workspace/components/ExperimentChart/index.less +++ b/react-ui/src/pages/Workspace/components/ExperimentChart/index.less @@ -2,6 +2,6 @@ width: 295px; min-width: 295px; height: 140px; - background-color: @workspace-background; + background: @workspace-background; border-radius: 4px; } diff --git a/react-ui/src/pages/Workspace/components/ExperimentChart/index.tsx b/react-ui/src/pages/Workspace/components/ExperimentChart/index.tsx index f4d30fe1..89c1f34d 100644 --- a/react-ui/src/pages/Workspace/components/ExperimentChart/index.tsx +++ b/react-ui/src/pages/Workspace/components/ExperimentChart/index.tsx @@ -140,6 +140,7 @@ function ExperimentChart({ chartData, style }: ExperimentChartProps) { itemStyle: { borderRadius: 3, }, + minAngle: 5, label: { show: false, }, @@ -152,11 +153,11 @@ function ExperimentChart({ chartData, style }: ExperimentChartProps) { show: false, }, data: [ - { value: chartData.Failed, name: '失败' }, - { value: chartData.Succeeded, name: '成功' }, - { value: chartData.Terminated, name: '中止' }, - { value: chartData.Pending, name: '等待' }, - { value: chartData.Running, name: '运行中' }, + { value: chartData.Failed > 0 ? chartData.Failed : null, name: '失败' }, + { value: chartData.Succeeded > 0 ? chartData.Succeeded : null, name: '成功' }, + { value: chartData.Terminated > 0 ? chartData.Terminated : null, name: '中止' }, + { value: chartData.Pending > 0 ? chartData.Pending : null, name: '等待' }, + { value: chartData.Running > 0 ? chartData.Running : null, name: '运行中' }, ], }, { diff --git a/react-ui/src/pages/Workspace/components/ExperimentTable/index.less b/react-ui/src/pages/Workspace/components/ExperimentTable/index.less index 85c5e42d..fc83b21d 100644 --- a/react-ui/src/pages/Workspace/components/ExperimentTable/index.less +++ b/react-ui/src/pages/Workspace/components/ExperimentTable/index.less @@ -3,7 +3,7 @@ min-width: 500px; height: 140px; padding: 12px 24px; - background-color: @workspace-background; + background: @workspace-background; border-radius: 4px; &__header { @@ -36,15 +36,15 @@ } &__duration { - width: 25%; + width: 30%; } &__date { - width: 35%; + width: calc(50% - 60px); } &__operation { - width: 20%; + width: 60px; :global { .ant-btn-link { diff --git a/react-ui/src/pages/Workspace/components/TotalStatistics/index.less b/react-ui/src/pages/Workspace/components/TotalStatistics/index.less index aec9945b..d8943328 100644 --- a/react-ui/src/pages/Workspace/components/TotalStatistics/index.less +++ b/react-ui/src/pages/Workspace/components/TotalStatistics/index.less @@ -4,7 +4,7 @@ justify-content: center; width: 400px; height: 140px; - background-color: @workspace-background; + background: @workspace-background; border-radius: 4px; &__icon { @@ -26,11 +26,7 @@ left: 0; width: 79px; height: 6px; - background-color: linear-gradient( - 87.07deg, - rgba(22, 100, 255, 0.6) 0%, - rgba(22, 100, 255, 0) 100% - ); + background: linear-gradient(87.07deg, rgba(22, 100, 255, 0.6) 0%, rgba(22, 100, 255, 0) 100%); } &__count { diff --git a/react-ui/src/pages/Workspace/components/UserSpace/index.less b/react-ui/src/pages/Workspace/components/UserSpace/index.less index b95fdf6d..1c36f6b3 100644 --- a/react-ui/src/pages/Workspace/components/UserSpace/index.less +++ b/react-ui/src/pages/Workspace/components/UserSpace/index.less @@ -20,8 +20,7 @@ &__avatar { position: relative; top: -28px; - width: 56px; - height: 56px; + background-color: white; } &__name { @@ -56,10 +55,5 @@ background-color: rgba(153, 153, 153, 0.13); border-radius: 50%; } - - &__user { - width: 36px; - height: 36px; - } } } diff --git a/react-ui/src/pages/Workspace/components/UserSpace/index.tsx b/react-ui/src/pages/Workspace/components/UserSpace/index.tsx index 503ea9fc..bd4bf323 100644 --- a/react-ui/src/pages/Workspace/components/UserSpace/index.tsx +++ b/react-ui/src/pages/Workspace/components/UserSpace/index.tsx @@ -1,5 +1,5 @@ import { useModel } from '@umijs/max'; -import { Divider, Flex, Space } from 'antd'; +import { Avatar, Divider, Flex, Space } from 'antd'; import styles from './index.less'; type UserSpaceProps = { @@ -14,7 +14,14 @@ function UserSpace({ users = [] }: UserSpaceProps) {
工作空间管理
- + } + >
{currentUser?.nickName}
{currentUser?.roleNames?.[0]?.roleName}
{users?.map((item, index) => { return ( - + icon={ + + } + > ); })} diff --git a/react-ui/src/pages/Workspace/index.less b/react-ui/src/pages/Workspace/index.less index 1a454f38..f7f95a24 100644 --- a/react-ui/src/pages/Workspace/index.less +++ b/react-ui/src/pages/Workspace/index.less @@ -2,9 +2,10 @@ height: 100%; padding: 20px 30px 10px; overflow-y: auto; - background-color: linear-gradient(#ecf2fe, #f9fafb); + background: linear-gradient(#ecf2fe, #f9fafb); &__overview { + gap: 15px; margin-bottom: 16px; padding: 20px 30px; background-color: white; diff --git a/react-ui/src/requestConfig.ts b/react-ui/src/requestConfig.ts index 2a9d6413..fe9cd44d 100644 --- a/react-ui/src/requestConfig.ts +++ b/react-ui/src/requestConfig.ts @@ -25,21 +25,6 @@ export const requestConfig: RequestConfig = { if (accessToken) { headers['Authorization'] = `Bearer ${accessToken}`; } - // const expireTime = getTokenExpireTime(); - // if (expireTime) { - // const left = Number(expireTime) - new Date().getTime(); - // const refreshToken = getRefreshToken(); - // if (left < 0 && refreshToken) { - // clearSessionToken(); - // } else { - // const accessToken = getAccessToken(); - // if (accessToken) { - // headers['Authorization'] = `Bearer ${accessToken}`; - // } - // } - // } else { - // clearSessionToken(); - // } } return { url, options }; }, @@ -55,6 +40,8 @@ export const requestConfig: RequestConfig = { clearSessionToken(); setRemoteMenu(null); gotoLoginPage(false); + message.error('请重新登录'); + return Promise.reject(response); } else { message.error(data?.msg ?? '请求失败'); return Promise.reject(response); diff --git a/react-ui/src/styles/menu.less b/react-ui/src/styles/menu.less new file mode 100644 index 00000000..29e3ed61 --- /dev/null +++ b/react-ui/src/styles/menu.less @@ -0,0 +1,59 @@ +.ant-menu-item, +.ant-menu-submenu { + .kf-menu-item { + display: flex; + align-items: center; + justify-content: flex-start; + font-size: 16px; + + .anticon.kf-menu-item__default-icon { + display: inline !important; + opacity: 1; + } + + .anticon.kf-menu-item__active-icon { + display: none !important; + margin-left: 0 !important; + } + + &:hover { + .anticon.kf-menu-item__default-icon { + display: none !important; + } + .anticon.kf-menu-item__active-icon { + display: inline !important; + opacity: 1; + } + } + } +} + +.ant-menu-item.ant-menu-item-selected, +.ant-menu-submenu.ant-menu-submenu-selected { + .kf-menu-item { + .anticon.kf-menu-item__default-icon { + display: none !important; + } + + .anticon.kf-menu-item__active-icon { + display: inline !important; + opacity: 1; + } + } +} + +.ant-pro-base-menu-vertical-collapsed { + .kf-menu-item { + justify-content: center; + + .kf-menu-item__name { + display: none !important; + } + } +} + +.ant-menu-submenu { + .ant-menu-submenu-title:hover { + color: #1664ff !important; + } +} diff --git a/react-ui/src/styles/theme.less b/react-ui/src/styles/theme.less index c6514915..65a5a32e 100644 --- a/react-ui/src/styles/theme.less +++ b/react-ui/src/styles/theme.less @@ -36,16 +36,33 @@ @font-size: 15px; @font-size-title: 18px; @font-size-content: 16px; +@font-size-input: 14px; +@font-size-input-lg: 16px; // 函数 .addAlpha(@color, @alpha) { @red: red(@color); @green: green(@color); @blue: blue(@color); - @result: rgba(@red, @green, @blue, @alpha); } +// 混合 +.singleLine() { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + word-break: break-all; +} + +.multiLine(@line) { + display: -webkit-box; + overflow: hidden; + word-break: break-all; + -webkit-box-orient: vertical; + -webkit-line-clamp: @line; +} + // 导出变量 :export { primaryColor: @primary-color; @@ -55,5 +72,9 @@ textColor: @text-color; textColorSecondary: @text-color-secondary; fontSize: @font-size; + fontSizeTitle: @font-size-title; + fontSizeContent: @font-size-content; + fontSizeInput: @font-size-input; + fontSizeInputLg: @font-size-input-lg; siderBGColor: @sider-background-color; } diff --git a/react-ui/src/utils/menuRender.tsx b/react-ui/src/utils/menuRender.tsx new file mode 100644 index 00000000..fc0b70dd --- /dev/null +++ b/react-ui/src/utils/menuRender.tsx @@ -0,0 +1,31 @@ +import KFIcon from '@/components/KFIcon'; +import { MenuDataItem } from '@ant-design/pro-components'; +import { Link } from '@umijs/max'; + +export const menuItemRender = (isSubMenu: boolean) => { + return (item: MenuDataItem) => { + const defaultIcon: string = item.icon as string; + const activeIcon = defaultIcon + '-active'; + const hasParent = item.pro_layout_parentKeys?.length > 0; + const childen = ( + <> + {!hasParent && defaultIcon && ( + <> + + + + )} + {item.name} + + ); + if (isSubMenu) { + return
{childen}
; + } else { + return ( + + {childen} + + ); + } + }; +}; diff --git a/react-ui/src/utils/ui.tsx b/react-ui/src/utils/ui.tsx index 108bc8c0..8f8bde3f 100644 --- a/react-ui/src/utils/ui.tsx +++ b/react-ui/src/utils/ui.tsx @@ -6,7 +6,7 @@ import { PageEnum } from '@/enums/pagesEnums'; import themes from '@/styles/theme.less'; import { history } from '@umijs/max'; -import { Modal, type ModalFuncProps, type UploadFile } from 'antd'; +import { Modal, message, type ModalFuncProps, type UploadFile } from 'antd'; // 自定义 Confirm 弹框 export function modalConfirm({ title, content, onOk, ...rest }: ModalFuncProps) { @@ -54,6 +54,7 @@ export const gotoLoginPage = (toHome: boolean = true) => { const urlParams = new URLSearchParams(); urlParams.append('redirect', pathname + search); const newSearch = toHome && pathname && pathname !== PageEnum.LOGIN ? '' : urlParams.toString(); + console.log('gotoLoginPage', pathname, search); if (window.location.pathname !== PageEnum.LOGIN) { history.replace({ pathname: PageEnum.LOGIN, @@ -61,3 +62,28 @@ export const gotoLoginPage = (toHome: boolean = true) => { }); } }; + +// 上传文件校验 +export const validateUploadFiles = (files: UploadFile[], required: boolean = true): boolean => { + if (required && files.length === 0) { + message.error('请上传文件'); + return false; + } + + const hasError = files.some((file) => { + if (file.status === 'uploading') { + message.error('请等待文件上传完成'); + return true; + } + if (file.status === 'error') { + message.error('存在上传失败的文件,请删除后重新上传文件'); + return true; + } + if (!file.response || file.response.code !== 200 || !file.response.data) { + message.error('存在上传失败的文件,请删除后重新上传文件'); + return true; + } + return false; + }); + return !hasError; +};