使用者 Excel 批次匯入(User Excel Import)
功能群:系統管理|三層 RBAC 模型與租戶/部門組織模型先讀 功能群總覽 §2、§3|上層導航頁見 使用者管理
事實基準:2026-07-05 從 FE
src/views/user-manage/UserManageUpload.vue+ BEapi/auth/routes/user_import_route.py+ jedi-authimport_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-01
的 add_user 路徑);login_name 留空時以 email
prefix 自動產生 |
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 設計
📸 實機截圖待補(亮色模式)。待補清單: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-71(generate)。
[POST] /api/1.0/users/upload
Request:multipart/form-data
| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
file |
file | 是 | 上傳檔案(.xlsx/.xls/.csv) |
Excel 表頭需完全對齊 8 欄:
| 表頭欄位 | 必填 | 說明 |
|---|---|---|
帳號 |
否 | 可留空(留空時以 email prefix 自動產生) |
E-Mail |
是 | |
姓名 |
是 | 顯示名稱 |
職稱 |
是 | 職稱 |
聯絡電話 |
是 | 電話 |
租戶 |
是 | 租戶名稱 |
機關(構)單位名稱 |
是 | 部門名稱 |
角色 |
是 | 角色名稱 |
Response
data[](UserExcelUploadResponse)(陣列,每項):
| 欄位 | 型別 | 說明 |
|---|---|---|
login_name |
string | 登入代碼 |
email |
string | |
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_excel →
check_excel_import_file +
check_excel_user_data。
逐列驗證邏輯(check_excel_user_data,import_user_service.py:101-174):必填欄缺漏
→ error[field]=AUTH_401002;login_name
留空自動以 email prefix 產生,非空但已存在 →
error.login_name=AUTH_409001;tenant 名稱查無
→ error.tenant=AUTH_404005;org_unit
依「該列所選租戶」scoped 查找(同名部門可能跨租戶重複)查無 →
error.org_unit=AUTH_404004;role 同樣
tenant-scoped 查找查無 →
error.role=AUTH_404003;email 已存在 →
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 | 是 | |
nickname |
string | 是 | 顯示名稱 |
job_title |
string | 是 | 職稱 |
tel |
string | 是 | 電話 |
tenant_id |
int | 是 | 租戶 id |
org_unit_id |
int | 是 | 部門 id |
role_uid |
string | 是 | 角色 uid |
Response:BooleanResponse。BE 逐筆呼叫
user_service.add_user(非單一 DB
交易的批次寫入;user_import_route.py:79-101),每筆各自套用
使用者表單
§6.2「建立」
的完整邏輯(含自動產密碼、寄信);check_upload_payload 把
role_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.py(UserUploadRoute
/ 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_409001(login_name
已存在)、AUTH_409002(email
已存在)、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. 邊界情況與已知坑
- 本頁端點缺角色守門(同 使用者表單 §12
坑):
UserUploadRoute/UserBatchUploadRoute僅@jwt_required(),內部逐筆add_user也無角色 / 能力檢查。本 spec 只記錄不修。 - 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-authadd_user加send_email: bool參數,避免回滾後信已寄)。 - Excel 匯入的部門 / 角色驗證是 tenant-scoped
查找:
org_unit/role依「該列所選租戶」比對名稱,同名部門或角色若存在於多個租戶會依tenant_id精準比對,不會誤配到其他租戶同名項;但也代表部門 / 角色名稱建議搭配租戶命名避免使用者混淆(非 bug,屬設計限制)。 - 匯入編輯表下拉已改逐列連動(2026-07-09 FR-047
六項#3):原本租戶 / 部門 /
角色三欄各自獨立完整下拉、不連動(選了租戶
A、部門欄仍顯示全部租戶的部門)。已改逐列(非整表共用)依該列已選
tenant_id過濾部門 / 角色下拉(角色另含tenant_id為空的全域角色);換租戶清該列舊選、未選租戶時回全量避免鎖死。上傳解析階段check_excel_user_data的逐列驗證仍保留為第二道防線。 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 可見的租戶/部門/角色選項。
- E2E:
compliance-manager-test/repo(Cucumber + Playwright);本頁相關 feature 檔以批次匯入/user-import搜尋。 - 相關文件:上層導航 使用者管理;使用者表單(帳號本體 CRUD);功能群總覽。