| @@ -127,6 +127,8 @@ export default defineConfig({ | |||||
| headScripts: [ | headScripts: [ | ||||
| // 解决首次加载时白屏的问题 | // 解决首次加载时白屏的问题 | ||||
| { src: '/scripts/loading.js', async: true }, | { src: '/scripts/loading.js', async: true }, | ||||
| { src: '/scripts/resize.js', async: true }, | |||||
| // { src: '/scripts/resize-breakpoint.js', async: true }, | |||||
| ], | ], | ||||
| // links: [ | // links: [ | ||||
| // { | // { | ||||
| @@ -20,14 +20,14 @@ export default { | |||||
| // localhost:8000/api/** -> https://preview.pro.ant.design/api/** | // localhost:8000/api/** -> https://preview.pro.ant.design/api/** | ||||
| '/api/': { | '/api/': { | ||||
| // 要代理的地址 | // 要代理的地址 | ||||
| // target: 'http://172.20.32.197:31213', // 开发环境 | |||||
| target: 'http://172.20.32.197:31213', // 开发环境 | |||||
| // target: 'http://172.20.32.235:31213', // 测试环境 | // target: 'http://172.20.32.235:31213', // 测试环境 | ||||
| target: 'http://172.20.32.44:8082', | |||||
| // target: 'http://172.20.32.150:8082', | |||||
| // target: 'http://172.20.32.44:8082', | |||||
| // target: 'http://172.20.32.164:8082', | |||||
| // 配置了这个可以从 http 代理到 https | // 配置了这个可以从 http 代理到 https | ||||
| // 依赖 origin 的功能可能需要这个,比如 cookie | // 依赖 origin 的功能可能需要这个,比如 cookie | ||||
| changeOrigin: true, | changeOrigin: true, | ||||
| pathRewrite: { '^/api': '' }, | |||||
| // pathRewrite: { '^/api': '' }, | |||||
| }, | }, | ||||
| '/profile/avatar/': { | '/profile/avatar/': { | ||||
| target: 'http://172.20.32.235:31213', | target: 'http://172.20.32.235:31213', | ||||
| @@ -13,7 +13,20 @@ | |||||
| export default [ | export default [ | ||||
| { | { | ||||
| path: '/', | path: '/', | ||||
| redirect: '/workspace', | |||||
| redirect: '/home', | |||||
| }, | |||||
| { | |||||
| name: '首页', | |||||
| path: '/home', | |||||
| layout: false, | |||||
| routes: [ | |||||
| { | |||||
| name: '首页', | |||||
| path: '', | |||||
| key: 'home', | |||||
| component: './Home/index', | |||||
| }, | |||||
| ], | |||||
| }, | }, | ||||
| { | { | ||||
| name: '工作空间', | name: '工作空间', | ||||
| @@ -1,6 +1,6 @@ | |||||
| @font-face { | @font-face { | ||||
| font-family: Alibaba; | font-family: Alibaba; | ||||
| src: url('./ALIBABA-PUHUITI-MEDIUM.TTF'); | |||||
| src: url('./ALIBABA-PUHUITI-REGULAR.TTF'); | |||||
| font-display: swap; | font-display: swap; | ||||
| } | } | ||||
| @@ -10,4 +10,17 @@ | |||||
| url('./DingTalk-JinBuTi.woff') format('woff'), /* 兼容性较好的 woff */ | url('./DingTalk-JinBuTi.woff') format('woff'), /* 兼容性较好的 woff */ | ||||
| url('./DingTalk-JinBuTi.ttf') format('truetype'); /* ttf 作为备选 */ | url('./DingTalk-JinBuTi.ttf') format('truetype'); /* ttf 作为备选 */ | ||||
| font-display: swap; /* 优化页面加载时的字体显示 */ | font-display: swap; /* 优化页面加载时的字体显示 */ | ||||
| } | |||||
| @font-face { | |||||
| font-family: 'WenYiHei'; | |||||
| src: url('./WenYiHei.ttf'); | |||||
| font-display: swap; /* 优化页面加载时的字体显示 */ | |||||
| } | |||||
| @font-face { | |||||
| font-family: 'YouSheBiaoTiHei'; | |||||
| src: url('./YouSheBiaoTiHei.ttf'); | |||||
| font-display: swap; /* 优化页面加载时的字体显示 */ | |||||
| } | } | ||||
| @@ -0,0 +1,52 @@ | |||||
| (function (doc, win) { | |||||
| 'use strict'; | |||||
| // 配置项 | |||||
| const config = { | |||||
| // 断点设置(单位:px) | |||||
| // 1440 1560 1680 1800 1920 2040 2160 2280 2400 2520 | |||||
| breakpoints: [ | |||||
| { minWidth: 2520, fontSize: 22 }, // 21 | |||||
| { minWidth: 2280, fontSize: 20 }, // 19 | |||||
| { minWidth: 2040, fontSize: 18 }, // 17 | |||||
| { minWidth: 1800, fontSize: 16 }, // 15 | |||||
| { minWidth: 1560, fontSize: 14 }, // 13 | |||||
| { minWidth: 0, fontSize: 12 }, | |||||
| ], | |||||
| delay: 300 // 防抖延迟(ms) | |||||
| }; | |||||
| const docEl = doc.documentElement; | |||||
| const resizeEvt = 'orientationchange' in win ? 'orientationchange' : 'resize'; | |||||
| let resizeTimeout; | |||||
| // 计算当前宽度对应的字体大小 | |||||
| function calculateFontSize() { | |||||
| const clientWidth = docEl.clientWidth || win.innerWidth; | |||||
| if (!clientWidth) return; | |||||
| // 从大到小匹配断点 | |||||
| const targetBreakpoint = config.breakpoints.find( | |||||
| bp => clientWidth >= bp.minWidth | |||||
| ); | |||||
| // 设置字体大小 | |||||
| docEl.style.fontSize = targetBreakpoint.fontSize + 'px'; | |||||
| // 调试输出(可选) | |||||
| console.debug('[REM-Resize]', | |||||
| 'Width:', clientWidth + 'px', | |||||
| 'Font-Size:', targetBreakpoint.fontSize + 'px'); | |||||
| } | |||||
| // 防抖处理 | |||||
| function handleResize() { | |||||
| clearTimeout(resizeTimeout); | |||||
| resizeTimeout = setTimeout(calculateFontSize, config.delay); | |||||
| } | |||||
| calculateFontSize(); | |||||
| // 初始化监听 | |||||
| win.addEventListener(resizeEvt, handleResize, false); | |||||
| })(document, window); | |||||
| @@ -0,0 +1,44 @@ | |||||
| // rem-resize.js | |||||
| (function (doc, win) { | |||||
| 'use strict'; | |||||
| // 配置项 | |||||
| const config = { | |||||
| designWidth: 1920, // 设计稿宽度 | |||||
| baseFontSize: 16, // 基础字体大小(设计稿下1rem = 16px) | |||||
| minFontSize: 12, // 最小字体限制 | |||||
| maxFontSize: 24, // 最大字体限制 | |||||
| delay: 300, // 窗口变化时的延迟执行(ms) | |||||
| }; | |||||
| const docEl = doc.documentElement; | |||||
| const resizeEvt = 'orientationchange' in win ? 'orientationchange' : 'resize'; | |||||
| let resizeTimeout; | |||||
| function calculateFontSize() { | |||||
| const clientWidth = docEl.clientWidth || win.innerWidth; | |||||
| if (!clientWidth) return; | |||||
| const fontSize = Math.min( | |||||
| Math.max((clientWidth / config.designWidth) * config.baseFontSize, config.minFontSize), | |||||
| config.maxFontSize, | |||||
| ); | |||||
| docEl.style.fontSize = fontSize + 'px'; | |||||
| // 可选:调试输出 | |||||
| if (win.console) { | |||||
| console.debug('[REM-Resize]', 'width:', clientWidth, 'font-size:', fontSize + 'px'); | |||||
| } | |||||
| } | |||||
| function resizeHandler() { | |||||
| clearTimeout(resizeTimeout); | |||||
| resizeTimeout = setTimeout(calculateFontSize, config.delay); | |||||
| } | |||||
| calculateFontSize(); | |||||
| // 初始化监听 | |||||
| win.addEventListener(resizeEvt, resizeHandler, false); | |||||
| })(document, window); | |||||
| @@ -1,4 +1,6 @@ | |||||
| export enum PageEnum { | export enum PageEnum { | ||||
| Root = '/', | |||||
| LOGIN = '/user/login', | LOGIN = '/user/login', | ||||
| Authorize = '/authorize', | Authorize = '/authorize', | ||||
| Home = '/home', | |||||
| } | } | ||||
| @@ -19,6 +19,24 @@ const clearCache = () => { | |||||
| } | } | ||||
| }; | }; | ||||
| const doubleTexxt = () => { | |||||
| if (process.env.NODE_ENV === 'development') { | |||||
| document.body.addEventListener('click', (e) => { | |||||
| const target = e.target; | |||||
| if ( | |||||
| e.altKey && | |||||
| e.ctrlKey && | |||||
| target && | |||||
| target.innerText && | |||||
| target.nodeType === Node.ELEMENT_NODE | |||||
| ) { | |||||
| const times = 2; | |||||
| target.innerText = target.innerText.repeat(times); | |||||
| } | |||||
| }); | |||||
| } | |||||
| }; | |||||
| // if pwa is true | // if pwa is true | ||||
| if (pwa) { | if (pwa) { | ||||
| // Notify user if offline now | // Notify user if offline now | ||||
| @@ -89,3 +107,5 @@ if (pwa) { | |||||
| clearCache(); | clearCache(); | ||||
| } | } | ||||
| doubleTexxt(); | |||||
| @@ -1,6 +1,7 @@ | |||||
| import { setSessionToken } from '@/access'; | import { setSessionToken } from '@/access'; | ||||
| import { loginByOauth2Req } from '@/services/auth'; | import { loginByOauth2Req } from '@/services/auth'; | ||||
| import { to } from '@/utils/promise'; | import { to } from '@/utils/promise'; | ||||
| import SessionStorage from '@/utils/sessionStorage'; | |||||
| import { history, useModel, useSearchParams } from '@umijs/max'; | import { history, useModel, useSearchParams } from '@umijs/max'; | ||||
| import { message } from 'antd'; | import { message } from 'antd'; | ||||
| import { useCallback, useEffect } from 'react'; | import { useCallback, useEffect } from 'react'; | ||||
| @@ -36,7 +37,9 @@ function Authorize() { | |||||
| setSessionToken(access_token, access_token, expires_in); | setSessionToken(access_token, access_token, expires_in); | ||||
| message.success('登录成功!'); | message.success('登录成功!'); | ||||
| await fetchUserInfo(); | await fetchUserInfo(); | ||||
| history.replace(redirect || '/'); | |||||
| const redierctUrl = SessionStorage.getItem(SessionStorage.redirectUrl); | |||||
| history.replace(redirect || redierctUrl || '/workspace'); | |||||
| SessionStorage.removeItem(SessionStorage.redirectUrl); | |||||
| } | } | ||||
| }, [fetchUserInfo, redirect, code]); | }, [fetchUserInfo, redirect, code]); | ||||
| @@ -0,0 +1,13 @@ | |||||
| .block-title { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: center; | |||||
| width: 100%; | |||||
| &__title { | |||||
| color: #020814; | |||||
| font-weight: 500; | |||||
| font-size: 2.25rem; | |||||
| text-align: center; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,24 @@ | |||||
| import classNames from 'classnames'; | |||||
| import ViewMore from '../ViewMore'; | |||||
| import styles from './index.less'; | |||||
| type BlockTitleProps = { | |||||
| /** 自定义类名 */ | |||||
| className?: string; | |||||
| /** 自定义样式 */ | |||||
| style?: React.CSSProperties; | |||||
| /** 标题 */ | |||||
| title: string; | |||||
| onClick?: () => void; | |||||
| }; | |||||
| function BlockTitle({ title, onClick, className, style }: BlockTitleProps) { | |||||
| return ( | |||||
| <div className={classNames(styles['block-title'], className)} style={style}> | |||||
| <div className={styles['block-title__title']}>{title}</div> | |||||
| <ViewMore onClick={onClick}></ViewMore> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default BlockTitle; | |||||
| @@ -0,0 +1,71 @@ | |||||
| .dataset { | |||||
| position: relative; | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| align-items: center; | |||||
| padding: 0 16.25rem 3.125rem; | |||||
| background-image: url(@/assets/img/home/model-bg.png); | |||||
| background-repeat: no-repeat; | |||||
| background-position: top 6.375rem left 0; | |||||
| background-size: 100% 100%; | |||||
| &__item { | |||||
| position: relative; | |||||
| width: 42.75rem; | |||||
| padding: 1.875rem 1.25rem; | |||||
| color: #8284a4; | |||||
| font-size: 0.8125rem; | |||||
| background-color: transparent; | |||||
| border-radius: 11px; | |||||
| cursor: pointer; | |||||
| .backgroundFullImage(url(@/assets/img/home/dataset-item-bg.png)); | |||||
| &:hover { | |||||
| .backgroundFullImage(url(@/assets/img/home/dataset-item-bg-hover.png)); | |||||
| } | |||||
| &__user-avatar { | |||||
| flex: none; | |||||
| width: 2.75rem; | |||||
| height: 2.75rem; | |||||
| margin-right: 1rem; | |||||
| } | |||||
| &__title { | |||||
| flex: 1; | |||||
| color: #020814; | |||||
| font-size: 1rem; | |||||
| .singleLine(); | |||||
| } | |||||
| &:hover &__title { | |||||
| color: @primary-color; | |||||
| } | |||||
| &__arrow { | |||||
| display: none; | |||||
| flex: none; | |||||
| width: 1.5625rem; | |||||
| margin-left: 0.75rem; | |||||
| } | |||||
| &:hover &__arrow { | |||||
| display: block; | |||||
| } | |||||
| &__desc { | |||||
| height: 2.75rem; | |||||
| margin-bottom: 0.875rem; | |||||
| font-size: 0.875rem; | |||||
| line-height: 1.375rem; | |||||
| .multiLine(2); | |||||
| } | |||||
| &__user-divider { | |||||
| height: 0.625rem; | |||||
| margin-right: 0.75rem; | |||||
| margin-left: 0.75rem; | |||||
| background-color: #8284a4; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,95 @@ | |||||
| import { useNavigate } from '@umijs/max'; | |||||
| import { Divider, Flex } from 'antd'; | |||||
| import BlockTitle from '../BlockTitle'; | |||||
| import styles from './index.less'; | |||||
| const datasetData = [ | |||||
| { | |||||
| id: 1, | |||||
| title: '材料大数据与机器学习', | |||||
| desc: '在材料科学与人工智能交叉融合的当下', | |||||
| user: '陈绮贞', | |||||
| date: '18小时前更新', | |||||
| }, | |||||
| { | |||||
| id: 2, | |||||
| title: '材料大数据与机器学习', | |||||
| desc: '在材料科学与人工智能交叉融合的当下,机器学习技术正逐步成为材料研究的重要工具。', | |||||
| user: '陈绮贞', | |||||
| date: '18小时前更新', | |||||
| }, | |||||
| { | |||||
| id: 3, | |||||
| title: '材料大数据与机器学习材料大数据与机器学习材料大数据与机器学习', | |||||
| desc: '在材料科学与人工智能交叉融合的当下,机器学习技术正逐步成为材料研究的重要工具。在材料科学与人工智能交叉融合的当下,机器学习技术正逐步成为材料研究的重要工具在材料科学与人工智能交叉融合的当下,机器学习技术正逐步成为材料研究的重要工具', | |||||
| user: '陈绮贞', | |||||
| date: '18小时前更新', | |||||
| }, | |||||
| { | |||||
| id: 4, | |||||
| title: '材料大数据与机器学习', | |||||
| desc: '在材料科学与人工智能交叉融合的当下,机器学习技术正逐步成为材料研究的重要工具。本课程为2025年新', | |||||
| user: '陈绮贞', | |||||
| date: '18小时前更新', | |||||
| }, | |||||
| { | |||||
| id: 5, | |||||
| title: '材料大数据与机器学习', | |||||
| desc: '在材料科学与人工智能交叉融合的当下,机器学习技术正逐步成为材料研究的重要工具。本课程为2025年新', | |||||
| user: '陈绮贞', | |||||
| date: '18小时前更新', | |||||
| }, | |||||
| { | |||||
| id: 6, | |||||
| title: '材料大数据与机器学习', | |||||
| desc: '在材料科学与人工智能交叉融合的当下,机器学习技术正逐步成为材料研究的重要工具。本课程为2025年新', | |||||
| user: '陈绮贞', | |||||
| date: '18小时前更新', | |||||
| }, | |||||
| ]; | |||||
| function DatasetBlock() { | |||||
| const navigate = useNavigate(); | |||||
| return ( | |||||
| <div className={styles.dataset}> | |||||
| <BlockTitle | |||||
| title="热门数据集" | |||||
| style={{ marginBottom: '6.75rem' }} | |||||
| onClick={() => navigate('/dataset/dataset')} | |||||
| ></BlockTitle> | |||||
| <Flex align="center" justify="space-between" style={{ width: '100%' }} wrap gap="1.875rem 0"> | |||||
| {datasetData.map((item) => { | |||||
| return ( | |||||
| <Flex className={styles['dataset__item']} key={item.id}> | |||||
| <img | |||||
| src={require('@/assets/img/home/user-avatar-big.png')} | |||||
| className={styles['dataset__item__user-avatar']} | |||||
| ></img> | |||||
| <div style={{ flex: 1, minWidth: 0 }}> | |||||
| <Flex align="center" style={{ marginBottom: '0.625rem' }}> | |||||
| <div className={styles['dataset__item__title']}>{item.title}</div> | |||||
| <img | |||||
| className={styles['dataset__item__arrow']} | |||||
| src={require('@/assets/img/home/dataset-arrow-right.png')} | |||||
| ></img> | |||||
| </Flex> | |||||
| <div className={styles['dataset__item__desc']}>{item.desc}</div> | |||||
| <Flex align="center"> | |||||
| <div>{item.user}</div> | |||||
| <Divider | |||||
| type="vertical" | |||||
| className={styles['dataset__item__user-divider']} | |||||
| ></Divider> | |||||
| <div>{item.date}</div> | |||||
| <div></div> | |||||
| </Flex> | |||||
| </div> | |||||
| </Flex> | |||||
| ); | |||||
| })} | |||||
| </Flex> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default DatasetBlock; | |||||
| @@ -0,0 +1,53 @@ | |||||
| .intro { | |||||
| position: relative; | |||||
| z-index: 10; | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| align-items: center; | |||||
| padding-top: 8.375rem; | |||||
| background-image: url(@/assets/img/home/header-bg.png); | |||||
| background-repeat: no-repeat; | |||||
| background-position: left top; | |||||
| background-size: 100% 100%; | |||||
| &__title { | |||||
| margin-bottom: 1.125rem; | |||||
| color: #ffffff; | |||||
| font-size: 2.375rem; | |||||
| font-family: WenYiHei; | |||||
| } | |||||
| &__desc { | |||||
| width: 54.5rem; | |||||
| margin-bottom: 1.875rem; | |||||
| color: #ffffff; | |||||
| font-size: 1rem; | |||||
| line-height: 1.75rem; | |||||
| text-align: center; | |||||
| } | |||||
| &__button { | |||||
| margin-bottom: 4.375rem; | |||||
| padding: 0.625rem 2.375rem; | |||||
| color: #ffffff; | |||||
| font-size: 1rem; | |||||
| text-align: center; | |||||
| background: linear-gradient( | |||||
| 108.54deg, | |||||
| #5eb4ff 3.72%, | |||||
| rgba(42, 92, 255, 0.01) 49.49%, | |||||
| rgba(232, 239, 255, 0.33) 98.01% | |||||
| ); | |||||
| border: 1px solid rgba(255, 255, 255, 0.38); | |||||
| border-radius: 0.5rem; | |||||
| cursor: pointer; | |||||
| &:hover { | |||||
| background: linear-gradient( | |||||
| 108.54deg, | |||||
| rgba(183, 131, 255, 0.81) 3.72%, | |||||
| rgba(119, 208, 255, 0.31) 98.01% | |||||
| ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,24 @@ | |||||
| // import NavBar from '../NavBar'; | |||||
| import { useNavigate } from '@umijs/max'; | |||||
| import StatisticsBlock from '../Statistics'; | |||||
| import styles from './index.less'; | |||||
| function IntroBlock() { | |||||
| const navigate = useNavigate(); | |||||
| return ( | |||||
| <div className={styles.intro}> | |||||
| {/* <NavBar></NavBar> */} | |||||
| <div className={styles['intro__title']}>智能材料科研平台</div> | |||||
| <div className={styles['intro__desc']}> | |||||
| 智能材料科研平台是用于材料研究和开发的技术平台,它旨在提供实验数据收集、分析和可视化等功能, | |||||
| 以支持材料工程师、科学家和研究人员在材料设计、性能评估和工艺优化方面的工作。 | |||||
| </div> | |||||
| <div className={styles['intro__button']} onClick={() => navigate('/workspace')}> | |||||
| 进入首页 | |||||
| </div> | |||||
| <StatisticsBlock></StatisticsBlock> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default IntroBlock; | |||||
| @@ -0,0 +1,67 @@ | |||||
| .model { | |||||
| position: relative; | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| align-items: center; | |||||
| padding: 5.375rem 16.25rem 9.125rem; | |||||
| .backgroundFullImage(url(@/assets/img/home/model-bg.png)); | |||||
| &__item { | |||||
| position: relative; | |||||
| width: 27.875rem; | |||||
| padding: 1.875rem 1.25rem; | |||||
| color: #8284a4; | |||||
| font-size: 0.8125rem; | |||||
| background-color: transparent; | |||||
| border-radius: 11px; | |||||
| box-shadow: 0rem 0.0625rem 0.75rem rgba(33, 73, 212, 0.09); | |||||
| cursor: pointer; | |||||
| .backgroundFullImage(url(@/assets/img/home/model-item-bg.png)); | |||||
| &:hover { | |||||
| color: white; | |||||
| .backgroundFullImage(url(@/assets/img/home/model-item-bg-hover.png)); | |||||
| } | |||||
| &:nth-child(3n + 2) { | |||||
| top: -3.75rem; | |||||
| } | |||||
| &__user-avatar { | |||||
| flex: none; | |||||
| width: 2.75rem; | |||||
| height: 2.75rem; | |||||
| margin-right: 0.875rem; | |||||
| } | |||||
| &__title { | |||||
| margin-bottom: 0.625rem; | |||||
| color: #020814; | |||||
| font-size: 1rem; | |||||
| .singleLine(); | |||||
| } | |||||
| &:hover &__title { | |||||
| color: white; | |||||
| } | |||||
| &__desc { | |||||
| height: 2.75rem; | |||||
| margin-bottom: 0.875rem; | |||||
| font-size: 0.875rem; | |||||
| line-height: 1.375rem; | |||||
| .multiLine(2); | |||||
| } | |||||
| &__user-divider { | |||||
| height: 0.625rem; | |||||
| margin-right: 0.75rem; | |||||
| margin-left: 0.75rem; | |||||
| background-color: #8284a4; | |||||
| } | |||||
| &:hover &__user-divider { | |||||
| background-color: white; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,89 @@ | |||||
| import { useNavigate } from '@umijs/max'; | |||||
| import { Divider, Flex } from 'antd'; | |||||
| import BlockTitle from '../BlockTitle'; | |||||
| import styles from './index.less'; | |||||
| const modelData = [ | |||||
| { | |||||
| id: 1, | |||||
| title: '材料大数据与机器学习', | |||||
| desc: '在材料科学与人工智能交叉融合的当下', | |||||
| user: '陈绮贞', | |||||
| date: '18小时前更新', | |||||
| }, | |||||
| { | |||||
| id: 2, | |||||
| title: '材料大数据与机器学习', | |||||
| desc: '在材料科学与人工智能交叉融合的当下,机器学习技术正逐步成为材料研究的重要工具。', | |||||
| user: '陈绮贞', | |||||
| date: '18小时前更新', | |||||
| }, | |||||
| { | |||||
| id: 3, | |||||
| title: '材料大数据与机器学习材料大数据与机器学习材料大数据与机器学习', | |||||
| desc: '在材料科学与人工智能交叉融合的当下,机器学习技术正逐步成为材料研究的重要工具。在材料科学与人工智能交叉融合的当下,机器学习技术正逐步成为材料研究的重要工具在材料科学与人工智能交叉融合的当下,机器学习技术正逐步成为材料研究的重要工具', | |||||
| user: '陈绮贞', | |||||
| date: '18小时前更新', | |||||
| }, | |||||
| { | |||||
| id: 4, | |||||
| title: '材料大数据与机器学习', | |||||
| desc: '在材料科学与人工智能交叉融合的当下,机器学习技术正逐步成为材料研究的重要工具。本课程为2025年新', | |||||
| user: '陈绮贞', | |||||
| date: '18小时前更新', | |||||
| }, | |||||
| { | |||||
| id: 5, | |||||
| title: '材料大数据与机器学习', | |||||
| desc: '在材料科学与人工智能交叉融合的当下,机器学习技术正逐步成为材料研究的重要工具。本课程为2025年新', | |||||
| user: '陈绮贞', | |||||
| date: '18小时前更新', | |||||
| }, | |||||
| { | |||||
| id: 6, | |||||
| title: '材料大数据与机器学习', | |||||
| desc: '在材料科学与人工智能交叉融合的当下,机器学习技术正逐步成为材料研究的重要工具。本课程为2025年新', | |||||
| user: '陈绮贞', | |||||
| date: '18小时前更新', | |||||
| }, | |||||
| ]; | |||||
| function ModelBlock() { | |||||
| const navigate = useNavigate(); | |||||
| return ( | |||||
| <div className={styles.model}> | |||||
| <BlockTitle | |||||
| title="热门模型" | |||||
| style={{ marginBottom: '8.125rem' }} | |||||
| onClick={() => navigate('/dataset/model')} | |||||
| ></BlockTitle> | |||||
| <Flex align="center" justify="space-between" style={{ width: '100%' }} wrap gap="3.125rem 0"> | |||||
| {modelData.map((item) => { | |||||
| return ( | |||||
| <Flex className={styles['model__item']} key={item.id}> | |||||
| <img | |||||
| src={require('@/assets/img/home/user-avatar-big.png')} | |||||
| className={styles['model__item__user-avatar']} | |||||
| ></img> | |||||
| <div style={{ flex: 1, minWidth: 0 }}> | |||||
| <div className={styles['model__item__title']}>{item.title}</div> | |||||
| <div className={styles['model__item__desc']}>{item.desc}</div> | |||||
| <Flex align="center"> | |||||
| <div>{item.user}</div> | |||||
| <Divider | |||||
| type="vertical" | |||||
| className={styles['model__item__user-divider']} | |||||
| ></Divider> | |||||
| <div>{item.date}</div> | |||||
| <div></div> | |||||
| </Flex> | |||||
| </div> | |||||
| </Flex> | |||||
| ); | |||||
| })} | |||||
| </Flex> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default ModelBlock; | |||||
| @@ -0,0 +1,7 @@ | |||||
| .nav-bar { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| padding: 1.25rem 15.625rem; | |||||
| } | |||||
| @@ -0,0 +1,12 @@ | |||||
| import styles from './index.less'; | |||||
| function NavBar() { | |||||
| return ( | |||||
| <div className={styles['nav-bar']}> | |||||
| <div>智能材料科研平台</div> | |||||
| <div>首页</div> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default NavBar; | |||||
| @@ -0,0 +1,75 @@ | |||||
| .service { | |||||
| position: relative; | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| align-items: center; | |||||
| width: 100%; | |||||
| margin-top: -4rem; | |||||
| padding: 9.625rem 16.25rem 6.25rem; | |||||
| .backgroundFullImage(url(@/assets/img/home/service-bg.png)); | |||||
| &__item { | |||||
| width: 21rem; | |||||
| padding: 1.25rem 1.25rem 1.5625rem; | |||||
| background: #ffffff; | |||||
| border-radius: 1.25rem; | |||||
| box-shadow: 0rem 0rem 0.75rem rgba(33, 73, 212, 0.06); | |||||
| cursor: pointer; | |||||
| &:hover { | |||||
| box-shadow: 0rem 0rem 0.75rem rgba(33, 73, 212, 0.12); | |||||
| } | |||||
| &__image-container { | |||||
| width: 18.4375rem; | |||||
| height: 10.6875rem; | |||||
| margin-bottom: 0.75rem; | |||||
| overflow: hidden; | |||||
| border-radius: 1.875rem; | |||||
| } | |||||
| &__image { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| background-repeat: no-repeat; | |||||
| background-position: top left; | |||||
| background-size: 100% 100%; | |||||
| transform: scale(1); | |||||
| transition: transform 0.3s linear; | |||||
| } | |||||
| &:hover &__image { | |||||
| transform: scale(1.1); | |||||
| } | |||||
| &__title { | |||||
| height: 2.625rem; | |||||
| margin-bottom: 0.875rem; | |||||
| color: #020814; | |||||
| font-size: 0.9375rem; | |||||
| .multiLine(2); | |||||
| } | |||||
| &:hover &__title { | |||||
| color: @primary-color; | |||||
| } | |||||
| &__user-avatar { | |||||
| width: 1.3125rem; | |||||
| height: 1.3125rem; | |||||
| margin-right: 0.5rem; | |||||
| } | |||||
| &__user-name { | |||||
| margin-right: 0.5rem; | |||||
| color: #191919; | |||||
| font-size: 0.875rem; | |||||
| } | |||||
| &__date { | |||||
| color: #8284a4; | |||||
| font-size: 0.8125rem; | |||||
| text-align: right; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,81 @@ | |||||
| import ServiceImg1 from '@/assets/img/home/service1.png'; | |||||
| import ServiceImg2 from '@/assets/img/home/service2.png'; | |||||
| import ServiceImg3 from '@/assets/img/home/service3.png'; | |||||
| import ServiceImg4 from '@/assets/img/home/service4.png'; | |||||
| import { useNavigate } from '@umijs/max'; | |||||
| import { Flex } from 'antd'; | |||||
| import BlockTitle from '../BlockTitle'; | |||||
| import styles from './index.less'; | |||||
| const serviceData = [ | |||||
| { | |||||
| id: 1, | |||||
| img: ServiceImg1, | |||||
| title: 'MD是研究原子间相互作用的基本工具', | |||||
| user: '陈绮贞', | |||||
| date: '18小时前更新', | |||||
| }, | |||||
| { | |||||
| id: 2, | |||||
| img: ServiceImg2, | |||||
| title: 'MD是研究原子间相互作用的基本工具 原子间相互作用势函数 通常基于力场或者量子', | |||||
| user: '陈绮贞', | |||||
| date: '18小时前更新', | |||||
| }, | |||||
| { | |||||
| id: 3, | |||||
| img: ServiceImg3, | |||||
| title: 'MD是研究原子间相互作用的基本工具 原子间相互作用势函数 通常基于力场或者量子', | |||||
| user: '陈绮贞', | |||||
| date: '18小时前更新', | |||||
| }, | |||||
| { | |||||
| id: 4, | |||||
| img: ServiceImg4, | |||||
| title: | |||||
| 'MD是研究原子间相互作用的基本工具 原子间相互作用势函数 通常基于力场或者量子 通常基于力场或者量子 通常基于力场或者量子', | |||||
| user: '陈绮贞', | |||||
| date: '18小时前更新', | |||||
| }, | |||||
| ]; | |||||
| function ServiceBlock() { | |||||
| const navigate = useNavigate(); | |||||
| return ( | |||||
| <div className={styles.service}> | |||||
| <BlockTitle | |||||
| title="热门APP" | |||||
| style={{ marginBottom: '5rem' }} | |||||
| onClick={() => navigate('dataset/modelDeployment')} | |||||
| ></BlockTitle> | |||||
| <Flex align="center" justify="space-between" style={{ width: '100%' }}> | |||||
| {serviceData.map((item) => { | |||||
| return ( | |||||
| <div className={styles['service__item']} key={item.id}> | |||||
| <div className={styles['service__item__image-container']}> | |||||
| <img | |||||
| src={item.img} | |||||
| draggable={false} | |||||
| className={styles['service__item__image']} | |||||
| ></img> | |||||
| </div> | |||||
| <div className={styles['service__item__title']}>{item.title}</div> | |||||
| <Flex align="center" justify="space-between"> | |||||
| <Flex align="center"> | |||||
| <img | |||||
| src={require('@/assets/img/home/user-avatar.png')} | |||||
| className={styles['service__item__user-avatar']} | |||||
| ></img> | |||||
| <div className={styles['service__item__user-name']}>{item.user}</div> | |||||
| </Flex> | |||||
| <div className={styles['service__item__date']}>{item.date}</div> | |||||
| </Flex> | |||||
| </div> | |||||
| ); | |||||
| })} | |||||
| </Flex> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default ServiceBlock; | |||||
| @@ -0,0 +1,30 @@ | |||||
| .statistics { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: space-evenly; | |||||
| width: 87.5rem; | |||||
| height: 7.5rem; | |||||
| .backgroundFullImage(url(@/assets/img/home/statistics-bg.png)); | |||||
| &__item { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| &__icon { | |||||
| width: 3rem; | |||||
| height: 3rem; | |||||
| margin-right: 1rem; | |||||
| } | |||||
| &__count { | |||||
| color: #ffffff; | |||||
| font-size: 2.25rem; | |||||
| font-family: YouSheBiaoTiHei; | |||||
| } | |||||
| &__name { | |||||
| color: #ffffff; | |||||
| font-size: 0.875rem; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,54 @@ | |||||
| import CodeIcon from '@/assets/img/home/code.png'; | |||||
| import DatasetIcon from '@/assets/img/home/dataset.png'; | |||||
| import ImageIcon from '@/assets/img/home/image.png'; | |||||
| import ModelIcon from '@/assets/img/home/model.png'; | |||||
| import ServiceIcon from '@/assets/img/home/service.png'; | |||||
| import styles from './index.less'; | |||||
| const dataList = [ | |||||
| { | |||||
| icon: DatasetIcon, | |||||
| name: '数据集', | |||||
| count: 30, | |||||
| }, | |||||
| { | |||||
| icon: ModelIcon, | |||||
| name: '模型', | |||||
| count: 30, | |||||
| }, | |||||
| { | |||||
| icon: ImageIcon, | |||||
| name: '镜像', | |||||
| count: 30, | |||||
| }, | |||||
| { | |||||
| icon: CodeIcon, | |||||
| name: '代码', | |||||
| count: 30, | |||||
| }, | |||||
| { | |||||
| icon: ServiceIcon, | |||||
| name: '服务', | |||||
| count: 30, | |||||
| }, | |||||
| ]; | |||||
| function StatisticsBlock() { | |||||
| return ( | |||||
| <div className={styles['statistics']}> | |||||
| {dataList.map((item) => { | |||||
| return ( | |||||
| <div key={item.name} className={styles['statistics__item']}> | |||||
| <img src={item.icon} draggable={false} className={styles['statistics__item__icon']} /> | |||||
| <div> | |||||
| <div className={styles['statistics__item__count']}>{item.count}</div> | |||||
| <div className={styles['statistics__item__name']}>{item.name}</div> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| })} | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default StatisticsBlock; | |||||
| @@ -0,0 +1,34 @@ | |||||
| .view-more { | |||||
| position: absolute; | |||||
| right: 16.25rem; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| color: .addAlpha(#020814, 0.7) []; | |||||
| font-size: 0.9375rem; | |||||
| cursor: pointer; | |||||
| &:hover { | |||||
| color: #020814; | |||||
| } | |||||
| &__img { | |||||
| display: inline; | |||||
| width: 1.125rem; | |||||
| height: 1.125rem; | |||||
| margin-left: 0.75rem; | |||||
| } | |||||
| &__hover-img { | |||||
| display: none; | |||||
| width: 1.5625rem; | |||||
| margin-left: 0.625rem; | |||||
| } | |||||
| &:hover &__img { | |||||
| display: none; | |||||
| } | |||||
| &:hover &__hover-img { | |||||
| display: inline; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,29 @@ | |||||
| import classNames from 'classnames'; | |||||
| import styles from './index.less'; | |||||
| type ViewMoreProps = { | |||||
| /** 自定义类名 */ | |||||
| className?: string; | |||||
| /** 自定义样式 */ | |||||
| style?: React.CSSProperties; | |||||
| /** 自定义样式 */ | |||||
| onClick?: () => void; | |||||
| }; | |||||
| function ViewMore({ className, style, onClick }: ViewMoreProps) { | |||||
| return ( | |||||
| <div className={classNames(styles['view-more'], className)} style={style} onClick={onClick}> | |||||
| <span>查看更多</span> | |||||
| <img | |||||
| className={styles['view-more__img']} | |||||
| src={require('@/assets/img/home/right-arrow.png')} | |||||
| ></img> | |||||
| <img | |||||
| className={styles['view-more__hover-img']} | |||||
| src={require('@/assets/img/home/right-arrow-hover.png')} | |||||
| ></img> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default ViewMore; | |||||
| @@ -0,0 +1,15 @@ | |||||
| .home { | |||||
| height: 100%; | |||||
| overflow-y: auto; | |||||
| font-family: Alibaba; | |||||
| &__separator { | |||||
| position: relative; | |||||
| z-index: 10; | |||||
| display: block; | |||||
| width: 97.5rem; | |||||
| height: 8.375rem; | |||||
| margin: 0 auto; | |||||
| margin-top: -5.875rem; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,23 @@ | |||||
| import DatasetBlock from './components/Dataset'; | |||||
| import IntroBlock from './components/Intro'; | |||||
| import ModelBlock from './components/Model'; | |||||
| import ServiceBlock from './components/Service'; | |||||
| import styles from './index.less'; | |||||
| function Home() { | |||||
| return ( | |||||
| <div className={styles.home}> | |||||
| <IntroBlock></IntroBlock> | |||||
| <ServiceBlock></ServiceBlock> | |||||
| <ModelBlock></ModelBlock> | |||||
| <img | |||||
| src={require('@/assets/img/home/model-between-dataset.png')} | |||||
| draggable={false} | |||||
| className={styles['home__separator']} | |||||
| ></img> | |||||
| <DatasetBlock></DatasetBlock> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default Home; | |||||
| @@ -51,6 +51,11 @@ | |||||
| @result: rgba(@red, @green, @blue, @alpha); | @result: rgba(@red, @green, @blue, @alpha); | ||||
| } | } | ||||
| // 转换为 rem | |||||
| .rem(@px) { | |||||
| @result: (@px / 16) * 1rem; | |||||
| } | |||||
| // 混合 | // 混合 | ||||
| // 单行 | // 单行 | ||||
| .singleLine() { | .singleLine() { | ||||
| @@ -73,7 +78,7 @@ | |||||
| .backgroundFullImage(@url) { | .backgroundFullImage(@url) { | ||||
| background-image: @url; | background-image: @url; | ||||
| background-repeat: no-repeat; | background-repeat: no-repeat; | ||||
| background-position: top center; | |||||
| background-position: top left; | |||||
| background-size: 100% 100%; | background-size: 100% 100%; | ||||
| } | } | ||||
| @@ -7,6 +7,9 @@ | |||||
| import { PageEnum } from '@/enums/pagesEnums'; | import { PageEnum } from '@/enums/pagesEnums'; | ||||
| import G6 from '@antv/g6'; | import G6 from '@antv/g6'; | ||||
| // 白名单,不需要登录 | |||||
| const whiteList = [PageEnum.Root, PageEnum.LOGIN, PageEnum.Authorize, PageEnum.Home]; | |||||
| /** | /** | ||||
| * 生成 8 位随机数 | * 生成 8 位随机数 | ||||
| * @returns 8 位随机数 | * @returns 8 位随机数 | ||||
| @@ -295,7 +298,7 @@ export const getGitUrl = (url?: string, branch?: string): string => { | |||||
| * @return {boolean} true if the pathname needs to be authorized, false otherwise | * @return {boolean} true if the pathname needs to be authorized, false otherwise | ||||
| */ | */ | ||||
| export const needAuth = (pathname: string): boolean => { | export const needAuth = (pathname: string): boolean => { | ||||
| return pathname !== PageEnum.LOGIN && pathname !== PageEnum.Authorize; | |||||
| return !whiteList.includes(pathname); | |||||
| }; | }; | ||||
| /** | /** | ||||
| @@ -13,6 +13,8 @@ export default class SessionStorage { | |||||
| static readonly aimUrlKey = 'aim-url'; | static readonly aimUrlKey = 'aim-url'; | ||||
| /** tensorBoard url */ | /** tensorBoard url */ | ||||
| static readonly tensorBoardUrlKey = 'tensor-board-url'; | static readonly tensorBoardUrlKey = 'tensor-board-url'; | ||||
| /** 登录之前的地址 */ | |||||
| static readonly redirectUrl = 'redirect-url'; | |||||
| /** | /** | ||||
| * 获取 SessionStorage 值 | * 获取 SessionStorage 值 | ||||
| @@ -77,6 +77,9 @@ export const gotoLoginPage = (toHome: boolean = true) => { | |||||
| if (pathname !== PageEnum.LOGIN) { | if (pathname !== PageEnum.LOGIN) { | ||||
| closeAllModals(); | closeAllModals(); | ||||
| removeAllPageCacheState(); | removeAllPageCacheState(); | ||||
| if (newSearch) { | |||||
| SessionStorage.setItem(newSearch, SessionStorage.redirectUrl); | |||||
| } | |||||
| history.replace({ | history.replace({ | ||||
| pathname: PageEnum.LOGIN, | pathname: PageEnum.LOGIN, | ||||
| search: newSearch, | search: newSearch, | ||||