Feature #1443
進行中Feature #1442: [功能開發] CourseProfile 後台管理 API 與 FE 交接需求
[介面修改] CourseProfile 後台管理 UI
0%
概述
目標¶
依父票 #1442 已完成的 CourseProfile 管理 API,新增後台「療程項目管理」UI。此票只處理 FE,不修改 API 或資料庫。
權限與選單¶
- 僅
administratorrole 可看到及操作。 - 選單位置:
Common Lists。 - 選單名稱:
療程項目管理。 - 使用 migration 已建立的 SS3A functions:
course_profile_mgmtcourse_profile_mgmt_listcourse_profile_mgmt_createcourse_profile_mgmt_edit
- 不提供刪除功能或刪除按鈕。
UI 設計原則¶
- Follow 現有後台其他列表頁設計與元件。
- 沿用
SectionTitle、WrapperTable、Datatable、ActionButton、Switch與既有搜尋表單元件。 - Boolean 顯示文字使用「有/無」。
- 搜尋欄位若不限制某旗標,request 不要帶該 property;不可用「全部」轉成
null或空字串送出。 -
false是有效搜尋值,不可用 truthy 判斷而漏傳。
列表頁¶
搜尋條件¶
- 關鍵字:同時搜尋名稱與 description。
- 是否啟用。
- 日誌功能。
- 滿意度調查。
- 事後關懷卡。
四個 Boolean 篩選器的可選值只有「有/無」;未選擇代表不限制,API request 不帶該欄位。
列表欄位¶
- Item ID
- 名稱
- 日誌功能(有/無)
- 滿意度調查(有/無)
- 事後關懷卡(有/無)
- 狀態
- 編輯操作
列表不顯示 Course/Booking 數量;數量只在狀態切換確認視窗顯示。
搜尋 API¶
POST /api/admin/course/profile/search
{
"page": 1,
"size": 10,
"sidx": [],
"sord": [],
"keyword": "選填",
"enabled": true,
"hasDiary": true,
"hasSatisfaction": false,
"hasPostEventCard": true
}
只有使用者已選擇的 optional Boolean 才可放入 request。
新增頁¶
欄位:
- 名稱:必填,最多 255 字元。
- Description:選填。
- 日誌功能:必填,有/無。
- 滿意度調查:必填,有/無。
- 事後關懷卡:必填,有/無。
建立前必須顯示確認視窗,列出名稱與三個建立後不可變更的旗標。取消時不得送出 request。
POST /api/admin/course/profile/create
{
"name": "必填",
"description": "選填",
"hasDiary": true,
"hasSatisfaction": false,
"hasPostEventCard": false
}
注意事項:
- 不傳
enabled,後端固定新建為false。 - 名稱會由後端 trim,且包含停用資料永久唯一。
- 名稱重複時 API 回 HTTP 409,response 含
field: "name",須將錯誤顯示在名稱欄位。 - 建立成功後回列表,資料顯示為停用。
編輯頁¶
先呼叫:
GET /api/admin/course/profile/info/{id}
顯示欄位:
- 名稱:唯讀。
- 日誌功能:唯讀。
- 滿意度調查:唯讀。
- 事後關懷卡:唯讀。
- Description:可修改。
- 是否啟用:可修改。
更新 API:
POST /api/admin/course/profile/update
{
"id": "Pxxxxxxx",
"description": "選填",
"enabled": true
}
FE 不得傳 name 或三個功能旗標。
- 只修改 description 時可直接送出 update。
- enabled 有變更時,必須先取得 impact 並顯示確認視窗;管理員確認後才送出 update。
- 管理員取消時不得送出 update,畫面狀態維持原值。
列表狀態切換¶
列表 Switch 不可先行改變畫面狀態。操作流程:
- 呼叫
GET /api/admin/course/profile/status/impact/{id}。 - 顯示確認視窗。
- 管理員確認後呼叫 status switch。
- 成功後重新取得列表或更新畫面狀態。
- 取消或 API 失敗時 Switch 回復原值。
Impact response:
{
"id": "Pxxxxxxx",
"name": "療程名稱",
"enabled": true,
"courseCount": 123,
"bookingCount": 45
}
確認視窗必須顯示:
- CourseProfile 名稱。
- Course 歷史總數。
- Booking 歷史總數。
- 啟用/停用影響說明。
提示文字語意:
- 啟用:啟用後會出現在新建 Course 與 Booking 的選單。
- 停用:停用後不再出現在新建 Course 與 Booking 的選單;既有 Course、Booking 及歷史流程不受影響。
Status switch API:
POST /api/admin/course/profile/status/switch
{
"id": "Pxxxxxxx",
"newStatus": false
}
API 清單¶
POST /api/admin/course/profile/searchGET /api/admin/course/profile/info/{id}POST /api/admin/course/profile/createPOST /api/admin/course/profile/updateGET /api/admin/course/profile/status/impact/{id}POST /api/admin/course/profile/status/switch
Backend branch:feature/redmine-1442-course-profile-admin
Backend commits:3cb9c49、d9d2a0b、438da92、6520c0c
API 測試報告:test_report/20260817_redmine_1442_course_profile_admin.md
驗收條件¶
- 非 administrator 看不到選單,且不能進入功能頁。
- 列表、搜尋、分頁、排序 follow 現有後台設計。
- keyword 可搜尋名稱與 description。
- 未選 Boolean 時不帶 property;選「無」時正確傳
false。 - 新增前顯示確認視窗;新資料固定停用。
- 編輯頁名稱與三旗標不可修改。
- 列表與編輯頁修改 enabled 前都顯示 impact 確認視窗。
- 確認視窗顯示 Course/Booking 數量與影響說明。
- 取消操作不得改變資料或 Switch 畫面狀態。
- 名稱重複錯誤能對應到名稱欄位。
- 不出現 delete 操作。
環境注意事項¶
截至 2026-08-17,公開 staging API hm-api.line2me.tw 回 HTTP 503。開始串接前請先確認父票分支已部署且 staging API 恢復。
是由 鍾正剛 於 約 1 個月 前更新
開發完成(FE)¶
branch: feature/issue-1443-course-profile-admin-ui(自 main 開,未合併)
commits: 048b3de 實作、cc7965b code review 修正
一、實作內容¶
頁面位於 react/admin/app/common/course-profile/,對應 migration 的 function_url。
- 列表:關鍵字(名稱/說明)+ 是否啟用、日誌功能、滿意度調查、事後關懷卡四個篩選;欄位為 Item ID、名稱、三旗標(有/無)、狀態、編輯;沿用既有 SectionTitle/WrapperTable/Datatable/ActionButton/Switch,未提供任何刪除功能。
- 搜尋 request:未選擇的 Boolean 不會出現在 request 中,選「無」會送出真正的
false。此段邏輯(helper.js的buildSearchPayload)另外寫了驗證,並以「故意改成 truthy 判斷」反向確認驗證確實會失敗。 - 新增:送出前二次確認名稱與三個不可變更旗標,取消不送 request;payload 不含
enabled。 - 編輯:名稱與三旗標唯讀且不進入 payload,update 只送
{id, description, enabled};enabled未變更直接送出,有變更則先取 impact 確認。 - 狀態切換:Switch 畫面狀態完全由查詢結果決定,不先行改變;流程為 impact → 確認視窗 → switch → refetch,取消或失敗皆不改變畫面。
- 確認視窗顯示 CourseProfile 名稱、Course 歷史總數、Booking 歷史總數,以及啟用/停用的影響說明。
- 名稱重複(HTTP 409,body
field: "name")顯示於名稱欄位,不跳共用錯誤視窗。
二、與票面規格的補充說明¶
驗收條件的「非 administrator 不能進入功能頁」,現行 admin 專案沒有任何 page 層級的權限守衛,既有模組都只靠選單隱藏加後端 403。本次在本模組內加了一個 guard:讀取後端回傳的選單樹,比對不到對應的 function url 就顯示 403 區塊。
刻意未沿用既有的 src/components/auth/not-allowed,因為該元件會 redirect('/signin'),會把已登入但無此權限的管理員直接登出。
此 guard 僅作用於本模組,未改動其他模組;若日後要全站套用再抽共用元件。
三、驗證範圍¶
-
yarn lint:0 error。 - 三條新路由於 dev server 均編譯成功。
- 搜尋 payload 組裝邏輯:16 項檢查全數通過。
- 未執行:六支 API 的實際串接驗證,需 administrator token,待人工於瀏覽器登入後確認。
四、與本票無關的既有問題¶
react/admin 的 yarn build 目前失敗:
static/chunks/0e02fca3-*.js from Terser
invalid unicode code point at line 1 column 562193
已在乾淨的 main(未含本次變更)重現,錯誤與位移完全相同,確認為既有問題、非本次造成。目前此專案無法產出 production build,建議另開票處理。