w-web-sso 1.1.14 → 1.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +77 -0
  2. package/dist/css/{app.f000459f.css → app.c117e572.css} +1 -1
  3. package/dist/index.tmp +1 -1
  4. package/dist/js/app-legacy.0e1b6835.js +1 -0
  5. package/dist/js/app.0e1b6835.js +1 -0
  6. package/dist/js/{chunk-vendors.97013ddc.js → chunk-vendors-legacy.b81fc7a8.js} +3 -3
  7. package/dist/js/{chunk-vendors-legacy.97013ddc.js → chunk-vendors.b81fc7a8.js} +3 -3
  8. package/dist/w-web-sso.umd.js +4 -4
  9. package/dist/w-web-sso.umd.js.map +1 -1
  10. package/docs/WWebSso.html +1 -1
  11. package/docs/global.html +1 -1
  12. package/docs/index.html +1 -1
  13. package/docs/server_WWebSso.mjs.html +33 -1
  14. package/docs/server_getIgnoredOrmKeys.mjs.html +1 -1
  15. package/docs/server_lockSave.mjs.html +1 -1
  16. package/docs/server_ormWrite.mjs.html +1 -1
  17. package/docs/server_staLogs_resolveShellWorker.mjs.html +1 -1
  18. package/docs/server_wrapTimer.mjs.html +1 -1
  19. package/docs/src_components_Common_CheckYesNo.vue.html +1 -1
  20. package/docs/src_fetchSsoMsg.mjs.html +1 -1
  21. package/docs/src_httpGetJson.mjs.html +1 -1
  22. package/docs/src_maskUrl.mjs.html +1 -1
  23. package/docs/src_plugins_staUsage.mjs.html +1 -1
  24. package/docs/src_plugins_submitGuard.mjs.html +1 -1
  25. package/package.json +2 -2
  26. package/server/WWebSso.mjs +32 -0
  27. package/server/procCore.mjs +552 -172
  28. package/server/procLang.mjs +114 -4
  29. package/server/procStaInfor.mjs +18 -0
  30. package/src/appUsage.mjs +115 -0
  31. package/src/components/AppTokenAddDialog.vue +384 -0
  32. package/src/components/LayoutContentTokens.vue +147 -76
  33. package/src/components/PageLogin.vue +3 -3
  34. package/src/getUserByToken.mjs +4 -1
  35. package/src/getUserByUserId.mjs +2 -1
  36. package/src/getUsersByToken.mjs +2 -1
  37. package/src/schema/tables/tokens.mjs +9 -1
  38. package/src/writeContracts/tokens.mjs +4 -3
  39. package/src/writeContracts/tokensSession.mjs +1 -1
  40. package/dist/js/app-legacy.19dcf609.js +0 -1
  41. package/dist/js/app.19dcf609.js +0 -1
package/README.md CHANGED
@@ -11,10 +11,87 @@ A web service for SSO.
11
11
  ## Documentation
12
12
  To view documentation or get support, visit [docs](https://yuda-lyu.github.io/w-web-sso/WWebSso.html).
13
13
 
14
+ ## Security: token 入口與呼叫者(2026-10-24)
15
+
16
+ 後端以 token 授權之入口,依呼叫者之通過(✓)與拒絕(✗;對外一律固定鍵 `tokenExpired`,除註明者)整理如下。呼叫者:**無**=未帶 token;**使用者**=一般使用者之登入 token;**管理員**=管理者之登入 token;**用途·使用者**=使用者用途之應用系統金鑰(綁一般使用者/綁管理員,授權同所綁使用者之登入 token);**用途·系統**=系統服務用途之應用系統金鑰(依 `perms`;基本權限 `readUsers` 恆具備)。使用者目前之狀態(已驗證、未封鎖、帳號未到期、未停用)於每次使用時判定;系統服務用途不受建立者狀態影響。
17
+
18
+ | 入口 | 無 | 使用者 | 管理員 | 用途·使用者(綁一般) | 用途·使用者(綁管理員) | 用途·系統(具 perm) | 用途·系統(缺 perm) |
19
+ |---|---|---|---|---|---|---|---|
20
+ | `checkToken`、`logoutByToken`、`logoutSsoUser`(HTTP/函數) | ✗ | ✓ 本人 | ✓ 本人 | ✓ 本 token | ✓ 本 token | ✓ 本 token | ✓ 本 token |
21
+ | `refreshToken` | ✗ | ✓ | ✓ | ✗ `tokenAppNoRefresh` | ✗ `tokenAppNoRefresh` | ✗ `tokenAppNoRefresh` | ✗ `tokenAppNoRefresh` |
22
+ | `getUserByToken`(查自己) | ✗ | ✓ | ✓ | ✓ 所綁使用者 | ✓ 所綁使用者 | ✓ 應用系統身分 | ✓ 應用系統身分 |
23
+ | `changeUserPassword` | ✗ | ✓ 本人(須舊密碼) | ✓ 本人 | ✓ 所綁使用者(須舊密碼) | ✓ 所綁使用者 | ✗ `tokenUserOnly` | ✗ `tokenUserOnly` |
24
+ | 讀使用者:`/api/getSsoUserInfor`(`key=id\|account\|email\|name\|token`)、`/api/getSsoUsersList`、`getUserInfor`、`getUsersList`(`readUsers`) | ✗ | ✗ | ✓ | ✗ | ✓ | ✓ | ✓ |
25
+ | 寫使用者:`updateUsersList`、`adminResetUserPassword`(`writeUsers`) | ✗ | ✗ | ✓ | ✗ | ✓ | ✓ | ✗ |
26
+ | 金鑰:`getTokensList`(`readTokens`);`updateTokensList`、`createAppToken`(`writeTokens`) | ✗ | ✗ | ✓ | ✗ | ✓ | ✓ | ✗ |
27
+ | IP:`getIpsList`(`readIps`);`updateIpsList`(`writeIps`) | ✗ | ✗ | ✓ | ✗ | ✓ | ✓ | ✗ |
28
+ | 統計:`getStaUserSummary`、`getStaTokenSummary`、`getStaIpSummary`、`getStaUserAccountLogin`、`getStaToken`、`getStaIp`(`readStats`) | ✗ | ✗ | ✓ | ✗ | ✓ | ✓ | ✗ |
29
+ | 系統函數 `[sys:getFuncList]`(只回函數名稱清單) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
30
+ | 系統函數 `[sys:polling]`(前端連線輪詢;本套件無同步表、不廣播,恆回空陣列) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
31
+ | 系統函數 `[sys:getTableTags]`(同步表時間戳;本套件無同步表) | ✗ `permission denied` | ✗ `permission denied` | ✗ `permission denied` | ✗ `permission denied` | ✗ `permission denied` | ✗ `permission denied` | ✗ `permission denied` |
32
+
33
+ - 公開入口(不讀 token):靜態頁、`getWebInfor`、`checkUserPassword`、`loginByAccountAndPassword`、`[sys:getFuncList]`、`[sys:polling]`;`createUser`、`verifyEmail`(HTTP 連結與函數)、`resendVerifyEmail` 另受 `allowUserRegistration` 開關約束(關閉時一律回 `userRegistrationNotAllowed`)。
34
+ - 系統函數(框架提供,非本套件 kpfun):本套件顯式設定 `sysFuncsPublic: ['[sys:getFuncList]', '[sys:polling]']`,只列未登入之登入頁確實需要且無敏感內容者(ADR-096);`[sys:getTableTags]` 登入頁不需要,且本套件 `getUserIdByToken` 恆回空字串(各 kpfun 自行以明確 token 參數驗證),故對任何呼叫者(含帶有效 token 者)恆被拒絕。`[sys:polling]` 公開以「無同步表、不使用廣播(恆回空)」為前提。
35
+ - 失效之 token(未知字串、已逾期之登入 token)一律同於「無」(對外 `tokenExpired`);**例外**:登出入口讓持有者清理自己已逾期之登入 token。
36
+ - 本表以 `test/api-accessmatrix.test.mjs` 逐格驗證(token 入口 27 個 × 呼叫者 7 類,另失效 token 子類與公開入口),修改任何入口之授權時須同步更新該檔之 `entries`;系統函數三列由 `test/api-sysfuncs.test.mjs` 逐格驗證(修改 `sysFuncsPublic` 時須同步)。
37
+
14
38
  ## Upgrade Notes
15
39
 
40
+ ### Upgrading from 1.1.15 and earlier
41
+
42
+ **框架系統函數之身分關卡(行為變更,ADR-096)**:升級 `w-serv-hapi` 至 `^1.1.8`(連帶 `w-serv-webdata` 1.1.16、`w-serv-broadcast` 1.1.12),並重建前端(前端元件輪詢改帶 token 鍵)。框架預設三個系統函數皆公開;本版起本套件顯式設定 `sysFuncsPublic: ['[sys:getFuncList]', '[sys:polling]']`,只列未登入之登入頁確實需要且無敏感內容者。以真瀏覽器擷取登入頁、註冊畫面、重寄驗證信畫面與登入後各頁之請求,開機流程相同(第 3 欄為擷取所見):
43
+
44
+ | 系統函數 | 前端何時呼叫 | 回傳內容 | 決定 |
45
+ |---|---|---|---|
46
+ | `[sys:polling]` | 前端連線建立後以計時器輪詢(約 2 秒後首輪,其後約每 2 秒一次);第一輪完成才會取函數清單並觸發前端函數綁定 | 恆為空陣列(本套件無同步表、不使用廣播);不回資料、不改使用者資料(伺服端僅在記憶體登記該連線,約 10 秒無輪詢即解除) | **公開**:不列則前端永遠停在「Connecting...」,登入頁不可用(實測) |
47
+ | `[sys:getFuncList]` | 輪詢通過後第一個 | 函數名稱字串清單(含管理函數之名稱;無資料) | **公開** |
48
+ | `[sys:getTableTags]` | 函數綁定完成後立即送出(與 `getWebInfor` 並行,無人等待其結果) | 同步表時間戳;本套件無同步表(公開時回空物件) | **不公開**:登入頁不需要其結果;對任何呼叫者恆回 `permission denied` |
49
+
50
+ - **`[sys:getTableTags]` 對任何呼叫者恆被拒絕**:本套件 `getUserIdByToken` 恆回空字串(各 kpfun 自行以明確 token 參數驗證,未改變),無從以身分放行;前端元件開機流程仍會呼叫一次(開機時尚無 token),被拒絕不影響已擷取之頁面(登入、申請帳號、重寄驗證信畫面與登入後後台各頁;瀏覽器主控台無錯誤)。依賴此函數取得同步表資訊者(本套件無同步表,預期無人)將收到 `permission denied`。`sysFuncsPublic` 只管這三個系統函數,不影響 kpfun。
51
+ - **伺服端每個前端連線開機會多一則 `error` 事件**(內容 `{ msg: 'permission denied', func: '[sys:getTableTags]' }`;匿名者直接呼叫可超過此數):範例 `srv.mjs` 之 `on('error')` 會 `console.log` 印出;未掛 `error` 監聽者時 `w-serv-hapi` 改以 `console.error` 輸出,故任何部署都會有輸出,屬預期。過濾請同時比對 `msg` 與 `func`,勿一律略過 `permission denied`。此事件不進 `srLog`。
52
+ - **`[sys:polling]` 公開之前提是本套件不廣播**:`WWebSso` 回傳之實例可經 `getInstWConverServer().broadcast(...)` 推送內容,該內容會送到所有(含未登入)輪詢者;嵌入端不得以此推送非公開內容。
53
+ - **已發布之舊版前端元件照常可用**:舊元件輪詢不帶 token 鍵,視為無身分,`[sys:polling]` 公開故放行;其 `[sys:getTableTags]` 同樣被拒。以真舊版框架用戶端(w-serv-hapi 1.1.7/w-serv-webdata 1.1.15/w-serv-broadcast 1.1.10)對本版後端開機實測(未登入與帶管理員 token 各一次):開機完成、`getWebInfor` 與帶明確 token 之 `getUsersList` 可用,用戶端僅收到一則 `[sys:getTableTags]` 之 `permission denied` 事件(尚未以已發布之舊版建置檔跑整頁瀏覽器擷取)。
54
+ - **下游專案**(w-web-perm/w-web-api/w-web-task 等):本套件提供之 helper(`getUserByToken` 等)以 HTTP GET `/api/getSsoUserInfor` 反查,不經框架用戶端,不受影響;自行以框架用戶端連線本套件者,僅 `[sys:getFuncList]`、`[sys:polling]` 可用,且每次開機會收到一則 `[sys:getTableTags]` 之拒絕(未逐一檢視各下游之原始碼)。
55
+ - 日後若新增同步表或廣播內容,須重新評估 `[sys:polling]` 之公開(`test/unit-sysfuncs-premise.test.mjs` 靜態守護此前提)。新增測試:`test/api-sysfuncs.test.mjs`(SF-01~06,`sysFuncsPublic` 之變異守護)、`test/unit-sysfuncs-premise.test.mjs`(SP-01~05)。
56
+
16
57
  ### Upgrading from 1.1.13 and earlier
17
58
 
59
+ **應用系統金鑰之兩種用途與反查身分(行為變更,ADR-095)**:應用系統金鑰(`isApp='y'`)依用途分為兩種,tokens 表新增 `appUsage`(`user`/`system`)與 `appName`(金鑰名稱)兩欄(既有資料不需遷移):
60
+
61
+ | | 使用者用途(`appUsage='user'`) | 系統服務用途(`appUsage='system'`) |
62
+ |---|---|---|
63
+ | 代表 | 所綁定之一位既有啟用使用者本人(`userId` 即所綁使用者,可綁管理員) | 外部應用系統本身,不綁使用者(`userId` 僅記建立者供稽核) |
64
+ | 授權 | 同該使用者之登入權杖(含管理入口之管理者判準),不適用 `perms` | 依 `perms`(ADR-069,預設只有 `readUsers`) |
65
+ | 可用性 | 每次使用即時依所綁使用者目前狀態判定(存在、啟用、未封鎖、帳號未到期、已驗證),不符即不可用,狀態恢復後可再用 | 不隨建立者之停用、刪除、封鎖而失效;由管理員於後台撤銷 |
66
+ | `getUserByToken`/`/api/getSsoUserInfor?key=token` 回傳 | 所綁使用者之真實資料,`isApp='y'` | 應用系統身分:`id=app:<金鑰主鍵>`、`name=金鑰名稱`、`isApp='y'`、`isAdmin='y'`,其餘為占位字串 |
67
+ | `changeUserPassword` | 可(仍須舊密碼,作用於所綁使用者) | 不可(`tokenUserOnly`) |
68
+
69
+ - **對下游專案(w-web-perm/w-web-api/w-web-task 等)之反查變更**:系統服務用途金鑰過去反查回之 `id` 為金鑰擁有者欄(建立者)之使用者主鍵,與真實使用者主鍵相同而無法區分;本版起為 `app:<金鑰主鍵>`(後台清單拒收 `app:` 開頭之使用者主鍵,故不與任何使用者相撞)且 `name` 為金鑰名稱。下游若以反查之 `id` 對應自家資料(角色、權限、稽核),須改以 `app:` 前綴辨識應用系統身分。使用者用途金鑰反查回所綁使用者本人(與其登入權杖同一身分,另帶 `isApp='y'`)。
70
+ - **反查之目標權杖須此刻可用**:以 `key=token` 反查之目標權杖已逾期、查無,或其使用者目前不可用(停用、封鎖、帳號到期、未驗證),一律回固定鍵(`tokenNoPermission`),不分原因。
71
+ - **不設期限、不續期**:兩種用途皆不給到期時間(後台列表顯示「不設期限」);對應用系統金鑰呼叫 `refreshToken` 一律拒收(`tokenAppNoRefresh`)。
72
+ - **升級前既有之應用系統金鑰列(無用途欄)於升級後第一次啟動一次性定案;升級前已失效者維持失效,不會因「不設期限」而復活**(升級預設相容:可用者照常可用,已失效者不得變成可用)。判準=升級前之判定(`timeEnd` 須為合法時間且現在早於 `timeEnd` 才可用)且以時刻比較亦未逾期(從嚴;本套件寫入之 `timeEnd` 兩者一致,只有手動寫入之非本機偏移時間字串〔如 `Z`、`+14:00`〕或升級同時更換伺服器時區才會不一致,一律判為已失效):
73
+ - **升級前可用**(`timeEnd` 合法且未逾期)→ 寫入 `appUsage='system'`,視為系統服務用途、不設期限,整合不中斷(授權依 `perms`,反查為 `app:<金鑰主鍵>`);
74
+ - **升級前不可用**(已逾期、無 `timeEnd`、`timeEnd` 格式錯)→ 寫入 `appUsage='retired'`(已失效),**永不可用**,作為呼叫者時各入口回 `tokenExpired`(`refreshToken` 維持 `tokenAppNoRefresh`;登出為持有者清理自己之權杖,放行並刪該列);列**保留不刪**,後台金鑰清單仍可檢視(用途欄顯示「已失效(升級前)」、到期欄顯示原到期時間、權限欄「不適用」)並可刪除,統計計入「已到期」而不計入「有效」;
75
+ - 只寫 `appUsage`(伺服器專有欄位,不入清單存檔基準,開啟中之後台清單不因而過期);`timeEnd` 與其他欄位不動、不刪列;於 `tokens` 表鎖內以系統身分寫入(更新者記 `system`)。**冪等**:重啟只處理仍缺 `appUsage` 者,第二次起零寫入;已定案者不因日後 `timeEnd` 成為過去值而改判。
76
+ - 為何須在啟動時定案:「升級前已逾期」是升級當下的時間點事實,事後無法由欄位推回,且金鑰改為不設期限後 `timeEnd` 不再生效;定案寫入持久標記後,升級時尚未逾期者不會因日後經過 `timeEnd` 而失效。
77
+ - 遷移失敗(極少見;記錄 `tokenAppLegacyMigrateFailed`)不阻擋啟動:尚未定案之舊列讀取時依升級前規則判定(已逾期者仍失效、未逾期者依其 `timeEnd`,尚未改為不設期限),永不比升級前更寬,後台金鑰清單與統計即顯示該判定之用途;修復後重啟即重試。啟動後才由外部直寫資料庫之無用途欄舊格式列亦同,待下次啟動定案。作為「被查詢之目標」(`getSsoUserInfor` 之 `key=token`)時,已失效之金鑰與逾期、查無同樣回固定鍵 `tokenNoPermission`。
78
+ - **升級後仍需要某把已失效之舊金鑰者,請於後台以「新增應用系統金鑰」重新核發**(不提供復原已失效之列)。
79
+ - **新增方式改為 `createAppToken`(後台「金鑰清單」之「新增應用系統金鑰」鈕)**:填名稱(1~60 字)、選用途;使用者用途須選一位啟用中之使用者,系統服務用途勾選權限;權杖字串由伺服端產生。金鑰清單存檔(`updateTokensList`)**不再能新增應用系統金鑰**(`tokenAppAddNotAllowed`),**不再能把登入權杖勾選升級為應用系統金鑰**(`tokenSessionUpgradeNotAllowed`;後台「是否為應用系統金鑰」欄改為唯讀),應用系統金鑰之金鑰字串、所綁使用者、用途、名稱、到期時間建立後不可變更(`tokenAppLocked`),使用者用途不可帶 `perms`(`tokenAppPermsNotForUser`);清單存檔仍可修改系統服務用途之權限與刪除金鑰。**直打 API 以清單鑄造應用系統金鑰之舊用法須改為呼叫 `createAppToken`**。
80
+ - **停用或刪除使用者時之撤銷範圍**:撤銷該使用者之登入權杖與**綁定該使用者之使用者用途金鑰**(刪列,重新啟用後不恢復,須重新核發);系統服務用途金鑰(含建立者欄為該使用者者)不撤銷。使用者被封鎖(含自動封鎖)、帳號到期、未驗證時,使用者用途金鑰不刪列,只是即時不可用,狀態恢復後可再用。
81
+ - **對外查詢之授權判準**:以使用者用途金鑰呼叫對外查詢、後台入口者,授權同所綁使用者(綁一般使用者者不具管理服務);使用者用途金鑰綁管理員時,同樣受「不得停用/降權/刪除自己」之保護(作用於所綁管理員)。
82
+ - 保留字:使用者主鍵不得以 `app:` 開頭(後台清單新增使用者時拒收,`invalidRows`)。**既有使用者若主鍵已以 `app:` 開頭,其與系統服務用途金鑰之應用系統身分同名**(`app:<金鑰主鍵>`),下游依 `id` 對應資料時會混同;升級前請檢查 `users` 表並更換此類主鍵(正常產生之主鍵為 UUID,不會如此)。
83
+ - 登出(`logoutByToken`、`logoutSsoUser`)為持有者清理自己權杖之入口:**已逾期之登入權杖仍可登出(只刪本權杖、不回任何資料、不行使任何能力)**,其餘各入口對逾期、使用者不可用之權杖一律回 `tokenExpired`。
84
+ - 統計之「權杖調用」以系統服務用途金鑰之應用系統身分記錄(顯示金鑰名稱),不再併入建立者名下。
85
+
86
+ **登入權杖之即時有效性(行為變更,S-4)**:登入權杖(session 權杖)原只檢查到期時間;本版起每次使用另依其使用者目前狀態判定(與登入同一判準:已驗證、帳號未到期、未被封鎖、啟用),不符即與到期同樣回 `tokenExpired`。**未驗證信箱、被封鎖、帳號到期或已停用使用者所持有之既有登入權杖因此立即失效**(原可使用至權杖到期);狀態恢復後權杖照常可用(未被撤銷者)。
87
+
88
+ **後台重設他人密碼之管理者判準(S-2,語系鍵移除)**:`adminResetUserPassword` 原僅判 `isAdmin==='y'` 並對非管理者回 `adminResetPasswordForbidden`;本版起與其他管理入口同一判準(`funCheckAdmin`:已驗證、帳號未到期、未被封鎖、啟用、管理者),非管理者、狀態不符或權杖無效一律回 `tokenExpired`。語系鍵 `adminResetPasswordForbidden` 已移除,呼叫端若以該鍵判斷須改判 `tokenExpired`。
89
+
90
+ **自助註冊關閉時之驗證入口(S-6)**:`allowUserRegistration` 為 `false`(預設)時,`verifyEmail`(HTTP 驗證連結與 kpfun)與 `resendVerifyEmail` 一律回 `userRegistrationNotAllowed`(驗證連結失效、不寄信、不改資料);登入頁之「重寄驗證信」連結同步隱藏。已開啟註冊之部署不受影響。
91
+
92
+ - 新增語系鍵:`tokenAppAddNotAllowed`、`tokenSessionUpgradeNotAllowed`、`tokenAppLocked`、`tokenAppPermsNotForUser`、`tokenAppUsageInvalid`、`tokenAppNameInvalid`、`tokenAppUserInvalid`、`tokenAppUserNotForSystem`、`tokenAppCreateFailed`、`tokenAppNoRefresh`、`tokenUserOnly` 及後台畫面用之文字鍵(eng/cht);移除 `adminResetPasswordForbidden`。
93
+ - 本節取代 1.1.12 節中「金鑰清單新增列僅限應用系統金鑰」「將既有 session 列升級為應用系統金鑰」之敘述。
94
+
18
95
  **改密碼後之 session 處置(行為變更)**:依 OWASP ASVS「改密碼後提供終止其他所有 session」,本版起改密碼會撤銷該使用者的登入權杖(session 權杖,`isApp` 非 `'y'`):
19
96
 
20
97
  - **管理員重設他人密碼**(後台「重設密碼」鈕,或具 `writeUsers` 之 app 權杖呼叫 `adminResetUserPassword`)→ 撤銷**對方全部** session 權杖;該使用者所有裝置立即登出(下次呼叫回登入頁),須以新密碼重新登入。強制下次登入改密碼(`isForceChangePw='y'`)之行為不變。
@@ -1 +1 @@
1
- .bg-blue-100[data-v-a0ffaf3e]{--tw-bg-opacity:1;background-color:rgb(219 234 254/var(--tw-bg-opacity,1))}.bg-gray-100[data-v-a0ffaf3e]{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.bg-gray-50[data-v-a0ffaf3e]{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.bg-green-100[data-v-a0ffaf3e]{--tw-bg-opacity:1;background-color:rgb(220 252 231/var(--tw-bg-opacity,1))}.bg-red-100[data-v-a0ffaf3e]{--tw-bg-opacity:1;background-color:rgb(254 226 226/var(--tw-bg-opacity,1))}.bg-white[data-v-a0ffaf3e]{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-yellow-100[data-v-a0ffaf3e]{--tw-bg-opacity:1;background-color:rgb(254 249 195/var(--tw-bg-opacity,1))}.border[data-v-a0ffaf3e]{border-width:1px}.border-collapse[data-v-a0ffaf3e]{border-collapse:collapse}.border-gray-200[data-v-a0ffaf3e]{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1))}.border-gray-300[data-v-a0ffaf3e]{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity,1))}.border-solid[data-v-a0ffaf3e]{border-style:solid}.cursor-pointer[data-v-a0ffaf3e]{cursor:pointer}.flex[data-v-a0ffaf3e]{display:-webkit-box;display:-ms-flexbox;display:flex}.focus\:ring-blue-500[data-v-a0ffaf3e]:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246/var(--tw-ring-opacity,1))}.font-bold[data-v-a0ffaf3e]{font-weight:700}.font-medium[data-v-a0ffaf3e]{font-weight:500}.font-semibold[data-v-a0ffaf3e]{font-weight:600}.gap-5[data-v-a0ffaf3e]{gap:1.25rem}.gap-6[data-v-a0ffaf3e]{gap:1.5rem}.h-4[data-v-a0ffaf3e]{height:1rem}.hover\:bg-gray-50[data-v-a0ffaf3e]:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.hover\:underline[data-v-a0ffaf3e]:hover{text-decoration-line:underline}.items-center[data-v-a0ffaf3e]{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.justify-between[data-v-a0ffaf3e]{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.mb-2[data-v-a0ffaf3e]{margin-bottom:.5rem}.mb-4[data-v-a0ffaf3e]{margin-bottom:1rem}.mb-8[data-v-a0ffaf3e]{margin-bottom:2rem}.ml-2[data-v-a0ffaf3e]{margin-left:.5rem}.ml-4[data-v-a0ffaf3e]{margin-left:1rem}.mr-2[data-v-a0ffaf3e]{margin-right:.5rem}.mt-2[data-v-a0ffaf3e]{margin-top:.5rem}.mt-4[data-v-a0ffaf3e]{margin-top:1rem}.overflow-x-auto[data-v-a0ffaf3e]{overflow-x:auto}.p-3[data-v-a0ffaf3e]{padding:.75rem}.p-5[data-v-a0ffaf3e]{padding:1.25rem}.pb-1[data-v-a0ffaf3e]{padding-bottom:.25rem}.pb-2[data-v-a0ffaf3e]{padding-bottom:.5rem}.pb-3[data-v-a0ffaf3e]{padding-bottom:.75rem}.px-2[data-v-a0ffaf3e]{padding-left:.5rem;padding-right:.5rem}.px-6[data-v-a0ffaf3e]{padding-left:1.5rem;padding-right:1.5rem}.py-1[data-v-a0ffaf3e]{padding-top:.25rem;padding-bottom:.25rem}.py-3[data-v-a0ffaf3e]{padding-top:.75rem;padding-bottom:.75rem}.py-4[data-v-a0ffaf3e]{padding-top:1rem;padding-bottom:1rem}.relative[data-v-a0ffaf3e]{position:relative}.rounded[data-v-a0ffaf3e]{border-radius:.25rem}.rounded-full[data-v-a0ffaf3e]{border-radius:9999px}.rounded-lg[data-v-a0ffaf3e]{border-radius:.5rem}.shadow-md[data-v-a0ffaf3e]{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-md[data-v-a0ffaf3e],.shadow-sm[data-v-a0ffaf3e]{-webkit-box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm[data-v-a0ffaf3e]{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.space-x-4[data-v-a0ffaf3e]>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.space-y-2[data-v-a0ffaf3e]>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-8[data-v-a0ffaf3e]>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(2rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem*var(--tw-space-y-reverse))}.sticky[data-v-a0ffaf3e]{position:sticky}.text-2xl[data-v-a0ffaf3e]{font-size:1.5rem;line-height:2rem}.text-blue-600[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-gray-500[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.text-gray-700[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.text-gray-900[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1))}.text-green-600[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(22 163 74/var(--tw-text-opacity,1))}.text-indigo-600[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity,1))}.text-left[data-v-a0ffaf3e]{text-align:left}.text-lg[data-v-a0ffaf3e]{font-size:1.125rem;line-height:1.75rem}.text-purple-600[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(147 51 234/var(--tw-text-opacity,1))}.text-red-600[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity,1))}.text-right[data-v-a0ffaf3e]{text-align:right}.text-sm[data-v-a0ffaf3e]{font-size:.875rem;line-height:1.25rem}.text-teal-600[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(13 148 136/var(--tw-text-opacity,1))}.text-xs[data-v-a0ffaf3e]{font-size:.75rem;line-height:1rem}.text-yellow-600[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(202 138 4/var(--tw-text-opacity,1))}.top-0[data-v-a0ffaf3e]{top:0}.transition-colors[data-v-a0ffaf3e]{-webkit-transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.15s;transition-duration:.15s}.w-4[data-v-a0ffaf3e]{width:1rem}.w-7[data-v-a0ffaf3e]{width:1.75rem}.w-full[data-v-a0ffaf3e]{width:100%}.z-10[data-v-a0ffaf3e]{z-index:10}.grid[data-v-a0ffaf3e]{display:grid}.grid-cols-1[data-v-a0ffaf3e]{grid-template-columns:repeat(1,minmax(0,1fr))}@media (min-width:640px){.sm\:grid-cols-2[data-v-a0ffaf3e]{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:1024px){.lg\:grid-cols-1[data-v-a0ffaf3e]{grid-template-columns:repeat(1,minmax(0,1fr))}.lg\:grid-cols-3[data-v-a0ffaf3e]{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4[data-v-a0ffaf3e]{grid-template-columns:repeat(4,minmax(0,1fr))}}.bg-blue-100[data-v-3796caa5]{--tw-bg-opacity:1;background-color:rgb(219 234 254/var(--tw-bg-opacity,1))}.bg-gray-100[data-v-3796caa5]{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.border-gray-200[data-v-3796caa5]{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1))}.border-t[data-v-3796caa5]{border-top-width:1px}.break-all[data-v-3796caa5]{word-break:break-all}.flex[data-v-3796caa5]{display:-webkit-box;display:-ms-flexbox;display:flex}.flex-shrink-0[data-v-3796caa5]{-ms-flex-negative:0;flex-shrink:0}.font-medium[data-v-3796caa5]{font-weight:500}.font-semibold[data-v-3796caa5]{font-weight:600}.gap-3[data-v-3796caa5]{gap:.75rem}.gap-4[data-v-3796caa5]{gap:1rem}.gap-x-8[data-v-3796caa5]{-webkit-column-gap:2rem;-moz-column-gap:2rem;column-gap:2rem}.gap-y-6[data-v-3796caa5]{row-gap:1.5rem}.inline-block[data-v-3796caa5]{display:inline-block}.items-center[data-v-3796caa5]{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.items-start[data-v-3796caa5]{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.mb-2[data-v-3796caa5]{margin-bottom:.5rem}.mr-3[data-v-3796caa5]{margin-right:.75rem}.mt-1[data-v-3796caa5]{margin-top:.25rem}.p-3[data-v-3796caa5]{padding:.75rem}.pt-6[data-v-3796caa5]{padding-top:1.5rem}.px-2[data-v-3796caa5]{padding-left:.5rem;padding-right:.5rem}.py-1[data-v-3796caa5]{padding-top:.25rem;padding-bottom:.25rem}.rounded-lg[data-v-3796caa5]{border-radius:.5rem}.rounded-md[data-v-3796caa5]{border-radius:.375rem}.space-y-8[data-v-3796caa5]>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(2rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem*var(--tw-space-y-reverse))}.text-base[data-v-3796caa5]{font-size:1rem;line-height:1.5rem}.text-blue-700[data-v-3796caa5]{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity,1))}.text-gray-400[data-v-3796caa5]{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.text-gray-500[data-v-3796caa5]{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.text-gray-700[data-v-3796caa5]{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.text-gray-900[data-v-3796caa5]{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1))}.text-sm[data-v-3796caa5]{font-size:.875rem;line-height:1.25rem}.text-xs[data-v-3796caa5]{font-size:.75rem;line-height:1rem}.text-red-800\/80[data-v-3796caa5]{color:rgba(153,27,27,.8)}.text-green-800\/80[data-v-3796caa5]{color:rgba(22,101,52,.8)}.grid[data-v-3796caa5]{display:grid}.grid-cols-1[data-v-3796caa5]{grid-template-columns:repeat(1,minmax(0,1fr))}@media (min-width:640px){.sm\:grid-cols-2[data-v-3796caa5]{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:768px){.md\:grid-cols-2[data-v-3796caa5]{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:col-span-2[data-v-3796caa5]{grid-column:span 2/span 2}}@media (min-width:1024px){.lg\:grid-cols-4[data-v-3796caa5]{grid-template-columns:repeat(4,minmax(0,1fr))}}.status-danger[data-v-3796caa5]{background-color:#fef2f2;color:#b91c1c;border:1px solid #fecaca}.status-warning[data-v-3796caa5]{background-color:#fffbeb;color:#b45309;border:1px solid #fde68a}.status-success[data-v-3796caa5]{background-color:#f0fdf4;color:#15803d;border:1px solid #bbf7d0}.status-info[data-v-3796caa5]{background-color:#f8fafc;color:#475569;border:1px solid #e2e8f0}.perms-trigger[data-v-3d1cbcc4]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:2px;border:1px solid #767676;border-radius:4px;background:#f0f0f0;cursor:pointer;-webkit-transition:background-color .2s;transition:background-color .2s}.perms-trigger[data-v-3d1cbcc4]:hover{background:#e5e5e5}.menu-row-click[data-v-4501b18f]{-webkit-transition:background .2s;transition:background .2s}.menu-row-click[data-v-4501b18f]:focus,.menu-row-click[data-v-4501b18f]:hover{background:#f2f2f2}body,html{font-family:微軟正黑體,Microsoft JhengHei,MicrosoftJhengHeiRegular,Avenir,Helvetica,Arial,sans-serif;overflow-y:hidden}a,button,div,input,p,pre,span,textarea{font-family:inherit}.sb{-webkit-transition:opacity .3s;transition:opacity .3s;scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.3) transparent}.sb::-webkit-scrollbar{width:8px;height:8px}.sb::-webkit-scrollbar-track{background:transparent}.sb::-webkit-scrollbar-thumb{background:rgba(0,0,0,.3);border-radius:20px;border:3px solid transparent}
1
+ .bg-blue-100[data-v-a0ffaf3e]{--tw-bg-opacity:1;background-color:rgb(219 234 254/var(--tw-bg-opacity,1))}.bg-gray-100[data-v-a0ffaf3e]{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.bg-gray-50[data-v-a0ffaf3e]{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.bg-green-100[data-v-a0ffaf3e]{--tw-bg-opacity:1;background-color:rgb(220 252 231/var(--tw-bg-opacity,1))}.bg-red-100[data-v-a0ffaf3e]{--tw-bg-opacity:1;background-color:rgb(254 226 226/var(--tw-bg-opacity,1))}.bg-white[data-v-a0ffaf3e]{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-yellow-100[data-v-a0ffaf3e]{--tw-bg-opacity:1;background-color:rgb(254 249 195/var(--tw-bg-opacity,1))}.border[data-v-a0ffaf3e]{border-width:1px}.border-collapse[data-v-a0ffaf3e]{border-collapse:collapse}.border-gray-200[data-v-a0ffaf3e]{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1))}.border-gray-300[data-v-a0ffaf3e]{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity,1))}.border-solid[data-v-a0ffaf3e]{border-style:solid}.cursor-pointer[data-v-a0ffaf3e]{cursor:pointer}.flex[data-v-a0ffaf3e]{display:-webkit-box;display:-ms-flexbox;display:flex}.focus\:ring-blue-500[data-v-a0ffaf3e]:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246/var(--tw-ring-opacity,1))}.font-bold[data-v-a0ffaf3e]{font-weight:700}.font-medium[data-v-a0ffaf3e]{font-weight:500}.font-semibold[data-v-a0ffaf3e]{font-weight:600}.gap-5[data-v-a0ffaf3e]{gap:1.25rem}.gap-6[data-v-a0ffaf3e]{gap:1.5rem}.h-4[data-v-a0ffaf3e]{height:1rem}.hover\:bg-gray-50[data-v-a0ffaf3e]:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.hover\:underline[data-v-a0ffaf3e]:hover{text-decoration-line:underline}.items-center[data-v-a0ffaf3e]{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.justify-between[data-v-a0ffaf3e]{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.mb-2[data-v-a0ffaf3e]{margin-bottom:.5rem}.mb-4[data-v-a0ffaf3e]{margin-bottom:1rem}.mb-8[data-v-a0ffaf3e]{margin-bottom:2rem}.ml-2[data-v-a0ffaf3e]{margin-left:.5rem}.ml-4[data-v-a0ffaf3e]{margin-left:1rem}.mr-2[data-v-a0ffaf3e]{margin-right:.5rem}.mt-2[data-v-a0ffaf3e]{margin-top:.5rem}.mt-4[data-v-a0ffaf3e]{margin-top:1rem}.overflow-x-auto[data-v-a0ffaf3e]{overflow-x:auto}.p-3[data-v-a0ffaf3e]{padding:.75rem}.p-5[data-v-a0ffaf3e]{padding:1.25rem}.pb-1[data-v-a0ffaf3e]{padding-bottom:.25rem}.pb-2[data-v-a0ffaf3e]{padding-bottom:.5rem}.pb-3[data-v-a0ffaf3e]{padding-bottom:.75rem}.px-2[data-v-a0ffaf3e]{padding-left:.5rem;padding-right:.5rem}.px-6[data-v-a0ffaf3e]{padding-left:1.5rem;padding-right:1.5rem}.py-1[data-v-a0ffaf3e]{padding-top:.25rem;padding-bottom:.25rem}.py-3[data-v-a0ffaf3e]{padding-top:.75rem;padding-bottom:.75rem}.py-4[data-v-a0ffaf3e]{padding-top:1rem;padding-bottom:1rem}.relative[data-v-a0ffaf3e]{position:relative}.rounded[data-v-a0ffaf3e]{border-radius:.25rem}.rounded-full[data-v-a0ffaf3e]{border-radius:9999px}.rounded-lg[data-v-a0ffaf3e]{border-radius:.5rem}.shadow-md[data-v-a0ffaf3e]{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-md[data-v-a0ffaf3e],.shadow-sm[data-v-a0ffaf3e]{-webkit-box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm[data-v-a0ffaf3e]{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.space-x-4[data-v-a0ffaf3e]>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.space-y-2[data-v-a0ffaf3e]>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-8[data-v-a0ffaf3e]>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(2rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem*var(--tw-space-y-reverse))}.sticky[data-v-a0ffaf3e]{position:sticky}.text-2xl[data-v-a0ffaf3e]{font-size:1.5rem;line-height:2rem}.text-blue-600[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-gray-500[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.text-gray-700[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.text-gray-900[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1))}.text-green-600[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(22 163 74/var(--tw-text-opacity,1))}.text-indigo-600[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity,1))}.text-left[data-v-a0ffaf3e]{text-align:left}.text-lg[data-v-a0ffaf3e]{font-size:1.125rem;line-height:1.75rem}.text-purple-600[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(147 51 234/var(--tw-text-opacity,1))}.text-red-600[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity,1))}.text-right[data-v-a0ffaf3e]{text-align:right}.text-sm[data-v-a0ffaf3e]{font-size:.875rem;line-height:1.25rem}.text-teal-600[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(13 148 136/var(--tw-text-opacity,1))}.text-xs[data-v-a0ffaf3e]{font-size:.75rem;line-height:1rem}.text-yellow-600[data-v-a0ffaf3e]{--tw-text-opacity:1;color:rgb(202 138 4/var(--tw-text-opacity,1))}.top-0[data-v-a0ffaf3e]{top:0}.transition-colors[data-v-a0ffaf3e]{-webkit-transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.15s;transition-duration:.15s}.w-4[data-v-a0ffaf3e]{width:1rem}.w-7[data-v-a0ffaf3e]{width:1.75rem}.w-full[data-v-a0ffaf3e]{width:100%}.z-10[data-v-a0ffaf3e]{z-index:10}.grid[data-v-a0ffaf3e]{display:grid}.grid-cols-1[data-v-a0ffaf3e]{grid-template-columns:repeat(1,minmax(0,1fr))}@media (min-width:640px){.sm\:grid-cols-2[data-v-a0ffaf3e]{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:1024px){.lg\:grid-cols-1[data-v-a0ffaf3e]{grid-template-columns:repeat(1,minmax(0,1fr))}.lg\:grid-cols-3[data-v-a0ffaf3e]{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4[data-v-a0ffaf3e]{grid-template-columns:repeat(4,minmax(0,1fr))}}.bg-blue-100[data-v-3796caa5]{--tw-bg-opacity:1;background-color:rgb(219 234 254/var(--tw-bg-opacity,1))}.bg-gray-100[data-v-3796caa5]{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.border-gray-200[data-v-3796caa5]{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1))}.border-t[data-v-3796caa5]{border-top-width:1px}.break-all[data-v-3796caa5]{word-break:break-all}.flex[data-v-3796caa5]{display:-webkit-box;display:-ms-flexbox;display:flex}.flex-shrink-0[data-v-3796caa5]{-ms-flex-negative:0;flex-shrink:0}.font-medium[data-v-3796caa5]{font-weight:500}.font-semibold[data-v-3796caa5]{font-weight:600}.gap-3[data-v-3796caa5]{gap:.75rem}.gap-4[data-v-3796caa5]{gap:1rem}.gap-x-8[data-v-3796caa5]{-webkit-column-gap:2rem;-moz-column-gap:2rem;column-gap:2rem}.gap-y-6[data-v-3796caa5]{row-gap:1.5rem}.inline-block[data-v-3796caa5]{display:inline-block}.items-center[data-v-3796caa5]{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.items-start[data-v-3796caa5]{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.mb-2[data-v-3796caa5]{margin-bottom:.5rem}.mr-3[data-v-3796caa5]{margin-right:.75rem}.mt-1[data-v-3796caa5]{margin-top:.25rem}.p-3[data-v-3796caa5]{padding:.75rem}.pt-6[data-v-3796caa5]{padding-top:1.5rem}.px-2[data-v-3796caa5]{padding-left:.5rem;padding-right:.5rem}.py-1[data-v-3796caa5]{padding-top:.25rem;padding-bottom:.25rem}.rounded-lg[data-v-3796caa5]{border-radius:.5rem}.rounded-md[data-v-3796caa5]{border-radius:.375rem}.space-y-8[data-v-3796caa5]>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(2rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem*var(--tw-space-y-reverse))}.text-base[data-v-3796caa5]{font-size:1rem;line-height:1.5rem}.text-blue-700[data-v-3796caa5]{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity,1))}.text-gray-400[data-v-3796caa5]{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.text-gray-500[data-v-3796caa5]{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.text-gray-700[data-v-3796caa5]{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.text-gray-900[data-v-3796caa5]{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1))}.text-sm[data-v-3796caa5]{font-size:.875rem;line-height:1.25rem}.text-xs[data-v-3796caa5]{font-size:.75rem;line-height:1rem}.text-red-800\/80[data-v-3796caa5]{color:rgba(153,27,27,.8)}.text-green-800\/80[data-v-3796caa5]{color:rgba(22,101,52,.8)}.grid[data-v-3796caa5]{display:grid}.grid-cols-1[data-v-3796caa5]{grid-template-columns:repeat(1,minmax(0,1fr))}@media (min-width:640px){.sm\:grid-cols-2[data-v-3796caa5]{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:768px){.md\:grid-cols-2[data-v-3796caa5]{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:col-span-2[data-v-3796caa5]{grid-column:span 2/span 2}}@media (min-width:1024px){.lg\:grid-cols-4[data-v-3796caa5]{grid-template-columns:repeat(4,minmax(0,1fr))}}.status-danger[data-v-3796caa5]{background-color:#fef2f2;color:#b91c1c;border:1px solid #fecaca}.status-warning[data-v-3796caa5]{background-color:#fffbeb;color:#b45309;border:1px solid #fde68a}.status-success[data-v-3796caa5]{background-color:#f0fdf4;color:#15803d;border:1px solid #bbf7d0}.status-info[data-v-3796caa5]{background-color:#f8fafc;color:#475569;border:1px solid #e2e8f0}.perms-trigger[data-v-a8b350e0]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:2px;border:1px solid #767676;border-radius:4px;background:#f0f0f0;cursor:pointer;-webkit-transition:background-color .2s;transition:background-color .2s}.perms-trigger[data-v-a8b350e0]:hover{background:#e5e5e5}.menu-row-click[data-v-4501b18f]{-webkit-transition:background .2s;transition:background .2s}.menu-row-click[data-v-4501b18f]:focus,.menu-row-click[data-v-4501b18f]:hover{background:#f2f2f2}body,html{font-family:微軟正黑體,Microsoft JhengHei,MicrosoftJhengHeiRegular,Avenir,Helvetica,Arial,sans-serif;overflow-y:hidden}a,button,div,input,p,pre,span,textarea{font-family:inherit}.sb{-webkit-transition:opacity .3s;transition:opacity .3s;scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.3) transparent}.sb::-webkit-scrollbar{width:8px;height:8px}.sb::-webkit-scrollbar-track{background:transparent}.sb::-webkit-scrollbar-thumb{background:rgba(0,0,0,.3);border-radius:20px;border:3px solid transparent}
package/dist/index.tmp CHANGED
@@ -1,3 +1,3 @@
1
1
  <!doctype html><html xmlns="http://www.w3.org/1999/xhtml" lang="zh-tw"><head><meta http-equiv="content-type" content="text/html; charset=UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,minimal-ui"><meta http-equiv="X-UA-Compatible" content="ie=edge"><meta name="referrer" content="strict-origin"><title></title><link _href="https://cdn.jsdelivr.net/npm/@mdi/font@7.4.47/css/materialdesignicons.min.css" rel="stylesheet"><link _href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.2/css/all.min.css" rel="stylesheet"><script>window.___pmwsso___={
2
2
  language: '{language}',
3
- }</script><script defer="defer" src="{sfd}/js/chunk-vendors.97013ddc.js" type="module"></script><script defer="defer" src="{sfd}/js/app.19dcf609.js" type="module"></script><link href="{sfd}/css/chunk-vendors.5c06be05.css" rel="stylesheet"><link href="{sfd}/css/app.f000459f.css" rel="stylesheet"><script defer="defer" src="{sfd}/js/chunk-vendors-legacy.97013ddc.js" nomodule></script><script defer="defer" src="{sfd}/js/app-legacy.19dcf609.js" nomodule></script></head><body style="font-family:'Microsoft JhengHei','Avenir','Helvetica', 'Arial', 'sans-serif'; padding:0px; margin:0px;"><noscript><strong>We're sorry but w-component-vue doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
3
+ }</script><script defer="defer" src="{sfd}/js/chunk-vendors.b81fc7a8.js" type="module"></script><script defer="defer" src="{sfd}/js/app.0e1b6835.js" type="module"></script><link href="{sfd}/css/chunk-vendors.5c06be05.css" rel="stylesheet"><link href="{sfd}/css/app.c117e572.css" rel="stylesheet"><script defer="defer" src="{sfd}/js/chunk-vendors-legacy.b81fc7a8.js" nomodule></script><script defer="defer" src="{sfd}/js/app-legacy.0e1b6835.js" nomodule></script></head><body style="font-family:'Microsoft JhengHei','Avenir','Helvetica', 'Arial', 'sans-serif'; padding:0px; margin:0px;"><noscript><strong>We're sorry but w-component-vue doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>