feat(矩阵): 添加知识领域和过程组的显示/隐藏功能

feat(详情页): 为ITTO内容添加显示/隐藏控制功能

refactor: 优化状态管理使用localStorage持久化
This commit is contained in:
史悦
2026-02-14 00:42:45 +08:00
parent 033ae6b121
commit 6505f977d9
3 changed files with 439 additions and 103 deletions

View File

@@ -1,17 +1,102 @@
/**
* 49过程矩阵页面
*/
import { useEffect } from 'react'
import { useEffect, useState } from 'react'
import { ProcessMatrix } from '@/components/visualize'
import { Maximize2, Minimize2 } from 'lucide-react'
import { Maximize2, Minimize2, Eye } from 'lucide-react'
import { useAppStore } from '@/stores/useAppStore'
import { clsx } from 'clsx'
import { knowledgeAreas, processGroups } from '@/data'
const STORAGE_KEY = 'ittoview:process-matrix:hidden-items'
interface HiddenIds {
knowledgeAreas: Set<string>
processGroups: Set<string>
}
// 从 localStorage 加载并清洗无效 ID
function loadHiddenIds(): HiddenIds {
try {
const raw = localStorage.getItem(STORAGE_KEY)
if (!raw) return { knowledgeAreas: new Set<string>(), processGroups: new Set<string>() }
const parsed = JSON.parse(raw)
if (typeof parsed !== 'object' || !parsed) {
return { knowledgeAreas: new Set<string>(), processGroups: new Set<string>() }
}
// 清洗无效 ID
const validKaIds = new Set(knowledgeAreas.map(ka => ka.id))
const validPgIds = new Set(processGroups.map(pg => pg.id))
const kaIds = Array.isArray(parsed.knowledgeAreas)
? parsed.knowledgeAreas.filter((id: string) => validKaIds.has(id))
: []
const pgIds = Array.isArray(parsed.processGroups)
? parsed.processGroups.filter((id: string) => validPgIds.has(id))
: []
return {
knowledgeAreas: new Set(kaIds),
processGroups: new Set(pgIds),
}
} catch {
return { knowledgeAreas: new Set<string>(), processGroups: new Set<string>() }
}
}
export function ProcessMatrixPage() {
const isFullScreen = useAppStore((s) => s.matrixFullScreen)
const setMatrixFullScreen = useAppStore((s) => s.setMatrixFullScreen)
const setSidebarOpen = useAppStore((s) => s.setSidebarOpen)
// 显示/隐藏状态管理
const [hiddenIds, setHiddenIds] = useState(() => loadHiddenIds())
const hiddenKnowledgeAreaIds = hiddenIds.knowledgeAreas
const hiddenProcessGroupIds = hiddenIds.processGroups
// 持久化状态
useEffect(() => {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify({
knowledgeAreas: Array.from(hiddenKnowledgeAreaIds),
processGroups: Array.from(hiddenProcessGroupIds),
}))
} catch (error) {
console.warn('无法保存矩阵显示状态:', error)
}
}, [hiddenKnowledgeAreaIds, hiddenProcessGroupIds])
const toggleKnowledgeArea = (id: string) => {
setHiddenIds(prev => {
const next = new Set(prev.knowledgeAreas)
if (next.has(id)) {
next.delete(id)
} else {
next.add(id)
}
return { ...prev, knowledgeAreas: next }
})
}
const toggleProcessGroup = (id: string) => {
setHiddenIds(prev => {
const next = new Set(prev.processGroups)
if (next.has(id)) {
next.delete(id)
} else {
next.add(id)
}
return { ...prev, processGroups: next }
})
}
const showAll = () => {
setHiddenIds({ knowledgeAreas: new Set(), processGroups: new Set() })
}
const hasHidden = hiddenKnowledgeAreaIds.size > 0 || hiddenProcessGroupIds.size > 0
const toggleFullScreen = () => {
if (!isFullScreen) {
setSidebarOpen(false)
@@ -46,20 +131,34 @@ export function ProcessMatrixPage() {
)}
{!isFullScreen && (
<div className="flex justify-between items-end">
<div className="flex justify-between items-end gap-4">
<div>
<h1 className="text-2xl font-bold text-gray-900 dark:text-white">49</h1>
<p className="text-gray-500 dark:text-gray-400 mt-1">
×
</p>
</div>
<button
onClick={toggleFullScreen}
className="flex items-center gap-2 px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors shadow-sm"
>
<Maximize2 className="w-4 h-4" />
</button>
<div className="flex items-center gap-2">
{hasHidden && (
<button
onClick={showAll}
className="flex items-center gap-2 px-3 py-2 text-sm font-medium text-indigo-700 dark:text-indigo-300 bg-indigo-50 dark:bg-indigo-900/30 border border-indigo-200 dark:border-indigo-800 rounded-lg hover:bg-indigo-100 dark:hover:bg-indigo-900/50 transition-colors"
>
<Eye className="w-4 h-4" />
<span className="text-xs opacity-75">
( {hiddenKnowledgeAreaIds.size} / {hiddenProcessGroupIds.size} )
</span>
</button>
)}
<button
onClick={toggleFullScreen}
className="flex items-center gap-2 px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors shadow-sm"
>
<Maximize2 className="w-4 h-4" />
</button>
</div>
</div>
)}
@@ -71,13 +170,27 @@ export function ProcessMatrixPage() {
{isFullScreen && (
<div className="flex justify-between items-center px-4 py-2 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 shrink-0">
<span className="font-medium text-gray-900 dark:text-white">49</span>
<button
onClick={toggleFullScreen}
className="flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50 dark:hover:bg-gray-600 transition-colors"
>
<Minimize2 className="w-4 h-4" />
退
</button>
<div className="flex items-center gap-2">
{hasHidden && (
<button
onClick={showAll}
className="flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-indigo-700 dark:text-indigo-300 bg-indigo-50 dark:bg-indigo-900/30 border border-indigo-200 dark:border-indigo-800 rounded-md hover:bg-indigo-100 dark:hover:bg-indigo-900/50 transition-colors"
>
<Eye className="w-4 h-4" />
<span className="text-xs opacity-75">
({hiddenKnowledgeAreaIds.size} / {hiddenProcessGroupIds.size} )
</span>
</button>
)}
<button
onClick={toggleFullScreen}
className="flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50 dark:hover:bg-gray-600 transition-colors"
>
<Minimize2 className="w-4 h-4" />
退
</button>
</div>
</div>
)}
@@ -85,6 +198,10 @@ export function ProcessMatrixPage() {
<ProcessMatrix
className={clsx(isFullScreen && "h-full w-full overflow-auto no-scrollbar")}
isFullScreen={isFullScreen}
hiddenKnowledgeAreaIds={hiddenKnowledgeAreaIds}
hiddenProcessGroupIds={hiddenProcessGroupIds}
onToggleKnowledgeArea={toggleKnowledgeArea}
onToggleProcessGroup={toggleProcessGroup}
/>
</div>
</div>