feat(过程详情): 新增主要作用字段替换5W1H显示

- types/itto.ts: Process 新增 purpose 可选字段
- processes.json: P8.7 监督风险添加 purpose 示例数据
- ProcessDetailPage: 隐藏5W1H,改为显示主要作用卡片
- CLAUDE.md: 记录三类日常学习内容更新操作指南

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>
This commit is contained in:
ittoview
2026-02-23 06:32:09 +00:00
parent 943ad2fe85
commit 0a5788e52c
4 changed files with 92 additions and 35 deletions

View File

@@ -237,3 +237,84 @@ import { useAppStore } from '@/stores/useAppStore'
- 需求设计文档: `docs/需求设计文档.md`
- ITTO 手册 PDF: `⑦ ITTO输入输出工具手册.pdf`
## 日常学习内容更新操作指南
### 1. 更新知识领域的敏捷裁剪因素
**文件:** `src/data/knowledge-areas.json`
在对应知识领域对象中添加 `tailoringFactors` 数组:
```json
{
"id": "KA06",
"name": "项目资源管理",
"tailoringFactors": [
{
"title": "多元化",
"description": "团队的多元化背景是什么?"
},
{
"title": "物理位置",
"description": "团队成员和实物资源的物理位置在哪里?"
}
]
}
```
**注意:** `tailoringFactors` 为可选字段,未填写的知识领域页面不显示该区块。
---
### 2. 更新过程的 ITTO 明细
**文件:** `src/data/processes.json`
`inputs` / `tools` / `outputs` 支持两种格式:
- 纯字符串 ID无明细`"A008"`
- 带明细对象(有子项展开):`{ "id": "A008", "detail": [{ "label": "质量管理计划" }, { "label": "范围基准" }] }`
**示例:**
```json
{
"id": "P5.1",
"inputs": [
{ "id": "A008", "detail": [{ "label": "质量管理计划" }, { "label": "范围基准" }] },
{ "id": "A076", "detail": [{ "label": "假设日志" }, { "label": "需求文件" }] },
"A005",
"A006"
],
"tools": [
"TT001",
{ "id": "TT008", "detail": [{ "label": "成本效益分析" }, { "label": "质量成本" }] }
],
"outputs": [
"A021",
{ "id": "A077", "detail": [{ "label": "经验教训登记册" }, { "label": "风险登记册" }] }
]
}
```
**注意:**
- `detail` 数组中每项必须是 `{ "label": "名称" }` 对象,不能是纯字符串
- 如果引用的工件/工具 ID 不存在于 `artifacts.json` / `tools.json`,需先添加
---
### 3. 更新过程的主要作用
**文件:** `src/data/processes.json`
在对应过程对象中添加 `purpose` 字段:
```json
{
"id": "P8.7",
"name": "监督风险",
"purpose": "保证项目决策是在整体项目风险和单个项目风险当前信息的基础上进行。本过程需要在整个项目期间开展。"
}
```
**注意:** `purpose` 为可选字段,填写后会在过程详情页标题下方以蓝色卡片展示;未填写则不显示。

View File

@@ -1261,6 +1261,7 @@
"inputs": ["A008", "A076", "A067", "A069", "A005", "A006"],
"tools": ["TT008", "TT067", "TT032"],
"outputs": ["A068", "A053", "A078", "A077", "A075"],
"purpose": "保证项目决策是在整体项目风险和单个项目风险当前信息的基础上进行。本过程需要在整个项目期间开展。",
"w5h1": {
"who": "PM主导风险责任人参与",
"what": "监督商定的风险应对计划的实施、跟踪已识别风险、识别和分析新风险,以及评估风险管理有效性",

View File

@@ -1,19 +1,9 @@
import { useParams, Link, useLocation, useNavigate } from 'react-router-dom'
import { motion } from 'framer-motion'
import { ArrowLeft, ArrowRight, FileText, Wrench, FileOutput, LayoutGrid, Workflow, User, Target, Clock, MapPin, HelpCircle, Cog, Eye, EyeOff } from 'lucide-react'
import { ArrowLeft, ArrowRight, FileText, Wrench, FileOutput, LayoutGrid, Workflow, Eye, EyeOff, Info } from 'lucide-react'
import { getProcessDetail, processes } from '@/data'
import { useState, useEffect } from 'react'
// 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' },
}
type IttoSection = 'inputs' | 'tools' | 'outputs'
const STORAGE_KEY = 'ittoview:process-detail:itto-visibility'
@@ -78,7 +68,7 @@ export function ProcessDetailPage() {
const ka = processDetail.knowledgeArea
const pg = processDetail.processGroup
const w5h1 = (processDetail as any).w5h1
const purpose = (processDetail as any).purpose
const currentIndex = processes.findIndex(p => p.id === id)
const prevProcess = currentIndex > 0 ? processes[currentIndex - 1] : null
@@ -151,35 +141,19 @@ export function ProcessDetailPage() {
</div>
</motion.div>
{/* 5W1H记忆卡片 */}
{w5h1 && (
{/* 主要作用 */}
{purpose && (
<motion.div
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"
className="bg-indigo-50 dark:bg-indigo-900/20 rounded-xl p-4 border border-indigo-100 dark:border-indigo-800"
>
<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 className="flex items-center gap-2 mb-2">
<Info size={16} className="text-indigo-600 dark:text-indigo-400 shrink-0" />
<h3 className="text-sm font-semibold text-indigo-900 dark:text-indigo-100"></h3>
</div>
<p className="text-sm text-indigo-800 dark:text-indigo-200 leading-relaxed">{purpose}</p>
</motion.div>
)}

View File

@@ -72,6 +72,7 @@ export interface Process {
inputs: ProcessRef[]; // 输入工件ID列表支持明细
tools: ProcessRef[]; // 工具与技术ID列表支持明细
outputs: ProcessRef[]; // 输出工件ID列表支持明细
purpose?: string; // 本过程的主要作用
w5h1?: Process5W1H; // 5W1H记忆辅助信息
}