| @@ -1,12 +1,9 @@ | |||||
| @import '@/styles/theme.less'; | |||||
| html, | html, | ||||
| body, | body, | ||||
| #root { | #root { | ||||
| height: 100%; | height: 100%; | ||||
| margin: 0; | margin: 0; | ||||
| padding: 0; | padding: 0; | ||||
| overflow-y: hidden; | |||||
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, | 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 Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', | ||||
| 'Noto Color Emoji'; | 'Noto Color Emoji'; | ||||
| @@ -35,24 +32,28 @@ body { | |||||
| -moz-osx-font-smoothing: grayscale; | -moz-osx-font-smoothing: grayscale; | ||||
| } | } | ||||
| .ant-pro-layout .ant-pro-layout-content { | .ant-pro-layout .ant-pro-layout-content { | ||||
| padding: 0 10px 10px; | |||||
| overflow-y: hidden; | |||||
| background-color: @background-color; | |||||
| padding: 10px; | |||||
| } | } | ||||
| .ant-pro-layout .ant-pro-layout-bg-list { | .ant-pro-layout .ant-pro-layout-bg-list { | ||||
| background: @background-color; | |||||
| background: #f9fafb; | |||||
| } | } | ||||
| .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 { | .ant-pro-base-menu-inline-item-title .ant-pro-base-menu-inline-item-text { | ||||
| color: #1d1d20; | |||||
| // color: #1d1d20; | |||||
| font-size: 16px; | font-size: 16px; | ||||
| } | } | ||||
| // .ant-menu-light .ant-menu-item-selected{ | |||||
| // color:#1664ff; | |||||
| // } | |||||
| .ant-pro-layout .ant-pro-sider-menu { | .ant-pro-layout .ant-pro-sider-menu { | ||||
| padding-top: 40px; | padding-top: 40px; | ||||
| } | } | ||||
| @@ -74,7 +75,9 @@ body { | |||||
| background: #f2f5f7; | background: #f2f5f7; | ||||
| border-radius: 0px 20px 20px 0px; | 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; | padding: 0; | ||||
| } | } | ||||
| @@ -84,6 +87,9 @@ body { | |||||
| .ant-drawer .ant-drawer-body .ant-form-item { | .ant-drawer .ant-drawer-body .ant-form-item { | ||||
| margin-bottom: 20px; | 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; | ||||
| @@ -99,8 +105,7 @@ body { | |||||
| height: 94vh; | height: 94vh; | ||||
| } | } | ||||
| .ant-pro-layout .ant-pro-layout-container { | .ant-pro-layout .ant-pro-layout-container { | ||||
| height: 100vh; | |||||
| overflow-y: hidden; | |||||
| height: 98vh; | |||||
| } | } | ||||
| .ant-modal-confirm .ant-modal-confirm-paragraph { | .ant-modal-confirm .ant-modal-confirm-paragraph { | ||||
| margin: 54px 0 auto; | margin: 54px 0 auto; | ||||
| @@ -117,7 +122,7 @@ body { | |||||
| width: 110px; | width: 110px; | ||||
| height: 40px; | height: 40px; | ||||
| margin-right: 10px; | margin-right: 10px; | ||||
| color: #1d1d20; | |||||
| // color: #1d1d20; | |||||
| font-size: 18px; | font-size: 18px; | ||||
| background: rgba(22, 100, 255, 0.06); | background: rgba(22, 100, 255, 0.06); | ||||
| border-color: transparent; | border-color: transparent; | ||||
| @@ -132,6 +137,7 @@ body { | |||||
| height: 40px; | height: 40px; | ||||
| font-size: 18px; | font-size: 18px; | ||||
| border-radius: 10px; | border-radius: 10px; | ||||
| border-radius: 10px; | |||||
| } | } | ||||
| .ant-modal .ant-input-affix-wrapper { | .ant-modal .ant-input-affix-wrapper { | ||||
| height: 46px; | height: 46px; | ||||
| @@ -163,7 +169,6 @@ body { | |||||
| background-repeat: no-repeat; | background-repeat: no-repeat; | ||||
| background-position: top center; | background-position: top center; | ||||
| background-size: 100%; | background-size: 100%; | ||||
| border-radius: 21px; | |||||
| border-radius: 0; | border-radius: 0; | ||||
| } | } | ||||
| .ant-modal .ant-modal-content { | .ant-modal .ant-modal-content { | ||||
| @@ -190,6 +195,17 @@ body { | |||||
| border-radius: 6px; | 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 { | // ::-webkit-scrollbar-button { | ||||
| // background: #97a1bd; | // background: #97a1bd; | ||||
| // } | // } | ||||
| @@ -1 +0,0 @@ | |||||
| <svg xmlns="http://www.w3.org/2000/svg" width="12.572" height="12.993" viewBox="0 0 12.572 12.993" fill="currentColor"><path class="a" d="M88.236,67l-5.66-2.951a.627.627,0,0,0-.579,0l-5.655,2.906a.627.627,0,0,0-.342.558v6.009a.629.629,0,0,0,.348.563l5.658,2.82a.627.627,0,0,0,.561,0l5.657-2.82a.629.629,0,0,0,.348-.563V67.555A.626.626,0,0,0,88.236,67Zm-6,2.842-2.124-1.046,4.811-2.577L87,67.3Zm.045-5,1.742.909-4.836,2.59-1.9-.934Zm-5.447,3.276,2.007.988v2.2a.419.419,0,0,0,.838,0V69.516l2.184,1.075V75.9l-5.029-2.509ZM82.705,75.9V70.54l5.029-2.681v5.531Z" transform="translate(-76 -63.975)"/></svg> | |||||
| @@ -1 +0,0 @@ | |||||
| <svg xmlns="http://www.w3.org/2000/svg" width="11.246" height="11.246" viewBox="0 0 11.246 11.246" fill="currentColor"><path class="a" d="M70.025,64a.2.2,0,0,1,.2.2V75.045a.2.2,0,0,1-.2.2h-.8a.2.2,0,0,1-.2-.2V64.2a.2.2,0,0,1,.2-.2Zm-2.008,1.2a.2.2,0,0,1,.2.2v.8a.2.2,0,0,1-.2.2H65.2v6.426h2.812a.2.2,0,0,1,.2.2v.8a.2.2,0,0,1-.2.2H64.2a.2.2,0,0,1-.2-.2V65.406a.2.2,0,0,1,.2-.2Zm6.226,7.631v1.2h-1.2v-1.2Zm-2.008,0v1.2h-1.2v-1.2Zm3.012-1.807v1.2h-1.2v-1.2Zm0-2.008v1.2h-1.2v-1.2Zm0-2.008v1.2h-1.2v-1.2ZM72.234,65.2v1.2h-1.2V65.2Zm2.008,0v1.2h-1.2V65.2Z" transform="translate(-64 -64)"/></svg> | |||||
| @@ -1 +0,0 @@ | |||||
| <svg xmlns="http://www.w3.org/2000/svg" width="12.036" height="13.5" viewBox="0 0 12.036 13.5" fill="currentColor" stroke="currentColor"><defs><style>.a{stroke-width:0.1px;}</style></defs><g transform="translate(-205.25 -176.646)"><path class="a" d="M211.268,190.1a1.261,1.261,0,0,1-.626-.167l-4.717-2.721a1.255,1.255,0,0,1-.626-1.084v-5.442a1.258,1.258,0,0,1,.626-1.084l4.717-2.721a1.271,1.271,0,0,1,1.251,0l4.717,2.721a1.255,1.255,0,0,1,.626,1.084v5.442a1.255,1.255,0,0,1-.626,1.084l-4.717,2.721A1.276,1.276,0,0,1,211.268,190.1Zm0-12.6a.478.478,0,0,0-.232.062l-4.717,2.721a.466.466,0,0,0-.232.4v5.442a.464.464,0,0,0,.232.4l4.717,2.721a.469.469,0,0,0,.463,0l4.717-2.721a.466.466,0,0,0,.232-.4V180.68a.464.464,0,0,0-.232-.4l-4.717-2.721A.465.465,0,0,0,211.268,177.5Z" transform="translate(0 0)"/><path class="a" d="M282.168,379.033a1.242,1.242,0,0,1-.616-.163l-3.722-2.1a.394.394,0,1,1,.387-.685l3.722,2.1a.461.461,0,0,0,.451,0l3.847-2.105a.394.394,0,1,1,.377.691l-3.845,2.107A1.251,1.251,0,0,1,282.168,379.033Z" transform="translate(-70.894 -195.36)"/><path class="a" d="M486.392,383.935a.392.392,0,0,1-.393-.4l.016-4.236a1.252,1.252,0,0,1,.653-1.094l3.8-2.067a.393.393,0,1,1,.375.691l-3.8,2.067a.467.467,0,0,0-.242.405l-.016,4.236A.394.394,0,0,1,486.392,383.935Z" transform="translate(-275.124 -195.422)"/><path class="a" d="M282.23,383.9a.392.392,0,0,1-.393-.391l-.016-4.236a.463.463,0,0,0-.242-.407l-3.678-2.069a.394.394,0,0,1,.385-.687l3.676,2.067a1.245,1.245,0,0,1,.647,1.092l.016,4.234a.4.4,0,0,1-.4.4Z" transform="translate(-70.962 -195.384)"/></g></svg> | |||||
| @@ -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; | ||||
| @@ -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> | ||||
| </> | </> | ||||
| @@ -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 | ||||
| @@ -99,22 +99,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(); | ||||
| @@ -10,6 +10,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); | ||||
| @@ -78,6 +79,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); | ||||
| @@ -104,6 +114,15 @@ const Props = forwardRef(({ onParentChange }, ref) => { | |||||
| setOpen(true); | setOpen(true); | ||||
| } | } | ||||
| }, | }, | ||||
| propClose: async () => { | |||||
| setOpen(false); | |||||
| const [openRes, propsError] = await to(setOpen(false)); | |||||
| console.log(setOpen(false)); | |||||
| }, | |||||
| // propClose() { | |||||
| // setOpen(false); | |||||
| // }, | |||||
| })); | })); | ||||
| // 选择数据集、模型 | // 选择数据集、模型 | ||||
| @@ -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)); | ||||
| } | } | ||||
| /** | /** | ||||
| * 通过主键查询单条数据 | * 通过主键查询单条数据 | ||||
| * | * | ||||
| @@ -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; | ||||
| } | } | ||||
| @@ -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); | |||||
| } | } | ||||
| } | } | ||||
| @@ -382,9 +382,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; | |||||
| } | |||||
| } | } | ||||
| @@ -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> | ||||
| <!--查询指定行数据--> | <!--查询指定行数据--> | ||||