對應 design:design-C5.md 級別:中 預估工時:FE 4~5 天
cd ~/Projects/Billows/Audit-Manager/compliance-manager-fe
# 1. C2.1 endpoints 已 ship?
# 確認以下 API 在 dev 環境可用:
# GET /projects/<uid>/current-ssp-uid
# GET /ssp/<uid>/system-characteristic
# GET /ssp/<uid>/parties
# GET /ssp/<uid>/ssp-resources
# PUT /ssp/<uid>/parties/<party_uid>
# POST /ssp/<uid>/ssp-resources/items
# 2. 找專案規劃頁 root component
find src/views -name "*Planning*" -o -name "*ProjectDetail*" | head -5
# 3. 找既有 MF panel 元件(可複用)
ls src/components/module_frame/
# 4. 確認既有 composable
ls src/composables/ | grep -E "ModuleFrame|Ssp"
# 5. 確認 PrimeVue 版本 + 已有 Accordion 元件
grep -n "primevue" package.jsonuseSspContext.js新檔:src/composables/useSspContext.js
內容:對齊 design-C5.md §4.3
Unit test:(Vitest if 有)
/projects/<uid>/current-ssp-uid 並設定 refCommit:feat(composables): C5 useSspContext
useSspParties.js / useSspResources.js / useSspSystemCharacteristic.js / useSspLeveraged.js新檔:對應 4 個 composable
每個 composable 包含:
useModuleFrameParties 模式)+ invalidate(sspUid) 清快取Commit:feat(composables): C5 useSspParties / useSspResources / useSspSystemCharacteristic / useSspLeveraged
新檔:
src/service/SspService.js(仿 ModuleFrameService 模式,但 entry 改 ssp_uid)內容:封裝 axios call for 所有 SSP-scoped endpoint
Commit:feat(service): C5 SspService
SspTabPanel.vue root 元件(FE)新檔:src/views/project/planning/SspTabPanel.vue
Props:
projectUid: String內容:
State:
const sspContext = useSspContext(toRef(props, 'projectUid'))
const selectedApUid = ref(null)
const expandedSections = ref(['basic']) // 預設展開
const isEditable = computed(() =>
sspContext.isEditable.value && currentUserRole.value === 'manager'
)
// AP selector
const apMenu = ref([])
async function loadApMenu() {
apMenu.value = await GrcProjectService.getApMenu(props.projectUid)
}
// Deep link
onMounted(() => {
const { section } = route.query
if (section) {
expandedSections.value = [section === 'scope' ? ['scope-devices', 'scope-info-systems'] : section]
}
})Commit:feat(project-planning): C5 SspTabPanel root component
SspBasicSection.vue 基本資料區塊(FE)新檔:src/components/project/ssp/SspBasicSection.vue
內容:
useSspSystemCharacteristic composableCommit:feat(project-planning): C5 SspBasicSection
SspScopeDevicesSection.vue + SspScopeInfoSystemsSection.vue(FE)新檔:
src/components/project/ssp/SspScopeDevicesSection.vuesrc/components/project/ssp/SspScopeInfoSystemsSection.vue仿 MF 版本:
src/components/module_frame/ModuleFrameSspDevicesPanel.vuesrc/components/module_frame/ModuleFrameSspInfoSystemsPanel.vue改動:
sspUid/ssp/<sspUid>/ssp-resources/...useSspResources composableCommit:feat(project-planning): C5 SspScopeDevicesSection + SspScopeInfoSystemsSection
SspPartiesSection.vue 參與人員區塊(FE)新檔:src/components/project/ssp/SspPartiesSection.vue
仿 MF 版本:src/components/module_frame/ModuleFramePartiesPanel.vue
改動:
sspUid/ssp/<sspUid>/parties/...GET /system/menu/ssp_party_role (C1)$t('lang.oscal_role.ssp_party_role.<key>.label') (C1 i18n)useSspParties composableCommit:feat(project-planning): C5 SspPartiesSection
SspLeveragedSection.vue 外部利用服務(FE,待 C2.2 後可實作)新檔:src/components/project/ssp/SspLeveragedSection.vue
Phase 1(C5 first ship):placeholder 顯示「尚未開放,待 C2.2」
Phase 2(C2.2 ship 後補):
/ssp/<uid>/leveragedCommit:feat(project-planning): C5 SspLeveragedSection placeholder(C5 階段)/ feat(project-planning): C5.2 SspLeveragedSection full impl(C2.2 後)
內容:
Commit:feat(project-planning): C5 控制項/程序書 link 區塊
檔案:專案規劃頁 root component(pre-flight 確認檔名)
動作:
?tab=ssp§ion=... 處理Commit:feat(project-planning): C5 SSP tab + AP selector 整合
檔案:
src/config/locales/i18n/zh-tw/project-planning.jsonsrc/config/locales/i18n/en/project-planning.json新增 key:
{
"project_planning": {
"tab_ssp": "SSP",
"ssp_no_active_ap": "請先啟動 AP",
"ssp_ap_closed_hint": "此 AP 已關閉,僅可檢視",
"ssp_historical_ap_hint": "歷史 AP,僅可檢視",
"ssp_no_manager_permission": "需 manager 權限",
"section": {
"basic": "基本資料",
"scope_devices": "受評範圍 — 設備",
"scope_info_systems": "受評範圍 — 資訊系統",
"leveraged": "外部利用服務",
"parties": "參與人員",
"controls_link": "前往控制項實作",
"ref_docs_link": "前往程序書管理"
}
}
}Commit:feat(i18n): C5 project-planning SSP tab 文案
步驟:
檔案:FE repo docs/changelog/YYYY-MM-DD-feat-project-planning-ssp-tab.md
---
type: feat
breaking: false
modules: [project-planning]
---
## 需求說明
C5:專案規劃頁加 SSP tab,讓 manager 在專案內直接編輯 current AP 對應的 SSP 內容。
## 變更範圍
### FE
- 5 個新 composable: useSspContext / useSspParties / useSspResources / useSspSystemCharacteristic / useSspLeveraged
- 1 個 service: SspService
- SspTabPanel root + 5 個 section components
- AP selector + 權限 / AP 狀態雙判斷 readonly mode
- Deep link `?tab=ssp§ion=...` 支援
- i18n 文案
## UX
- Tab 切到 SSP 才 fetch(lazy load)
- 預設展開「基本資料」accordion
- 從專案詳情頁的範圍 card 點「前往 SSP 編輯」可直跳 + 自動展開 scope section
- 控制項實作 / 程序書連結既有頁面
## 後續
- Leveraged section 待 C2.2 後補
- Excel import 入口待 C2.2 後補| 測試 | 內容 |
|---|---|
| Manual smoke | 上面 T11 全 case |
| Manual smoke | Deep link 跳轉行為(從詳情頁 + 直接貼 URL) |
| Manual smoke | AP 切換 + lazy load 行為 |
| Manual smoke | 權限:manager / reviewer / auditor / viewer 四角色 UI 差異 |
| Vitest (if exists) | composable cache invalidation |
| 風險 | 緩解 |
|---|---|
| C2.1 endpoint 還沒 ship FE 撞 404 | 開工前 verify C2.1 全綠 |
| 既有 MF 元件複用後改不乾淨造成 MF 頁面 break | 複用採 複製整檔再改 ssp 版本,而非抽 base,MF 完全不動 |
| 大型 component 一次性 ship 撞 review block | 拆 commit by section(每個 section 一個 commit) |
| Deep link 與 router 行為衝突 | 用 beforeEach 或 onMounted 處理,加 unit test |
Rollback:FE-only,新增檔案,git revert 即可。專案規劃頁原本的 tab 邏輯不動。