@fui-org/fui-cli 0.2.0 → 0.3.0

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 (212) hide show
  1. package/README.md +13 -1
  2. package/dist/fui.js +160 -43
  3. package/package.json +4 -2
  4. package/skills/fui/SKILL.md +131 -66
  5. package/skills/fui-skill/README.md +112 -0
  6. package/skills/fui-skill/SKILL.md +269 -0
  7. package/skills/fui-skill/assets/projectdefaultstyle.css +518 -0
  8. package/skills/fui-skill/design-md/airbnb/DESIGN.md +545 -0
  9. package/skills/fui-skill/design-md/airbnb/README.md +5 -0
  10. package/skills/fui-skill/design-md/airtable/DESIGN.md +554 -0
  11. package/skills/fui-skill/design-md/airtable/README.md +5 -0
  12. package/skills/fui-skill/design-md/apple/DESIGN.md +562 -0
  13. package/skills/fui-skill/design-md/apple/README.md +5 -0
  14. package/skills/fui-skill/design-md/asu/DESIGN.md +179 -0
  15. package/skills/fui-skill/design-md/asu/README.md +107 -0
  16. package/skills/fui-skill/design-md/binance/DESIGN.md +634 -0
  17. package/skills/fui-skill/design-md/binance/README.md +5 -0
  18. package/skills/fui-skill/design-md/bmw/DESIGN.md +544 -0
  19. package/skills/fui-skill/design-md/bmw/README.md +5 -0
  20. package/skills/fui-skill/design-md/bmw-m/DESIGN.md +503 -0
  21. package/skills/fui-skill/design-md/bmw-m/README.md +5 -0
  22. package/skills/fui-skill/design-md/bugatti/DESIGN.md +454 -0
  23. package/skills/fui-skill/design-md/bugatti/README.md +5 -0
  24. package/skills/fui-skill/design-md/cal/DESIGN.md +542 -0
  25. package/skills/fui-skill/design-md/cal/README.md +5 -0
  26. package/skills/fui-skill/design-md/claude/DESIGN.md +589 -0
  27. package/skills/fui-skill/design-md/claude/README.md +5 -0
  28. package/skills/fui-skill/design-md/clay/DESIGN.md +541 -0
  29. package/skills/fui-skill/design-md/clay/README.md +5 -0
  30. package/skills/fui-skill/design-md/clickhouse/DESIGN.md +544 -0
  31. package/skills/fui-skill/design-md/clickhouse/README.md +5 -0
  32. package/skills/fui-skill/design-md/cohere/DESIGN.md +451 -0
  33. package/skills/fui-skill/design-md/cohere/README.md +5 -0
  34. package/skills/fui-skill/design-md/coinbase/DESIGN.md +570 -0
  35. package/skills/fui-skill/design-md/coinbase/README.md +5 -0
  36. package/skills/fui-skill/design-md/composio/DESIGN.md +506 -0
  37. package/skills/fui-skill/design-md/composio/README.md +5 -0
  38. package/skills/fui-skill/design-md/cursor/DESIGN.md +537 -0
  39. package/skills/fui-skill/design-md/cursor/README.md +5 -0
  40. package/skills/fui-skill/design-md/elevenlabs/DESIGN.md +504 -0
  41. package/skills/fui-skill/design-md/elevenlabs/README.md +5 -0
  42. package/skills/fui-skill/design-md/expo/DESIGN.md +526 -0
  43. package/skills/fui-skill/design-md/expo/README.md +5 -0
  44. package/skills/fui-skill/design-md/ferrari/DESIGN.md +531 -0
  45. package/skills/fui-skill/design-md/ferrari/README.md +5 -0
  46. package/skills/fui-skill/design-md/figma/DESIGN.md +578 -0
  47. package/skills/fui-skill/design-md/figma/README.md +5 -0
  48. package/skills/fui-skill/design-md/framer/DESIGN.md +544 -0
  49. package/skills/fui-skill/design-md/framer/README.md +5 -0
  50. package/skills/fui-skill/design-md/fui/DESIGN.md +532 -0
  51. package/skills/fui-skill/design-md/hashicorp/DESIGN.md +575 -0
  52. package/skills/fui-skill/design-md/hashicorp/README.md +5 -0
  53. package/skills/fui-skill/design-md/ibm/DESIGN.md +550 -0
  54. package/skills/fui-skill/design-md/ibm/README.md +5 -0
  55. package/skills/fui-skill/design-md/intercom/DESIGN.md +546 -0
  56. package/skills/fui-skill/design-md/intercom/README.md +5 -0
  57. package/skills/fui-skill/design-md/kraken/DESIGN.md +125 -0
  58. package/skills/fui-skill/design-md/kraken/README.md +5 -0
  59. package/skills/fui-skill/design-md/lamborghini/DESIGN.md +288 -0
  60. package/skills/fui-skill/design-md/lamborghini/README.md +5 -0
  61. package/skills/fui-skill/design-md/linear.app/DESIGN.md +548 -0
  62. package/skills/fui-skill/design-md/linear.app/README.md +5 -0
  63. package/skills/fui-skill/design-md/lovable/DESIGN.md +298 -0
  64. package/skills/fui-skill/design-md/lovable/README.md +5 -0
  65. package/skills/fui-skill/design-md/mastercard/DESIGN.md +365 -0
  66. package/skills/fui-skill/design-md/mastercard/README.md +5 -0
  67. package/skills/fui-skill/design-md/meta/DESIGN.md +683 -0
  68. package/skills/fui-skill/design-md/meta/README.md +5 -0
  69. package/skills/fui-skill/design-md/minimax/DESIGN.md +746 -0
  70. package/skills/fui-skill/design-md/minimax/README.md +5 -0
  71. package/skills/fui-skill/design-md/mintlify/DESIGN.md +852 -0
  72. package/skills/fui-skill/design-md/mintlify/README.md +5 -0
  73. package/skills/fui-skill/design-md/miro/DESIGN.md +825 -0
  74. package/skills/fui-skill/design-md/miro/README.md +5 -0
  75. package/skills/fui-skill/design-md/mistral.ai/DESIGN.md +773 -0
  76. package/skills/fui-skill/design-md/mistral.ai/README.md +5 -0
  77. package/skills/fui-skill/design-md/mongodb/DESIGN.md +767 -0
  78. package/skills/fui-skill/design-md/mongodb/README.md +5 -0
  79. package/skills/fui-skill/design-md/nike/DESIGN.md +575 -0
  80. package/skills/fui-skill/design-md/nike/README.md +5 -0
  81. package/skills/fui-skill/design-md/notion/DESIGN.md +821 -0
  82. package/skills/fui-skill/design-md/notion/README.md +5 -0
  83. package/skills/fui-skill/design-md/nvidia/DESIGN.md +640 -0
  84. package/skills/fui-skill/design-md/nvidia/README.md +5 -0
  85. package/skills/fui-skill/design-md/ollama/DESIGN.md +539 -0
  86. package/skills/fui-skill/design-md/ollama/README.md +5 -0
  87. package/skills/fui-skill/design-md/opencode.ai/DESIGN.md +521 -0
  88. package/skills/fui-skill/design-md/opencode.ai/README.md +5 -0
  89. package/skills/fui-skill/design-md/pinterest/DESIGN.md +597 -0
  90. package/skills/fui-skill/design-md/pinterest/README.md +5 -0
  91. package/skills/fui-skill/design-md/playstation/DESIGN.md +661 -0
  92. package/skills/fui-skill/design-md/playstation/README.md +5 -0
  93. package/skills/fui-skill/design-md/posthog/DESIGN.md +690 -0
  94. package/skills/fui-skill/design-md/posthog/README.md +5 -0
  95. package/skills/fui-skill/design-md/raycast/DESIGN.md +669 -0
  96. package/skills/fui-skill/design-md/raycast/README.md +5 -0
  97. package/skills/fui-skill/design-md/renault/DESIGN.md +589 -0
  98. package/skills/fui-skill/design-md/renault/README.md +5 -0
  99. package/skills/fui-skill/design-md/replicate/DESIGN.md +616 -0
  100. package/skills/fui-skill/design-md/replicate/README.md +5 -0
  101. package/skills/fui-skill/design-md/resend/DESIGN.md +585 -0
  102. package/skills/fui-skill/design-md/resend/README.md +5 -0
  103. package/skills/fui-skill/design-md/revolut/DESIGN.md +636 -0
  104. package/skills/fui-skill/design-md/revolut/README.md +5 -0
  105. package/skills/fui-skill/design-md/runwayml/DESIGN.md +244 -0
  106. package/skills/fui-skill/design-md/runwayml/README.md +5 -0
  107. package/skills/fui-skill/design-md/sanity/DESIGN.md +357 -0
  108. package/skills/fui-skill/design-md/sanity/README.md +5 -0
  109. package/skills/fui-skill/design-md/sentry/DESIGN.md +551 -0
  110. package/skills/fui-skill/design-md/sentry/README.md +5 -0
  111. package/skills/fui-skill/design-md/shopify/DESIGN.md +516 -0
  112. package/skills/fui-skill/design-md/shopify/README.md +5 -0
  113. package/skills/fui-skill/design-md/slack/DESIGN.md +482 -0
  114. package/skills/fui-skill/design-md/spacex/DESIGN.md +363 -0
  115. package/skills/fui-skill/design-md/spacex/README.md +5 -0
  116. package/skills/fui-skill/design-md/spotify/DESIGN.md +246 -0
  117. package/skills/fui-skill/design-md/spotify/README.md +5 -0
  118. package/skills/fui-skill/design-md/starbucks/DESIGN.md +580 -0
  119. package/skills/fui-skill/design-md/starbucks/README.md +5 -0
  120. package/skills/fui-skill/design-md/stripe/DESIGN.md +487 -0
  121. package/skills/fui-skill/design-md/stripe/README.md +5 -0
  122. package/skills/fui-skill/design-md/supabase/DESIGN.md +462 -0
  123. package/skills/fui-skill/design-md/supabase/README.md +5 -0
  124. package/skills/fui-skill/design-md/superhuman/DESIGN.md +448 -0
  125. package/skills/fui-skill/design-md/superhuman/README.md +5 -0
  126. package/skills/fui-skill/design-md/tesla/DESIGN.md +286 -0
  127. package/skills/fui-skill/design-md/tesla/README.md +5 -0
  128. package/skills/fui-skill/design-md/theverge/DESIGN.md +339 -0
  129. package/skills/fui-skill/design-md/theverge/README.md +5 -0
  130. package/skills/fui-skill/design-md/together.ai/DESIGN.md +633 -0
  131. package/skills/fui-skill/design-md/together.ai/README.md +5 -0
  132. package/skills/fui-skill/design-md/uber/DESIGN.md +636 -0
  133. package/skills/fui-skill/design-md/uber/README.md +5 -0
  134. package/skills/fui-skill/design-md/vercel/DESIGN.md +736 -0
  135. package/skills/fui-skill/design-md/vercel/README.md +5 -0
  136. package/skills/fui-skill/design-md/vodafone/DESIGN.md +538 -0
  137. package/skills/fui-skill/design-md/vodafone/README.md +5 -0
  138. package/skills/fui-skill/design-md/voltagent/DESIGN.md +521 -0
  139. package/skills/fui-skill/design-md/voltagent/README.md +5 -0
  140. package/skills/fui-skill/design-md/warp/DESIGN.md +526 -0
  141. package/skills/fui-skill/design-md/warp/README.md +5 -0
  142. package/skills/fui-skill/design-md/webflow/DESIGN.md +588 -0
  143. package/skills/fui-skill/design-md/webflow/README.md +5 -0
  144. package/skills/fui-skill/design-md/wired/DESIGN.md +497 -0
  145. package/skills/fui-skill/design-md/wired/README.md +5 -0
  146. package/skills/fui-skill/design-md/wise/DESIGN.md +544 -0
  147. package/skills/fui-skill/design-md/wise/README.md +5 -0
  148. package/skills/fui-skill/design-md/x.ai/DESIGN.md +465 -0
  149. package/skills/fui-skill/design-md/x.ai/README.md +5 -0
  150. package/skills/fui-skill/design-md/zapier/DESIGN.md +537 -0
  151. package/skills/fui-skill/design-md/zapier/README.md +5 -0
  152. package/skills/fui-skill/examples/component.vue +162 -0
  153. package/skills/fui-skill/examples/f-table-patterns.json +331 -0
  154. package/skills/fui-skill/examples/module-patterns.json +973 -0
  155. package/skills/fui-skill/examples/project-patterns.json +222 -0
  156. package/skills/fui-skill/metadata.json +75 -0
  157. package/skills/fui-skill/references/INDEX.md +144 -0
  158. package/skills/fui-skill/references/advanced-techniques.md +160 -0
  159. package/skills/fui-skill/references/coding-standards.md +112 -0
  160. package/skills/fui-skill/references/component-design.md +455 -0
  161. package/skills/fui-skill/references/component-quickref.md +77 -0
  162. package/skills/fui-skill/references/component-table.md +276 -0
  163. package/skills/fui-skill/references/components-dialog.md +192 -0
  164. package/skills/fui-skill/references/components-display.md +147 -0
  165. package/skills/fui-skill/references/components-echart.md +391 -0
  166. package/skills/fui-skill/references/components-input.md +359 -0
  167. package/skills/fui-skill/references/controls-patterns.md +847 -0
  168. package/skills/fui-skill/references/controls-styling-vocabulary.md +140 -0
  169. package/skills/fui-skill/references/db-table-design.md +77 -0
  170. package/skills/fui-skill/references/db-workflow.md +504 -0
  171. package/skills/fui-skill/references/default-function.md +415 -0
  172. package/skills/fui-skill/references/design-modes.md +85 -0
  173. package/skills/fui-skill/references/echart-templates.md +481 -0
  174. package/skills/fui-skill/references/fastproject.md +97 -0
  175. package/skills/fui-skill/references/fsheet.md +218 -0
  176. package/skills/fui-skill/references/fullstack-workflow.md +351 -0
  177. package/skills/fui-skill/references/module-data-patterns.md +126 -0
  178. package/skills/fui-skill/references/module-json-anatomy.md +137 -0
  179. package/skills/fui-skill/references/module-structure.md +260 -0
  180. package/skills/fui-skill/references/new-session.md +108 -0
  181. package/skills/fui-skill/references/pdfmake.md +60 -0
  182. package/skills/fui-skill/references/permission-system.md +169 -0
  183. package/skills/fui-skill/references/platform-architecture.md +294 -0
  184. package/skills/fui-skill/references/project-config.md +335 -0
  185. package/skills/fui-skill/references/project-provisioning.md +383 -0
  186. package/skills/fui-skill/references/script-map.md +296 -0
  187. package/skills/fui-skill/references/sql-clr-functions.md +224 -0
  188. package/skills/fui-skill/references/system-design.md +116 -0
  189. package/skills/fui-skill/references/tapi-file-api.md +191 -0
  190. package/skills/fui-skill/references/tapi-permission-patterns.md +158 -0
  191. package/skills/fui-skill/references/tapi-reference.md +549 -0
  192. package/skills/fui-skill/references/tools-registry.md +460 -0
  193. package/skills/fui-skill/references/ui-crosswindow-patterns.md +317 -0
  194. package/skills/fui-skill/references/ui-dialog-patterns.md +229 -0
  195. package/skills/fui-skill/references/ui-layout-patterns.md +176 -0
  196. package/skills/fui-skill/references/ui-patterns.md +315 -0
  197. package/skills/fui-skill/references/ui-screenshot-review.md +94 -0
  198. package/skills/fui-skill/references/ui-table-cell-patterns.md +316 -0
  199. package/skills/fui-skill/references/ui-templates.md +29 -0
  200. package/skills/fui-skill/references/verification.md +246 -0
  201. package/skills/fui-skill/references/watcher-patterns.md +196 -0
  202. package/skills/fui-skill/references/websocket-realtime.md +254 -0
  203. package/skills/fui-skill/scripts/component-3.0.js +2549 -0
  204. package/skills/fui-skill/scripts/component.js +3142 -0
  205. package/skills/fui-skill/scripts/componentTable-3.0.js +909 -0
  206. package/skills/fui-skill/scripts/componentTable.js +769 -0
  207. package/skills/fui-skill/scripts/defaultfunction-3.0.js +781 -0
  208. package/skills/fui-skill/scripts/defaultfunction.js +966 -0
  209. package/skills/fui-skill/scripts/fastproject-3.0.js +870 -0
  210. package/skills/fui-skill/scripts/fastproject.js +828 -0
  211. package/skills/fui-skill/scripts/fechart.js +890 -0
  212. package/skills/fui-skill/scripts/fsheet.js +1330 -0
@@ -0,0 +1,276 @@
1
+ # FUI Table Components (Source-Based)
2
+
3
+ > File này sở hữu: **`f-table` chuyên sâu: mọi props, auto-header, `sum-format`, readonly table**. Điều khiển trong ô (`t-*`) xem [ui-table-cell-patterns.md](ui-table-cell-patterns.md).
4
+
5
+ This file is derived from `scripts/componentTable.js` (V2) and `scripts/componentTable-3.0.js` (V3).
6
+ Focus: `f-table` and `t-*` renderers.
7
+
8
+ > **Xác định phiên bản trước khi viết headers** — V2 và V3 dùng tên field khác nhau, sai tên thì bảng không render. Xem mục "V2 vs V3 — Sự khác biệt quan trọng" cuối file.
9
+
10
+ > `f-table` đảm nhận cả hai vai trò: bảng CRUD và bảng chỉ xem (readonly). Bảng chỉ xem = `f-table` không khai báo `:update-api` (hoặc thêm `:disabled-update true`); có thể bỏ luôn `:headers` để bảng tự dựng header từ dữ liệu (xem Auto Headers bên dưới).
11
+
12
+ ## Prefix Reminder
13
+
14
+ - `f-table`: FUI component.
15
+ - `t-*`: FUI cell renderers for table columns.
16
+ - `v-data-table`: Vuetify internal implementation, but CRUD and table action flow comes from FUI wrappers.
17
+
18
+ ## f-table
19
+
20
+ ### Props (exact from source)
21
+
22
+ `value`, `headers`, `updateForm`, `updateFormAttr`, `updateApi`, `items`, `label`, `excel`, `showSearch`, `sumFormat`, `disabledHover`, `returnObject`, `itemKey`, `itemsPerPage`, `disabledUpdate`, `hideDefaultFooter`, `template`, `headercomponent`, `height`, `fixedHeader`, `fixedCols`
23
+
24
+ ### Real Behavior
25
+
26
+ 1. If a header item has `el`, table creates custom slot renderer automatically.
27
+ 2. If `updateApi.new` or `updateApi['new-action']` exists, add button appears.
28
+ 3. CRUD action slots rely on header `value: "ctrl-update"`.
29
+ 4. Editing dialog is `f-dialog` with `updateForm`.
30
+ 5. Selection result emit:
31
+ - if `returnObject=false`: emit array of `itemKey`
32
+ - if `returnObject=true`: emit selected row objects
33
+ 6. Emits row events from slots: `click:row`, `mouseover:row`, `mouseleave:row`.
34
+ 7. **Auto headers**: nếu KHÔNG truyền `:headers`, table tự build header từ `items` (xem mục Auto Headers).
35
+ 8. **Sum row / sum line**: prop `sum-format` nhận string HOẶC object — hai cách render khác nhau (xem mục sum-format).
36
+
37
+ ### Cố định cột bên trái (`fixed-cols`)
38
+
39
+ Khai `fixed-cols="N"` để giữ N cột đầu tiên khi cuộn ngang. Tính năng có ở cả FUI V2 và V3; bỏ prop, đặt `0`, hoặc truyền giá trị không hợp lệ thì bảng hoạt động như cũ.
40
+
41
+ ```json
42
+ {
43
+ "el": "f-table",
44
+ "w": 12,
45
+ "attr": {
46
+ ":items": "dsNhanVien",
47
+ "fixed-cols": "2",
48
+ ":headers": [
49
+ { "text": "Mã", "value": "Ma", "width": "100px" },
50
+ { "text": "Họ tên", "value": "HoTen", "width": "220px" },
51
+ { "text": "Phòng ban", "value": "PhongBan", "width": "180px" }
52
+ ]
53
+ }
54
+ }
55
+ ```
56
+
57
+ - Nên khai `width` cho từng cột được cố định; nếu bỏ trống, `f-table` dùng `150px`.
58
+ - `width` dạng số được hiểu là pixel; chuỗi CSS như `"120px"` vẫn được giữ nguyên.
59
+ - `fixed-cols` đếm theo thứ tự cột render thực tế. Nếu bật cột chọn dòng/group của Vuetify thì các cột hệ thống đó cũng nằm trong phép đếm.
60
+ - CSS được scope theo từng instance `f-table`, nên nhiều bảng có số cột cố định khác nhau có thể cùng xuất hiện trên một trang.
61
+
62
+ ### Auto Headers (khi không truyền `:headers`)
63
+
64
+ Khi bỏ hẳn prop `:headers`, `f-table` tự build header từ row đầu tiên của `items` (qua `buildHeader`):
65
+
66
+ - Mỗi key của row → một cột `{ text: key, value: key, divider: true }`; key có giá trị số → tự gắn `el: "t-num"` (format số bên phải).
67
+ - Nếu có `:update-api` với `edit`/`delete` và không `disabled-update` → tự thêm cột `ctrl-update` cuối bảng.
68
+ - Headers được rebuild mỗi khi `items` đổi shape (watch trên `items`) — an toàn khi data load async.
69
+
70
+ **Khi nào dùng:** bảng hiển thị nhanh, cột đúng bằng field trả về từ API (SP đã alias tên cột đẹp bằng tiếng Việt). **Khi nào KHÔNG dùng (phải khai `:headers` tường minh):** cần label khác tên field, cần ẩn bớt cột, cần `t-*` renderer tùy biến (t-time, t-check, t-link...), cần width/align cụ thể, hoặc data có field kỹ thuật (ID nội bộ, flag) không nên hiển thị.
71
+
72
+ ```json
73
+ { "el": "f-table", "w": "12", "attr": { "label": "Kết quả", ":items": "dsKetQua", "show-search": true } }
74
+ ```
75
+
76
+ ### sum-format — Tổng cột (2 dạng)
77
+
78
+ Prop `sum-format` có 2 dạng, render hoàn toàn khác nhau:
79
+
80
+ **Dạng 1 — string template → MỘT dòng text tổng dưới bảng** (trong `v-card-actions`, KHÔNG nằm trong `v-data-table`, không thẳng cột):
81
+
82
+ ```json
83
+ "sum-format": "Tổng đăng ký: [[DangKy]] | Nhập học: [[NhapHoc]]"
84
+ ```
85
+
86
+ - `[[FieldName]]` được thay bằng `_.sumBy(items, 'FieldName')` format cố định `'0,0'` (numeral).
87
+ - Kết quả là 1 dòng text duy nhất, căn phải, phía dưới bảng (có `v-divider` ngăn cách).
88
+ - Dùng khi: chỉ cần 1 dòng tóm tắt tổng, hoặc tổng của nhiều cột gộp chung 1 câu.
89
+ - Là string tĩnh → khai báo attr KHÔNG có `:` prefix.
90
+
91
+ **Dạng 2 — object → HÀNG TỔNG thật sự trong bảng** (slot `body.append` của `v-data-table`, thẳng theo từng cột):
92
+
93
+ ```json
94
+ ":sum-format": { "DangKy": "0,0", "NhapHoc": "0,0", "HocPhi": "0,0.0" }
95
+ ```
96
+
97
+ - Key = `value` của cột trong headers; value = numeral format string riêng cho cột đó (`"0,0"`, `"0,0.0"`, `"0.0%"`, ...).
98
+ - Render một `<tr>` cuối thân bảng: ô của cột có key trong object hiển thị `_.sumBy(items, key)` theo format tương ứng; các cột khác để trống. Tất cả ô căn phải, `font-weight-medium`.
99
+ - Hàng tổng nằm TRONG bảng nên thẳng hàng với cột, cuộn cùng thân bảng.
100
+ - Là object → khai báo attr CÓ `:` prefix.
101
+
102
+ **Chọn dạng nào:** user cần "hàng tổng dưới mỗi cột / dòng tổng trong bảng / tổng thẳng cột" → dạng object. User cần "dòng chữ tổng kết chung" → dạng string. **KHÔNG tự dựng hàng tổng thủ công** (không push row "Tổng" vào items, không tự viết template body.append) — dùng `sum-format`.
103
+
104
+ Ví dụ đầy đủ dạng object:
105
+
106
+ ```json
107
+ {
108
+ "el": "f-table", "w": "12",
109
+ "attr": {
110
+ "label": "Thống kê tuyển sinh",
111
+ ":items": "dsThongKe",
112
+ ":headers": [
113
+ { "text": "Ngành", "value": "TenNganh" },
114
+ { "text": "Đăng ký", "value": "DangKy", "el": "t-num" },
115
+ { "text": "Nhập học", "value": "NhapHoc", "el": "t-num" }
116
+ ],
117
+ ":sum-format": { "DangKy": "0,0", "NhapHoc": "0,0" }
118
+ }
119
+ }
120
+ ```
121
+
122
+ ### updateApi Keys Used By Source
123
+
124
+ - `new`
125
+ - `edit`
126
+ - `delete`
127
+ - `default-item`
128
+ - `new-action`
129
+ - `edit-action`
130
+ - `data-out`
131
+
132
+ ### Minimal CRUD Example
133
+
134
+ ```json
135
+ {
136
+ "el": "f-table",
137
+ "w": "12",
138
+ "attr": {
139
+ "label": "Danh sach nhan vien",
140
+ ":items": "items",
141
+ "item-key": "ID",
142
+ ":return-object": false,
143
+ "show-search": true,
144
+ "excel": true,
145
+ ":headers": [
146
+ { "text": "Ho ten", "value": "FullName" },
147
+ { "text": "Email", "value": "Email" },
148
+ { "text": "Trang thai", "value": "Active", "el": "t-boolean", "align": "center", "width": "90px" },
149
+ { "text": "Tac vu", "value": "ctrl-update", "align": "center", "width": "120px" }
150
+ ],
151
+ ":update-form": [
152
+ { "el": "v-text-field", "attr": { "v-model": "FullName", "label": "Ho ten", ":required": true } },
153
+ { "el": "v-text-field", "attr": { "v-model": "Email", "label": "Email", ":required": true } }
154
+ ],
155
+ ":update-api": {
156
+ "default-item": { "FullName": "", "Email": "", "Active": true },
157
+ "new": {
158
+ "API": "/api/staff/create",
159
+ "IN": { "FullName": "item.FullName", "Email": "item.Email", "Active": "item.Active" },
160
+ "CALLBACK": { "CALL": "apiLoadItems" }
161
+ },
162
+ "edit": {
163
+ "API": "/api/staff/update",
164
+ "IN": { "ID": "item.ID", "FullName": "item.FullName", "Email": "item.Email", "Active": "item.Active" },
165
+ "CALLBACK": { "CALL": "apiLoadItems" }
166
+ },
167
+ "delete": {
168
+ "CONFIRM": "Xac nhan xoa?",
169
+ "API": "/api/staff/delete",
170
+ "IN": { "ID": "item.ID" },
171
+ "CALLBACK": { "CALL": "apiLoadItems" }
172
+ }
173
+ }
174
+ }
175
+ }
176
+ ```
177
+
178
+ ## Readonly Table
179
+
180
+ Bảng chỉ xem = `f-table` không có `:update-api` (không hiện nút thêm/sửa/xóa) — bỏ `:headers` nếu muốn auto-build:
181
+
182
+ ```json
183
+ {
184
+ "el": "f-table",
185
+ "w": "12",
186
+ "attr": {
187
+ "label": "Danh sach xem nhanh",
188
+ ":items": "items",
189
+ "item-key": "ID",
190
+ "show-search": true,
191
+ "excel": true,
192
+ ":items-per-page": 20
193
+ }
194
+ }
195
+ ```
196
+
197
+ ## t-* Cell Renderers
198
+
199
+ Use in `headers` by setting `el`.
200
+
201
+ Example header:
202
+
203
+ ```json
204
+ { "text": "Ngay tao", "value": "CreatedAt", "el": "t-time", "attr": { "format": "DD/MM/YYYY HH:mm" } }
205
+ ```
206
+
207
+ ### Supported `t-*` components
208
+
209
+ - `t-html`
210
+ - `t-label`
211
+ - `t-num`
212
+ - `t-time`
213
+ - `t-boolean`
214
+ - `t-check`
215
+ - `t-text`
216
+ - `t-select`
217
+ - `t-combobox`
218
+ - `t-menu`
219
+ - `t-link`
220
+ - `t-button`
221
+
222
+ ### Notes
223
+
224
+ 1. Editable renderers (`t-check`, `t-text`, `t-select`, `t-combobox`, `t-menu`, `t-button`) use `tableActionEvent`.
225
+ 2. For dialog opening in row actions, use `target: "dialog"` plus `wid`, `url`, `title`, `onclose`.
226
+ 3. Apply literal-string rule only in Action `IN` mapping.
227
+ Static component props without `:` are plain strings by default.
228
+
229
+ ---
230
+
231
+ ## V2 vs V3 — Sự khác biệt quan trọng (nguồn: `componentTable.js` vs `componentTable-3.0.js`)
232
+
233
+ Phiên bản framework được xác định từ `_projectInfo.json` hoặc `_moduleInfo.json` — tra trước khi viết headers.
234
+
235
+ ### Header field names
236
+
237
+ **Đây là điểm dễ nhầm nhất.** Hai trường `text`/`value` của V2 đổi tên thành `title`/`key` ở V3:
238
+
239
+ | Trường | V2 (`componentTable.js`) | V3 (`componentTable-3.0.js`) |
240
+ |---|---|---|
241
+ | Nhãn cột | `"text": "Tên cột"` | `"title": "Tên cột"` |
242
+ | Field data | `"value": "TenField"` | `"key": "TenField"` |
243
+ | Cột ctrl | `"value": "ctrl-update"` | `"key": "ctrl-update"` |
244
+
245
+ ```json
246
+ // V2 ✅
247
+ { "text": "Họ tên", "value": "HoTen", "el": "t-label" }
248
+ { "text": "Tác vụ", "value": "ctrl-update", "align": "center" }
249
+
250
+ // V3 ✅
251
+ { "title": "Họ tên", "key": "HoTen", "el": "t-label" }
252
+ { "title": "Tác vụ", "key": "ctrl-update", "align": "center" }
253
+ ```
254
+
255
+ > Dùng `text`/`value` trên project V3 → cột render nhưng **tiêu đề biến mất và sort không hoạt động** (Vuetify 3 đọc `title`/`key`, bỏ qua `text`/`value`). Không có lỗi JS nào báo — chỉ nhìn thấy qua ảnh render.
256
+
257
+ ### Props bổ sung ở V3
258
+
259
+ | Prop | Mặc định V3 | Ghi chú |
260
+ |---|---|---|
261
+ | `density` | `'compact'` | Mật độ dòng — `'compact'`/`'comfortable'`/`'default'` |
262
+ | `disable-sort` | `false` | Tắt sort toàn bảng |
263
+ | `slots` | `null` | Custom slot động (object `{ name, html }`) |
264
+ | `group-template` | `null` | Template cho nhóm gộp (`groupBy`) |
265
+ | `height` | `null` | Giống V2: null/bỏ trống = tự giãn; ≤0 = fill đáy; >0 = px cố định |
266
+
267
+ ### sum-format object dạng V3
268
+
269
+ Ở V3, key của `sum-format` object phải khớp `key` của header (không phải `value`):
270
+
271
+ ```json
272
+ // V3 ✅ — key = "DangKy" khớp với header { "key": "DangKy" }
273
+ ":sum-format": { "DangKy": "0,0", "NhapHoc": "0,0" }
274
+ ```
275
+
276
+ Logic giống V2 hoàn toàn — chỉ khác ở chỗ V3 đọc `col.key` thay vì `col.value` nên tên field phải nhất quán.
@@ -0,0 +1,192 @@
1
+ # FUI Dialog & Overlay Components
2
+
3
+ > File này sở hữu: **`f-dialog`, `f-window`, `f-editor`**. Pattern dialog thủ công (`v-dialog` + hidden-container) xem [ui-dialog-patterns.md](ui-dialog-patterns.md).
4
+
5
+ Components liên quan đến dialog, overlay, và editor nội dung. Xem prefix/binding rules tại [components-display.md](components-display.md).
6
+
7
+ ## f-window
8
+
9
+ - Props (source): `id`
10
+ - Behavior: internal iframe dialog host, thường được mở qua `openWindow(...)`
11
+ - Example:
12
+
13
+ ```json
14
+ {
15
+ "FUN": "openWindow",
16
+ "IN": {
17
+ "id": "`winUser",
18
+ "url": "'/fp/module?mid=123'",
19
+ "title": "Chi tiet user",
20
+ "width": 1100
21
+ }
22
+ }
23
+ ```
24
+
25
+ ## f-editor
26
+
27
+ - Props (source): `value`, `imageapi`, `height`, `toolbar`
28
+ - Emit: `input` with HTML content
29
+ - Behavior: wraps CKEditor with upload auth header
30
+ - Example:
31
+
32
+ ```json
33
+ {
34
+ "el": "f-editor",
35
+ "w": "12",
36
+ "attr": {
37
+ "v-model": "formData.contentHtml",
38
+ "imageapi": "/api/editor/upload",
39
+ ":height": 360
40
+ }
41
+ }
42
+ ```
43
+
44
+ ## f-editor-dialog
45
+
46
+ - Props (source): `value`, `imageapi`, `label`, `width`, `toolbar`
47
+ - Runtime expectation: `value` là object (`open`, `text`, `object`, `ok`), không phải plain string
48
+ - Behavior: modal editor, write-back on OK
49
+ - Example:
50
+
51
+ ```json
52
+ {
53
+ "el": "f-editor-dialog",
54
+ "w": "6",
55
+ "attr": {
56
+ ":value": "editorState",
57
+ "label": "Noi dung mo rong",
58
+ ":width": 1000,
59
+ "imageapi": "/api/editor/upload"
60
+ }
61
+ }
62
+ ```
63
+
64
+ ## f-dialog
65
+
66
+ Modal dialog tự build form từ mảng `controls`, có hỗ trợ watchers cục bộ, validation, và action buttons.
67
+
68
+ - Props:
69
+ - `value` (Boolean, default: `false`) — v-model để mở/đóng dialog
70
+ - `data` (Object, default: `{}`) — dữ liệu đầu vào, bind bằng `:data.sync`; khi dialog mở dữ liệu này được copy vào các field
71
+ - `dataOut` (Object, default: `{}`) — dữ liệu đầu ra, bind bằng `:data-out.sync`; nhận instance component khi dialog mở
72
+ - `title` (String, default: `''`) — tiêu đề dialog
73
+ - `controls` (Array, default: `[]`) — mảng control definitions để build form; mỗi control có `el`, `attr`, `w` (col width); field nào có `v-model` không bắt đầu bằng `vueData.` sẽ được tạo data cục bộ tự động (khởi tạo `null`)
74
+ - `watch` (Object, default: `{}`) — watchers cục bộ trong dialog; key là tên field, value là action chạy khi field thay đổi; watchers được đăng ký khi dialog mở và hủy khi đóng
75
+ - `button` (Array, default: `[]`) — mảng button definitions (xem cấu trúc button bên dưới)
76
+ - `disableValidate` (Boolean, default: `false`) — bỏ qua form validation khi `true`
77
+ - `width` (Number, default: `800`) — chiều rộng dialog (px)
78
+ - `openAction` (Object, default: `null`) — action chạy ngay khi dialog mở
79
+
80
+ - Emits:
81
+ - `input` — mở/đóng dialog (dùng với v-model)
82
+ - `update:data-out` — phát ra instance component khi dialog mở (để parent truy cập data cục bộ)
83
+ - `update:data` — phát ra `v_outData` khi button có `getoutdata: true` được click (sau khi validation pass)
84
+
85
+ - Vòng đời khi mở (`value = true`):
86
+ 1. Reset tất cả field về giá trị từ `:data` (gọi `setDefaultData`)
87
+ 2. Đăng ký watchers từ prop `watch`
88
+ 3. Chạy `openAction` nếu có
89
+ 4. Emit `update:data-out` với instance component
90
+
91
+ - Vòng đời khi đóng (`value = false`):
92
+ 1. Hủy tất cả watchers đã đăng ký
93
+
94
+ - Cấu trúc button object:
95
+ - `label` (String) — text hiển thị trên button
96
+ - `color` (String, default: `"primary"`) — màu button
97
+ - `elevation` (Number, default: `0`) — độ nổi
98
+ - `text` (Boolean, default: `true`) — dạng text button
99
+ - `type` (String) — ví dụ `"submit"`
100
+ - `:disabled` (String) — biểu thức Vue để disable button, ví dụ `"!checkBoxValue"`
101
+ - `v-if` (String) — biểu thức Vue để ẩn/hiện button, ví dụ `"ModuleID==1"`
102
+ - `icon-text` (String) — icon MDI hiển thị bên trái label
103
+ - `checkvalid` (Boolean) — validate form trước khi chạy action; nếu không pass thì dừng
104
+ - `getoutdata` (Boolean) — sync field values vào `v_outData` rồi emit `update:data`; cũng trigger validation
105
+ - `action` (Array | Function) — danh sách actions chạy khi click; context truyền vào gồm tất cả fields trong `v_outData` và key `dData` trỏ về `v_outData`
106
+
107
+ - Lưu ý:
108
+ - Button click được debounce 500ms (leading edge) để tránh double-click
109
+ - Controls hỗ trợ `br: true` để xuống hàng (row break)
110
+ - Template được build tĩnh lúc `data()` init, không re-render khi prop `controls` thay đổi
111
+ - `watch` trong prop template là `:watch` (bind động), khác với `watch` mặc định của Vue
112
+ - **Không dùng `f-dialog` bên trong template của component:** `f-dialog` chỉ hoạt động khi được khai báo trực tiếp trong `controls` của cấu trúc JSON module. Nếu đặt trong template của một Vue component, nó sẽ không hoạt động đúng.
113
+ - **Khai báo biến `vueData` trước khi dùng trong controls:** Nếu một control bind vào `vueData.someVar`, biến đó phải được khai báo trước trong `data` của module — Vue không thể thiết lập reactivity cho biến chưa tồn tại lúc init.
114
+
115
+ ```json
116
+ "data": [
117
+ { "projectList": [] }
118
+ ],
119
+ "controls": [
120
+ {
121
+ "prop": "fluid pa-0",
122
+ "rows": [{ "prop": "", "cols": [
123
+ {
124
+ "el": "v-autocomplete",
125
+ "attr": {
126
+ "v-model": "pid",
127
+ "label": "Module name",
128
+ ":items": "vueData.projectList",
129
+ "item-text": "ModuleName",
130
+ "item-value": "ModuleID"
131
+ }
132
+ }
133
+ ]}]
134
+ }
135
+ ]
136
+ ```
137
+
138
+ - Ví dụ đầy đủ:
139
+
140
+ ```json
141
+ {
142
+ "el": "f-dialog",
143
+ "attr": {
144
+ "v-model": "dialogOpen",
145
+ ":data.sync": "dialogData",
146
+ "title": "Nhap du lieu",
147
+ ":open-action": { "MESSBOX": "Bạn vừa mở dialog" },
148
+ ":controls": [
149
+ { "el": "v-text-field", "attr": { "v-model": "Domain", "label": "Domain" }, "w": 4 },
150
+ { "el": "v-text-field", "attr": { "v-model": "ModuleID", "label": "ModuleID" }, "w": 3 },
151
+ { "el": "v-text-field", "attr": { "v-model": "ModuleName", "label": "ModuleName" }, "w": 8 },
152
+ {
153
+ "el": "v-checkbox",
154
+ "attr": { ":label": "`Tôi đã hiểu và đồng ý: ${checkBoxValue}`", "v-model": "checkBoxValue" }
155
+ },
156
+ {
157
+ "el": "v-select",
158
+ "attr": {
159
+ "label": "select", "v-model": "bienselect",
160
+ ":items": "vueData.Mang", "item-text": "AppName", "item-value": "AppListID"
161
+ }
162
+ }
163
+ ],
164
+ ":watch": {
165
+ "bienselect": { "MESSBOX": "Watch Select {{bienselect}}" },
166
+ "Domain": { "MESSBOX": "Watch textbox {{Domain}}" }
167
+ },
168
+ ":button": [
169
+ {
170
+ "label": "Submit OK",
171
+ "type": "submit",
172
+ ":disabled": "!checkBoxValue",
173
+ "action": [
174
+ { "ModuleName": "gan gia tri cho ModuleName" },
175
+ { "MESSBOX": "thong bao 1" },
176
+ { "dialogOpen": false }
177
+ ]
178
+ },
179
+ {
180
+ "label": "Chay mot API",
181
+ "checkvalid": true,
182
+ "v-if": "ModuleID==1",
183
+ "action": [{ "API": "/chaymotapi" }]
184
+ },
185
+ {
186
+ "label": "Close",
187
+ "action": [{ "dialogOpen": false }]
188
+ }
189
+ ]
190
+ }
191
+ }
192
+ ```
@@ -0,0 +1,147 @@
1
+ # FUI Display & Presentation Components
2
+
3
+ > File này sở hữu: **component hiển thị: `f-label`, `f-title`, `f-box`, `f-header`, `f-slider`, chip/badge**.
4
+
5
+ Components dùng để hiển thị thông tin, chart, media. File này cũng chứa prefix/binding rules áp dụng cho tất cả f-* components.
6
+
7
+ ## Prefix và Binding Rules
8
+
9
+ - `f-*`: FUI components (định nghĩa trong FUI runtime)
10
+ - `v-*`: Vuetify components
11
+ - `uc-*`: Custom module components từ `components/`
12
+ - Trong `module.json`, truyền props qua `attr`
13
+ - Dùng kebab-case trong JSON cho custom props (`api-upload`, `item-value`)
14
+ - Giá trị động dùng `:prop`
15
+ - Dùng `v-on:*` trong JSON (không dùng `@*`)
16
+ - Props không có `:` (ví dụ `url`, `api-upload`) là plain string mặc định
17
+ - Literal-string forcing (backtick/quote) chỉ dùng trong Action `IN` mapping, không dùng cho static props
18
+
19
+ ## Minimal Control Pattern
20
+
21
+ ```json
22
+ {
23
+ "el": "f-date",
24
+ "w": "6",
25
+ "attr": {
26
+ "v-model": "formData.fromDate",
27
+ "label": "From date"
28
+ }
29
+ }
30
+ ```
31
+
32
+ ---
33
+
34
+ ## f-label
35
+
36
+ - Props (source): `items`, `text`, `color`, `iconText`
37
+ - Behavior: render `v-chip` từ `text` và/hoặc `items`
38
+ - Example:
39
+
40
+ ```json
41
+ {
42
+ "el": "f-label",
43
+ "w": "12",
44
+ "attr": {
45
+ "text": "Trang thai",
46
+ "icon-text": "mdi-information"
47
+ }
48
+ }
49
+ ```
50
+
51
+ ## f-box
52
+
53
+ - Props (source): `rowFormat`, `items`, `label`, `edit`, `saveclick`
54
+ - Emit: `input` khi dữ liệu nội bộ thay đổi
55
+ - Behavior: hiển thị/chỉnh sửa key-value rows, tự build row format từ data nếu thiếu
56
+ - `rowFormat`: mảng `{ text, value, noEdit }` — `noEdit: true` khóa cột đó khi `edit=true`
57
+ - `items`: object hoặc array; object tự động wrap thành array 1 phần tử
58
+ - Example:
59
+
60
+ ```json
61
+ {
62
+ "el": "f-box",
63
+ "w": "12",
64
+ "attr": {
65
+ "label": "Thong tin",
66
+ ":items": "detailData",
67
+ ":edit": "isEditMode",
68
+ ":row-format": [
69
+ { "text": "Mã", "value": "StudentID", "noEdit": true },
70
+ { "text": "Họ tên", "value": "FullName" },
71
+ { "text": "Ngày sinh", "value": "BirthDate" }
72
+ ]
73
+ }
74
+ }
75
+ ```
76
+
77
+ ## f-header
78
+
79
+ - Props (source): `label`
80
+ - Example:
81
+
82
+ ```json
83
+ {
84
+ "el": "f-header",
85
+ "w": "12",
86
+ "attr": { "label": "Bao cao tong hop" }
87
+ }
88
+ ```
89
+
90
+ ## f-title
91
+
92
+ - Props (source): `label`
93
+ - Example:
94
+
95
+ ```json
96
+ {
97
+ "el": "f-title",
98
+ "w": "12",
99
+ "attr": { "label": "Danh sach ho so" }
100
+ }
101
+ ```
102
+
103
+ ## f-slider
104
+
105
+ - Props (source): `items`, `itemAttr`
106
+ - Behavior: bọc `v-carousel` và `v-carousel-item`
107
+ - Example:
108
+
109
+ ```json
110
+ {
111
+ "el": "f-slider",
112
+ "w": "12",
113
+ "attr": {
114
+ ":items": "slideItems",
115
+ ":item-attr": { "contain": true }
116
+ }
117
+ }
118
+ ```
119
+
120
+ ## f-echart
121
+
122
+ → Xem [`components-echart.md`](components-echart.md) — tài liệu đầy đủ về props, config, global module `FEchartFormatter` và ví dụ.
123
+
124
+ ## f-pdfmake
125
+
126
+ - Props (source): `data`
127
+ - Behavior: render PDF trong iframe, re-render khi `data` thay đổi (deep watch)
128
+ - Example:
129
+
130
+ ```json
131
+ {
132
+ "el": "f-pdfmake",
133
+ "w": "12",
134
+ "attr": {
135
+ ":data": "pdfDefinition",
136
+ "height": "550"
137
+ }
138
+ }
139
+ ```
140
+
141
+ ---
142
+
143
+ ## Practical Notes
144
+
145
+ 1. Hầu hết `f-*` components forward unknown attrs qua `v-bind="$attrs"` — Vuetify attrs vẫn hoạt động nếu child là Vuetify control.
146
+ 2. Literal-string rule chỉ áp dụng khi truyền API/path strings trong Action `IN` mapping.
147
+ 3. Xem `references/component-table.md` cho `f-table`.