本卡屬 FR-164(母卡見「母卡」欄),批 1。做控制項視圖右邊的兩個子元件與兩支 composable,全部新增檔、不碰既有檔;資料用 provide/inject 從總覽頁拿(本卡定 key,FR-164.3 才在總覽頁 provide)。畫面以雛形為準。
右上「參考資料」:只讀。選群組顯示群組描述與統計;選控制項顯示條文、現況說明(實作狀態、現況描述、備註、參考程序書);選評估目標顯示條文、評估目標現況,右邊仍帶控制項現況說明。整塊可收起只留標題列。沒有任何按鈕。
右下「任務」:永遠一張平表、一列一個任務。欄:任務名、位置(控制項代號+[a]+條文全文、不截斷)、負責人、證據數(AI 徽章)、狀態、操作(「⚡ 執行」或「開啟 ›」)。工具列:篩選(全部/待我執行/未完成/已完成)、分群(不分群/依控制項/依評估目標,預設跟著左邊選的層走)。分群時同一張表插小標列,審閱鈕長在小標列上;不分群時審閱鈕在標題列右側。表內沒有任何展開收合。
~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/composables/useControlView.js provide/inject key+型別註解(總覽頁要給的資料與函式清單,見下)
~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/components/grc/control-view/ControlReferencePane.vue 右上
~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/components/grc/control-view/ControlTaskTable.vue 右下(含標題列、工具列、DataTable)
~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/components/grc/control-view/useControlTaskRows.js 攤平、篩選、分群、摘要(純函式,可單測)
~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/components/grc/control-view/__tests__/useControlTaskRows.spec.js 攤平與分群的單測(本卡屬核心共用邏輯,要寫)
只讀參考:
~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/components/grc/evidence-view/EvidenceTable.vue DataTable 分群小標列(rowGroupMode="subheader"、groupheader slot、pt colspan 陷阱)
~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/components/grc/evidence-view/EvidenceListHeader.vue 標題列+工具列分段鈕樣式
~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/components/grc/evidence-view/useEvidenceTableRows.js 攤平+分群的寫法
~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/components/grc/planning/AoJobSection.vue 任務列的欄位、canRead 守門(:34-36)、executable-dot
~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/views/project/ProjectAuditorOverview.vue:1557-1605 群組層 header 卡+統計(只讀參考)
~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/views/project/ProjectAuditorOverview.vue:1854-1900 控制項現況說明區(SspStatusTag/sspDescriptions/sspRemarks/ReferenceDocumentList;群組層同款在 1676-1722)
~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/views/project/ProjectAuditorOverview.vue:1741-1780 評估目標 header(aoStatusFromAo/aoTaskCount/審閱鈕 tooltip 規則在 1765-1773)
~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/views/project/ProjectAuditorOverview.vue:659-700, 773-800 toggleReviewed/toggleAoReviewed/reviewersTooltip/canUnreview
useControlView.js:export const CONTROL_VIEW_KEY = Symbol('control-view');註解列出 inject 物件的形狀:{ groups, controlsMap, controlDetailMap, controlsLoadingSet, controlDetailLoadingSet, sspDescriptions, sspStatuses, sspRemarks, controlReferenceDocuments, sspDetailLoading, controlReviewMap, aoReviewMap, reviewLoading, isPlanningPhase, isApClosed, readonlyReason, userInfo, fetchControls, fetchControlDetail, fetchSspDetail, toggleReviewed, toggleAoReviewed, canReviewControl, canUnreview, reviewersTooltip, writeDisabled, jobIsExecutable, hasAiEvidence, openJobDrawer }——名字與總覽頁現有的一模一樣,FR-164.3 才 provide。ControlReferencePane.vue:props scope({level, groupId, controlId?, aoId?},與 EvidenceNavTree 的 select 事件同形)、collapsed(v-model)。標題列照 EvidenceNavTree 的 .evidence-nav__title 同款(icon+「參考資料」+副標+右側路徑+收起鈕)。內容三種層級照 design.md「右上:參考資料」段;控制項與評估目標層的現況說明區塊直接沿用舊面板 :1854-1900 的結構(SspStatusTag、ReferenceDocumentList :readonly="true")。選到控制項或評估目標時呼叫 fetchSspDetail(controlId)(既有,有快取)。useControlTaskRows.js:輸入 { scope, groups, controlsMap, filter, groupBy, myTasksOnly, jobIsExecutable },輸出 { rows, summary, groupByOptions }。rows 每筆 { kind:'job'|'seg-ctrl'|'seg-ao'|'empty', job?, ao, ctrl, group, segKey },seg-* 是分群小標列,empty 是分群下該評估目標無任務的佔位列(照 EvidenceTable.vue 的 ev-placeholder-row 做法,顯示「尚無任務」)。groupBy 預設:scope.level==='group'→'ctrl'、'control'→'ao'、'ao'→'none';使用者改過記在 Map<level, value>。summary={done,total,execN}。ControlTaskTable.vue:標題列「任務」+done/total 已完成+execN 待我執行(橘字,0 不顯示);工具列篩選 全部|待我執行|未完成|已完成 與分群,分段鈕樣式照 EvidenceListHeader.vue 的 .ev-seg;不分群且 scope 非群組時標題列右側放審閱鈕(對 scope 那一層)。表格 DataTable class="p-datatable-sm" scrollable scrollHeight="flex",分群用 rowGroupMode="subheader" groupRowsBy="segKey"(注意 EvidenceTable.vue:21-23 的 colspan 陷阱)。pi pi-check-circle(完成,綠)/pi pi-circle(未完成,灰)+名稱;位置=scope.level==='group':控制項代號小字+tag-code [a]+條文(white-space:normal,不截斷);'control':[a]+條文;依評估目標分群或 'ao' 時整欄不顯示(欄寬給任務名)。負責人=UserAvatar size="sm" 最多兩個+「+N」,單人加名字;證據=pi pi-paperclip N(0 用 text-color-secondary)+SourceBadge source="AI_CLASSIFIED"(hasAiEvidence(job));狀態=StatusBadge :status="job.status";操作=jobIsExecutable(job) && !writeDisabled() 顯示 Button size="small" icon="pi pi-bolt" label="執行"(severity warning),否則 Button outlined size="small" label="開啟" icon="pi pi-chevron-right" iconPos="right"。列與兩顆鈕都 openJobDrawer(job, ctx),ctx 照總覽頁 :1803-1808 的形狀;沒 $can(CAP.GRC_JOB_READ) 不接點擊(照 AoJobSection.vue:34-36)。seg-ctrl=代號徽章+名稱+⚡(ctrlHasExecutableJob)+done/total+StatusBadge(ctrlStatusFromAos)+審閱鈕(文字版);seg-ao=[a]+條文(換行)+⚡+done/total+小圓點狀態+審閱鈕(icon 版,v-tooltip)。審閱鈕規則整段照舊面板 :1765-1773(評估目標)與 :1659-1667(控制項):canReviewControl 才顯示、v-can="CAP.GRC_AUDIT_APPROVE"、未完成 disabled+tooltip、已審閱非本人 disabled+tooltip、:loading="reviewLoading.has(key)"、writeDisabled(...)。小標列底色照 EvidenceTable.vue 的 .p-rowgroup-header td(--bg-base+上下 1px 線)。ctrlStatusFromAos/aoStatusFromAo/aoTaskCount 這三支狀態推導目前在總覽頁 :723-760,是純函式——搬到 useControlTaskRows.js export(FR-164.3 刪舊面板時總覽頁就不需要它們了;若總覽頁其他地方還用,.3 改成 import)。rows 只留 jobIsExecutable 的任務、只留有這種任務的控制項/評估目標(與左樹同一判準)。useControlTaskRows.spec.js:① 群組層預設依控制項分群,小標列順序=控制項順序、每個小標後跟它的任務;② 控制項層預設依評估目標、無任務的評估目標出 empty 列;③ 評估目標層不分群、groupByOptions 為空;④ 篩選「待我執行」只留 jobIsExecutable 為真的;⑤ 使用者改過分群後切層再切回來,記住的值仍在;⑥ summary 的 done/total 不含 CANCEL。突變測試:把 ① 的預設值改成 'none' 要紅。GET /ssp/<ssp_uid>/control-tree,DEV 專案 6bfe7e29-…)當 inject 資料,渲染 ControlTaskTable 與 ControlReferencePane 三個層級各一次,截圖存 docs/features/FR-164-control-view-redesign/screenshots/。