diff --git a/src/App.tsx b/src/App.tsx index 487f9b0..df8082d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -17,6 +17,7 @@ import PerformanceDomainPracticePage from './pages/PerformanceDomainPracticePage import KnowledgeAreasTailoringPage from './pages/KnowledgeAreasTailoringPage' import { LearningMapsPage } from './pages/LearningMapsPage' import { ApiDocPage } from './pages/ApiDocPage' +import { IttoCollectionsPage } from './pages/IttoCollectionsPage' function App() { return ( @@ -30,6 +31,7 @@ function App() { } /> } /> } /> + } /> } /> } /> } /> diff --git a/src/pages/IttoCollectionsPage.tsx b/src/pages/IttoCollectionsPage.tsx new file mode 100644 index 0000000..0143a87 --- /dev/null +++ b/src/pages/IttoCollectionsPage.tsx @@ -0,0 +1,197 @@ +import { useMemo, useState } from 'react' +import { motion } from 'framer-motion' +import { FileOutput, FileText, Wrench } from 'lucide-react' +import { + artifactMap, + knowledgeAreas, + processGroups, + processes, + toolMap, + normalizeProcessRef, +} from '@/data' +import type { Process, ProcessRef } from '@/types/itto' + +type ViewKey = 'inputs' | 'tools' | 'outputs' + +type CollectionRow = { + processGroupId: string + processGroupName: string + color: string + items: string[] +} + +type CollectionArea = { + id: string + order: number + name: string + nameEn: string + color: string + rows: CollectionRow[] +} + +const tabs: Array<{ key: ViewKey; label: string; icon: typeof FileText }> = [ + { key: 'inputs', label: '输入', icon: FileText }, + { key: 'tools', label: '工具', icon: Wrench }, + { key: 'outputs', label: '输出', icon: FileOutput }, +] + +const containerVariants = { + hidden: { opacity: 0 }, + visible: { opacity: 1, transition: { staggerChildren: 0.03 } }, +} + +const itemVariants = { + hidden: { opacity: 0, y: 10 }, + visible: { opacity: 1, y: 0 }, +} + +function formatRef(ref: ProcessRef, viewKey: ViewKey) { + const normalized = normalizeProcessRef(ref) + const entity = viewKey === 'tools' ? toolMap.get(normalized.id) : artifactMap.get(normalized.id) + const name = entity?.name ?? normalized.id + const detail = normalized.detail?.map((item) => item.label).filter(Boolean) ?? [] + + if (!detail.length) return name + return `${name}(${detail.join('、')})` +} + +function getRefsByView(process: Process, viewKey: ViewKey) { + if (viewKey === 'inputs') return process.inputs + if (viewKey === 'tools') return process.tools + return process.outputs +} + +function uniqueItems(items: string[]) { + return Array.from(new Set(items)) +} + +function buildCollection(viewKey: ViewKey): CollectionArea[] { + return knowledgeAreas.map((area) => { + const areaProcesses = processes.filter((process) => process.knowledgeAreaId === area.id) + const rows = processGroups.map((group) => { + const groupProcesses = areaProcesses.filter((process) => process.processGroupId === group.id) + const items = uniqueItems( + groupProcesses.flatMap((process) => + getRefsByView(process, viewKey).map((ref) => formatRef(ref, viewKey)) + ) + ) + + return { + processGroupId: group.id, + processGroupName: group.name, + color: group.color, + items, + } + }).filter((row) => row.items.length > 0) + + return { + id: area.id, + order: area.order, + name: area.name, + nameEn: area.nameEn, + color: area.color, + rows, + } + }) +} + +export function IttoCollectionsPage() { + const [activeTab, setActiveTab] = useState('inputs') + const collection = useMemo(() => buildCollection(activeTab), [activeTab]) + + return ( + + + + 输入 · 工具 · 输出 + 按知识领域与过程组汇总 + + + {tabs.map((tab) => { + const Icon = tab.icon + const isActive = activeTab === tab.key + return ( + setActiveTab(tab.key)} + className={`inline-flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition-colors ${ + isActive + ? 'bg-indigo-600 text-white shadow-sm' + : 'text-gray-600 hover:bg-gray-50 dark:text-gray-300 dark:hover:bg-gray-700' + }`} + > + + {tab.label} + + ) + })} + + + + + {collection.map((area) => ( + + + + {area.order} + + + {area.name} + {area.nameEn} + + + + + + + + + 过程组 + + + 对应集合 + + + + + {area.rows.map((row) => ( + + + + {row.processGroupName} + + + + {row.items.join(';')} + + + ))} + + + + + ))} + + + ) +} diff --git a/src/pages/ProcessDetailPage.tsx b/src/pages/ProcessDetailPage.tsx index 81a3d4a..a7bbfeb 100644 --- a/src/pages/ProcessDetailPage.tsx +++ b/src/pages/ProcessDetailPage.tsx @@ -795,7 +795,7 @@ export function ProcessDetailPage() { {showAnswer && practiceMode === 'proficient' && ( - 当前显示:{SECTION_LABELS[currentSection]}分组未完成答案({currentSectionRemainingItems.length} 项) + {SECTION_LABELS[currentSection]}分组未完成答案({currentSectionRemainingItems.length} 项) )} {showAnswer && practiceMode === 'standard' && currentPracticeItem && ( @@ -1021,7 +1021,7 @@ function PracticeList({ {'_'.repeat(item.name.length)} {mode === 'proficient' && isCurrentSection && ( - 待输入 + 待作答 )} )} diff --git a/src/pages/ToolDetailPage.tsx b/src/pages/ToolDetailPage.tsx index 1a3283e..4166fed 100644 --- a/src/pages/ToolDetailPage.tsx +++ b/src/pages/ToolDetailPage.tsx @@ -116,7 +116,7 @@ export function ToolDetailPage() { {usedByProcesses.length === 0 && ( - 暂无使用此工具的过程记录 + 未找到相关过程 )} diff --git a/src/pages/index.ts b/src/pages/index.ts index c4f54c9..fc8a1bb 100644 --- a/src/pages/index.ts +++ b/src/pages/index.ts @@ -11,3 +11,4 @@ export { SettingsPage } from './SettingsPage' export { PerformanceDomainsPage } from './PerformanceDomainsPage' export { LearningMapsPage } from './LearningMapsPage' +export { IttoCollectionsPage } from './IttoCollectionsPage'
按知识领域与过程组汇总
{area.nameEn}