| @@ -19,7 +19,7 @@ const Settings: ProLayoutProps & { | |||||
| title: '复杂智能软件', | title: '复杂智能软件', | ||||
| pwa: true, | pwa: true, | ||||
| logo: '/assets/images/left-top-logo.png', | logo: '/assets/images/left-top-logo.png', | ||||
| iconfontUrl: '//at.alicdn.com/t/c/font_4509211_dfghcwme8ki.js', | |||||
| iconfontUrl: '//at.alicdn.com/t/c/font_4511326_ndnvm4elll.js', | |||||
| token: { | token: { | ||||
| // 参见ts声明,demo 见文档,通过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 | //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 | ||||
| @@ -144,6 +144,16 @@ export default [ | |||||
| path: '', | path: '', | ||||
| component: './Mirror/list', | component: './Mirror/list', | ||||
| }, | }, | ||||
| { | |||||
| name: '镜像详情', | |||||
| path: ':id', | |||||
| component: './Mirror/info', | |||||
| }, | |||||
| { | |||||
| name: '创建镜像', | |||||
| path: 'create', | |||||
| component: './Mirror/create', | |||||
| }, | |||||
| ], | ], | ||||
| }, | }, | ||||
| { | { | ||||
| @@ -0,0 +1,31 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-04-17 12:53:06 | |||||
| * @Description: | |||||
| */ | |||||
| import '@/iconfont/iconfont.js'; | |||||
| import { createFromIconfontCN } from '@ant-design/icons'; | |||||
| const Icon = createFromIconfontCN({ | |||||
| scriptUrl: '', | |||||
| }); | |||||
| type IconFontProps = Parameters<typeof Icon>[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 <Icon type={type} style={iconStyle} />; | |||||
| } | |||||
| export default KFIcon; | |||||
| @@ -1,7 +1,11 @@ | |||||
| .kf-modal { | .kf-modal { | ||||
| .ant-modal-content { | .ant-modal-content { | ||||
| padding: 20px 67px; | padding: 20px 67px; | ||||
| background: linear-gradient(180deg, #cfdfff 0%, #d4e2ff 9.77%, #ffffff 40%, #ffffff 100%); | |||||
| background-image: url(/assets/images/modal-back.png); | |||||
| background-repeat:no-repeat; | |||||
| background-size:100%; | |||||
| background-position: top center; | |||||
| // background: linear-gradient(180deg, #cfdfff 0%, #d4e2ff 9.77%, #ffffff 40%, #ffffff 100%); | |||||
| border-radius: 21px; | border-radius: 21px; | ||||
| } | } | ||||
| .ant-modal-header { | .ant-modal-header { | ||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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 ( | |||||
| <span className={'kf-radio'}> | |||||
| {items.map((item) => { | |||||
| return ( | |||||
| <span | |||||
| key={item.key} | |||||
| className={ | |||||
| value === item.key | |||||
| ? classNames('kf-radio__item', 'kf-radio__item--active') | |||||
| : 'kf-radio__item' | |||||
| } | |||||
| onClick={() => onChange?.(item.key)} | |||||
| > | |||||
| {item.icon} | |||||
| <span style={{ marginLeft: '5px' }}>{item.title}</span> | |||||
| </span> | |||||
| ); | |||||
| })} | |||||
| </span> | |||||
| ); | |||||
| } | |||||
| export default KFRadio; | |||||
| @@ -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'); | |||||
| } | |||||
| @@ -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 ( | |||||
| <div className={classNames('kf-page-title', className)} style={style}> | |||||
| {title} | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default PageTitle; | |||||
| @@ -0,0 +1,8 @@ | |||||
| @import '@/styles/theme.less'; | |||||
| .kf-subarea-title { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| color: @text-color; | |||||
| font-size: 16px; | |||||
| } | |||||
| @@ -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 ( | |||||
| <div className={'kf-subarea-title'} style={style}> | |||||
| <img src={image} width={14} /> | |||||
| <span style={{ marginLeft: '8px' }}>{title}</span> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default SubAreaTitle; | |||||
| @@ -51,10 +51,37 @@ a { | |||||
| } | } | ||||
| .ant-menu-light .ant-menu-item-selected { | .ant-menu-light .ant-menu-item-selected { | ||||
| background: rgba(197, 232, 255, 0.8) !important; | background: rgba(197, 232, 255, 0.8) !important; | ||||
| } | |||||
| .ant-menu-light .ant-menu-item-selected .ant-pro-base-menu-inline-item-text{ | |||||
| color:#1664ff; | |||||
| } | } | ||||
| .ant-pro-layout .ant-pro-sider .ant-layout-sider-children { | .ant-pro-layout .ant-pro-sider .ant-layout-sider-children { | ||||
| background: #f2f5f7; | background: #f2f5f7; | ||||
| } | } | ||||
| .ant-pro-base-menu-inline-item-title .ant-pro-base-menu-inline-item-text{ | |||||
| color:#1d1d20; | |||||
| font-size:16px; | |||||
| } | |||||
| // .ant-menu-light .ant-menu-item-selected{ | |||||
| // color:#1664ff; | |||||
| // } | |||||
| .ant-pro-layout .ant-pro-sider-menu{ | |||||
| padding-top: 40px; | |||||
| } | |||||
| .ant-pro-global-header-logo-mix{ | |||||
| 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; | |||||
| } | |||||
| .ant-pro-layout .ant-pro-sider .ant-layout-sider-children{ | |||||
| border-right: unset; | |||||
| border-bottom-right-radius: 20px; | |||||
| } | |||||
| .ant-pro-base-menu-inline { | .ant-pro-base-menu-inline { | ||||
| // height: 87vh; | // height: 87vh; | ||||
| background: #f2f5f7; | background: #f2f5f7; | ||||
| @@ -63,19 +90,31 @@ a { | |||||
| .ant-pro-layout .ant-pro-layout-content { | .ant-pro-layout .ant-pro-layout-content { | ||||
| background-color: transparent; | background-color: transparent; | ||||
| } | } | ||||
| .ant-drawer .ant-drawer-body{ | |||||
| padding: 0; | |||||
| } | |||||
| .ant-drawer .ant-drawer-body .ant-row{ | |||||
| padding: 0 24px; | |||||
| } | |||||
| .ant-drawer .ant-drawer-body .ant-form-item{ | |||||
| margin-bottom: 20px; | |||||
| } | |||||
| .ant-menu .ant-menu-submenu-title .anticon { | |||||
| font-size: 16px; | |||||
| } | |||||
| .ant-table-wrapper .ant-table-pagination.ant-pagination { | .ant-table-wrapper .ant-table-pagination.ant-pagination { | ||||
| margin: 0; | margin: 0; | ||||
| padding: 21px 16px; | padding: 21px 16px; | ||||
| background-color: #fff; | background-color: #fff; | ||||
| } | } | ||||
| .ant-table-wrapper .ant-table { | .ant-table-wrapper .ant-table { | ||||
| height: 75vh; | |||||
| height: 81vh; | |||||
| } | } | ||||
| .ant-pro-global-header-logo img { | .ant-pro-global-header-logo img { | ||||
| height: 21px; | height: 21px; | ||||
| } | } | ||||
| .ant-pro-layout .ant-layout-sider.ant-pro-sider { | .ant-pro-layout .ant-layout-sider.ant-pro-sider { | ||||
| height: 87vh; | |||||
| height: 94vh; | |||||
| } | } | ||||
| .ant-pro-layout .ant-pro-layout-container { | .ant-pro-layout .ant-pro-layout-container { | ||||
| height: 98vh; | height: 98vh; | ||||
| @@ -139,7 +178,6 @@ border-color: transparent; | |||||
| } | } | ||||
| .ant-modal-confirm-body-wrapper{ | .ant-modal-confirm-body-wrapper{ | ||||
| height:303px; | height:303px; | ||||
| border-radius:21px; | |||||
| background-image: url(/assets/images/modal-back.png); | background-image: url(/assets/images/modal-back.png); | ||||
| background-repeat:no-repeat; | background-repeat:no-repeat; | ||||
| background-size:100%; | background-size:100%; | ||||
| @@ -73,21 +73,28 @@ export function useCallbackState<T>(initialValue: T) { | |||||
| * | * | ||||
| * @param initialWidth - The initial width of the element. | * @param initialWidth - The initial width of the element. | ||||
| * @param initialHeight - The initial height 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. | * @return - A tuple containing the ref to the DOM element, the current width, and the current height. | ||||
| */ | */ | ||||
| export function useDomSize<T extends HTMLElement>(initialWidth: number, initialHeight: number) { | |||||
| export function useDomSize<T extends HTMLElement>( | |||||
| initialWidth: number, | |||||
| initialHeight: number, | |||||
| deps: React.DependencyList = [], | |||||
| ) { | |||||
| const domRef = useRef<T>(null); | const domRef = useRef<T>(null); | ||||
| const [width, setWidth] = useState(initialWidth); | const [width, setWidth] = useState(initialWidth); | ||||
| const [height, setHeight] = useState(initialHeight); | const [height, setHeight] = useState(initialHeight); | ||||
| useEffect(() => { | useEffect(() => { | ||||
| console.log('dddddd'); | |||||
| const setDomHeight = () => { | const setDomHeight = () => { | ||||
| if (domRef.current) { | if (domRef.current) { | ||||
| setHeight(domRef.current.offsetHeight); | setHeight(domRef.current.offsetHeight); | ||||
| setWidth(domRef.current.offsetWidth); | setWidth(domRef.current.offsetWidth); | ||||
| } | } | ||||
| }; | }; | ||||
| const debounceFunc = debounce(setDomHeight, 500); | |||||
| const debounceFunc = debounce(setDomHeight, 200); | |||||
| setDomHeight(); | setDomHeight(); | ||||
| window.addEventListener('resize', debounceFunc); | window.addEventListener('resize', debounceFunc); | ||||
| @@ -95,7 +102,7 @@ export function useDomSize<T extends HTMLElement>(initialWidth: number, initialH | |||||
| return () => { | return () => { | ||||
| window.removeEventListener('resize', debounceFunc); | window.removeEventListener('resize', debounceFunc); | ||||
| }; | }; | ||||
| }, [domRef]); | |||||
| }, [domRef, ...deps]); | |||||
| return [domRef, { width, height }] as const; | return [domRef, { width, height }] as const; | ||||
| } | } | ||||
| @@ -0,0 +1 @@ | |||||
| <svg xmlns="http://www.w3.org/2000/svg" width="14.902" height="14.902" viewBox="0 0 14.902 14.902"><defs><style>.a{fill:#1664ff;}</style></defs><g transform="translate(-75.735 -76.787)"><path class="a" d="M87.7,88.735a6.355,6.355,0,1,0-8.985,0A6.355,6.355,0,0,0,87.7,88.735Zm.763.763a7.451,7.451,0,1,1,0-10.519A7.451,7.451,0,0,1,88.464,89.5Z" transform="translate(0 0)"/><path class="a" d="M283.541,282.446H286.5a.552.552,0,0,1,0,1.1h-2.954V286.5a.552.552,0,0,1-1.1,0v-2.954h-2.963a.552.552,0,0,1,0-1.1h2.963v-2.963a.552.552,0,0,1,1.1,0Z" transform="translate(-199.785 -198.751)"/></g></svg> | |||||
| @@ -0,0 +1 @@ | |||||
| <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1713324052180" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1059" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M440.167543 988.161377h-269.463331c-24.790626 0-45.970444-8.784505-63.539453-26.299621A86.551622 86.551622 0 0 1 80.865138 898.322302v-808.389993C80.865138 65.141682 89.649642 43.961865 107.164759 26.446748A86.551622 86.551622 0 0 1 170.704212 0.147127h471.56083a44.407557 44.407557 0 0 1 33.35956 14.874376l202.097498 224.516847a44.515342 44.515342 0 0 1 11.533031 30.072108v202.097498h-89.839075v-202.097498h44.946484l-33.413453 30.018215-202.097498-224.57074 33.413453-30.018215v44.892591h-471.56083v808.389993h269.463331v89.839075z m45.000377-44.892591a44.946484 44.946484 0 0 1-82.45578 25.006197 44.946484 44.946484 0 1 1 74.856914-50.012394 44.730913 44.730913 0 0 1 7.544973 25.006197z m404.194996-471.56083a45.000376 45.000376 0 1 1-90.000752 0 45.000376 45.000376 0 0 1 90.000752 0zM838.757703 933.460321l-112.312317-89.892968 56.156159-70.114358 112.258423 89.839074-56.102265 70.114359z m73.024562-35.138019a44.892591 44.892591 0 0 1-62.192136 41.605139 44.892591 44.892591 0 0 1-7.814437-79.006649 44.892591 44.892591 0 0 1 66.611335 20.20975 44.892591 44.892591 0 0 1 3.395238 17.245653z m-112.258423-89.785182a44.892591 44.892591 0 0 1-53.784881 44.138094 44.892591 44.892591 0 0 1-32.766741-61.383747 44.892591 44.892591 0 0 1 66.557443-20.20975 44.892591 44.892591 0 0 1 19.994179 37.455403z" fill="#D47AEF" p-id="1060"></path><path d="M844.36254 314.503049H619.7918a44.784806 44.784806 0 0 1-44.892591-44.892591V45.039718h89.785182v224.57074H619.7918v-44.946484h224.57074v89.839075z m45.000376-44.892591a44.892591 44.892591 0 0 1-45.000376 45.000376 44.892591 44.892591 0 0 1-45.000376-45.000376 44.892591 44.892591 0 0 1 62.192137-41.605138 44.892591 44.892591 0 0 1 27.808615 41.605138zM664.792176 45.039718a44.892591 44.892591 0 0 1-53.784881 44.138094A44.892591 44.892591 0 0 1 578.294447 27.794065a44.892591 44.892591 0 0 1 66.557443-20.155857 44.892591 44.892591 0 0 1 19.994179 37.40151zM619.7918 494.127306a188.624332 188.624332 0 1 0 0 377.248663 188.624332 188.624332 0 0 0 0-377.248663z m0 88.922899a99.701433 99.701433 0 1 1 0 199.402865 99.701433 99.701433 0 0 1 0-199.402865z" fill="#D47AEF" p-id="1061"></path></svg> | |||||
| @@ -1 +1 @@ | |||||
| <svg xmlns="http://www.w3.org/2000/svg" width="14.239" height="14.266" viewBox="0 0 14.239 14.266" fill="currentColor"><g transform="translate(59 -12320.6)"><path class="a" d="M325.069,355.086a6.46,6.46,0,0,1-4.983-2.344.445.445,0,1,1,.684-.57,5.573,5.573,0,0,0,7.689.869.447.447,0,0,1,.542.712A6.341,6.341,0,0,1,325.069,355.086Zm5.9-4.826a.388.388,0,0,1-.085-.006.445.445,0,0,1-.35-.526,5.641,5.641,0,0,0,.107-1.1,5.548,5.548,0,0,0-3.09-4.993.442.442,0,0,1-.2-.6.447.447,0,0,1,.6-.2,6.443,6.443,0,0,1,3.582,5.79,6.374,6.374,0,0,1-.129,1.276A.442.442,0,0,1,330.972,350.26Zm-11.926-1.389h-.016a.448.448,0,0,1-.435-.463,6.5,6.5,0,0,1,4.965-6.08.448.448,0,0,1,.214.869,5.586,5.586,0,0,0-4.272,5.242A.461.461,0,0,1,319.046,348.871Zm0,0" transform="translate(-376.902 11979.78)"/><path class="a" d="M469.186,298.366a1.783,1.783,0,1,1,1.786-1.78A1.787,1.787,0,0,1,469.186,298.366Z" transform="translate(-521.02 12025.8)"/><path class="a" d="M303.767,323a.891.891,0,1,0,.891.891A.893.893,0,0,0,303.767,323Zm-5.38,11.287a1.786,1.786,0,1,1,1.786-1.786A1.787,1.787,0,0,1,298.386,334.287Z" transform="translate(-355.6 11998.488)"/><path class="a" d="M325.891,568.795a.892.892,0,1,0,.891.892A.893.893,0,0,0,325.891,568.795Zm10.666,2.678a1.786,1.786,0,1,1,1.786-1.786A1.787,1.787,0,0,1,336.558,571.472Z" transform="translate(-383.105 11761.302)"/><path class="a" d="M664.492,596.3a.891.891,0,1,0,.891.891A.893.893,0,0,0,664.492,596.3Z" transform="translate(-711.039 11733.797)"/></g></svg> | |||||
| <svg xmlns="http://www.w3.org/2000/svg" width="14.239" height="14.266" viewBox="0 0 14.239 14.266" fill="currentColor"><defs><style></style></defs><g transform="translate(59 -12320.6)"><path class="a" d="M325.069,355.086a6.46,6.46,0,0,1-4.983-2.344.445.445,0,1,1,.684-.57,5.573,5.573,0,0,0,7.689.869.447.447,0,0,1,.542.712A6.341,6.341,0,0,1,325.069,355.086Zm5.9-4.826a.388.388,0,0,1-.085-.006.445.445,0,0,1-.35-.526,5.641,5.641,0,0,0,.107-1.1,5.548,5.548,0,0,0-3.09-4.993.442.442,0,0,1-.2-.6.447.447,0,0,1,.6-.2,6.443,6.443,0,0,1,3.582,5.79,6.374,6.374,0,0,1-.129,1.276A.442.442,0,0,1,330.972,350.26Zm-11.926-1.389h-.016a.448.448,0,0,1-.435-.463,6.5,6.5,0,0,1,4.965-6.08.448.448,0,0,1,.214.869,5.586,5.586,0,0,0-4.272,5.242A.461.461,0,0,1,319.046,348.871Zm0,0" transform="translate(-376.902 11979.78)"/><path class="a" d="M469.186,298.366a1.783,1.783,0,1,1,1.786-1.78A1.787,1.787,0,0,1,469.186,298.366Z" transform="translate(-521.02 12025.8)"/><path class="a" d="M303.767,323a.891.891,0,1,0,.891.891A.893.893,0,0,0,303.767,323Zm-5.38,11.287a1.786,1.786,0,1,1,1.786-1.786A1.787,1.787,0,0,1,298.386,334.287Z" transform="translate(-355.6 11998.488)"/><path class="a" d="M325.891,568.795a.892.892,0,1,0,.891.892A.893.893,0,0,0,325.891,568.795Zm10.666,2.678a1.786,1.786,0,1,1,1.786-1.786A1.787,1.787,0,0,1,336.558,571.472Z" transform="translate(-383.105 11761.302)"/><path class="a" d="M664.492,596.3a.891.891,0,1,0,.891.891A.893.893,0,0,0,664.492,596.3Z" transform="translate(-711.039 11733.797)"/></g></svg> | |||||
| @@ -1 +0,0 @@ | |||||
| <svg xmlns="http://www.w3.org/2000/svg" width="14.34" height="14.34" viewBox="0 0 14.34 14.34"><defs><style>.a{fill:#1664ff;}</style></defs><path class="a" d="M7.17,0a7.17,7.17,0,1,0,7.17,7.17.664.664,0,1,0-1.328,0A5.894,5.894,0,0,1,7.17,13.012,5.894,5.894,0,0,1,1.328,7.17,5.894,5.894,0,0,1,7.17,1.328a4.9,4.9,0,0,1,3.054.929V2.39h0l-.664.8c-.266.266,0,.8.4.8l3.054.133c.266,0,.531-.4.531-.664L12.614.531A.515.515,0,0,0,11.685.4l-.531.8A7.026,7.026,0,0,0,7.17,0Z"/></svg> | |||||
| @@ -0,0 +1 @@ | |||||
| <svg xmlns="http://www.w3.org/2000/svg" width="14.34" height="14.34" viewBox="0 0 14.34 14.34" fill="currentColor"><path class="a" d="M7.17,0a7.17,7.17,0,1,0,7.17,7.17.664.664,0,1,0-1.328,0A5.894,5.894,0,0,1,7.17,13.012,5.894,5.894,0,0,1,1.328,7.17,5.894,5.894,0,0,1,7.17,1.328a4.9,4.9,0,0,1,3.054.929V2.39h0l-.664.8c-.266.266,0,.8.4.8l3.054.133c.266,0,.531-.4.531-.664L12.614.531A.515.515,0,0,0,11.685.4l-.531.8A7.026,7.026,0,0,0,7.17,0Z"/></svg> | |||||
| @@ -0,0 +1 @@ | |||||
| <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="17" height="17" viewBox="0 0 17 17"><defs><style>.a{fill:#fff;stroke:#707070;}.b{clip-path:url(#a);}.c,.d{fill:#f98e1b;}.c{stroke:#f98e1b;stroke-width:0.2px;}.d{opacity:0.21;}</style><clipPath id="a"><rect class="a" width="17" height="17" transform="translate(1789 324)"/></clipPath></defs><g class="b" transform="translate(-1789 -324)"><g transform="translate(1790.273 325.273)"><path class="c" d="M9.8,11.963H1.359A1.335,1.335,0,0,1,0,10.653V.522A.532.532,0,0,1,.542,0a.538.538,0,0,1,.542.522V10.653a.271.271,0,0,0,.276.266H9.788a.271.271,0,0,0,.276-.266V.522A.532.532,0,0,1,10.605,0a.538.538,0,0,1,.542.522V10.653A1.326,1.326,0,0,1,9.8,11.963Z" transform="translate(1.644 2.491)"/><path class="c" d="M13.9,1.044H.542A.532.532,0,0,1,0,.522.532.532,0,0,1,.542,0H13.912a.532.532,0,0,1,.542.522A.54.54,0,0,1,13.9,1.044Z" transform="translate(0 2.098)"/><path class="c" d="M.542,7.859A.532.532,0,0,1,0,7.337V.522A.532.532,0,0,1,.542,0a.538.538,0,0,1,.542.522V7.337A.538.538,0,0,1,.542,7.859Z" transform="translate(5.246 4.241)"/><path class="c" d="M.542,7.859A.532.532,0,0,1,0,7.337V.522A.532.532,0,0,1,.542,0a.538.538,0,0,1,.542.522V7.337A.526.526,0,0,1,.542,7.859Z" transform="translate(8.458 4.241)"/><path class="c" d="M2.708,1.044H.542A.532.532,0,0,1,0,.522.538.538,0,0,1,.542,0H2.718A.532.532,0,0,1,3.26.522.54.54,0,0,1,2.708,1.044Z" transform="translate(5.597)"/><rect class="d" width="6" height="7" transform="translate(6 2.454)"/></g></g></svg> | |||||
| @@ -1 +1 @@ | |||||
| <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="17" height="17" viewBox="0 0 17 17" fill="currentColor"><defs><style>.a{fill:#fff;stroke:#1431b3;}.b{clip-path:url(#a);}.c,.d{}.c{opacity:0.21;}</style><clipPath id="a"><rect class="a" width="17" height="17" transform="translate(1607 208)"/></clipPath></defs><g class="b" transform="translate(-1607 -208)"><g transform="translate(-0.136 -0.214)"><rect class="c" width="4.75" height="8.011" rx="2" transform="translate(1617.532 209.427)"/><g transform="translate(1511.991 145.627)"><path class="d" d="M282,256.622a.524.524,0,0,0-.522-.522h-6.657a.522.522,0,0,0,0,1.044h6.657A.524.524,0,0,0,282,256.622Zm-7.179,2.6a.522.522,0,0,0,0,1.044h3.109a.522.522,0,0,0,0-1.044Zm7.487,5.349a.464.464,0,0,0-.112-.085,2.565,2.565,0,0,0,.467-1.479,2.631,2.631,0,1,0-2.631,2.6,2.649,2.649,0,0,0,1.443-.425.521.521,0,0,0,.094.13l1.355,1.355a.522.522,0,0,0,.739-.739Zm-2.276.01a1.573,1.573,0,1,1,1.594-1.573A1.584,1.584,0,0,1,280.033,264.581Z" transform="translate(-174.416 -189.172)"/><path class="d" d="M104.819,77.329h-5.8a1.044,1.044,0,0,1-1.041-1.041V65.9a1.044,1.044,0,0,1,1.041-1.041h8.9a1.044,1.044,0,0,1,1.041,1.041v5.18h0v0a.524.524,0,0,0,1.048,0c0-.02,0-.037,0-.057V65.882c0-1.145-.449-2.082-1.594-2.082H99.082A2.089,2.089,0,0,0,97,65.882V76.291a2.089,2.089,0,0,0,2.082,2.082h5.73a.522.522,0,0,0,.007-1.044Z" transform="translate(0 0)"/><path class="d" d="M832.7,607.722a.524.524,0,1,0,.524-.522A.523.523,0,0,0,832.7,607.722Z" transform="translate(-723.731 -534.559)"/></g></g></g></svg> | |||||
| <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="17" height="17" viewBox="0 0 17 17" fill="currentColor"><defs><clipPath id="a"><rect class="a" width="17" height="17" transform="translate(1607 208)"/></clipPath></defs><g class="b" transform="translate(-1607 -208)"><g transform="translate(-0.136 -0.214)"><rect class="c" opacity="0.21" width="4.75" height="8.011" rx="2" transform="translate(1617.532 209.427)"/><g transform="translate(1511.991 145.627)"><path class="d" d="M282,256.622a.524.524,0,0,0-.522-.522h-6.657a.522.522,0,0,0,0,1.044h6.657A.524.524,0,0,0,282,256.622Zm-7.179,2.6a.522.522,0,0,0,0,1.044h3.109a.522.522,0,0,0,0-1.044Zm7.487,5.349a.464.464,0,0,0-.112-.085,2.565,2.565,0,0,0,.467-1.479,2.631,2.631,0,1,0-2.631,2.6,2.649,2.649,0,0,0,1.443-.425.521.521,0,0,0,.094.13l1.355,1.355a.522.522,0,0,0,.739-.739Zm-2.276.01a1.573,1.573,0,1,1,1.594-1.573A1.584,1.584,0,0,1,280.033,264.581Z" transform="translate(-174.416 -189.172)"/><path class="d" d="M104.819,77.329h-5.8a1.044,1.044,0,0,1-1.041-1.041V65.9a1.044,1.044,0,0,1,1.041-1.041h8.9a1.044,1.044,0,0,1,1.041,1.041v5.18h0v0a.524.524,0,0,0,1.048,0c0-.02,0-.037,0-.057V65.882c0-1.145-.449-2.082-1.594-2.082H99.082A2.089,2.089,0,0,0,97,65.882V76.291a2.089,2.089,0,0,0,2.082,2.082h5.73a.522.522,0,0,0,.007-1.044Z" transform="translate(0 0)"/><path class="d" d="M832.7,607.722a.524.524,0,1,0,.524-.522A.523.523,0,0,0,832.7,607.722Z" transform="translate(-723.731 -534.559)"/></g></g></g></svg> | |||||
| @@ -0,0 +1 @@ | |||||
| <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1713324237000" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1430" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M912.384 668.551529v88.545883a99.448471 99.448471 0 0 1-99.568941 99.508706H211.184941a99.448471 99.448471 0 0 1-99.568941-99.508706v-88.545883a49.814588 49.814588 0 0 0-99.568941 0v87.100236a199.800471 199.800471 0 0 0 199.80047 199.80047h600.184471a199.800471 199.800471 0 0 0 199.800471-199.80047v-87.100236a49.814588 49.814588 0 0 0-99.568942 0z" fill="#1664FF" p-id="1431"></path><path d="M728.003765 398.516706a50.778353 50.778353 0 0 0-71.740236 0l-95.171764 95.171765V125.530353a49.814588 49.814588 0 1 0-99.568941 0v368.158118l-95.171765-95.171765a50.718118 50.718118 0 1 0-71.740235 71.740235l177.995294 177.995294a54.753882 54.753882 0 0 0 77.462588 0l177.874823-177.995294a50.537412 50.537412 0 0 0 0.060236-71.740235z" fill="#1664FF" p-id="1432"></path></svg> | |||||
| @@ -1 +0,0 @@ | |||||
| <svg xmlns="http://www.w3.org/2000/svg" width="14.34" height="14.34" viewBox="0 0 14.34 14.34"><defs><style>.a{fill:#1664ff;}</style></defs><path class="a" d="M7.17,0a7.17,7.17,0,1,0,7.17,7.17.664.664,0,1,0-1.328,0A5.894,5.894,0,0,1,7.17,13.012,5.894,5.894,0,0,1,1.328,7.17,5.894,5.894,0,0,1,7.17,1.328a4.9,4.9,0,0,1,3.054.929V2.39h0l-.664.8c-.266.266,0,.8.4.8l3.054.133c.266,0,.531-.4.531-.664L12.614.531A.515.515,0,0,0,11.685.4l-.531.8A7.026,7.026,0,0,0,7.17,0Z"/></svg> | |||||
| @@ -0,0 +1 @@ | |||||
| <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="17" height="17" viewBox="0 0 17 17"><defs><style>.a{fill:#fff;stroke:#1431b3;}.b{clip-path:url(#a);}.c,.d{fill:#1664ff;}.c{opacity:0.21;}</style><clipPath id="a"><rect class="a" width="17" height="17" transform="translate(1607 208)"/></clipPath></defs><g class="b" transform="translate(-1607 -208)"><g transform="translate(-0.136 -0.214)"><rect class="c" width="4.75" height="8.011" rx="2" transform="translate(1617.532 209.427)"/><g transform="translate(1511.991 145.627)"><path class="d" d="M282,256.622a.524.524,0,0,0-.522-.522h-6.657a.522.522,0,0,0,0,1.044h6.657A.524.524,0,0,0,282,256.622Zm-7.179,2.6a.522.522,0,0,0,0,1.044h3.109a.522.522,0,0,0,0-1.044Zm7.487,5.349a.464.464,0,0,0-.112-.085,2.565,2.565,0,0,0,.467-1.479,2.631,2.631,0,1,0-2.631,2.6,2.649,2.649,0,0,0,1.443-.425.521.521,0,0,0,.094.13l1.355,1.355a.522.522,0,0,0,.739-.739Zm-2.276.01a1.573,1.573,0,1,1,1.594-1.573A1.584,1.584,0,0,1,280.033,264.581Z" transform="translate(-174.416 -189.172)"/><path class="d" d="M104.819,77.329h-5.8a1.044,1.044,0,0,1-1.041-1.041V65.9a1.044,1.044,0,0,1,1.041-1.041h8.9a1.044,1.044,0,0,1,1.041,1.041v5.18h0v0a.524.524,0,0,0,1.048,0c0-.02,0-.037,0-.057V65.882c0-1.145-.449-2.082-1.594-2.082H99.082A2.089,2.089,0,0,0,97,65.882V76.291a2.089,2.089,0,0,0,2.082,2.082h5.73a.522.522,0,0,0,.007-1.044Z" transform="translate(0 0)"/><path class="d" d="M832.7,607.722a.524.524,0,1,0,.524-.522A.523.523,0,0,0,832.7,607.722Z" transform="translate(-723.731 -534.559)"/></g></g></g></svg> | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -7,6 +7,7 @@ | |||||
| padding-right: 30px; | padding-right: 30px; | ||||
| background-image: url(/assets/images/pipeline-back.png); | background-image: url(/assets/images/pipeline-back.png); | ||||
| background-size: 100% 100%; | background-size: 100% 100%; | ||||
| font-family: 'Alibaba'; | |||||
| } | } | ||||
| .datasetIntroTopBox { | .datasetIntroTopBox { | ||||
| display: flex; | display: flex; | ||||
| @@ -38,6 +39,7 @@ | |||||
| background: #ffffff; | background: #ffffff; | ||||
| border-radius: 10px; | border-radius: 10px; | ||||
| box-shadow: 0px 2px 12px rgba(180, 182, 191, 0.09); | box-shadow: 0px 2px 12px rgba(180, 182, 191, 0.09); | ||||
| font-family: alibaba; | |||||
| .dataButtonList { | .dataButtonList { | ||||
| display: flex; | display: flex; | ||||
| align-items: center; | align-items: center; | ||||
| @@ -68,6 +70,7 @@ | |||||
| .datasetBox { | .datasetBox { | ||||
| font-family: 'Alibaba'; | font-family: 'Alibaba'; | ||||
| background: #f9fafb; | background: #f9fafb; | ||||
| :global { | :global { | ||||
| .ant-tabs-top > .ant-tabs-nav { | .ant-tabs-top > .ant-tabs-nav { | ||||
| margin: 0; | margin: 0; | ||||
| @@ -104,7 +107,7 @@ | |||||
| display: flex; | display: flex; | ||||
| justify-content: space-between; | justify-content: space-between; | ||||
| width: 100%; | width: 100%; | ||||
| height: 85vh; | |||||
| height: 87.5vh; | |||||
| :global { | :global { | ||||
| .ant-btn { | .ant-btn { | ||||
| color: #1d1d20; | color: #1d1d20; | ||||
| @@ -117,6 +120,7 @@ | |||||
| margin-right: 10px; | margin-right: 10px; | ||||
| padding-top: 15px; | padding-top: 15px; | ||||
| background: #ffffff; | background: #ffffff; | ||||
| font-family: 'Alibaba'; | |||||
| box-shadow: 0px 3px 6px rgba(146, 146, 146, 0.09); | box-shadow: 0px 3px 6px rgba(146, 146, 146, 0.09); | ||||
| .custTab { | .custTab { | ||||
| display: flex; | display: flex; | ||||
| @@ -136,6 +140,7 @@ | |||||
| padding: 15px 20px; | padding: 15px 20px; | ||||
| overflow-x: hidden; | overflow-x: hidden; | ||||
| overflow-y: auto; | overflow-y: auto; | ||||
| font-family: 'Alibaba'; | |||||
| .itemTitle { | .itemTitle { | ||||
| margin-bottom: 15px; | margin-bottom: 15px; | ||||
| color: #1d1d20; | color: #1d1d20; | ||||
| @@ -205,6 +210,7 @@ | |||||
| display: flex; | display: flex; | ||||
| flex: 1; | flex: 1; | ||||
| flex-direction: column; | flex-direction: column; | ||||
| font-family: 'Alibaba'; | |||||
| height: 100%; | height: 100%; | ||||
| padding: 22px 30px 26px 30px; | padding: 22px 30px 26px 30px; | ||||
| background: #ffffff; | background: #ffffff; | ||||
| @@ -223,38 +229,69 @@ | |||||
| flex: 1; | flex: 1; | ||||
| flex-wrap: wrap; | flex-wrap: wrap; | ||||
| align-content: flex-start; | align-content: flex-start; | ||||
| width: 100%; | |||||
| font-family: 'Alibaba'; | |||||
| width: 103%; | |||||
| .dataItem { | .dataItem { | ||||
| position: relative; | position: relative; | ||||
| width: 32%; | |||||
| height: 66px; | |||||
| margin: 0 15px 18px 0; | |||||
| background: rgba(128, 128, 128, 0.05); | |||||
| border-radius: 8px; | |||||
| box-shadow: 0px 0px 12px rgba(75, 84, 137, 0.05); | |||||
| width: 23%; | |||||
| height:164px; | |||||
| background:#ffffff; | |||||
| border:1px solid; | |||||
| border-color:#eaeaea; | |||||
| border-radius:4px; | |||||
| margin: 0 20px 25px 0; | |||||
| cursor: pointer; | cursor: pointer; | ||||
| .itemText { | .itemText { | ||||
| position: absolute; | position: absolute; | ||||
| top: 10px; | |||||
| top: 20px; | |||||
| left: 20px; | left: 20px; | ||||
| color: #1d1d20; | |||||
| font-size: 15px; | |||||
| background: linear-gradient(to right ,rgba(22, 100, 255,0.6) 0,rgba(22, 100, 255,0) 100%); | |||||
| height: 6px; | |||||
| line-height: 0px; | |||||
| color:#1d1d20; | |||||
| font-size:16px; | |||||
| } | |||||
| .itemDescripition{ | |||||
| position: absolute; | |||||
| top: 57px; | |||||
| left: 20px; | |||||
| padding-right: 28px; | |||||
| color:#575757; | |||||
| font-size:14px; | |||||
| word-break: break-all; | |||||
| overflow: hidden; | |||||
| display: -webkit-box; | |||||
| -webkit-line-clamp: 2; | |||||
| -webkit-box-orient: vertical; | |||||
| } | } | ||||
| .itemTime { | .itemTime { | ||||
| position: absolute; | position: absolute; | ||||
| bottom: 10px; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| bottom: 22px; | |||||
| left: 20px; | left: 20px; | ||||
| color: #808080; | color: #808080; | ||||
| font-size: 14px; | |||||
| font-size: 13px; | |||||
| } | } | ||||
| .itemIcon { | .itemIcon { | ||||
| position: absolute; | position: absolute; | ||||
| display: flex; | |||||
| align-items: center; | |||||
| right: 20px; | right: 20px; | ||||
| bottom: 10px; | |||||
| bottom: 22px; | |||||
| color: #808080; | color: #808080; | ||||
| font-size: 14px; | |||||
| font-size: 13px; | |||||
| } | } | ||||
| } | } | ||||
| .dataItem:hover{ | |||||
| border-color: #1664FF; | |||||
| box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.2) | |||||
| } | |||||
| .dataItem:hover .itemText{ | |||||
| color: #1664FF; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,4 +1,6 @@ | |||||
| import { getAccessToken } from '@/access'; | import { getAccessToken } from '@/access'; | ||||
| import clock from '@/assets/img/clock.png'; | |||||
| import creatByImg from '@/assets/img/creatBy.png'; | |||||
| import { addDatesetAndVesion, getAssetIcon, getDatasetList } from '@/services/dataset/index.js'; | import { addDatesetAndVesion, getAssetIcon, getDatasetList } from '@/services/dataset/index.js'; | ||||
| import { getDictSelectOption } from '@/services/system/dict'; | import { getDictSelectOption } from '@/services/system/dict'; | ||||
| import { PlusCircleOutlined, UploadOutlined } from '@ant-design/icons'; | import { PlusCircleOutlined, UploadOutlined } from '@ant-design/icons'; | ||||
| @@ -40,7 +42,7 @@ const PublicData = (React.FC = () => { | |||||
| }; | }; | ||||
| const [queryFlow, setQueryFlow] = useState({ | const [queryFlow, setQueryFlow] = useState({ | ||||
| page: 0, | page: 0, | ||||
| size: 10, | |||||
| size: 20, | |||||
| name: null, | name: null, | ||||
| available_range: 0, | available_range: 0, | ||||
| }); | }); | ||||
| @@ -149,6 +151,11 @@ const PublicData = (React.FC = () => { | |||||
| const onFinishFailed = (errorInfo) => { | const onFinishFailed = (errorInfo) => { | ||||
| console.log('Failed:', 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(() => { | useEffect(() => { | ||||
| getDictSelectOption('available_cluster').then((data) => { | getDictSelectOption('available_cluster').then((data) => { | ||||
| setClusterOptions(data); | setClusterOptions(data); | ||||
| @@ -268,17 +275,19 @@ const PublicData = (React.FC = () => { | |||||
| ? datasetList.map((item) => { | ? datasetList.map((item) => { | ||||
| return ( | return ( | ||||
| <div className={Styles.dataItem} onClick={(e) => routeToIntro(e, item)}> | <div className={Styles.dataItem} onClick={(e) => routeToIntro(e, item)}> | ||||
| <div className={Styles.itemText}>{item.name}</div> | |||||
| <span className={Styles.itemText}>{item.name}</span> | |||||
| <div className={Styles.itemDescripition}>{item.description}</div> | |||||
| <div className={Styles.itemTime}> | <div className={Styles.itemTime}> | ||||
| <span>最近更新: {moment(item.update_time).format('YYYY-MM-DD')}</span> | |||||
| </div> | |||||
| <div className={Styles.itemIcon}> | |||||
| <img | <img | ||||
| style={{ width: '17px', marginRight: '3px' }} | |||||
| src={`/assets/images/upload-icon.png`} | |||||
| style={{ width: '17px', marginRight: '6px' }} | |||||
| src={creatByImg} | |||||
| alt="" | alt="" | ||||
| /> | /> | ||||
| <span>1582</span> | |||||
| <span>{item.create_by}</span> | |||||
| </div> | |||||
| <div className={Styles.itemIcon}> | |||||
| <img style={{ width: '12px', marginRight: '5px' }} src={clock} alt="" /> | |||||
| <span>最近更新: {moment(item.update_time).format('YYYY-MM-DD')}</span> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| ); | ); | ||||
| @@ -286,7 +295,14 @@ const PublicData = (React.FC = () => { | |||||
| : ''} | : ''} | ||||
| {/* <Select.Option value="demo">Demo</Select.Option> */} | {/* <Select.Option value="demo">Demo</Select.Option> */} | ||||
| </div> | </div> | ||||
| <Pagination size="small" total={total} showSizeChanger showQuickJumper /> | |||||
| <Pagination | |||||
| total={total} | |||||
| showSizeChanger | |||||
| defaultPageSize={20} | |||||
| pageSizeOptions={[20, 40, 60, 80, 100]} | |||||
| showQuickJumper | |||||
| onChange={onPageChange} | |||||
| /> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <Modal | <Modal | ||||
| @@ -1,3 +1,5 @@ | |||||
| import clock from '@/assets/img/clock.png'; | |||||
| import creatByImg from '@/assets/img/creatBy.png'; | |||||
| import { getAssetIcon, getDatasetList } from '@/services/dataset/index.js'; | import { getAssetIcon, getDatasetList } from '@/services/dataset/index.js'; | ||||
| import { Form, Input, Pagination } from 'antd'; | import { Form, Input, Pagination } from 'antd'; | ||||
| import moment from 'moment'; | import moment from 'moment'; | ||||
| @@ -109,6 +111,11 @@ const PublicData = (React.FC = () => { | |||||
| const onFinishFailed = (errorInfo) => { | const onFinishFailed = (errorInfo) => { | ||||
| console.log('Failed:', 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(() => { | useEffect(() => { | ||||
| getAssetIconList(iconParams); | getAssetIconList(iconParams); | ||||
| getDatasetlist(queryFlow); | getDatasetlist(queryFlow); | ||||
| @@ -217,17 +224,19 @@ const PublicData = (React.FC = () => { | |||||
| ? datasetList.map((item) => { | ? datasetList.map((item) => { | ||||
| return ( | return ( | ||||
| <div className={Styles.dataItem} onClick={(e) => routeToIntro(e, item)}> | <div className={Styles.dataItem} onClick={(e) => routeToIntro(e, item)}> | ||||
| <div className={Styles.itemText}>{item.name}</div> | |||||
| <span className={Styles.itemText}>{item.name}</span> | |||||
| <div className={Styles.itemDescripition}>{item.description}</div> | |||||
| <div className={Styles.itemTime}> | <div className={Styles.itemTime}> | ||||
| <span>最近更新: {moment(item.update_time).format('YYYY-MM-DD')}</span> | |||||
| </div> | |||||
| <div className={Styles.itemIcon}> | |||||
| <img | <img | ||||
| style={{ width: '17px', marginRight: '3px' }} | |||||
| src={`/assets/images/upload-icon.png`} | |||||
| style={{ width: '17px', marginRight: '6px' }} | |||||
| src={creatByImg} | |||||
| alt="" | alt="" | ||||
| /> | /> | ||||
| <span>1582</span> | |||||
| <span>{item.create_by}</span> | |||||
| </div> | |||||
| <div className={Styles.itemIcon}> | |||||
| <img style={{ width: '12px', marginRight: '5px' }} src={clock} alt="" /> | |||||
| <span>最近更新: {moment(item.update_time).format('YYYY-MM-DD')}</span> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| ); | ); | ||||
| @@ -235,7 +244,14 @@ const PublicData = (React.FC = () => { | |||||
| : ''} | : ''} | ||||
| {/* <Select.Option value="demo">Demo</Select.Option> */} | {/* <Select.Option value="demo">Demo</Select.Option> */} | ||||
| </div> | </div> | ||||
| <Pagination size="small" total={total} showSizeChanger showQuickJumper /> | |||||
| <Pagination | |||||
| total={total} | |||||
| showSizeChanger | |||||
| defaultPageSize={20} | |||||
| pageSizeOptions={[20, 40, 60, 80, 100]} | |||||
| showQuickJumper | |||||
| onChange={onPageChange} | |||||
| /> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </> | </> | ||||
| @@ -1,12 +1,12 @@ | |||||
| .modal { | .modal { | ||||
| :global { | :global { | ||||
| .ant-input { | |||||
| height: 30px; | |||||
| border-color: #e6e6e6; | |||||
| } | |||||
| .ant-select-single { | |||||
| height: 40px; | |||||
| } | |||||
| // .ant-input { | |||||
| // height: 30px; | |||||
| // border-color: #e6e6e6; | |||||
| // } | |||||
| // .ant-select-single { | |||||
| // height: 40px; | |||||
| // } | |||||
| .ant-form-item .ant-form-item-label > label { | .ant-form-item .ant-form-item-label > label { | ||||
| color: rgba(29, 29, 32, 0.8); | color: rgba(29, 29, 32, 0.8); | ||||
| } | } | ||||
| @@ -8,8 +8,8 @@ | |||||
| align-items: center; | align-items: center; | ||||
| width: 100%; | width: 100%; | ||||
| height: 43px; | height: 43px; | ||||
| margin-bottom: 10px; | |||||
| padding: 0 20px; | |||||
| margin-bottom: 20px; | |||||
| padding: 0 24px; | |||||
| color: #1d1d20; | color: #1d1d20; | ||||
| font-size: 15px; | font-size: 15px; | ||||
| font-family: 'Alibaba'; | font-family: 'Alibaba'; | ||||
| @@ -67,7 +67,7 @@ const Props = forwardRef(({ onParentChange }, ref) => { | |||||
| span: 16, | span: 16, | ||||
| }} | }} | ||||
| wrapperCol={{ | wrapperCol={{ | ||||
| span: 16, | |||||
| span: 24, | |||||
| }} | }} | ||||
| style={{ | style={{ | ||||
| maxWidth: 600, | maxWidth: 600, | ||||
| @@ -81,7 +81,7 @@ const Props = forwardRef(({ onParentChange }, ref) => { | |||||
| > | > | ||||
| <div className={Styles.editPipelinePropsContent}> | <div className={Styles.editPipelinePropsContent}> | ||||
| <img | <img | ||||
| style={{ width: '13px', marginRight: '10px' }} | |||||
| style={{ width: '15px', marginRight: '10px' }} | |||||
| src={'/assets/images/static-message.png'} | src={'/assets/images/static-message.png'} | ||||
| alt="" | alt="" | ||||
| /> | /> | ||||
| @@ -113,7 +113,7 @@ const Props = forwardRef(({ onParentChange }, ref) => { | |||||
| </Form.Item> | </Form.Item> | ||||
| <div className={Styles.editPipelinePropsContent}> | <div className={Styles.editPipelinePropsContent}> | ||||
| <img | <img | ||||
| style={{ width: '13px', marginRight: '10px' }} | |||||
| style={{ width: '15px', marginRight: '10px' }} | |||||
| src={'/assets/images/duty-message.png'} | src={'/assets/images/duty-message.png'} | ||||
| alt="" | alt="" | ||||
| /> | /> | ||||
| @@ -136,7 +136,7 @@ const Props = forwardRef(({ onParentChange }, ref) => { | |||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item label="启动命令" name="command"> | <Form.Item label="启动命令" name="command"> | ||||
| <Input disabled /> | |||||
| <TextArea disabled /> | |||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | <Form.Item | ||||
| label="资源规格" | label="资源规格" | ||||
| @@ -195,7 +195,7 @@ const Props = forwardRef(({ onParentChange }, ref) => { | |||||
| : ''} | : ''} | ||||
| <div className={Styles.editPipelinePropsContent}> | <div className={Styles.editPipelinePropsContent}> | ||||
| <img | <img | ||||
| style={{ width: '13px', marginRight: '10px' }} | |||||
| style={{ width: '15px', marginRight: '10px' }} | |||||
| src={'/assets/images/duty-message.png'} | src={'/assets/images/duty-message.png'} | ||||
| alt="" | alt="" | ||||
| /> | /> | ||||
| @@ -390,12 +390,13 @@ const Props = forwardRef(({ onParentChange }, ref) => { | |||||
| <Drawer | <Drawer | ||||
| title="任务执行详情" | title="任务执行详情" | ||||
| placement="right" | placement="right" | ||||
| rootStyle={{ marginTop: '45px' }} | |||||
| rootStyle={{ marginTop: '68px' }} | |||||
| getContainer={false} | |||||
| closeIcon={false} | closeIcon={false} | ||||
| onClose={onClose} | onClose={onClose} | ||||
| afterOpenChange={afterOpenChange} | afterOpenChange={afterOpenChange} | ||||
| open={open} | open={open} | ||||
| width={600} | |||||
| width={420} | |||||
| destroyOnClose={true} | destroyOnClose={true} | ||||
| > | > | ||||
| <div className={Styles.detailBox}>任务名称:{stagingItem.label}</div> | <div className={Styles.detailBox}>任务名称:{stagingItem.label}</div> | ||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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 ( | |||||
| <div className={styles['mirror-create']}> | |||||
| <PageTitle title="基本信息"></PageTitle> | |||||
| <div className={styles['mirror-create__content']}> | |||||
| <div> | |||||
| <Form | |||||
| name="mirror-create" | |||||
| labelCol={{ flex: '120px' }} | |||||
| wrapperCol={{ flex: 1 }} | |||||
| labelAlign="left" | |||||
| form={form} | |||||
| initialValues={{ type: CommonTabKeys.Public }} | |||||
| onFinish={handleSubmit} | |||||
| > | |||||
| <SubAreaTitle | |||||
| title="基本信息" | |||||
| image={require('@/assets/img/mirror-basic.png')} | |||||
| style={{ marginBottom: '26px' }} | |||||
| ></SubAreaTitle> | |||||
| <Row gutter={10}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="镜像名称及Tag" | |||||
| name="name" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入镜像名称', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input placeholder="请输入镜像名称" maxLength={64} showCount allowClear /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label=" " | |||||
| name="tag" | |||||
| labelCol={{ flex: '20px' }} | |||||
| wrapperCol={{ flex: 1 }} | |||||
| required={false} | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入镜像Tag', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input placeholder="请输入镜像Tag" maxLength={64} showCount allowClear /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={10}> | |||||
| <Col span={20}> | |||||
| <Form.Item | |||||
| label="镜像描述" | |||||
| name="description" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入镜像描述', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input.TextArea | |||||
| autoSize={{ minRows: 2, maxRows: 6 }} | |||||
| placeholder="请输入镜像描述,最长128字符" | |||||
| maxLength={128} | |||||
| showCount | |||||
| allowClear | |||||
| /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <SubAreaTitle | |||||
| title="镜像构建" | |||||
| image={require('@/assets/img/mirror-version.png')} | |||||
| style={{ marginTop: '20px', marginBottom: '24px' }} | |||||
| ></SubAreaTitle> | |||||
| <Row gutter={10}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="构建方式" | |||||
| name="type" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请选择构建方式', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <KFRadio items={mirrorRadioItems}></KFRadio> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Form.Item | |||||
| noStyle | |||||
| shouldUpdate={(prevValues, curValues) => prevValues.type !== curValues.type} | |||||
| > | |||||
| {({ getFieldValue }) => { | |||||
| const type = getFieldValue('type'); | |||||
| if (type === CommonTabKeys.Public) { | |||||
| return ( | |||||
| <> | |||||
| <Row gutter={10}> | |||||
| <Col span={10}> | |||||
| <Form.Item label="仓库类型" required> | |||||
| <span>公网</span> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={10}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="镜像地址" | |||||
| name="path" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入镜像地址', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input | |||||
| placeholder="请输入镜像地址" | |||||
| maxLength={128} | |||||
| showCount | |||||
| allowClear | |||||
| /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| </> | |||||
| ); | |||||
| } else { | |||||
| return ( | |||||
| <> | |||||
| <Row gutter={10}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="镜像文件" | |||||
| name="path" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请上传镜像地址', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| {/* <Upload {...props} data={{ uuid: uuid }}> | |||||
| <Button | |||||
| style={{ | |||||
| fontSize: '14px', | |||||
| border: '1px solid', | |||||
| borderColor: '#1664ff', | |||||
| background: '#fff', | |||||
| }} | |||||
| icon={<UploadOutlined style={{ color: '#1664ff' }} />} | |||||
| > | |||||
| 上传文件 | |||||
| </Button> | |||||
| </Upload> */} | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| </> | |||||
| ); | |||||
| } | |||||
| }} | |||||
| </Form.Item> | |||||
| <Form.Item wrapperCol={{ offset: 0, span: 16 }}> | |||||
| <Button type="primary" htmlType="submit"> | |||||
| 创建镜像 | |||||
| </Button> | |||||
| <Button type="default" htmlType="reset" style={{ marginLeft: '20px' }}> | |||||
| 取消 | |||||
| </Button> | |||||
| </Form.Item> | |||||
| </Form> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default MirrorCreate; | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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<MirrorInfoData>({}); | |||||
| const [tableData, setTableData] = useState<MirrorVersionData[]>([]); | |||||
| const [topRef, { height: topHeight }] = useDomSize<HTMLDivElement>(0, 0, [mirrorInfo]); | |||||
| const [pagination, setPagination] = useState<TablePaginationConfig>({ | |||||
| 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<MirrorVersionData>['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) => <span>{dayjs(text).format('YYYY-MM-DD HH:mm:ss')}</span>, | |||||
| }, | |||||
| { | |||||
| title: '操作', | |||||
| dataIndex: 'operation', | |||||
| width: '20%', | |||||
| key: 'operation', | |||||
| render: (_: any, record: any) => ( | |||||
| <div> | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| key="info" | |||||
| // icon={<Icon icon="local:view-detail" style={{ verticalAlign: '-4px' }} />} | |||||
| //icon={<MyIcon type="icon-shiyanduibi" style={{ fontSize: '16px' }}></MyIcon>} | |||||
| onClick={() => downloadVersion(record)} | |||||
| > | |||||
| 下载 | |||||
| </Button> | |||||
| {!isPublic && ( | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| key="remove" | |||||
| // icon={<MyIcon type="icon-shiyanduibi" style={{ fontSize: '16px' }}></MyIcon>} | |||||
| // icon={<Icon icon="local:view-detail" style={{ verticalAlign: '-2px' }} />} | |||||
| onClick={() => removeVersion(record)} | |||||
| > | |||||
| 删除 | |||||
| </Button> | |||||
| )} | |||||
| </div> | |||||
| ), | |||||
| }, | |||||
| ]; | |||||
| return ( | |||||
| <div className={styles['mirror-info']}> | |||||
| <PageTitle title="镜像详情"></PageTitle> | |||||
| <div className={styles['mirror-info__content']}> | |||||
| <div ref={topRef}> | |||||
| <SubAreaTitle | |||||
| title="基本信息" | |||||
| image={require('@/assets/img/mirror-basic.png')} | |||||
| style={{ marginBottom: '26px' }} | |||||
| ></SubAreaTitle> | |||||
| <div className={styles['mirror-info__basic']}> | |||||
| <Row gutter={40} style={{ marginBottom: '20px' }}> | |||||
| <Col span={10}> | |||||
| <div className={styles['mirror-info__basic__item']}> | |||||
| <div className={styles['label']}>镜像名称:</div> | |||||
| <div className={styles['value']}>{mirrorInfo.name}</div> | |||||
| </div> | |||||
| </Col> | |||||
| <Col span={10}> | |||||
| <div className={styles['mirror-info__basic__item']}> | |||||
| <div className={styles['label']}>版本数:</div> | |||||
| <div className={styles['value']}>{mirrorInfo.version_count}</div> | |||||
| </div> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={40}> | |||||
| <Col span={10}> | |||||
| <div className={styles['mirror-info__basic__item']}> | |||||
| <div className={styles['label']}>镜像描述:</div> | |||||
| <div className={styles['value']}>{mirrorInfo.description}</div> | |||||
| </div> | |||||
| </Col> | |||||
| <Col span={10}> | |||||
| <div className={styles['mirror-info__basic__item']}> | |||||
| <div className={styles['label']}>创建时间:</div> | |||||
| <div className={styles['value']}>{mirrorInfo.create_time}</div> | |||||
| </div> | |||||
| </Col> | |||||
| </Row> | |||||
| </div> | |||||
| <SubAreaTitle | |||||
| title="镜像版本" | |||||
| image={require('@/assets/img/mirror-version.png')} | |||||
| style={{ marginTop: '40px' }} | |||||
| ></SubAreaTitle> | |||||
| </div> | |||||
| <div | |||||
| className={classNames('vertical-scroll-table', styles['mirror-info__content__table'])} | |||||
| style={{ marginTop: '24px', height: `calc(100% - ${topHeight + 24}px)` }} | |||||
| > | |||||
| <Table | |||||
| dataSource={tableData} | |||||
| columns={columns} | |||||
| scroll={{ y: 'calc(100% - 55px)' }} | |||||
| pagination={pagination} | |||||
| onChange={handleTableChange} | |||||
| rowKey="id" | |||||
| /> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default MirrorInfo; | |||||
| @@ -1,10 +1,11 @@ | |||||
| @import '@/styles/theme.less'; | |||||
| .mirror-list { | .mirror-list { | ||||
| height: 100%; | height: 100%; | ||||
| background-color: #f9fafb; | |||||
| &__tabs-container { | &__tabs-container { | ||||
| height: 49px; | height: 49px; | ||||
| padding-left: 27px; | padding-left: 27px; | ||||
| background-image: url('../../assets/img/mirror-tabs-bg.png'); | |||||
| background-image: url('../../assets/img/page-title-bg.png'); | |||||
| } | } | ||||
| &__content { | &__content { | ||||
| @@ -24,20 +25,6 @@ | |||||
| &__table { | &__table { | ||||
| height: calc(100% - 44px); | height: calc(100% - 44px); | ||||
| margin-top: 12px; | 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); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -3,12 +3,13 @@ | |||||
| * @Date: 2024-04-16 13:58:08 | * @Date: 2024-04-16 13:58:08 | ||||
| * @Description: 镜像列表 | * @Description: 镜像列表 | ||||
| */ | */ | ||||
| import KFIcon from '@/components/KFIcon'; | |||||
| import { CommonTabKeys } from '@/enums'; | import { CommonTabKeys } from '@/enums'; | ||||
| import { useDomSize } from '@/hooks'; | |||||
| import { getMirrorListReq } from '@/services/mirror'; | import { getMirrorListReq } from '@/services/mirror'; | ||||
| import { to } from '@/utils/promise'; | 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 dayjs from 'dayjs'; | ||||
| import { useEffect, useState } from 'react'; | import { useEffect, useState } from 'react'; | ||||
| import styles from './list.less'; | 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() { | function MirrorList() { | ||||
| const navgite = useNavigate(); | |||||
| const [activeTab, setActiveTab] = useState('Public'); | const [activeTab, setActiveTab] = useState('Public'); | ||||
| const [tableData, setTableData] = useState([]); | |||||
| const [contentRef, { height: tableHeight }] = useDomSize<HTMLDivElement>(0, 0); | |||||
| const [pagination, setPagination] = useState({ | |||||
| const [searchText, setSearchText] = useState(''); | |||||
| const [tableData, setTableData] = useState<MirrorData[]>([]); | |||||
| const [pagination, setPagination] = useState<TablePaginationConfig>({ | |||||
| showSizeChanger: true, | showSizeChanger: true, | ||||
| showQuickJumper: true, | showQuickJumper: true, | ||||
| current: 1, | current: 1, | ||||
| @@ -38,10 +47,56 @@ function MirrorList() { | |||||
| total: 0, | total: 0, | ||||
| }); | }); | ||||
| useEffect(() => { | useEffect(() => { | ||||
| getMirrorList(''); | |||||
| getMirrorList(); | |||||
| }, [activeTab]); | }, [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<MirrorData>['columns'] = [ | |||||
| { | { | ||||
| title: '镜像名称', | title: '镜像名称', | ||||
| dataIndex: 'name', | dataIndex: 'name', | ||||
| @@ -71,45 +126,38 @@ function MirrorList() { | |||||
| { | { | ||||
| title: '操作', | title: '操作', | ||||
| dataIndex: 'operation', | dataIndex: 'operation', | ||||
| width: '100px', | |||||
| width: '15%', | |||||
| key: 'operation', | key: 'operation', | ||||
| render: (_: any, record: any) => [ | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| key="download" | |||||
| icon={<Icon icon="local:view-detail" style={{ verticalAlign: '-4px' }} />} | |||||
| // onClick={(e) => downloadAlone(e, record)} | |||||
| > | |||||
| 查看详情 | |||||
| </Button>, | |||||
| ], | |||||
| render: (_: any, record: any) => ( | |||||
| <div> | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| key="info" | |||||
| // icon={<Icon icon="local:view-detail" style={{ verticalAlign: '-4px' }} />} | |||||
| icon={<KFIcon type="icon-chakanxiangqing" />} | |||||
| onClick={() => toDetail(record)} | |||||
| > | |||||
| 查看详情 | |||||
| </Button> | |||||
| {activeTab === CommonTabKeys.Private && ( | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| key="remove" | |||||
| icon={<KFIcon type="icon-shiyanduibi1" />} | |||||
| // icon={<Icon icon="local:view-detail" style={{ verticalAlign: '-2px' }} />} | |||||
| // onClick={(e) => downloadAlone(e, record)} | |||||
| > | |||||
| 删除 | |||||
| </Button> | |||||
| )} | |||||
| </div> | |||||
| ), | |||||
| }, | }, | ||||
| ]; | ]; | ||||
| 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 ( | return ( | ||||
| <div className={styles['mirror-list']}> | <div className={styles['mirror-list']}> | ||||
| <div className={styles['mirror-list__tabs-container']}> | <div className={styles['mirror-list__tabs-container']}> | ||||
| @@ -126,21 +174,36 @@ function MirrorList() { | |||||
| placeholder="按数据集名称筛选" | placeholder="按数据集名称筛选" | ||||
| allowClear | allowClear | ||||
| onSearch={onSearch} | onSearch={onSearch} | ||||
| onChange={(e) => setSearchText(e.target.value)} | |||||
| style={{ width: 300 }} | style={{ width: 300 }} | ||||
| value={searchText} | |||||
| /> | /> | ||||
| {activeTab === CommonTabKeys.Private && ( | |||||
| <Button | |||||
| style={{ marginLeft: '20px' }} | |||||
| type="default" | |||||
| onClick={createMirror} | |||||
| icon={<Icon icon="local:refresh" style={{ verticalAlign: '-2px' }} />} | |||||
| > | |||||
| 制作镜像 | |||||
| </Button> | |||||
| )} | |||||
| <Button | <Button | ||||
| type="primary" | |||||
| icon={<Icon icon="local:refresh-btn" style={{ verticalAlign: '-2px' }} />} | |||||
| style={{ marginRight: 0, marginLeft: 'auto' }} | |||||
| type="default" | |||||
| onClick={getMirrorList} | |||||
| icon={<Icon icon="local:refresh" style={{ verticalAlign: '-2px' }} />} | |||||
| > | > | ||||
| 刷新 | 刷新 | ||||
| </Button> | </Button> | ||||
| </div> | </div> | ||||
| <div className={styles['mirror-list__content__table']} ref={contentRef}> | |||||
| <div className={classNames('vertical-scroll-table', styles['mirror-list__content__table'])}> | |||||
| <Table | <Table | ||||
| dataSource={tableData} | dataSource={tableData} | ||||
| columns={columns} | columns={columns} | ||||
| scroll={{ y: tableHeight - 55 - 74 }} | |||||
| scroll={{ y: 'calc(100% - 55px)' }} | |||||
| pagination={pagination} | pagination={pagination} | ||||
| onChange={handleTableChange} | |||||
| rowKey="id" | rowKey="id" | ||||
| /> | /> | ||||
| </div> | </div> | ||||
| @@ -105,7 +105,7 @@ | |||||
| display: flex; | display: flex; | ||||
| justify-content: space-between; | justify-content: space-between; | ||||
| width: 100%; | width: 100%; | ||||
| height: 85vh; | |||||
| height: 87.5vh; | |||||
| .datasetCneterLeftBox { | .datasetCneterLeftBox { | ||||
| width: 340px; | width: 340px; | ||||
| @@ -222,35 +222,65 @@ | |||||
| width: 100%; | width: 100%; | ||||
| .dataItem { | .dataItem { | ||||
| position: relative; | position: relative; | ||||
| width: 32%; | |||||
| height: 66px; | |||||
| margin: 0 15px 18px 0; | |||||
| background: rgba(128, 128, 128, 0.05); | |||||
| border-radius: 8px; | |||||
| box-shadow: 0px 0px 12px rgba(75, 84, 137, 0.05); | |||||
| width: 23%; | |||||
| height:164px; | |||||
| background:#ffffff; | |||||
| border:1px solid; | |||||
| border-color:#eaeaea; | |||||
| border-radius:4px; | |||||
| margin: 0 20px 25px 0; | |||||
| cursor: pointer; | cursor: pointer; | ||||
| .itemText { | .itemText { | ||||
| position: absolute; | position: absolute; | ||||
| top: 10px; | |||||
| top: 20px; | |||||
| left: 20px; | left: 20px; | ||||
| color: #1d1d20; | |||||
| font-size: 15px; | |||||
| background: linear-gradient(to right ,rgba(22, 100, 255,0.6) 0,rgba(22, 100, 255,0) 100%); | |||||
| height: 6px; | |||||
| line-height: 0px; | |||||
| color:#1d1d20; | |||||
| font-size:16px; | |||||
| } | |||||
| .itemDescripition{ | |||||
| position: absolute; | |||||
| top: 57px; | |||||
| left: 20px; | |||||
| padding-right: 28px; | |||||
| color:#575757; | |||||
| font-size:14px; | |||||
| word-break: break-all; | |||||
| overflow: hidden; | |||||
| display: -webkit-box; | |||||
| -webkit-line-clamp: 2; | |||||
| -webkit-box-orient: vertical; | |||||
| } | } | ||||
| .itemTime { | .itemTime { | ||||
| position: absolute; | position: absolute; | ||||
| bottom: 10px; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| bottom: 22px; | |||||
| left: 20px; | left: 20px; | ||||
| color: #808080; | color: #808080; | ||||
| font-size: 14px; | |||||
| font-size: 13px; | |||||
| } | } | ||||
| .itemIcon { | .itemIcon { | ||||
| position: absolute; | position: absolute; | ||||
| display: flex; | |||||
| align-items: center; | |||||
| right: 20px; | right: 20px; | ||||
| bottom: 10px; | |||||
| bottom: 22px; | |||||
| color: #808080; | color: #808080; | ||||
| font-size: 14px; | |||||
| font-size: 13px; | |||||
| } | } | ||||
| } | } | ||||
| .dataItem:hover{ | |||||
| border-color: #1664FF; | |||||
| box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.2) | |||||
| } | |||||
| .dataItem:hover .itemText{ | |||||
| color: #1664FF; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,4 +1,6 @@ | |||||
| import { getAccessToken } from '@/access'; | import { getAccessToken } from '@/access'; | ||||
| import clock from '@/assets/img/clock.png'; | |||||
| import creatByImg from '@/assets/img/creatBy.png'; | |||||
| import { addModel, getAssetIcon, getModelList } from '@/services/dataset/index.js'; | import { addModel, getAssetIcon, getModelList } from '@/services/dataset/index.js'; | ||||
| import { PlusCircleOutlined, UploadOutlined } from '@ant-design/icons'; | import { PlusCircleOutlined, UploadOutlined } from '@ant-design/icons'; | ||||
| import { Button, Form, Input, Modal, Pagination, Radio, Select, Upload } from 'antd'; | import { Button, Form, Input, Modal, Pagination, Radio, Select, Upload } from 'antd'; | ||||
| @@ -148,6 +150,11 @@ const PublicData = () => { | |||||
| const onFinishFailed = (errorInfo) => { | const onFinishFailed = (errorInfo) => { | ||||
| console.log('Failed:', 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(() => { | useEffect(() => { | ||||
| getAssetIconList(iconParams); | getAssetIconList(iconParams); | ||||
| getModelLists(queryFlow); | getModelLists(queryFlow); | ||||
| @@ -271,17 +278,19 @@ const PublicData = () => { | |||||
| ? datasetList.map((item) => { | ? datasetList.map((item) => { | ||||
| return ( | return ( | ||||
| <div className={Styles.dataItem} onClick={(e) => routeToIntro(e, item)}> | <div className={Styles.dataItem} onClick={(e) => routeToIntro(e, item)}> | ||||
| <div className={Styles.itemText}>{item.name}</div> | |||||
| <span className={Styles.itemText}>{item.name}</span> | |||||
| <div className={Styles.itemDescripition}>{item.description}</div> | |||||
| <div className={Styles.itemTime}> | <div className={Styles.itemTime}> | ||||
| <span>最近更新: {moment(item.update_time).format('YYYY-MM-DD')}</span> | |||||
| </div> | |||||
| <div className={Styles.itemIcon}> | |||||
| <img | <img | ||||
| style={{ width: '17px', marginRight: '3px' }} | |||||
| src={`/assets/images/upload-icon.png`} | |||||
| style={{ width: '17px', marginRight: '6px' }} | |||||
| src={creatByImg} | |||||
| alt="" | alt="" | ||||
| /> | /> | ||||
| <span>1582</span> | |||||
| <span>{item.create_by}</span> | |||||
| </div> | |||||
| <div className={Styles.itemIcon}> | |||||
| <img style={{ width: '12px', marginRight: '5px' }} src={clock} alt="" /> | |||||
| <span>最近更新: {moment(item.update_time).format('YYYY-MM-DD')}</span> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| ); | ); | ||||
| @@ -289,7 +298,14 @@ const PublicData = () => { | |||||
| : ''} | : ''} | ||||
| {/* <Select.Option value="demo">Demo</Select.Option> */} | {/* <Select.Option value="demo">Demo</Select.Option> */} | ||||
| </div> | </div> | ||||
| <Pagination size="small" total={total} showSizeChanger showQuickJumper /> | |||||
| <Pagination | |||||
| total={total} | |||||
| showSizeChanger | |||||
| defaultPageSize={20} | |||||
| pageSizeOptions={[20, 40, 60, 80, 100]} | |||||
| showQuickJumper | |||||
| onChange={onPageChange} | |||||
| /> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <Modal | <Modal | ||||
| @@ -1,3 +1,5 @@ | |||||
| import clock from '@/assets/img/clock.png'; | |||||
| import creatByImg from '@/assets/img/creatBy.png'; | |||||
| import { getAssetIcon, getModelList } from '@/services/dataset/index.js'; | import { getAssetIcon, getModelList } from '@/services/dataset/index.js'; | ||||
| import { Form, Input, Modal, Pagination, Radio } from 'antd'; | import { Form, Input, Modal, Pagination, Radio } from 'antd'; | ||||
| import moment from 'moment'; | import moment from 'moment'; | ||||
| @@ -110,6 +112,11 @@ const PublicData = () => { | |||||
| const onFinishFailed = (errorInfo) => { | const onFinishFailed = (errorInfo) => { | ||||
| console.log('Failed:', 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(() => { | useEffect(() => { | ||||
| getAssetIconList(iconParams); | getAssetIconList(iconParams); | ||||
| getModelLists(queryFlow); | getModelLists(queryFlow); | ||||
| @@ -218,17 +225,19 @@ const PublicData = () => { | |||||
| ? datasetList.map((item) => { | ? datasetList.map((item) => { | ||||
| return ( | return ( | ||||
| <div className={Styles.dataItem} onClick={(e) => routeToIntro(e, item)}> | <div className={Styles.dataItem} onClick={(e) => routeToIntro(e, item)}> | ||||
| <div className={Styles.itemText}>{item.name}</div> | |||||
| <span className={Styles.itemText}>{item.name}</span> | |||||
| <div className={Styles.itemDescripition}>{item.description}</div> | |||||
| <div className={Styles.itemTime}> | <div className={Styles.itemTime}> | ||||
| <span>最近更新: {moment(item.update_time).format('YYYY-MM-DD')}</span> | |||||
| </div> | |||||
| <div className={Styles.itemIcon}> | |||||
| <img | <img | ||||
| style={{ width: '17px', marginRight: '3px' }} | |||||
| src={`/assets/images/upload-icon.png`} | |||||
| style={{ width: '17px', marginRight: '6px' }} | |||||
| src={creatByImg} | |||||
| alt="" | alt="" | ||||
| /> | /> | ||||
| <span>1582</span> | |||||
| <span>{item.create_by}</span> | |||||
| </div> | |||||
| <div className={Styles.itemIcon}> | |||||
| <img style={{ width: '12px', marginRight: '5px' }} src={clock} alt="" /> | |||||
| <span>最近更新: {moment(item.update_time).format('YYYY-MM-DD')}</span> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| ); | ); | ||||
| @@ -236,7 +245,14 @@ const PublicData = () => { | |||||
| : ''} | : ''} | ||||
| {/* <Select.Option value="demo">Demo</Select.Option> */} | {/* <Select.Option value="demo">Demo</Select.Option> */} | ||||
| </div> | </div> | ||||
| <Pagination size="small" total={total} showSizeChanger showQuickJumper /> | |||||
| <Pagination | |||||
| total={total} | |||||
| showSizeChanger | |||||
| defaultPageSize={20} | |||||
| pageSizeOptions={[20, 40, 60, 80, 100]} | |||||
| showQuickJumper | |||||
| onChange={onPageChange} | |||||
| /> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <Modal | <Modal | ||||
| @@ -8,8 +8,8 @@ | |||||
| align-items: center; | align-items: center; | ||||
| width: 100%; | width: 100%; | ||||
| height: 43px; | height: 43px; | ||||
| margin-bottom: 10px; | |||||
| padding: 0 20px; | |||||
| margin-bottom: 20px; | |||||
| padding: 0 24px; | |||||
| color: #1d1d20; | color: #1d1d20; | ||||
| font-size: 15px; | font-size: 15px; | ||||
| font-family: 'Alibaba'; | font-family: 'Alibaba'; | ||||
| @@ -101,22 +101,32 @@ const EditPipeline = () => { | |||||
| openParamsDrawer(); | openParamsDrawer(); | ||||
| return; | return; | ||||
| } | } | ||||
| const data = graph.save(); | |||||
| console.log(data); | |||||
| const params = { | |||||
| ...locationParams, | |||||
| dag: JSON.stringify(data), | |||||
| global_param: JSON.stringify(res.global_param), | |||||
| }; | |||||
| saveWorkflow(params).then((ret) => { | |||||
| message.success('保存成功'); | |||||
| closeParamsDrawer(); | |||||
| setTimeout(() => { | |||||
| if (val) { | |||||
| navgite({ pathname: `/pipeline` }); | |||||
| } | |||||
| }, 500); | |||||
| }); | |||||
| const [propsRes, propsError] = await to(propsRef.current.getFieldsValue()); | |||||
| console.log(await to(propsRef.current.getFieldsValue())); | |||||
| if (propsError) { | |||||
| message.error('基本信息必填项需配置'); | |||||
| // handlerClick(); | |||||
| return; | |||||
| } | |||||
| propsRef.current.propClose(); | |||||
| setTimeout(() => { | |||||
| const data = graph.save(); | |||||
| console.log(data); | |||||
| const params = { | |||||
| ...locationParams, | |||||
| dag: JSON.stringify(data), | |||||
| global_param: JSON.stringify(res.global_param), | |||||
| }; | |||||
| saveWorkflow(params).then((ret) => { | |||||
| message.success('保存成功'); | |||||
| closeParamsDrawer(); | |||||
| setTimeout(() => { | |||||
| if (val) { | |||||
| navgite({ pathname: `/pipeline` }); | |||||
| } | |||||
| }, 500); | |||||
| }); | |||||
| }, 500); | |||||
| }; | }; | ||||
| const handlerClick = (e) => { | const handlerClick = (e) => { | ||||
| e.stopPropagation(); | e.stopPropagation(); | ||||
| @@ -1,5 +1,6 @@ | |||||
| import { pick } from '@/utils/index'; | import { pick } from '@/utils/index'; | ||||
| import { openAntdModal } from '@/utils/modal'; | import { openAntdModal } from '@/utils/modal'; | ||||
| import { to } from '@/utils/promise'; | |||||
| import { Icon } from '@umijs/max'; | import { Icon } from '@umijs/max'; | ||||
| import { Button, Drawer, Form, Input } from 'antd'; | import { Button, Drawer, Form, Input } from 'antd'; | ||||
| import { forwardRef, useImperativeHandle, useState } from 'react'; | import { forwardRef, useImperativeHandle, useState } from 'react'; | ||||
| @@ -8,6 +9,7 @@ import Styles from './editPipeline.less'; | |||||
| const { TextArea } = Input; | const { TextArea } = Input; | ||||
| const Props = forwardRef(({ onParentChange }, ref) => { | const Props = forwardRef(({ onParentChange }, ref) => { | ||||
| const [form] = Form.useForm(); | const [form] = Form.useForm(); | ||||
| const [stagingItem, setStagingItem] = useState({}); | const [stagingItem, setStagingItem] = useState({}); | ||||
| const [open, setOpen] = useState(false); | const [open, setOpen] = useState(false); | ||||
| const [selectedModel, setSelectedModel] = useState(undefined); | const [selectedModel, setSelectedModel] = useState(undefined); | ||||
| @@ -59,6 +61,15 @@ const Props = forwardRef(({ onParentChange }, ref) => { | |||||
| console.log('Failed:', errorInfo); | console.log('Failed:', errorInfo); | ||||
| }; | }; | ||||
| useImperativeHandle(ref, () => ({ | useImperativeHandle(ref, () => ({ | ||||
| getFieldsValue: async () => { | |||||
| const [propsRes, propsError] = await to(form.validateFields()); | |||||
| if (propsRes && !propsError) { | |||||
| const values = form.getFieldsValue(); | |||||
| return values; | |||||
| } else { | |||||
| return Promise.reject(propsError); | |||||
| } | |||||
| }, | |||||
| showDrawer(e) { | showDrawer(e) { | ||||
| if (e.item && e.item.getModel()) { | if (e.item && e.item.getModel()) { | ||||
| // console.log(e.item.getModel().in_parameters); | // console.log(e.item.getModel().in_parameters); | ||||
| @@ -80,9 +91,20 @@ const Props = forwardRef(({ onParentChange }, ref) => { | |||||
| // setTimeout(() => { | // setTimeout(() => { | ||||
| // console.log(stagingItem); | // console.log(stagingItem); | ||||
| // }, (500)); | // }, (500)); | ||||
| setSelectedModel(undefined); | |||||
| setSelectedDataset(undefined); | |||||
| setOpen(true); | setOpen(true); | ||||
| } | } | ||||
| }, | }, | ||||
| propClose: async () => { | |||||
| setOpen(false); | |||||
| const [openRes, propsError] = await to(setOpen(false)); | |||||
| console.log(setOpen(false)); | |||||
| }, | |||||
| // propClose() { | |||||
| // setOpen(false); | |||||
| // }, | |||||
| })); | })); | ||||
| // 选择数据集、模型 | // 选择数据集、模型 | ||||
| @@ -152,16 +174,22 @@ const Props = forwardRef(({ onParentChange }, ref) => { | |||||
| onClose={onClose} | onClose={onClose} | ||||
| afterOpenChange={afterOpenChange} | afterOpenChange={afterOpenChange} | ||||
| open={open} | open={open} | ||||
| width={540} | |||||
| width={420} | |||||
| > | > | ||||
| <Form | <Form | ||||
| name="form" | name="form" | ||||
| form={form} | form={form} | ||||
| // layout="vertical" | // layout="vertical" | ||||
| labelCol={{ span: 10 }} | |||||
| wrapperCol={{ span: 20 }} | |||||
| // initialValues={{ global_param: globalParam }} | |||||
| labelAlign="left" | |||||
| layout="vertical" | |||||
| labelCol={{ | |||||
| span: 16, | |||||
| }} | |||||
| wrapperCol={{ | |||||
| span: 24, | |||||
| }} | |||||
| style={{ | |||||
| maxWidth: 600, | |||||
| }} | |||||
| initialValues={{ | initialValues={{ | ||||
| remember: true, | remember: true, | ||||
| }} | }} | ||||
| @@ -203,7 +231,7 @@ const Props = forwardRef(({ onParentChange }, ref) => { | |||||
| </Form.Item> | </Form.Item> | ||||
| <div className={Styles.editPipelinePropsContent}> | <div className={Styles.editPipelinePropsContent}> | ||||
| <img | <img | ||||
| style={{ width: '13px', marginRight: '10px' }} | |||||
| style={{ width: '15px', marginRight: '10px' }} | |||||
| src={'/assets/images/duty-message.png'} | src={'/assets/images/duty-message.png'} | ||||
| alt="" | alt="" | ||||
| /> | /> | ||||
| @@ -226,7 +254,7 @@ const Props = forwardRef(({ onParentChange }, ref) => { | |||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item label="启动命令" name="command"> | <Form.Item label="启动命令" name="command"> | ||||
| <Input /> | |||||
| <TextArea /> | |||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | <Form.Item | ||||
| label="资源规格" | label="资源规格" | ||||
| @@ -255,7 +283,7 @@ const Props = forwardRef(({ onParentChange }, ref) => { | |||||
| : ''} | : ''} | ||||
| <div className={Styles.editPipelinePropsContent}> | <div className={Styles.editPipelinePropsContent}> | ||||
| <img | <img | ||||
| style={{ width: '13px', marginRight: '10px' }} | |||||
| style={{ width: '15px', marginRight: '10px' }} | |||||
| src={'/assets/images/duty-message.png'} | src={'/assets/images/duty-message.png'} | ||||
| alt="" | alt="" | ||||
| /> | /> | ||||
| @@ -294,7 +322,7 @@ const Props = forwardRef(({ onParentChange }, ref) => { | |||||
| : ''} | : ''} | ||||
| <div className={Styles.editPipelinePropsContent}> | <div className={Styles.editPipelinePropsContent}> | ||||
| <img | <img | ||||
| style={{ width: '13px', marginRight: '10px' }} | |||||
| style={{ width: '15px', marginRight: '10px' }} | |||||
| src={'/assets/images/duty-message.png'} | src={'/assets/images/duty-message.png'} | ||||
| alt="" | alt="" | ||||
| /> | /> | ||||
| @@ -297,7 +297,7 @@ const Pipeline = () => { | |||||
| }, | }, | ||||
| ]} | ]} | ||||
| > | > | ||||
| <Input showCount maxLength={64} /> | |||||
| <Input placeholder="请输入流水线名称" showCount maxLength={64} /> | |||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | <Form.Item | ||||
| label="流水线描述" | label="流水线描述" | ||||
| @@ -309,7 +309,7 @@ const Pipeline = () => { | |||||
| }, | }, | ||||
| ]} | ]} | ||||
| > | > | ||||
| <Input showCount maxLength={128} /> | |||||
| <Input placeholder="请输入流水线描述" showCount maxLength={128} /> | |||||
| </Form.Item> | </Form.Item> | ||||
| </Form> | </Form> | ||||
| </Modal> | </Modal> | ||||
| @@ -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, | |||||
| }); | |||||
| } | |||||
| @@ -1,7 +1,10 @@ | |||||
| // 全局颜色变量 | // 全局颜色变量 | ||||
| // FIXME: 不能设置 @primary-color 不起作用,感觉是哪里被重置了 | // FIXME: 不能设置 @primary-color 不起作用,感觉是哪里被重置了 | ||||
| @kf-primary-color: #1664ff; // 主色调 | @kf-primary-color: #1664ff; // 主色调 | ||||
| @primary-color-hover: #4086ff; | |||||
| @background-color: #f9fafb; // 页面背景颜色 | |||||
| @text-color: #1d1d20; | @text-color: #1d1d20; | ||||
| @text-color-second: #575757; | |||||
| @font-size: 15px; | @font-size: 15px; | ||||
| @border-color: rgba(22, 100, 255, 0.3); | @border-color: rgba(22, 100, 255, 0.3); | ||||
| @border-color-second: rgba(22, 100, 255, 0.1); | @border-color-second: rgba(22, 100, 255, 0.1); | ||||
| @@ -1,5 +1,6 @@ | |||||
| package com.ruoyi.platform.controller.dataset; | package com.ruoyi.platform.controller.dataset; | ||||
| import com.ruoyi.common.core.utils.StringUtils; | |||||
| import com.ruoyi.common.core.web.domain.AjaxResult; | import com.ruoyi.common.core.web.domain.AjaxResult; | ||||
| import com.ruoyi.common.security.utils.SecurityUtils; | import com.ruoyi.common.security.utils.SecurityUtils; | ||||
| import com.ruoyi.platform.domain.Dataset; | import com.ruoyi.platform.domain.Dataset; | ||||
| @@ -54,11 +55,15 @@ public class DatasetController { | |||||
| public AjaxResult queryByPage(Dataset dataset, @RequestParam("page") int page, | public AjaxResult queryByPage(Dataset dataset, @RequestParam("page") int page, | ||||
| @RequestParam("size") int size, | @RequestParam("size") int size, | ||||
| @RequestParam(value = "available_range") int availableRange , | @RequestParam(value = "available_range") int availableRange , | ||||
| @RequestParam(value = "data_type", required = false) String dataType) { | |||||
| @RequestParam(value = "data_type", required = false) String dataType, | |||||
| @RequestParam(value = "data_tag", required = false) String dataTag) { | |||||
| if (dataType != null) { // 仅当dataType有值时设置 | if (dataType != null) { // 仅当dataType有值时设置 | ||||
| dataset.setDataType(dataType); | dataset.setDataType(dataType); | ||||
| } | } | ||||
| if (dataTag != null) { | |||||
| dataset.setDataTag(dataTag); | |||||
| } | |||||
| dataset.setAvailableRange(availableRange); | dataset.setAvailableRange(availableRange); | ||||
| PageRequest pageRequest = PageRequest.of(page, size); | PageRequest pageRequest = PageRequest.of(page, size); | ||||
| return AjaxResult.success(this.datasetService.queryByPage(dataset, pageRequest)); | return AjaxResult.success(this.datasetService.queryByPage(dataset, pageRequest)); | ||||
| @@ -79,6 +84,9 @@ public class DatasetController { | |||||
| if (dataType != null) { // 仅当dataType有值时设置 | if (dataType != null) { // 仅当dataType有值时设置 | ||||
| dataset.setDataType(dataType); | dataset.setDataType(dataType); | ||||
| } | } | ||||
| if (dataTag != null) { | |||||
| dataset.setDataTag(dataTag); | |||||
| } | |||||
| PageRequest pageRequest = PageRequest.of(page, size); | PageRequest pageRequest = PageRequest.of(page, size); | ||||
| return AjaxResult.success(this.datasetService.queryByPage(dataset, pageRequest)); | return AjaxResult.success(this.datasetService.queryByPage(dataset, pageRequest)); | ||||
| } | } | ||||
| @@ -122,7 +122,7 @@ public class ImageController extends BaseController { | |||||
| @PostMapping("/net") | @PostMapping("/net") | ||||
| @ApiOperation("从网络上传构建镜像") | @ApiOperation("从网络上传构建镜像") | ||||
| public GenericsAjaxResult<String> createImageFromNet(@RequestParam("name") String imageName, | |||||
| public GenericsAjaxResult<Map<String, String>> createImageFromNet(@RequestParam("name") String imageName, | |||||
| @RequestParam("tag") String imageTag, | @RequestParam("tag") String imageTag, | ||||
| @RequestParam("path") String path) throws Exception { | @RequestParam("path") String path) throws Exception { | ||||
| return genericsSuccess(this.imageService.createImageFromNet(imageName,imageTag,path)); | return genericsSuccess(this.imageService.createImageFromNet(imageName,imageTag,path)); | ||||
| @@ -130,7 +130,7 @@ public class ImageController extends BaseController { | |||||
| @PostMapping("/local") | @PostMapping("/local") | ||||
| @ApiOperation("从本地上传构建镜像") | @ApiOperation("从本地上传构建镜像") | ||||
| public GenericsAjaxResult<String> createImageFromLocal(@RequestParam("name") String imageName, | |||||
| public GenericsAjaxResult<Map<String, String>> createImageFromLocal(@RequestParam("name") String imageName, | |||||
| @RequestParam("tag") String imageTag, | @RequestParam("tag") String imageTag, | ||||
| @RequestParam("path") String path) throws Exception { | @RequestParam("path") String path) throws Exception { | ||||
| return genericsSuccess(this.imageService.createImageFromLocal(imageName,imageTag,path)); | return genericsSuccess(this.imageService.createImageFromLocal(imageName,imageTag,path)); | ||||
| @@ -8,8 +8,10 @@ import io.swagger.annotations.ApiOperation; | |||||
| import org.springframework.data.domain.Page; | import org.springframework.data.domain.Page; | ||||
| import org.springframework.data.domain.PageRequest; | import org.springframework.data.domain.PageRequest; | ||||
| import org.springframework.web.bind.annotation.*; | import org.springframework.web.bind.annotation.*; | ||||
| import org.springframework.web.multipart.MultipartFile; | |||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||
| import java.util.Map; | |||||
| /** | /** | ||||
| * (ImageVersion)表控制层 | * (ImageVersion)表控制层 | ||||
| @@ -36,11 +38,17 @@ public class ImageVersionController extends BaseController { | |||||
| */ | */ | ||||
| @GetMapping | @GetMapping | ||||
| @ApiOperation("分页查询") | @ApiOperation("分页查询") | ||||
| public GenericsAjaxResult<Page<ImageVersion>> queryByPage(ImageVersion imageVersion, int page, int size) { | |||||
| public GenericsAjaxResult<Page<ImageVersion>> queryByPage(ImageVersion imageVersion, @RequestParam("page") int page, | |||||
| @RequestParam("size") int size, | |||||
| @RequestParam(value = "image_id") int imageId) { | |||||
| imageVersion.setImageId(imageId); | |||||
| PageRequest pageRequest = PageRequest.of(page,size); | PageRequest pageRequest = PageRequest.of(page,size); | ||||
| return genericsSuccess(this.imageVersionService.queryByPage(imageVersion, pageRequest)); | return genericsSuccess(this.imageVersionService.queryByPage(imageVersion, pageRequest)); | ||||
| } | } | ||||
| /** | /** | ||||
| * 通过主键查询单条数据 | * 通过主键查询单条数据 | ||||
| * | * | ||||
| @@ -36,7 +36,10 @@ public class ComputingResourceController extends BaseController { | |||||
| */ | */ | ||||
| @GetMapping | @GetMapping | ||||
| @ApiOperation("分页查询") | @ApiOperation("分页查询") | ||||
| public GenericsAjaxResult<Page<ComputingResource>> queryByPage(ComputingResource computingResource, int page, int size) { | |||||
| public GenericsAjaxResult<Page<ComputingResource>> queryByPage(ComputingResource computingResource, @RequestParam("page") int page, | |||||
| @RequestParam("size") int size, | |||||
| @RequestParam(value = "resource_type") String resourceType ) { | |||||
| computingResource.setComputingResource(resourceType); | |||||
| PageRequest pageRequest = PageRequest.of(page,size); | PageRequest pageRequest = PageRequest.of(page,size); | ||||
| return genericsSuccess(this.computingResourceService.queryByPage(computingResource, pageRequest)); | return genericsSuccess(this.computingResourceService.queryByPage(computingResource, pageRequest)); | ||||
| } | } | ||||
| @@ -71,7 +71,7 @@ public interface ComputingResourceDao { | |||||
| * @param computingResource 实例对象 | * @param computingResource 实例对象 | ||||
| * @return 影响行数 | * @return 影响行数 | ||||
| */ | */ | ||||
| int update(ComputingResource computingResource); | |||||
| int update(@Param("computingResource") ComputingResource computingResource); | |||||
| /** | /** | ||||
| * 通过主键删除数据 | * 通过主键删除数据 | ||||
| @@ -1,13 +1,11 @@ | |||||
| package com.ruoyi.platform.service; | package com.ruoyi.platform.service; | ||||
| import com.ruoyi.platform.domain.Image; | import com.ruoyi.platform.domain.Image; | ||||
| import com.ruoyi.platform.domain.Workflow; | |||||
| import com.ruoyi.platform.vo.ImageVo; | import com.ruoyi.platform.vo.ImageVo; | ||||
| import org.springframework.data.domain.Page; | import org.springframework.data.domain.Page; | ||||
| import org.springframework.data.domain.PageRequest; | import org.springframework.data.domain.PageRequest; | ||||
| import org.springframework.web.multipart.MultipartFile; | import org.springframework.web.multipart.MultipartFile; | ||||
| import java.util.Collection; | |||||
| import java.util.Map; | import java.util.Map; | ||||
| /** | /** | ||||
| @@ -69,13 +67,14 @@ public interface ImageService { | |||||
| /** | /** | ||||
| * 本地上传构建镜像 | * 本地上传构建镜像 | ||||
| * | |||||
| * @param imageName | * @param imageName | ||||
| * @param imageTag | * @param imageTag | ||||
| * @param path | * @param path | ||||
| * @return | * @return | ||||
| */ | */ | ||||
| String createImageFromLocal(String imageName, String imageTag, String path) throws Exception; | |||||
| String createImageFromNet(String imageName, String imageTag, String NetPath) throws Exception; | |||||
| Map<String, String> createImageFromLocal(String imageName, String imageTag, String path) throws Exception; | |||||
| Map<String, String> createImageFromNet(String imageName, String imageTag, String NetPath) throws Exception; | |||||
| Map<String, String> uploadImageFiles(MultipartFile file) throws Exception; | Map<String, String> uploadImageFiles(MultipartFile file) throws Exception; | ||||
| } | } | ||||
| @@ -268,7 +268,7 @@ public class DatasetServiceImpl implements DatasetService { | |||||
| // 获取所有相同模型ID的记录 | // 获取所有相同模型ID的记录 | ||||
| List<DatasetVersion> versions = datasetVersionDao.queryByDatasetId(datasetId); | List<DatasetVersion> versions = datasetVersionDao.queryByDatasetId(datasetId); | ||||
| if (versions.isEmpty()) { | if (versions.isEmpty()) { | ||||
| throw new Exception("未找到相关数据集版本记录"); | |||||
| return new ArrayList<>(); // 如果没有找到任何版本记录,返回空列表 | |||||
| } | } | ||||
| // 使用Stream API提取version字段,并去重 | // 使用Stream API提取version字段,并去重 | ||||
| return versions.stream() | return versions.stream() | ||||
| @@ -8,6 +8,7 @@ import com.ruoyi.platform.mapper.ImageVersionDao; | |||||
| import com.ruoyi.platform.service.ImageService; | import com.ruoyi.platform.service.ImageService; | ||||
| import com.ruoyi.platform.service.ImageVersionService; | import com.ruoyi.platform.service.ImageVersionService; | ||||
| import com.ruoyi.platform.service.MinioService; | import com.ruoyi.platform.service.MinioService; | ||||
| import com.ruoyi.platform.utils.FileUtil; | |||||
| import com.ruoyi.platform.utils.K8sClientUtil; | import com.ruoyi.platform.utils.K8sClientUtil; | ||||
| import com.ruoyi.platform.vo.ImageVo; | import com.ruoyi.platform.vo.ImageVo; | ||||
| import com.ruoyi.system.api.model.LoginUser; | import com.ruoyi.system.api.model.LoginUser; | ||||
| @@ -23,7 +24,9 @@ import org.springframework.web.multipart.MultipartFile; | |||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||
| import java.util.Date; | import java.util.Date; | ||||
| import java.util.HashMap; | |||||
| import java.util.Map; | import java.util.Map; | ||||
| import java.util.concurrent.CompletableFuture; | |||||
| /** | /** | ||||
| * (Image)表服务实现类 | * (Image)表服务实现类 | ||||
| @@ -171,7 +174,6 @@ public class ImageServiceImpl implements ImageService { | |||||
| image.setName(imageVo.getName()); | image.setName(imageVo.getName()); | ||||
| image.setDescription(imageVo.getDescription()); | image.setDescription(imageVo.getDescription()); | ||||
| image.setImageType(imageVo.getImageType()); | image.setImageType(imageVo.getImageType()); | ||||
| Image imageInsert = this.insert(image); | Image imageInsert = this.insert(image); | ||||
| if (imageInsert == null){ | if (imageInsert == null){ | ||||
| throw new Exception("新增镜像失败"); | throw new Exception("新增镜像失败"); | ||||
| @@ -181,17 +183,50 @@ public class ImageServiceImpl implements ImageService { | |||||
| imageVersion.setVersion(imageVo.getVersion()); | imageVersion.setVersion(imageVo.getVersion()); | ||||
| imageVersion.setUrl(imageVo.getUrl()); | imageVersion.setUrl(imageVo.getUrl()); | ||||
| imageVersion.setTagName(imageVo.getTagName()); | imageVersion.setTagName(imageVo.getTagName()); | ||||
| //imageVersion.setFileSize(datasetVo.getFileSize()); | |||||
| imageVersion.setFileSize(imageVo.getFileSize()); | |||||
| imageVersion.setStatus("building"); | |||||
| ImageVersion imageVersionInsert = this.imageVersionService.insert(imageVersion); | ImageVersion imageVersionInsert = this.imageVersionService.insert(imageVersion); | ||||
| if (imageVersionInsert == null) { | if (imageVersionInsert == null) { | ||||
| throw new Exception("新增镜像失败"); | throw new Exception("新增镜像失败"); | ||||
| } | } | ||||
| return "新增镜像成功"; | |||||
| // 使用CompletableFuture异步执行不同的镜像构建逻辑 | |||||
| CompletableFuture.supplyAsync(() -> { | |||||
| Map<String, String> resultMap = new HashMap<>(); | |||||
| try { | |||||
| if(imageVo.getUploadType()==0){ | |||||
| resultMap = createImageFromNet(imageVo.getName(), imageVo.getTagName(), imageVo.getPath()); | |||||
| }else{ | |||||
| resultMap = createImageFromLocal(imageVo.getName(), imageVo.getTagName(), imageVo.getPath()); | |||||
| } | |||||
| } catch (Exception e) { | |||||
| imageVersion.setStatus("failed"); | |||||
| imageVersionService.update(imageVersion); | |||||
| throw new RuntimeException("镜像构建失败: " + e.getMessage(), e); | |||||
| } | |||||
| return resultMap; | |||||
| }).thenAccept(resultMap ->{ | |||||
| try { | |||||
| String imageUrl = resultMap.get("url"); | |||||
| String fileSize = resultMap.get("filesize"); | |||||
| imageVersion.setUrl(imageUrl); | |||||
| imageVersion.setFileSize(fileSize); | |||||
| imageVersion.setStatus("available"); | |||||
| imageVersionService.update(imageVersion); | |||||
| } catch (Exception e) { | |||||
| System.err.println("更新数据库失败: " + e.getMessage()); | |||||
| } | |||||
| }).exceptionally(ex -> { | |||||
| System.err.println("异步操作发生错误: " + ex.getMessage()); | |||||
| return null; | |||||
| }); | |||||
| return "新增镜像成功,镜像构建中..."; | |||||
| } | } | ||||
| @Override | @Override | ||||
| public String createImageFromNet(String imageName, String imageTag, String netPath) throws Exception { | |||||
| public Map<String, String> createImageFromNet(String imageName, String imageTag, String netPath) throws Exception { | |||||
| Map<String, String> resultMap = new HashMap<>(); | |||||
| // 得到容器 | // 得到容器 | ||||
| V1Pod pod = k8sClientUtil.getNSPodList(serviceNS, deploymentName); | V1Pod pod = k8sClientUtil.getNSPodList(serviceNS, deploymentName); | ||||
| if (pod == null) { | if (pod == null) { | ||||
| @@ -203,7 +238,7 @@ public class ImageServiceImpl implements ImageService { | |||||
| // 在这个容器的/data/admin 目录下执行命令 docker load -i fileName 得到返回的镜像名字name:tag | // 在这个容器的/data/admin 目录下执行命令 docker load -i fileName 得到返回的镜像名字name:tag | ||||
| String username = SecurityUtils.getLoginUser().getUsername(); | String username = SecurityUtils.getLoginUser().getUsername(); | ||||
| // | // | ||||
| String logs2 = k8sClientUtil.executeCommand(pod,"docker pull "+netPath); | |||||
| String logs2 = k8sClientUtil.executeCommand(pod,"docker pull "+ netPath); | |||||
| // 在容器里执行 docker tag name:tag nexus3.kube-system.svc:8083/imageName:imageTag | // 在容器里执行 docker tag name:tag nexus3.kube-system.svc:8083/imageName:imageTag | ||||
| if (StringUtils.isNoneBlank(logs2)){ | if (StringUtils.isNoneBlank(logs2)){ | ||||
| String substring = logs2.substring(logs2.indexOf(harborUrl), logs2.length()); | String substring = logs2.substring(logs2.indexOf(harborUrl), logs2.length()); | ||||
| @@ -211,19 +246,28 @@ public class ImageServiceImpl implements ImageService { | |||||
| String cmd1 = "docker tag " + cleanedString+ " " + harborUrl+"/"+repository+"/"+username+"/" + imageName + imageTag; | String cmd1 = "docker tag " + cleanedString+ " " + harborUrl+"/"+repository+"/"+username+"/" + imageName + imageTag; | ||||
| String imageUrl = harborUrl+"/"+repository+"/"+username+"/" + imageName + imageTag; | String imageUrl = harborUrl+"/"+repository+"/"+username+"/" + imageName + imageTag; | ||||
| String cmd2 = "docker push " + imageUrl; | String cmd2 = "docker push " + imageUrl; | ||||
| String cmd3 = "docker inspect --format='{{.Size}}' " + imageUrl; | |||||
| String s = k8sClientUtil.executeCommand(pod, cmd1); | String s = k8sClientUtil.executeCommand(pod, cmd1); | ||||
| if (StringUtils.isNotEmpty(k8sClientUtil.executeCommand(pod, cmd2))){ | if (StringUtils.isNotEmpty(k8sClientUtil.executeCommand(pod, cmd2))){ | ||||
| return imageUrl; | |||||
| resultMap.put("url", imageUrl); | |||||
| //得到镜像文件大小 | |||||
| long sizeInBytes = Long.parseLong(k8sClientUtil.executeCommand(pod, cmd3)); | |||||
| String formattedImageSize = FileUtil.formatFileSize(sizeInBytes); // 格式化镜像文件大小 | |||||
| resultMap.put("fileSize", formattedImageSize); | |||||
| return resultMap; | |||||
| }else { | }else { | ||||
| throw new Exception("拉取公网镜像失败,请检查网络或者镜像地址"); | |||||
| throw new Exception("拉取公网镜像失败,请检查网络或者镜像地址"); | |||||
| } | } | ||||
| }else { | }else { | ||||
| throw new Exception("拉取公网镜像失败,请检查网络或者镜像地址"); | |||||
| throw new Exception("拉取公网镜像失败,请检查网络或者镜像地址"); | |||||
| } | } | ||||
| } | } | ||||
| @Override | @Override | ||||
| public String createImageFromLocal(String imageName, String imageTag, String path) throws Exception { | |||||
| public Map<String, String> createImageFromLocal(String imageName, String imageTag, String path) throws Exception { | |||||
| Map<String, String> resultMap = new HashMap<>(); | |||||
| // 得到容器 | // 得到容器 | ||||
| V1Pod pod = k8sClientUtil.getNSPodList(serviceNS, deploymentName); | V1Pod pod = k8sClientUtil.getNSPodList(serviceNS, deploymentName); | ||||
| if (pod == null) { | if (pod == null) { | ||||
| @@ -244,11 +288,17 @@ public class ImageServiceImpl implements ImageService { | |||||
| String cmd1 = "docker tag " + cleanedString+ " " + harborUrl+"/"+repository+"/"+username+"/" + imageName + imageTag; | String cmd1 = "docker tag " + cleanedString+ " " + harborUrl+"/"+repository+"/"+username+"/" + imageName + imageTag; | ||||
| String imageUrl = harborUrl+"/"+repository+"/"+username+"/" + imageName + imageTag; | String imageUrl = harborUrl+"/"+repository+"/"+username+"/" + imageName + imageTag; | ||||
| String cmd2 = "docker push " + imageUrl; | String cmd2 = "docker push " + imageUrl; | ||||
| String cmd3 = "docker inspect --format='{{.Size}}' " + imageUrl; | |||||
| String s = k8sClientUtil.executeCommand(pod, cmd1); | String s = k8sClientUtil.executeCommand(pod, cmd1); | ||||
| if (StringUtils.isNotEmpty(k8sClientUtil.executeCommand(pod, cmd2))){ | if (StringUtils.isNotEmpty(k8sClientUtil.executeCommand(pod, cmd2))){ | ||||
| return imageUrl; | |||||
| resultMap.put("url", imageUrl); | |||||
| //得到镜像文件大小 | |||||
| long sizeInBytes = Long.parseLong(k8sClientUtil.executeCommand(pod, cmd3)); | |||||
| String formattedImageSize = FileUtil.formatFileSize(sizeInBytes); // 格式化镜像文件大小 | |||||
| resultMap.put("fileSize", formattedImageSize); | |||||
| return resultMap; | |||||
| }else { | }else { | ||||
| throw new Exception("解析镜像压缩包失败,请检查镜像文件"); | |||||
| throw new Exception("解析镜像压缩包失败,请检查镜像文件"); | |||||
| } | } | ||||
| }else { | }else { | ||||
| throw new Exception("解析镜像压缩包失败,请检查镜像文件"); | throw new Exception("解析镜像压缩包失败,请检查镜像文件"); | ||||
| @@ -259,7 +309,6 @@ public class ImageServiceImpl implements ImageService { | |||||
| public Map<String, String> uploadImageFiles(MultipartFile file) throws Exception { | public Map<String, String> uploadImageFiles(MultipartFile file) throws Exception { | ||||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | LoginUser loginUser = SecurityUtils.getLoginUser(); | ||||
| String path = loginUser.getUsername()+"/"+file.getOriginalFilename(); | String path = loginUser.getUsername()+"/"+file.getOriginalFilename(); | ||||
| Map<String, String> stringMap = minioService.uploadFile(bucketName, path, file); | |||||
| return stringMap; | |||||
| return minioService.uploadFile(bucketName, path, file); | |||||
| } | } | ||||
| } | } | ||||
| @@ -317,10 +317,8 @@ public class ModelsServiceImpl implements ModelsService { | |||||
| List<ModelsVersion> versions = modelsVersionDao.queryByModelsId(modelId); | List<ModelsVersion> versions = modelsVersionDao.queryByModelsId(modelId); | ||||
| if (versions.isEmpty()) { | if (versions.isEmpty()) { | ||||
| throw new Exception("未找到相关模型版本记录"); | |||||
| return new ArrayList<>(); // 如果没有找到任何版本记录,返回空列表 | |||||
| } | } | ||||
| // // 将结果按照版本分类 | |||||
| // return versions.stream().collect(Collectors.groupingBy(ModelsVersion::getVersion)); | |||||
| // 使用Stream API提取version字段,并去重 | // 使用Stream API提取version字段,并去重 | ||||
| return versions.stream() | return versions.stream() | ||||
| @@ -378,9 +378,10 @@ public class K8sClientUtil { | |||||
| // invokes the CoreV1Api client | // invokes the CoreV1Api client | ||||
| for (V1Pod item : v1PodList.getItems()) { | for (V1Pod item : v1PodList.getItems()) { | ||||
| if (item.getMetadata().getGenerateName().startsWith(deploymentName)) { | |||||
| String generateName = item.getMetadata().getGenerateName(); | |||||
| if (StringUtils.isNotEmpty(generateName) && generateName.startsWith(deploymentName)) { | |||||
| // 找到匹配的Pod,获取其名称 | // 找到匹配的Pod,获取其名称 | ||||
| return item; | |||||
| return item; | |||||
| } | } | ||||
| } | } | ||||
| return null; | return null; | ||||
| @@ -9,10 +9,7 @@ import java.io.Serializable; | |||||
| @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) | @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) | ||||
| public class ImageVo implements Serializable { | public class ImageVo implements Serializable { | ||||
| /** | |||||
| * 主键 | |||||
| */ | |||||
| private Integer id; | |||||
| /** | /** | ||||
| * 镜像名称 | * 镜像名称 | ||||
| */ | */ | ||||
| @@ -58,13 +55,20 @@ public class ImageVo implements Serializable { | |||||
| @ApiModelProperty(name = "status") | @ApiModelProperty(name = "status") | ||||
| private String status; | private String status; | ||||
| public Integer getId() { | |||||
| return id; | |||||
| } | |||||
| @ApiModelProperty(value = "上传方式, 基于公网上传0,基于本地上传1") | |||||
| private Integer uploadType; | |||||
| public void setId(Integer id) { | |||||
| this.id = id; | |||||
| } | |||||
| @ApiModelProperty(value = "镜像上传路径") | |||||
| private String path; | |||||
| // public Integer getId() { | |||||
| // return id; | |||||
| // } | |||||
| // | |||||
| // public void setId(Integer id) { | |||||
| // this.id = id; | |||||
| // } | |||||
| public String getName() { | public String getName() { | ||||
| return name; | return name; | ||||
| @@ -129,4 +133,19 @@ public class ImageVo implements Serializable { | |||||
| public void setStatus(String status) { | public void setStatus(String status) { | ||||
| this.status = status; | this.status = status; | ||||
| } | } | ||||
| public Integer getUploadType() { | |||||
| return uploadType; | |||||
| } | |||||
| public void setUploadType(Integer uploadType) { | |||||
| this.uploadType = uploadType; | |||||
| } | |||||
| public String getPath() { | |||||
| return path; | |||||
| } | |||||
| public void setPath(String path) { | |||||
| this.path = path; | |||||
| } | |||||
| } | } | ||||
| @@ -73,7 +73,7 @@ | |||||
| and computing_resource = #{computingResource.computingResource} | and computing_resource = #{computingResource.computingResource} | ||||
| </if> | </if> | ||||
| <if test="computingResource.standard != null and computingResource.standard != ''"> | <if test="computingResource.standard != null and computingResource.standard != ''"> | ||||
| and standard = #{computingResource.standard} | |||||
| and standard = #{computingResource.computingResource} | |||||
| </if> | </if> | ||||
| <if test="computingResource.description != null and computingResource.description != ''"> | <if test="computingResource.description != null and computingResource.description != ''"> | ||||
| and description = #{computingResource.description} | and description = #{computingResource.description} | ||||
| @@ -96,17 +96,17 @@ | |||||
| </where> | </where> | ||||
| </select> | </select> | ||||
| <!--新增所有列--> | |||||
| <insert id="insert" keyProperty="id" useGeneratedKeys="true"> | <insert id="insert" keyProperty="id" useGeneratedKeys="true"> | ||||
| insert into computing_resource(computing_resourcestandarddescriptioncreate_bycreate_timeupdate_byupdate_timestate) | |||||
| values (#{computingResource}#{standard}#{description}#{createBy}#{createTime}#{updateBy}#{updateTime}#{state}) | |||||
| insert into computing_resource (computing_resource, standard, description, create_by, create_time, update_by, update_time, state) | |||||
| values (#{computingResource.computingResource}, #{computingResource.standard}, #{computingResource.description}, #{computingResource.createBy}, #{computingResource.createTime}, #{computingResource.updateBy}, #{computingResource.updateTime}, #{computingResource.state}) | |||||
| </insert> | </insert> | ||||
| <insert id="insertBatch" keyProperty="id" useGeneratedKeys="true"> | <insert id="insertBatch" keyProperty="id" useGeneratedKeys="true"> | ||||
| insert into computing_resource(computing_resourcestandarddescriptioncreate_bycreate_timeupdate_byupdate_timestate) | |||||
| insert into computing_resource(computing_resource,standard,description,create_by,create_time,update_by,update_time,state) | |||||
| values | values | ||||
| <foreach collection="entities" item="entity" separator=","> | <foreach collection="entities" item="entity" separator=","> | ||||
| (#{entity.computingResource}#{entity.standard}#{entity.description}#{entity.createBy}#{entity.createTime}#{entity.updateBy}#{entity.updateTime}#{entity.state}) | |||||
| (#{entity.computingResource},#{entity.standard},#{entity.description},#{entity.createBy},#{entity.createTime},#{entity.updateBy},#{entity.updateTime},#{entity.state}) | |||||
| </foreach> | </foreach> | ||||
| </insert> | </insert> | ||||
| @@ -19,7 +19,7 @@ | |||||
| select | select | ||||
| id,name,description,image_type,create_by,create_time,update_by,update_time,state | id,name,description,image_type,create_by,create_time,update_by,update_time,state | ||||
| from image | from image | ||||
| where id = #{id} | |||||
| where id = #{id} and state = 1 | |||||
| </select> | </select> | ||||
| <!--查询指定行数据--> | <!--查询指定行数据--> | ||||
| @@ -34,7 +34,7 @@ | |||||
| and img.id = #{image.id} | and img.id = #{image.id} | ||||
| </if> | </if> | ||||
| <if test="image.name != null and image.name != ''"> | <if test="image.name != null and image.name != ''"> | ||||
| and img.name like "%"#{image.name}"%" | |||||
| and img.name like concat('%', #{image.name}, '%') | |||||
| </if> | </if> | ||||
| <if test="image.description != null and image.description != ''"> | <if test="image.description != null and image.description != ''"> | ||||
| and img.description = #{image.description} | and img.description = #{image.description} | ||||
| @@ -86,7 +86,7 @@ | |||||
| and id = #{image.id} | and id = #{image.id} | ||||
| </if> | </if> | ||||
| <if test="image.name != null and image.name != ''"> | <if test="image.name != null and image.name != ''"> | ||||
| and name like "%"#{image.name}"%" | |||||
| and name like concat('%', #{image.name}, '%') | |||||
| </if> | </if> | ||||
| <if test="image.description != null and image.description != ''"> | <if test="image.description != null and image.description != ''"> | ||||
| and description = #{image.description} | and description = #{image.description} | ||||