手冊首頁 / 租戶與組織 / 使用者 Excel 批次匯入

使用者 Excel 批次匯入(User Excel Import)

功能群:系統管理|三層 RBAC 模型與租戶/部門組織模型先讀 功能群總覽 §2、§3|上層導航頁見 使用者管理

事實基準:2026-07-05 從 FE src/views/user-manage/UserManageUpload.vue + BE api/auth/routes/user_import_route.py + jedi-auth import_user_service.py + 主專案 app/auth/service/user_import_template_app_service.py + routes.json / db_schema.json 掃出。

變更紀錄

日期 FR 變更
2026-07-06 FR-047 user-manage.md 拆出:Excel 批次匯入精靈(Tab1)獨立成子頁
2026-07-09 FR-047 已知坑修復:批次匯入改單一交易(R-3);匯入編輯表下拉改逐列連動(六項#3)

1. 功能描述

Excel 批次匯入是 使用者管理Tab1「Excel 批次上傳」UserManageUpload.vue),把整批帳號透過 xlsx 一次建立。三步式精靈:Step1 下載範本 → 選檔上傳解析;Step2 預覽逐列驗證 → 線上修正重驗 → 勾選批次建立。批次建立時逐筆呼叫 add_user(非單一 DB 交易),每筆各自套用帳號建立的完整邏輯(自動產密碼、寄信)。

主要使用者:系統 / 租戶管理員。

角色速覽(完整定義見 _overview §2、§3):

角色 一句話
系統 / 租戶管理員(可見本選單者) 下載範本 + 批次匯入
一般使用者 無此選單(ui_routes 可見性未命中)

1.1 功能總覽(本頁全部功能)

# 功能 說明 位置 詳述
1 Excel 範本下載 依下載者 RLS 動態產生下拉選項(租戶 / 部門 / 角色)的 xlsx 範本 Step1 §6.2
2 Excel 拖放上傳 / 選檔上傳 選檔即自動上傳解析,僅接受 .xlsx/.xls/.csv Step1 UC-USER-03
3 匯入預覽逐列編輯 / 重驗 Step2 DataTable 可 row-edit,存檔即呼叫單筆 validate 重新檢核 Step2 UC-USER-03
4 匯入錯誤欄位提示 有錯欄位以紅字按鈕呈現,點擊彈出對應 i18n 錯誤訊息 Step2 UC-USER-03
5 勾選批次建立 僅送出勾選列,逐筆呼叫新增使用者(非單一批次 API) Step2 UC-USER-03
6 移除選取列 從待匯入清單中移除(僅前端清單,不動 DB) Step2
7 重新上傳 清空目前解析結果,回到 Step1 Step2

展開成 UC:UC-USER-03(Excel 批次匯入三步)。帳號本體 CRUD 與授權組合見 使用者表單

2. Use Case

角色速覽(完整定義見 _overview §2、§3):

角色 一句話
系統 / 租戶管理員(可見本選單者) 下載範本 + 批次匯入
一般使用者 無此選單

流程圖視覺慣例:菱形 = 判斷、橘底 = 例外/擋下、紅框 = 錯誤(標 error code)、綠框 = 成功終點。

UC-USER-03 Excel 批次匯入

項目 內容
角色 具本頁可見性的管理員
前置條件 檔案格式為 .xlsx/.xls/.csv;表頭需與範本 8 欄一致
產出 / 後置條件 勾選列逐筆呼叫新增使用者(同 UC-USER-01add_user 路徑);login_name 留空時以 email prefix 自動產生
user_import start Tab1 Excel 批次上傳(Step1) dl 下載範本 GET /user/download/sample 依下載者 RLS 動態產生租戶/部門/角色下拉 start->dl pick 選檔或拖放 (僅接受 .xlsx/.xls/.csv) dl->pick fmtchk 副檔名格式檢查 pick->fmtchk fmterr 擋下:invalid_file 提示 fmtchk->fmterr 不符 upload POST /users/upload 解析 8 欄表頭 + 逐列驗證 fmtchk->upload 符合 hdrchk BE 檢查:表頭是否對齊 8 欄? upload->hdrchk hdrerr 400 AUTH_400001 Excel Header不符合規範 hdrchk->hdrerr 不符 step2 Step2 預覽表格 每列附 error{欄位:碼},紅字按鈕顯示 hdrchk->step2 符合 edit 使用者 row-edit 修正某列 step2->edit select 勾選欲建立的列(可先移除不要的列) step2->select 無需修正可直接勾選 revalidate POST /user/validate(單筆重驗) 回填新的 error edit->revalidate stillerr 該列仍有 error? revalidate->stillerr stillerr->edit 是(迴圈修正) stillerr->select batch POST /user/batch-upload 逐筆呼叫 add_user(各自獨立交易,非單一批次) select->batch partial 某列失敗(如 500)? batch->partial partialwarn 前面已成功的列不會回滾 FE 未特別處理部分失敗 partial->partialwarn ok 成功 → toast + 觸發列表 reload partial->ok 否(全數成功) partialwarn->ok
UC-USER-03 流程:下載範本→上傳解析→逐列驗證回填 error→線上修正重驗→勾選批次建立(逐筆 add_user,非單一交易)

3. 權限矩陣

專案層 RBAC 基調見 _overview §5。本頁的實際檢查點:

操作 FE 判定 BE 強制 BE 檢查位置
Excel 批次上傳 / 驗證 / 建立 有上傳按鈕即可 ⚠️ 僅 @jwt_required user_import_route.py(全部 route)
下載匯入範本 同上 ⚠️ 僅 @jwt_required;範本內容依 RLS 動態產生(見 §12) user_import_route.py:60-76

⚠️ 本頁端點缺角色守門UserUploadRoute / UserBatchUploadRoute 皆只掛 @jwt_required(),批次建立內部逐筆呼叫的 add_user 亦無角色檢查——與 使用者表單 §3_overview §5 一致(本群多頁通病)。收進 §12。

4. 狀態機與前置條件

帳號本身狀態見 使用者管理 §4。本頁無獨立狀態機;精靈步驟由 users.length 是否 > 0 自動判定停留在 Step1(上傳)或 Step2(預覽),以 Steps 元件呈現。批次建立時 check_upload_payload 固定塞入 effective_date=今天 / expire_date=一年後

5. UI 設計

Steps: ① 上傳 ——— ② 預覽(依 users.length > 0 自動判定) 開啟:§6.2 Excel 批次匯入(下載範本/上傳解析) Step1 · 下載範本 → 上傳 下載範本(依 RLS 動態產下拉:租戶/部門/角色) GET /user/download/sample 拖放 / 選檔(.xlsx/.xls/.csv,選檔即上傳) POST /users/upload → 解析+逐列驗證 開啟:§6.2 Excel 批次匯入(逐列重驗/批次建立) Step2 · 預覽逐列編輯 DataTable row-edit,存檔即單筆重驗 POST /user/validate(單筆) 錯誤欄位=紅字按鈕(點擊彈 i18n 錯誤碼) 勾選列 → 批次建立(逐筆 add_user,非單一交易) POST /user/batch-upload Step2 動作:勾選批次建立 | 移除選取列(僅前端清單)| 重新上傳(清空回 Step1) 逐列驗證(check_excel_user_data): 必填缺→AUTH_401002|login_name 已存在→409001|email→409002|tenant→404005|org_unit(tenant-scoped)→404004|role→404003 login_name 留空 → 以 email prefix 自動產生;org_unit/role 皆依該列所選租戶 scoped 比對 彩色=可點跳本頁 §6.2 錨點(teal=Step1 範本/上傳・coral=Step2 重驗/批次建立)|灰=結構描述|虛線框=dropzone API 僅列代表性,完整規格見 §6
使用者 Excel 匯入版面 wireframe:Step1 下載範本+dropzone、Step2 預覽 DataTable(錯誤欄位紅字)+勾選/移除/重新上傳;三步各標對應 endpoint

📸 實機截圖待補(亮色模式)。待補清單:Step1 上傳 dropzone、Step2 預覽表格(含錯誤欄位紅字態)。

狀態呈現:Excel 匯入用 Steps 元件呈現目前在 Step1(上傳)或 Step2(預覽),依 users.length 是否 > 0 自動判定。

6. API 規格

Envelope:成功 {"code": 1, "data": …}、失敗 {"code": 0, "msg": "…"}

6.1 總清單(本頁呼叫的全部 endpoint)

分類 Method + Path 說明 完整規格
批次匯入 GET /api/1.0/user/download/sample 下載範本(依下載者 RLS 動態產生下拉選項) §6.2
批次匯入 POST /api/1.0/users/upload 上傳 Excel、解析 + 逐列驗證回傳預覽 §6.2
批次匯入 POST /api/1.0/user/validate 單筆重新驗證(Step2 row-edit-save 觸發) §6.2
批次匯入 POST /api/1.0/user/batch-upload 批次建立(逐筆呼叫 add_user,非單一交易) §6.2

帳號 CRUD / 列表端點見 使用者表單 §6使用者管理 §6

6.2 Excel 批次匯入(request / response)

四支端點串成三步精靈(下載範本 → 上傳解析 → 逐列重驗 → 批次建立):

[GET] /api/1.0/user/download/sample

無 query 參數。回傳 xlsx 檔(user_batch_import_sample.xlsx),依下載者 RLS 可見範圍動態產生「租戶 / 機關(構)單位名稱 / 角色」三欄的隱藏 sheet 下拉選項(平表下拉,非 INDIRECT 連動)。出處:app/auth/service/user_import_template_app_service.py:48-71generate)。

[POST] /api/1.0/users/upload

Request:multipart/form-data

欄位 型別 必填 說明
file file 上傳檔案(.xlsx/.xls/.csv

Excel 表頭需完全對齊 8 欄:

表頭欄位 必填 說明
帳號 可留空(留空時以 email prefix 自動產生)
E-Mail Email
姓名 顯示名稱
職稱 職稱
聯絡電話 電話
租戶 租戶名稱
機關(構)單位名稱 部門名稱
角色 角色名稱

Response data[]UserExcelUploadResponse)(陣列,每項):

欄位 型別 說明
login_name string 登入代碼
email string Email
nickname string 顯示名稱
job_title string 職稱
tel string 電話
tenant string 租戶名稱
tenant_id int 租戶 id
org_unit string 部門名稱
org_unit_id int 部門 id
role string 角色名稱
role_uid string 角色 uid
error dict[str,str] 逐列驗證錯誤(欄位名 → error code)

出處:api/auth/routes/user_import_route.py:28-43 → jedi-auth ImportUserService.import_user_from_excelcheck_excel_import_file + check_excel_user_data

逐列驗證邏輯check_excel_user_dataimport_user_service.py:101-174):必填欄缺漏 → error[field]=AUTH_401002login_name 留空自動以 email prefix 產生,非空但已存在 → error.login_name=AUTH_409001tenant 名稱查無 → error.tenant=AUTH_404005org_unit 依「該列所選租戶」scoped 查找(同名部門可能跨租戶重複)查無 → error.org_unit=AUTH_404004role 同樣 tenant-scoped 查找查無 → error.role=AUTH_404003email 已存在 → error.email=AUTH_409002

[POST] /api/1.0/user/validate

Request:單筆 UserExcelUploadResponse(exclude error)body(Step2 row-edit-save 後送出該列新值)。Response:同 UserExcelUploadResponse(重新跑一次上述驗證,回填新的 error)。出處:user_import_route.py:46-57

[POST] /api/1.0/user/batch-upload

Request:list[UserExcelUploadRequest](僅送「驗證通過、使用者勾選」的列),每項欄位:

欄位 型別 必填 說明
login_name string 登入代碼
email string Email
nickname string 顯示名稱
job_title string 職稱
tel string 電話
tenant_id int 租戶 id
org_unit_id int 部門 id
role_uid string 角色 uid

Response:BooleanResponseBE 逐筆呼叫 user_service.add_user(非單一 DB 交易的批次寫入;user_import_route.py:79-101),每筆各自套用 使用者表單 §6.2「建立」 的完整邏輯(含自動產密碼、寄信);check_upload_payloadrole_uid 轉成單筆 user_roles=[{..., is_default:true}],並固定塞入 effective_date=今天 / expire_date=一年後。出處:import_user_service.py:195-225

7. 前端檔案地圖(compliance-manager-fe/)

檔案 角色
src/views/user-manage/UserManageTabView.vue route user-manage 的實際 component;包兩個 Tab(帳號管理 / Excel 批次上傳)
src/views/user-manage/UserManageUpload.vue Tab1:Excel 批次上傳兩步精靈(Step1 上傳 / Step2 預覽編輯)
src/config/api/api.js:32-42 USER_BATCH_UPLOAD / USER_VALIDATE / DOWNLOAD_USER_EXCEL_SAMPLE / UPLOAD_USER_EXCEL 端點常數

8. 後端檔案地圖

鏈路 Route App Service 底層
Excel 匯入三步 api/auth/routes/user_import_route.pyUserUploadRoute / UserValidateRoute / UserBatchUploadRoute 直接委派 jedi-auth import_user_service.py
匯入範本下載 同檔 UserUploadSampleDownloadRoute app/auth/service/user_import_template_app_service.py::generate主專案自有,依 RLS 動態產生 xlsx) tenant_service / org_unit_service / role_service(皆 jedi-auth)

DDD 提醒:批次匯入 route 直接注入 jedi-auth 的 ImportUserService;主專案在這條鏈路唯一自建邏輯是 UserImportTemplateAppService(範本產生,依 RLS 動態組 xlsx 下拉)。改行為要分清邊界(CLAUDE.md 外部套件異動規範)。

9. DB

9.1 資料表總清單(本頁讀寫的全部表)

讀/寫 說明 詳述
public.users (透過 add_user 逐筆) 帳號本體 使用者表單 §9.3
public.user_roles (透過 add_user 授權組合(role_uid 轉單筆 is_default:true 使用者表單 §9.3
public.user_tenants / public.user_org_units (透過 add_user 租戶 / 部門歸屬 使用者表單 §9.1
public.tenants 範本下拉、逐列 tenant 名稱比對 _overview §6
public.org_units 範本下拉、逐列 org_unit(tenant-scoped)比對 _overview §6
public.roles 範本下拉、逐列 role(tenant-scoped)比對 role-manage.md §9

9.2 ER 圖

批次匯入不新增資料表,寫入路徑與 使用者表單 §9.2 相同(逐筆走 add_user);讀取範本用的租戶 / 部門 / 角色屬唯讀依賴。

10. 頁面邏輯與資料對應

儲存流程Step2 row-edit-save 呼叫 /user/validate 單筆重驗 → 勾選列送 /user/batch-upload 逐筆建立。

錯誤對應:BE error envelope → toast / 逐列紅字按鈕;常見碼:AUTH_409001login_name 已存在)、AUTH_409002email 已存在)、AUTH_404005(租戶不存在)、AUTH_404004(部門不存在)、AUTH_404003(角色不存在)、AUTH_401002(Excel 必填欄未填)、AUTH_400001(Excel 表頭不符)、AUTH_400002(Excel 資料為空)。

11. 背景行為與外部依賴

類型 內容
通知 每筆建立成功 → 寄送帳號建立信(同 使用者表單 §11
Job / 排程
Socket
jedi-* 套件 jedi-auth ImportUserService 擁有解析 / 驗證 / 批次建立邏輯;主專案僅範本產生 wrapper
系統參數 USER_EXCEL_UPLOAD_DIR(環境設定)決定上傳檔案暫存路徑

12. 邊界情況與已知坑

  1. 本頁端點缺角色守門(同 使用者表單 §12 坑):UserUploadRoute/UserBatchUploadRoute@jwt_required(),內部逐筆 add_user 也無角色 / 能力檢查。本 spec 只記錄不修
  2. Excel 批次建立已改單一交易(2026-07-08 FR-047 R-3(a)):原本 POST /user/batch-upload 對每列各自呼叫 add_user()(各自獨立 @transaction 各自 commit),第 N 列失敗前 N-1 列不回滾。已改走主專案 user_batch_import_app_service——_persist_batch 以單一 @transaction 整批寫入(任一列失敗整批回滾、錯誤帶「第 N 列」前綴);密碼信移到 commit 後統一寄(jedi-auth add_usersend_email: bool 參數,避免回滾後信已寄)。
  3. Excel 匯入的部門 / 角色驗證是 tenant-scoped 查找org_unit / role 依「該列所選租戶」比對名稱,同名部門或角色若存在於多個租戶會依 tenant_id 精準比對,不會誤配到其他租戶同名項;但也代表部門 / 角色名稱建議搭配租戶命名避免使用者混淆(非 bug,屬設計限制)。
  4. 匯入編輯表下拉已改逐列連動(2026-07-09 FR-047 六項#3):原本租戶 / 部門 / 角色三欄各自獨立完整下拉、不連動(選了租戶 A、部門欄仍顯示全部租戶的部門)。已改逐列(非整表共用)依該列已選 tenant_id 過濾部門 / 角色下拉(角色另含 tenant_id 為空的全域角色);換租戶清該列舊選、未選租戶時回全量避免鎖死。上傳解析階段 check_excel_user_data 的逐列驗證仍保留為第二道防線。
  5. login_name 留空自動由 email prefix 產生:留空欄非錯誤;但若同批多列共用同一 email prefix(不同 domain)會產生相同 login_name → 第二列起 AUTH_409001

13. 開發與驗證

  • 跑起來:BE python main_socketio.py(port 8000,log 在 log/app.log);FE 在 compliance-manager-fe/ 起 Vite dev server。BE 改 service code 後必須重啟
  • 測試帳號:管理員帳號見 memory reference_dev_login / .env(憑證不寫入本文件)。
  • 導航路徑:登入 → 側選單「系統管理」→「使用者管理」(/auth/user-manage)→ Tab「Excel 批次上傳」。
  • 前置資料:Excel 匯入需先下載範本取得目前 RLS 可見的租戶/部門/角色選項。
  • E2Ecompliance-manager-test/ repo(Cucumber + Playwright);本頁相關 feature 檔以 批次匯入 / user-import 搜尋。
  • 相關文件:上層導航 使用者管理使用者表單(帳號本體 CRUD);功能群總覽