feat(process): 添加5W1H记忆辅助信息并优化页面布局

- 在Process接口中添加5W1H可选字段
- 为所有过程添加5W1H记忆辅助信息
- 优化知识领域、过程组和过程详情页面的紧凑布局
- 在过程详情页添加5W1H记忆卡片展示
- 调整动画效果和间距提升用户体验
This commit is contained in:
史悦
2026-02-03 10:14:24 +08:00
parent f0823fad30
commit 8651747c12
5 changed files with 679 additions and 392 deletions

View File

@@ -10,7 +10,15 @@
"order": 1,
"inputs": ["A002", "A004", "A003", "A005", "A006"],
"tools": ["TT001", "TT002", "TT022", "TT032"],
"outputs": ["A001", "A007"]
"outputs": ["A001", "A007"],
"w5h1": {
"who": "发起人签发PM协助编写",
"what": "编写正式批准项目并授权PM使用组织资源的文件",
"when": "启动过程组,项目最开始",
"where": "组织高层与发起人处",
"why": "正式授权项目存在,建立项目与战略目标的联系",
"how": "专家判断+数据收集+人际关系技能+会议"
}
},
{
"id": "P1.2",
@@ -22,7 +30,15 @@
"order": 2,
"inputs": ["A001", "A076", "A005", "A006"],
"tools": ["TT001", "TT002", "TT022", "TT032"],
"outputs": ["A008"]
"outputs": ["A008"],
"w5h1": {
"who": "项目经理主导,团队参与",
"what": "定义、准备、协调所有子计划并整合为综合项目管理计划",
"when": "规划过程组,章程批准后",
"where": "项目团队内部",
"why": "为项目执行、监控、收尾提供统一指导基准",
"how": "专家判断+数据收集+人际关系技能+会议"
}
},
{
"id": "P1.3",
@@ -34,7 +50,15 @@
"order": 3,
"inputs": ["A008", "A076", "A079", "A005", "A006"],
"tools": ["TT001", "TT033", "TT032"],
"outputs": ["A070", "A067", "A065", "A053", "A078", "A077", "A075"]
"outputs": ["A070", "A067", "A065", "A053", "A078", "A077", "A075"],
"w5h1": {
"who": "项目经理领导,团队执行",
"what": "领导和执行项目管理计划中所规定的工作",
"when": "执行过程组,贯穿项目始终",
"where": "项目执行现场",
"why": "产出可交付成果,实现项目目标",
"how": "专家判断+PMIS项目管理信息系统+会议"
}
},
{
"id": "P1.4",
@@ -46,7 +70,15 @@
"order": 4,
"inputs": ["A008", "A076", "A070", "A005", "A006"],
"tools": ["TT001", "TT110", "TT111", "TT022"],
"outputs": ["A066", "A078", "A075"]
"outputs": ["A066", "A078", "A075"],
"w5h1": {
"who": "项目经理主导,全员参与",
"what": "使用现有知识并生成新知识,以实现项目目标并促进组织学习",
"when": "执行过程组,持续进行",
"where": "组织知识库+项目环境",
"why": "避免重蹈覆辙,促进组织持续改进",
"how": "知识管理+信息管理+人际关系技能"
}
},
{
"id": "P1.5",
@@ -58,7 +90,15 @@
"order": 5,
"inputs": ["A008", "A076", "A068", "A004", "A005", "A006"],
"tools": ["TT001", "TT008", "TT018", "TT032"],
"outputs": ["A069", "A053", "A078", "A077"]
"outputs": ["A069", "A053", "A078", "A077"],
"w5h1": {
"who": "项目经理",
"what": "跟踪、审查和报告整体项目进展,以实现项目管理计划中的绩效目标",
"when": "监控过程组,贯穿项目始终",
"where": "项目管理层面",
"why": "及时发现偏差,采取纠正/预防措施",
"how": "专家判断+数据分析+决策+会议"
}
},
{
"id": "P1.6",
@@ -70,7 +110,15 @@
"order": 6,
"inputs": ["A008", "A076", "A069", "A053", "A005", "A006"],
"tools": ["TT001", "TT108", "TT008", "TT018", "TT032"],
"outputs": ["A079", "A080", "A078", "A077"]
"outputs": ["A079", "A080", "A077"],
"w5h1": {
"who": "项目经理+CCB变更控制委员会",
"what": "审查所有变更请求,批准变更,管理对可交付成果和文档的变更",
"when": "监控过程组,有变更请求时",
"where": "CCB会议/变更控制系统",
"why": "确保只有经批准的变更才被实施,维护基准完整性",
"how": "专家判断+变更控制工具+数据分析+决策+会议"
}
},
{
"id": "P1.7",
@@ -82,7 +130,15 @@
"order": 7,
"inputs": ["A001", "A008", "A076", "A072", "A005", "A006"],
"tools": ["TT001", "TT008", "TT032"],
"outputs": ["A078", "A073", "A074", "A075"]
"outputs": ["A078", "A073", "A074", "A075"],
"w5h1": {
"who": "项目经理+发起人确认",
"what": "终结项目、阶段或合同的所有活动",
"when": "收尾过程组,项目/阶段结束时",
"where": "与客户/发起人交接处",
"why": "正式结束项目,释放资源,归档文档,总结经验教训",
"how": "专家判断+数据分析+会议"
}
},
{
"id": "P2.1",
@@ -94,7 +150,15 @@
"order": 1,
"inputs": ["A001", "A008", "A005", "A006"],
"tools": ["TT001", "TT008", "TT032"],
"outputs": ["A009", "A010"]
"outputs": ["A009", "A010"],
"w5h1": {
"who": "项目经理+范围管理团队",
"what": "创建范围管理计划,记录如何定义、确认和控制项目范围",
"when": "规划过程组早期",
"where": "项目规划环境",
"why": "为后续范围管理活动提供指导和方向",
"how": "专家判断+数据分析+会议"
}
},
{
"id": "P2.2",
@@ -106,7 +170,15 @@
"order": 2,
"inputs": ["A001", "A008", "A076", "A004", "A005", "A006"],
"tools": ["TT001", "TT002", "TT008", "TT018", "TT034", "TT022", "TT115"],
"outputs": ["A028", "A029"]
"outputs": ["A028", "A029"],
"w5h1": {
"who": "项目经理+业务分析师+相关方",
"what": "为实现目标而确定、记录并管理相关方的需要和需求",
"when": "规划过程组,定义范围前",
"where": "与相关方访谈/研讨会/焦点小组",
"why": "确保项目满足相关方期望,为范围定义提供依据",
"how": "专家判断+数据收集+数据分析+决策+人际关系技能+系统交互图+原型法"
}
},
{
"id": "P2.3",
@@ -118,7 +190,15 @@
"order": 3,
"inputs": ["A001", "A008", "A076", "A005", "A006"],
"tools": ["TT001", "TT008", "TT018", "TT022", "TT114"],
"outputs": ["A027", "A077"]
"outputs": ["A027", "A077"],
"w5h1": {
"who": "项目经理+团队+关键相关方",
"what": "制定项目和产品的详细描述",
"when": "规划过程组,收集需求后",
"where": "项目规划环境",
"why": "明确项目边界,区分包含和排除的内容",
"how": "专家判断+数据分析+决策+人际关系技能+产品分析"
}
},
{
"id": "P2.4",
@@ -130,7 +210,15 @@
"order": 4,
"inputs": ["A008", "A076", "A005", "A006"],
"tools": ["TT001", "TT059"],
"outputs": ["A021", "A077"]
"outputs": ["A021", "A077"],
"w5h1": {
"who": "项目经理+团队成员",
"what": "把项目可交付成果和项目工作分解成较小、更易于管理的组件",
"when": "规划过程组,定义范围后",
"where": "项目规划环境",
"why": "便于估算、管理和控制,明确工作包",
"how": "专家判断+分解技术"
}
},
{
"id": "P2.5",
@@ -142,7 +230,15 @@
"order": 5,
"inputs": ["A008", "A076", "A071", "A067", "A005", "A006"],
"tools": ["TT065", "TT018"],
"outputs": ["A072", "A068", "A053", "A077"]
"outputs": ["A072", "A068", "A053", "A077"],
"w5h1": {
"who": "项目经理+客户/发起人",
"what": "正式验收已完成的项目可交付成果",
"when": "监控过程组,可交付成果完成后",
"where": "与客户验收会议",
"why": "获得客户正式认可,确保可交付成果满足需求",
"how": "检查+决策"
}
},
{
"id": "P2.6",
@@ -154,7 +250,15 @@
"order": 6,
"inputs": ["A008", "A076", "A067", "A005", "A006"],
"tools": ["TT008"],
"outputs": ["A068", "A053", "A078", "A077"]
"outputs": ["A068", "A053", "A078", "A077"],
"w5h1": {
"who": "项目经理",
"what": "监督项目和产品的范围状态,管理范围基准变更",
"when": "监控过程组,贯穿项目始终",
"where": "项目管理层面",
"why": "防止范围蔓延,确保只做批准的工作",
"how": "数据分析(偏差分析+趋势分析)"
}
},
{
"id": "P3.1",
@@ -166,7 +270,15 @@
"order": 1,
"inputs": ["A001", "A008", "A005", "A006"],
"tools": ["TT001", "TT008", "TT032"],
"outputs": ["A011"]
"outputs": ["A011"],
"w5h1": {
"who": "项目经理+进度管理团队",
"what": "制定进度规划、编制、管理、执行和控制的政策、程序和文档",
"when": "规划过程组早期",
"where": "项目规划环境",
"why": "为后续进度管理活动提供指导和方向",
"how": "专家判断+数据分析+会议"
}
},
{
"id": "P3.2",
@@ -178,7 +290,15 @@
"order": 2,
"inputs": ["A008", "A005", "A006"],
"tools": ["TT001", "TT059", "TT060", "TT032"],
"outputs": ["A032", "A033", "A034", "A053", "A078"]
"outputs": ["A032", "A033", "A034", "A053", "A078"],
"w5h1": {
"who": "项目经理+团队成员",
"what": "识别和记录为完成项目可交付成果而需采取的具体行动",
"when": "规划过程组WBS创建后",
"where": "项目规划环境",
"why": "将工作包分解为可调度、可估算、可执行的活动",
"how": "专家判断+分解+滚动式规划+会议"
}
},
{
"id": "P3.3",
@@ -190,7 +310,15 @@
"order": 3,
"inputs": ["A008", "A076", "A005", "A006"],
"tools": ["TT061", "TT062", "TT050", "TT033"],
"outputs": ["A035", "A077"]
"outputs": ["A035", "A077"],
"w5h1": {
"who": "项目经理+进度规划人员",
"what": "识别和记录项目活动之间的逻辑关系",
"when": "规划过程组,定义活动后",
"where": "项目规划环境",
"why": "确定活动执行的合理顺序,为进度计划提供依据",
"how": "紧前关系绘图法PDM+确定和整合依赖关系+提前量与滞后量+PMIS"
}
},
{
"id": "P3.4",
@@ -202,7 +330,15 @@
"order": 4,
"inputs": ["A008", "A076", "A005", "A006"],
"tools": ["TT001", "TT055", "TT056", "TT057", "TT058", "TT018", "TT032"],
"outputs": ["A038", "A039", "A077"]
"outputs": ["A038", "A039", "A077"],
"w5h1": {
"who": "项目经理+团队成员+专家",
"what": "根据资源估算结果,估算完成各活动所需的工作时段数",
"when": "规划过程组,排列顺序后",
"where": "项目规划环境",
"why": "为制定进度计划提供时间依据",
"how": "专家判断+类比估算+参数估算+三点估算+自下而上估算+决策+会议"
}
},
{
"id": "P3.5",
@@ -214,7 +350,15 @@
"order": 5,
"inputs": ["A008", "A076", "A004", "A005", "A006"],
"tools": ["TT045", "TT046", "TT047", "TT008", "TT050", "TT051", "TT033", "TT063"],
"outputs": ["A022", "A040", "A041", "A042", "A053", "A078", "A077"]
"outputs": ["A022", "A040", "A041", "A042", "A053", "A078", "A077"],
"w5h1": {
"who": "项目经理+进度规划人员",
"what": "分析活动顺序、持续时间、资源需求和约束,创建进度模型",
"when": "规划过程组,估算持续时间后",
"where": "项目规划环境",
"why": "确定项目活动的计划开始和完成日期",
"how": "进度网络分析+关键路径法+资源优化+数据分析+提前量滞后量+进度压缩+PMIS+敏捷发布规划"
}
},
{
"id": "P3.6",
@@ -226,7 +370,15 @@
"order": 6,
"inputs": ["A008", "A076", "A067", "A005", "A006"],
"tools": ["TT008", "TT046", "TT047", "TT050", "TT051", "TT033"],
"outputs": ["A068", "A087", "A053", "A078", "A077"]
"outputs": ["A068", "A087", "A053", "A078", "A077"],
"w5h1": {
"who": "项目经理",
"what": "监督项目状态,以更新项目进度和管理进度基准变更",
"when": "监控过程组,贯穿项目始终",
"where": "项目管理层面",
"why": "确保项目按时完成,及时发现进度偏差",
"how": "数据分析(挣值分析+迭代燃尽图+绩效审查+趋势分析+偏差分析+假设情景分析)+关键路径法+资源优化+提前量滞后量+进度压缩+PMIS"
}
},
{
"id": "P4.1",
@@ -238,7 +390,15 @@
"order": 1,
"inputs": ["A001", "A008", "A005", "A006"],
"tools": ["TT001", "TT008", "TT032"],
"outputs": ["A012"]
"outputs": ["A012"],
"w5h1": {
"who": "项目经理+成本管理团队",
"what": "确定如何估算、预算、管理、监督和控制项目成本",
"when": "规划过程组早期",
"where": "项目规划环境",
"why": "为后续成本管理活动提供指导和方向",
"how": "专家判断+数据分析+会议"
}
},
{
"id": "P4.2",
@@ -250,7 +410,15 @@
"order": 2,
"inputs": ["A008", "A076", "A005", "A006"],
"tools": ["TT001", "TT055", "TT056", "TT057", "TT058", "TT008", "TT018", "TT033"],
"outputs": ["A043", "A039", "A077"]
"outputs": ["A043", "A039", "A077"],
"w5h1": {
"who": "项目经理+成本估算人员+专家",
"what": "对完成项目活动所需资源成本进行近似估算",
"when": "规划过程组,定义活动后",
"where": "项目规划环境",
"why": "为制定预算提供成本依据",
"how": "专家判断+类比估算+参数估算+自下而上估算+三点估算+数据分析+决策+PMIS"
}
},
{
"id": "P4.3",
@@ -262,7 +430,15 @@
"order": 3,
"inputs": ["A008", "A076", "A004", "A005", "A006"],
"tools": ["TT001", "TT010", "TT008", "TT016", "TT044"],
"outputs": ["A023", "A044", "A077"]
"outputs": ["A023", "A044", "A077"],
"w5h1": {
"who": "项目经理+财务人员",
"what": "汇总所有单个活动或工作包的估算成本,建立经批准的成本基准",
"when": "规划过程组,估算成本后",
"where": "项目规划环境",
"why": "确定项目授权的成本基准,用于监控绩效",
"how": "专家判断+成本汇总+数据分析(储备分析)+历史信息审查+资金限制平衡+融资"
}
},
{
"id": "P4.4",
@@ -274,9 +450,16 @@
"order": 4,
"inputs": ["A008", "A076", "A044", "A067", "A005", "A006"],
"tools": ["TT001", "TT008", "TT011", "TT013", "TT014", "TT016", "TT033"],
"outputs": ["A068", "A086", "A053", "A078", "A077"]
"outputs": ["A068", "A086", "A053", "A078", "A077"],
"w5h1": {
"who": "项目经理",
"what": "监督项目状态,以更新项目成本和管理成本基准变更",
"when": "监控过程组,贯穿项目始终",
"where": "项目管理层面",
"why": "确保项目在预算内完成,及时发现成本偏差",
"how": "专家判断+数据分析(挣值分析EVM+偏差分析+趋势分析+储备分析)+完工尚需绩效指数TCPI+PMIS"
}
,
},
{
"id": "P5.1",
"code": "5.1",
@@ -287,7 +470,15 @@
"order": 1,
"inputs": ["A001", "A008", "A076", "A005", "A006"],
"tools": ["TT001", "TT002", "TT008", "TT018", "TT034", "TT066", "TT064", "TT032"],
"outputs": ["A013", "A045", "A078", "A077"]
"outputs": ["A013", "A045", "A078", "A077"],
"w5h1": {
"who": "项目经理+质量管理团队",
"what": "识别项目及其可交付成果的质量要求和标准,并记录如何证明符合质量要求",
"when": "规划过程组,与其他规划并行",
"where": "项目规划环境",
"why": "为整个项目管理质量提供指南和方向",
"how": "专家判断+数据收集+数据分析+决策+数据表现(流程图/逻辑数据模型/矩阵图/思维导图)+测试与检查规划+会议"
}
},
{
"id": "P5.2",
@@ -299,7 +490,15 @@
"order": 2,
"inputs": ["A008", "A076", "A005", "A006"],
"tools": ["TT002", "TT008", "TT018", "TT034", "TT067", "TT068", "TT069", "TT070"],
"outputs": ["A046", "A047", "A053", "A078", "A077"]
"outputs": ["A046", "A047", "A053", "A078", "A077"],
"w5h1": {
"who": "项目经理+质量保证人员",
"what": "把组织的质量政策用于项目,将质量管理计划转化为可执行的质量活动",
"when": "执行过程组,贯穿项目始终",
"where": "项目执行环境",
"why": "提高实现质量目标的可能性,识别无效过程和导致质量低劣的原因",
"how": "数据收集+数据分析+决策+数据表现+审计+面向X的设计+问题解决+质量改进方法"
}
},
{
"id": "P5.3",
@@ -311,7 +510,15 @@
"order": 3,
"inputs": ["A008", "A076", "A079", "A070", "A067", "A005", "A006"],
"tools": ["TT002", "TT008", "TT065", "TT066", "TT034"],
"outputs": ["A084", "A071", "A068", "A053", "A078", "A077"]
"outputs": ["A084", "A071", "A068", "A053", "A078", "A077"],
"w5h1": {
"who": "项目经理+质量控制人员",
"what": "监督和记录质量管理活动执行结果,以便评估绩效并确保项目输出完整、正确",
"when": "监控过程组,可交付成果产出时",
"where": "项目执行和测试环境",
"why": "核实可交付成果和工作满足主要相关方的质量要求",
"how": "数据收集(核对单/核查表/统计抽样/问卷调查)+数据分析(绩效审查/根本原因分析)+检查+测试/产品评估+数据表现(因果图/控制图/直方图/散点图)"
}
},
{
"id": "P6.1",
@@ -323,7 +530,15 @@
"order": 1,
"inputs": ["A001", "A008", "A076", "A005", "A006"],
"tools": ["TT001", "TT034", "TT112", "TT032"],
"outputs": ["A014", "A048", "A077"]
"outputs": ["A014", "A048", "A077"],
"w5h1": {
"who": "项目经理+资源管理团队",
"what": "定义如何估算、获取、管理和使用团队以及实物资源",
"when": "规划过程组早期",
"where": "项目规划环境",
"why": "根据项目类型和复杂程度确定适用的资源管理方法",
"how": "专家判断+数据表现(层级型/责任分配矩阵RAM/文本型)+组织理论+会议"
}
},
{
"id": "P6.2",
@@ -335,7 +550,15 @@
"order": 2,
"inputs": ["A008", "A076", "A005", "A006"],
"tools": ["TT001", "TT057", "TT055", "TT056", "TT008", "TT033", "TT032"],
"outputs": ["A082", "A039", "A037", "A077"]
"outputs": ["A082", "A039", "A037", "A077"],
"w5h1": {
"who": "项目经理+团队成员",
"what": "估算执行项目所需的团队资源、材料、设备和用品的类型和数量",
"when": "规划过程组,定义活动后",
"where": "项目规划环境",
"why": "明确完成项目所需的资源种类、数量和特性",
"how": "专家判断+自下而上估算+类比估算+参数估算+数据分析+PMIS+会议"
}
},
{
"id": "P6.3",
@@ -347,7 +570,15 @@
"order": 3,
"inputs": ["A008", "A076", "A005", "A006"],
"tools": ["TT018", "TT022", "TT107", "TT102"],
"outputs": ["A051", "A050", "A049", "A053", "A078", "A077", "A005"]
"outputs": ["A051", "A050", "A049", "A053", "A078", "A077", "A005"],
"w5h1": {
"who": "项目经理+职能经理+HR",
"what": "获取项目所需的团队成员、设施、设备、材料、用品和其他资源",
"when": "执行过程组,需要资源时",
"where": "组织内部和外部",
"why": "确保项目有执行工作所需的资源",
"how": "决策(多标准决策分析)+人际关系与团队技能(谈判)+预分派+虚拟团队"
}
},
{
"id": "P6.4",
@@ -359,7 +590,15 @@
"order": 4,
"inputs": ["A008", "A076", "A005", "A006"],
"tools": ["TT101", "TT102", "TT086", "TT022", "TT103", "TT104", "TT105", "TT032"],
"outputs": ["A052", "A053", "A078", "A077", "A005"]
"outputs": ["A052", "A053", "A078", "A077", "A005"],
"w5h1": {
"who": "项目经理",
"what": "提高工作能力,促进团队成员互动,改善团队整体氛围",
"when": "执行过程组,团队组建后持续进行",
"where": "项目团队环境",
"why": "提升团队协作和项目绩效,激励团队",
"how": "集中办公+虚拟团队+沟通技术+人际关系与团队技能+认可与奖励+培训+个人和团队评估+会议"
}
},
{
"id": "P6.5",
@@ -371,7 +610,15 @@
"order": 5,
"inputs": ["A008", "A076", "A052", "A067", "A005", "A006"],
"tools": ["TT022", "TT033"],
"outputs": ["A053", "A078", "A077", "A005"]
"outputs": ["A053", "A078", "A077", "A005"],
"w5h1": {
"who": "项目经理",
"what": "跟踪团队成员工作表现,提供反馈,解决问题并管理团队变更",
"when": "执行过程组,贯穿项目始终",
"where": "项目团队环境",
"why": "优化项目绩效,解决冲突,管理团队变更",
"how": "人际关系与团队技能(冲突管理/决策/情商/影响力/领导力)+PMIS"
}
},
{
"id": "P6.6",
@@ -383,7 +630,15 @@
"order": 6,
"inputs": ["A008", "A076", "A067", "A004", "A005", "A006"],
"tools": ["TT008", "TT069", "TT022", "TT033"],
"outputs": ["A068", "A053", "A078", "A077"]
"outputs": ["A068", "A053", "A078", "A077"],
"w5h1": {
"who": "项目经理",
"what": "确保按计划为项目分配实物资源,并监督资源实际使用情况",
"when": "监控过程组,贯穿项目始终",
"where": "项目管理层面",
"why": "确保所分配资源适时适地可用,资源在不需要时被释放",
"how": "数据分析(备选方案分析/成本效益分析/绩效审查/趋势分析)+问题解决+人际关系与团队技能+PMIS"
}
},
{
"id": "P7.1",
@@ -395,7 +650,15 @@
"order": 1,
"inputs": ["A001", "A008", "A076", "A005", "A006"],
"tools": ["TT001", "TT085", "TT086", "TT087", "TT008", "TT022", "TT034", "TT032"],
"outputs": ["A015", "A078", "A077"]
"outputs": ["A015", "A078", "A077"],
"w5h1": {
"who": "项目经理+沟通专家",
"what": "基于相关方的信息需求和可用的组织资产,制定项目沟通的恰当方法和计划",
"when": "规划过程组早期",
"where": "项目规划环境",
"why": "及时向相关方提供相关信息,引导相关方有效参与项目",
"how": "专家判断+沟通需求分析+沟通技术+沟通模型+沟通方法+人际关系与团队技能+数据表现+会议"
}
},
{
"id": "P7.2",
@@ -407,7 +670,15 @@
"order": 2,
"inputs": ["A008", "A076", "A069", "A005", "A006"],
"tools": ["TT086", "TT085", "TT088", "TT033", "TT090", "TT032"],
"outputs": ["A054", "A078", "A077", "A075"]
"outputs": ["A054", "A078", "A077", "A075"],
"w5h1": {
"who": "项目经理+团队成员",
"what": "确保项目信息及时且恰当地收集、生成、发布、存储、检索、管理、监督和最终处置",
"when": "执行过程组,贯穿项目始终",
"where": "项目沟通渠道",
"why": "促进项目团队与相关方之间的有效信息流动",
"how": "沟通技术+沟通方法+沟通技能+PMIS+项目报告+人际关系与团队技能+会议"
}
},
{
"id": "P7.3",
@@ -419,7 +690,15 @@
"order": 3,
"inputs": ["A008", "A076", "A067", "A005", "A006"],
"tools": ["TT001", "TT033", "TT022", "TT032"],
"outputs": ["A068", "A053", "A078", "A077"]
"outputs": ["A068", "A053", "A078", "A077"],
"w5h1": {
"who": "项目经理",
"what": "确保满足项目及其相关方的信息需求",
"when": "监控过程组,贯穿项目始终",
"where": "项目管理层面",
"why": "按沟通管理计划和相关方参与计划的要求优化信息传递流程",
"how": "专家判断+PMIS+数据分析+人际关系与团队技能+会议"
}
},
{
"id": "P8.1",
@@ -431,7 +710,15 @@
"order": 1,
"inputs": ["A001", "A008", "A076", "A005", "A006"],
"tools": ["TT001", "TT008", "TT032"],
"outputs": ["A016"]
"outputs": ["A016"],
"w5h1": {
"who": "PM主导风险管理团队参与",
"what": "定义如何实施项目风险管理活动的过程",
"when": "规划过程组,项目早期",
"where": "项目规划会议中",
"why": "确保风险管理的程度、类型和可见度与风险及项目重要性相匹配",
"how": "专家判断+数据分析+会议"
}
},
{
"id": "P8.2",
@@ -443,7 +730,15 @@
"order": 2,
"inputs": ["A008", "A076", "A004", "A057", "A005", "A006"],
"tools": ["TT001", "TT002", "TT008", "TT022", "TT120", "TT032"],
"outputs": ["A055", "A056", "A077"]
"outputs": ["A055", "A056", "A077"],
"w5h1": {
"who": "PM主导全体团队及相关方参与",
"what": "识别单个项目风险及整体项目风险来源,并记录风险特征",
"when": "规划过程组,贯穿整个项目",
"where": "风险识别研讨会、头脑风暴会议",
"why": "使团队能够预测已知风险,为后续分析和应对奠定基础",
"how": "专家判断+数据收集(头脑风暴/核对单/访谈)+数据分析+人际关系技能+提示清单"
}
},
{
"id": "P8.3",
@@ -455,7 +750,15 @@
"order": 3,
"inputs": ["A008", "A076", "A005", "A006"],
"tools": ["TT001", "TT002", "TT008", "TT022", "TT071", "TT044", "TT072", "TT034", "TT032"],
"outputs": ["A077"]
"outputs": ["A077"],
"w5h1": {
"who": "PM主导风险分析人员参与",
"what": "通过评估单个项目风险发生的概率和影响以及其他特征,对风险进行优先级排序",
"when": "规划过程组,识别风险后",
"where": "项目规划会议中",
"why": "聚焦高优先级风险,优化资源分配,为后续分析奠定基础",
"how": "专家判断+数据收集+数据分析(概率影响矩阵)+人际关系技能+风险分类+会议"
}
},
{
"id": "P8.4",
@@ -467,7 +770,15 @@
"order": 4,
"inputs": ["A008", "A076", "A005", "A006"],
"tools": ["TT001", "TT002", "TT022", "TT034", "TT075", "TT079", "TT080", "TT077"],
"outputs": ["A077"]
"outputs": ["A077"],
"w5h1": {
"who": "PM主导风险分析专家参与",
"what": "就已识别的单个项目风险和其他不确定性来源对整体项目目标的综合影响进行定量分析",
"when": "规划过程组,定性分析后(可选过程)",
"where": "项目规划会议中",
"why": "为决策提供量化的风险信息依据",
"how": "专家判断+数据收集+人际关系技能+不确定性表现方式+数据分析(模拟/敏感性/决策树/影响图)"
}
},
{
"id": "P8.5",
@@ -479,7 +790,15 @@
"order": 5,
"inputs": ["A008", "A076", "A005", "A006"],
"tools": ["TT001", "TT002", "TT022", "TT081", "TT082", "TT083", "TT084", "TT008", "TT018"],
"outputs": ["A053", "A078", "A077"]
"outputs": ["A053", "A078", "A077"],
"w5h1": {
"who": "PM主导风险责任人参与",
"what": "为处理整体项目风险敞口以及应对单个项目风险而制定可选方案、选择应对策略并商定应对行动",
"when": "规划过程组,风险分析后",
"where": "项目规划会议中",
"why": "降低威胁的概率和影响,提高机会的概率和影响",
"how": "专家判断+数据收集+人际关系技能+威胁应对策略+机会应对策略+应急应对策略+整体风险应对策略+数据分析+决策"
}
},
{
"id": "P8.6",
@@ -491,7 +810,15 @@
"order": 6,
"inputs": ["A008", "A076", "A005", "A006"],
"tools": ["TT001", "TT022", "TT033"],
"outputs": ["A053", "A077"]
"outputs": ["A053", "A077"],
"w5h1": {
"who": "PM主导风险责任人执行",
"what": "执行商定的风险应对计划",
"when": "执行过程组,风险触发或按计划执行时",
"where": "项目执行环境中",
"why": "确保风险应对措施按计划得到执行,最大限度降低威胁、最大限度利用机会",
"how": "专家判断+人际关系技能+项目管理信息系统"
}
},
{
"id": "P8.7",
@@ -503,7 +830,15 @@
"order": 7,
"inputs": ["A008", "A076", "A067", "A069", "A005", "A006"],
"tools": ["TT008", "TT067", "TT032"],
"outputs": ["A068", "A053", "A078", "A077", "A075"]
"outputs": ["A068", "A053", "A078", "A077", "A075"],
"w5h1": {
"who": "PM主导风险责任人参与",
"what": "监督商定的风险应对计划的实施、跟踪已识别风险、识别和分析新风险,以及评估风险管理有效性",
"when": "监控过程组,贯穿整个项目",
"where": "项目管理层面、风险审查会议",
"why": "确保风险管理持续有效,使项目决策基于当前的风险敞口信息",
"how": "数据分析(技术绩效分析/储备分析)+审计+会议"
}
},
{
"id": "P9.1",
@@ -515,7 +850,15 @@
"order": 1,
"inputs": ["A001", "A008", "A076", "A005", "A006"],
"tools": ["TT001", "TT002", "TT092", "TT008", "TT032"],
"outputs": ["A017", "A091", "A059", "A058", "A060", "A061", "A062", "A053", "A077", "A075"]
"outputs": ["A017", "A091", "A059", "A058", "A060", "A061", "A062", "A053", "A077", "A075"],
"w5h1": {
"who": "PM主导采购专家参与",
"what": "记录项目采购决策、明确采购方法及识别潜在卖方",
"when": "规划过程组,项目早期",
"where": "项目规划会议中",
"why": "确定是否从外部获取货物和服务,以及获取什么、如何获取、获取多少、何时获取",
"how": "专家判断+数据收集+数据分析(自制或外购分析)+供方选择分析+会议"
}
},
{
"id": "P9.2",
@@ -527,7 +870,15 @@
"order": 2,
"inputs": ["A008", "A076", "A057", "A081", "A005", "A006"],
"tools": ["TT001", "TT093", "TT008", "TT022", "TT094"],
"outputs": ["A063", "A004", "A053", "A078", "A077", "A075"]
"outputs": ["A063", "A004", "A053", "A078", "A077", "A075"],
"w5h1": {
"who": "PM主导采购人员执行",
"what": "获取卖方应答、选择卖方并授予合同",
"when": "执行过程组,需要外部资源时",
"where": "与潜在卖方交互的场合",
"why": "选择合格的卖方并签订法律协议以交付工作",
"how": "专家判断+广告+投标人会议+数据分析+人际关系技能(谈判)"
}
},
{
"id": "P9.3",
@@ -539,7 +890,15 @@
"order": 3,
"inputs": ["A008", "A076", "A057", "A004", "A079", "A067", "A005", "A006"],
"tools": ["TT001", "TT095", "TT008", "TT065", "TT067"],
"outputs": ["A088", "A068", "A057", "A053", "A078", "A077", "A075"]
"outputs": ["A088", "A068", "A057", "A053", "A078", "A077", "A075"],
"w5h1": {
"who": "PM主导合同管理员参与",
"what": "管理采购关系、监督合同绩效、实施必要的变更和纠偏,以及关闭合同",
"when": "监控过程组,合同执行期间",
"where": "与卖方协作的场合",
"why": "确保买卖双方履行合同义务,保护买方的合法权益",
"how": "专家判断+索赔管理+数据分析+检查+审计"
}
},
{
"id": "P10.1",
@@ -551,7 +910,15 @@
"order": 1,
"inputs": ["A001", "A008", "A076", "A004", "A005", "A006"],
"tools": ["TT001", "TT002", "TT008", "TT034", "TT032"],
"outputs": ["A064", "A053", "A078", "A077"]
"outputs": ["A064", "A053", "A078", "A077"],
"w5h1": {
"who": "PM主导发起人及团队参与",
"what": "定期识别项目相关方,分析和记录他们的利益、参与度、相互依赖性、影响力和对项目成功的潜在影响",
"when": "启动过程组,贯穿整个项目",
"where": "组织内外部环境",
"why": "使PM能够确定每个相关方的适当关注点建立相关方参与策略的基础",
"how": "专家判断+数据收集(问卷/头脑风暴)+数据分析(相关方分析/文件分析)+数据表现(相关方映射/权力利益方格)+会议"
}
},
{
"id": "P10.2",
@@ -563,7 +930,15 @@
"order": 2,
"inputs": ["A001", "A008", "A076", "A004", "A005", "A006"],
"tools": ["TT001", "TT002", "TT018", "TT034", "TT032"],
"outputs": ["A018"]
"outputs": ["A018"],
"w5h1": {
"who": "PM主导",
"what": "根据相关方的需求、期望、利益和对项目的潜在影响,制定项目相关方参与项目决策和执行的方法",
"when": "规划过程组,识别相关方后",
"where": "项目规划会议中",
"why": "提供与相关方进行有效互动的可行计划,有效调动相关方支持项目",
"how": "专家判断+数据收集+数据分析(假设和制约因素分析/根本原因分析)+决策+数据表现(思维导图/相关方参与度评估矩阵)+会议"
}
},
{
"id": "P10.3",
@@ -575,7 +950,15 @@
"order": 3,
"inputs": ["A008", "A076", "A005", "A006"],
"tools": ["TT001", "TT088", "TT022", "TT100", "TT032"],
"outputs": ["A053", "A078", "A077"]
"outputs": ["A053", "A078", "A077"],
"w5h1": {
"who": "PM主导团队成员参与",
"what": "与相关方进行沟通和协作以满足其需求和期望、处理问题,并促进相关方合理参与",
"when": "执行过程组,贯穿整个项目",
"where": "与相关方交互的各种场合",
"why": "提高相关方支持度,降低阻力,显著提高项目成功的机会",
"how": "专家判断+沟通技能+人际关系技能(冲突管理/文化意识/谈判/观察/政治意识)+基本规则+会议"
}
},
{
"id": "P10.4",
@@ -587,7 +970,15 @@
"order": 4,
"inputs": ["A008", "A076", "A067", "A005", "A006"],
"tools": ["TT008", "TT018", "TT034", "TT088", "TT032"],
"outputs": ["A068", "A053", "A078", "A077"]
"outputs": ["A068", "A053", "A078", "A077"],
"w5h1": {
"who": "PM主导",
"what": "监督项目相关方关系,并通过修订参与策略和计划来引导相关方合理参与项目",
"when": "监控过程组,贯穿整个项目",
"where": "项目管理层面、相关方审查会议",
"why": "随着项目进展和环境变化,维持并提升相关方参与活动的效率和效果",
"how": "数据分析(备选方案分析/根本原因分析/相关方分析)+决策+数据表现(相关方参与度评估矩阵)+沟通技能+人际关系技能+会议"
}
}
]
}

View File

@@ -5,14 +5,11 @@ import { knowledgeAreas, processesByKnowledgeArea, knowledgeAreaMap, processGrou
const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: { staggerChildren: 0.05 },
},
visible: { opacity: 1, transition: { staggerChildren: 0.03 } },
}
const itemVariants = {
hidden: { opacity: 0, y: 20 },
hidden: { opacity: 0, y: 10 },
visible: { opacity: 1, y: 0 },
}
@@ -22,106 +19,71 @@ export function KnowledgeAreasPage() {
const processes = id ? processesByKnowledgeArea.get(id) || [] : []
if (selectedKA) {
// 显示知识领域详情
return (
<div className="space-y-6">
<div className="space-y-4">
{/* 面包屑 */}
<nav className="flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400">
<Link to="/knowledge-areas" className="hover:text-indigo-600 dark:hover:text-indigo-400">
</Link>
<Link to="/knowledge-areas" className="hover:text-indigo-600 dark:hover:text-indigo-400"></Link>
<span>/</span>
<span className="text-gray-900 dark:text-white">{selectedKA.name}</span>
</nav>
{/* 知识领域标题 */}
{/* 知识领域标题 - 紧凑版 */}
<motion.div
initial={{ opacity: 0, y: -20 }}
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
className="rounded-xl p-6"
className="rounded-xl p-4"
style={{ backgroundColor: `${selectedKA.color}15` }}
>
<div className="flex items-center gap-4">
<div className="flex items-center gap-3">
<div
className="flex h-14 w-14 items-center justify-center rounded-xl text-white font-bold text-xl"
className="flex h-12 w-12 items-center justify-center rounded-lg text-white font-bold text-lg"
style={{ backgroundColor: selectedKA.color }}
>
{selectedKA.order}
</div>
<div>
<h1 className="text-2xl font-bold text-gray-900 dark:text-white">
{selectedKA.name}
</h1>
<p className="text-gray-500 dark:text-gray-400">{selectedKA.nameEn}</p>
<div className="flex-1">
<h1 className="text-xl font-bold text-gray-900 dark:text-white">{selectedKA.name}</h1>
<p className="text-sm text-gray-500 dark:text-gray-400">{selectedKA.nameEn}</p>
</div>
<div className="text-right">
<div className="text-2xl font-bold text-gray-900 dark:text-white">{processes.length}</div>
<div className="text-xs text-gray-500"></div>
</div>
</div>
<p className="mt-4 text-gray-600 dark:text-gray-300">{selectedKA.description}</p>
<p className="mt-2 text-sm text-gray-600 dark:text-gray-300">{selectedKA.description}</p>
</motion.div>
{/* 过程列表 */}
<motion.div
variants={containerVariants}
initial="hidden"
animate="visible"
className="space-y-4"
>
<h2 className="text-lg font-semibold text-gray-900 dark:text-white">
{processes.length}
</h2>
{/* 过程列表 - 紧凑版 */}
<motion.div variants={containerVariants} initial="hidden" animate="visible" className="space-y-2">
{processes.map((process) => {
const pg = processGroupMap.get(process.processGroupId)
return (
<motion.div key={process.id} variants={itemVariants}>
<Link
to={`/process/${process.id}`}
className="group block bg-white dark:bg-gray-800 rounded-xl p-5 shadow-sm border border-gray-100 dark:border-gray-700 hover:shadow-md hover:border-gray-200 dark:hover:border-gray-600 transition-all"
className="group flex items-center gap-3 bg-white dark:bg-gray-800 rounded-lg p-3 shadow-sm border border-gray-100 dark:border-gray-700 hover:shadow-md hover:border-gray-200 dark:hover:border-gray-600 transition-all"
>
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<div
className="flex h-10 w-10 items-center justify-center rounded-lg text-white font-medium"
className="flex h-9 w-9 items-center justify-center rounded-lg text-white font-medium text-sm shrink-0"
style={{ backgroundColor: selectedKA.color }}
>
{process.code}
</div>
<div>
<h3 className="font-semibold text-gray-900 dark:text-white">
{process.name}
</h3>
<p className="text-sm text-gray-500 dark:text-gray-400">
{process.nameEn}
</p>
<div className="flex-1 min-w-0">
<h3 className="font-medium text-gray-900 dark:text-white text-sm truncate">{process.name}</h3>
<p className="text-xs text-gray-500 dark:text-gray-400 truncate">{process.nameEn}</p>
</div>
</div>
<div className="flex items-center gap-4">
<div className="flex items-center gap-3 text-xs text-gray-500 dark:text-gray-400 shrink-0">
<span className="flex items-center gap-1"><FileText size={12} />{process.inputs.length}</span>
<span className="flex items-center gap-1"><Wrench size={12} />{process.tools.length}</span>
<span className="flex items-center gap-1"><FileOutput size={12} />{process.outputs.length}</span>
{pg && (
<span
className="px-3 py-1 rounded-full text-xs font-medium text-white"
style={{ backgroundColor: pg.color }}
>
<span className="px-2 py-0.5 rounded-full text-xs font-medium text-white hidden sm:inline" style={{ backgroundColor: pg.color }}>
{pg.name}
</span>
)}
<ArrowRight
size={20}
className="text-gray-400 group-hover:text-gray-600 dark:group-hover:text-gray-300 group-hover:translate-x-1 transition-all"
/>
</div>
</div>
{/* ITTO统计 */}
<div className="mt-4 flex items-center gap-6 text-sm text-gray-500 dark:text-gray-400">
<span className="flex items-center gap-1">
<FileText size={14} />
{process.inputs.length}
</span>
<span className="flex items-center gap-1">
<Wrench size={14} />
{process.tools.length}
</span>
<span className="flex items-center gap-1">
<FileOutput size={14} />
{process.outputs.length}
</span>
<ArrowRight size={16} className="text-gray-400 group-hover:text-gray-600 dark:group-hover:text-gray-300 group-hover:translate-x-0.5 transition-all" />
</div>
</Link>
</motion.div>
@@ -132,55 +94,41 @@ export function KnowledgeAreasPage() {
)
}
// 显示知识领域列表
// 显示知识领域列表 - 紧凑版双列
return (
<div className="space-y-6">
<div className="space-y-4">
<div>
<h1 className="text-2xl font-bold text-gray-900 dark:text-white"></h1>
<p className="text-gray-500 dark:text-gray-400 mt-1">
PMBOK第6版定义的10大项目管理知识领域
</p>
<h1 className="text-xl font-bold text-gray-900 dark:text-white"></h1>
<p className="text-sm text-gray-500 dark:text-gray-400">PMBOK第6版定义的10大项目管理知识领域</p>
</div>
<motion.div
variants={containerVariants}
initial="hidden"
animate="visible"
className="grid md:grid-cols-2 gap-4"
className="grid md:grid-cols-2 gap-3"
>
{knowledgeAreas.map((ka) => (
<motion.div key={ka.id} variants={itemVariants}>
<Link
to={`/knowledge-areas/${ka.id}`}
className="group block bg-white dark:bg-gray-800 rounded-xl p-5 shadow-sm border border-gray-100 dark:border-gray-700 hover:shadow-md transition-all"
style={{ borderLeftWidth: 4, borderLeftColor: ka.color }}
className="group flex items-center gap-3 bg-white dark:bg-gray-800 rounded-lg p-3 shadow-sm border border-gray-100 dark:border-gray-700 hover:shadow-md transition-all"
style={{ borderLeftWidth: 3, borderLeftColor: ka.color }}
>
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<div
className="flex h-12 w-12 items-center justify-center rounded-lg text-white font-bold text-lg"
className="flex h-10 w-10 items-center justify-center rounded-lg text-white font-bold shrink-0"
style={{ backgroundColor: ka.color }}
>
{ka.order}
</div>
<div>
<h3 className="font-semibold text-gray-900 dark:text-white">{ka.name}</h3>
<p className="text-sm text-gray-500 dark:text-gray-400">{ka.nameEn}</p>
<div className="flex-1 min-w-0">
<h3 className="font-semibold text-gray-900 dark:text-white text-sm">{ka.name}</h3>
<p className="text-xs text-gray-500 dark:text-gray-400 truncate">{ka.nameEn}</p>
</div>
<div className="flex items-center gap-2 shrink-0">
<span className="text-sm font-medium text-gray-600 dark:text-gray-300">{ka.processCount}</span>
<ArrowRight size={16} className="text-gray-400 group-hover:text-gray-600 dark:group-hover:text-gray-300 group-hover:translate-x-0.5 transition-all" />
</div>
<div className="flex items-center gap-2">
<span className="text-sm text-gray-500 dark:text-gray-400">
{ka.processCount}
</span>
<ArrowRight
size={20}
className="text-gray-400 group-hover:text-gray-600 dark:group-hover:text-gray-300 group-hover:translate-x-1 transition-all"
/>
</div>
</div>
<p className="mt-3 text-sm text-gray-500 dark:text-gray-400 line-clamp-2">
{ka.description}
</p>
</Link>
</motion.div>
))}

View File

@@ -1,27 +1,31 @@
import { useParams, Link, useLocation, useNavigate } from 'react-router-dom'
import { motion } from 'framer-motion'
import { ArrowLeft, ArrowRight, FileText, Wrench, FileOutput, LayoutGrid } from 'lucide-react'
import { ArrowLeft, ArrowRight, FileText, Wrench, FileOutput, LayoutGrid, User, Target, Clock, MapPin, HelpCircle, Cog } from 'lucide-react'
import { getProcessDetail, processes, artifactMap, toolMap } from '@/data'
// 5W1H图标和标签配置
const w5h1Config = {
who: { icon: User, label: 'Who', title: '谁负责', color: 'text-blue-600 dark:text-blue-400' },
what: { icon: Target, label: 'What', title: '做什么', color: 'text-emerald-600 dark:text-emerald-400' },
when: { icon: Clock, label: 'When', title: '何时', color: 'text-amber-600 dark:text-amber-400' },
where: { icon: MapPin, label: 'Where', title: '何地', color: 'text-purple-600 dark:text-purple-400' },
why: { icon: HelpCircle, label: 'Why', title: '为什么', color: 'text-rose-600 dark:text-rose-400' },
how: { icon: Cog, label: 'How', title: '如何做', color: 'text-indigo-600 dark:text-indigo-400' },
}
export function ProcessDetailPage() {
const { id } = useParams()
const location = useLocation()
const navigate = useNavigate()
const processDetail = id ? getProcessDetail(id) : null
// 检查是否从矩阵页面来
const fromMatrix = location.state?.from === 'matrix'
if (!processDetail) {
return (
<div className="flex flex-col items-center justify-center py-20">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4">
</h2>
<Link
to="/knowledge-areas"
className="text-indigo-600 dark:text-indigo-400 hover:underline"
>
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4"></h2>
<Link to="/knowledge-areas" className="text-indigo-600 dark:text-indigo-400 hover:underline">
</Link>
</div>
@@ -30,38 +34,31 @@ export function ProcessDetailPage() {
const ka = processDetail.knowledgeArea
const pg = processDetail.processGroup
const w5h1 = (processDetail as any).w5h1
// 获取前后过程
const currentIndex = processes.findIndex(p => p.id === id)
const prevProcess = currentIndex > 0 ? processes[currentIndex - 1] : null
const nextProcess = currentIndex < processes.length - 1 ? processes[currentIndex + 1] : null
return (
<div className="space-y-6">
<div className="space-y-4">
{/* 返回按钮 + 面包屑 */}
<div className="flex items-center gap-4">
<div className="flex items-center gap-3 text-sm">
{fromMatrix && (
<button
onClick={() => navigate('/process-matrix')}
className="flex items-center gap-2 px-3 py-1.5 rounded-lg bg-indigo-50 dark:bg-indigo-900/30 text-indigo-600 dark:text-indigo-400 hover:bg-indigo-100 dark:hover:bg-indigo-900/50 transition-colors text-sm font-medium"
className="flex items-center gap-1.5 px-2.5 py-1 rounded-lg bg-indigo-50 dark:bg-indigo-900/30 text-indigo-600 dark:text-indigo-400 hover:bg-indigo-100 dark:hover:bg-indigo-900/50 transition-colors font-medium"
>
<LayoutGrid size={16} />
<LayoutGrid size={14} />
</button>
)}
<nav className="flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400">
<Link to="/knowledge-areas" className="hover:text-indigo-600 dark:hover:text-indigo-400">
</Link>
<nav className="flex items-center gap-1.5 text-gray-500 dark:text-gray-400">
<Link to="/knowledge-areas" className="hover:text-indigo-600 dark:hover:text-indigo-400"></Link>
<span>/</span>
{ka && (
<>
<Link
to={`/knowledge-areas/${ka.id}`}
className="hover:text-indigo-600 dark:hover:text-indigo-400"
>
{ka.name}
</Link>
<Link to={`/knowledge-areas/${ka.id}`} className="hover:text-indigo-600 dark:hover:text-indigo-400">{ka.name}</Link>
<span>/</span>
</>
)}
@@ -69,74 +66,90 @@ export function ProcessDetailPage() {
</nav>
</div>
{/* 过程标题 */}
{/* 过程标题 - 更紧凑 */}
<motion.div
initial={{ opacity: 0, y: -20 }}
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
className="rounded-xl p-6 bg-white dark:bg-gray-800 shadow-sm border border-gray-100 dark:border-gray-700"
className="rounded-xl p-4 bg-white dark:bg-gray-800 shadow-sm border border-gray-100 dark:border-gray-700"
>
<div className="flex items-start gap-4">
<div className="flex items-center gap-3">
<div
className="flex h-16 w-16 items-center justify-center rounded-xl text-white font-bold text-xl shrink-0"
className="flex h-12 w-12 items-center justify-center rounded-lg text-white font-bold text-lg shrink-0"
style={{ backgroundColor: ka?.color || '#6366F1' }}
>
{processDetail.code}
</div>
<div className="flex-1">
<h1 className="text-2xl font-bold text-gray-900 dark:text-white">
{processDetail.name}
</h1>
<p className="text-gray-500 dark:text-gray-400">{processDetail.nameEn}</p>
<div className="flex items-center gap-3 mt-3">
<div className="flex-1 min-w-0">
<h1 className="text-xl font-bold text-gray-900 dark:text-white truncate">{processDetail.name}</h1>
<p className="text-sm text-gray-500 dark:text-gray-400">{processDetail.nameEn}</p>
</div>
<div className="flex items-center gap-2 shrink-0">
{ka && (
<span
className="px-3 py-1 rounded-full text-xs font-medium text-white"
style={{ backgroundColor: ka.color }}
>
<span className="px-2.5 py-1 rounded-full text-xs font-medium text-white" style={{ backgroundColor: ka.color }}>
{ka.name}
</span>
)}
{pg && (
<span
className="px-3 py-1 rounded-full text-xs font-medium text-white"
style={{ backgroundColor: pg.color }}
>
<span className="px-2.5 py-1 rounded-full text-xs font-medium text-white" style={{ backgroundColor: pg.color }}>
{pg.name}
</span>
)}
</div>
</div>
</div>
</motion.div>
{/* ITTO表格 */}
{/* 5W1H记忆卡片 */}
{w5h1 && (
<motion.div
initial={{ opacity: 0, y: 20 }}
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.05 }}
className="bg-gradient-to-r from-slate-50 to-gray-50 dark:from-gray-800 dark:to-gray-800 rounded-xl p-4 border border-gray-200 dark:border-gray-700"
>
<h3 className="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-3 flex items-center gap-2">
<span className="px-2 py-0.5 bg-indigo-100 dark:bg-indigo-900/50 text-indigo-700 dark:text-indigo-300 rounded text-xs">5W1H</span>
</h3>
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-3">
{(Object.keys(w5h1Config) as Array<keyof typeof w5h1Config>).map((key) => {
const config = w5h1Config[key]
const Icon = config.icon
const value = w5h1[key]
return (
<div key={key} className="bg-white dark:bg-gray-700/50 rounded-lg p-2.5 border border-gray-100 dark:border-gray-600">
<div className="flex items-center gap-1.5 mb-1">
<Icon size={14} className={config.color} />
<span className={`text-xs font-semibold ${config.color}`}>{config.label}</span>
<span className="text-xs text-gray-400">({config.title})</span>
</div>
<p className="text-xs text-gray-700 dark:text-gray-300 leading-relaxed">{value}</p>
</div>
)
})}
</div>
</motion.div>
)}
{/* ITTO表格 - 更紧凑 */}
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.1 }}
className="grid lg:grid-cols-3 gap-6"
className="grid lg:grid-cols-3 gap-4"
>
{/* 输入 */}
<div className="bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-100 dark:border-gray-700 overflow-hidden">
<div className="flex items-center gap-2 px-4 py-3 bg-blue-50 dark:bg-blue-900/30 border-b border-blue-100 dark:border-blue-800">
<FileText size={18} className="text-blue-600 dark:text-blue-400" />
<h3 className="font-semibold text-blue-900 dark:text-blue-100">
({processDetail.inputs.length})
</h3>
<div className="flex items-center gap-2 px-3 py-2 bg-blue-50 dark:bg-blue-900/30 border-b border-blue-100 dark:border-blue-800">
<FileText size={16} className="text-blue-600 dark:text-blue-400" />
<h3 className="font-semibold text-blue-900 dark:text-blue-100 text-sm"> ({processDetail.inputs.length})</h3>
</div>
<ul className="divide-y divide-gray-100 dark:divide-gray-700">
{processDetail.inputs.map((inputId) => {
const artifact = artifactMap.get(inputId)
return (
<li key={inputId} className="px-4 py-3 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors">
<div className="font-medium text-gray-900 dark:text-white">
{artifact?.name || inputId}
</div>
{artifact && (
<div className="text-sm text-gray-500 dark:text-gray-400">
{artifact.nameEn}
</div>
)}
<li key={inputId} className="px-3 py-2 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors">
<div className="font-medium text-gray-900 dark:text-white text-sm">{artifact?.name || inputId}</div>
{artifact && <div className="text-xs text-gray-500 dark:text-gray-400">{artifact.nameEn}</div>}
</li>
)
})}
@@ -145,25 +158,17 @@ export function ProcessDetailPage() {
{/* 工具与技术 */}
<div className="bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-100 dark:border-gray-700 overflow-hidden">
<div className="flex items-center gap-2 px-4 py-3 bg-amber-50 dark:bg-amber-900/30 border-b border-amber-100 dark:border-amber-800">
<Wrench size={18} className="text-amber-600 dark:text-amber-400" />
<h3 className="font-semibold text-amber-900 dark:text-amber-100">
({processDetail.tools.length})
</h3>
<div className="flex items-center gap-2 px-3 py-2 bg-amber-50 dark:bg-amber-900/30 border-b border-amber-100 dark:border-amber-800">
<Wrench size={16} className="text-amber-600 dark:text-amber-400" />
<h3 className="font-semibold text-amber-900 dark:text-amber-100 text-sm"> ({processDetail.tools.length})</h3>
</div>
<ul className="divide-y divide-gray-100 dark:divide-gray-700">
{processDetail.tools.map((toolId) => {
const tool = toolMap.get(toolId)
return (
<li key={toolId} className="px-4 py-3 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors">
<div className="font-medium text-gray-900 dark:text-white">
{tool?.name || toolId}
</div>
{tool && (
<div className="text-sm text-gray-500 dark:text-gray-400">
{tool.nameEn}
</div>
)}
<li key={toolId} className="px-3 py-2 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors">
<div className="font-medium text-gray-900 dark:text-white text-sm">{tool?.name || toolId}</div>
{tool && <div className="text-xs text-gray-500 dark:text-gray-400">{tool.nameEn}</div>}
</li>
)
})}
@@ -172,25 +177,17 @@ export function ProcessDetailPage() {
{/* 输出 */}
<div className="bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-100 dark:border-gray-700 overflow-hidden">
<div className="flex items-center gap-2 px-4 py-3 bg-emerald-50 dark:bg-emerald-900/30 border-b border-emerald-100 dark:border-emerald-800">
<FileOutput size={18} className="text-emerald-600 dark:text-emerald-400" />
<h3 className="font-semibold text-emerald-900 dark:text-emerald-100">
({processDetail.outputs.length})
</h3>
<div className="flex items-center gap-2 px-3 py-2 bg-emerald-50 dark:bg-emerald-900/30 border-b border-emerald-100 dark:border-emerald-800">
<FileOutput size={16} className="text-emerald-600 dark:text-emerald-400" />
<h3 className="font-semibold text-emerald-900 dark:text-emerald-100 text-sm"> ({processDetail.outputs.length})</h3>
</div>
<ul className="divide-y divide-gray-100 dark:divide-gray-700">
{processDetail.outputs.map((outputId) => {
const artifact = artifactMap.get(outputId)
return (
<li key={outputId} className="px-4 py-3 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors">
<div className="font-medium text-gray-900 dark:text-white">
{artifact?.name || outputId}
</div>
{artifact && (
<div className="text-sm text-gray-500 dark:text-gray-400">
{artifact.nameEn}
</div>
)}
<li key={outputId} className="px-3 py-2 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors">
<div className="font-medium text-gray-900 dark:text-white text-sm">{artifact?.name || outputId}</div>
{artifact && <div className="text-xs text-gray-500 dark:text-gray-400">{artifact.nameEn}</div>}
</li>
)
})}
@@ -198,41 +195,37 @@ export function ProcessDetailPage() {
</div>
</motion.div>
{/* 前后导航 */}
{/* 前后导航 - 更紧凑 */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.2 }}
className="flex items-center justify-between pt-6 border-t border-gray-200 dark:border-gray-700"
transition={{ delay: 0.15 }}
className="flex items-center justify-between pt-3 border-t border-gray-200 dark:border-gray-700"
>
{prevProcess ? (
<Link
to={`/process/${prevProcess.id}`}
className="flex items-center gap-2 text-gray-600 dark:text-gray-400 hover:text-indigo-600 dark:hover:text-indigo-400 transition-colors"
className="flex items-center gap-2 text-gray-600 dark:text-gray-400 hover:text-indigo-600 dark:hover:text-indigo-400 transition-colors text-sm"
>
<ArrowLeft size={18} />
<ArrowLeft size={16} />
<div>
<div className="text-xs text-gray-400"></div>
<div className="text-xs text-gray-400"></div>
<div className="font-medium">{prevProcess.code} {prevProcess.name}</div>
</div>
</Link>
) : (
<div />
)}
) : <div />}
{nextProcess ? (
<Link
to={`/process/${nextProcess.id}`}
className="flex items-center gap-2 text-gray-600 dark:text-gray-400 hover:text-indigo-600 dark:hover:text-indigo-400 transition-colors text-right"
className="flex items-center gap-2 text-gray-600 dark:text-gray-400 hover:text-indigo-600 dark:hover:text-indigo-400 transition-colors text-right text-sm"
>
<div>
<div className="text-xs text-gray-400"></div>
<div className="text-xs text-gray-400"></div>
<div className="font-medium">{nextProcess.code} {nextProcess.name}</div>
</div>
<ArrowRight size={18} />
<ArrowRight size={16} />
</Link>
) : (
<div />
)}
) : <div />}
</motion.div>
</div>
)

View File

@@ -5,14 +5,11 @@ import { processGroups, processesByProcessGroup, processGroupMap, knowledgeAreaM
const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: { staggerChildren: 0.05 },
},
visible: { opacity: 1, transition: { staggerChildren: 0.03 } },
}
const itemVariants = {
hidden: { opacity: 0, y: 20 },
hidden: { opacity: 0, y: 10 },
visible: { opacity: 1, y: 0 },
}
@@ -22,106 +19,71 @@ export function ProcessGroupsPage() {
const processes = id ? processesByProcessGroup.get(id) || [] : []
if (selectedPG) {
// 显示过程组详情
return (
<div className="space-y-6">
<div className="space-y-4">
{/* 面包屑 */}
<nav className="flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400">
<Link to="/process-groups" className="hover:text-indigo-600 dark:hover:text-indigo-400">
</Link>
<Link to="/process-groups" className="hover:text-indigo-600 dark:hover:text-indigo-400"></Link>
<span>/</span>
<span className="text-gray-900 dark:text-white">{selectedPG.name}</span>
</nav>
{/* 过程组标题 */}
{/* 过程组标题 - 紧凑版 */}
<motion.div
initial={{ opacity: 0, y: -20 }}
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
className="rounded-xl p-6"
className="rounded-xl p-4"
style={{ backgroundColor: `${selectedPG.color}15` }}
>
<div className="flex items-center gap-4">
<div className="flex items-center gap-3">
<div
className="flex h-14 w-14 items-center justify-center rounded-xl text-white font-bold text-xl"
className="flex h-12 w-12 items-center justify-center rounded-lg text-white font-bold text-lg"
style={{ backgroundColor: selectedPG.color }}
>
{selectedPG.order}
</div>
<div>
<h1 className="text-2xl font-bold text-gray-900 dark:text-white">
{selectedPG.name}
</h1>
<p className="text-gray-500 dark:text-gray-400">{selectedPG.nameEn}</p>
<div className="flex-1">
<h1 className="text-xl font-bold text-gray-900 dark:text-white">{selectedPG.name}</h1>
<p className="text-sm text-gray-500 dark:text-gray-400">{selectedPG.nameEn}</p>
</div>
<div className="text-right">
<div className="text-2xl font-bold text-gray-900 dark:text-white">{processes.length}</div>
<div className="text-xs text-gray-500"></div>
</div>
</div>
<p className="mt-4 text-gray-600 dark:text-gray-300">{selectedPG.description}</p>
<p className="mt-2 text-sm text-gray-600 dark:text-gray-300">{selectedPG.description}</p>
</motion.div>
{/* 过程列表 */}
<motion.div
variants={containerVariants}
initial="hidden"
animate="visible"
className="space-y-4"
>
<h2 className="text-lg font-semibold text-gray-900 dark:text-white">
{processes.length}
</h2>
{/* 过程列表 - 紧凑版 */}
<motion.div variants={containerVariants} initial="hidden" animate="visible" className="space-y-2">
{processes.map((process) => {
const ka = knowledgeAreaMap.get(process.knowledgeAreaId)
return (
<motion.div key={process.id} variants={itemVariants}>
<Link
to={`/process/${process.id}`}
className="group block bg-white dark:bg-gray-800 rounded-xl p-5 shadow-sm border border-gray-100 dark:border-gray-700 hover:shadow-md hover:border-gray-200 dark:hover:border-gray-600 transition-all"
className="group flex items-center gap-3 bg-white dark:bg-gray-800 rounded-lg p-3 shadow-sm border border-gray-100 dark:border-gray-700 hover:shadow-md hover:border-gray-200 dark:hover:border-gray-600 transition-all"
>
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<div
className="flex h-10 w-10 items-center justify-center rounded-lg text-white font-medium"
className="flex h-9 w-9 items-center justify-center rounded-lg text-white font-medium text-sm shrink-0"
style={{ backgroundColor: ka?.color || selectedPG.color }}
>
{process.code}
</div>
<div>
<h3 className="font-semibold text-gray-900 dark:text-white">
{process.name}
</h3>
<p className="text-sm text-gray-500 dark:text-gray-400">
{process.nameEn}
</p>
<div className="flex-1 min-w-0">
<h3 className="font-medium text-gray-900 dark:text-white text-sm truncate">{process.name}</h3>
<p className="text-xs text-gray-500 dark:text-gray-400 truncate">{process.nameEn}</p>
</div>
</div>
<div className="flex items-center gap-4">
<div className="flex items-center gap-3 text-xs text-gray-500 dark:text-gray-400 shrink-0">
<span className="flex items-center gap-1"><FileText size={12} />{process.inputs.length}</span>
<span className="flex items-center gap-1"><Wrench size={12} />{process.tools.length}</span>
<span className="flex items-center gap-1"><FileOutput size={12} />{process.outputs.length}</span>
{ka && (
<span
className="px-3 py-1 rounded-full text-xs font-medium text-white"
style={{ backgroundColor: ka.color }}
>
<span className="px-2 py-0.5 rounded-full text-xs font-medium text-white hidden sm:inline" style={{ backgroundColor: ka.color }}>
{ka.name}
</span>
)}
<ArrowRight
size={20}
className="text-gray-400 group-hover:text-gray-600 dark:group-hover:text-gray-300 group-hover:translate-x-1 transition-all"
/>
</div>
</div>
{/* ITTO统计 */}
<div className="mt-4 flex items-center gap-6 text-sm text-gray-500 dark:text-gray-400">
<span className="flex items-center gap-1">
<FileText size={14} />
{process.inputs.length}
</span>
<span className="flex items-center gap-1">
<Wrench size={14} />
{process.tools.length}
</span>
<span className="flex items-center gap-1">
<FileOutput size={14} />
{process.outputs.length}
</span>
<ArrowRight size={16} className="text-gray-400 group-hover:text-gray-600 dark:group-hover:text-gray-300 group-hover:translate-x-0.5 transition-all" />
</div>
</Link>
</motion.div>
@@ -132,58 +94,40 @@ export function ProcessGroupsPage() {
)
}
// 显示过程组列表
// 显示过程组列表 - 紧凑版
return (
<div className="space-y-6">
<div className="space-y-4">
<div>
<h1 className="text-2xl font-bold text-gray-900 dark:text-white"></h1>
<p className="text-gray-500 dark:text-gray-400 mt-1">
PMBOK第6版定义的5大项目管理过程组
</p>
<h1 className="text-xl font-bold text-gray-900 dark:text-white"></h1>
<p className="text-sm text-gray-500 dark:text-gray-400">PMBOK第6版定义的5大项目管理过程组</p>
</div>
<motion.div
variants={containerVariants}
initial="hidden"
animate="visible"
className="space-y-4"
>
<motion.div variants={containerVariants} initial="hidden" animate="visible" className="space-y-2">
{processGroups.map((pg) => (
<motion.div key={pg.id} variants={itemVariants}>
<Link
to={`/process-groups/${pg.id}`}
className="group block bg-white dark:bg-gray-800 rounded-xl p-6 shadow-sm border border-gray-100 dark:border-gray-700 hover:shadow-md transition-all"
className="group flex items-center gap-4 bg-white dark:bg-gray-800 rounded-xl p-4 shadow-sm border border-gray-100 dark:border-gray-700 hover:shadow-md transition-all"
style={{ borderLeftWidth: 4, borderLeftColor: pg.color }}
>
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<div
className="flex h-14 w-14 items-center justify-center rounded-xl text-white font-bold text-xl"
className="flex h-12 w-12 items-center justify-center rounded-lg text-white font-bold text-lg shrink-0"
style={{ backgroundColor: pg.color }}
>
{pg.order}
</div>
<div>
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">{pg.name}</h3>
<div className="flex-1 min-w-0">
<h3 className="font-semibold text-gray-900 dark:text-white">{pg.name}</h3>
<p className="text-sm text-gray-500 dark:text-gray-400">{pg.nameEn}</p>
<p className="text-xs text-gray-400 dark:text-gray-500 mt-1 line-clamp-1">{pg.description}</p>
</div>
</div>
<div className="flex items-center gap-4">
<div className="flex items-center gap-3 shrink-0">
<div className="text-right">
<div className="text-2xl font-bold text-gray-900 dark:text-white">
{pg.processCount}
<div className="text-xl font-bold text-gray-900 dark:text-white">{pg.processCount}</div>
<div className="text-xs text-gray-500"></div>
</div>
<div className="text-sm text-gray-500 dark:text-gray-400"></div>
<ArrowRight size={20} className="text-gray-400 group-hover:text-gray-600 dark:group-hover:text-gray-300 group-hover:translate-x-1 transition-all" />
</div>
<ArrowRight
size={24}
className="text-gray-400 group-hover:text-gray-600 dark:group-hover:text-gray-300 group-hover:translate-x-1 transition-all"
/>
</div>
</div>
<p className="mt-4 text-gray-500 dark:text-gray-400">
{pg.description}
</p>
</Link>
</motion.div>
))}

View File

@@ -26,6 +26,16 @@ export interface ProcessGroup {
processCount: number; // 包含的过程数量
}
// 5W1H记忆辅助信息
export interface Process5W1H {
who: string; // 谁负责执行
what: string; // 做什么(核心目的)
when: string; // 什么时候执行
where: string; // 在哪里/什么场景执行
why: string; // 为什么要执行(价值意义)
how: string; // 如何执行(关键方法)
}
// 过程
export interface Process {
id: string; // 如 "P4.1"
@@ -38,6 +48,7 @@ export interface Process {
inputs: string[]; // 输入工件ID列表
tools: string[]; // 工具与技术ID列表
outputs: string[]; // 输出工件ID列表
w5h1?: Process5W1H; // 5W1H记忆辅助信息
}
// 工件类别