| @@ -55,3 +55,6 @@ mvnw | |||||
| /k8s/template-yaml/deploy/ | /k8s/template-yaml/deploy/ | ||||
| /k8s/dockerfiles/html/ | /k8s/dockerfiles/html/ | ||||
| /k8s/dockerfiles/jar | /k8s/dockerfiles/jar | ||||
| # web | |||||
| **/node_modules | |||||
| @@ -6,8 +6,14 @@ baseDir="/home/somuns/ci4s" | |||||
| #判断$1是否为all,如果是,则编译所有模块,否则只编译management-platform模块 | #判断$1是否为all,如果是,则编译所有模块,否则只编译management-platform模块 | ||||
| if [ "$1" == "all" ]; then | if [ "$1" == "all" ]; then | ||||
| buildDir=$baseDir | buildDir=$baseDir | ||||
| else | |||||
| elif [ "$1" == "manage" ]; then | |||||
| buildDir="$baseDir/ruoyi-modules/management-platform" | buildDir="$baseDir/ruoyi-modules/management-platform" | ||||
| elif [ "$1" == "auth" ]; then | |||||
| buildDir="$baseDir/ruoyi-auth" | |||||
| elif [ "$1" == "gateway" ]; then | |||||
| buildDir="$baseDir/ruoyi-gateway" | |||||
| elif [ "$1" == "system" ]; then | |||||
| buildDir="$baseDir/ruoyi-modules/ruoyi-system" | |||||
| fi | fi | ||||
| echo "Building $buildDir" | echo "Building $buildDir" | ||||
| @@ -30,7 +30,7 @@ done | |||||
| echo "branch: $branch" | echo "branch: $branch" | ||||
| echo "service: $service" | echo "service: $service" | ||||
| valid_services=("manage-front" "manage" "front" "all") | |||||
| valid_services=("manage-front" "manage" "front" "all" "auth" "gateway" "system") | |||||
| if [[ ! " ${valid_services[@]} " =~ " $service " ]]; then | if [[ ! " ${valid_services[@]} " =~ " $service " ]]; then | ||||
| echo "Invalid service name: $service" >&2 | echo "Invalid service name: $service" >&2 | ||||
| echo "Valid services are: ${valid_services[*]}" | echo "Valid services are: ${valid_services[*]}" | ||||
| @@ -107,13 +107,19 @@ compile_java() { | |||||
| fi | fi | ||||
| } | } | ||||
| if [ "$service" == "manage-front" ] || [ "$service" == "front" ]; then | |||||
| if [ "$service" == "front" ]; then | |||||
| # 编译前端 | # 编译前端 | ||||
| compile_front | compile_front | ||||
| fi | fi | ||||
| if [ "$service" == "manage-front" ]; then | |||||
| # 编译前端 | |||||
| compile_front | |||||
| # 编译java | |||||
| compile_java "manage" | |||||
| fi | |||||
| if [ "$service" == "manage-front" ] || [ "$service" == "manage" ]; then | |||||
| if [ "$service" != "manage-front" ] && [ "$service" != "all" ] && [ "$service" != "front" ]; then | |||||
| # 编译java | # 编译java | ||||
| compile_java $service | compile_java $service | ||||
| fi | fi | ||||
| @@ -3,6 +3,10 @@ | |||||
| #记录开始时间 | #记录开始时间 | ||||
| startTime=$(date +%s) | startTime=$(date +%s) | ||||
| # 登录到目标环境 | |||||
| baseDir="/home/somuns/ci4s" | |||||
| cd ${baseDir} | |||||
| #build | #build | ||||
| # 默认参数 | # 默认参数 | ||||
| branch="master" | branch="master" | ||||
| @@ -31,20 +35,6 @@ while getopts "b:s:e:h" opt; do | |||||
| esac | esac | ||||
| done | done | ||||
| valid_services=("manage-front" "manage" "front" "all") | |||||
| if [[ ! " ${valid_services[@]} " =~ " $service " ]]; then | |||||
| echo "Invalid service name: $service" >&2 | |||||
| echo "Valid services are: ${valid_services[*]}" | |||||
| exit 1 | |||||
| fi | |||||
| valid_envs=("dev" "test") | |||||
| if [[ ! " ${valid_envs[@]} " =~ " $env " ]]; then | |||||
| echo "Invalid environment: $env" >&2 | |||||
| echo "Valid environments are: ${valid_envs[*]}" | |||||
| exit 1 | |||||
| fi | |||||
| # 拉取指定分支的最新代码 | # 拉取指定分支的最新代码 | ||||
| echo "Checking out and pulling branch $branch..." | echo "Checking out and pulling branch $branch..." | ||||
| @@ -64,9 +54,19 @@ fi | |||||
| chmod +777 ${baseDir}/k8s/*.sh | chmod +777 ${baseDir}/k8s/*.sh | ||||
| # 登录到目标环境 | |||||
| baseDir="/home/somuns/ci4s" | |||||
| cd ${baseDir} | |||||
| valid_services=("manage-front" "manage" "front" "all" "auth" "gateway" "system") | |||||
| if [[ ! " ${valid_services[@]} " =~ " $service " ]]; then | |||||
| echo "Invalid service name: $service" >&2 | |||||
| echo "Valid services are: ${valid_services[*]}" | |||||
| exit 1 | |||||
| fi | |||||
| valid_envs=("dev" "test") | |||||
| if [[ ! " ${valid_envs[@]} " =~ " $env " ]]; then | |||||
| echo "Invalid environment: $env" >&2 | |||||
| echo "Valid environments are: ${valid_envs[*]}" | |||||
| exit 1 | |||||
| fi | |||||
| echo "start build" | echo "start build" | ||||
| sh ${baseDir}/k8s/build.sh -b ${branch} -s ${service} | sh ${baseDir}/k8s/build.sh -b ${branch} -s ${service} | ||||
| @@ -27,7 +27,7 @@ done | |||||
| echo "Deploy service: $service, environment: $env" | echo "Deploy service: $service, environment: $env" | ||||
| valid_services=("manage-front" "manage" "front" "all") | |||||
| valid_services=("manage-front" "manage" "front" "all" "auth" "gateway" "system") | |||||
| if [[ ! " ${valid_services[@]} " =~ " $service " ]]; then | if [[ ! " ${valid_services[@]} " =~ " $service " ]]; then | ||||
| echo "Invalid service name: $service" >&2 | echo "Invalid service name: $service" >&2 | ||||
| echo "Valid services are: ${valid_services[*]}" | echo "Valid services are: ${valid_services[*]}" | ||||
| @@ -129,15 +129,34 @@ build_and_deploy() { | |||||
| deploy_service ${yaml_file} | deploy_service ${yaml_file} | ||||
| } | } | ||||
| if [ "$service" == "front" ]; then | |||||
| build_and_deploy "nginx-dockerfile" "172.20.32.187/ci4s/ci4s-front:${tag}" "k8s-12front.yaml" | |||||
| fi | |||||
| # 构建和部署 manage 服务 | # 构建和部署 manage 服务 | ||||
| if [ "$service" == "manage-front" ] || [ "$service" == "manage" ]; then | |||||
| if [ "$service" == "manage" ]; then | |||||
| build_and_deploy "managent-dockerfile" "172.20.32.187/ci4s/ci4s-managent:${tag}" "k8s-7management.yaml" | build_and_deploy "managent-dockerfile" "172.20.32.187/ci4s/ci4s-managent:${tag}" "k8s-7management.yaml" | ||||
| fi | fi | ||||
| if [ "$service" == "auth" ]; then | |||||
| #部署认证中心 | |||||
| build_and_deploy "auth-dockerfile" "172.20.32.187/ci4s/ci4s-auth:${tag}" "k8s-5auth.yaml" | |||||
| fi | |||||
| if [ "$service" == "gateway" ]; then | |||||
| #部署网关 | |||||
| build_and_deploy "gateway-dockerfile" "172.20.32.187/ci4s/ci4s-gateway:${tag}" "k8s-4gateway.yaml" | |||||
| fi | |||||
| if [ "$service" == "system" ]; then | |||||
| #部署系统服务 | |||||
| build_and_deploy "system-dockerfile" "172.20.32.187/ci4s/ci4s-system:${tag}" "k8s-6system.yaml" | |||||
| fi | |||||
| # 构建和部署 front 服务 | # 构建和部署 front 服务 | ||||
| if [ "$service" == "manage-front" ] || [ "$service" == "front" ]; then | |||||
| if [ "$service" == "manage-front" ]; then | |||||
| build_and_deploy "nginx-dockerfile" "172.20.32.187/ci4s/ci4s-front:${tag}" "k8s-12front.yaml" | build_and_deploy "nginx-dockerfile" "172.20.32.187/ci4s/ci4s-front:${tag}" "k8s-12front.yaml" | ||||
| build_and_deploy "managent-dockerfile" "172.20.32.187/ci4s/ci4s-managent:${tag}" "k8s-7management.yaml" | |||||
| fi | fi | ||||
| @@ -27,6 +27,16 @@ export default [ | |||||
| }, | }, | ||||
| ], | ], | ||||
| }, | }, | ||||
| { | |||||
| path: '/authorize', | |||||
| layout: false, | |||||
| component: './Authorize/index', | |||||
| }, | |||||
| { | |||||
| path: '/gitlink', | |||||
| layout: true, | |||||
| component: './GitLink/index', | |||||
| }, | |||||
| { | { | ||||
| path: '/user', | path: '/user', | ||||
| layout: false, | layout: false, | ||||
| @@ -7,7 +7,6 @@ import defaultSettings from '../config/defaultSettings'; | |||||
| import '../public/fonts/font.css'; | import '../public/fonts/font.css'; | ||||
| import { getAccessToken } from './access'; | import { getAccessToken } from './access'; | ||||
| import './dayjsConfig'; | import './dayjsConfig'; | ||||
| import { PageEnum } from './enums/pagesEnums'; | |||||
| import './global.less'; | import './global.less'; | ||||
| import { removeAllPageCacheState } from './hooks/pageCacheState'; | import { removeAllPageCacheState } from './hooks/pageCacheState'; | ||||
| import { | import { | ||||
| @@ -23,6 +22,7 @@ export { requestConfig as request } from './requestConfig'; | |||||
| import { type GlobalInitialState } from '@/types'; | import { type GlobalInitialState } from '@/types'; | ||||
| import { menuItemRender } from '@/utils/menuRender'; | import { menuItemRender } from '@/utils/menuRender'; | ||||
| import ErrorBoundary from './components/ErrorBoundary'; | import ErrorBoundary from './components/ErrorBoundary'; | ||||
| import { needAuth } from './utils'; | |||||
| import { gotoLoginPage } from './utils/ui'; | import { gotoLoginPage } from './utils/ui'; | ||||
| /** | /** | ||||
| @@ -40,14 +40,17 @@ export async function getInitialState(): Promise<GlobalInitialState> { | |||||
| roleNames: response.user.roles, | roleNames: response.user.roles, | ||||
| } as API.CurrentUser; | } as API.CurrentUser; | ||||
| } catch (error) { | } catch (error) { | ||||
| console.error(error); | |||||
| console.error('1111', error); | |||||
| gotoLoginPage(); | gotoLoginPage(); | ||||
| } | } | ||||
| return undefined; | return undefined; | ||||
| }; | }; | ||||
| // 如果不是登录页面,执行 | // 如果不是登录页面,执行 | ||||
| const { location } = history; | const { location } = history; | ||||
| if (location.pathname !== PageEnum.LOGIN) { | |||||
| console.log('getInitialState', needAuth(location.pathname)); | |||||
| if (needAuth(location.pathname)) { | |||||
| const currentUser = await fetchUserInfo(); | const currentUser = await fetchUserInfo(); | ||||
| return { | return { | ||||
| fetchUserInfo, | fetchUserInfo, | ||||
| @@ -94,7 +97,7 @@ export const layout: RuntimeConfig['layout'] = ({ initialState }) => { | |||||
| onPageChange: () => { | onPageChange: () => { | ||||
| const { location } = history; | const { location } = history; | ||||
| // 如果没有登录,重定向到 login | // 如果没有登录,重定向到 login | ||||
| if (!initialState?.currentUser && location.pathname !== PageEnum.LOGIN) { | |||||
| if (!initialState?.currentUser && needAuth(location.pathname)) { | |||||
| gotoLoginPage(); | gotoLoginPage(); | ||||
| } | } | ||||
| }, | }, | ||||
| @@ -159,8 +162,8 @@ export const layout: RuntimeConfig['layout'] = ({ initialState }) => { | |||||
| export const onRouteChange: RuntimeConfig['onRouteChange'] = async (e) => { | export const onRouteChange: RuntimeConfig['onRouteChange'] = async (e) => { | ||||
| const { location } = e; | const { location } = e; | ||||
| const menus = getRemoteMenu(); | const menus = getRemoteMenu(); | ||||
| // console.log('onRouteChange', e); | |||||
| if (menus === null && location.pathname !== PageEnum.LOGIN) { | |||||
| console.log('onRouteChange', menus); | |||||
| if (menus === null && needAuth(location.pathname)) { | |||||
| history.go(0); | history.go(0); | ||||
| } | } | ||||
| }; | }; | ||||
| @@ -170,12 +173,12 @@ export const patchRoutes: RuntimeConfig['patchRoutes'] = (e) => { | |||||
| }; | }; | ||||
| export const patchClientRoutes: RuntimeConfig['patchClientRoutes'] = (e) => { | export const patchClientRoutes: RuntimeConfig['patchClientRoutes'] = (e) => { | ||||
| //console.log('patchClientRoutes', e); | |||||
| console.log('patchClientRoutes', e); | |||||
| patchRouteWithRemoteMenus(e.routes); | patchRouteWithRemoteMenus(e.routes); | ||||
| }; | }; | ||||
| export function render(oldRender: () => void) { | export function render(oldRender: () => void) { | ||||
| // console.log('render'); | |||||
| console.log('render'); | |||||
| const token = getAccessToken(); | const token = getAccessToken(); | ||||
| if (!token || token?.length === 0) { | if (!token || token?.length === 0) { | ||||
| oldRender(); | oldRender(); | ||||
| @@ -27,7 +27,7 @@ | |||||
| display: flex; | display: flex; | ||||
| flex: 1; | flex: 1; | ||||
| flex-direction: column; | flex-direction: column; | ||||
| align-items: flex-start; | |||||
| align-items: stretch; | |||||
| min-width: 0; | min-width: 0; | ||||
| } | } | ||||
| @@ -12,6 +12,7 @@ export enum IframePageType { | |||||
| DatasetAnnotation = 'DatasetAnnotation', // 数据标注 | DatasetAnnotation = 'DatasetAnnotation', // 数据标注 | ||||
| AppDevelopment = 'AppDevelopment', // 应用开发 | AppDevelopment = 'AppDevelopment', // 应用开发 | ||||
| DevEnv = 'DevEnv', // 开发环境 | DevEnv = 'DevEnv', // 开发环境 | ||||
| GitLink = 'GitLink', | |||||
| } | } | ||||
| const getRequestAPI = (type: IframePageType): (() => Promise<any>) => { | const getRequestAPI = (type: IframePageType): (() => Promise<any>) => { | ||||
| @@ -26,6 +27,8 @@ const getRequestAPI = (type: IframePageType): (() => Promise<any>) => { | |||||
| code: 200, | code: 200, | ||||
| data: SessionStorage.getItem(SessionStorage.editorUrlKey) || '', | data: SessionStorage.getItem(SessionStorage.editorUrlKey) || '', | ||||
| }); | }); | ||||
| case IframePageType.GitLink: | |||||
| return () => Promise.resolve({ code: 200, data: 'http://172.20.32.201:4000' }); | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -1,6 +1,8 @@ | |||||
| import { clearSessionToken } from '@/access'; | import { clearSessionToken } from '@/access'; | ||||
| import { setRemoteMenu } from '@/services/session'; | import { setRemoteMenu } from '@/services/session'; | ||||
| import { logout } from '@/services/system/auth'; | import { logout } from '@/services/system/auth'; | ||||
| import { ClientInfo } from '@/types'; | |||||
| import SessionStorage from '@/utils/sessionStorage'; | |||||
| import { gotoLoginPage } from '@/utils/ui'; | import { gotoLoginPage } from '@/utils/ui'; | ||||
| import { LogoutOutlined, UserOutlined } from '@ant-design/icons'; | import { LogoutOutlined, UserOutlined } from '@ant-design/icons'; | ||||
| import { setAlpha } from '@ant-design/pro-components'; | import { setAlpha } from '@ant-design/pro-components'; | ||||
| @@ -64,6 +66,11 @@ const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => { | |||||
| clearSessionToken(); | clearSessionToken(); | ||||
| setRemoteMenu(null); | setRemoteMenu(null); | ||||
| gotoLoginPage(); | gotoLoginPage(); | ||||
| const clientInfo: ClientInfo = SessionStorage.getItem(SessionStorage.clientInfoKey, true); | |||||
| if (clientInfo) { | |||||
| const { logoutUri } = clientInfo; | |||||
| location.replace(logoutUri); | |||||
| } | |||||
| }; | }; | ||||
| const actionClassName = useEmotionCss(({ token }) => { | const actionClassName = useEmotionCss(({ token }) => { | ||||
| return { | return { | ||||
| @@ -0,0 +1,50 @@ | |||||
| import { setSessionToken } from '@/access'; | |||||
| import { loginByOauth2Req } from '@/services/auth'; | |||||
| import { to } from '@/utils/promise'; | |||||
| import { history, useModel, useSearchParams } from '@umijs/max'; | |||||
| import { message } from 'antd'; | |||||
| import { useEffect } from 'react'; | |||||
| import { flushSync } from 'react-dom'; | |||||
| import styles from './index.less'; | |||||
| function Authorize() { | |||||
| const { initialState, setInitialState } = useModel('@@initialState'); | |||||
| const [searchParams] = useSearchParams(); | |||||
| const code = searchParams.get('code'); | |||||
| const redirect = searchParams.get('redirect'); | |||||
| useEffect(() => { | |||||
| loginByOauth2(); | |||||
| }, []); | |||||
| // 登录 | |||||
| const loginByOauth2 = async () => { | |||||
| const params = { | |||||
| code, | |||||
| }; | |||||
| const [res] = await to(loginByOauth2Req(params)); | |||||
| debugger; | |||||
| if (res && res.data) { | |||||
| const { access_token, expires_in } = res.data; | |||||
| setSessionToken(access_token, access_token, expires_in); | |||||
| message.success('登录成功!'); | |||||
| await fetchUserInfo(); | |||||
| history.push(redirect || '/'); | |||||
| } | |||||
| }; | |||||
| const fetchUserInfo = async () => { | |||||
| const userInfo = await initialState?.fetchUserInfo?.(); | |||||
| if (userInfo) { | |||||
| flushSync(() => { | |||||
| setInitialState((s) => ({ | |||||
| ...s, | |||||
| currentUser: userInfo, | |||||
| })); | |||||
| }); | |||||
| } | |||||
| }; | |||||
| return <div className={styles.container}></div>; | |||||
| } | |||||
| export default Authorize; | |||||
| @@ -50,7 +50,7 @@ | |||||
| height: 100%; | height: 100%; | ||||
| .ant-tabs-nav-wrap { | .ant-tabs-nav-wrap { | ||||
| padding-top: 8px; | padding-top: 8px; | ||||
| padding-left: 30px; | |||||
| padding-left: @content-padding; | |||||
| background-color: white; | background-color: white; | ||||
| border-radius: 10px 10px 0 0; | border-radius: 10px 10px 0 0; | ||||
| } | } | ||||
| @@ -2,7 +2,7 @@ | |||||
| width: 100%; | width: 100%; | ||||
| &__top { | &__top { | ||||
| padding: 20px 30px; | |||||
| padding: 20px @content-padding; | |||||
| background: white; | background: white; | ||||
| border-radius: 0 0 10px 10px; | border-radius: 0 0 10px 10px; | ||||
| box-shadow: 0px 2px 12px rgba(180, 182, 191, 0.09); | box-shadow: 0px 2px 12px rgba(180, 182, 191, 0.09); | ||||
| @@ -22,4 +22,15 @@ | |||||
| font-size: @font-size; | font-size: @font-size; | ||||
| } | } | ||||
| } | } | ||||
| &--dataset { | |||||
| height: 100%; | |||||
| background-color: white; | |||||
| border-radius: 0 0 10px 10px; | |||||
| } | |||||
| &--dataset &__top { | |||||
| border-radius: 0; | |||||
| box-shadow: none; | |||||
| } | |||||
| } | } | ||||
| @@ -12,6 +12,7 @@ import { | |||||
| } from '@/pages/Dataset/config'; | } from '@/pages/Dataset/config'; | ||||
| import ModelMetrics from '@/pages/Model/components/ModelMetrics'; | import ModelMetrics from '@/pages/Model/components/ModelMetrics'; | ||||
| import { getGitUrl } from '@/utils'; | import { getGitUrl } from '@/utils'; | ||||
| import classNames from 'classnames'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| type ResourceIntroProps = { | type ResourceIntroProps = { | ||||
| @@ -206,7 +207,11 @@ function ResourceIntro({ | |||||
| : getModelDatas(info as ModelData); | : getModelDatas(info as ModelData); | ||||
| return ( | return ( | ||||
| <div className={styles['resource-intro']}> | |||||
| <div | |||||
| className={classNames(styles['resource-intro'], { | |||||
| [styles['resource-intro--dataset']]: resourceType === ResourceType.Dataset, | |||||
| })} | |||||
| > | |||||
| <div className={styles['resource-intro__top']}> | <div className={styles['resource-intro__top']}> | ||||
| <SubAreaTitle | <SubAreaTitle | ||||
| title="基本信息" | title="基本信息" | ||||
| @@ -1,6 +1,6 @@ | |||||
| .resource-version { | .resource-version { | ||||
| min-height: 100%; | min-height: 100%; | ||||
| padding: 20px 30px; | |||||
| padding: 20px @content-padding; | |||||
| color: @text-color; | color: @text-color; | ||||
| font-size: @font-size-content; | font-size: @font-size-content; | ||||
| background: white; | background: white; | ||||
| @@ -0,0 +1,7 @@ | |||||
| import IframePage, { IframePageType } from '@/components/IFramePage'; | |||||
| function GitLink() { | |||||
| return <IframePage type={IframePageType.GitLink}></IframePage>; | |||||
| } | |||||
| export default GitLink; | |||||
| @@ -1,7 +1,7 @@ | |||||
| .model-evolution { | .model-evolution { | ||||
| width: 100%; | width: 100%; | ||||
| height: 100%; | height: 100%; | ||||
| padding: 0 30px 20px; | |||||
| padding: 0 @content-padding 20px; | |||||
| overflow-x: hidden; | overflow-x: hidden; | ||||
| background: white; | background: white; | ||||
| border-radius: 0 0 10px 10px; | border-radius: 0 0 10px 10px; | ||||
| @@ -1,7 +1,7 @@ | |||||
| .model-metrics { | .model-metrics { | ||||
| &__table { | &__table { | ||||
| margin-top: 10px; | margin-top: 10px; | ||||
| padding: 20px 30px 0; | |||||
| padding: 20px @content-padding 0; | |||||
| background: white; | background: white; | ||||
| border-radius: 10px; | border-radius: 10px; | ||||
| @@ -9,6 +9,7 @@ | |||||
| line-height: 42px; | line-height: 42px; | ||||
| text-align: center; | text-align: center; | ||||
| background: @background; | background: @background; | ||||
| border-radius: 4px 4px 0 0; | |||||
| .singleLine(); | .singleLine(); | ||||
| } | } | ||||
| @@ -16,6 +17,7 @@ | |||||
| margin-bottom: 20px !important; | margin-bottom: 20px !important; | ||||
| color: @text-color-secondary; | color: @text-color-secondary; | ||||
| font-size: 13px; | font-size: 13px; | ||||
| line-height: 22px; | |||||
| word-break: break-all; | word-break: break-all; | ||||
| .singleLine(); | .singleLine(); | ||||
| } | } | ||||
| @@ -54,9 +56,10 @@ | |||||
| flex: none; | flex: none; | ||||
| width: 117px; | width: 117px; | ||||
| padding: 0 15px; | padding: 0 15px; | ||||
| background: white; | |||||
| background: rgba(255, 255, 255, 0.1); | |||||
| border: 1px solid .addAlpha(@primary-color, 0.2) []; | border: 1px solid .addAlpha(@primary-color, 0.2) []; | ||||
| border-radius: 4px; | border-radius: 4px; | ||||
| box-shadow: 0px 3px 6px .addAlpha(@primary-color, 0.1) [] inset; | |||||
| &__title { | &__title { | ||||
| margin-bottom: 20px; | margin-bottom: 20px; | ||||
| @@ -1,11 +1,12 @@ | |||||
| import { clearSessionToken, setSessionToken } from '@/access'; | import { clearSessionToken, setSessionToken } from '@/access'; | ||||
| import { getClientInfoReq } from '@/services/auth'; | |||||
| import { getCaptchaImg, login } from '@/services/system/auth'; | import { getCaptchaImg, login } from '@/services/system/auth'; | ||||
| import { parseJsonText } from '@/utils'; | |||||
| import { safeInvoke } from '@/utils/functional'; | |||||
| import LocalStorage from '@/utils/localStorage'; | import LocalStorage from '@/utils/localStorage'; | ||||
| import { to } from '@/utils/promise'; | import { to } from '@/utils/promise'; | ||||
| import SessionStorage from '@/utils/sessionStorage'; | |||||
| import { gotoOAuth2 } from '@/utils/ui'; | |||||
| import { history, useModel } from '@umijs/max'; | import { history, useModel } from '@umijs/max'; | ||||
| import { Button, Checkbox, Flex, Form, Image, Input, message, type InputRef } from 'antd'; | |||||
| import { Form, message, type InputRef } from 'antd'; | |||||
| import CryptoJS from 'crypto-js'; | import CryptoJS from 'crypto-js'; | ||||
| import { useEffect, useRef, useState } from 'react'; | import { useEffect, useRef, useState } from 'react'; | ||||
| import { flushSync } from 'react-dom'; | import { flushSync } from 'react-dom'; | ||||
| @@ -31,25 +32,35 @@ const Login = () => { | |||||
| const captchaInputRef = useRef<InputRef>(null); | const captchaInputRef = useRef<InputRef>(null); | ||||
| useEffect(() => { | useEffect(() => { | ||||
| getCaptchaCode(); | |||||
| const autoLogin = LocalStorage.getItem(LocalStorage.rememberPasswordKey) ?? 'false'; | |||||
| if (autoLogin === 'true') { | |||||
| const userStorage = LocalStorage.getItem(LocalStorage.loginUserKey); | |||||
| const userJson = safeInvoke((text: string) => | |||||
| CryptoJS.AES.decrypt(text, AESKEY).toString(CryptoJS.enc.Utf8), | |||||
| )(userStorage); | |||||
| const user = safeInvoke(parseJsonText)(userJson); | |||||
| if (user && typeof user === 'object' && user.version === VERSION) { | |||||
| const { username, password } = user; | |||||
| form.setFieldsValue({ username: username, password: password, autoLogin: true }); | |||||
| } else { | |||||
| form.setFieldsValue({ username: '', password: '', autoLogin: true }); | |||||
| LocalStorage.removeItem(LocalStorage.loginUserKey); | |||||
| } | |||||
| } else { | |||||
| form.setFieldsValue({ username: '', password: '', autoLogin: false }); | |||||
| } | |||||
| // getCaptchaCode(); | |||||
| // const autoLogin = LocalStorage.getItem(LocalStorage.rememberPasswordKey) ?? 'false'; | |||||
| // if (autoLogin === 'true') { | |||||
| // const userStorage = LocalStorage.getItem(LocalStorage.loginUserKey); | |||||
| // const userJson = safeInvoke((text: string) => | |||||
| // CryptoJS.AES.decrypt(text, AESKEY).toString(CryptoJS.enc.Utf8), | |||||
| // )(userStorage); | |||||
| // const user = safeInvoke(parseJsonText)(userJson); | |||||
| // if (user && typeof user === 'object' && user.version === VERSION) { | |||||
| // const { username, password } = user; | |||||
| // form.setFieldsValue({ username: username, password: password, autoLogin: true }); | |||||
| // } else { | |||||
| // form.setFieldsValue({ username: '', password: '', autoLogin: true }); | |||||
| // LocalStorage.removeItem(LocalStorage.loginUserKey); | |||||
| // } | |||||
| // } else { | |||||
| // form.setFieldsValue({ username: '', password: '', autoLogin: false }); | |||||
| // } | |||||
| getClientInfo(); | |||||
| }, []); | }, []); | ||||
| const getClientInfo = async () => { | |||||
| const [res] = await to(getClientInfoReq()); | |||||
| if (res && res.data) { | |||||
| const clientInfo = res.data; | |||||
| SessionStorage.setItem(SessionStorage.clientInfoKey, clientInfo, true); | |||||
| gotoOAuth2(); | |||||
| } | |||||
| }; | |||||
| const getCaptchaCode = async () => { | const getCaptchaCode = async () => { | ||||
| const [res] = await to(getCaptchaImg()); | const [res] = await to(getCaptchaImg()); | ||||
| if (res) { | if (res) { | ||||
| @@ -71,6 +82,12 @@ const Login = () => { | |||||
| } | } | ||||
| }; | }; | ||||
| const handleSubmit2 = async (values: API.LoginParams) => { | |||||
| const url = | |||||
| 'http://172.20.32.106:8080/oauth/authorize?client_id=ci4s&response_type=code&grant_type=authorization_code'; | |||||
| window.location.href = url; | |||||
| }; | |||||
| // 登录 | // 登录 | ||||
| const handleSubmit = async (values: API.LoginParams) => { | const handleSubmit = async (values: API.LoginParams) => { | ||||
| const [res, error] = await to(login({ ...values, uuid })); | const [res, error] = await to(login({ ...values, uuid })); | ||||
| @@ -109,113 +126,115 @@ const Login = () => { | |||||
| } | } | ||||
| }; | }; | ||||
| return ( | |||||
| <div className={styles['user-login']}> | |||||
| <div className={styles['user-login__left']}> | |||||
| <div className={styles['user-login__left__top']}> | |||||
| <img | |||||
| src={require('@/assets/img/logo.png')} | |||||
| style={{ width: '32px', marginRight: '12px' }} | |||||
| draggable={false} | |||||
| alt="" | |||||
| /> | |||||
| 智能材料科研平台 | |||||
| </div> | |||||
| <div className={styles['user-login__left__title']}> | |||||
| <span>智能材料科研平台</span> | |||||
| <img | |||||
| src={require('@/assets/img/login-ai-logo.png')} | |||||
| className={styles['user-login__left__title__img']} | |||||
| draggable={false} | |||||
| alt="" | |||||
| /> | |||||
| </div> | |||||
| <div className={styles['user-login__left__message']}> | |||||
| <span>大语言模型运维 统一管理平台</span> | |||||
| </div> | |||||
| <img | |||||
| className={styles['user-login__left__bottom-img']} | |||||
| src={require('@/assets/img/login-left-image.png')} | |||||
| draggable={false} | |||||
| alt="" | |||||
| /> | |||||
| </div> | |||||
| <div className={styles['user-login__right']}> | |||||
| <div> | |||||
| <div className={styles['user-login__right__title']}> | |||||
| <span style={{ color: '#111111' }}>欢迎登录</span> | |||||
| <span>智能材料科研平台</span> | |||||
| </div> | |||||
| <div className={styles['user-login__right__content']}> | |||||
| <div className={styles['user-login__right__content__title']}>账号登录</div> | |||||
| <div className={styles['user-login__right__content__form']}> | |||||
| <Form | |||||
| labelCol={{ span: 0 }} | |||||
| wrapperCol={{ span: 24 }} | |||||
| initialValues={{ autoLogin: true }} | |||||
| onFinish={handleSubmit} | |||||
| autoComplete="off" | |||||
| form={form} | |||||
| > | |||||
| <Form.Item name="username" rules={[{ required: true, message: '请输入用户名' }]}> | |||||
| <Input | |||||
| placeholder="请输入用户名" | |||||
| prefix={<LoginInputPrefix icon={require('@/assets/img/login-user.png')} />} | |||||
| allowClear | |||||
| /> | |||||
| </Form.Item> | |||||
| <Form.Item name="password" rules={[{ required: true, message: '请输入密码' }]}> | |||||
| <Input.Password | |||||
| placeholder="请输入密码" | |||||
| prefix={<LoginInputPrefix icon={require('@/assets/img/login-password.png')} />} | |||||
| allowClear | |||||
| /> | |||||
| </Form.Item> | |||||
| <Flex align="start" style={{ height: '98px' }}> | |||||
| <div style={{ flex: 1 }}> | |||||
| <Form.Item name="code" rules={[{ required: true, message: '请输入验证码' }]}> | |||||
| <Input | |||||
| placeholder="请输入验证码" | |||||
| prefix={ | |||||
| <LoginInputPrefix icon={require('@/assets/img/login-captcha.png')} /> | |||||
| } | |||||
| ref={captchaInputRef} | |||||
| allowClear | |||||
| /> | |||||
| </Form.Item> | |||||
| </div> | |||||
| <Image | |||||
| className={styles['user-login__right__content__form__captcha']} | |||||
| src={captchaCode} | |||||
| alt="验证码" | |||||
| preview={false} | |||||
| onClick={() => getCaptchaCode()} | |||||
| /> | |||||
| </Flex> | |||||
| <Form.Item | |||||
| name="autoLogin" | |||||
| valuePropName="checked" | |||||
| labelCol={{ span: 0 }} | |||||
| wrapperCol={{ span: 16 }} | |||||
| > | |||||
| <Checkbox>记住密码</Checkbox> | |||||
| </Form.Item> | |||||
| <Form.Item labelCol={{ span: 0 }} wrapperCol={{ span: 24 }}> | |||||
| <Button type="primary" htmlType="submit"> | |||||
| 登录 | |||||
| </Button> | |||||
| </Form.Item> | |||||
| </Form> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| return <div className={styles['user-login']}></div>; | |||||
| // return ( | |||||
| // <div className={styles['user-login']}> | |||||
| // <div className={styles['user-login__left']}> | |||||
| // <div className={styles['user-login__left__top']}> | |||||
| // <img | |||||
| // src={require('@/assets/img/logo.png')} | |||||
| // style={{ width: '32px', marginRight: '12px' }} | |||||
| // draggable={false} | |||||
| // alt="" | |||||
| // /> | |||||
| // 智能材料科研平台 | |||||
| // </div> | |||||
| // <div className={styles['user-login__left__title']}> | |||||
| // <span>智能材料科研平台</span> | |||||
| // <img | |||||
| // src={require('@/assets/img/login-ai-logo.png')} | |||||
| // className={styles['user-login__left__title__img']} | |||||
| // draggable={false} | |||||
| // alt="" | |||||
| // /> | |||||
| // </div> | |||||
| // <div className={styles['user-login__left__message']}> | |||||
| // <span>大语言模型运维 统一管理平台</span> | |||||
| // </div> | |||||
| // <img | |||||
| // className={styles['user-login__left__bottom-img']} | |||||
| // src={require('@/assets/img/login-left-image.png')} | |||||
| // draggable={false} | |||||
| // alt="" | |||||
| // /> | |||||
| // </div> | |||||
| // <div className={styles['user-login__right']}> | |||||
| // <div> | |||||
| // <div className={styles['user-login__right__title']}> | |||||
| // <span style={{ color: '#111111' }}>欢迎登录</span> | |||||
| // <span>智能材料科研平台</span> | |||||
| // </div> | |||||
| // <div className={styles['user-login__right__content']}> | |||||
| // <div className={styles['user-login__right__content__title']}>账号登录</div> | |||||
| // <div className={styles['user-login__right__content__form']}> | |||||
| // <Form | |||||
| // labelCol={{ span: 0 }} | |||||
| // wrapperCol={{ span: 24 }} | |||||
| // initialValues={{ autoLogin: true }} | |||||
| // onFinish={handleSubmit2} | |||||
| // autoComplete="off" | |||||
| // form={form} | |||||
| // > | |||||
| // <Form.Item name="username" rules={[{ required: false, message: '请输入用户名' }]}> | |||||
| // <Input | |||||
| // placeholder="请输入用户名" | |||||
| // prefix={<LoginInputPrefix icon={require('@/assets/img/login-user.png')} />} | |||||
| // allowClear | |||||
| // /> | |||||
| // </Form.Item> | |||||
| // <Form.Item name="password" rules={[{ required: false, message: '请输入密码' }]}> | |||||
| // <Input.Password | |||||
| // placeholder="请输入密码" | |||||
| // prefix={<LoginInputPrefix icon={require('@/assets/img/login-password.png')} />} | |||||
| // allowClear | |||||
| // /> | |||||
| // </Form.Item> | |||||
| // <Flex align="start" style={{ height: '98px' }}> | |||||
| // <div style={{ flex: 1 }}> | |||||
| // <Form.Item name="code" rules={[{ required: false, message: '请输入验证码' }]}> | |||||
| // <Input | |||||
| // placeholder="请输入验证码" | |||||
| // prefix={ | |||||
| // <LoginInputPrefix icon={require('@/assets/img/login-captcha.png')} /> | |||||
| // } | |||||
| // ref={captchaInputRef} | |||||
| // allowClear | |||||
| // /> | |||||
| // </Form.Item> | |||||
| // </div> | |||||
| // <Image | |||||
| // className={styles['user-login__right__content__form__captcha']} | |||||
| // src={captchaCode} | |||||
| // alt="验证码" | |||||
| // preview={false} | |||||
| // onClick={() => getCaptchaCode()} | |||||
| // /> | |||||
| // </Flex> | |||||
| // <Form.Item | |||||
| // name="autoLogin" | |||||
| // valuePropName="checked" | |||||
| // labelCol={{ span: 0 }} | |||||
| // wrapperCol={{ span: 16 }} | |||||
| // > | |||||
| // <Checkbox>记住密码</Checkbox> | |||||
| // </Form.Item> | |||||
| // <Form.Item labelCol={{ span: 0 }} wrapperCol={{ span: 24 }}> | |||||
| // <Button type="primary" htmlType="submit"> | |||||
| // 登录 | |||||
| // </Button> | |||||
| // </Form.Item> | |||||
| // </Form> | |||||
| // </div> | |||||
| // </div> | |||||
| // </div> | |||||
| // </div> | |||||
| // </div> | |||||
| // ); | |||||
| }; | }; | ||||
| export default Login; | export default Login; | ||||
| @@ -0,0 +1,221 @@ | |||||
| import { clearSessionToken, setSessionToken } from '@/access'; | |||||
| import { getCaptchaImg, login } from '@/services/system/auth'; | |||||
| import { parseJsonText } from '@/utils'; | |||||
| import { safeInvoke } from '@/utils/functional'; | |||||
| import LocalStorage from '@/utils/localStorage'; | |||||
| import { to } from '@/utils/promise'; | |||||
| import { history, useModel } from '@umijs/max'; | |||||
| import { Button, Checkbox, Flex, Form, Image, Input, message, type InputRef } from 'antd'; | |||||
| import CryptoJS from 'crypto-js'; | |||||
| import { useEffect, useRef, useState } from 'react'; | |||||
| import { flushSync } from 'react-dom'; | |||||
| import styles from './login.less'; | |||||
| const VERSION = 1; | |||||
| const AESKEY = 'OPENSOURCETECHNOLOGYCENTER'; | |||||
| const LoginInputPrefix = ({ icon }: { icon: string }) => { | |||||
| return ( | |||||
| <div className={styles['login-input-prefix']}> | |||||
| <img className={styles['login-input-prefix__icon']} src={icon} alt="" draggable={false} /> | |||||
| <div className={styles['login-input-prefix__line']}></div> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| const Login = () => { | |||||
| const { initialState, setInitialState } = useModel('@@initialState'); | |||||
| const [captchaCode, setCaptchaCode] = useState<string>(''); | |||||
| const [uuid, setUuid] = useState<string>(''); | |||||
| const [form] = Form.useForm(); | |||||
| const captchaInputRef = useRef<InputRef>(null); | |||||
| useEffect(() => { | |||||
| getCaptchaCode(); | |||||
| const autoLogin = LocalStorage.getItem(LocalStorage.rememberPasswordKey) ?? 'false'; | |||||
| if (autoLogin === 'true') { | |||||
| const userStorage = LocalStorage.getItem(LocalStorage.loginUserKey); | |||||
| const userJson = safeInvoke((text: string) => | |||||
| CryptoJS.AES.decrypt(text, AESKEY).toString(CryptoJS.enc.Utf8), | |||||
| )(userStorage); | |||||
| const user = safeInvoke(parseJsonText)(userJson); | |||||
| if (user && typeof user === 'object' && user.version === VERSION) { | |||||
| const { username, password } = user; | |||||
| form.setFieldsValue({ username: username, password: password, autoLogin: true }); | |||||
| } else { | |||||
| form.setFieldsValue({ username: '', password: '', autoLogin: true }); | |||||
| LocalStorage.removeItem(LocalStorage.loginUserKey); | |||||
| } | |||||
| } else { | |||||
| form.setFieldsValue({ username: '', password: '', autoLogin: false }); | |||||
| } | |||||
| }, []); | |||||
| const getCaptchaCode = async () => { | |||||
| const [res] = await to(getCaptchaImg()); | |||||
| if (res) { | |||||
| const imgdata = `data:image/png;base64,${res.img}`; | |||||
| setCaptchaCode(imgdata); | |||||
| setUuid(res.uuid); | |||||
| } | |||||
| }; | |||||
| const fetchUserInfo = async () => { | |||||
| const userInfo = await initialState?.fetchUserInfo?.(); | |||||
| if (userInfo) { | |||||
| flushSync(() => { | |||||
| setInitialState((s) => ({ | |||||
| ...s, | |||||
| currentUser: userInfo, | |||||
| })); | |||||
| }); | |||||
| } | |||||
| }; | |||||
| // 登录 | |||||
| const handleSubmit = async (values: API.LoginParams) => { | |||||
| const [res, error] = await to(login({ ...values, uuid })); | |||||
| if (res && res.data) { | |||||
| const current = new Date(); | |||||
| const expireTime = current.setTime(current.getTime() + 1000 * 12 * 60 * 60); | |||||
| const { access_token } = res.data; | |||||
| setSessionToken(access_token, access_token, expireTime); | |||||
| message.success('登录成功!'); | |||||
| LocalStorage.setItem(LocalStorage.rememberPasswordKey, values.autoLogin ? 'true' : 'false'); | |||||
| if (values.autoLogin) { | |||||
| const user = { | |||||
| username: values.username, | |||||
| password: values.password, | |||||
| version: VERSION, | |||||
| }; | |||||
| const encrypted = CryptoJS.AES.encrypt(JSON.stringify(user), AESKEY).toString(); | |||||
| LocalStorage.setItem(LocalStorage.loginUserKey, encrypted); | |||||
| } else { | |||||
| LocalStorage.removeItem(LocalStorage.loginUserKey); | |||||
| } | |||||
| await fetchUserInfo(); | |||||
| const urlParams = new URL(window.location.href).searchParams; | |||||
| history.push(urlParams.get('redirect') || '/'); | |||||
| } else { | |||||
| if (error?.data?.code === 500 && error?.data?.msg === '验证码错误') { | |||||
| captchaInputRef.current?.focus({ | |||||
| cursor: 'all', | |||||
| }); | |||||
| } | |||||
| clearSessionToken(); | |||||
| getCaptchaCode(); | |||||
| } | |||||
| }; | |||||
| return ( | |||||
| <div className={styles['user-login']}> | |||||
| <div className={styles['user-login__left']}> | |||||
| <div className={styles['user-login__left__top']}> | |||||
| <img | |||||
| src={require('@/assets/img/logo.png')} | |||||
| style={{ width: '32px', marginRight: '12px' }} | |||||
| draggable={false} | |||||
| alt="" | |||||
| /> | |||||
| 智能材料科研平台 | |||||
| </div> | |||||
| <div className={styles['user-login__left__title']}> | |||||
| <span>智能材料科研平台</span> | |||||
| <img | |||||
| src={require('@/assets/img/login-ai-logo.png')} | |||||
| className={styles['user-login__left__title__img']} | |||||
| draggable={false} | |||||
| alt="" | |||||
| /> | |||||
| </div> | |||||
| <div className={styles['user-login__left__message']}> | |||||
| <span>大语言模型运维 统一管理平台</span> | |||||
| </div> | |||||
| <img | |||||
| className={styles['user-login__left__bottom-img']} | |||||
| src={require('@/assets/img/login-left-image.png')} | |||||
| draggable={false} | |||||
| alt="" | |||||
| /> | |||||
| </div> | |||||
| <div className={styles['user-login__right']}> | |||||
| <div> | |||||
| <div className={styles['user-login__right__title']}> | |||||
| <span style={{ color: '#111111' }}>欢迎登录</span> | |||||
| <span>智能材料科研平台</span> | |||||
| </div> | |||||
| <div className={styles['user-login__right__content']}> | |||||
| <div className={styles['user-login__right__content__title']}>账号登录</div> | |||||
| <div className={styles['user-login__right__content__form']}> | |||||
| <Form | |||||
| labelCol={{ span: 0 }} | |||||
| wrapperCol={{ span: 24 }} | |||||
| initialValues={{ autoLogin: true }} | |||||
| onFinish={handleSubmit} | |||||
| autoComplete="off" | |||||
| form={form} | |||||
| > | |||||
| <Form.Item name="username" rules={[{ required: true, message: '请输入用户名' }]}> | |||||
| <Input | |||||
| placeholder="请输入用户名" | |||||
| prefix={<LoginInputPrefix icon={require('@/assets/img/login-user.png')} />} | |||||
| allowClear | |||||
| /> | |||||
| </Form.Item> | |||||
| <Form.Item name="password" rules={[{ required: true, message: '请输入密码' }]}> | |||||
| <Input.Password | |||||
| placeholder="请输入密码" | |||||
| prefix={<LoginInputPrefix icon={require('@/assets/img/login-password.png')} />} | |||||
| allowClear | |||||
| /> | |||||
| </Form.Item> | |||||
| <Flex align="start" style={{ height: '98px' }}> | |||||
| <div style={{ flex: 1 }}> | |||||
| <Form.Item name="code" rules={[{ required: true, message: '请输入验证码' }]}> | |||||
| <Input | |||||
| placeholder="请输入验证码" | |||||
| prefix={ | |||||
| <LoginInputPrefix icon={require('@/assets/img/login-captcha.png')} /> | |||||
| } | |||||
| ref={captchaInputRef} | |||||
| allowClear | |||||
| /> | |||||
| </Form.Item> | |||||
| </div> | |||||
| <Image | |||||
| className={styles['user-login__right__content__form__captcha']} | |||||
| src={captchaCode} | |||||
| alt="验证码" | |||||
| preview={false} | |||||
| onClick={() => getCaptchaCode()} | |||||
| /> | |||||
| </Flex> | |||||
| <Form.Item | |||||
| name="autoLogin" | |||||
| valuePropName="checked" | |||||
| labelCol={{ span: 0 }} | |||||
| wrapperCol={{ span: 16 }} | |||||
| > | |||||
| <Checkbox>记住密码</Checkbox> | |||||
| </Form.Item> | |||||
| <Form.Item labelCol={{ span: 0 }} wrapperCol={{ span: 24 }}> | |||||
| <Button type="primary" htmlType="submit"> | |||||
| 登录 | |||||
| </Button> | |||||
| </Form.Item> | |||||
| </Form> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| export default Login; | |||||
| @@ -0,0 +1,16 @@ | |||||
| import { request } from '@umijs/max'; | |||||
| // 单点登录 | |||||
| export function loginByOauth2Req(data) { | |||||
| return request(`/api/auth/loginByOauth2`, { | |||||
| method: 'POST', | |||||
| data, | |||||
| }); | |||||
| } | |||||
| // 登录获取客户端信息 | |||||
| export function getClientInfoReq() { | |||||
| return request(`/api/auth/oauth2ClientInfo`, { | |||||
| method: 'GET', | |||||
| }); | |||||
| } | |||||
| @@ -38,11 +38,14 @@ | |||||
| ); | ); | ||||
| // 字体大小 | // 字体大小 | ||||
| @font-size-input: 14px; | |||||
| @font-size: 15px; | @font-size: 15px; | ||||
| @font-size-title: 18px; | |||||
| @font-size-content: 16px; | @font-size-content: 16px; | ||||
| @font-size-input: 14px; | |||||
| @font-size-input-lg: 16px; | |||||
| @font-size-input-lg: @font-size-content; | |||||
| @font-size-title: 18px; | |||||
| // padding | |||||
| @content-padding: 25px; | |||||
| // 函数 | // 函数 | ||||
| .addAlpha(@color, @alpha) { | .addAlpha(@color, @alpha) { | ||||
| @@ -7,6 +7,17 @@ | |||||
| import { ExperimentStatus, TensorBoardStatus } from '@/enums'; | import { ExperimentStatus, TensorBoardStatus } from '@/enums'; | ||||
| import type { Settings as LayoutSettings } from '@ant-design/pro-components'; | import type { Settings as LayoutSettings } from '@ant-design/pro-components'; | ||||
| export type ClientInfo = { | |||||
| accessTokenUri: string; | |||||
| checkTokenUri: string; | |||||
| clientId: string; | |||||
| clientSecret: string; | |||||
| loginPage: string; | |||||
| logoutUri: string; | |||||
| redirectUri: string; | |||||
| userAuthorizationUri: string; | |||||
| }; | |||||
| // 全局初始状态类型 | // 全局初始状态类型 | ||||
| export type GlobalInitialState = { | export type GlobalInitialState = { | ||||
| settings?: Partial<LayoutSettings>; | settings?: Partial<LayoutSettings>; | ||||
| @@ -14,6 +25,7 @@ export type GlobalInitialState = { | |||||
| fetchUserInfo?: () => Promise<API.CurrentUser | undefined>; | fetchUserInfo?: () => Promise<API.CurrentUser | undefined>; | ||||
| loading?: boolean; | loading?: boolean; | ||||
| collapsed?: boolean; | collapsed?: boolean; | ||||
| clientInfo?: ClientInfo; | |||||
| }; | }; | ||||
| // 流水线全局参数 | // 流水线全局参数 | ||||
| @@ -9,6 +9,8 @@ export default class SessionStorage { | |||||
| static readonly serviceVersionInfoKey = 'service-version-info'; | static readonly serviceVersionInfoKey = 'service-version-info'; | ||||
| // 编辑器 url | // 编辑器 url | ||||
| static readonly editorUrlKey = 'editor-url'; | static readonly editorUrlKey = 'editor-url'; | ||||
| // 客户端信息 | |||||
| static readonly clientInfoKey = 'client-info'; | |||||
| static getItem(key: string, isObject: boolean = false) { | static getItem(key: string, isObject: boolean = false) { | ||||
| const jsonStr = sessionStorage.getItem(key); | const jsonStr = sessionStorage.getItem(key); | ||||
| @@ -6,9 +6,11 @@ | |||||
| import { PageEnum } from '@/enums/pagesEnums'; | import { PageEnum } from '@/enums/pagesEnums'; | ||||
| import { removeAllPageCacheState } from '@/hooks/pageCacheState'; | import { removeAllPageCacheState } from '@/hooks/pageCacheState'; | ||||
| import themes from '@/styles/theme.less'; | import themes from '@/styles/theme.less'; | ||||
| import { type ClientInfo } from '@/types'; | |||||
| import { history } from '@umijs/max'; | import { history } from '@umijs/max'; | ||||
| import { Modal, message, type ModalFuncProps, type UploadFile } from 'antd'; | import { Modal, message, type ModalFuncProps, type UploadFile } from 'antd'; | ||||
| import { closeAllModals } from './modal'; | import { closeAllModals } from './modal'; | ||||
| import SessionStorage from './sessionStorage'; | |||||
| type ModalConfirmProps = ModalFuncProps & { | type ModalConfirmProps = ModalFuncProps & { | ||||
| isDelete?: boolean; | isDelete?: boolean; | ||||
| @@ -75,9 +77,7 @@ export const gotoLoginPage = (toHome: boolean = true) => { | |||||
| const { pathname, search } = location; | const { pathname, search } = location; | ||||
| const urlParams = new URLSearchParams(); | const urlParams = new URLSearchParams(); | ||||
| urlParams.append('redirect', pathname + search); | urlParams.append('redirect', pathname + search); | ||||
| const newSearch = toHome && pathname !== '/' ? '' : urlParams.toString(); | |||||
| // console.log('pathname', pathname); | |||||
| // console.log('search', search); | |||||
| const newSearch = toHome || pathname === '/' ? '' : urlParams.toString(); | |||||
| if (pathname !== PageEnum.LOGIN) { | if (pathname !== PageEnum.LOGIN) { | ||||
| closeAllModals(); | closeAllModals(); | ||||
| removeAllPageCacheState(); | removeAllPageCacheState(); | ||||
| @@ -88,6 +88,15 @@ export const gotoLoginPage = (toHome: boolean = true) => { | |||||
| } | } | ||||
| }; | }; | ||||
| export const gotoOAuth2 = () => { | |||||
| const clientInfo = SessionStorage.getItem(SessionStorage.clientInfoKey, true) as ClientInfo; | |||||
| if (clientInfo) { | |||||
| const { clientId, userAuthorizationUri } = clientInfo; | |||||
| const url = `${userAuthorizationUri}?client_id=${clientId}&response_type=code&grant_type=authorization_code`; | |||||
| location.replace(url); | |||||
| } | |||||
| }; | |||||
| /** | /** | ||||
| * 验证文件上传 | * 验证文件上传 | ||||
| * | * | ||||
| @@ -0,0 +1,25 @@ | |||||
| package com.ruoyi.auth.config; | |||||
| import lombok.Getter; | |||||
| import lombok.Setter; | |||||
| import org.springframework.boot.context.properties.ConfigurationProperties; | |||||
| import org.springframework.cloud.context.config.annotation.RefreshScope; | |||||
| import org.springframework.context.annotation.Configuration; | |||||
| @Configuration | |||||
| @RefreshScope | |||||
| @ConfigurationProperties(prefix = "oauth2") | |||||
| @Getter | |||||
| @Setter | |||||
| public class Oauth2ClientProperties { | |||||
| private String clientId; | |||||
| private String clientSecret; | |||||
| private String scope; | |||||
| private String userAuthorizationUri; | |||||
| private String accessTokenUri; | |||||
| private String redirectUri; | |||||
| private String logoutUri; | |||||
| private String checkTokenUri; | |||||
| private String loginPage; | |||||
| } | |||||
| @@ -2,12 +2,19 @@ package com.ruoyi.auth.controller; | |||||
| import javax.servlet.http.HttpServletRequest; | import javax.servlet.http.HttpServletRequest; | ||||
| import com.alibaba.fastjson2.JSON; | |||||
| import com.ruoyi.auth.config.Oauth2ClientProperties; | |||||
| import com.ruoyi.auth.form.AccessTokenVo; | |||||
| import com.ruoyi.auth.form.LoginKeyBody; | import com.ruoyi.auth.form.LoginKeyBody; | ||||
| import com.ruoyi.common.core.exception.ServiceException; | |||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.web.bind.annotation.DeleteMapping; | |||||
| import org.springframework.web.bind.annotation.PostMapping; | |||||
| import org.springframework.web.bind.annotation.RequestBody; | |||||
| import org.springframework.web.bind.annotation.RestController; | |||||
| import org.springframework.http.HttpEntity; | |||||
| import org.springframework.http.HttpHeaders; | |||||
| import org.springframework.http.MediaType; | |||||
| import org.springframework.http.ResponseEntity; | |||||
| import org.springframework.util.LinkedMultiValueMap; | |||||
| import org.springframework.util.MultiValueMap; | |||||
| import org.springframework.web.bind.annotation.*; | |||||
| import com.ruoyi.auth.form.LoginBody; | import com.ruoyi.auth.form.LoginBody; | ||||
| import com.ruoyi.auth.form.RegisterBody; | import com.ruoyi.auth.form.RegisterBody; | ||||
| import com.ruoyi.auth.service.SysLoginService; | import com.ruoyi.auth.service.SysLoginService; | ||||
| @@ -18,6 +25,9 @@ import com.ruoyi.common.security.auth.AuthUtil; | |||||
| import com.ruoyi.common.security.service.TokenService; | import com.ruoyi.common.security.service.TokenService; | ||||
| import com.ruoyi.common.security.utils.SecurityUtils; | import com.ruoyi.common.security.utils.SecurityUtils; | ||||
| import com.ruoyi.system.api.model.LoginUser; | import com.ruoyi.system.api.model.LoginUser; | ||||
| import org.springframework.web.client.RestTemplate; | |||||
| import java.util.Map; | |||||
| /** | /** | ||||
| * token 控制 | * token 控制 | ||||
| @@ -33,6 +43,9 @@ public class TokenController | |||||
| @Autowired | @Autowired | ||||
| private SysLoginService sysLoginService; | private SysLoginService sysLoginService; | ||||
| @Autowired | |||||
| private Oauth2ClientProperties oauth2ClientProperties; | |||||
| @PostMapping("login") | @PostMapping("login") | ||||
| public R<?> login(@RequestBody LoginBody form) | public R<?> login(@RequestBody LoginBody form) | ||||
| { | { | ||||
| @@ -51,6 +64,64 @@ public class TokenController | |||||
| return R.ok(tokenService.createToken(userInfo)); | return R.ok(tokenService.createToken(userInfo)); | ||||
| } | } | ||||
| @PostMapping("loginByOauth2") | |||||
| public R<?> loginByOauth2(@RequestBody Map<String,String> params) | |||||
| /** | |||||
| * { | |||||
| * "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiZGVtby1hcHAiXSwiZXhwIjoxNzI5MTU0MTExLCJ1c2VyX25hbWUiOiJhZG1pbiIsImp0aSI6IjQzNGVkNmI0LWIzN2MtNDliMS04NTczLWZhNmU4YTg5YTUxYSIsImNsaWVudF9pZCI6IkFCQyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdfQ.U591q4fUaUBtBt5Ex-S2daM7DIl9-Ov0MsveymNfHxI", | |||||
| * "token_type": "bearer", | |||||
| * "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiZGVtby1hcHAiXSwidXNlcl9uYW1lIjoiYWRtaW4iLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiYXRpIjoiNDM0ZWQ2YjQtYjM3Yy00OWIxLTg1NzMtZmE2ZThhODlhNTFhIiwiZXhwIjoxNzMxNjQ5OTY4LCJqdGkiOiJiODFhNmJkMC02ZDQzLTQ4M2QtOThmMy1hZWIxNDcyZDUwNzciLCJjbGllbnRfaWQiOiJBQkMifQ.0uMYVqW1G7j0chwxIdWGwpjDr12ogZPcD1iQfPsAs5k", | |||||
| * "expires_in": 7198, | |||||
| * "scope": "read write", | |||||
| * "account_info": { | |||||
| * "id": 1, | |||||
| * "clientId": "ABC", | |||||
| * "username": "admin", | |||||
| * "mobile": "1232378743", | |||||
| * "email": "abc@123.com" | |||||
| * } | |||||
| * } | |||||
| */ | |||||
| { | |||||
| if (params.containsKey("code") && StringUtils.isNotBlank(params.get("code"))){ | |||||
| RestTemplate restTemplate = new RestTemplate(); | |||||
| String url = oauth2ClientProperties.getAccessTokenUri(); | |||||
| HttpHeaders headers = new HttpHeaders(); | |||||
| headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); | |||||
| MultiValueMap<String, String> map= new LinkedMultiValueMap<>(); | |||||
| map.add("grant_type", "authorization_code"); | |||||
| map.add("code", params.get("code")); | |||||
| map.add("redirect_uri", oauth2ClientProperties.getRedirectUri()); | |||||
| map.add("client_id", oauth2ClientProperties.getClientId()); | |||||
| map.add("client_secret", oauth2ClientProperties.getClientSecret()); | |||||
| HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers); | |||||
| ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class); | |||||
| String body = response.getBody(); | |||||
| AccessTokenVo accessTokenVo = JSON.parseObject(body, AccessTokenVo.class); | |||||
| String accessToken = accessTokenVo.getAccess_token(); | |||||
| AccessTokenVo.Account_info accountInfo = accessTokenVo.getAccount_info(); | |||||
| // 用户登录 | |||||
| LoginUser userInfo = sysLoginService.login(accountInfo); | |||||
| // 获取登录token | |||||
| Map<String, Object> token = tokenService.createToken(userInfo); | |||||
| token.put("checkTokenUri",oauth2ClientProperties.getCheckTokenUri()); | |||||
| token.put("logoutUri",oauth2ClientProperties.getLogoutUri()); | |||||
| token.put("oauth2AccessToken",accessToken); | |||||
| return R.ok(token); | |||||
| } | |||||
| throw new ServiceException("用户信息获取失败"); | |||||
| } | |||||
| @GetMapping("oauth2ClientInfo") | |||||
| public R<?> getClientInfo() { | |||||
| return R.ok(JSON.toJSON(oauth2ClientProperties)); | |||||
| } | |||||
| @DeleteMapping("logout") | @DeleteMapping("logout") | ||||
| public R<?> logout(HttpServletRequest request) | public R<?> logout(HttpServletRequest request) | ||||
| { | { | ||||
| @@ -0,0 +1,119 @@ | |||||
| package com.ruoyi.auth.form; | |||||
| import java.io.Serializable; | |||||
| import java.lang.Integer; | |||||
| import java.lang.String; | |||||
| public class AccessTokenVo implements Serializable { | |||||
| private String access_token; | |||||
| private String refresh_token; | |||||
| private String scope; | |||||
| private Account_info account_info; | |||||
| private String token_type; | |||||
| private Integer expires_in; | |||||
| public String getAccess_token() { | |||||
| return this.access_token; | |||||
| } | |||||
| public void setAccess_token(String access_token) { | |||||
| this.access_token = access_token; | |||||
| } | |||||
| public String getRefresh_token() { | |||||
| return this.refresh_token; | |||||
| } | |||||
| public void setRefresh_token(String refresh_token) { | |||||
| this.refresh_token = refresh_token; | |||||
| } | |||||
| public String getScope() { | |||||
| return this.scope; | |||||
| } | |||||
| public void setScope(String scope) { | |||||
| this.scope = scope; | |||||
| } | |||||
| public Account_info getAccount_info() { | |||||
| return this.account_info; | |||||
| } | |||||
| public void setAccount_info(Account_info account_info) { | |||||
| this.account_info = account_info; | |||||
| } | |||||
| public String getToken_type() { | |||||
| return this.token_type; | |||||
| } | |||||
| public void setToken_type(String token_type) { | |||||
| this.token_type = token_type; | |||||
| } | |||||
| public Integer getExpires_in() { | |||||
| return this.expires_in; | |||||
| } | |||||
| public void setExpires_in(Integer expires_in) { | |||||
| this.expires_in = expires_in; | |||||
| } | |||||
| public static class Account_info implements Serializable { | |||||
| private String clientId; | |||||
| private String mobile; | |||||
| private Integer id; | |||||
| private String email; | |||||
| private String username; | |||||
| public String getClientId() { | |||||
| return this.clientId; | |||||
| } | |||||
| public void setClientId(String clientId) { | |||||
| this.clientId = clientId; | |||||
| } | |||||
| public String getMobile() { | |||||
| return this.mobile; | |||||
| } | |||||
| public void setMobile(String mobile) { | |||||
| this.mobile = mobile; | |||||
| } | |||||
| public Integer getId() { | |||||
| return this.id; | |||||
| } | |||||
| public void setId(Integer id) { | |||||
| this.id = id; | |||||
| } | |||||
| public String getEmail() { | |||||
| return this.email; | |||||
| } | |||||
| public void setEmail(String email) { | |||||
| this.email = email; | |||||
| } | |||||
| public String getUsername() { | |||||
| return this.username; | |||||
| } | |||||
| public void setUsername(String username) { | |||||
| this.username = username; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,5 +1,6 @@ | |||||
| package com.ruoyi.auth.service; | package com.ruoyi.auth.service; | ||||
| import com.ruoyi.auth.form.AccessTokenVo; | |||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||
| import com.ruoyi.common.core.constant.CacheConstants; | import com.ruoyi.common.core.constant.CacheConstants; | ||||
| @@ -193,4 +194,62 @@ public class SysLoginService | |||||
| } | } | ||||
| return userInfo; | return userInfo; | ||||
| } | } | ||||
| public LoginUser login(AccessTokenVo.Account_info accountInfo) { | |||||
| String username = accountInfo.getUsername(); | |||||
| // 用户名或密码为空 错误 | |||||
| if (StringUtils.isAnyBlank(username)) | |||||
| { | |||||
| recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户/密码必须填写"); | |||||
| throw new ServiceException("用户/密码必须填写"); | |||||
| } | |||||
| // 用户名不在指定范围内 错误 | |||||
| if (username.length() < UserConstants.USERNAME_MIN_LENGTH | |||||
| || username.length() > UserConstants.USERNAME_MAX_LENGTH) | |||||
| { | |||||
| recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户名不在指定范围"); | |||||
| throw new ServiceException("用户名不在指定范围"); | |||||
| } | |||||
| // IP黑名单校验 | |||||
| String blackStr = Convert.toStr(redisService.getCacheObject(CacheConstants.SYS_LOGIN_BLACKIPLIST)); | |||||
| if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) | |||||
| { | |||||
| recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "很遗憾,访问IP已被列入系统黑名单"); | |||||
| throw new ServiceException("很遗憾,访问IP已被列入系统黑名单"); | |||||
| } | |||||
| // 查询用户信息 | |||||
| R<LoginUser> userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER); | |||||
| if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData())) | |||||
| { | |||||
| recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在"); | |||||
| throw new ServiceException("登录用户:" + username + " 不存在"); | |||||
| // register(username, "123456"); | |||||
| // userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER); | |||||
| } | |||||
| if (R.FAIL == userResult.getCode()) | |||||
| { | |||||
| throw new ServiceException(userResult.getMsg()); | |||||
| } | |||||
| LoginUser userInfo = userResult.getData(); | |||||
| SysUser user = userResult.getData().getSysUser(); | |||||
| if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) | |||||
| { | |||||
| recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "对不起,您的账号已被删除"); | |||||
| throw new ServiceException("对不起,您的账号:" + username + " 已被删除"); | |||||
| } | |||||
| if (UserStatus.DISABLE.getCode().equals(user.getStatus())) | |||||
| { | |||||
| recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户已停用,请联系管理员"); | |||||
| throw new ServiceException("对不起,您的账号:" + username + " 已停用"); | |||||
| } | |||||
| recordLogService.recordLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功"); | |||||
| return userInfo; | |||||
| } | |||||
| } | } | ||||
| @@ -3,7 +3,7 @@ server: | |||||
| port: 8082 | port: 8082 | ||||
| # Spring | # Spring | ||||
| spring: | |||||
| spring: | |||||
| application: | application: | ||||
| # 应用名称 | # 应用名称 | ||||
| name: ruoyi-gateway | name: ruoyi-gateway | ||||
| @@ -83,7 +83,7 @@ public class DevEnvironmentController extends BaseController { | |||||
| * @return 删除是否成功 | * @return 删除是否成功 | ||||
| */ | */ | ||||
| @DeleteMapping("{id}") | @DeleteMapping("{id}") | ||||
| public GenericsAjaxResult<String> deleteById(@PathVariable("id") Integer id) { | |||||
| public GenericsAjaxResult<String> deleteById(@PathVariable("id") Integer id) throws Exception { | |||||
| return genericsSuccess(this.devEnvironmentService.removeById(id)); | return genericsSuccess(this.devEnvironmentService.removeById(id)); | ||||
| } | } | ||||
| @@ -54,5 +54,5 @@ public interface DevEnvironmentService { | |||||
| */ | */ | ||||
| boolean deleteById(Integer id); | boolean deleteById(Integer id); | ||||
| String removeById(Integer id); | |||||
| String removeById(Integer id) throws Exception; | |||||
| } | } | ||||
| @@ -138,7 +138,7 @@ public class DevEnvironmentServiceImpl implements DevEnvironmentService { | |||||
| } | } | ||||
| @Override | @Override | ||||
| public String removeById(Integer id) { | |||||
| public String removeById(Integer id) throws Exception { | |||||
| DevEnvironment devEnvironment = this.devEnvironmentDao.queryById(id); | DevEnvironment devEnvironment = this.devEnvironmentDao.queryById(id); | ||||
| if (devEnvironment == null){ | if (devEnvironment == null){ | ||||
| return "开发环境信息不存在"; | return "开发环境信息不存在"; | ||||
| @@ -152,6 +152,7 @@ public class DevEnvironmentServiceImpl implements DevEnvironmentService { | |||||
| return "无权限删除该开发环境"; | return "无权限删除该开发环境"; | ||||
| } | } | ||||
| jupyterService.stopJupyterService(id); | |||||
| devEnvironment.setState(0); | devEnvironment.setState(0); | ||||
| return this.devEnvironmentDao.update(devEnvironment)>0?"删除成功":"删除失败"; | return this.devEnvironmentDao.update(devEnvironment)>0?"删除成功":"删除失败"; | ||||
| } | } | ||||
| @@ -63,7 +63,7 @@ public class ImageServiceImpl implements ImageService { | |||||
| private MinioService minioService; | private MinioService minioService; | ||||
| @Value("${minio.dataReleaseBucketName}") | @Value("${minio.dataReleaseBucketName}") | ||||
| private String bucketName; | private String bucketName; | ||||
| // @Value("${harbor.bucketName}") | |||||
| // @Value("${harbor.bucketName}") | |||||
| // private String bucketName; | // private String bucketName; | ||||
| @Value("${harbor.repository}") | @Value("${harbor.repository}") | ||||
| private String repository; | private String repository; | ||||
| @@ -184,12 +184,14 @@ public class ImageServiceImpl implements ImageService { | |||||
| // } | // } | ||||
| List<ImageVersion> imageVersions = imageVersionService.queryByImageId(id); | List<ImageVersion> imageVersions = imageVersionService.queryByImageId(id); | ||||
| for (ImageVersion imageVersion :imageVersions) { | |||||
| dockerClientUtil.removeImage(imageVersion.getUrl(), imageVersion.getHostIp()); | |||||
| for (ImageVersion imageVersion : imageVersions) { | |||||
| if (StringUtils.isNotEmpty(imageVersion.getHostIp())) { | |||||
| dockerClientUtil.removeImage(imageVersion.getUrl(), imageVersion.getHostIp()); | |||||
| } | |||||
| } | } | ||||
| image.setState(0); | image.setState(0); | ||||
| return this.imageDao.update(image) > 0 ? "删除成功" : "删除失败"; | |||||
| return this.imageDao.update(image) > 0 ? "删除成功" : "删除失败"; | |||||
| } | } | ||||
| @@ -376,10 +378,10 @@ public class ImageServiceImpl implements ImageService { | |||||
| if (oldImage != null) { | if (oldImage != null) { | ||||
| List<ImageVersion> oldImageVersions = imageVersionDao.queryByImageId(oldImage.getId()); | List<ImageVersion> oldImageVersions = imageVersionDao.queryByImageId(oldImage.getId()); | ||||
| for (ImageVersion oldImageVersion : oldImageVersions) { | for (ImageVersion oldImageVersion : oldImageVersions) { | ||||
| if(oldImageVersion.getTagName().equals(imageVo.getTagName())){ | |||||
| if (oldImageVersion.getTagName().equals(imageVo.getTagName())) { | |||||
| throw new IllegalStateException("镜像tag不能重复"); | throw new IllegalStateException("镜像tag不能重复"); | ||||
| } | } | ||||
| } | |||||
| } | |||||
| } | } | ||||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | LoginUser loginUser = SecurityUtils.getLoginUser(); | ||||
| @@ -116,6 +116,7 @@ public class ServiceServiceImpl implements ServiceService { | |||||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | LoginUser loginUser = SecurityUtils.getLoginUser(); | ||||
| serviceVersion.setCreateBy(loginUser.getUsername()); | serviceVersion.setCreateBy(loginUser.getUsername()); | ||||
| serviceVersion.setUpdateBy(loginUser.getUsername()); | serviceVersion.setUpdateBy(loginUser.getUsername()); | ||||
| serviceVersion.setRunState(Constant.Pending); | |||||
| serviceDao.insertServiceVersion(serviceVersion); | serviceDao.insertServiceVersion(serviceVersion); | ||||
| runServiceVersion(serviceVersion.getId()); | runServiceVersion(serviceVersion.getId()); | ||||
| return serviceVersion; | return serviceVersion; | ||||
| @@ -12,8 +12,7 @@ import io.kubernetes.client.openapi.ApiException; | |||||
| import io.kubernetes.client.openapi.apis.AppsV1Api; | import io.kubernetes.client.openapi.apis.AppsV1Api; | ||||
| import io.kubernetes.client.openapi.apis.CoreV1Api; | import io.kubernetes.client.openapi.apis.CoreV1Api; | ||||
| import io.kubernetes.client.openapi.models.*; | import io.kubernetes.client.openapi.models.*; | ||||
| import io.kubernetes.client.util.ClientBuilder; | |||||
| import io.kubernetes.client.util.credentials.AccessTokenAuthentication; | |||||
| import io.kubernetes.client.util.Config; | |||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||
| import org.apache.commons.lang.StringUtils; | import org.apache.commons.lang.StringUtils; | ||||
| import org.json.JSONObject; | import org.json.JSONObject; | ||||
| @@ -62,9 +61,10 @@ public class K8sClientUtil { | |||||
| this.http = http; | this.http = http; | ||||
| this.token = token; | this.token = token; | ||||
| try { | try { | ||||
| this.apiClient = new ClientBuilder(). | |||||
| setBasePath(http).setVerifyingSsl(false). | |||||
| setAuthentication(new AccessTokenAuthentication(token)).build(); | |||||
| // this.apiClient = new ClientBuilder(). | |||||
| // setBasePath(http).setVerifyingSsl(false). | |||||
| // setAuthentication(new AccessTokenAuthentication(token)).build(); | |||||
| this.apiClient = Config.fromCluster(); | |||||
| } catch (Exception e) { | } catch (Exception e) { | ||||
| log.error("构建K8s-Client异常", e); | log.error("构建K8s-Client异常", e); | ||||
| throw new RuntimeException("构建K8s-Client异常"); | throw new RuntimeException("构建K8s-Client异常"); | ||||
| @@ -624,7 +624,17 @@ public class K8sClientUtil { | |||||
| public V1Pod createPodWithEnv(String podName, String namespace, String proxyUrl, String mountPath, String pvcName, String image) { | public V1Pod createPodWithEnv(String podName, String namespace, String proxyUrl, String mountPath, String pvcName, String image) { | ||||
| CoreV1Api api = new CoreV1Api(apiClient); | CoreV1Api api = new CoreV1Api(apiClient); | ||||
| V1PodList v1PodList = null; | |||||
| V1SecurityContext v1SecurityContext = new V1SecurityContext(); | |||||
| v1SecurityContext.setPrivileged(true); | |||||
| // 配置卷和卷挂载 | |||||
| List<V1VolumeMount> volumeMounts = new ArrayList<>(); | |||||
| volumeMounts.add(new V1VolumeMount().name("workspace").mountPath(mountPath)); | |||||
| List<V1Volume> volumes = new ArrayList<>(); | |||||
| volumes.add(new V1Volume().name("workspace").hostPath(new V1HostPathVolumeSource().path(hostPath + "/" + podName + "/" + mountPath).type("DirectoryOrCreate"))); | |||||
| V1Pod pod = new V1PodBuilder() | V1Pod pod = new V1PodBuilder() | ||||
| .withNewMetadata() | .withNewMetadata() | ||||
| .withName(podName) | .withName(podName) | ||||
| @@ -633,7 +643,9 @@ public class K8sClientUtil { | |||||
| .addNewContainer() | .addNewContainer() | ||||
| .withName(podName) | .withName(podName) | ||||
| .withImage(image) // 替换为您实际要使用的镜像名称 | .withImage(image) // 替换为您实际要使用的镜像名称 | ||||
| .withVolumeMounts(new V1VolumeMount().name("workspace").mountPath(mountPath)) | |||||
| .withSecurityContext(v1SecurityContext) | |||||
| // .withVolumeMounts(new V1VolumeMount().name("workspace").mountPath(mountPath)) | |||||
| .withVolumeMounts(volumeMounts) | |||||
| .withNewSecurityContext().withNewPrivileged(true).endSecurityContext() | .withNewSecurityContext().withNewPrivileged(true).endSecurityContext() | ||||
| .addNewEnv() | .addNewEnv() | ||||
| .withName("HTTP_PROXY") | .withName("HTTP_PROXY") | ||||
| @@ -648,9 +660,10 @@ public class K8sClientUtil { | |||||
| .withValue("localhost,kubernetes.default.svc") | .withValue("localhost,kubernetes.default.svc") | ||||
| .endEnv() | .endEnv() | ||||
| .endContainer() | .endContainer() | ||||
| .addNewVolume() | |||||
| .withName("workspace").withPersistentVolumeClaim(new V1PersistentVolumeClaimVolumeSource().claimName(pvcName)) | |||||
| .endVolume() | |||||
| // .addNewVolume() | |||||
| // .withName("workspace").withPersistentVolumeClaim(new V1PersistentVolumeClaimVolumeSource().claimName(pvcName)) | |||||
| // .endVolume() | |||||
| .withVolumes(volumes) | |||||
| .endSpec() | .endSpec() | ||||
| .build(); | .build(); | ||||
| try { | try { | ||||