From 4fdc77e45331bc9336595259a18c24f70429e4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=B2=E6=82=A6?= Date: Tue, 3 Feb 2026 09:02:44 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E8=BF=87=E7=A8=8B?= =?UTF-8?q?=E7=9F=A9=E9=98=B5=E5=85=A8=E5=B1=8F=E5=8A=9F=E8=83=BD=E5=B9=B6?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=83=A8=E7=BD=B2=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加过程矩阵全屏查看功能,包括状态管理、快捷键支持和响应式布局 优化 Dockerfile 使用 npm ci 并添加生产环境标志 添加 nginx 配置支持 SPA 路由和静态资源缓存 --- Dockerfile | 6 +- nginx.conf | 22 ++++++ src/components/visualize/ProcessMatrix.tsx | 9 ++- src/pages/ProcessMatrixPage.tsx | 88 +++++++++++++++++++--- src/stores/useAppStore.ts | 5 ++ 5 files changed, 118 insertions(+), 12 deletions(-) create mode 100644 nginx.conf diff --git a/Dockerfile b/Dockerfile index c5a9562..895db1a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ WORKDIR /app COPY package*.json ./ -RUN npm install +RUN npm ci --only=production=false COPY . . @@ -12,6 +12,10 @@ RUN npm run build FROM nginx:alpine +# 复制自定义 nginx 配置(支持 SPA 路由) +COPY nginx.conf /etc/nginx/conf.d/default.conf + +# 复制构建产物 COPY --from=builder /app/dist /usr/share/nginx/html EXPOSE 80 diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..c862cb2 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,22 @@ +server { + listen 80; + server_name localhost; + root /usr/share/nginx/html; + index index.html; + + # SPA 路由支持 - 所有路径都返回 index.html + location / { + try_files $uri $uri/ /index.html; + } + + # 静态资源缓存 + location /assets { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # gzip 压缩 + gzip on; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml; + gzip_min_length 1000; +} diff --git a/src/components/visualize/ProcessMatrix.tsx b/src/components/visualize/ProcessMatrix.tsx index 67da0f2..002327f 100644 --- a/src/components/visualize/ProcessMatrix.tsx +++ b/src/components/visualize/ProcessMatrix.tsx @@ -4,13 +4,18 @@ */ import { Link } from 'react-router-dom' import { motion } from 'framer-motion' +import { clsx } from 'clsx' import { knowledgeAreas, processGroups, processes, } from '@/data' -export function ProcessMatrix() { +interface ProcessMatrixProps { + className?: string +} + +export function ProcessMatrix({ className }: ProcessMatrixProps) { // 构建矩阵数据:knowledgeAreaId -> processGroupId -> Process[] const matrix = new Map>() @@ -33,7 +38,7 @@ export function ProcessMatrix() { }) return ( -
+
{/* 表头:过程组 */} diff --git a/src/pages/ProcessMatrixPage.tsx b/src/pages/ProcessMatrixPage.tsx index 76a98c6..c94c3ce 100644 --- a/src/pages/ProcessMatrixPage.tsx +++ b/src/pages/ProcessMatrixPage.tsx @@ -1,19 +1,89 @@ /** * 49过程矩阵页面 */ +import { useEffect } from 'react' import { ProcessMatrix } from '@/components/visualize' +import { Maximize2, Minimize2 } from 'lucide-react' +import { useAppStore } from '@/stores/useAppStore' +import { clsx } from 'clsx' export function ProcessMatrixPage() { + const isFullScreen = useAppStore((s) => s.matrixFullScreen) + const setMatrixFullScreen = useAppStore((s) => s.setMatrixFullScreen) + const setSidebarOpen = useAppStore((s) => s.setSidebarOpen) + + const toggleFullScreen = () => { + if (!isFullScreen) { + setSidebarOpen(false) + } + setMatrixFullScreen(!isFullScreen) + } + + // Handle Escape key to exit full screen + useEffect(() => { + const handleEsc = (e: KeyboardEvent) => { + if (e.key === 'Escape' && isFullScreen) { + setMatrixFullScreen(false) + } + } + window.addEventListener('keydown', handleEsc) + return () => window.removeEventListener('keydown', handleEsc) + }, [isFullScreen, setMatrixFullScreen]) + return ( -
-
-

49过程矩阵

-

- 知识领域 × 过程组 的全景矩阵视图,点击过程可查看详情 -

-
-
- +
+ {/* 隐藏滚动条的样式 */} + {isFullScreen && ( + + )} + + {!isFullScreen && ( +
+
+

49过程矩阵

+

+ 知识领域 × 过程组 的全景矩阵视图,点击过程可查看详情 +

+
+ +
+ )} + +
+ {isFullScreen && ( +
+ 49过程矩阵全景图 + +
+ )} + +
+ +
) diff --git a/src/stores/useAppStore.ts b/src/stores/useAppStore.ts index 903063f..26b5aa4 100644 --- a/src/stores/useAppStore.ts +++ b/src/stores/useAppStore.ts @@ -6,6 +6,7 @@ interface AppState { sidebarOpen: boolean darkMode: boolean searchQuery: string + matrixFullScreen: boolean // 操作 toggleSidebar: () => void @@ -13,6 +14,7 @@ interface AppState { toggleDarkMode: () => void setDarkMode: (dark: boolean) => void setSearchQuery: (query: string) => void + setMatrixFullScreen: (fullScreen: boolean) => void } export const useAppStore = create()( @@ -22,6 +24,7 @@ export const useAppStore = create()( sidebarOpen: true, darkMode: false, searchQuery: '', + matrixFullScreen: false, // 操作方法 toggleSidebar: () => set((state) => ({ sidebarOpen: !state.sidebarOpen })), @@ -29,12 +32,14 @@ export const useAppStore = create()( toggleDarkMode: () => set((state) => ({ darkMode: !state.darkMode })), setDarkMode: (dark) => set({ darkMode: dark }), setSearchQuery: (query) => set({ searchQuery: query }), + setMatrixFullScreen: (fullScreen) => set({ matrixFullScreen: fullScreen }), }), { name: 'ittoview-app-storage', partialize: (state) => ({ sidebarOpen: state.sidebarOpen, darkMode: state.darkMode, + matrixFullScreen: state.matrixFullScreen, // searchQuery 不持久化到 localStorage,刷新后重置 }), }