產生 MS Project 可直接匯入的 WBS 專案時程 XML(MSPDI 格式),第一層功能模組、第二層工項, 含工期、負責資源、前置依賴、資源指派,日期照依賴鏈自動展開成甘特圖。 當使用者要「WBS」「工作分解」「專案時程」「開發排程」「甘特圖」「MS Project 檔」「.mpp/.xml 時程」 「排一份 N 天 / N 人的開發計畫」「by 功能 / by 工項排時程」時觸發。 **只要使用者要的是「能匯入 MS Project 的時程表」就用這個 skill**——手刻 MSPDI XML 極易踩雷 (打不開 / 日期全塌 / 工期顯示 0),本 skill 把這些坑全部編碼進生成腳本,一次到位。
Scanned 9/3/2026
Install to Claude Code
npx -y skills add abs1294/fulin-claude-plugins --skill msproject-wbs --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Msproject Wbs?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/abs1294-msproject-wbs)More formats (shields.io, HTML) on the badges page.
---
name: msproject-wbs
description: >
產生 MS Project 可直接匯入的 WBS 專案時程 XML(MSPDI 格式),第一層功能模組、第二層工項,
含工期、負責資源、前置依賴、資源指派,日期照依賴鏈自動展開成甘特圖。
當使用者要「WBS」「工作分解」「專案時程」「開發排程」「甘特圖」「MS Project 檔」「.mpp/.xml 時程」
「排一份 N 天 / N 人的開發計畫」「by 功能 / by 工項排時程」時觸發。
**只要使用者要的是「能匯入 MS Project 的時程表」就用這個 skill**——手刻 MSPDI XML 極易踩雷
(打不開 / 日期全塌 / 工期顯示 0),本 skill 把這些坑全部編碼進生成腳本,一次到位。
---
# MS Project WBS 產生器
產生 **MSPDI XML**(MS Project 的匯入格式)。手刻這種 XML 有幾個非踩不可的雷,本 skill 的價值就是把雷全部封在生成腳本裡,讓你只需描述「有哪些工項」,其餘由腳本保證正確。
## 為什麼需要這個 skill(實戰踩過的雷,每個都會讓成果報廢)
親手寫過 MSPDI XML 的都知道,「XML 看起來對」跟「MS Project 打得開且排程正確」是兩回事。
1. **【頭號雷】Task 子元素順序違反 XSD 序列 → 欄位被靜默丟棄**。MSPDI 匯入器嚴格照 schema 序列讀 Task 子元素,**順序不對的欄位不報錯、直接忽略**。經典病徵:`Start`/`Finish` 被放在 `Duration`/`Summary` 之後 → 被丟棄 → **所有任務日期塌到專案起始日,但工期正常顯示**(因為 Duration 剛好在對的位置被讀到)。這個雷極難排查:XML well-formed、PowerShell parser 全過、內容看起來完全正確——只有 MS Project 實際匯入才會露餡。腳本用 `TASK_ORDER` 白名單固定順序(`UID→ID→Name→Type→IsNull→OutlineLevel→Start→Finish→Duration→DurationFormat→Work→Estimated→Milestone→Summary→ConstraintType→ConstraintDate→PredecessorLink→Active→Manual`)並內建順序自檢,違序在生成期就 throw。
2. **缺 Project 層全域欄位 → 直接打不開**。MS Project 期待 `SaveVersion` / `MinutesPerDay` / `DefaultStartTime` / `DurationFormat` / `HonorConstraints` 等一整組全域設定,缺了會判定檔案不完整而拒開。Project 層欄位同樣要照 XSD 序列。腳本已補齊。
3. **日曆 `WorkingTimes` / `WorkingTime` 標籤配對 → XML 非 well-formed**。只差一個 `s`,手拼巢狀極易配對錯,整份解析失敗。腳本用固定正確結構產生。
4. **缺 `ConstraintType` / `ConstraintDate`(或 `HonorConstraints` 沒開)→ 自動排程重算把任務推到「越早越好」**。給每個**葉子任務**加 `ConstraintType=4`(Start No Earlier Than)+ `ConstraintDate=該任務開始日`,Project 層設 `HonorConstraints=1`。**摘要任務不加約束**(日期由子任務彙總,鎖死會打架)。注意:約束欄位放錯位置一樣會被雷 1 吃掉——順序對了約束才存在。
5. **UTF-8 無 BOM → 中文亂碼 / 解析失敗**。Windows 上無 BOM 的 UTF-8 中文 XML 會被用系統 ANSI 誤判。輸出加 UTF-8 BOM。
6. **工期顯示 0 天**:`Duration` 要配對應的 `Work` 欄,MS Project 才算得出天數。
7. **負責人別塞 `Notes`**:用 **Resource + Assignment**(資源指派),甘特圖「資源名稱」欄才會正確顯示;Notes 塞字在表格上是又醜又錯位的「標記」欄。
## 使用流程
> ⚠️ **貫穿全流程的硬規則:XML 改了,XLSX 必須同輪跟著重生**(若該專案已有交付 XLSX)。
> XLSX 是 XML 的下游轉出物,禁止只更新其一造成漂移。細節與指令見流程 3 的【HARNESS 硬規則】。
### 1. 蒐集 WBS 內容
跟使用者確認這些(能從對話推出的就自己填,缺的一次問完):
- **功能模組清單**(第一層)+ 每個模組底下的**工項**(第二層)。
- 每個工項的:**工期(天,建議 ≤3 天一項)**、**負責資源**(如後端 / 前端 / QA)、**前置依賴**(此工項要等哪個工項完成才能開始)。
- **專案起始日**、**資源清單**(有哪幾種角色)、**單人或多人並行**(多人時各資源各一條時間線,工項起始 = max(該資源空閒日, 依賴完成日))。
- **截止日**(若有)——算完總工期後主動比對「排出來的完成日 vs 截止日」,塌不進要老實講、給選項(加人 / 縮範圍 / 接受真實排程),不要灌水硬塞。
> 工項若能抄既有系統 / 既有畫面已存在,工時要據實壓低(別當全新開發估);估時基準講清楚寫進交付說明。
### 2. 填生成腳本
複製 `scripts/generate-wbs.mjs`,**只改頂部的 `MODULES` 陣列**與 `OUT`/`PROJECT_NAME`/`RESOURCES`/`TODAY`(用週次落位才需再設 `START`/`W1_MON`)。腳本內的排程演算法、MSPDI 框架、雷區處理**不要動**——那是本 skill 的核心價值。範本頂部附完整示範資料(同時展示三層 / 兩種排程 / 里程碑 / 貫穿全期),照著改即可。
工項物件格式(見腳本內註解,依需要挑欄位):
```
基本: { id:'唯一id', name:'工項名(純中文,不放代號)', res:'資源key' }
排程三選一:
依賴鏈: d:工期天數, dep:'前置工項id'(選填) ← 簡單專案,腳本自動依資源時間線+依賴往後排
週次區間:w:[起週,迄週] ← W(a)週一→W(b)週五,inclusive
天粒度: pd:[絕對週次, 起日, 迄日] ← 週內第幾天 0=一…4=五
前期週次:pre:[起,迄] ← 落在 W1 之前的前期(以 START 為基準)
層級/標記:
sum:true 此為 L2 主條目,其後緊接的一般工項自動歸它當 L3 子項(要三層時用)
ms:true 里程碑(菱形,單日)
top:true 貫穿全期/獨立 L2 工項(不當某條目的子項)
```
> **何時用哪種排程**:時程**並行重疊**(例 系統二 W7–W10 與 系統三 W7–W8 同時跑)→ 必用週次落位(`w`/`pd`),依賴鏈會把重疊硬拆成串行、日期就對不上。單純線性專案用依賴鏈最省事。兩種可在同一份 MODULES 混用。
> **兩層 vs 三層**:只給模組(L1)+工項即為兩層;要三層就把中層條目標 `sum:true`,其後的工項自動變它的 L3 子項。
**任務名只放純中文**——別放 `M1` / `B1-2` 這種模組序 / 需求編號代號,使用者看不懂。分組資訊由「模組(第一層摘要任務)」承載即可。
### 3. 執行 + 驗證(必做,別跳)
```bash
node scripts/generate-wbs.mjs
```
> ⚠️ **【HARNESS 硬規則】XML 與 XLSX 必須同步更新,禁止只更新其一。**
> 只要因任何原因重跑 `generate-wbs.mjs`(改工項/改資源/改日期/修雷…)而 XML 內容有變,
> **同一輪就必須接著重跑 `mspdi-to-xlsx.py` 重生 XLSX**——只要該專案已產出過交付用 XLSX(見流程 4/常見追加需求),就一律連動,不問是否「這次只是小改」。
> 原因:XLSX 是從 XML 轉出的**下游產物**,兩者一旦不同步,交付出去的 XLSX 就是舊時程(日期/工項對不上 XML 與 MS Project),且此類漂移靜態難察覺。
> 標準連動指令(改完 XML 後照跑):
> ```bash
> node scripts/generate-wbs.mjs # 1) 重生 XML
> python scripts/mspdi-to-xlsx.py <輸出.xml> <交付.xlsx> # 2) 立刻重生 XLSX(同一輪)
> ```
> 收尾自檢:確認 XML 與 XLSX 的 `mtime` 皆為本輪、且工項數一致;不一致代表漏跑步驟 2。
產出後**兩層驗證都要做**——注意:`[xml]` 只驗 well-formed,**驗不到元素順序**(雷 1),所以第二段順序檢查不可省:
```powershell
$f = "<輸出的 xml 絕對路徑>"
try {
[xml]$x = Get-Content -Raw -Path $f
"OK well-formed | Task: " + $x.Project.Tasks.Task.Count + " | Resource: " + $x.Project.Resources.Resource.Count + " | Assignment: " + $x.Project.Assignments.Assignment.Count
# 雷1 檢查:每個 Task 子元素順序必須遞增於 XSD 序列(違反 = MS Project 靜默丟欄位)
$order = @('UID','ID','Name','Type','IsNull','OutlineLevel','Start','Finish','Duration','DurationFormat','Work','Estimated','Milestone','Summary','ConstraintType','ConstraintDate','PredecessorLink','Active','Manual')
$bad = 0
foreach ($t in $x.Project.Tasks.Task) {
$last = -1
foreach ($c in $t.ChildNodes) {
$i = $order.IndexOf($c.Name)
if ($i -lt 0 -or $i -lt $last) { $bad++; "❌ UID $($t.UID) 欄位 $($c.Name) 順序違規"; break }
$last = $i
}
}
"順序違規 Task 數(要0): $bad"
"HonorConstraints(要1): " + $x.Project.HonorConstraints
"葉子約束數(要=工項數): " + ($x.Project.Tasks.Task | Where-Object { $_.ConstraintType }).Count
"摘要有約束數(要0): " + ($x.Project.Tasks.Task | Where-Object { $_.OutlineLevel -eq '1' -and $_.ConstraintType }).Count
} catch { "XML ERROR: " + $_.Exception.Message }
```
**驗收標準**(全中才算好):
- `OK well-formed` 且 **順序違規 Task 數 = 0**(順序違規就是雷 1,交付出去日期必塌)
- `HonorConstraints = 1`;葉子約束數 = 工項數、摘要約束數 = 0
- 抽查幾個葉子任務的 `Start`/`ConstraintDate`:應是**展開的**日期(第一項在起始日、最後一項在完成日附近),不是全擠在起始日
> 用 Bash grep / node 簡易正則**驗不準** MSPDI(`<Task>` vs `<Tasks>`、多層巢狀會誤判)。一定用 PowerShell `[xml]`。
> **誠實原則**:以上驗證仍屬「靜態檢查」,最終判準是 MS Project 實際匯入的畫面——交付時請使用者匯入確認「日期展開、工期天數、資源名稱」三點,不要在使用者確認前宣告成功。
### 4. 交付
告訴使用者檔案路徑、起訖日、總工項數、每工項 ≤N 天。若有截止日,明說「排出來 vs 截止日」是否塌得進。提醒匯入後應看到:任務名純中文、有工期天數、資源名稱欄顯示負責人、甘特圖依日期展開。
## 常見追加需求
- **改任務名 / 去代號**:只改 `MODULES` 的 `name`,重跑。
- **加人並行 / 改工期**:改 `RESOURCES` 與工項的 `res`/`d`,重跑(腳本自動依資源排時間線)。
- **使用者說「打不開 / 日期全塌 / 工期 0」**:對照上面「四個雷」逐一查——幾乎都是某個欄位缺了。用 PowerShell parser 定位。若是既有檔要修,先跑 parser 找出是哪個雷,再針對性補(打不開通常是雷 1/2,日期塌是雷 3)。
- **使用者要 XLSX 交付檔(免手動 MPP 轉檔)**:客戶常把 XML→MS Project→存 MPP→另存 XLSX,得到白底黑字、無階層、難讀。用 `scripts/mspdi-to-xlsx.py` 直接從 MSPDI XML 產出**內容與 MS Project 匯出完全一致**的 XLSX,並額外加階層縮排/層級配色(L1 藍、L2 灰、里程碑黃)/凍結窗格/可摺疊 outline。
- 執行:`python scripts/mspdi-to-xlsx.py <輸入.xml> <輸出.xlsx>`
- **內容對等契約**(改動前想清楚):8 欄=大綱編號(1/1.1/1.1.1,依 OutlineLevel 累進非 UID)/名稱/工期("N 工作日"=Duration 時數÷8)/開始時間(「2026年7月27日 上午 08:00」月日不補零、12 小時制)/完成時間/前置任務(PredecessorLink→對應列大綱編號)/資源名稱(摘要列空白)/完成百分比。
- **驗收**:若客戶已有一份自己轉的 XLSX,用「名稱+開始日」複合 key 逐欄比對,內容 diff 必須為 0(大綱編號會因模組增減位移,屬正常)。排版只走樣式層,**絕不改欄位字串內容**(不可把工期寫「3 天」、日期改 ISO),否則對不上客戶端匯出結果。
- **使用者要「預計完成%」基準線欄**(依開檔當天算「今天照計畫該完成幾趴」):**兩邊都能加**——
- **XLSX 側(已實作+已驗證,活公式)**:`mspdi-to-xlsx.py` 產出 I 欄「預計完成%」,公式 `=IF(TODAY()<=起,0,IF(TODAY()>=迄,1,已過工作天/總工作天))` 用 `NETWORKDAYS` 算工作天,開檔當天自動重算。
- **關鍵設計**:D/E「開始/完成日期」存**真 Excel 日期**、只用儲存格格式 `yyyy"年"m"月"d"日"` 顯示成中文——所以畫面是中文日期、底層可運算,I 欄公式**直接引用 D/E**,不需額外輔助欄。(早期版本誤把 D/E 存成中文字串、被迫另開隱藏 J/K 放真日期,是走了冤枉路;日期一律存真值+格式化顯示。)摘要/里程碑列留空。
- **XML 側(MSPDI ExtendedAttribute)——公式欄「可以」匯入,且要顯示 % 必須用 Text 欄(已查 Microsoft XSD+MS Project COM 實測雙重確認)**:
- **要顯示「54%」→ 必須用 Text 欄,不能用 Number 欄**。MS Project 的 Number 型自訂欄位**沒有百分比顯示格式**(schema 無 Percent 型別、無 Format/Mask 元素)——Number 存 0.54 就永遠顯示 `0.54`。正解:用 **Text1**(FieldID `188743731`,CFType **7**),公式輸出字串:`Format(<fraction>*100,"0") & "%"` → 顯示「54%」。(本 skill 曾誤用 Number1 顯示成 0.54,已改 Text。)
- **FieldID 別搞錯型別**:`188743731`=Text1(`pjCustomTaskText1`),`188743767`=Number1(`pjCustomTaskNumber1`)。型別(CFType)要與 FieldID 對應,否則 MS Project 當欄位不存在(連欄名都不出現)。
- **Project 層定義(子元素嚴格照 XSD 序列,違序會被靜默丟)**:`FieldID→FieldName→CFType→…→Alias→…→CalculationType→Formula→…`。本 skill 用的 Text 版:`<FieldID>188743731</FieldID><FieldName>Text1</FieldName><CFType>7</CFType><Alias>顯示名</Alias><CalculationType>2</CalculationType><Formula>IIf([Duration]=0,"",Format(…*100,"0") & "%")</Formula>`。CFType:0=Cost 1=Date 2=Duration 3=Finish 4=Flag 5=Number 6=Start **7=Text**。CalculationType:0=None 1=Rollup **2=Calculation**。**公式欄名用英文中括號**(`[Start]`/`[Finish]`/`[Duration]`),匯入後 MS Project 會自動在地化成 `[開始時間]/[完成時間]/[工期]`。公式內 `&` 要 XML 轉義成 `&`。
- **Task 層引用**:本 skill 序列放在 `Manual` 之後(實測 well-formed 且 COM 匯入通過)。公式欄由 MS Project 依 Formula 自算,Text 公式欄**不寫 per-task `<Value>`**,只放 `<ValueGUID>00000000-0000-0000-0000-000000000000</ValueGUID>` 標「計算欄」。`ExtendedAttribute` 要加進 `TASK_ORDER` 白名單否則順序自檢 throw。
- **驗證方式(本機有 MS Project 才行)**:COM round-trip 是終極判準——`New-Object -ComObject MSProject.Application`→`FileOpen(xml)`→`CustomFieldGetName/GetFormula(188743731)`+逐 Task `GetField(188743731)`。⚠ **兩個實測踩過的坑**:① MS Project 若已開著檔,COM 建立會 `RPC_E_CALL_REJECTED`(0x80010001),要先 `Stop-Process WINPROJ`;② 測「進行中」的值別靠改系統時鐘,改造一份把公式 `Now()` 換成固定中段日期的 probe XML 匯入,讀回值即可驗證非 0(本 skill 用 2026/9/15 驗到 100%/部分%)。
- **「今天顯示 0% 不是壞掉」**:公式用 `Now()`=系統時鐘。若專案起始日在未來,今天所有任務都還沒開始→全 0% 是**正確**基準線(「以今天而言照計畫該完成幾趴」)。要看非 0 得等到專案期間、或改系統日期、或用上面的 probe XML。交付時要主動跟使用者講這點,免得誤判成 bug。
- 出處:Microsoft Learn MSPDI schema(ExtendedAttribute/CFType/Formula element,無 Format/Percent)、`PjCustomField` enumeration、Dale Howard MVP(Number 欄無 % 格式,須 Text+`Format(...) & "%"`)。
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!