@fui-org/fui-cli 1.3.2 → 2.1.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 (115) hide show
  1. package/README.md +21 -3
  2. package/dist/fui-cx180e19.js +379 -0
  3. package/dist/fui.js +1 -1
  4. package/package.json +3 -6
  5. package/skills/fui/SKILL.md +9 -41
  6. package/skills/fui-skill/SKILL.md +95 -225
  7. package/skills/fui-skill/assets/projectdefaultstyle-3.0.css +555 -0
  8. package/skills/fui-skill/assets/projectdefaultstyle.css +207 -235
  9. package/skills/fui-skill/references/INDEX.md +105 -137
  10. package/skills/fui-skill/references/advanced-techniques.md +76 -68
  11. package/skills/fui-skill/references/coding-standards.md +56 -56
  12. package/skills/fui-skill/references/component-design.md +166 -173
  13. package/skills/fui-skill/references/component-quickref.md +61 -60
  14. package/skills/fui-skill/references/component-table.md +128 -117
  15. package/skills/fui-skill/references/components-dialog.md +55 -56
  16. package/skills/fui-skill/references/components-display.md +24 -30
  17. package/skills/fui-skill/references/components-echart.md +186 -261
  18. package/skills/fui-skill/references/components-input.md +72 -96
  19. package/skills/fui-skill/references/controls-patterns.md +196 -342
  20. package/skills/fui-skill/references/controls-styling-vocabulary.md +130 -97
  21. package/skills/fui-skill/references/db-table-design.md +24 -28
  22. package/skills/fui-skill/references/db-workflow.md +191 -390
  23. package/skills/fui-skill/references/default-function.md +169 -128
  24. package/skills/fui-skill/references/design-modes.md +35 -63
  25. package/skills/fui-skill/references/echart-templates.md +204 -196
  26. package/skills/fui-skill/references/fastproject.md +62 -60
  27. package/skills/fui-skill/references/fsheet.md +109 -124
  28. package/skills/fui-skill/references/fullstack-workflow.md +90 -128
  29. package/skills/fui-skill/references/module-data-patterns.md +31 -40
  30. package/skills/fui-skill/references/module-json-anatomy.md +47 -52
  31. package/skills/fui-skill/references/module-structure.md +80 -196
  32. package/skills/fui-skill/references/new-session.md +49 -51
  33. package/skills/fui-skill/references/pdfmake.md +17 -17
  34. package/skills/fui-skill/references/permission-system.md +89 -108
  35. package/skills/fui-skill/references/platform-architecture.md +128 -153
  36. package/skills/fui-skill/references/project-config.md +102 -134
  37. package/skills/fui-skill/references/project-provisioning.md +139 -244
  38. package/skills/fui-skill/references/script-map.md +208 -242
  39. package/skills/fui-skill/references/sql-clr-functions.md +98 -97
  40. package/skills/fui-skill/references/system-design.md +63 -88
  41. package/skills/fui-skill/references/tapi-file-api.md +46 -52
  42. package/skills/fui-skill/references/tapi-permission-patterns.md +51 -53
  43. package/skills/fui-skill/references/tapi-reference.md +132 -207
  44. package/skills/fui-skill/references/tools-registry.md +84 -460
  45. package/skills/fui-skill/references/ui-crosswindow-patterns.md +79 -75
  46. package/skills/fui-skill/references/ui-dialog-patterns.md +98 -72
  47. package/skills/fui-skill/references/ui-layout-patterns.md +26 -26
  48. package/skills/fui-skill/references/ui-patterns.md +71 -83
  49. package/skills/fui-skill/references/ui-screenshot-review.md +63 -62
  50. package/skills/fui-skill/references/ui-table-cell-patterns.md +61 -59
  51. package/skills/fui-skill/references/ui-templates.md +16 -23
  52. package/skills/fui-skill/references/verification.md +236 -246
  53. package/skills/fui-skill/references/watcher-patterns.md +30 -63
  54. package/skills/fui-skill/references/websocket-realtime.md +83 -66
  55. package/skills/fui-skill/scripts/component-3.0.js +298 -131
  56. package/skills/fui-skill/scripts/component.js +277 -271
  57. package/skills/fui-skill/scripts/componentTable-3.0.js +182 -53
  58. package/skills/fui-skill/scripts/componentTable.js +171 -49
  59. package/skills/fui-skill/scripts/defaultfunction-3.0.js +88 -3
  60. package/skills/fui-skill/scripts/defaultfunction.js +88 -3
  61. package/skills/fui-skill/scripts/fsheet.js +38 -0
  62. package/skills/fui-target/.claude-plugin/plugin.json +6 -0
  63. package/skills/fui-target/hooks/hooks.json +1 -0
  64. package/skills/fui-target/hooks/register.tsx +71 -0
  65. package/skills/fui-target/types/index.d.ts +7 -0
  66. package/dist/fui-y8an39cn.js +0 -420
  67. package/skills/fui-skill/README.md +0 -112
  68. package/skills/fui-skill/metadata.json +0 -75
  69. package/skills/fui-skill-cli/SKILL.md +0 -139
  70. package/skills/fui-skill-cli/references/INDEX.md +0 -110
  71. package/skills/fui-skill-cli/references/advanced-techniques.md +0 -168
  72. package/skills/fui-skill-cli/references/coding-standards.md +0 -112
  73. package/skills/fui-skill-cli/references/component-design.md +0 -448
  74. package/skills/fui-skill-cli/references/component-quickref.md +0 -78
  75. package/skills/fui-skill-cli/references/component-table.md +0 -248
  76. package/skills/fui-skill-cli/references/components-dialog.md +0 -191
  77. package/skills/fui-skill-cli/references/components-display.md +0 -141
  78. package/skills/fui-skill-cli/references/components-echart.md +0 -316
  79. package/skills/fui-skill-cli/references/components-input.md +0 -335
  80. package/skills/fui-skill-cli/references/controls-patterns.md +0 -701
  81. package/skills/fui-skill-cli/references/controls-styling-vocabulary.md +0 -137
  82. package/skills/fui-skill-cli/references/db-table-design.md +0 -73
  83. package/skills/fui-skill-cli/references/db-workflow.md +0 -288
  84. package/skills/fui-skill-cli/references/default-function.md +0 -425
  85. package/skills/fui-skill-cli/references/design-modes.md +0 -57
  86. package/skills/fui-skill-cli/references/echart-templates.md +0 -489
  87. package/skills/fui-skill-cli/references/fastproject.md +0 -99
  88. package/skills/fui-skill-cli/references/fsheet.md +0 -203
  89. package/skills/fui-skill-cli/references/fullstack-workflow.md +0 -313
  90. package/skills/fui-skill-cli/references/module-data-patterns.md +0 -117
  91. package/skills/fui-skill-cli/references/module-json-anatomy.md +0 -132
  92. package/skills/fui-skill-cli/references/module-structure.md +0 -141
  93. package/skills/fui-skill-cli/references/new-session.md +0 -85
  94. package/skills/fui-skill-cli/references/pdfmake.md +0 -60
  95. package/skills/fui-skill-cli/references/permission-system.md +0 -150
  96. package/skills/fui-skill-cli/references/platform-architecture.md +0 -269
  97. package/skills/fui-skill-cli/references/project-config.md +0 -303
  98. package/skills/fui-skill-cli/references/project-provisioning.md +0 -278
  99. package/skills/fui-skill-cli/references/script-map.md +0 -262
  100. package/skills/fui-skill-cli/references/sql-clr-functions.md +0 -225
  101. package/skills/fui-skill-cli/references/system-design.md +0 -89
  102. package/skills/fui-skill-cli/references/tapi-file-api.md +0 -185
  103. package/skills/fui-skill-cli/references/tapi-permission-patterns.md +0 -156
  104. package/skills/fui-skill-cli/references/tapi-reference.md +0 -474
  105. package/skills/fui-skill-cli/references/tools-registry.md +0 -84
  106. package/skills/fui-skill-cli/references/ui-crosswindow-patterns.md +0 -321
  107. package/skills/fui-skill-cli/references/ui-dialog-patterns.md +0 -255
  108. package/skills/fui-skill-cli/references/ui-layout-patterns.md +0 -176
  109. package/skills/fui-skill-cli/references/ui-patterns.md +0 -303
  110. package/skills/fui-skill-cli/references/ui-screenshot-review.md +0 -95
  111. package/skills/fui-skill-cli/references/ui-table-cell-patterns.md +0 -318
  112. package/skills/fui-skill-cli/references/ui-templates.md +0 -22
  113. package/skills/fui-skill-cli/references/verification.md +0 -236
  114. package/skills/fui-skill-cli/references/watcher-patterns.md +0 -163
  115. package/skills/fui-skill-cli/references/websocket-realtime.md +0 -271
@@ -1,45 +1,45 @@
1
1
  # Default Functions
2
2
 
3
- > File này sở hữu: **hàm tiện ích FUI dùng được trong `FUN`/`EXE`/`script.js`** (openWindow, ajaxCALL, jsonToExcel, groupBy...). Vị trí trong source xem [script-map.md](script-map.md).
3
+ > Owns: **FUI utility functions usable in `FUN`/`EXE`/`script.js`** (openWindow, ajaxCALL, jsonToExcel, groupBy...). Source locations: [script-map.md](script-map.md).
4
4
 
5
- Các hàm và biến global được định nghĩa trong `defaultfunction.js` — tự động load trong mọi module FUI V2.
5
+ Globals defined in `defaultfunction.js`, auto-loaded in every FUI V2 module.
6
6
 
7
7
  ---
8
8
 
9
9
  ## Global Variables
10
10
 
11
- | Variable | Mô tả |
12
- |---|---|
13
- | `$isMobile` | `true` nếu user agent là thiết bị mobile |
14
- | `$isPhone` | `true` nếu là điện thoại (không tính tablet) |
15
- | `$isApple` | `true` nếu là thiết bị Apple (iPad, iPhone, iPod) |
11
+ | Variable | Meaning |
12
+ | ----------- | ------------------------------------------- |
13
+ | `$isMobile` | `true` if mobile user agent |
14
+ | `$isPhone` | `true` if phone (not tablet) |
15
+ | `$isApple` | `true` if Apple device (iPad, iPhone, iPod) |
16
16
 
17
17
  ---
18
18
 
19
- ## Dialog & Thông báo
19
+ ## Dialogs & Messages
20
20
 
21
21
  ### confirm(obj)
22
22
 
23
- Hiển thị hộp thoại xác nhận OK/Cancel có style. Wrapper của `$.confirm` (jquery-confirm).
23
+ Styled OK/Cancel dialog; wraps `$.confirm` (jquery-confirm).
24
24
 
25
- | Param | Mô tả |
26
- |---|---|
27
- | `title` | Tiêu đề dialog |
28
- | `message` | Nội dung |
29
- | `action` | Function chạy khi nhấn OK |
30
- | `cancel` | Function chạy khi nhấn Cancel (tùy chọn) |
31
- | `type` | Màu: `'blue'` (mặc định), `'red'`, `'green'`, `'orange'` |
32
- | `icon` | Icon class, ví dụ `'mdi mdi-delete'` |
25
+ | Param | Meaning |
26
+ | --------- | --------------------------------------------------------- |
27
+ | `title` | Title |
28
+ | `message` | Body |
29
+ | `action` | Function run on OK |
30
+ | `cancel` | Function run on Cancel (optional) |
31
+ | `type` | Color: `'blue'` (default), `'red'`, `'green'`, `'orange'` |
32
+ | `icon` | Icon class, e.g. `'mdi mdi-delete'` |
33
33
 
34
34
  ```js
35
35
  confirm({
36
- title: 'Xác nhận xóa',
37
- message: 'Bạn có chắc muốn xóa bản ghi này không?',
38
- type: 'red',
39
- icon: 'mdi mdi-delete',
40
- action: function() {
41
- CALL(vueData.actDelete);
42
- }
36
+ title: "Xác nhận xóa",
37
+ message: "Bạn có chắc muốn xóa bản ghi này không?",
38
+ type: "red",
39
+ icon: "mdi mdi-delete",
40
+ action: function () {
41
+ CALL(vueData.actDelete);
42
+ },
43
43
  });
44
44
  ```
45
45
 
@@ -47,31 +47,31 @@ confirm({
47
47
 
48
48
  ### showMessage(obj)
49
49
 
50
- Hiển thị hộp thoại thông báo (chỉ có nút Close). Wrapper của `$.dialog`.
50
+ Message dialog (Close button only); wraps `$.dialog`.
51
51
 
52
- | Param | Mô tả |
53
- |---|---|
54
- | `title` | Tiêu đề |
55
- | `message` | Nội dung |
56
- | `type` | Màu: `'blue'`, `'red'`, `'green'` |
57
- | `icon` | Icon class |
58
- | `onclose` | FUI action object chạy sau khi đóng dialog |
52
+ | Param | Meaning |
53
+ | --------- | ----------------------------------- |
54
+ | `title` | Title |
55
+ | `message` | Body |
56
+ | `type` | Color: `'blue'`, `'red'`, `'green'` |
57
+ | `icon` | Icon class |
58
+ | `onclose` | FUI action object run after close |
59
59
 
60
60
  ```js
61
- showMessage({ title: 'Thông báo', message: 'Lưu thành công!' });
61
+ showMessage({ title: "Thông báo", message: "Lưu thành công!" });
62
62
 
63
63
  showMessage({
64
- title: 'Lỗi',
65
- message: 'Không tìm thấy dữ liệu',
66
- type: 'red',
67
- icon: 'mdi mdi-alert-circle'
64
+ title: "Lỗi",
65
+ message: "Không tìm thấy dữ liệu",
66
+ type: "red",
67
+ icon: "mdi mdi-alert-circle",
68
68
  });
69
69
 
70
70
  // Chạy action sau khi đóng
71
71
  showMessage({
72
- title: 'Hoàn tất',
73
- message: 'Import xong!',
74
- onclose: vueData.actReload
72
+ title: "Hoàn tất",
73
+ message: "Import xong!",
74
+ onclose: vueData.actReload,
75
75
  });
76
76
  ```
77
77
 
@@ -81,57 +81,57 @@ showMessage({
81
81
 
82
82
  ### pushRouter(router)
83
83
 
84
- Cập nhật URL trên thanh địa chỉ trình duyệt (không reload trang). Dùng để đồng bộ URL với trạng thái UI hiện tại.
84
+ Updates the browser URL without reload — sync URL with UI state.
85
85
 
86
86
  ```js
87
- pushRouter('/fp/don-hang/danh-sach');
87
+ pushRouter("/fp/don-hang/danh-sach");
88
88
  ```
89
89
 
90
90
  ---
91
91
 
92
92
  ### openWindow(obj)
93
93
 
94
- Mở một cửa sổ FUI (`f-window`) overlay trên trang hiện tại.
94
+ Opens an FUI window (`f-window`) overlay.
95
95
 
96
- | Param | Mô tả |
97
- |---|---|
98
- | `url` | URL nội dung cửa sổ (bắt buộc) |
99
- | `title` | Tiêu đề cửa sổ |
100
- | `id` | ID định danh (tự sinh nếu bỏ qua) — dùng để tránh mở trùng |
101
- | `width` | Chiều rộng (px hoặc %) |
102
- | `height` | Chiều cao |
96
+ | Param | Meaning |
97
+ | -------- | --------------------------------------------------------- |
98
+ | `url` | Content URL (required) |
99
+ | `title` | Window title |
100
+ | `id` | Identifier (auto if omitted) — prevents duplicate windows |
101
+ | `width` | Width (px or %) |
102
+ | `height` | Height |
103
103
 
104
104
  ```js
105
105
  // Cách đơn giản — chỉ truyền URL
106
- openWindow('/fp/san-pham/chi-tiet?id=123');
106
+ openWindow("/fp/san-pham/chi-tiet?id=123");
107
107
 
108
108
  // Đầy đủ options
109
109
  openWindow({
110
- id: 'winChiTiet',
111
- url: '/fp/san-pham/chi-tiet?id=' + vueData.selectedId,
112
- title: 'Chi tiết sản phẩm',
113
- width: '80%'
110
+ id: "winChiTiet",
111
+ url: "/fp/san-pham/chi-tiet?id=" + vueData.selectedId,
112
+ title: "Chi tiết sản phẩm",
113
+ width: "80%",
114
114
  });
115
115
  ```
116
116
 
117
- > Nếu gọi từ bên trong một `f-window` (iframe), FUI tự động chuyển sang `windowSendMessage('#PARENT', 'openWindow', obj)` để mở ở cửa sổ cha.
117
+ > Called inside an `f-window` (iframe) → FUI switches to `windowSendMessage('#PARENT', 'openWindow', obj)` to open in the parent.
118
118
 
119
119
  ---
120
120
 
121
121
  ### redirect(obj, query)
122
122
 
123
- Chuyển hướng trang hiện tại sang URL khác.
123
+ Navigates the current page to another URL.
124
124
 
125
125
  ```js
126
- redirect('/fp/trang-chu');
127
- redirect({ url: '/fp/don-hang', query: true }); // giữ lại query params hiện tại
126
+ redirect("/fp/trang-chu");
127
+ redirect({ url: "/fp/don-hang", query: true }); // giữ lại query params hiện tại
128
128
  ```
129
129
 
130
130
  ---
131
131
 
132
132
  ### reload()
133
133
 
134
- Tải lại trang hiện tại.
134
+ Reloads the page.
135
135
 
136
136
  ```js
137
137
  reload();
@@ -141,20 +141,20 @@ reload();
141
141
 
142
142
  ### windowSendMessage(window, cmd, data)
143
143
 
144
- Gửi `postMessage` đến một cửa sổ/iframe khác. Dùng để giao tiếp giữa các `f-window`.
144
+ `postMessage` to another window/iframe — communication between `f-window`s.
145
145
 
146
- | Param | Mô tả |
147
- |---|---|
148
- | `window` | Object window, `'#PARENT'` (cửa sổ cha), hoặc `'#iframeId'` (ID của iframe) |
149
- | `cmd` | Tên lệnh |
150
- | `data` | Dữ liệu gửi kèm |
146
+ | Param | Meaning |
147
+ | -------- | ----------------------------------------------------------------- |
148
+ | `window` | Window object, `'#PARENT'` (parent), or `'#iframeId'` (iframe ID) |
149
+ | `cmd` | Command name |
150
+ | `data` | Payload |
151
151
 
152
152
  ```js
153
153
  // Gửi lên cửa sổ cha
154
- windowSendMessage('#PARENT', 'refreshData', { id: vueData.selectedId });
154
+ windowSendMessage("#PARENT", "refreshData", { id: vueData.selectedId });
155
155
 
156
156
  // Gửi đến iframe có id="iframeChild"
157
- windowSendMessage('#iframeChild', 'loadItem', { itemId: 5 });
157
+ windowSendMessage("#iframeChild", "loadItem", { itemId: 5 });
158
158
  ```
159
159
 
160
160
  ---
@@ -163,89 +163,128 @@ windowSendMessage('#iframeChild', 'loadItem', { itemId: 5 });
163
163
 
164
164
  ### ajaxCALL(URL, DATA, callBack, errorCallBack, header)
165
165
 
166
- Gọi API bằng AJAX POST. URL chỉ cần truyền path — hệ thống tự ghép domain qua `fixURL`.
166
+ AJAX POST. Pass only the path — domain is added via `fixURL`.
167
167
 
168
168
  ```js
169
- ajaxCALL('/SP_GetDonHang', { maKH: vueData.maKH }, function(res) {
170
- vueData.danhSach = res.data;
169
+ ajaxCALL("/SP_GetDonHang", { maKH: vueData.maKH }, function (res) {
170
+ vueData.danhSach = res.data;
171
171
  });
172
172
 
173
173
  // Với error handler
174
- ajaxCALL('/SP_SaveDonHang', vueData.form,
175
- function(res) { Vue.$toast.success('Lưu thành công', { position: 'top' }); },
176
- function(err) { showMessage({ title: 'Lỗi', message: err.message, type: 'red' }); }
174
+ ajaxCALL(
175
+ "/SP_SaveDonHang",
176
+ vueData.form,
177
+ function (res) {
178
+ Vue.$toast.success("Lưu thành công", { position: "top" });
179
+ },
180
+ function (err) {
181
+ showMessage({ title: "Lỗi", message: err.message, type: "red" });
182
+ },
177
183
  );
178
184
  ```
179
185
 
180
186
  ---
181
187
 
182
- ## Xuất file
188
+ ## File Export
183
189
 
184
190
  ### jsonToExcel(Obj)
185
191
 
186
- Xuất dữ liệu JSON ra file `.xlsx`. Tự động load ExcelJS nếu chưa có.
192
+ Exports JSON to `.xlsx`. Auto-loads ExcelJS.
187
193
 
188
194
  **Single sheet:**
195
+
189
196
  ```js
190
197
  jsonToExcel({
191
- data: vueData.danhSach, // Array of objects
192
- filename: 'danh-sach.xlsx',
193
- worksheet: 'DanhSach'
198
+ data: vueData.danhSach, // Array of objects
199
+ filename: "danh-sach.xlsx",
200
+ worksheet: "DanhSach",
194
201
  });
195
202
  ```
196
203
 
197
204
  **Multi sheet:**
205
+
198
206
  ```js
199
207
  jsonToExcel({
200
- filename: 'bao-cao.xlsx',
201
- sheets: [
202
- { name: 'Sheet1', data: vueData.list1 },
203
- { name: 'Sheet2', data: vueData.list2 }
204
- ]
208
+ filename: "bao-cao.xlsx",
209
+ sheets: [
210
+ { name: "Sheet1", data: vueData.list1 },
211
+ { name: "Sheet2", data: vueData.list2 },
212
+ ],
205
213
  });
206
214
  ```
207
215
 
216
+ Without `columns`, the columns are the keys of the **first row**, headers are the key names, values are raw. A field missing from the first row is missing from the whole file.
217
+
218
+ **Pick columns, headers and formats — `columns`** (`f-table excel="UI"` also uses `columns`, but only `header`/`key`, no formatting):
219
+
220
+ ```js
221
+ jsonToExcel({
222
+ data: vueData.dsHang, // the original array of objects — no need to map each row
223
+ filename: "kho.xlsx",
224
+ worksheet: "Kho",
225
+ columns: [
226
+ { header: "Tên hàng", key: "Ten" },
227
+ { header: "Số lượng", key: "SoLuong", type: "number", numFmt: "#,##0", sum: true },
228
+ { header: "Thành tiền", key: "ThanhTien", type: "number", numFmt: "#,##0.00", sum: "#,##0" },
229
+ { header: "Ngày nhập", key: "NgayNhap", type: "date", numFmt: "dd/mm/yyyy" },
230
+ { header: "Ghi chú", key: "GhiChuHtml", type: "html", width: 40 },
231
+ ],
232
+ });
233
+ ```
234
+
235
+ | Field | Meaning |
236
+ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
237
+ | `header` | Column title. May repeat (two "Tổng" columns do not overwrite each other) |
238
+ | `key` | Row field; nested paths `a.b` are supported |
239
+ | `type` | `'number'`: numeric string → number. `'date'`: ISO/`yyyy-mm-dd` string → real date in **local time** (no one-day shift from UTC). `'html'`: strip tags, keep text. Omitted: as is (object/array → JSON string) |
240
+ | `numFmt` | **Excel** format code (not numeral/moment): `#,##0`, `#,##0.00`, `0.0%`, `dd/mm/yyyy hh:mm`. `'#,##0;-#,##0;'` hides zeros but keeps the value |
241
+ | `width` | Width in characters; omitted, it is estimated from the first 100 rows |
242
+ | `sum` | `true` or a numFmt → adds a total row at the end of the sheet with a `SUM` formula over the exported rows |
243
+
244
+ - With `columns`, the header row is bold and frozen. Each sheet in `sheets` can have its own `columns`: `{ name, data, columns }`.
245
+ - Only fields listed in `columns` go into the file. This is the clean export (no IDs or technical fields leak) and it is lighter than mapping to a new array of objects just to rename keys.
246
+
208
247
  ---
209
248
 
210
249
  ## Data Utilities
211
250
 
212
251
  ### groupBy(arrayObj, groupField, sumArr)
213
252
 
214
- Group mảng object theo một field và tính tổng các cột số. Trả về mảng đã group kèm `count`.
253
+ Groups objects by a field and sums numeric columns; returns grouped array with `count`.
215
254
 
216
255
  ```js
217
256
  // groupBy(data, 'Khoa', ['SLNghiHoc', 'SLTotNghiep'])
218
- var result = groupBy(vueData.data, 'phongBan', ['soLuong', 'doanhThu']);
257
+ var result = groupBy(vueData.data, "phongBan", ["soLuong", "doanhThu"]);
219
258
  // result: [{ phongBan: 'A', soLuong: 10, doanhThu: 5000, count: 3 }, ...]
220
259
  ```
221
260
 
222
- > Với nhu cầu group phức tạp hơn, dùng `_.groupBy` của Lodash trực tiếp.
261
+ > For complex grouping use Lodash `_.groupBy`.
223
262
 
224
263
  ---
225
264
 
226
265
  ### findInArray(obj)
227
266
 
228
- Tìm phần tử trong mảng theo điều kiện.
267
+ Finds an element by condition.
229
268
 
230
269
  ```js
231
270
  var item = findInArray({ array: vueData.list, value: { id: 5 } });
232
271
  ```
233
272
 
234
- > Thường dùng `_.find(array, condition)` của Lodash thay thế vì ngắn gọn hơn.
273
+ > Usually prefer the shorter Lodash `_.find(array, condition)`.
235
274
 
236
275
  ---
237
276
 
238
277
  ### fillData(obj)
239
278
 
240
- Copy dữ liệu từ mảng nguồn vào object đích theo key và mapping.
279
+ Copies data from a source array into a target object by key and mapping.
241
280
 
242
- - **Parameters:** `{ src, des, key, map }` — src: array nguồn, des: object đích, key: giá trị khớp, map: mapping field
281
+ - **Parameters:** `{ src, des, key, map }` — src: source array, des: target object, key: matching value, map: field mapping
243
282
 
244
283
  ---
245
284
 
246
285
  ### buildHeader(obj, mapCol)
247
286
 
248
- Tự sinh mảng `headers` cho `f-table` từ dữ liệu. Không truyền `mapCol` → suy header từ key của bản ghi đầu tiên (cột số tự gán `el: 't-num'`); có `mapCol` → map từ `{ text, value }`.
287
+ Builds `headers` for `f-table` from data. No `mapCol` → headers from the first record's keys (numeric columns get `el: 't-num'`); with `mapCol` → mapped from `{ text, value }`.
249
288
 
250
289
  ```js
251
290
  // Tự dựng header từ dữ liệu API
@@ -254,11 +293,11 @@ vueData.headers = buildHeader(vueData.dsData);
254
293
 
255
294
  ### capacityText(numb)
256
295
 
257
- Đổi số byte → chuỗi dung lượng (`'1.5 Mb'`, `'320 Kb'`) — dùng hiển thị kích thước file.
296
+ Bytes → size string (`'1.5 Mb'`, `'320 Kb'`) for file sizes.
258
297
 
259
298
  ### appCommand(cmdData)
260
299
 
261
- Gửi lệnh sang app native (React Native / iOS webkit / Android) khi trang FUI nhúng trong app di động.
300
+ Sends a command to the native app (React Native / iOS webkit / Android) when FUI is embedded in a mobile app.
262
301
 
263
302
  ---
264
303
 
@@ -266,13 +305,15 @@ Gửi lệnh sang app native (React Native / iOS webkit / Android) khi trang FUI
266
305
 
267
306
  ### printPDF(obj)
268
307
 
269
- Tạo và in/tải PDF dùng `pdfMake`. Tự động load pdfMake nếu chưa có.
308
+ Builds and prints/downloads a PDF with `pdfMake`. Auto-loads pdfMake.
270
309
 
271
310
  ```js
272
311
  printPDF({
273
- data: docDefinition, // pdfMake docDefinition object
274
- download: true, // true = tải file, false = mở viewer
275
- callBack: function() { console.log('Done'); }
312
+ data: docDefinition, // pdfMake docDefinition object
313
+ download: true, // true = tải file, false = mở viewer
314
+ callBack: function () {
315
+ console.log("Done");
316
+ },
276
317
  });
277
318
  ```
278
319
 
@@ -282,7 +323,7 @@ printPDF({
282
323
 
283
324
  ### copyToClipboard(textToCopy)
284
325
 
285
- Copy chuỗi vào clipboard. Tự động dùng `navigator.clipboard` nếu có (HTTPS), fallback về `execCommand`.
326
+ Copies to clipboard; uses `navigator.clipboard` when available (HTTPS), else `execCommand`.
286
327
 
287
328
  ```js
288
329
  copyToClipboard(vueData.maHoaDon);
@@ -293,7 +334,7 @@ copyToClipboard(JSON.stringify(vueData.data));
293
334
 
294
335
  ### fileNameClear(fname)
295
336
 
296
- Xóa các ký tự đặc biệt khỏi tên file (chỉ giữ chữ, số, khoảng trắng, dấu gạch).
337
+ Strips special characters from a file name (keeps letters, digits, spaces, dashes).
297
338
 
298
339
  ```js
299
340
  var safeName = fileNameClear(vueData.tenFile); // "report (2025)!" → "report 2025"
@@ -303,20 +344,20 @@ var safeName = fileNameClear(vueData.tenFile); // "report (2025)!" → "report 2
303
344
 
304
345
  ### hashCode(s)
305
346
 
306
- Tạo hash số nguyên từ chuỗi (dùng để generate key duy nhất).
347
+ Integer hash of a string (for unique keys).
307
348
 
308
349
  ```js
309
- var key = hashCode('unique-string-' + Date.now());
350
+ var key = hashCode("unique-string-" + Date.now());
310
351
  ```
311
352
 
312
353
  ---
313
354
 
314
355
  ### generateID()
315
356
 
316
- Tạo ID ngẫu nhiên dạng chuỗi.
357
+ Random string ID.
317
358
 
318
359
  ```js
319
- var newId = 'win_' + generateID();
360
+ var newId = "win_" + generateID();
320
361
  ```
321
362
 
322
363
  ---
@@ -325,32 +366,32 @@ var newId = 'win_' + generateID();
325
366
 
326
367
  ### getCookie(cname) / setCookie(name, value, days, domain)
327
368
 
328
- Đọc/ghi cookie trình duyệt.
369
+ Read/write browser cookies.
329
370
 
330
371
  ```js
331
- var token = getCookie('awt');
332
- setCookie('theme', 'dark', 30); // hết hạn sau 30 ngày
333
- setCookie('lang', 'vi', 365, '.fui.vn'); // share cookie toàn domain
372
+ var token = getCookie("awt");
373
+ setCookie("theme", "dark", 30); // hết hạn sau 30 ngày
374
+ setCookie("lang", "vi", 365, ".fui.vn"); // share cookie toàn domain
334
375
  ```
335
376
 
336
377
  ---
337
378
 
338
379
  ### logout(cookiesName, domain, url)
339
380
 
340
- Xóa cookie và chuyển hướng đến trang login.
381
+ Clears the cookie and redirects to login.
341
382
 
342
383
  ```js
343
- logout(); // xóa cookie 'awt', redirect về login mặc định
344
- logout('myToken', '.fui.vn', '/login');
384
+ logout(); // xóa cookie 'awt', redirect về login mặc định
385
+ logout("myToken", ".fui.vn", "/login");
345
386
  ```
346
387
 
347
388
  ---
348
389
 
349
- ## Quyền hạn
390
+ ## Permissions
350
391
 
351
392
  ### rightTest(rightObject)
352
393
 
353
- Kiểm tra user hiện tại có quyền hạn yêu cầu không. So sánh với `vueData.user`.
394
+ Checks whether the current user has the required rights, against `vueData.user`.
354
395
 
355
396
  ```js
356
397
  // Kiểm tra user có role 'admin' hoặc 'manager'
@@ -368,23 +409,23 @@ if (rightTest({ dept: 'IT', level: [1, 2] })) { ... }
368
409
 
369
410
  ### colorLib(color)
370
411
 
371
- Utility xử lý màu sắc (hex, rgb, hsl). Dùng chủ yếu trong chart.
412
+ Color utility (hex, rgb, hsl), mostly for charts.
372
413
 
373
414
  ```js
374
- var c = colorLib('#4e73df');
375
- c.hexString() // '#4e73df'
376
- c.rgbString() // 'rgb(78, 115, 223)'
377
- c.lighten(0.2) // làm sáng 20%
378
- c.darken(0.1) // làm tối 10%
379
- c.alpha(0.5).rgbString() // 'rgba(78, 115, 223, 0.5)'
415
+ var c = colorLib("#4e73df");
416
+ c.hexString(); // '#4e73df'
417
+ c.rgbString(); // 'rgb(78, 115, 223)'
418
+ c.lighten(0.2); // làm sáng 20%
419
+ c.darken(0.1); // làm tối 10%
420
+ c.alpha(0.5).rgbString(); // 'rgba(78, 115, 223, 0.5)'
380
421
  ```
381
422
 
382
423
  ### transparentize(value, opacity)
383
424
 
384
- Shortcut tạo màu trong suốt từ mã màu.
425
+ Shortcut for a transparent color.
385
426
 
386
427
  ```js
387
- transparentize('#4e73df', 0.5) // 'rgba(78, 115, 223, 0.5)'
428
+ transparentize("#4e73df", 0.5); // 'rgba(78, 115, 223, 0.5)'
388
429
  ```
389
430
 
390
431
  ---
@@ -393,11 +434,11 @@ transparentize('#4e73df', 0.5) // 'rgba(78, 115, 223, 0.5)'
393
434
 
394
435
  ### loadScripts(scriptsArray, callbackFunc)
395
436
 
396
- Load thêm script từ URL và chạy callback khi xong. Dùng để load thư viện on-demand.
437
+ Loads scripts by URL, then runs the callback — on-demand libraries.
397
438
 
398
439
  ```js
399
- loadScripts(['/include/pdfmake/pdfmake.min.js', '/include/pdfmake/vfs_fonts.js'], function() {
400
- printPDF({ data: docDef, download: true });
440
+ loadScripts(["/include/pdfmake/pdfmake.min.js", "/include/pdfmake/vfs_fonts.js"], function () {
441
+ printPDF({ data: docDef, download: true });
401
442
  });
402
443
  ```
403
444
 
@@ -407,9 +448,9 @@ loadScripts(['/include/pdfmake/pdfmake.min.js', '/include/pdfmake/vfs_fonts.js']
407
448
 
408
449
  ### extractHostname(url) / getDomainWithoutSubdomain(url)
409
450
 
410
- Trích xuất hostname/domain từ URL. Dùng nội bộ, ít dùng trực tiếp.
451
+ Extract hostname/domain from a URL. Internal; rarely used directly.
411
452
 
412
453
  ```js
413
- extractHostname('https://api.fui.vn/fp/test') // 'api.fui.vn'
414
- getDomainWithoutSubdomain('https://api.fui.vn') // 'fui.vn'
454
+ extractHostname("https://api.fui.vn/fp/test"); // 'api.fui.vn'
455
+ getDomainWithoutSubdomain("https://api.fui.vn"); // 'fui.vn'
415
456
  ```