From cbfa4471f15cfb6c62624b9739f82063ce917700 Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Thu, 18 Apr 2024 11:50:04 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=E9=95=9C=E5=83=8F?= =?UTF-8?q?=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- react-ui/config/routes.ts | 10 + react-ui/src/assets/img/mirror-basic.png | Bin 0 -> 468 bytes react-ui/src/assets/img/mirror-version.png | Bin 0 -> 445 bytes .../{mirror-tabs-bg.png => page-title-bg.png} | Bin react-ui/src/components/KFIcon/index.tsx | 31 +++ react-ui/src/components/KFRadio/index.less | 29 +++ react-ui/src/components/KFRadio/index.tsx | 45 ++++ react-ui/src/components/PageTitle/index.less | 7 + react-ui/src/components/PageTitle/index.tsx | 23 ++ .../src/components/SubAreaTitle/index.less | 8 + .../src/components/SubAreaTitle/index.tsx | 24 ++ react-ui/src/global.less | 106 ++++---- react-ui/src/hooks/index.ts | 13 +- react-ui/src/iconfont/iconfont.js | 1 + react-ui/src/icons/add.svg | 1 + react-ui/src/icons/doc-not-inventory.svg | 1 + react-ui/src/icons/public-mirror-tab.svg | 2 +- react-ui/src/icons/refresh-btn.svg | 1 - react-ui/src/icons/refresh.svg | 1 + react-ui/src/icons/remove.svg | 1 + react-ui/src/icons/view-detail.svg | 2 +- react-ui/src/icons/下载.svg | 1 + react-ui/src/icons/刷新.svg | 1 - react-ui/src/icons/查看详情.svg | 1 + react-ui/src/overrides.less | 37 +++ react-ui/src/pages/Mirror/create.less | 19 ++ react-ui/src/pages/Mirror/create.tsx | 244 ++++++++++++++++++ react-ui/src/pages/Mirror/info.less | 55 ++++ react-ui/src/pages/Mirror/info.tsx | 231 +++++++++++++++++ react-ui/src/pages/Mirror/list.less | 19 +- react-ui/src/pages/Mirror/list.tsx | 157 +++++++---- .../src/pages/Pipeline/editPipeline/props.jsx | 2 + react-ui/src/services/mirror/index.ts | 37 ++- react-ui/src/styles/theme.less | 3 + 34 files changed, 979 insertions(+), 134 deletions(-) create mode 100644 react-ui/src/assets/img/mirror-basic.png create mode 100644 react-ui/src/assets/img/mirror-version.png rename react-ui/src/assets/img/{mirror-tabs-bg.png => page-title-bg.png} (100%) create mode 100644 react-ui/src/components/KFIcon/index.tsx create mode 100644 react-ui/src/components/KFRadio/index.less create mode 100644 react-ui/src/components/KFRadio/index.tsx create mode 100644 react-ui/src/components/PageTitle/index.less create mode 100644 react-ui/src/components/PageTitle/index.tsx create mode 100644 react-ui/src/components/SubAreaTitle/index.less create mode 100644 react-ui/src/components/SubAreaTitle/index.tsx create mode 100644 react-ui/src/iconfont/iconfont.js create mode 100644 react-ui/src/icons/add.svg create mode 100644 react-ui/src/icons/doc-not-inventory.svg delete mode 100644 react-ui/src/icons/refresh-btn.svg create mode 100644 react-ui/src/icons/refresh.svg create mode 100644 react-ui/src/icons/remove.svg create mode 100644 react-ui/src/icons/下载.svg delete mode 100644 react-ui/src/icons/刷新.svg create mode 100644 react-ui/src/icons/查看详情.svg create mode 100644 react-ui/src/pages/Mirror/create.less create mode 100644 react-ui/src/pages/Mirror/create.tsx create mode 100644 react-ui/src/pages/Mirror/info.less create mode 100644 react-ui/src/pages/Mirror/info.tsx diff --git a/react-ui/config/routes.ts b/react-ui/config/routes.ts index 959bf0aa..5de745ab 100644 --- a/react-ui/config/routes.ts +++ b/react-ui/config/routes.ts @@ -144,6 +144,16 @@ export default [ path: '', component: './Mirror/list', }, + { + name: '镜像详情', + path: ':id', + component: './Mirror/info', + }, + { + name: '创建镜像', + path: 'create', + component: './Mirror/create', + }, ], }, { diff --git a/react-ui/src/assets/img/mirror-basic.png b/react-ui/src/assets/img/mirror-basic.png new file mode 100644 index 0000000000000000000000000000000000000000..d9ca34a9a2b8551f1cd868f0c202173b1677d8d3 GIT binary patch literal 468 zcmV;_0W1EAP)?Y02jLN3(9sa z-It-8HZ7VT2>gM-c0t8VCe0W0O zgiOLsbIzW zADh#K6uf>aDyo_Wa|RfDx!Tg&kCJT?6uivd}mihD$tjk(n;$ZH4XMX9M*ZP?G<@z}W=2 zXpMSK=%!j1(SH)E-LX;$7Zu^z9f50z!$Yxs&tWtu)oS=Ci0>t3EDRl85DJ7c1tyf zbAI>0ak+~Nfd~H2u*C74kP>rpq4QjAHeHL2v4=p7rB*V0z#Syq6O>c{9pDZK z6=1FjNI3)1@;+-9tsN^PJ?+oTym>pb)*M=)t6PCJ5AI6qv#=6&X^Kq_nf6ZtcQb*c z7(CQ|5=dR}HK~z+ zc)up_t_fTv6G%gNdVvCx>48hVOu%~Me)gu&bB1apg`yR_KN9eXs6I+nAm4j^Wp8HN zN6ULtBc8%lY#xjRwMaTi@fgV(#cB6RX5RNg-`FTJ72bp[0]; + +interface KFIconProps extends IconFontProps { + type: string; + font?: number; + color?: string; + style?: React.CSSProperties; +} + +function KFIcon({ type, font = 15, color = '', style = {} }: KFIconProps) { + const iconStyle = { + ...style, + fontSize: font, + color, + }; + return ; +} + +export default KFIcon; diff --git a/react-ui/src/components/KFRadio/index.less b/react-ui/src/components/KFRadio/index.less new file mode 100644 index 00000000..f9a277b1 --- /dev/null +++ b/react-ui/src/components/KFRadio/index.less @@ -0,0 +1,29 @@ +@import '@/styles/theme.less'; + +.kf-radio { + display: flex; + align-items: center; + + &__item { + display: flex; + align-items: center; + padding: 12px 20px; + color: @text-color-second; + border: 1px solid #e0e0e0; + border-radius: 8px; + + &:hover { + color: @primary-color-hover; + border: 1px solid @primary-color-hover; + } + + &--active { + color: @kf-primary-color; + border: 1px solid @kf-primary-color; + } + + & + & { + margin-left: 20px; + } + } +} diff --git a/react-ui/src/components/KFRadio/index.tsx b/react-ui/src/components/KFRadio/index.tsx new file mode 100644 index 00000000..b60a4d11 --- /dev/null +++ b/react-ui/src/components/KFRadio/index.tsx @@ -0,0 +1,45 @@ +/* + * @Author: 赵伟 + * @Date: 2024-04-17 16:59:42 + * @Description: 自定义Radio + */ + +import classNames from 'classnames'; +import './index.less'; + +export type KFRadioItem = { + key: string; + title: string; + icon?: React.ReactNode; +}; + +type KFRadioProps = { + items: KFRadioItem[]; + value?: string; + onChange?: (value: string) => void; +}; + +function KFRadio({ items, value, onChange }: KFRadioProps) { + return ( + + {items.map((item) => { + return ( + onChange?.(item.key)} + > + {item.icon} + {item.title} + + ); + })} + + ); +} + +export default KFRadio; diff --git a/react-ui/src/components/PageTitle/index.less b/react-ui/src/components/PageTitle/index.less new file mode 100644 index 00000000..071bb711 --- /dev/null +++ b/react-ui/src/components/PageTitle/index.less @@ -0,0 +1,7 @@ +.kf-page-title { + display: flex; + align-items: center; + height: 49px; + padding-left: 30px; + background-image: url('../../assets/img/page-title-bg.png'); +} diff --git a/react-ui/src/components/PageTitle/index.tsx b/react-ui/src/components/PageTitle/index.tsx new file mode 100644 index 00000000..ca192454 --- /dev/null +++ b/react-ui/src/components/PageTitle/index.tsx @@ -0,0 +1,23 @@ +/* + * @Author: 赵伟 + * @Date: 2024-04-17 14:01:46 + * @Description: 页面标题 + */ +import classNames from 'classnames'; +import React from 'react'; +import './index.less'; + +type PageTitleProps = { + title: string; + className?: string; + style?: React.CSSProperties; +}; +function PageTitle({ title, style, className = '' }: PageTitleProps) { + return ( +
+ {title} +
+ ); +} + +export default PageTitle; diff --git a/react-ui/src/components/SubAreaTitle/index.less b/react-ui/src/components/SubAreaTitle/index.less new file mode 100644 index 00000000..5683824c --- /dev/null +++ b/react-ui/src/components/SubAreaTitle/index.less @@ -0,0 +1,8 @@ +@import '@/styles/theme.less'; + +.kf-subarea-title { + display: flex; + align-items: center; + color: @text-color; + font-size: 16px; +} diff --git a/react-ui/src/components/SubAreaTitle/index.tsx b/react-ui/src/components/SubAreaTitle/index.tsx new file mode 100644 index 00000000..cfdef539 --- /dev/null +++ b/react-ui/src/components/SubAreaTitle/index.tsx @@ -0,0 +1,24 @@ +/* + * @Author: 赵伟 + * @Date: 2024-04-17 15:25:04 + * @Description: 分区标题 + */ + +import './index.less'; + +type SubAreaTitleProps = { + title: string; + image: string; + style?: React.CSSProperties; +}; + +function SubAreaTitle({ title, image, style }: SubAreaTitleProps) { + return ( +
+ + {title} +
+ ); +} + +export default SubAreaTitle; diff --git a/react-ui/src/global.less b/react-ui/src/global.less index 3c954573..05925b9f 100644 --- a/react-ui/src/global.less +++ b/react-ui/src/global.less @@ -1,9 +1,12 @@ +@import '@/styles/theme.less'; + html, body, #root { height: 100%; margin: 0; padding: 0; + overflow-y: hidden; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; @@ -38,10 +41,12 @@ a { color: #1664ff; } .ant-pro-layout .ant-pro-layout-content { - padding: 10px; + padding: 0 10px 10px; + overflow-y: hidden; + background-color: @background-color; } .ant-pro-layout .ant-pro-layout-bg-list { - background: #f9fafb; + background: @background-color; } .ant-table-wrapper .ant-table-thead > tr > th { background-color: #fff; @@ -55,23 +60,23 @@ a { .ant-pro-layout .ant-pro-sider .ant-layout-sider-children { background: #f2f5f7; } -.ant-pro-base-menu-inline-item-title .ant-pro-base-menu-inline-item-text{ - color:#1d1d20; -font-size:16px; +.ant-pro-base-menu-inline-item-title .ant-pro-base-menu-inline-item-text { + color: #1d1d20; + font-size: 16px; } -.ant-pro-layout .ant-pro-sider-menu{ +.ant-pro-layout .ant-pro-sider-menu { padding-top: 40px; } -.ant-pro-global-header-logo-mix{ +.ant-pro-global-header-logo-mix { + width: 257px; height: 75px; - border-bottom: 1px solid rgba(233, 237, 240, 1); margin-left: -16px; - width: 257px; - background:#f2f5f7; - border-top-right-radius: 20px; padding-left: 28px; + background: #f2f5f7; + border-bottom: 1px solid rgba(233, 237, 240, 1); + border-top-right-radius: 20px; } -.ant-pro-layout .ant-pro-sider .ant-layout-sider-children{ +.ant-pro-layout .ant-pro-sider .ant-layout-sider-children { border-right: unset; border-bottom-right-radius: 20px; } @@ -80,16 +85,14 @@ font-size:16px; background: #f2f5f7; border-radius: 0px 20px 20px 0px; } -.ant-pro-layout .ant-pro-layout-content { - background-color: transparent; -} -.ant-drawer .ant-drawer-body{ + +.ant-drawer .ant-drawer-body { padding: 0; } -.ant-drawer .ant-drawer-body .ant-row{ +.ant-drawer .ant-drawer-body .ant-row { padding: 0 24px; } -.ant-drawer .ant-drawer-body .ant-form-item{ +.ant-drawer .ant-drawer-body .ant-form-item { margin-bottom: 20px; } .ant-table-wrapper .ant-table-pagination.ant-pagination { @@ -107,9 +110,10 @@ font-size:16px; height: 94vh; } .ant-pro-layout .ant-pro-layout-container { - height: 98vh; + height: 100vh; + overflow-y: hidden; } -.ant-modal-confirm .ant-modal-confirm-paragraph{ +.ant-modal-confirm .ant-modal-confirm-paragraph { margin: 54px 0 auto; text-align: center; } @@ -120,36 +124,35 @@ font-size:16px; margin-top: 30px; text-align: center; } -.ant-modal-confirm-btns .ant-btn-default{ - width:110px; -height:40px; -background:rgba(22, 100, 255, 0.06); -border-radius:10px; -color:#1d1d20; -font-size:18px; -margin-right: 10px; -border-color: transparent; +.ant-modal-confirm-btns .ant-btn-default { + width: 110px; + height: 40px; + margin-right: 10px; + color: #1d1d20; + font-size: 18px; + background: rgba(22, 100, 255, 0.06); + border-color: transparent; + border-radius: 10px; } .ant-modal-confirm-btns .ant-btn-default:hover { background: rgba(22, 100, 255, 0.06); border-color: transparent; } -.ant-modal-confirm-btns .ant-btn-primary{ - width:110px; - height:40px; - background:#1664ff; - border-radius:10px; +.ant-modal-confirm-btns .ant-btn-primary { + width: 110px; + height: 40px; font-size: 18px; + background: #1664ff; + border-radius: 10px; } -.ant-modal .ant-input-affix-wrapper{ +.ant-modal .ant-input-affix-wrapper { height: 46px; padding: 1px 11px; } -.ant-modal .ant-select-single{ +.ant-modal .ant-select-single { height: 46px; - } -.ant-modal .ant-select-single .ant-select-selector .ant-select-selection-placeholder{ +.ant-modal .ant-select-single .ant-select-selector .ant-select-selection-placeholder { line-height: 46px; } .ant-modal .ant-modal-close-x { @@ -166,14 +169,14 @@ border-color: transparent; .ant-modal .ant-modal-content { padding: 0; } -.ant-modal-confirm-body-wrapper{ -height:303px; -border-radius:21px; -background-image: url(/assets/images/modal-back.png); -background-repeat:no-repeat; -background-size:100%; -background-position: top center; -border-radius: 0; +.ant-modal-confirm-body-wrapper { + height: 303px; + background-image: url(/assets/images/modal-back.png); + background-repeat: no-repeat; + background-position: top center; + background-size: 100%; + border-radius: 21px; + border-radius: 0; } .ant-modal .ant-modal-content { border-radius: 20px; @@ -201,17 +204,6 @@ border-radius: 0; border-radius: 6px; } -.ant-tabs { - .ant-tabs-nav::before, - div > .ant-tabs-nav::before { - border: none; - } - - .ant-tabs-nav { - margin-bottom: 0; - } -} - // ::-webkit-scrollbar-button { // background: #97a1bd; // } diff --git a/react-ui/src/hooks/index.ts b/react-ui/src/hooks/index.ts index 47510edf..32f162ad 100644 --- a/react-ui/src/hooks/index.ts +++ b/react-ui/src/hooks/index.ts @@ -73,21 +73,28 @@ export function useCallbackState(initialValue: T) { * * @param initialWidth - The initial width of the element. * @param initialHeight - The initial height of the element. + * @param deps - dependency list. * @return - A tuple containing the ref to the DOM element, the current width, and the current height. */ -export function useDomSize(initialWidth: number, initialHeight: number) { +export function useDomSize( + initialWidth: number, + initialHeight: number, + deps: React.DependencyList = [], +) { const domRef = useRef(null); const [width, setWidth] = useState(initialWidth); const [height, setHeight] = useState(initialHeight); useEffect(() => { + console.log('dddddd'); + const setDomHeight = () => { if (domRef.current) { setHeight(domRef.current.offsetHeight); setWidth(domRef.current.offsetWidth); } }; - const debounceFunc = debounce(setDomHeight, 500); + const debounceFunc = debounce(setDomHeight, 200); setDomHeight(); window.addEventListener('resize', debounceFunc); @@ -95,7 +102,7 @@ export function useDomSize(initialWidth: number, initialH return () => { window.removeEventListener('resize', debounceFunc); }; - }, [domRef]); + }, [domRef, ...deps]); return [domRef, { width, height }] as const; } diff --git a/react-ui/src/iconfont/iconfont.js b/react-ui/src/iconfont/iconfont.js new file mode 100644 index 00000000..3695c17e --- /dev/null +++ b/react-ui/src/iconfont/iconfont.js @@ -0,0 +1 @@ +window._iconfont_svg_string_4511447='',function(l){var a=(a=document.getElementsByTagName("script"))[a.length-1],t=a.getAttribute("data-injectcss"),a=a.getAttribute("data-disable-injectsvg");if(!a){var h,i,e,o,d,z=function(a,t){t.parentNode.insertBefore(a,t)};if(t&&!l.__iconfont__svg__cssinject__){l.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}h=function(){var a,t=document.createElement("div");t.innerHTML=l._iconfont_svg_string_4511447,(t=t.getElementsByTagName("svg")[0])&&(t.setAttribute("aria-hidden","true"),t.style.position="absolute",t.style.width=0,t.style.height=0,t.style.overflow="hidden",t=t,(a=document.body).firstChild?z(t,a.firstChild):a.appendChild(t))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(h,0):(i=function(){document.removeEventListener("DOMContentLoaded",i,!1),h()},document.addEventListener("DOMContentLoaded",i,!1)):document.attachEvent&&(e=h,o=l.document,d=!1,n(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,p())})}function p(){d||(d=!0,e())}function n(){try{o.documentElement.doScroll("left")}catch(a){return void setTimeout(n,50)}p()}}(window); \ No newline at end of file diff --git a/react-ui/src/icons/add.svg b/react-ui/src/icons/add.svg new file mode 100644 index 00000000..272dd5ac --- /dev/null +++ b/react-ui/src/icons/add.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/react-ui/src/icons/doc-not-inventory.svg b/react-ui/src/icons/doc-not-inventory.svg new file mode 100644 index 00000000..bfd7d4b4 --- /dev/null +++ b/react-ui/src/icons/doc-not-inventory.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/react-ui/src/icons/public-mirror-tab.svg b/react-ui/src/icons/public-mirror-tab.svg index c9246fe6..0019be13 100644 --- a/react-ui/src/icons/public-mirror-tab.svg +++ b/react-ui/src/icons/public-mirror-tab.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/react-ui/src/icons/refresh-btn.svg b/react-ui/src/icons/refresh-btn.svg deleted file mode 100644 index 4c6215f3..00000000 --- a/react-ui/src/icons/refresh-btn.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/refresh.svg b/react-ui/src/icons/refresh.svg new file mode 100644 index 00000000..00f51915 --- /dev/null +++ b/react-ui/src/icons/refresh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/react-ui/src/icons/remove.svg b/react-ui/src/icons/remove.svg new file mode 100644 index 00000000..b3519764 --- /dev/null +++ b/react-ui/src/icons/remove.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/react-ui/src/icons/view-detail.svg b/react-ui/src/icons/view-detail.svg index ff8a2db8..c74fe45a 100644 --- a/react-ui/src/icons/view-detail.svg +++ b/react-ui/src/icons/view-detail.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/react-ui/src/icons/下载.svg b/react-ui/src/icons/下载.svg new file mode 100644 index 00000000..bf00e67e --- /dev/null +++ b/react-ui/src/icons/下载.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/react-ui/src/icons/刷新.svg b/react-ui/src/icons/刷新.svg deleted file mode 100644 index 4c6215f3..00000000 --- a/react-ui/src/icons/刷新.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/查看详情.svg b/react-ui/src/icons/查看详情.svg new file mode 100644 index 00000000..ebdfa4b0 --- /dev/null +++ b/react-ui/src/icons/查看详情.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/react-ui/src/overrides.less b/react-ui/src/overrides.less index 8b137891..00735646 100644 --- a/react-ui/src/overrides.less +++ b/react-ui/src/overrides.less @@ -1 +1,38 @@ +// 设置 Table 可以滑动 +.vertical-scroll-table { + .ant-table-wrapper { + height: 100%; + .ant-spin-nested-loading { + height: 100%; + .ant-spin-container { + height: 100%; + + .ant-table { + height: calc(100% - 74px); + + .ant-table-container { + height: 100%; + + .ant-table-body { + overflow-y: auto !important; + } + } + } + } + } + } +} + +// Tabs 样式 +// 删除底部白色横线 +.ant-tabs { + .ant-tabs-nav::before { + border: none; + } + + // 删除下边的 margin-bottom + .ant-tabs-nav { + margin-bottom: 0; + } +} diff --git a/react-ui/src/pages/Mirror/create.less b/react-ui/src/pages/Mirror/create.less new file mode 100644 index 00000000..baf2e6c0 --- /dev/null +++ b/react-ui/src/pages/Mirror/create.less @@ -0,0 +1,19 @@ +@import '@/styles/theme.less'; + +.mirror-create { + height: 100%; + + &__content { + height: calc(100% - 59px); + margin-top: 10px; + padding: 30px 30px 10px; + overflow: auto; + background-color: white; + border-radius: 10px; + + &__title { + display: flex; + align-items: center; + } + } +} diff --git a/react-ui/src/pages/Mirror/create.tsx b/react-ui/src/pages/Mirror/create.tsx new file mode 100644 index 00000000..e61cd665 --- /dev/null +++ b/react-ui/src/pages/Mirror/create.tsx @@ -0,0 +1,244 @@ +/* + * @Author: 赵伟 + * @Date: 2024-04-16 13:58:08 + * @Description: 镜像详情 + */ +import KFRadio, { type KFRadioItem } from '@/components/KFRadio'; +import PageTitle from '@/components/PageTitle'; +import SubAreaTitle from '@/components/SubAreaTitle'; +import { CommonTabKeys } from '@/enums'; +import { createPrivateMirrorReq, createPublicMirrorReq } from '@/services/mirror'; +import { to } from '@/utils/promise'; +import { useNavigate, useSearchParams } from '@umijs/max'; +import { Button, Col, Form, Input, Row, message } from 'antd'; +import styles from './create.less'; + +type FormData = { + name: string; + tag: string; + description: string; + path?: string; + type: string; +}; + +const mirrorRadioItems: KFRadioItem[] = [ + { + key: CommonTabKeys.Public, + title: '基于公网镜像', + }, + { + key: CommonTabKeys.Private, + title: '本地上传', + }, +]; + +function MirrorCreate() { + const navgite = useNavigate(); + const [seachParams] = useSearchParams(); + const [form] = Form.useForm(); + const isPublic = seachParams.get('isPublic') === 'true'; + + // 创建公网、本地镜像 + const createPublicMirror = async (params: FormData) => { + // createPrivateMirrorReq + const req = isPublic ? createPublicMirrorReq : createPrivateMirrorReq; + const [res] = await to(req(params)); + if (res) { + message.success('创建成功'); + navgite(-1); + } + }; + + // 提交 + const handleSubmit = (values: FormData) => { + console.log(values); + createPublicMirror(values); + }; + + return ( +
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + prevValues.type !== curValues.type} + > + {({ getFieldValue }) => { + const type = getFieldValue('type'); + if (type === CommonTabKeys.Public) { + return ( + <> + + + + 公网 + + + + + + + + + + + + ); + } else { + return ( + <> + + + + {/* + + */} + + + + + ); + } + }} + + + + + + +
+
+
+
+ ); +} + +export default MirrorCreate; diff --git a/react-ui/src/pages/Mirror/info.less b/react-ui/src/pages/Mirror/info.less new file mode 100644 index 00000000..b96c0d7a --- /dev/null +++ b/react-ui/src/pages/Mirror/info.less @@ -0,0 +1,55 @@ +@import '@/styles/theme.less'; + +.mirror-info { + height: 100%; + + &__basic { + &__item { + display: flex; + align-items: flex-start; + font-size: 16px; + line-height: 1.6; + + .label { + width: 80px; + color: @text-color-second; + } + + .value { + flex: 1; + color: @text-color; + } + } + } + + &__content { + height: calc(100% - 59px); + margin-top: 10px; + padding: 30px 30px 0; + background-color: white; + border-radius: 10px; + + &__title { + display: flex; + align-items: center; + } + + &__table { + :global { + .ant-table-wrapper { + height: 100%; + .ant-spin-nested-loading { + height: 100%; + } + .ant-spin-container { + height: 100%; + } + .ant-table { + height: calc(100% - 74px); + overflow: auto; + } + } + } + } + } +} diff --git a/react-ui/src/pages/Mirror/info.tsx b/react-ui/src/pages/Mirror/info.tsx new file mode 100644 index 00000000..5841fe26 --- /dev/null +++ b/react-ui/src/pages/Mirror/info.tsx @@ -0,0 +1,231 @@ +/* + * @Author: 赵伟 + * @Date: 2024-04-16 13:58:08 + * @Description: 镜像详情 + */ +import PageTitle from '@/components/PageTitle'; +import SubAreaTitle from '@/components/SubAreaTitle'; +import { useDomSize } from '@/hooks'; +import { getMirrorInfoReq, getMirrorVersionListReq } from '@/services/mirror'; +import { to } from '@/utils/promise'; +import { useParams, useSearchParams } from '@umijs/max'; +import { Button, Col, Row, Table, TablePaginationConfig, TableProps } from 'antd'; +import classNames from 'classnames'; +import dayjs from 'dayjs'; +import { useEffect, useState } from 'react'; +import styles from './info.less'; + +type MirrorInfoData = { + name?: string; + description?: string; + version_count?: string; + create_time?: string; +}; + +type MirrorVersionData = { + version: string; + url: string; + status: string; + file_size: string; + create_time: string; +}; + +function MirrorInfo() { + const urlParams = useParams(); + const [seachParams] = useSearchParams(); + const [mirrorInfo, setMirrorInfo] = useState({}); + const [tableData, setTableData] = useState([]); + const [topRef, { height: topHeight }] = useDomSize(0, 0, [mirrorInfo]); + const [pagination, setPagination] = useState({ + showSizeChanger: true, + showQuickJumper: true, + current: 1, + pageSize: 10, + total: 0, + }); + const isPublic = seachParams.get('isPublic') === 'true'; + useEffect(() => { + getMirrorInfo(); + getMirrorVersionList(); + }, []); + + // 获取镜像详情 + const getMirrorInfo = async () => { + const id = Number(urlParams.id); + const [res] = await to(getMirrorInfoReq(id)); + if (res && res.data) { + const { name = '', description = '', version_count = '', create_time: time } = res.data; + const create_time = time ? dayjs(time).format('YYYY-MM-DD HH:mm:ss') : ''; + setMirrorInfo({ + name, + description, + version_count, + create_time, + }); + } + }; + + // 获取镜像版本列表 + const getMirrorVersionList = async () => { + const id = Number(urlParams.id); + const params = { + page: pagination.current! - 1, + size: pagination.pageSize, + image_id: id, + }; + const [res] = await to(getMirrorVersionListReq(params)); + if (res && res.data) { + const { content = [], totalElements = 0 } = res.data; + setTableData(content); + setPagination((prev) => ({ + ...prev, + total: totalElements, + })); + } + }; + + // 分页切换 + const handleTableChange: TableProps['onChange'] = (pagination, filters, sorter, { action }) => { + if (action === 'paginate') { + setPagination(pagination); + getMirrorVersionList(); + } + console.log(pagination, filters, sorter, action); + }; + + const downloadVersion = (record: MirrorVersionData) => {}; + const removeVersion = (record: MirrorVersionData) => {}; + + const columns: TableProps['columns'] = [ + { + title: '镜像版本', + dataIndex: 'version', + key: 'version', + width: '20%', + }, + { + title: '镜像地址', + dataIndex: 'url', + key: 'url', + width: '26%', + }, + { + title: '状态', + dataIndex: 'status', + key: 'status', + width: '7%', + }, + { + title: '镜像大小', + dataIndex: 'file_size', + key: 'file_size', + width: '7%', + }, + { + title: '创建时间', + dataIndex: 'create_time', + key: 'create_time', + width: '20%', + render: (text: string) => {dayjs(text).format('YYYY-MM-DD HH:mm:ss')}, + }, + { + title: '操作', + dataIndex: 'operation', + width: '20%', + key: 'operation', + render: (_: any, record: any) => ( +
+ + {!isPublic && ( + + )} +
+ ), + }, + ]; + + return ( +
+ +
+
+ +
+ + +
+
镜像名称:
+
{mirrorInfo.name}
+
+ + +
+
版本数:
+
{mirrorInfo.version_count}
+
+ +
+ + +
+
镜像描述:
+
{mirrorInfo.description}
+
+ + +
+
创建时间:
+
{mirrorInfo.create_time}
+
+ +
+
+ + +
+
+ + + + + ); +} + +export default MirrorInfo; diff --git a/react-ui/src/pages/Mirror/list.less b/react-ui/src/pages/Mirror/list.less index 1ecb6fc8..edd9183d 100644 --- a/react-ui/src/pages/Mirror/list.less +++ b/react-ui/src/pages/Mirror/list.less @@ -1,10 +1,11 @@ +@import '@/styles/theme.less'; + .mirror-list { height: 100%; - background-color: #f9fafb; &__tabs-container { height: 49px; padding-left: 27px; - background-image: url('../../assets/img/mirror-tabs-bg.png'); + background-image: url('../../assets/img/page-title-bg.png'); } &__content { @@ -24,20 +25,6 @@ &__table { height: calc(100% - 44px); margin-top: 12px; - :global { - .ant-table-wrapper { - height: 100%; - .ant-spin-nested-loading { - height: 100%; - } - .ant-spin-container { - height: 100%; - } - .ant-table { - height: calc(100% - 74px); - } - } - } } } } diff --git a/react-ui/src/pages/Mirror/list.tsx b/react-ui/src/pages/Mirror/list.tsx index 8269f17b..53136147 100644 --- a/react-ui/src/pages/Mirror/list.tsx +++ b/react-ui/src/pages/Mirror/list.tsx @@ -3,12 +3,13 @@ * @Date: 2024-04-16 13:58:08 * @Description: 镜像列表 */ +import KFIcon from '@/components/KFIcon'; import { CommonTabKeys } from '@/enums'; -import { useDomSize } from '@/hooks'; import { getMirrorListReq } from '@/services/mirror'; import { to } from '@/utils/promise'; -import { Icon } from '@umijs/max'; -import { Button, Input, Table, Tabs } from 'antd'; +import { Icon, useNavigate } from '@umijs/max'; +import { Button, Input, Table, TablePaginationConfig, TableProps, Tabs } from 'antd'; +import classNames from 'classnames'; import dayjs from 'dayjs'; import { useEffect, useState } from 'react'; import styles from './list.less'; @@ -26,11 +27,19 @@ const mirrorTabItems = [ }, ]; +export type MirrorData = { + id: number; + name: string; + description: string; + create_time: string; +}; + function MirrorList() { + const navgite = useNavigate(); const [activeTab, setActiveTab] = useState('Public'); - const [tableData, setTableData] = useState([]); - const [contentRef, { height: tableHeight }] = useDomSize(0, 0); - const [pagination, setPagination] = useState({ + const [searchText, setSearchText] = useState(''); + const [tableData, setTableData] = useState([]); + const [pagination, setPagination] = useState({ showSizeChanger: true, showQuickJumper: true, current: 1, @@ -38,10 +47,56 @@ function MirrorList() { total: 0, }); useEffect(() => { - getMirrorList(''); + getMirrorList(); }, [activeTab]); - const columns = [ + // 获取镜像列表 + const getMirrorList = async () => { + const params = { + page: pagination.current! - 1, + size: pagination.pageSize, + name: searchText, + image_type: activeTab === CommonTabKeys.Public ? 1 : 0, + }; + const [res] = await to(getMirrorListReq(params)); + if (res && res.data) { + const { content = [], totalElements = 0 } = res.data; + setTableData(content); + setPagination((prev) => ({ + ...prev, + total: totalElements, + })); + } + }; + + // 搜索 + const onSearch = () => { + getMirrorList(); + }; + + // 查看详情 + const toDetail = (record: MirrorData) => { + console.log('record', record); + navgite({ + pathname: `/dataset/mirror/${record.id}?isPublic=${activeTab === CommonTabKeys.Public}`, + }); + }; + + // 创建镜像 + const createMirror = () => { + navgite({ pathname: `/dataset/mirror/create?isPublic=${activeTab === CommonTabKeys.Public}` }); + }; + + // 分页切换 + const handleTableChange: TableProps['onChange'] = (pagination, filters, sorter, { action }) => { + if (action === 'paginate') { + setPagination(pagination); + getMirrorList(); + } + console.log(pagination, filters, sorter, action); + }; + + const columns: TableProps['columns'] = [ { title: '镜像名称', dataIndex: 'name', @@ -71,45 +126,38 @@ function MirrorList() { { title: '操作', dataIndex: 'operation', - width: '100px', + width: '15%', key: 'operation', - render: (_: any, record: any) => [ - , - ], + render: (_: any, record: any) => ( +
+ + {activeTab === CommonTabKeys.Private && ( + + )} +
+ ), }, ]; - const getMirrorList = async (name: string) => { - const params = { - page: pagination.current - 1, - size: pagination.pageSize, - name, - image_type: activeTab === CommonTabKeys.Public ? 1 : 0, - }; - const [res] = await to(getMirrorListReq(params)); - if (res && res.data) { - const { content = [], totalElements = 0 } = res.data; - console.log(res); - setTableData(content); - setPagination((prev) => ({ - ...prev, - total: totalElements, - })); - } - }; - - const onSearch = (value: string) => { - getMirrorList(value); - }; - return (
@@ -126,21 +174,36 @@ function MirrorList() { placeholder="按数据集名称筛选" allowClear onSearch={onSearch} + onChange={(e) => setSearchText(e.target.value)} style={{ width: 300 }} + value={searchText} /> + {activeTab === CommonTabKeys.Private && ( + + )}
-
+
diff --git a/react-ui/src/pages/Pipeline/editPipeline/props.jsx b/react-ui/src/pages/Pipeline/editPipeline/props.jsx index 5ed82de9..b6f2c1f9 100644 --- a/react-ui/src/pages/Pipeline/editPipeline/props.jsx +++ b/react-ui/src/pages/Pipeline/editPipeline/props.jsx @@ -80,6 +80,8 @@ const Props = forwardRef(({ onParentChange }, ref) => { // setTimeout(() => { // console.log(stagingItem); // }, (500)); + setSelectedModel(undefined); + setSelectedDataset(undefined); setOpen(true); } }, diff --git a/react-ui/src/services/mirror/index.ts b/react-ui/src/services/mirror/index.ts index ca6fcf71..544d63d4 100644 --- a/react-ui/src/services/mirror/index.ts +++ b/react-ui/src/services/mirror/index.ts @@ -13,10 +13,33 @@ export function getMirrorListReq(params: any) { }); } -// // 分页查询镜像列表 -// export function getMirrorList(params: any) { -// return request(`/image/`, { -// method: 'GET', -// params, -// }); -// } +// 查询镜像详情 +export function getMirrorInfoReq(id: number) { + return request(`/api/mmp/image/${id}`, { + method: 'GET', + }); +} + +// 查询镜像版本列表 +export function getMirrorVersionListReq(params: any) { + return request(`/api/mmp/imageVersion/`, { + method: 'GET', + params, + }); +} + +// 创建公网镜像 +export function createPublicMirrorReq(data: any) { + return request(`/api/mmp/image/net`, { + method: 'POST', + data, + }); +} + +// 创建本地镜像 +export function createPrivateMirrorReq(data: any) { + return request(`/api/mmp/image/local`, { + method: 'POST', + data, + }); +} diff --git a/react-ui/src/styles/theme.less b/react-ui/src/styles/theme.less index 8f33148d..9f6aaace 100644 --- a/react-ui/src/styles/theme.less +++ b/react-ui/src/styles/theme.less @@ -1,7 +1,10 @@ // 全局颜色变量 // FIXME: 不能设置 @primary-color 不起作用,感觉是哪里被重置了 @kf-primary-color: #1664ff; // 主色调 +@primary-color-hover: #4086ff; +@background-color: #f9fafb; // 页面背景颜色 @text-color: #1d1d20; +@text-color-second: #575757; @font-size: 15px; @border-color: rgba(22, 100, 255, 0.3); @border-color-second: rgba(22, 100, 255, 0.1);