feat: 完成镜像界面
|
@ -144,6 +144,16 @@ export default [
|
|||
path: '',
|
||||
component: './Mirror/list',
|
||||
},
|
||||
{
|
||||
name: '镜像详情',
|
||||
path: ':id',
|
||||
component: './Mirror/info',
|
||||
},
|
||||
{
|
||||
name: '创建镜像',
|
||||
path: 'create',
|
||||
component: './Mirror/create',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
After Width: | Height: | Size: 468 B |
After Width: | Height: | Size: 445 B |
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB |
|
@ -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;
|
|
@ -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;
|
|
@ -1,9 +1,12 @@
|
|||
@import '@/styles/theme.less';
|
||||
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-y: hidden;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
|
||||
'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
|
||||
'Noto Color Emoji';
|
||||
|
@ -38,10 +41,12 @@ a {
|
|||
color: #1664ff;
|
||||
}
|
||||
.ant-pro-layout .ant-pro-layout-content {
|
||||
padding: 10px;
|
||||
padding: 0 10px 10px;
|
||||
overflow-y: hidden;
|
||||
background-color: @background-color;
|
||||
}
|
||||
.ant-pro-layout .ant-pro-layout-bg-list {
|
||||
background: #f9fafb;
|
||||
background: @background-color;
|
||||
}
|
||||
.ant-table-wrapper .ant-table-thead > tr > th {
|
||||
background-color: #fff;
|
||||
|
@ -55,23 +60,23 @@ a {
|
|||
.ant-pro-layout .ant-pro-sider .ant-layout-sider-children {
|
||||
background: #f2f5f7;
|
||||
}
|
||||
.ant-pro-base-menu-inline-item-title .ant-pro-base-menu-inline-item-text{
|
||||
color:#1d1d20;
|
||||
font-size:16px;
|
||||
.ant-pro-base-menu-inline-item-title .ant-pro-base-menu-inline-item-text {
|
||||
color: #1d1d20;
|
||||
font-size: 16px;
|
||||
}
|
||||
.ant-pro-layout .ant-pro-sider-menu{
|
||||
.ant-pro-layout .ant-pro-sider-menu {
|
||||
padding-top: 40px;
|
||||
}
|
||||
.ant-pro-global-header-logo-mix{
|
||||
height: 75px;
|
||||
border-bottom: 1px solid rgba(233, 237, 240, 1);
|
||||
margin-left: -16px;
|
||||
.ant-pro-global-header-logo-mix {
|
||||
width: 257px;
|
||||
background:#f2f5f7;
|
||||
border-top-right-radius: 20px;
|
||||
height: 75px;
|
||||
margin-left: -16px;
|
||||
padding-left: 28px;
|
||||
background: #f2f5f7;
|
||||
border-bottom: 1px solid rgba(233, 237, 240, 1);
|
||||
border-top-right-radius: 20px;
|
||||
}
|
||||
.ant-pro-layout .ant-pro-sider .ant-layout-sider-children{
|
||||
.ant-pro-layout .ant-pro-sider .ant-layout-sider-children {
|
||||
border-right: unset;
|
||||
border-bottom-right-radius: 20px;
|
||||
}
|
||||
|
@ -80,16 +85,14 @@ font-size:16px;
|
|||
background: #f2f5f7;
|
||||
border-radius: 0px 20px 20px 0px;
|
||||
}
|
||||
.ant-pro-layout .ant-pro-layout-content {
|
||||
background-color: transparent;
|
||||
}
|
||||
.ant-drawer .ant-drawer-body{
|
||||
|
||||
.ant-drawer .ant-drawer-body {
|
||||
padding: 0;
|
||||
}
|
||||
.ant-drawer .ant-drawer-body .ant-row{
|
||||
.ant-drawer .ant-drawer-body .ant-row {
|
||||
padding: 0 24px;
|
||||
}
|
||||
.ant-drawer .ant-drawer-body .ant-form-item{
|
||||
.ant-drawer .ant-drawer-body .ant-form-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.ant-table-wrapper .ant-table-pagination.ant-pagination {
|
||||
|
@ -107,9 +110,10 @@ font-size:16px;
|
|||
height: 94vh;
|
||||
}
|
||||
.ant-pro-layout .ant-pro-layout-container {
|
||||
height: 98vh;
|
||||
height: 100vh;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
.ant-modal-confirm .ant-modal-confirm-paragraph{
|
||||
.ant-modal-confirm .ant-modal-confirm-paragraph {
|
||||
margin: 54px 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -120,36 +124,35 @@ font-size:16px;
|
|||
margin-top: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
.ant-modal-confirm-btns .ant-btn-default{
|
||||
width:110px;
|
||||
height:40px;
|
||||
background:rgba(22, 100, 255, 0.06);
|
||||
border-radius:10px;
|
||||
color:#1d1d20;
|
||||
font-size:18px;
|
||||
margin-right: 10px;
|
||||
border-color: transparent;
|
||||
.ant-modal-confirm-btns .ant-btn-default {
|
||||
width: 110px;
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
color: #1d1d20;
|
||||
font-size: 18px;
|
||||
background: rgba(22, 100, 255, 0.06);
|
||||
border-color: transparent;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.ant-modal-confirm-btns .ant-btn-default:hover {
|
||||
background: rgba(22, 100, 255, 0.06);
|
||||
border-color: transparent;
|
||||
}
|
||||
.ant-modal-confirm-btns .ant-btn-primary{
|
||||
width:110px;
|
||||
height:40px;
|
||||
background:#1664ff;
|
||||
border-radius:10px;
|
||||
.ant-modal-confirm-btns .ant-btn-primary {
|
||||
width: 110px;
|
||||
height: 40px;
|
||||
font-size: 18px;
|
||||
background: #1664ff;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.ant-modal .ant-input-affix-wrapper{
|
||||
.ant-modal .ant-input-affix-wrapper {
|
||||
height: 46px;
|
||||
padding: 1px 11px;
|
||||
}
|
||||
.ant-modal .ant-select-single{
|
||||
.ant-modal .ant-select-single {
|
||||
height: 46px;
|
||||
|
||||
}
|
||||
.ant-modal .ant-select-single .ant-select-selector .ant-select-selection-placeholder{
|
||||
.ant-modal .ant-select-single .ant-select-selector .ant-select-selection-placeholder {
|
||||
line-height: 46px;
|
||||
}
|
||||
.ant-modal .ant-modal-close-x {
|
||||
|
@ -166,14 +169,14 @@ border-color: transparent;
|
|||
.ant-modal .ant-modal-content {
|
||||
padding: 0;
|
||||
}
|
||||
.ant-modal-confirm-body-wrapper{
|
||||
height:303px;
|
||||
border-radius:21px;
|
||||
background-image: url(/assets/images/modal-back.png);
|
||||
background-repeat:no-repeat;
|
||||
background-size:100%;
|
||||
background-position: top center;
|
||||
border-radius: 0;
|
||||
.ant-modal-confirm-body-wrapper {
|
||||
height: 303px;
|
||||
background-image: url(/assets/images/modal-back.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: top center;
|
||||
background-size: 100%;
|
||||
border-radius: 21px;
|
||||
border-radius: 0;
|
||||
}
|
||||
.ant-modal .ant-modal-content {
|
||||
border-radius: 20px;
|
||||
|
@ -201,17 +204,6 @@ border-radius: 0;
|
|||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.ant-tabs {
|
||||
.ant-tabs-nav::before,
|
||||
div > .ant-tabs-nav::before {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ant-tabs-nav {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ::-webkit-scrollbar-button {
|
||||
// background: #97a1bd;
|
||||
// }
|
||||
|
|
|
@ -73,21 +73,28 @@ export function useCallbackState<T>(initialValue: T) {
|
|||
*
|
||||
* @param initialWidth - The initial width of the element.
|
||||
* @param initialHeight - The initial height of the element.
|
||||
* @param deps - dependency list.
|
||||
* @return - A tuple containing the ref to the DOM element, the current width, and the current height.
|
||||
*/
|
||||
export function useDomSize<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 [width, setWidth] = useState(initialWidth);
|
||||
const [height, setHeight] = useState(initialHeight);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('dddddd');
|
||||
|
||||
const setDomHeight = () => {
|
||||
if (domRef.current) {
|
||||
setHeight(domRef.current.offsetHeight);
|
||||
setWidth(domRef.current.offsetWidth);
|
||||
}
|
||||
};
|
||||
const debounceFunc = debounce(setDomHeight, 500);
|
||||
const debounceFunc = debounce(setDomHeight, 200);
|
||||
|
||||
setDomHeight();
|
||||
window.addEventListener('resize', debounceFunc);
|
||||
|
@ -95,7 +102,7 @@ export function useDomSize<T extends HTMLElement>(initialWidth: number, initialH
|
|||
return () => {
|
||||
window.removeEventListener('resize', debounceFunc);
|
||||
};
|
||||
}, [domRef]);
|
||||
}, [domRef, ...deps]);
|
||||
|
||||
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>
|
After Width: | Height: | Size: 591 B |
|
@ -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>
|
After Width: | Height: | Size: 2.4 KiB |
|
@ -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>
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.5 KiB |
|
@ -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>
|
Before Width: | Height: | Size: 472 B |
|
@ -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>
|
After Width: | Height: | Size: 447 B |
|
@ -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>
|
After Width: | Height: | Size: 1.5 KiB |
|
@ -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>
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
@ -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>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -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>
|
Before Width: | Height: | Size: 472 B |
|
@ -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>
|
After Width: | Height: | Size: 1.5 KiB |
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
height: 100%;
|
||||
background-color: #f9fafb;
|
||||
&__tabs-container {
|
||||
height: 49px;
|
||||
padding-left: 27px;
|
||||
background-image: url('../../assets/img/mirror-tabs-bg.png');
|
||||
background-image: url('../../assets/img/page-title-bg.png');
|
||||
}
|
||||
|
||||
&__content {
|
||||
|
@ -24,20 +25,6 @@
|
|||
&__table {
|
||||
height: calc(100% - 44px);
|
||||
margin-top: 12px;
|
||||
:global {
|
||||
.ant-table-wrapper {
|
||||
height: 100%;
|
||||
.ant-spin-nested-loading {
|
||||
height: 100%;
|
||||
}
|
||||
.ant-spin-container {
|
||||
height: 100%;
|
||||
}
|
||||
.ant-table {
|
||||
height: calc(100% - 74px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
* @Date: 2024-04-16 13:58:08
|
||||
* @Description: 镜像列表
|
||||
*/
|
||||
import KFIcon from '@/components/KFIcon';
|
||||
import { CommonTabKeys } from '@/enums';
|
||||
import { useDomSize } from '@/hooks';
|
||||
import { getMirrorListReq } from '@/services/mirror';
|
||||
import { to } from '@/utils/promise';
|
||||
import { Icon } from '@umijs/max';
|
||||
import { Button, Input, Table, Tabs } from 'antd';
|
||||
import { Icon, useNavigate } from '@umijs/max';
|
||||
import { Button, Input, Table, TablePaginationConfig, TableProps, Tabs } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import dayjs from 'dayjs';
|
||||
import { useEffect, useState } from 'react';
|
||||
import styles from './list.less';
|
||||
|
@ -26,11 +27,19 @@ const mirrorTabItems = [
|
|||
},
|
||||
];
|
||||
|
||||
export type MirrorData = {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
create_time: string;
|
||||
};
|
||||
|
||||
function MirrorList() {
|
||||
const navgite = useNavigate();
|
||||
const [activeTab, setActiveTab] = useState('Public');
|
||||
const [tableData, setTableData] = useState([]);
|
||||
const [contentRef, { height: tableHeight }] = useDomSize<HTMLDivElement>(0, 0);
|
||||
const [pagination, setPagination] = useState({
|
||||
const [searchText, setSearchText] = useState('');
|
||||
const [tableData, setTableData] = useState<MirrorData[]>([]);
|
||||
const [pagination, setPagination] = useState<TablePaginationConfig>({
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
current: 1,
|
||||
|
@ -38,10 +47,56 @@ function MirrorList() {
|
|||
total: 0,
|
||||
});
|
||||
useEffect(() => {
|
||||
getMirrorList('');
|
||||
getMirrorList();
|
||||
}, [activeTab]);
|
||||
|
||||
const columns = [
|
||||
// 获取镜像列表
|
||||
const getMirrorList = async () => {
|
||||
const params = {
|
||||
page: pagination.current! - 1,
|
||||
size: pagination.pageSize,
|
||||
name: searchText,
|
||||
image_type: activeTab === CommonTabKeys.Public ? 1 : 0,
|
||||
};
|
||||
const [res] = await to(getMirrorListReq(params));
|
||||
if (res && res.data) {
|
||||
const { content = [], totalElements = 0 } = res.data;
|
||||
setTableData(content);
|
||||
setPagination((prev) => ({
|
||||
...prev,
|
||||
total: totalElements,
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
// 搜索
|
||||
const onSearch = () => {
|
||||
getMirrorList();
|
||||
};
|
||||
|
||||
// 查看详情
|
||||
const toDetail = (record: MirrorData) => {
|
||||
console.log('record', record);
|
||||
navgite({
|
||||
pathname: `/dataset/mirror/${record.id}?isPublic=${activeTab === CommonTabKeys.Public}`,
|
||||
});
|
||||
};
|
||||
|
||||
// 创建镜像
|
||||
const createMirror = () => {
|
||||
navgite({ pathname: `/dataset/mirror/create?isPublic=${activeTab === CommonTabKeys.Public}` });
|
||||
};
|
||||
|
||||
// 分页切换
|
||||
const handleTableChange: TableProps['onChange'] = (pagination, filters, sorter, { action }) => {
|
||||
if (action === 'paginate') {
|
||||
setPagination(pagination);
|
||||
getMirrorList();
|
||||
}
|
||||
console.log(pagination, filters, sorter, action);
|
||||
};
|
||||
|
||||
const columns: TableProps<MirrorData>['columns'] = [
|
||||
{
|
||||
title: '镜像名称',
|
||||
dataIndex: 'name',
|
||||
|
@ -71,45 +126,38 @@ function MirrorList() {
|
|||
{
|
||||
title: '操作',
|
||||
dataIndex: 'operation',
|
||||
width: '100px',
|
||||
width: '15%',
|
||||
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 (
|
||||
<div className={styles['mirror-list']}>
|
||||
<div className={styles['mirror-list__tabs-container']}>
|
||||
|
@ -126,21 +174,36 @@ function MirrorList() {
|
|||
placeholder="按数据集名称筛选"
|
||||
allowClear
|
||||
onSearch={onSearch}
|
||||
onChange={(e) => setSearchText(e.target.value)}
|
||||
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
|
||||
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>
|
||||
</div>
|
||||
<div className={styles['mirror-list__content__table']} ref={contentRef}>
|
||||
<div className={classNames('vertical-scroll-table', styles['mirror-list__content__table'])}>
|
||||
<Table
|
||||
dataSource={tableData}
|
||||
columns={columns}
|
||||
scroll={{ y: tableHeight - 55 - 74 }}
|
||||
scroll={{ y: 'calc(100% - 55px)' }}
|
||||
pagination={pagination}
|
||||
onChange={handleTableChange}
|
||||
rowKey="id"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -80,6 +80,8 @@ const Props = forwardRef(({ onParentChange }, ref) => {
|
|||
// setTimeout(() => {
|
||||
// console.log(stagingItem);
|
||||
// }, (500));
|
||||
setSelectedModel(undefined);
|
||||
setSelectedDataset(undefined);
|
||||
setOpen(true);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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 不起作用,感觉是哪里被重置了
|
||||
@kf-primary-color: #1664ff; // 主色调
|
||||
@primary-color-hover: #4086ff;
|
||||
@background-color: #f9fafb; // 页面背景颜色
|
||||
@text-color: #1d1d20;
|
||||
@text-color-second: #575757;
|
||||
@font-size: 15px;
|
||||
@border-color: rgba(22, 100, 255, 0.3);
|
||||
@border-color-second: rgba(22, 100, 255, 0.1);
|
||||
|
|