diff --git a/react-ui/config/config.ts b/react-ui/config/config.ts index 20c738a1..4ac775d9 100644 --- a/react-ui/config/config.ts +++ b/react-ui/config/config.ts @@ -177,28 +177,22 @@ export default defineConfig({ apps: process.env.UMI_APP_HUO_SHI ? [ { - name: 'flint-data', // 数据服务微应用 + name: 'flint', // 数据服务微应用 + // entry: 'http://localhost:8083', // 开发环境地址 + entry: '/flint', // 生产环境地址 + activeRule: '/flint', // 激活规则 + }, + { + name: 'trainfer', // 服务管理 // entry: 'http://localhost:8081', // 开发环境地址 - entry: '/flint-data/', // 生产环境地址 - activeRule: '/flint-data', // 激活规则 + entry: '/trainfer', // 生产环境地址 + activeRule: '/trainfer', // 激活规则 }, { - name: 'flint-bml', // 训练模块微应用 - // entry: 'http://localhost:8082', - entry: '/flint-bml/', - activeRule: '/training/flint-bml', - }, - { - name: 'flint-console', // 集群管理 - // entry: 'http://localhost:8083', - entry: '/flint-console/', - activeRule: '/flint-console', - }, - { - name: 'flint-service', // 服务模块微应用 - // entry: 'http://localhost:8085', - entry: '/flint-service/', - activeRule: '/dataset/flint-service', + name: 'portal', // 服务管理 + // entry: 'http://localhost:8082', // 开发环境地址 + entry: '/portal', // 生产环境地址 + activeRule: '/portal', // 激活规则 }, ] : [], diff --git a/react-ui/config/proxy.ts b/react-ui/config/proxy.ts index 8f793831..795a034e 100644 --- a/react-ui/config/proxy.ts +++ b/react-ui/config/proxy.ts @@ -18,6 +18,12 @@ export default { // 如果需要自定义本地开发服务器 请取消注释按需调整 dev: { // localhost:8000/api/** -> https://preview.pro.ant.design/api/** + '/proxyApi/': { + target: 'https://172.29.246.110:30016', + changeOrigin: true, + secure: false, + // target: 'http://172.31.164.103:30009/', + }, '/api/': { // 要代理的地址 target: 'http://172.20.32.121:31213/', // 开发环境 @@ -60,7 +66,7 @@ export default { }, '/huoshiProxyApi/': { // target: 'http:///218.77.58.19:31213', // 公网环境 - target: 'http://218.77.58.19:30009/', // 火石环境 + target: 'https://172.29.246.110:30016', // 火石环境 changeOrigin: true, pathRewrite: { '^/huoshiProxyApi': '' }, secure: false, @@ -75,10 +81,7 @@ export default { // target: 'http://172.31.164.103:30009/', changeOrigin: true, }, - '/proxyApi/': { - target: 'http://192.168.60.11:30009/', - // target: 'http://172.31.164.103:30009/', - }, + }, /** diff --git a/react-ui/config/routes.ts b/react-ui/config/routes.ts index 15d4201c..46e8682a 100644 --- a/react-ui/config/routes.ts +++ b/react-ui/config/routes.ts @@ -775,237 +775,255 @@ export default [ }, ...(process.env.UMI_APP_HUO_SHI ? [ + { + path: '/flint/*', + name: '数据管理', + microApp: 'flint', + layout: true, + }, + { + path: '/trainfer/*', + name: '火石服务', + microApp: 'trainfer', + layout: true, + }, + { + path: '/portal/*', + name: '火石服务', + microApp: 'portal', + layout: true, + }, // 数据标注页面 - 使用自定义组件包装微应用 - { - path: '/flint-data/mark/list', - name: '数据标注', - component: './DatasetPreparation/mark/index', - layout: true, - }, - // 数据服务子路径 - 直接路由到微应用(排除 mark/list) - { - path: '/flint-data/*', - name: '数据服务', - microApp: 'flint-data', - layout: true, - }, - { - path: '/training/flint-bml/*', - name: '训练模块', - microApp: 'flint-bml', - layout: true, - }, - { - path: '/flint-console/*', - name: '集群管理', - microApp: 'flint-console', - layout: true, - }, - { - path: '/dataset/flint-service/*', - name: '服务模块', - microApp: 'flint-service', - layout: true, - }, - { - path: '/training', - name: '模型训练', - routes: [ - { - name: '小模型训练', - path: 'pipeline', - routes: [ - { - path: '', - redirect: 'template', - }, - { - name: '流水线模板', - path: 'template', - routes: [ - { - name: '流水线模板', - path: '', - component: './Pipeline/index', - }, - { - name: '流水线详情', - path: 'info/:id', - component: './Pipeline/Info/index', - }, - ], - }, - { - name: '实验', - path: 'experiment', - routes: [ - { - name: '实验', - path: '', - component: './Experiment/index', - }, - { - name: '实验实例', - path: 'instance/:workflowId/:id', - component: './Experiment/Info/index', - }, - { - name: '实验对比', - path: 'compare', - routes: [ - { - name: '实验对比', - path: '', - component: './Experiment/Comparison/index', - }, - { - name: '可视化对比', - path: 'compare-visual', - component: './Experiment/Aim/index', - }, - ], - }, - { - name: '可视化', - path: 'visual', - component: './Experiment/Tensorboard/index', - }, - ], - }, - { - name: '自动机器学习', - path: 'automl', - routes: [ - { - name: '自动机器学习', - path: '', - component: './AutoML/List/index', - }, - { - name: '实验详情', - path: 'info/:id', - component: './AutoML/Info/index', - }, - { - name: '创建实验', - path: 'create', - component: './AutoML/Create/index', - }, - { - name: '编辑实验', - path: 'edit/:id', - component: './AutoML/Create/index', - }, - { - name: '复制实验', - path: 'copy/:id', - component: './AutoML/Create/index', - }, - { - name: '实验实例详情', - path: 'instance/:experimentId/:id', - component: './AutoML/Instance/index', - }, - ], - }, - { - name: '超参数自动寻优', - path: 'hyperparameter', - routes: [ - { - name: '超参数寻优', - path: '', - component: './HyperParameter/List/index', - }, - { - name: '实验详情', - path: 'info/:id', - component: './HyperParameter/Info/index', - }, - { - name: '创建实验', - path: 'create', - component: './HyperParameter/Create/index', - }, - { - name: '编辑实验', - path: 'edit/:id', - component: './HyperParameter/Create/index', - }, - { - name: '复制实验', - path: 'copy/:id', - component: './HyperParameter/Create/index', - }, - { - name: '实验实例详情', - path: 'instance/:experimentId/:id', - routes: [ - { - name: '实验实例详情', - path: '', - component: './HyperParameter/Instance/index', - }, - { - name: '可视化对比', - path: 'compare-visual', - component: './Experiment/Aim/index', - }, - ], - }, - ], - }, - { - name: '主动学习', - path: 'active-learn', - routes: [ - { - name: '主动学习', - path: '', - component: './ActiveLearn/List/index', - }, - { - name: '实验详情', - path: 'info/:id', - component: './ActiveLearn/Info/index', - }, - { - name: '创建实验', - path: 'create', - component: './ActiveLearn/Create/index', - }, - { - name: '编辑实验', - path: 'edit/:id', - component: './ActiveLearn/Create/index', - }, - { - name: '复制实验', - path: 'copy/:id', - component: './ActiveLearn/Create/index', - }, - { - name: '实验实例详情', - path: 'instance/:experimentId/:id', - routes: [ - { - name: '实验实例详情', - path: '', - component: './ActiveLearn/Instance/index', - }, - { - name: '数据标注', - path: 'label', - component: './ActiveLearn/Label/index', - }, - ], - }, - ], - }, - ], - }, - ], - }, + // { + // path: '/flint-data/mark/list', + // name: '数据标注', + // component: './DatasetPreparation/mark/index', + // layout: true, + // }, + // // 数据服务子路径 - 直接路由到微应用(排除 mark/list) + // { + // path: '/flint-data/*', + // name: '数据服务', + // microApp: 'flint-data', + // layout: true, + // }, + // { + // path: '/training/flint-bml/*', + // name: '训练模块', + // microApp: 'flint-bml', + // layout: true, + // }, + // { + // path: '/flint-console/*', + // name: '集群管理', + // microApp: 'flint-console', + // layout: true, + // }, + // { + // path: '/dataset/flint-service/*', + // name: '服务模块', + // microApp: 'flint-service', + // layout: true, + // }, + // { + // path: '/training', + // name: '模型训练', + // routes: [ + // { + // name: '小模型训练', + // path: 'pipeline', + // routes: [ + // { + // path: '', + // redirect: 'template', + // }, + // { + // name: '流水线模板', + // path: 'template', + // routes: [ + // { + // name: '流水线模板', + // path: '', + // component: './Pipeline/index', + // }, + // { + // name: '流水线详情', + // path: 'info/:id', + // component: './Pipeline/Info/index', + // }, + // ], + // }, + // { + // name: '实验', + // path: 'experiment', + // routes: [ + // { + // name: '实验', + // path: '', + // component: './Experiment/index', + // }, + // { + // name: '实验实例', + // path: 'instance/:workflowId/:id', + // component: './Experiment/Info/index', + // }, + // { + // name: '实验对比', + // path: 'compare', + // routes: [ + // { + // name: '实验对比', + // path: '', + // component: './Experiment/Comparison/index', + // }, + // { + // name: '可视化对比', + // path: 'compare-visual', + // component: './Experiment/Aim/index', + // }, + // ], + // }, + // { + // name: '可视化', + // path: 'visual', + // component: './Experiment/Tensorboard/index', + // }, + // ], + // }, + // { + // name: '自动机器学习', + // path: 'automl', + // routes: [ + // { + // name: '自动机器学习', + // path: '', + // component: './AutoML/List/index', + // }, + // { + // name: '实验详情', + // path: 'info/:id', + // component: './AutoML/Info/index', + // }, + // { + // name: '创建实验', + // path: 'create', + // component: './AutoML/Create/index', + // }, + // { + // name: '编辑实验', + // path: 'edit/:id', + // component: './AutoML/Create/index', + // }, + // { + // name: '复制实验', + // path: 'copy/:id', + // component: './AutoML/Create/index', + // }, + // { + // name: '实验实例详情', + // path: 'instance/:experimentId/:id', + // component: './AutoML/Instance/index', + // }, + // ], + // }, + // { + // name: '超参数自动寻优', + // path: 'hyperparameter', + // routes: [ + // { + // name: '超参数寻优', + // path: '', + // component: './HyperParameter/List/index', + // }, + // { + // name: '实验详情', + // path: 'info/:id', + // component: './HyperParameter/Info/index', + // }, + // { + // name: '创建实验', + // path: 'create', + // component: './HyperParameter/Create/index', + // }, + // { + // name: '编辑实验', + // path: 'edit/:id', + // component: './HyperParameter/Create/index', + // }, + // { + // name: '复制实验', + // path: 'copy/:id', + // component: './HyperParameter/Create/index', + // }, + // { + // name: '实验实例详情', + // path: 'instance/:experimentId/:id', + // routes: [ + // { + // name: '实验实例详情', + // path: '', + // component: './HyperParameter/Instance/index', + // }, + // { + // name: '可视化对比', + // path: 'compare-visual', + // component: './Experiment/Aim/index', + // }, + // ], + // }, + // ], + // }, + // { + // name: '主动学习', + // path: 'active-learn', + // routes: [ + // { + // name: '主动学习', + // path: '', + // component: './ActiveLearn/List/index', + // }, + // { + // name: '实验详情', + // path: 'info/:id', + // component: './ActiveLearn/Info/index', + // }, + // { + // name: '创建实验', + // path: 'create', + // component: './ActiveLearn/Create/index', + // }, + // { + // name: '编辑实验', + // path: 'edit/:id', + // component: './ActiveLearn/Create/index', + // }, + // { + // name: '复制实验', + // path: 'copy/:id', + // component: './ActiveLearn/Create/index', + // }, + // { + // name: '实验实例详情', + // path: 'instance/:experimentId/:id', + // routes: [ + // { + // name: '实验实例详情', + // path: '', + // component: './ActiveLearn/Instance/index', + // }, + // { + // name: '数据标注', + // path: 'label', + // component: './ActiveLearn/Label/index', + // }, + // ], + // }, + // ], + // }, + // ], + // }, + // ], + // }, ] : []), { diff --git a/react-ui/src/app.tsx b/react-ui/src/app.tsx index c82321c9..5b96c542 100644 --- a/react-ui/src/app.tsx +++ b/react-ui/src/app.tsx @@ -28,6 +28,7 @@ import { addAlpha } from './utils/color'; import { HomeUrl } from './utils/constant'; import { closeAllModals } from './utils/modal'; import { gotoHomePage } from './utils/ui'; +import '@/huoshi.less' export { requestConfig as request } from './requestConfig'; /** diff --git a/react-ui/src/huoshi.less b/react-ui/src/huoshi.less new file mode 100644 index 00000000..3b9d04ff --- /dev/null +++ b/react-ui/src/huoshi.less @@ -0,0 +1,374 @@ +.wrapper { + width: 1200px; + margin: 0 auto; +} +.flexCBox{ + display: flex; + align-items: center; +} +.flexMBox { + display: flex; + justify-content: space-between; + align-items: center; +} +.flexCenter { + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; +} +.textCenter { + text-align: center; +} +.noData { + text-align: center; + font-size: 16px; + color: #999; +} +.pd-right-24 { + padding-right: 24px; +} +.mg-right-24 { + margin-right: 24px; +} +/* +文字溢出 +*/ +/* 单行溢出 */ +.single-over { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +/* 多行溢出 */ +.multi-over2, .multi-over3, .multi-over4, .multi-over5 { + display: -webkit-box; + -webkit-box-orient: vertical; + overflow: hidden; +} +.multi-over2 { + -webkit-line-clamp: 2; +} +.multi-over3 { + -webkit-line-clamp: 3; +} +.multi-over4 { + -webkit-line-clamp: 4; +} +.multi-over5 { + -webkit-line-clamp: 5; +} +// common 统一样式 +.mouse-clazz { + font-size: 14px; +} +.can-click { + color: var(--el-color-primary); + cursor: pointer; + &:hover { + color: var(--el-color-primary-light-3); + } +} +.text-click { + cursor: pointer; + transition: all .2s ease; + &:hover { + color: var(--el-color-primary); + } +} +.right-box { + flex-shrink: 0; +} +.input-item { + margin-top: 4px; + margin-bottom: 4px; + margin-right: 24px; + &:last-child { + margin-right: 0; + } +} +.common-input { + // 设计是 224px + width: 220px; +} +.input-label { + display: inline-block; + max-width: 86px; + min-width: 70px; + text-align: right; +} +.input-box { + margin-top: 14px; + width: 100%; + display: flex; + flex-wrap: wrap; + &:first-child { + margin: 0; + } +} +.flex-between { + display: flex; + justify-content: space-between; +} +.m-dropdown-content { + position: relative; + .m-dropdown { + display: none; + position: absolute; + top: 40px; + right: -8px; + min-width: 120px; + line-height: 1; + padding-top: 10px; + .icon-sanjiao { + width: 0; + height: 0; + position: absolute; + top: 4px; + right: 40px; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-bottom: 8px solid #fff; + } + li { + background-color: #fff; + line-height: 40px; + color: var(--main-color); + text-align: center; + cursor: pointer; + box-shadow: 0px 0px 10px 2px #d1dce5; + &:hover { + color: var(--el-color-primary); + } + } + } + &:hover { + .m-dropdown { + display: block; + } + } +} +.el-button--primary.el-button:focus { + color: var(--el-button-text-color); + border-color: var(--el-button-border-color); + background-color: var(--el-button-bg-color); + outline: none; + outline-offset: 0; +} +.el-dialog__title { + font-size: var(--font-16); +} +// .tl-divider { +// width 100vw +// } +.custom-fullscreen-dialog { + .is-fullscreen { + display: flex; + flex-direction: column; + padding: 0; + .el-dialog__header { + // padding: var(--el-dialog-padding-primary); + // box-sizing: border-box; + // height: 65px; + // line-height: 22px; + padding: 0; + // height: 64px; + height: 0; + line-height: 64px; + background: linear-gradient(180deg, #e4eaff, #eaf1fa 48%, #eef2fb); + border-radius: 1px; + position: relative; + border-bottom: none; + // border-bottom 1px solid rgba(255,255,255,0.8) + .el-dialog__headerbtn { + left: 24px; + display: flex; + height: auto; + width: 64px; + top: 20px; + // top 50% + // transform: translateY(-50%); + align-items: center; + .el-dialog__close { + font-size: 17px; + color: var(--el-color-primary); + width: 27px; + height: 27px; + background: rgba(255, 255, 255, 0.69); + border: 1px solid rgba(255, 255, 255, 0.31); + border-radius: 50%; + box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.08); + } + &::after { + content: '返回'; + font-size: 14px; + font-family: PingFangSC, PingFangSC-Regular; + font-weight: 400; + text-align: left; + color: #323233; + line-height: 20px; + margin-left: 8px; + white-space: nowrap; + } + } + } + .el-dialog__body { + flex: 1; + height: 100%; + padding: 0; + // overflow: auto + } + } +} +.message-drawer-container { + .el-drawer__header { + font-family: PingFangSC, PingFangSC-Medium; + border-radius: 3px 3px 0px 0px; + border: 1px solid #e2e7ee; + margin-bottom: 0; + padding-bottom: 20px; + .title { + font-weight: var(--font-weight-bold); + color: #323233; + font-size: 15px; + line-height: 24px; + height: 24px; + } + .goBox { + margin-left: 24px; + cursor: pointer; + display: flex; + align-items: center; + // img { + // vertical-align bottom + // } + } + } + .el-drawer__body { + padding: 16px 0; + } +} + +// 表格公共样式 +.t-table, .f-table-com { + --el-table-header-bg-color: #fff; + .el-table { + &.is-scrolling-left { + th { + &.el-table-fixed-column--left { + background-color: #fff; + } + &.el-table-fixed-column--right { + background-color: #fff; + } + } + } + &.is-scrolling-none { + th { + &.el-table-fixed-column--left { + background-color: #fff; + } + &.el-table-fixed-column--right { + background-color: #fff; + } + } + } + .el-table__header { + thead.is-group { + th { + &.el-table-fixed-column--right { + background-color: var(--el-fill-color-light); + } + &.el-table-fixed-column--left { + background-color: var(--el-fill-color-light); + } + } + } + th { + height: 45px; + background-color: #fff; + font-weight: 400; + font-size: 12px; + letter-spacing: -0.2px; + .cell { + padding: 0 8px; + } + &.el-table-fixed-column--right { + background-color: #fff; + } + } + } + .el-table__body { + .el-table__cell { + cursor: default; + height: 50px; + color: var(--el-text-color-primary); + font-size: 12px; + .cell { + // width: calc(100% - 2px) !important; + padding: 0 8px; + .table-handle-container { + display: flex; + align-items: center; + justify-content: flex-start; + margin-left: -8px; + & > .handle-span { + padding: 0 8px; + font-size: 12px; + color: var(--el-color-primary); + cursor: pointer; + &.is-disabled { + color: var(--el-color-primary-light-5); + } + } + & > .el-dropdown { + font-size: 12px; + } + } + } + } + } + } + .el-pagination.is-background { + position: relative; + justify-content: flex-end; + .el-pager { + li { + &.is-active { + background-color: var(--el-color-primary) !important; + } + } + } + } + +} + +// 解决el-tabs__headers排列在l-tabs__content下面的问题 +.el-tabs { + &.el-tabs--top { + flex-direction: column !important; + } + .el-tabs__header { + order: 1; + } + .el-tabs__content { + order: 2; + } +} + + +// 覆盖aicc-theme样式 +.aicc-theme .el-checkbox__inner::after { + left: 0 !important; + right: 0 !important; + margin: auto !important; +} + +.aicc-theme .el-radio__inner::after { + width: 6px !important; + height: 6px !important; +} + +.qiankun-micro-app-container{ + padding: 70px 24px 24px; +} \ No newline at end of file diff --git a/react-ui/src/pages/Application/useSourceContext.tsx b/react-ui/src/pages/Application/useSourceContext.tsx new file mode 100644 index 00000000..c58e62cd --- /dev/null +++ b/react-ui/src/pages/Application/useSourceContext.tsx @@ -0,0 +1,46 @@ +// src/contexts/SourceContext.tsx +import { createContext, ReactNode, useContext, useState } from 'react'; +import { ApplicationSource } from './types'; + +// 1. 定义 Context 值的类型 +interface SourceContextType { + source: T | null; + setSource: (value: T | null) => void; +} + +// 2. 创建 Context,指定默认值为 undefined(更好的类型安全) +const SourceContext = createContext(undefined); + +// 3. 定义 Provider 组件的 Props 类型 +interface SourceProviderProps { + children: ReactNode; + initialValue?: T | null; +} + +// 4. 创建泛型 Provider 组件 +export function SourceProvider({ children, initialValue = null }: SourceProviderProps) { + const [source, setSource] = useState(initialValue as T | null); + + // 优化性能 + const contextValue = { + source, + setSource, + }; + + return {children}; +} + +// 5. 创建自定义 Hook(支持泛型) +export function useSourceContext(): SourceContextType { + const context = useContext(SourceContext); + + if (context === undefined) { + throw new Error('useSourceContext must be used within a SourceProvider'); + } + + return context as SourceContextType; +} + +export function useTypedSourceContext() { + return useSourceContext(); +} diff --git a/react-ui/src/services/huoshi.ts b/react-ui/src/services/huoshi.ts index f2ce212b..043dc824 100644 --- a/react-ui/src/services/huoshi.ts +++ b/react-ui/src/services/huoshi.ts @@ -69,11 +69,20 @@ export const getHuoshiRoutes = async () => { user: { appList:menuInfo.data.appList, userInfo: userInfo.data, - tenantInfoList: tenantInfo.data, - configInfo:configInfo.data, + tenant: tenantInfo.data, + gConfig:configInfo.data, navList, consoleList }, }), ); + sessionStorage.setItem('globalState',JSON.stringify({ + gConfig:configInfo.data, + userInfo:userInfo.data, + sysType:1 + })) + localStorage.setItem('generate_subMenus','dataDistillation,dataEnhance,dataReflux,qaExtraction') + localStorage.setItem('getCurrentZoneFun','function(e){const t=e.url.split("/")[1];let r=[];const n=sessionStorage.getItem("currentZone");let o=[null,void 0,"null","undefined"].includes(n)?"default":n;if(localStorage.serviceList&&(r=JSON.parse(localStorage.serviceList)),r.length&&t){const e=r.find(e=>e.name===t);if(e?.zones){const t=e.zones.split(",");t.includes(o)||(o=t[0])}}return o}') + localStorage.setItem('processing_subMenus','dataClean,dataFormat,dataAnalysis') + localStorage.setItem('currentLanguage','zh_CN') }; diff --git a/react-ui/火石前端部署.md b/react-ui/火石前端部署.md new file mode 100644 index 00000000..3194c06d --- /dev/null +++ b/react-ui/火石前端部署.md @@ -0,0 +1,58 @@ +### 大模型训练 & 数据管理 (已完成) +> 前端包路径 /home/ruoyi/projects/flint + nginx 修改 115 行 + ```nginx + location /flint { + add_header 'Access-Control-Allow-Private-Network' 'true' always; + add_header 'Access-Control-Allow-Origin' $cors_origin always; + alias /home/ruoyi/projects/flint; + try_files $uri $uri/ @fallback_flint; + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + add_header 'Access-Control-Allow-Origin' $cors_origin always; + expires 1y; + add_header Cache-Control "public, immutable"; + } + } + + location @fallback_flint { + root /home/ruoyi/projects; + try_files /ruoyi-ui/index.html =404; + add_header 'Access-Control-Allow-Origin' $cors_origin always; + } + ``` + +### 服务管理 (开发中) + +> 前端包路径 /home/ruoyi/projects/trainfer + nginx 修改 127 行 + ```nginx + location /trainfer { + add_header 'Access-Control-Allow-Private-Network' 'true' always; + add_header 'Access-Control-Allow-Origin' $cors_origin always; + alias /home/ruoyi/projects/trainfer; + try_files $uri $uri/ @fallback_flint; + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + add_header 'Access-Control-Allow-Origin' $cors_origin always; + expires 1y; + add_header Cache-Control "public, immutable"; + } + } + ``` + +### 集群管理 (开发中) + +> 前端包路径 /home/ruoyi/projects/portal + nginx 修改 139 行 + ```nginx + location /portal { + add_header 'Access-Control-Allow-Private-Network' 'true' always; + add_header 'Access-Control-Allow-Origin' $cors_origin always; + alias /home/ruoyi/projects/portal; + try_files $uri $uri/ @fallback_flint; + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + add_header 'Access-Control-Allow-Origin' $cors_origin always; + expires 1y; + add_header Cache-Control "public, immutable"; + } + } + ``` \ No newline at end of file