diff --git a/react-ui/config/config.ts b/react-ui/config/config.ts index 4ecf3ebd..d0830923 100644 --- a/react-ui/config/config.ts +++ b/react-ui/config/config.ts @@ -1,12 +1,14 @@ // https://umijs.org/config/ import { defineConfig } from '@umijs/max'; -import { join } from 'path'; +import { join, resolve } from 'path'; import defaultSettings from './defaultSettings'; import proxy from './proxy'; import routes from './routes'; const { REACT_APP_ENV = 'dev' } = process.env; +console.log('zzz', resolve(__dirname, '../src/styles/theme.less')); + export default defineConfig({ /** * @name 开启 hash 模式 @@ -39,7 +41,8 @@ export default defineConfig({ theme: { // 如果不想要 configProvide 动态设置主题需要把这个设置为 default // 只有设置为 variable, 才能使用 configProvide 动态设置主色调 - 'root-entry-name': 'variable', + // 'root-entry-name': 'variable', + 'kf-success-color': '#ff0000', }, /** * @name moment 的国际化配置 @@ -157,4 +160,10 @@ export default defineConfig({ }, requestRecord: {}, icons: {}, + lessLoader: { + modifyVars: { + hack: 'true; @import "@/styles/theme.less";', + }, + javascriptEnabled: true, + }, }); diff --git a/react-ui/config/proxy.ts b/react-ui/config/proxy.ts index 2b02d8f0..0fdf89e3 100644 --- a/react-ui/config/proxy.ts +++ b/react-ui/config/proxy.ts @@ -1,3 +1,8 @@ +/* + * @Author: 赵伟 + * @Date: 2024-04-17 08:48:09 + * @Description: + */ /** * @name 代理的配置 * @see 在生产环境 代理是无法生效的,所以这里没有生产环境的配置 @@ -16,8 +21,8 @@ export default { '/api/': { // 要代理的地址 // target: 'http://172.20.32.181:31205', - // target: 'http://172.20.32.98:8082', - target: 'http://172.20.32.150:8082', + target: 'http://172.20.32.98:8082', + // target: 'http://172.20.32.150:8082', // 配置了这个可以从 http 代理到 https // 依赖 origin 的功能可能需要这个,比如 cookie changeOrigin: true, diff --git a/react-ui/jsconfig.json b/react-ui/jsconfig.json deleted file mode 100644 index 197bee5d..00000000 --- a/react-ui/jsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "jsx": "react-jsx", - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "baseUrl": ".", - "paths": { - "@/*": ["./src/*"] - } - } -} diff --git a/react-ui/public/assets/images/backup/component-icon-7-Failed.png b/react-ui/public/assets/images/backup/component-icon-7-Failed.png new file mode 100644 index 00000000..2427996b Binary files /dev/null and b/react-ui/public/assets/images/backup/component-icon-7-Failed.png differ diff --git a/react-ui/public/assets/images/backup/component-icon-7-Omitted.png b/react-ui/public/assets/images/backup/component-icon-7-Omitted.png new file mode 100644 index 00000000..33a4445e Binary files /dev/null and b/react-ui/public/assets/images/backup/component-icon-7-Omitted.png differ diff --git a/react-ui/public/assets/images/backup/component-icon-7-Pending.png b/react-ui/public/assets/images/backup/component-icon-7-Pending.png new file mode 100644 index 00000000..12a5aa4e Binary files /dev/null and b/react-ui/public/assets/images/backup/component-icon-7-Pending.png differ diff --git a/react-ui/public/assets/images/backup/component-icon-7-Running.png b/react-ui/public/assets/images/backup/component-icon-7-Running.png new file mode 100644 index 00000000..0328188f Binary files /dev/null and b/react-ui/public/assets/images/backup/component-icon-7-Running.png differ diff --git a/react-ui/public/assets/images/backup/component-icon-7-Skipped.png b/react-ui/public/assets/images/backup/component-icon-7-Skipped.png new file mode 100644 index 00000000..33a4445e Binary files /dev/null and b/react-ui/public/assets/images/backup/component-icon-7-Skipped.png differ diff --git a/react-ui/public/assets/images/backup/component-icon-7-Succeeded.png b/react-ui/public/assets/images/backup/component-icon-7-Succeeded.png new file mode 100644 index 00000000..30676934 Binary files /dev/null and b/react-ui/public/assets/images/backup/component-icon-7-Succeeded.png differ diff --git a/react-ui/public/assets/images/backup/component-icon-7.png b/react-ui/public/assets/images/backup/component-icon-7.png new file mode 100644 index 00000000..c0c1087c Binary files /dev/null and b/react-ui/public/assets/images/backup/component-icon-7.png differ diff --git a/react-ui/public/assets/images/component-icon-7-Failed.png b/react-ui/public/assets/images/component-icon-7-Failed.png index 2427996b..9854dc38 100644 Binary files a/react-ui/public/assets/images/component-icon-7-Failed.png and b/react-ui/public/assets/images/component-icon-7-Failed.png differ diff --git a/react-ui/public/assets/images/component-icon-7-Omitted.png b/react-ui/public/assets/images/component-icon-7-Omitted.png index 33a4445e..59b81026 100644 Binary files a/react-ui/public/assets/images/component-icon-7-Omitted.png and b/react-ui/public/assets/images/component-icon-7-Omitted.png differ diff --git a/react-ui/public/assets/images/component-icon-7-Pending.png b/react-ui/public/assets/images/component-icon-7-Pending.png index 12a5aa4e..bf06cf26 100644 Binary files a/react-ui/public/assets/images/component-icon-7-Pending.png and b/react-ui/public/assets/images/component-icon-7-Pending.png differ diff --git a/react-ui/public/assets/images/component-icon-7-Running.png b/react-ui/public/assets/images/component-icon-7-Running.png index 0328188f..6dcc20d6 100644 Binary files a/react-ui/public/assets/images/component-icon-7-Running.png and b/react-ui/public/assets/images/component-icon-7-Running.png differ diff --git a/react-ui/public/assets/images/component-icon-7-Skipped.png b/react-ui/public/assets/images/component-icon-7-Skipped.png index 33a4445e..59b81026 100644 Binary files a/react-ui/public/assets/images/component-icon-7-Skipped.png and b/react-ui/public/assets/images/component-icon-7-Skipped.png differ diff --git a/react-ui/public/assets/images/component-icon-7-Succeeded.png b/react-ui/public/assets/images/component-icon-7-Succeeded.png index 30676934..f12a5a82 100644 Binary files a/react-ui/public/assets/images/component-icon-7-Succeeded.png and b/react-ui/public/assets/images/component-icon-7-Succeeded.png differ diff --git a/react-ui/public/assets/images/component-icon-7.png b/react-ui/public/assets/images/component-icon-7.png index c0c1087c..d550d28c 100644 Binary files a/react-ui/public/assets/images/component-icon-7.png and b/react-ui/public/assets/images/component-icon-7.png differ diff --git a/react-ui/public/assets/images/component-icon-8-Failed.png b/react-ui/public/assets/images/component-icon-8-Failed.png new file mode 100644 index 00000000..a5d20128 Binary files /dev/null and b/react-ui/public/assets/images/component-icon-8-Failed.png differ diff --git a/react-ui/public/assets/images/component-icon-8-Omitted.png b/react-ui/public/assets/images/component-icon-8-Omitted.png new file mode 100644 index 00000000..ab0015cc Binary files /dev/null and b/react-ui/public/assets/images/component-icon-8-Omitted.png differ diff --git a/react-ui/public/assets/images/component-icon-8-Pending.png b/react-ui/public/assets/images/component-icon-8-Pending.png new file mode 100644 index 00000000..3dfc540e Binary files /dev/null and b/react-ui/public/assets/images/component-icon-8-Pending.png differ diff --git a/react-ui/public/assets/images/component-icon-8-Running.png b/react-ui/public/assets/images/component-icon-8-Running.png new file mode 100644 index 00000000..4713143e Binary files /dev/null and b/react-ui/public/assets/images/component-icon-8-Running.png differ diff --git a/react-ui/public/assets/images/component-icon-8-Skipped.png b/react-ui/public/assets/images/component-icon-8-Skipped.png new file mode 100644 index 00000000..ab0015cc Binary files /dev/null and b/react-ui/public/assets/images/component-icon-8-Skipped.png differ diff --git a/react-ui/public/assets/images/component-icon-8-Succeeded.png b/react-ui/public/assets/images/component-icon-8-Succeeded.png new file mode 100644 index 00000000..c890e8a1 Binary files /dev/null and b/react-ui/public/assets/images/component-icon-8-Succeeded.png differ diff --git a/react-ui/public/assets/images/component-icon-8.png b/react-ui/public/assets/images/component-icon-8.png new file mode 100644 index 00000000..81dfbe9e Binary files /dev/null and b/react-ui/public/assets/images/component-icon-8.png differ diff --git a/react-ui/src/app.tsx b/react-ui/src/app.tsx index 5c255b73..cd88f984 100644 --- a/react-ui/src/app.tsx +++ b/react-ui/src/app.tsx @@ -156,7 +156,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState }) => { export async function onRouteChange({ clientRoutes, location }: any) { const menus = getRemoteMenu(); - console.log('onRouteChange', clientRoutes, location, menus); + // console.log('onRouteChange', clientRoutes, location, menus); if (menus === null && location.pathname !== PageEnum.LOGIN) { console.log('refresh'); history.go(0); @@ -164,16 +164,16 @@ export async function onRouteChange({ clientRoutes, location }: any) { } export function patchRoutes({ routes, routeComponents }: any) { - console.log('patchRoutes', routes, routeComponents); + //console.log('patchRoutes', routes, routeComponents); } export async function patchClientRoutes({ routes }: any) { - console.log('patchClientRoutes', routes); + // console.log('patchClientRoutes', routes); patchRouteWithRemoteMenus(routes); } export function render(oldRender: () => void) { - console.log('render get routers', oldRender); + // console.log('render get routers', oldRender); const token = getAccessToken(); if (!token || token?.length === 0) { oldRender(); @@ -190,10 +190,38 @@ export const antd: RuntimeAntdConfig = (memo) => { memo.theme ??= {}; memo.theme.token = { colorPrimary: themes['primaryColor'], + colorSuccess: themes['successColor'], + colorError: themes['errorColor'], + colorWarning: themes['warningColor'], + // fontSize: themes['fontSize'], }; memo.theme.components ??= {}; memo.theme.components.Tabs = {}; - // memo.theme.cssVar = true; + memo.theme.components.Button = { + defaultBg: 'rgba(22, 100, 255, 0.06)', + defaultBorderColor: 'rgba(22, 100, 255, 0.11)', + defaultColor: themes['textColor'], + defaultHoverBg: 'rgba(22, 100, 255, 0.06)', + defaultHoverBorderColor: 'rgba(22, 100, 255, 0.5)', + defaultHoverColor: '#3F7FFF ', + defaultActiveBg: 'rgba(22, 100, 255, 0.12)', + defaultActiveBorderColor: 'rgba(22, 100, 255, 0.75)', + defaultActiveColor: themes['primaryColor'], + contentFontSize: themes['fontSize'], + paddingBlock: 4, + paddingInline: 15, + controlHeight: 34, + }; + memo.theme.components.Input = { + inputFontSize: themes['fontSize'], + paddingBlock: 4, + paddingInline: 15, + }; + memo.theme.components.Table = { + headerBg: 'rgba(242, 244, 247, 0.36)', + headerBorderRadius: 4, + }; + memo.theme.cssVar = true; // memo.theme.hashed = false; // memo.appConfig = { diff --git a/react-ui/src/assets/img/clock.png b/react-ui/src/assets/img/clock.png new file mode 100644 index 00000000..a2068364 Binary files /dev/null and b/react-ui/src/assets/img/clock.png differ diff --git a/react-ui/src/assets/img/creatBy.png b/react-ui/src/assets/img/creatBy.png new file mode 100644 index 00000000..de3341cb Binary files /dev/null and b/react-ui/src/assets/img/creatBy.png differ diff --git a/react-ui/src/assets/img/modal-select-mirror.png b/react-ui/src/assets/img/modal-select-mirror.png new file mode 100644 index 00000000..93e12760 Binary files /dev/null and b/react-ui/src/assets/img/modal-select-mirror.png differ diff --git a/react-ui/src/assets/svg/modal-close.svg b/react-ui/src/assets/svg/modal-close.svg deleted file mode 100644 index 1345011e..00000000 --- a/react-ui/src/assets/svg/modal-close.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/assets/svg/parameter.svg b/react-ui/src/assets/svg/parameter.svg deleted file mode 100644 index 58803521..00000000 --- a/react-ui/src/assets/svg/parameter.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/assets/svg/save--return.svg b/react-ui/src/assets/svg/save--return.svg deleted file mode 100644 index 73fd196d..00000000 --- a/react-ui/src/assets/svg/save--return.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/assets/svg/view-param.svg b/react-ui/src/assets/svg/view-param.svg deleted file mode 100644 index 3eb2efce..00000000 --- a/react-ui/src/assets/svg/view-param.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/components/KFRadio/index.less b/react-ui/src/components/KFRadio/index.less index f9a277b1..7a941188 100644 --- a/react-ui/src/components/KFRadio/index.less +++ b/react-ui/src/components/KFRadio/index.less @@ -1,4 +1,4 @@ -@import '@/styles/theme.less'; +// @import '@/styles/theme.less'; .kf-radio { display: flex; @@ -8,7 +8,7 @@ display: flex; align-items: center; padding: 12px 20px; - color: @text-color-second; + color: @text-color-secondary; border: 1px solid #e0e0e0; border-radius: 8px; @@ -18,8 +18,8 @@ } &--active { - color: @kf-primary-color; - border: 1px solid @kf-primary-color; + color: @primary-color; + border: 1px solid @primary-color; } & + & { diff --git a/react-ui/src/components/ModalTitle/index.less b/react-ui/src/components/ModalTitle/index.less index 1ff70e81..24e10386 100644 --- a/react-ui/src/components/ModalTitle/index.less +++ b/react-ui/src/components/ModalTitle/index.less @@ -2,7 +2,7 @@ .modal_title { display: flex; align-items: center; - color: @kf-primary-color; + color: @primary-color; font-weight: 400; font-size: 20px; diff --git a/react-ui/src/components/RightContent/index.tsx b/react-ui/src/components/RightContent/index.tsx index 52a49bbd..c2a4a7bf 100644 --- a/react-ui/src/components/RightContent/index.tsx +++ b/react-ui/src/components/RightContent/index.tsx @@ -50,7 +50,7 @@ const GlobalHeaderRight: React.FC = () => { - + {/* */} ); }; diff --git a/react-ui/src/enums/index.ts b/react-ui/src/enums/index.ts index c610ecf3..0c0c7b81 100644 --- a/react-ui/src/enums/index.ts +++ b/react-ui/src/enums/index.ts @@ -3,3 +3,10 @@ export enum CommonTabKeys { Private = 'Private', // 私有 Public = 'Public', // 公开 } + +// 镜像状态 +export enum MirrorVersionStatus { + Available = 'available', // 可用 + Building = 'building', // 构建中 + Failed = 'failed', // 构建中 +} diff --git a/react-ui/src/global.less b/react-ui/src/global.less index 05925b9f..43894072 100644 --- a/react-ui/src/global.less +++ b/react-ui/src/global.less @@ -1,12 +1,9 @@ -@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'; @@ -34,36 +31,29 @@ body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } -a { - color: #1664ff; -} -.ant-btn-link { - color: #1664ff; -} .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 { - background: @background-color; -} -.ant-table-wrapper .ant-table-thead > tr > th { - background-color: #fff; -} -.ant-table-wrapper .ant-table-thead > tr > td { - background-color: #fff; + background: #f9fafb; } + .ant-menu-light .ant-menu-item-selected { 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 { background: #f2f5f7; } .ant-pro-base-menu-inline-item-title .ant-pro-base-menu-inline-item-text { - color: #1d1d20; + // color: #1d1d20; font-size: 16px; } +// .ant-menu-light .ant-menu-item-selected{ +// color:#1664ff; +// } .ant-pro-layout .ant-pro-sider-menu { padding-top: 40px; } @@ -85,7 +75,9 @@ a { background: #f2f5f7; border-radius: 0px 20px 20px 0px; } - +.ant-pro-layout .ant-pro-layout-content { + background-color: transparent; +} .ant-drawer .ant-drawer-body { padding: 0; } @@ -95,6 +87,9 @@ a { .ant-drawer .ant-drawer-body .ant-form-item { margin-bottom: 20px; } +.ant-menu .ant-menu-submenu-title .anticon { + font-size: 16px; +} .ant-table-wrapper .ant-table-pagination.ant-pagination { margin: 0; padding: 21px 16px; @@ -110,8 +105,7 @@ a { height: 94vh; } .ant-pro-layout .ant-pro-layout-container { - height: 100vh; - overflow-y: hidden; + height: 98vh; } .ant-modal-confirm .ant-modal-confirm-paragraph { margin: 54px 0 auto; @@ -128,7 +122,7 @@ a { width: 110px; height: 40px; margin-right: 10px; - color: #1d1d20; + // color: #1d1d20; font-size: 18px; background: rgba(22, 100, 255, 0.06); border-color: transparent; @@ -142,7 +136,7 @@ a { width: 110px; height: 40px; font-size: 18px; - background: #1664ff; + border-radius: 10px; border-radius: 10px; } .ant-modal .ant-input-affix-wrapper { @@ -175,7 +169,6 @@ a { background-repeat: no-repeat; background-position: top center; background-size: 100%; - border-radius: 21px; border-radius: 0; } .ant-modal .ant-modal-content { @@ -189,8 +182,6 @@ a { } .ant-pagination .ant-pagination-item-active a { color: #fff; - background: #1664ff; - border-color: #1664ff; border-radius: 6px; } .ant-pagination .ant-pagination-item-active:hover { @@ -204,6 +195,17 @@ a { 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; // } @@ -242,7 +244,3 @@ ol { } } } - -.umi-local-svg { - vertical-align: -1px; -} diff --git a/react-ui/src/hooks/index.ts b/react-ui/src/hooks/index.ts index 32f162ad..24a80d81 100644 --- a/react-ui/src/hooks/index.ts +++ b/react-ui/src/hooks/index.ts @@ -3,14 +3,14 @@ * @Date: 2024-04-15 10:01:29 * @Description: */ +import { FormInstance } from 'antd'; import { debounce } from 'lodash'; import { useCallback, useEffect, useRef, useState } from 'react'; - /** - * Generates a state reference with the initial value. + * 生成具有初始值的状态引用 * - * @param initialValue - The initial value for the state - * @return An array containing the state value, state setter function, and a mutable reference object + * @param initialValue - 状态的初始值 + * @return 包含状态值、状态设置函数和可变引用对象的数组 */ export function useStateRef(initialValue: T) { const [value, setValue] = useState(initialValue); @@ -25,10 +25,10 @@ export function useStateRef(initialValue: T) { } /** - * Generates a custom hook for managing the visibility state of a modal. + * 生成一个自定义钩子,用于管理模态框的可见性状态。 * - * @param initialValue - The initial visibility state of the modal. - * @return An array containing the visibility state and functions to open and close the modal. + * @param initialValue - 模态框的初始可见性状态。 + * @return 一个数组,包含可见性状态和打开和关闭模态框的函数。 */ export function useVisible(initialValue: boolean) { const [visible, setVisible] = useState(initialValue); @@ -47,34 +47,34 @@ export function useVisible(initialValue: boolean) { type Callback = (state: T) => void; /** - * Generates a stateful value and a function to update it that triggers callbacks. + * 生成一个具有回调机制的可变状态值和更新它的函数。 * - * @param initialValue - The initial value of the state. - * @return A tuple containing the current state value and a function to update the state. + * @param initialValue - 初始状态值。 + * @return 一个元组,包含当前状态值和用于更新状态的函数。 */ export function useCallbackState(initialValue: T) { - const [state, _setState] = useState(initialValue); + const [state, _setState] = useState(initialValue); const callbackQueue = useRef[]>([]); useEffect(() => { callbackQueue.current.forEach((cb) => cb(state)); callbackQueue.current = []; }, [state]); - const setState = (newValue: T, callback: Callback) => { + const setState = (newValue: T | ((prevState: T) => T), callback?: Callback) => { _setState(newValue); if (callback && typeof callback === 'function') { callbackQueue.current.push(callback); } }; - return [state, setState]; + return [state, setState] as const; } /** - * A hook that tracks the size of a DOM element. + * 用于追踪 DOM 元素尺寸的 hook。 * - * @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. + * @param initialWidth - 初始宽度。 + * @param initialHeight - 初始高度。 + * @param deps - 依赖列表。 + * @return 一个元组,包含 DOM 元素的 ref、当前宽度和当前高度。 */ export function useDomSize( initialWidth: number, @@ -86,8 +86,6 @@ export function useDomSize( const [height, setHeight] = useState(initialHeight); useEffect(() => { - console.log('dddddd'); - const setDomHeight = () => { if (domRef.current) { setHeight(domRef.current.offsetHeight); @@ -106,3 +104,25 @@ export function useDomSize( return [domRef, { width, height }] as const; } + +/** + * 用于在 modal 关闭时重置 Form 表单的 hook。 + * + * @param form - Ant Design Form 表单实例 + * @param open - modal 是否打开 + */ +export const useResetFormOnCloseModal = (form: FormInstance, open: boolean) => { + const prevOpenRef = useRef(); + + useEffect(() => { + prevOpenRef.current = open; + }, [open]); + + const prevOpen = prevOpenRef.current; + + useEffect(() => { + if (!open && prevOpen) { + form.resetFields(); + } + }, [form, prevOpen, open]); +}; diff --git a/react-ui/src/iconfont/iconfont.js b/react-ui/src/iconfont/iconfont.js index 3695c17e..a7ee3e08 100644 --- a/react-ui/src/iconfont/iconfont.js +++ b/react-ui/src/iconfont/iconfont.js @@ -1 +1 @@ -window._iconfont_svg_string_4511447='',function(l){var a=(a=document.getElementsByTagName("script"))[a.length-1],t=a.getAttribute("data-injectcss"),a=a.getAttribute("data-disable-injectsvg");if(!a){var h,i,e,o,d,z=function(a,t){t.parentNode.insertBefore(a,t)};if(t&&!l.__iconfont__svg__cssinject__){l.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}h=function(){var a,t=document.createElement("div");t.innerHTML=l._iconfont_svg_string_4511447,(t=t.getElementsByTagName("svg")[0])&&(t.setAttribute("aria-hidden","true"),t.style.position="absolute",t.style.width=0,t.style.height=0,t.style.overflow="hidden",t=t,(a=document.body).firstChild?z(t,a.firstChild):a.appendChild(t))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(h,0):(i=function(){document.removeEventListener("DOMContentLoaded",i,!1),h()},document.addEventListener("DOMContentLoaded",i,!1)):document.attachEvent&&(e=h,o=l.document,d=!1,n(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,p())})}function p(){d||(d=!0,e())}function n(){try{o.documentElement.doScroll("left")}catch(a){return void setTimeout(n,50)}p()}}(window); \ No newline at end of file +window._iconfont_svg_string_4511447='',function(t){var a=(a=document.getElementsByTagName("script"))[a.length-1],h=a.getAttribute("data-injectcss"),a=a.getAttribute("data-disable-injectsvg");if(!a){var v,i,o,l,z,m=function(a,h){h.parentNode.insertBefore(a,h)};if(h&&!t.__iconfont__svg__cssinject__){t.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}v=function(){var a,h=document.createElement("div");h.innerHTML=t._iconfont_svg_string_4511447,(h=h.getElementsByTagName("svg")[0])&&(h.setAttribute("aria-hidden","true"),h.style.position="absolute",h.style.width=0,h.style.height=0,h.style.overflow="hidden",h=h,(a=document.body).firstChild?m(h,a.firstChild):a.appendChild(h))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(v,0):(i=function(){document.removeEventListener("DOMContentLoaded",i,!1),v()},document.addEventListener("DOMContentLoaded",i,!1)):document.attachEvent&&(o=v,l=t.document,z=!1,d(),l.onreadystatechange=function(){"complete"==l.readyState&&(l.onreadystatechange=null,n())})}function n(){z||(z=!0,o())}function d(){try{l.documentElement.doScroll("left")}catch(a){return void setTimeout(d,50)}n()}}(window); \ No newline at end of file diff --git a/react-ui/src/icons/add.svg b/react-ui/src/icons/add.svg deleted file mode 100644 index 272dd5ac..00000000 --- a/react-ui/src/icons/add.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/dataset-select-button.svg b/react-ui/src/icons/dataset-select-button.svg deleted file mode 100644 index 2a376d71..00000000 --- a/react-ui/src/icons/dataset-select-button.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/doc-not-inventory.svg b/react-ui/src/icons/doc-not-inventory.svg deleted file mode 100644 index bfd7d4b4..00000000 --- a/react-ui/src/icons/doc-not-inventory.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/mirror-select-button.svg b/react-ui/src/icons/mirror-select-button.svg deleted file mode 100644 index 59e5a215..00000000 --- a/react-ui/src/icons/mirror-select-button.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/modal-close.svg b/react-ui/src/icons/modal-close.svg deleted file mode 100644 index 1345011e..00000000 --- a/react-ui/src/icons/modal-close.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/model-select-button.svg b/react-ui/src/icons/model-select-button.svg deleted file mode 100644 index 525e061b..00000000 --- a/react-ui/src/icons/model-select-button.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/parameter.svg b/react-ui/src/icons/parameter.svg deleted file mode 100644 index 58803521..00000000 --- a/react-ui/src/icons/parameter.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/private-mirror-tab.svg b/react-ui/src/icons/private-mirror-tab.svg deleted file mode 100644 index 0898ad86..00000000 --- a/react-ui/src/icons/private-mirror-tab.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/public-mirror-tab.svg b/react-ui/src/icons/public-mirror-tab.svg deleted file mode 100644 index 0019be13..00000000 --- a/react-ui/src/icons/public-mirror-tab.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/refresh.svg b/react-ui/src/icons/refresh.svg deleted file mode 100644 index 00f51915..00000000 --- a/react-ui/src/icons/refresh.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/remove.svg b/react-ui/src/icons/remove.svg deleted file mode 100644 index b3519764..00000000 --- a/react-ui/src/icons/remove.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/view-detail.svg b/react-ui/src/icons/view-detail.svg deleted file mode 100644 index c74fe45a..00000000 --- a/react-ui/src/icons/view-detail.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/view-param.svg b/react-ui/src/icons/view-param.svg deleted file mode 100644 index 3eb2efce..00000000 --- a/react-ui/src/icons/view-param.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/下载.svg b/react-ui/src/icons/下载.svg deleted file mode 100644 index bf00e67e..00000000 --- a/react-ui/src/icons/下载.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/查看详情.svg b/react-ui/src/icons/查看详情.svg deleted file mode 100644 index ebdfa4b0..00000000 --- a/react-ui/src/icons/查看详情.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/overrides.less b/react-ui/src/overrides.less index 00735646..1b766517 100644 --- a/react-ui/src/overrides.less +++ b/react-ui/src/overrides.less @@ -36,3 +36,13 @@ margin-bottom: 0; } } + +// 表格样式 +.ant-table-header { + border: 1px solid rgba(167, 178, 194, 0.17); + border-bottom: none; +} + +.ant-table-wrapper .ant-table-thead > tr > td { + background-color: #fff; +} diff --git a/react-ui/src/pages/Dataset/index.less b/react-ui/src/pages/Dataset/index.less index 8be59a9d..2ff0b580 100644 --- a/react-ui/src/pages/Dataset/index.less +++ b/react-ui/src/pages/Dataset/index.less @@ -7,6 +7,7 @@ padding-right: 30px; background-image: url(/assets/images/pipeline-back.png); background-size: 100% 100%; + font-family: 'Alibaba'; } .datasetIntroTopBox { display: flex; @@ -38,6 +39,7 @@ background: #ffffff; border-radius: 10px; box-shadow: 0px 2px 12px rgba(180, 182, 191, 0.09); + font-family: alibaba; .dataButtonList { display: flex; align-items: center; @@ -68,6 +70,7 @@ .datasetBox { font-family: 'Alibaba'; background: #f9fafb; + :global { .ant-tabs-top > .ant-tabs-nav { margin: 0; @@ -117,6 +120,7 @@ margin-right: 10px; padding-top: 15px; background: #ffffff; + font-family: 'Alibaba'; box-shadow: 0px 3px 6px rgba(146, 146, 146, 0.09); .custTab { display: flex; @@ -136,6 +140,7 @@ padding: 15px 20px; overflow-x: hidden; overflow-y: auto; + font-family: 'Alibaba'; .itemTitle { margin-bottom: 15px; color: #1d1d20; @@ -223,38 +228,69 @@ flex: 1; flex-wrap: wrap; align-content: flex-start; - width: 100%; + + width: 102%; .dataItem { 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.5%; + height:164px; + background:#ffffff; + border:1px solid; + border-color:#eaeaea; + border-radius:4px; + margin: 0 20px 25px 0; cursor: pointer; .itemText { position: absolute; - top: 10px; + top: 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; + font-family: 'Alibaba'; + } + .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 { position: absolute; - bottom: 10px; + display: flex; + align-items: center; + bottom: 22px; left: 20px; color: #808080; - font-size: 14px; + font-size: 13px; } .itemIcon { position: absolute; + display: flex; + align-items: center; right: 20px; - bottom: 10px; + bottom: 22px; color: #808080; - font-size: 14px; + font-size: 13px; } } + .dataItem:hover{ + border-color: #1664FF; + box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.1) + + } + .dataItem:hover .itemText{ + color: #1664FF; + } } } } diff --git a/react-ui/src/pages/Dataset/personalData.jsx b/react-ui/src/pages/Dataset/personalData.jsx index cbebbd0a..3d183016 100644 --- a/react-ui/src/pages/Dataset/personalData.jsx +++ b/react-ui/src/pages/Dataset/personalData.jsx @@ -1,4 +1,6 @@ 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 { getDictSelectOption } from '@/services/system/dict'; import { PlusCircleOutlined, UploadOutlined } from '@ant-design/icons'; @@ -40,7 +42,7 @@ const PublicData = (React.FC = () => { }; const [queryFlow, setQueryFlow] = useState({ page: 0, - size: 10, + size: 20, name: null, available_range: 0, }); @@ -149,6 +151,11 @@ const PublicData = (React.FC = () => { const onFinishFailed = (errorInfo) => { console.log('Failed:', errorInfo); }; + const onPageChange = (pageNum, pageSize) => { + console.log(pageNum, pageSize); + setQueryFlow({ ...queryFlow, page: pageNum - 1, size: pageSize }); + getDatasetlist({ ...queryFlow, page: pageNum - 1, size: pageSize }); + }; useEffect(() => { getDictSelectOption('available_cluster').then((data) => { setClusterOptions(data); @@ -268,17 +275,19 @@ const PublicData = (React.FC = () => { ? datasetList.map((item) => { return (
routeToIntro(e, item)}> -
{item.name}
+ {item.name} +
{item.description}
- 最近更新: {moment(item.update_time).format('YYYY-MM-DD')} -
-
- 1582 + {item.create_by} +
+
+ + 最近更新: {moment(item.update_time).format('YYYY-MM-DD')}
); @@ -286,7 +295,14 @@ const PublicData = (React.FC = () => { : ''} {/* Demo */} - + { const onFinishFailed = (errorInfo) => { console.log('Failed:', errorInfo); }; + const onPageChange = (pageNum, pageSize) => { + console.log(pageNum, pageSize); + setQueryFlow({ ...queryFlow, page: pageNum - 1, size: pageSize }); + getDatasetlist({ ...queryFlow, page: pageNum - 1, size: pageSize }); + }; useEffect(() => { getAssetIconList(iconParams); getDatasetlist(queryFlow); @@ -217,17 +224,19 @@ const PublicData = (React.FC = () => { ? datasetList.map((item) => { return (
routeToIntro(e, item)}> -
{item.name}
+ {item.name} +
{item.description}
- 最近更新: {moment(item.update_time).format('YYYY-MM-DD')} -
-
- 1582 + {item.create_by} +
+
+ + 最近更新: {moment(item.update_time).format('YYYY-MM-DD')}
); @@ -235,7 +244,14 @@ const PublicData = (React.FC = () => { : ''} {/* Demo */} - + diff --git a/react-ui/src/pages/Experiment/experimentText/index.jsx b/react-ui/src/pages/Experiment/experimentText/index.jsx index 7911ec53..baa5bd04 100644 --- a/react-ui/src/pages/Experiment/experimentText/index.jsx +++ b/react-ui/src/pages/Experiment/experimentText/index.jsx @@ -1,4 +1,3 @@ -import { ReactComponent as ViewParam } from '@/assets/svg/view-param.svg'; import { useVisible } from '@/hooks'; import { getExperimentIns } from '@/services/experiment/index.js'; import { getWorkflowById } from '@/services/pipeline/index.js'; @@ -425,11 +424,7 @@ function ExperimentText() { {experimentStatusInfo[message.status]?.label} - diff --git a/react-ui/src/pages/Experiment/index.jsx b/react-ui/src/pages/Experiment/index.jsx index b79821f3..2eead78c 100644 --- a/react-ui/src/pages/Experiment/index.jsx +++ b/react-ui/src/pages/Experiment/index.jsx @@ -1,3 +1,4 @@ +import KFIcon from '@/components/KFIcon'; import { deleteExperimentById, deleteQueryByExperimentInsId, @@ -12,16 +13,11 @@ import { runTensorBoardReq, } from '@/services/experiment/index.js'; import { getWorkflow } from '@/services/pipeline/index.js'; +import themes from '@/styles/theme.less'; import { elapsedTime } from '@/utils/date'; import { to } from '@/utils/promise'; -import { - DeleteOutlined, - EditOutlined, - FieldTimeOutlined, - PlayCircleOutlined, - PlusCircleOutlined, -} from '@ant-design/icons'; -import { Button, Modal, Space, Table, message } from 'antd'; +import { modalConfirm } from '@/utils/ui'; +import { Button, ConfigProvider, Space, Table, message } from 'antd'; import momnet from 'moment'; import { useEffect, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; @@ -323,7 +319,7 @@ function Experiment() { type="link" size="small" key="run" - icon={} + icon={} onClick={() => { runExperiment(record.id); }} @@ -334,61 +330,45 @@ function Experiment() { type="link" size="small" key="edit" - icon={} + icon={} onClick={() => { editExperiment(record.id); }} > 编辑 - + + ), }, @@ -405,7 +385,7 @@ function Experiment() { type="primary" className={Styles.plusButton} onClick={createExperiment} - icon={} + icon={} > 新建实验 @@ -485,7 +465,7 @@ function Experiment() { item.status === 'Failed' || item.status === 'Terminated' } - icon={} + icon={} onClick={async () => { putQueryByExperimentInsId(item.id).then((ret) => { if (ret.code === 200) { @@ -499,35 +479,38 @@ function Experiment() { > 终止 - + + )) diff --git a/react-ui/src/pages/Experiment/status.ts b/react-ui/src/pages/Experiment/status.ts index 0a7b6652..2a075951 100644 --- a/react-ui/src/pages/Experiment/status.ts +++ b/react-ui/src/pages/Experiment/status.ts @@ -15,7 +15,10 @@ export enum ExperimentStatus { Omitted = 'Omitted', } -export const experimentStatusInfo: Record = { +type ExperimentStatusKeys = keyof typeof ExperimentStatus; +type ExperimentStatusValues = (typeof ExperimentStatus)[ExperimentStatusKeys]; + +export const experimentStatusInfo: Record = { Running: { label: '运行中', color: '#165bff', diff --git a/react-ui/src/pages/Mirror/components/MirrorStatusCell/index.less b/react-ui/src/pages/Mirror/components/MirrorStatusCell/index.less new file mode 100644 index 00000000..23c518c7 --- /dev/null +++ b/react-ui/src/pages/Mirror/components/MirrorStatusCell/index.less @@ -0,0 +1,13 @@ +//@import '@/styles/theme.less'; + +.mirror-status-cell { + color: @text-color; + + &--success { + color: @success-color; + } + + &--error { + color: @error-color; + } +} diff --git a/react-ui/src/pages/Mirror/components/MirrorStatusCell/index.tsx b/react-ui/src/pages/Mirror/components/MirrorStatusCell/index.tsx new file mode 100644 index 00000000..bf0522ed --- /dev/null +++ b/react-ui/src/pages/Mirror/components/MirrorStatusCell/index.tsx @@ -0,0 +1,40 @@ +/* + * @Author: 赵伟 + * @Date: 2024-04-18 18:35:41 + * @Description: + */ +import { MirrorVersionStatus } from '@/enums'; +import styles from './index.less'; + +type MirrorStatusCellProps = { + status: MirrorVersionStatus; +}; + +type MirrorVersionStatusKeys = keyof typeof MirrorVersionStatus; +type MirrorVersionStatusValues = (typeof MirrorVersionStatus)[MirrorVersionStatusKeys]; + +export type MirrorVersionStatusInfo = { + text: string; + classname: string; +}; + +const statusInfo: Record = { + [MirrorVersionStatus.Building]: { + text: '构建中', + classname: styles['mirror-status-cell'], + }, + [MirrorVersionStatus.Available]: { + classname: styles['mirror-status-cell--success'], + text: '可用', + }, + [MirrorVersionStatus.Failed]: { + classname: styles['mirror-status-cell--error'], + text: '构建失败', + }, +}; + +function MirrorStatusCell({ status }: MirrorStatusCellProps) { + return {statusInfo[status].text}; +} + +export default MirrorStatusCell; diff --git a/react-ui/src/pages/Mirror/create.tsx b/react-ui/src/pages/Mirror/create.tsx index e61cd665..4a87edbb 100644 --- a/react-ui/src/pages/Mirror/create.tsx +++ b/react-ui/src/pages/Mirror/create.tsx @@ -1,8 +1,9 @@ /* * @Author: 赵伟 * @Date: 2024-04-16 13:58:08 - * @Description: 镜像详情 + * @Description: 创建镜像 */ +import KFIcon from '@/components/KFIcon'; import KFRadio, { type KFRadioItem } from '@/components/KFRadio'; import PageTitle from '@/components/PageTitle'; import SubAreaTitle from '@/components/SubAreaTitle'; @@ -25,10 +26,12 @@ const mirrorRadioItems: KFRadioItem[] = [ { key: CommonTabKeys.Public, title: '基于公网镜像', + icon: , }, { key: CommonTabKeys.Private, title: '本地上传', + icon: , }, ]; diff --git a/react-ui/src/pages/Mirror/info.less b/react-ui/src/pages/Mirror/info.less index b96c0d7a..61d034d8 100644 --- a/react-ui/src/pages/Mirror/info.less +++ b/react-ui/src/pages/Mirror/info.less @@ -12,7 +12,7 @@ .label { width: 80px; - color: @text-color-second; + color: @text-color-secondary; } .value { diff --git a/react-ui/src/pages/Mirror/info.tsx b/react-ui/src/pages/Mirror/info.tsx index 5841fe26..8785f586 100644 --- a/react-ui/src/pages/Mirror/info.tsx +++ b/react-ui/src/pages/Mirror/info.tsx @@ -3,16 +3,20 @@ * @Date: 2024-04-16 13:58:08 * @Description: 镜像详情 */ +import KFIcon from '@/components/KFIcon'; import PageTitle from '@/components/PageTitle'; import SubAreaTitle from '@/components/SubAreaTitle'; +import { MirrorVersionStatus } from '@/enums'; import { useDomSize } from '@/hooks'; import { getMirrorInfoReq, getMirrorVersionListReq } from '@/services/mirror'; +import themes from '@/styles/theme.less'; import { to } from '@/utils/promise'; import { useParams, useSearchParams } from '@umijs/max'; -import { Button, Col, Row, Table, TablePaginationConfig, TableProps } from 'antd'; +import { Button, Col, ConfigProvider, Row, Table, TablePaginationConfig, TableProps } from 'antd'; import classNames from 'classnames'; import dayjs from 'dayjs'; import { useEffect, useState } from 'react'; +import MirrorStatusCell from './components/MirrorStatusCell'; import styles from './info.less'; type MirrorInfoData = { @@ -36,18 +40,20 @@ function MirrorInfo() { const [mirrorInfo, setMirrorInfo] = useState({}); const [tableData, setTableData] = useState([]); const [topRef, { height: topHeight }] = useDomSize(0, 0, [mirrorInfo]); + const [total, setTotal] = useState(0); const [pagination, setPagination] = useState({ showSizeChanger: true, showQuickJumper: true, current: 1, pageSize: 10, - total: 0, }); const isPublic = seachParams.get('isPublic') === 'true'; useEffect(() => { getMirrorInfo(); - getMirrorVersionList(); }, []); + useEffect(() => { + getMirrorVersionList(); + }, [pagination]); // 获取镜像详情 const getMirrorInfo = async () => { @@ -77,10 +83,7 @@ function MirrorInfo() { if (res && res.data) { const { content = [], totalElements = 0 } = res.data; setTableData(content); - setPagination((prev) => ({ - ...prev, - total: totalElements, - })); + setTotal(totalElements); } }; @@ -88,9 +91,7 @@ function MirrorInfo() { const handleTableChange: TableProps['onChange'] = (pagination, filters, sorter, { action }) => { if (action === 'paginate') { setPagination(pagination); - getMirrorVersionList(); } - console.log(pagination, filters, sorter, action); }; const downloadVersion = (record: MirrorVersionData) => {}; @@ -99,64 +100,61 @@ function MirrorInfo() { const columns: TableProps['columns'] = [ { title: '镜像版本', - dataIndex: 'version', - key: 'version', - width: '20%', + dataIndex: 'tag_name', + key: 'tag_name', + width: '25%', }, { title: '镜像地址', dataIndex: 'url', key: 'url', - width: '26%', }, { title: '状态', dataIndex: 'status', key: 'status', - width: '7%', + width: 150, + render: (text: string) => , }, { title: '镜像大小', dataIndex: 'file_size', key: 'file_size', - width: '7%', + width: 150, }, { title: '创建时间', dataIndex: 'create_time', key: 'create_time', - width: '20%', + width: 200, render: (text: string) => {dayjs(text).format('YYYY-MM-DD HH:mm:ss')}, }, { title: '操作', dataIndex: 'operation', - width: '20%', + width: 150, key: 'operation', + hidden: isPublic, render: (_: any, record: any) => (
- {!isPublic && ( - + + )}
), @@ -184,7 +182,7 @@ function MirrorInfo() {
版本数:
-
{mirrorInfo.version_count}
+
{mirrorInfo.version_count || '--'}
@@ -218,7 +216,7 @@ function MirrorInfo() { dataSource={tableData} columns={columns} scroll={{ y: 'calc(100% - 55px)' }} - pagination={pagination} + pagination={{ ...pagination, total }} onChange={handleTableChange} rowKey="id" /> diff --git a/react-ui/src/pages/Mirror/list.less b/react-ui/src/pages/Mirror/list.less index edd9183d..4f838b76 100644 --- a/react-ui/src/pages/Mirror/list.less +++ b/react-ui/src/pages/Mirror/list.less @@ -1,5 +1,3 @@ -@import '@/styles/theme.less'; - .mirror-list { height: 100%; &__tabs-container { diff --git a/react-ui/src/pages/Mirror/list.tsx b/react-ui/src/pages/Mirror/list.tsx index 53136147..c6881779 100644 --- a/react-ui/src/pages/Mirror/list.tsx +++ b/react-ui/src/pages/Mirror/list.tsx @@ -6,9 +6,18 @@ import KFIcon from '@/components/KFIcon'; import { CommonTabKeys } from '@/enums'; import { getMirrorListReq } from '@/services/mirror'; +import themes from '@/styles/theme.less'; import { to } from '@/utils/promise'; -import { Icon, useNavigate } from '@umijs/max'; -import { Button, Input, Table, TablePaginationConfig, TableProps, Tabs } from 'antd'; +import { useNavigate } from '@umijs/max'; +import { + Button, + ConfigProvider, + Input, + Table, + TablePaginationConfig, + TableProps, + Tabs, +} from 'antd'; import classNames from 'classnames'; import dayjs from 'dayjs'; import { useEffect, useState } from 'react'; @@ -18,12 +27,12 @@ const mirrorTabItems = [ { key: CommonTabKeys.Public, label: '公共镜像', - icon: , + icon: , }, { key: CommonTabKeys.Private, label: '个人镜像', - icon: , + icon: , }, ]; @@ -39,16 +48,16 @@ function MirrorList() { const [activeTab, setActiveTab] = useState('Public'); const [searchText, setSearchText] = useState(''); const [tableData, setTableData] = useState([]); + const [total, setTotal] = useState(0); const [pagination, setPagination] = useState({ showSizeChanger: true, showQuickJumper: true, current: 1, pageSize: 10, - total: 0, }); useEffect(() => { getMirrorList(); - }, [activeTab]); + }, [activeTab, pagination]); // 获取镜像列表 const getMirrorList = async () => { @@ -62,10 +71,7 @@ function MirrorList() { if (res && res.data) { const { content = [], totalElements = 0 } = res.data; setTableData(content); - setPagination((prev) => ({ - ...prev, - total: totalElements, - })); + setTotal(totalElements); } }; @@ -82,6 +88,9 @@ function MirrorList() { }); }; + // 删除镜像 + const deleteMirror = (record: MirrorData) => {}; + // 创建镜像 const createMirror = () => { navgite({ pathname: `/dataset/mirror/create?isPublic=${activeTab === CommonTabKeys.Public}` }); @@ -91,7 +100,6 @@ function MirrorList() { const handleTableChange: TableProps['onChange'] = (pagination, filters, sorter, { action }) => { if (action === 'paginate') { setPagination(pagination); - getMirrorList(); } console.log(pagination, filters, sorter, action); }; @@ -101,32 +109,31 @@ function MirrorList() { title: '镜像名称', dataIndex: 'name', key: 'name', - width: '10%', + width: '30%', }, { title: '版本数据', dataIndex: 'version_count', key: 'version_count', - width: '10%', + width: 100, }, { title: '镜像描述', dataIndex: 'description', key: 'description', - width: '50%', //ellipsis: true, }, { title: '创建时间', dataIndex: 'create_time', key: 'create_time', - width: '20%', + width: 200, render: (text: string) => {dayjs(text).format('YYYY-MM-DD HH:mm:ss')}, }, { title: '操作', dataIndex: 'operation', - width: '15%', + width: activeTab === CommonTabKeys.Private ? 200 : 150, key: 'operation', render: (_: any, record: any) => (
@@ -134,24 +141,29 @@ function MirrorList() { type="link" size="small" key="info" - // icon={} icon={} onClick={() => toDetail(record)} > 查看详情 {activeTab === CommonTabKeys.Private && ( - + + )}
), @@ -183,7 +195,7 @@ function MirrorList() { style={{ marginLeft: '20px' }} type="default" onClick={createMirror} - icon={} + icon={} > 制作镜像 @@ -192,7 +204,7 @@ function MirrorList() { style={{ marginRight: 0, marginLeft: 'auto' }} type="default" onClick={getMirrorList} - icon={} + icon={} > 刷新 @@ -202,7 +214,7 @@ function MirrorList() { dataSource={tableData} columns={columns} scroll={{ y: 'calc(100% - 55px)' }} - pagination={pagination} + pagination={{ ...pagination, total: total }} onChange={handleTableChange} rowKey="id" /> diff --git a/react-ui/src/pages/Model/index.less b/react-ui/src/pages/Model/index.less index 81a18b11..7bee2701 100644 --- a/react-ui/src/pages/Model/index.less +++ b/react-ui/src/pages/Model/index.less @@ -219,38 +219,68 @@ flex: 1; flex-wrap: wrap; align-content: flex-start; - width: 100%; + width: 102%; .dataItem { 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.5%; + height:164px; + background:#ffffff; + border:1px solid; + border-color:#eaeaea; + border-radius:4px; + margin: 0 20px 25px 0; cursor: pointer; .itemText { position: absolute; - top: 10px; + top: 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; + font-family: 'Alibaba'; + } + .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 { position: absolute; - bottom: 10px; + display: flex; + align-items: center; + bottom: 22px; left: 20px; color: #808080; - font-size: 14px; + font-size: 13px; } .itemIcon { position: absolute; + display: flex; + align-items: center; right: 20px; - bottom: 10px; + bottom: 22px; color: #808080; - font-size: 14px; + font-size: 13px; } } + .dataItem:hover{ + border-color: #1664FF; + box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.1) + + } + .dataItem:hover .itemText{ + color: #1664FF; + } } } } diff --git a/react-ui/src/pages/Model/personalData.jsx b/react-ui/src/pages/Model/personalData.jsx index a52420c8..152b3450 100644 --- a/react-ui/src/pages/Model/personalData.jsx +++ b/react-ui/src/pages/Model/personalData.jsx @@ -1,4 +1,6 @@ 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 { PlusCircleOutlined, UploadOutlined } from '@ant-design/icons'; import { Button, Form, Input, Modal, Pagination, Radio, Select, Upload } from 'antd'; @@ -148,6 +150,11 @@ const PublicData = () => { const onFinishFailed = (errorInfo) => { console.log('Failed:', errorInfo); }; + const onPageChange = (pageNum, pageSize) => { + console.log(pageNum, pageSize); + setQueryFlow({ ...queryFlow, page: pageNum - 1, size: pageSize }); + getModelLists({ ...queryFlow, page: pageNum - 1, size: pageSize }); + }; useEffect(() => { getAssetIconList(iconParams); getModelLists(queryFlow); @@ -271,17 +278,19 @@ const PublicData = () => { ? datasetList.map((item) => { return (
routeToIntro(e, item)}> -
{item.name}
+ {item.name} +
{item.description}
- 最近更新: {moment(item.update_time).format('YYYY-MM-DD')} -
-
- 1582 + {item.create_by} +
+
+ + 最近更新: {moment(item.update_time).format('YYYY-MM-DD')}
); @@ -289,7 +298,14 @@ const PublicData = () => { : ''} {/* Demo */} - + { const onFinishFailed = (errorInfo) => { console.log('Failed:', errorInfo); }; + const onPageChange = (pageNum, pageSize) => { + console.log(pageNum, pageSize); + setQueryFlow({ ...queryFlow, page: pageNum - 1, size: pageSize }); + getModelLists({ ...queryFlow, page: pageNum - 1, size: pageSize }); + }; useEffect(() => { getAssetIconList(iconParams); getModelLists(queryFlow); @@ -218,17 +225,19 @@ const PublicData = () => { ? datasetList.map((item) => { return (
routeToIntro(e, item)}> -
{item.name}
+ {item.name} +
{item.description}
- 最近更新: {moment(item.update_time).format('YYYY-MM-DD')} -
-
- 1582 + {item.create_by} +
+
+ + 最近更新: {moment(item.update_time).format('YYYY-MM-DD')}
); @@ -236,7 +245,14 @@ const PublicData = () => { : ''} {/* Demo */} - + Promise; - getVersions: (params: number) => Promise; - getFiles: (params: GetFilesReqParam) => Promise; + getList: (params: any) => Promise; + getVersions: (params: any) => Promise; + getFiles: (params: any) => Promise; + handleVersionResponse: (res: any) => any[]; modalIcon: string; buttonIcon: string; name: string; + litReqParamKey: 'available_range' | 'image_type'; fileReqParamKey: 'models_id' | 'dataset_id'; tabItems: TabsProps['items']; }; +// 获取镜像列表,为了兼容之前的结构 +const getMirrorFilesReq = ({ id, version }: { id: number; version: string }): Promise => { + const index = version.indexOf('-'); + const url = version.slice(index + 1); + return Promise.resolve({ + data: { + content: [ + { + id: `${id}-${version}`, + file_name: `${url}`, + }, + ], + }, + }); +}; + export const selectorTypeData: Record = { - Model: { + [ResourceSelectorType.Model]: { getList: getModelList, getVersions: getModelVersionsById, getFiles: getModelVersionIdList, + handleVersionResponse: (res) => res.data || [], name: '模型', modalIcon: modelImg, buttonIcon: 'local:model-select-button', + litReqParamKey: 'available_range', fileReqParamKey: 'models_id', tabItems: [ { @@ -74,13 +85,15 @@ export const selectorTypeData: Record res.data || [], name: '数据集', modalIcon: datasetImg, buttonIcon: 'local:dataset-select-button', + litReqParamKey: 'available_range', fileReqParamKey: 'dataset_id', tabItems: [ { @@ -93,6 +106,29 @@ export const selectorTypeData: Record getMirrorVersionListReq({ image_id: id, page: 0, size: 200 }), + getFiles: getMirrorFilesReq, + handleVersionResponse: (res) => + res.data?.content?.filter((v: MirrorVersion) => v.status === MirrorVersionStatus.Available) || + [], + name: '镜像', + modalIcon: mirrorImg, + buttonIcon: 'local:mirror-select-button', + litReqParamKey: 'image_type', + fileReqParamKey: 'dataset_id', + tabItems: [ + { + key: CommonTabKeys.Private, + label: '我的镜像', + }, + { + key: CommonTabKeys.Public, + label: '公开镜像', + }, + ], + }, }; type ResourceSelectorResponse = { @@ -108,7 +144,7 @@ interface ResourceSelectorModalProps extends Omit { defaultExpandedKeys: React.Key[]; defaultCheckedKeys: React.Key[]; defaultActiveTab: CommonTabKeys; - onOk?: (params: ResourceSelectorResponse | null) => void; + onOk?: (params: ResourceSelectorResponse | string | null) => void; } type ResourceGroup = { @@ -116,6 +152,13 @@ type ResourceGroup = { name: string; // 数据集或者模型 id }; +type MirrorVersion = { + id: number; // 镜像版本id + status: MirrorVersionStatus; // 镜像版本状态 + tag_name: string; // 镜像版本 + url: string; // 镜像版本路径 +}; + type ResourceFile = { id: number; // 文件 id file_name: string; // 文件 name @@ -133,6 +176,27 @@ const convertToTreeData = (list: ResourceGroup[]): TreeDataNode[] => { })); }; +// 版本转成 treeData +const convertVersionToTreeData = (parentId: number) => { + return (item: string | MirrorVersion): TreeDataNode => { + if (typeof item === 'string') { + return { + title: item, + key: `${parentId}-${item}`, + isLeaf: true, + checkable: true, + }; + } else { + return { + title: item.tag_name, + key: `${parentId}-${item.id}-${item.url}`, + isLeaf: true, + checkable: true, + }; + } + }; +}; + // 更新树形结构的 children const updateChildren = (parentId: number, children: TreeDataNode[]) => { return (node: TreeDataNode) => { @@ -197,11 +261,11 @@ function ResourceSelectorModal({ // 获取数据集或模型列表 const getTreeData = async () => { - const available_range = activeTab === CommonTabKeys.Private ? '0' : '1'; + const available_range = activeTab === CommonTabKeys.Private ? 0 : 1; const params = { page: 0, size: 200, - available_range: available_range, + [selectorTypeData[type].litReqParamKey]: available_range, }; const getListReq = selectorTypeData[type].getList; const [res] = await to(getListReq(params)); @@ -222,13 +286,8 @@ function ResourceSelectorModal({ const getVersionsReq = selectorTypeData[type].getVersions; const [res, error] = await to(getVersionsReq(parentId)); if (res) { - const list = res.data || []; - const children = list.map((v: string) => ({ - title: v, - key: `${parentId}-${v}`, - isLeaf: true, - checkable: true, - })); + const list = selectorTypeData[type].handleVersionResponse(res); + const children = list.map(convertVersionToTreeData(parentId)); // 更新 treeData children setOriginTreeData((prev) => prev.map(updateChildren(parentId, children))); // 缓存 loadedKeys @@ -248,7 +307,7 @@ function ResourceSelectorModal({ const getFiles = async (id: number, version: string) => { const getFilesReq = selectorTypeData[type].getFiles; const paramsKey = selectorTypeData[type].fileReqParamKey; - const params = { version: version, [paramsKey]: id } as GetFilesReqParam; + const params = { version: version, [paramsKey]: id }; const [res] = await to(getFilesReq(params)); if (res) { setVersionPath(res.data?.path || ''); @@ -329,17 +388,21 @@ function ResourceSelectorModal({ // 提交 const handleOk = () => { if (checkedKeys.length > 0) { - const last = checkedKeys[0] as string; - const { id, version } = getIdAndVersion(last); - const name = (treeData.find((v) => Number(v.key) === id)?.title ?? '') as string; - const res = { - id, - name, - path: versionPath, - version, - activeTab: activeTab as CommonTabKeys, - }; - onOk?.(res); + if (type === ResourceSelectorType.Mirror) { + onOk?.(files[0].file_name); + } else { + const last = checkedKeys[0] as string; + const { id, version } = getIdAndVersion(last); + const name = (treeData.find((v) => Number(v.key) === id)?.title ?? '') as string; + const res = { + id, + name, + path: versionPath, + version, + activeTab: activeTab as CommonTabKeys, + }; + onOk?.(res); + } } else { onOk?.(null); } @@ -347,7 +410,10 @@ function ResourceSelectorModal({ const title = `选择${selectorTypeData[type].name}`; const palceholder = `请输入${selectorTypeData[type].name}名称`; - const fileTitle = `已选${selectorTypeData[type].name}文件(${files.length})`; + const fileTitle = + type === ResourceSelectorType.Mirror + ? '已选镜像' + : `已选${selectorTypeData[type].name}文件(${files.length})`; const tabItems = selectorTypeData[type].tabItems; const titleImg = selectorTypeData[type].modalIcon; diff --git a/react-ui/src/pages/Pipeline/editPipeline/globalParamsDrawer.tsx b/react-ui/src/pages/Pipeline/editPipeline/globalParamsDrawer.tsx index fad63da3..82532a06 100644 --- a/react-ui/src/pages/Pipeline/editPipeline/globalParamsDrawer.tsx +++ b/react-ui/src/pages/Pipeline/editPipeline/globalParamsDrawer.tsx @@ -4,8 +4,9 @@ import { } from '@/pages/Experiment/experimentText/addExperimentModal'; import { type PipelineGlobalParam } from '@/types'; import { to } from '@/utils/promise'; +import { modalConfirm } from '@/utils/ui'; import { DeleteOutlined, PlusOutlined } from '@ant-design/icons'; -import { Button, Drawer, Form, Input, Radio } from 'antd'; +import { Button, Drawer, Form, Input, Radio, Tooltip } from 'antd'; import { NamePath } from 'antd/es/form/interface'; import { forwardRef, useImperativeHandle } from 'react'; import styles from './globalParamsDrawer.less'; @@ -22,9 +23,8 @@ const GlobalParamsDrawer = forwardRef( useImperativeHandle(ref, () => ({ getFieldsValue: async () => { - const [res, error] = await to(form.validateFields()); - if (res && !error) { - const values = form.getFieldsValue(); + const [values, error] = await to(form.validateFields()); + if (!error && values) { return values; } else { return Promise.reject(error); @@ -32,10 +32,20 @@ const GlobalParamsDrawer = forwardRef( }, })); + // 处理参数类型变化 const handleTypeChange = (name: NamePath) => { form.setFieldValue(name, null); }; + const removeParameter = (name: number, remove: (param: number) => void) => { + modalConfirm({ + title: '确认删除该参数吗?', + onOk: () => { + remove(name); + }, + }); + }; + return ( 否 - + + + ))} @@ -150,6 +162,7 @@ const GlobalParamsDrawer = forwardRef( )} + {/* //{contextHolder} */} ); }, diff --git a/react-ui/src/pages/Pipeline/editPipeline/index.jsx b/react-ui/src/pages/Pipeline/editPipeline/index.jsx index 5d31298a..948cd364 100644 --- a/react-ui/src/pages/Pipeline/editPipeline/index.jsx +++ b/react-ui/src/pages/Pipeline/editPipeline/index.jsx @@ -1,9 +1,7 @@ -import { ReactComponent as ParameterIcon } from '@/assets/svg/parameter.svg'; -import { ReactComponent as SaveAndReturn } from '@/assets/svg/save--return.svg'; +import KFIcon from '@/components/KFIcon'; import { useVisible } from '@/hooks'; import { getWorkflowById, saveWorkflow } from '@/services/pipeline/index.js'; import { to } from '@/utils/promise'; -import { SaveOutlined } from '@ant-design/icons'; import { useEmotionCss } from '@ant-design/use-emotion-css'; import G6 from '@antv/g6'; import { Button, message } from 'antd'; @@ -101,22 +99,32 @@ const EditPipeline = () => { openParamsDrawer(); 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) => { e.stopPropagation(); @@ -706,7 +714,7 @@ const EditPipeline = () => {
- - + +
+ + + + + + +
@@ -242,11 +306,20 @@ const Props = forwardRef(({ onParentChange }, ref) => { rules={[ { required: true, - message: '请输入资源规格', + message: '请选择资源规格', }, ]} > - + diff --git a/react-ui/src/pages/Pipeline/index.jsx b/react-ui/src/pages/Pipeline/index.jsx index 7378bbc3..50206ace 100644 --- a/react-ui/src/pages/Pipeline/index.jsx +++ b/react-ui/src/pages/Pipeline/index.jsx @@ -1,3 +1,4 @@ +import KFIcon from '@/components/KFIcon'; import { addWorkflow, cloneWorkflow, @@ -6,8 +7,9 @@ import { getWorkflowById, removeWorkflow, } from '@/services/pipeline/index.js'; -import { CopyOutlined, DeleteOutlined, EditOutlined, PlusCircleOutlined } from '@ant-design/icons'; -import { Button, Form, Input, Modal, Space, Table, message } from 'antd'; +import themes from '@/styles/theme.less'; +import { modalConfirm } from '@/utils/ui'; +import { Button, ConfigProvider, Form, Input, Modal, Space, Table, message } from 'antd'; import momnet from 'moment'; import { useEffect, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; @@ -26,7 +28,7 @@ const Pipeline = () => { const editTable = (e, record) => { e.stopPropagation(); getWorkflowById(record.id).then((ret) => { - if (ret.code == 200) { + if (ret.code === 200) { form.resetFields(); form.setFieldsValue({ ...ret.data }); setFormId(ret.data.id); @@ -152,7 +154,7 @@ const Pipeline = () => { type="link" size="small" key="edit" - icon={} + icon={} onClick={(e) => { editTable(e, record); }} @@ -163,7 +165,7 @@ const Pipeline = () => { type="link" size="small" key="clone" - icon={} + icon={} onClick={async () => { Modal.confirm({ title: '复制', @@ -173,7 +175,7 @@ const Pipeline = () => { onOk: () => { console.log(record); cloneWorkflow(record.id).then((ret) => { - if (ret.code == 200) { + if (ret.code === 200) { message.success('复制成功'); getList(); } else { @@ -192,54 +194,45 @@ const Pipeline = () => { > 复制 - + + ), }, @@ -251,7 +244,7 @@ const Pipeline = () => { type="primary" className={Styles.plusButton} onClick={showModal} - icon={} + icon={} > 新建流水线 diff --git a/react-ui/src/services/pipeline/index.js b/react-ui/src/services/pipeline/index.js index d722398b..7262d6b1 100644 --- a/react-ui/src/services/pipeline/index.js +++ b/react-ui/src/services/pipeline/index.js @@ -1,3 +1,8 @@ +/* + * @Author: 赵伟 + * @Date: 2024-03-25 13:52:54 + * @Description: + */ import { request } from '@umijs/max'; // 查询流水线列表 export function getWorkflow(params) { @@ -63,3 +68,11 @@ export function getWorkflowById(id) { method: 'GET', }); } + +// 获取资源规格 +export function getComputingResourceReq(params) { + return request(`/api/mmp/computingResource`, { + method: 'GET', + params + }); +} diff --git a/react-ui/src/styles/theme.less b/react-ui/src/styles/theme.less index 9f6aaace..64b78619 100644 --- a/react-ui/src/styles/theme.less +++ b/react-ui/src/styles/theme.less @@ -1,17 +1,32 @@ // 全局颜色变量 -// FIXME: 不能设置 @primary-color 不起作用,感觉是哪里被重置了 -@kf-primary-color: #1664ff; // 主色调 -@primary-color-hover: #4086ff; +@primary-color: #1664ff; // 主色调 +@primary-color-hover: #69b1ff; @background-color: #f9fafb; // 页面背景颜色 @text-color: #1d1d20; -@text-color-second: #575757; -@font-size: 15px; +@text-color-secondary: #575757; +@success-color: #1ace62; +@error-color: #c73131; +@warning-color: #f98e1b; + @border-color: rgba(22, 100, 255, 0.3); @border-color-second: rgba(22, 100, 255, 0.1); @background-color-primay: rgba(22, 100, 255, 0.03); @background-color-gray: rgba(4, 3, 3, 0.06); +@heading-color: rgba(0, 0, 0, 0.85); +@input-icon-hover-color: rgba(0, 0, 0, 0.85); +@border-color-base: #d9d9d9; +@link-hover-color: #69b1ff; + +// 字体大小 +@font-size: 15px; + // 导出变量 :export { - primaryColor: @kf-primary-color; + primaryColor: @primary-color; + successColor: @success-color; + errorColor: @error-color; + warningColor: @warning-color; + textColor: @text-color; + fontSize: @font-size; } diff --git a/react-ui/src/utils/modal.tsx b/react-ui/src/utils/modal.tsx index d55d8378..4a3b765f 100644 --- a/react-ui/src/utils/modal.tsx +++ b/react-ui/src/utils/modal.tsx @@ -3,7 +3,8 @@ * @Date: 2024-04-13 10:08:35 * @Description: */ -import { type ModalProps } from 'antd'; +import { ConfigProvider, type ModalProps } from 'antd'; +import { globalConfig } from 'antd/es/config-provider'; import React, { useState } from 'react'; import { createRoot } from 'react-dom/client'; @@ -19,19 +20,20 @@ export const openAntdModal = ( modalProps: T, ) => { const CustomModel = modal; - const element = document.createElement('div'); - element.id = 'modal-container'; - document.body.appendChild(element); - const root = createRoot(element); + const container = document.createDocumentFragment(); + const root = createRoot(container); const { afterClose, onCancel } = modalProps; + const global = globalConfig(); + let timeoutId: ReturnType; function destroy() { root.unmount(); - document.body.removeChild(element); } function handleAfterClose() { afterClose?.(); + // Warning: Attempted to synchronously unmount a root while React was already rendering. + // React cannot finish unmounting the root until the current render has completed, which may lead to a race condition. setTimeout(() => { destroy(); }, 0); @@ -46,11 +48,26 @@ export const openAntdModal = ( } function render(props: T) { - root.render(); + clearTimeout(timeoutId); + + timeoutId = setTimeout(() => { + const rootPrefixCls = global.getPrefixCls(); + const iconPrefixCls = global.getIconPrefixCls(); + const theme = global.getTheme(); + const dom = ( + + ); + + root.render( + + {global.holderRender ? global.holderRender(dom) : dom} + , + ); + }); } function close() { - render({ ...modalProps, open: false, afterClose: handleAfterClose }); + render({ ...modalProps, open: false }); } render({ ...modalProps, open: true }); diff --git a/react-ui/src/utils/ui.tsx b/react-ui/src/utils/ui.tsx new file mode 100644 index 00000000..79a4c1f8 --- /dev/null +++ b/react-ui/src/utils/ui.tsx @@ -0,0 +1,28 @@ +/* + * @Author: 赵伟 + * @Date: 2024-04-19 14:42:51 + * @Description: UI 公共方法 + */ +import themes from '@/styles/theme.less'; +import { Modal, type ModalFuncProps } from 'antd'; + +// 自定义 Confirm 弹框 +export function modalConfirm({ title, content, onOk, ...rest }: ModalFuncProps) { + Modal.confirm({ + ...rest, + title: ( +
+ +
{title}
+
+ ), + content: content &&
{content}
, + okText: '确认', + cancelText: '取消', + onOk: onOk, + }); +}