本卡屬 FR-169(母卡 (建卡後補 Case No)),卡 F1,批 2。只改 FE(compliance-manager-fe)。依賴:P1。
前端這邊做「看得到效果」的最小一段:①一個共用對話框元件 ProtectedDownloadDialog——照雛形畫面①:提示「密碼只顯示這一次」、密碼框、複製鈕、按過複製「下載」鈕才亮、7z 格式多一句「要用 7-Zip 或 Keka 開」;②一支共用 composable useProtectedDownload——先看安全政策開關(開啟才跳對話框),在瀏覽器端產 16 碼密碼,確認後把密碼放 HTTP header 送出去下載,密碼不進 URL、不進 Pinia、不進 localStorage,下載完清掉;③安全政策頁「登入」段後面加一個「檔案下載保護」開關(照兩階段驗證那個開關的寫法),關閉時頁頂出現警示;④先把稽核計畫與結案報告兩處下載改走它。i18n 的 key 本卡一次佔好,後面 F2 只接線不碰 i18n。
new:src/composables/useProtectedDownload.js(先問 /security-policy 開關快取;開啟→開 ProtectedDownloadDialog 產密碼(crypto.getRandomValues,16 碼四段去 0O1lI)→確認後 axios blob 帶 X-File-Password;關閉→直接下載;檔名用既有 filenameFromHeaders、下載用既有 downloadBlob),取代各 composable 內重複的 axios blob 段。new:src/components/common/ProtectedDownloadDialog.vue(照雛形①:提示列、密碼框、複製後下載鈕才亮、7z 提醒依 needs7zip 顯示)。extend:SecurityPolicyForm.vue 登入段後加「檔案下載保護」InputSwitch(照 MFA 那段形狀)+關閉時頁頂 Message 警示;useApExportDownload.js、useClosingReport.js 改走新 composable。i18n 兩語言 key 本卡一次佔好(含 F2 會用的)
repo:~/Projects/Billows/Audit-Manager/compliance-manager-fe
改既有:src/composables/useApExportDownload.js
改既有:src/composables/useClosingReport.js
改既有:src/views/security-policy/SecurityPolicyForm.vue
改既有:src/config/locales/i18n/zh-tw/security-policy.json
改既有:src/config/locales/i18n/en/security-policy.json
改既有:src/config/locales/i18n/zh-tw/common.json
改既有:src/config/locales/i18n/en/common.json
新開:src/composables/useProtectedDownload.js
新開:src/components/common/ProtectedDownloadDialog.vue
src/components/common/ProtectedDownloadDialog.vue:PrimeVue Dialog,props visible/password/needs7zip/fileLabel,emits confirm/cancel;版面照雛形 prototype/index.html 畫面①(hint-bar+密碼框+複製鈕+說明一行),不照抄雛形樣式(字級與卡片用全站基準,grep border-left 必為 0);複製用 navigator.clipboard.writeText,不存在(http+IP)退回 document.execCommand('copy');下載鈕 :disabled="!copied"。src/composables/useProtectedDownload.js:download(url, params, fallbackName, {needs7zip})——讀 useSecurityPolicyStore().fileDownloadProtection(新 store 或掛既有 settings store,登入後載一次 GET /security-policy,安全政策頁存檔後刷新);關閉→直接 axios blob;開啟→產密碼(crypto.getRandomValues(new Uint8Array(16)) 映射到去 0O1lI 字母表、四段)→ 開對話框 → confirm 後 axios.get(url,{params,responseType:'blob',headers:{'X-File-Password':pw},meta:{withHeaders:true}}) → 既有 filenameFromHeaders+downloadBlob → 清 pw。錯誤由既有 interceptor 跳。SecurityPolicyForm.vue:登入段後加 InputSwitch 綁 form.FILE_DOWNLOAD_PROTECTION(:trueValue="true" :falseValue="false",照 MFA 那段)+ hint;form.value 初始化與送出兩處加這個 key;頁頂 <Message severity="warn"> 當值為 false 時顯示「檔案下載保護已關閉」。useApExportDownload.js 與 useClosingReport.js 的 blob 段改呼叫 composable;AP 的 zip 與 closing bundle 傳 needs7zip: true。security-policy.json 加 file_download_protection/_hint/_off_warning;common.json 加 protected_download.*(title/hint/copy/copied/download/cancel/needs_7zip/open_hint)兩語言;FE error-code.json 加 B1 的新碼。http://<本機 IP>:5173 非 localhost 開頁:crypto.getRandomValues 可用、複製退路可用。稽核計畫頁按匯出 Word:對話框顯示 19 字元密碼、「下載」鈕灰到按「複製」才亮、下載後對話框關閉;DevTools Network 看請求 header 有 X-File-Password、URL 無密碼;localStorage/Pinia 無密碼;再按一次密碼不同;匯出 ZIP 對話框多 7-Zip 提醒;安全政策頁多一個開關、關掉存檔後頁頂出現警示、再按匯出不跳對話框;grep -rn border-left src/components/common/ProtectedDownloadDialog.vue 為 0;http://<IP>:5173 非 localhost 開頁實測 crypto.getRandomValues 可用
~/Projects/Billows/Audit-Manager/compliance-manager-be/docs/features/FR-169-2610-download-file-encryption/design.md §3 決策、§5 詳細設計、§6 拆分表本卡那列~/Projects/Billows/Audit-Manager/compliance-manager-be/docs/features/FR-169-2610-download-file-encryption/prototype/index.html(畫面①對話框、②開關、②b 關閉警示、③Agent、④稽核)~/Projects/Billows/Audit-Manager/compliance-manager-be/docs/analysis/2026-10-29-download-file-encryption-approach.md