@fui-org/fui-cli 1.3.1 → 2.0.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.
- package/README.md +19 -3
- package/dist/fui-bmg5pnmq.js +379 -0
- package/dist/fui.js +1 -1
- package/package.json +7 -6
- package/skills/fui/SKILL.md +9 -41
- package/skills/fui-skill/SKILL.md +95 -225
- package/skills/fui-skill/assets/projectdefaultstyle-3.0.css +555 -0
- package/skills/fui-skill/assets/projectdefaultstyle.css +207 -235
- package/skills/fui-skill/references/INDEX.md +105 -137
- package/skills/fui-skill/references/advanced-techniques.md +76 -68
- package/skills/fui-skill/references/coding-standards.md +56 -56
- package/skills/fui-skill/references/component-design.md +166 -173
- package/skills/fui-skill/references/component-quickref.md +61 -60
- package/skills/fui-skill/references/component-table.md +128 -117
- package/skills/fui-skill/references/components-dialog.md +55 -56
- package/skills/fui-skill/references/components-display.md +24 -30
- package/skills/fui-skill/references/components-echart.md +186 -261
- package/skills/fui-skill/references/components-input.md +72 -96
- package/skills/fui-skill/references/controls-patterns.md +196 -342
- package/skills/fui-skill/references/controls-styling-vocabulary.md +130 -97
- package/skills/fui-skill/references/db-table-design.md +24 -28
- package/skills/fui-skill/references/db-workflow.md +191 -390
- package/skills/fui-skill/references/default-function.md +169 -128
- package/skills/fui-skill/references/design-modes.md +35 -63
- package/skills/fui-skill/references/echart-templates.md +204 -196
- package/skills/fui-skill/references/fastproject.md +62 -60
- package/skills/fui-skill/references/fsheet.md +109 -124
- package/skills/fui-skill/references/fullstack-workflow.md +90 -128
- package/skills/fui-skill/references/module-data-patterns.md +31 -40
- package/skills/fui-skill/references/module-json-anatomy.md +47 -52
- package/skills/fui-skill/references/module-structure.md +80 -196
- package/skills/fui-skill/references/new-session.md +49 -51
- package/skills/fui-skill/references/pdfmake.md +17 -17
- package/skills/fui-skill/references/permission-system.md +89 -108
- package/skills/fui-skill/references/platform-architecture.md +128 -153
- package/skills/fui-skill/references/project-config.md +102 -134
- package/skills/fui-skill/references/project-provisioning.md +139 -244
- package/skills/fui-skill/references/script-map.md +208 -242
- package/skills/fui-skill/references/sql-clr-functions.md +98 -97
- package/skills/fui-skill/references/system-design.md +63 -88
- package/skills/fui-skill/references/tapi-file-api.md +46 -52
- package/skills/fui-skill/references/tapi-permission-patterns.md +51 -53
- package/skills/fui-skill/references/tapi-reference.md +132 -207
- package/skills/fui-skill/references/tools-registry.md +84 -460
- package/skills/fui-skill/references/ui-crosswindow-patterns.md +79 -75
- package/skills/fui-skill/references/ui-dialog-patterns.md +98 -72
- package/skills/fui-skill/references/ui-layout-patterns.md +26 -26
- package/skills/fui-skill/references/ui-patterns.md +71 -83
- package/skills/fui-skill/references/ui-screenshot-review.md +63 -62
- package/skills/fui-skill/references/ui-table-cell-patterns.md +61 -59
- package/skills/fui-skill/references/ui-templates.md +16 -23
- package/skills/fui-skill/references/verification.md +236 -246
- package/skills/fui-skill/references/watcher-patterns.md +30 -63
- package/skills/fui-skill/references/websocket-realtime.md +83 -66
- package/skills/fui-skill/scripts/component-3.0.js +298 -131
- package/skills/fui-skill/scripts/component.js +277 -271
- package/skills/fui-skill/scripts/componentTable-3.0.js +182 -53
- package/skills/fui-skill/scripts/componentTable.js +171 -49
- package/skills/fui-skill/scripts/defaultfunction-3.0.js +88 -3
- package/skills/fui-skill/scripts/defaultfunction.js +88 -3
- package/skills/fui-skill/scripts/fsheet.js +38 -0
- package/dist/fui-x7kph78r.js +0 -420
- package/skills/fui-skill/README.md +0 -112
- package/skills/fui-skill/metadata.json +0 -75
- package/skills/fui-skill-cli/SKILL.md +0 -139
- package/skills/fui-skill-cli/references/INDEX.md +0 -110
- package/skills/fui-skill-cli/references/advanced-techniques.md +0 -168
- package/skills/fui-skill-cli/references/coding-standards.md +0 -112
- package/skills/fui-skill-cli/references/component-design.md +0 -448
- package/skills/fui-skill-cli/references/component-quickref.md +0 -78
- package/skills/fui-skill-cli/references/component-table.md +0 -248
- package/skills/fui-skill-cli/references/components-dialog.md +0 -191
- package/skills/fui-skill-cli/references/components-display.md +0 -141
- package/skills/fui-skill-cli/references/components-echart.md +0 -316
- package/skills/fui-skill-cli/references/components-input.md +0 -335
- package/skills/fui-skill-cli/references/controls-patterns.md +0 -701
- package/skills/fui-skill-cli/references/controls-styling-vocabulary.md +0 -137
- package/skills/fui-skill-cli/references/db-table-design.md +0 -73
- package/skills/fui-skill-cli/references/db-workflow.md +0 -288
- package/skills/fui-skill-cli/references/default-function.md +0 -425
- package/skills/fui-skill-cli/references/design-modes.md +0 -57
- package/skills/fui-skill-cli/references/echart-templates.md +0 -489
- package/skills/fui-skill-cli/references/fastproject.md +0 -99
- package/skills/fui-skill-cli/references/fsheet.md +0 -203
- package/skills/fui-skill-cli/references/fullstack-workflow.md +0 -313
- package/skills/fui-skill-cli/references/module-data-patterns.md +0 -117
- package/skills/fui-skill-cli/references/module-json-anatomy.md +0 -132
- package/skills/fui-skill-cli/references/module-structure.md +0 -141
- package/skills/fui-skill-cli/references/new-session.md +0 -85
- package/skills/fui-skill-cli/references/pdfmake.md +0 -60
- package/skills/fui-skill-cli/references/permission-system.md +0 -150
- package/skills/fui-skill-cli/references/platform-architecture.md +0 -269
- package/skills/fui-skill-cli/references/project-config.md +0 -303
- package/skills/fui-skill-cli/references/project-provisioning.md +0 -278
- package/skills/fui-skill-cli/references/script-map.md +0 -262
- package/skills/fui-skill-cli/references/sql-clr-functions.md +0 -225
- package/skills/fui-skill-cli/references/system-design.md +0 -89
- package/skills/fui-skill-cli/references/tapi-file-api.md +0 -185
- package/skills/fui-skill-cli/references/tapi-permission-patterns.md +0 -156
- package/skills/fui-skill-cli/references/tapi-reference.md +0 -474
- package/skills/fui-skill-cli/references/tools-registry.md +0 -84
- package/skills/fui-skill-cli/references/ui-crosswindow-patterns.md +0 -321
- package/skills/fui-skill-cli/references/ui-dialog-patterns.md +0 -255
- package/skills/fui-skill-cli/references/ui-layout-patterns.md +0 -176
- package/skills/fui-skill-cli/references/ui-patterns.md +0 -303
- package/skills/fui-skill-cli/references/ui-screenshot-review.md +0 -95
- package/skills/fui-skill-cli/references/ui-table-cell-patterns.md +0 -318
- package/skills/fui-skill-cli/references/ui-templates.md +0 -22
- package/skills/fui-skill-cli/references/verification.md +0 -236
- package/skills/fui-skill-cli/references/watcher-patterns.md +0 -163
- package/skills/fui-skill-cli/references/websocket-realtime.md +0 -271
|
@@ -1,97 +1,99 @@
|
|
|
1
1
|
# FastProject (Core Framework)
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Owns: **the `fastproject.js` bootstrapper: project/module init lifecycle**. Full script map: [script-map.md](script-map.md).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`fastproject.js` initializes the app, builds UI from JSON config, and runs the logic engine.
|
|
6
6
|
|
|
7
7
|
## Global State
|
|
8
8
|
|
|
9
9
|
### vueData
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
- `
|
|
14
|
-
- `
|
|
10
|
+
|
|
11
|
+
Central reactive state.
|
|
12
|
+
|
|
13
|
+
- `p_domain`, `p_routers`, `p_params`: routing and environment.
|
|
14
|
+
- `user`: current user.
|
|
15
|
+
- `v_Set`: app settings (title, menu, attributes).
|
|
16
|
+
- `v_Loading`: global loading state.
|
|
15
17
|
|
|
16
18
|
### vueOBJ
|
|
17
|
-
|
|
19
|
+
|
|
20
|
+
Vue instance config object.
|
|
18
21
|
|
|
19
22
|
## Core Functions
|
|
20
23
|
|
|
21
24
|
### loadModuleInfo()
|
|
22
|
-
|
|
23
|
-
1.
|
|
24
|
-
2.
|
|
25
|
-
3.
|
|
26
|
-
4.
|
|
25
|
+
|
|
26
|
+
1. Load project and module settings.
|
|
27
|
+
2. Build URL parameters.
|
|
28
|
+
3. Fetch user info (if configured).
|
|
29
|
+
4. Call `createModuleDom()`.
|
|
27
30
|
|
|
28
31
|
### createModuleDom()
|
|
29
|
-
|
|
30
|
-
1.
|
|
31
|
-
2.
|
|
32
|
-
3.
|
|
33
|
-
4.
|
|
32
|
+
|
|
33
|
+
1. Run initial data actions (`$moduleUI.data`).
|
|
34
|
+
2. Generate HTML via `buildModuleUI`.
|
|
35
|
+
3. Init Vue watchers and WebSocket connections.
|
|
36
|
+
4. Mount the Vue instance.
|
|
34
37
|
|
|
35
38
|
### buildModuleUI(controlsList, target)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
-
|
|
39
|
+
|
|
40
|
+
Recursively builds DOM from a JSON control list.
|
|
41
|
+
|
|
42
|
+
- `controlsList` (Array): control definitions.
|
|
43
|
+
- `target` (Object): binding target (usually `vueData`).
|
|
44
|
+
- Returns: jQuery object with the generated HTML.
|
|
41
45
|
|
|
42
46
|
### buildControl(controlsList, flex, target)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
|
|
48
|
+
`buildModuleUI` helper for individual controls.
|
|
49
|
+
|
|
50
|
+
- Grid layout (`v-layout`, `v-flex`) and nested components.
|
|
51
|
+
- Attribute binding and event mapping.
|
|
46
52
|
|
|
47
53
|
### runAction(obj, includeData)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
-
|
|
53
|
-
|
|
54
|
-
- `API`: Call an API.
|
|
55
|
-
- `CALL`: Recursive call to another action.
|
|
56
|
-
- `EXE`: Execute raw JavaScript.
|
|
57
|
-
- `FUN`: Call a global function.
|
|
58
|
-
- `IF/THEN/ELSE`: Conditional logic.
|
|
59
|
-
- `MESS`/`MESSBOX`: Show messages.
|
|
60
|
-
- `IN`/`OUT`: Data mapping.
|
|
54
|
+
|
|
55
|
+
Central logic engine; runs a JSON action sequence.
|
|
56
|
+
|
|
57
|
+
- `obj` (Object|Array): action(s).
|
|
58
|
+
- `includeData` (Object): context data.
|
|
59
|
+
- Action types: `CONFIRM` (confirm dialog), `API` (call API), `CALL` (another action, recursive), `EXE` (raw JS), `FUN` (global function), `IF/THEN/ELSE`, `MESS`/`MESSBOX` (messages), `IN`/`OUT` (data mapping).
|
|
61
60
|
|
|
62
61
|
### vueAction(objAction, includeData, callBack)
|
|
63
|
-
|
|
62
|
+
|
|
63
|
+
Internal; runs a single action step for `runAction`.
|
|
64
64
|
|
|
65
65
|
### callAPI(objApi, callBack, includeData)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
|
|
67
|
+
Runs an API call from a JSON action.
|
|
68
|
+
|
|
69
|
+
- Handles `BEFORE`, `AFTER` actions, success/error callbacks.
|
|
70
|
+
- Maps response into `vueData` when `OUT` is set.
|
|
69
71
|
|
|
70
72
|
### mapData(map, target, src, includeData)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
- `src` (Object): Source object.
|
|
73
|
+
|
|
74
|
+
Maps source → target by a mapping definition.
|
|
75
|
+
|
|
76
|
+
- Cross-window mapping via `#PARENT` or window IDs.
|
|
77
|
+
- `map` (Object|String): mapping; `target` (Object): destination; `src` (Object): source.
|
|
77
78
|
|
|
78
79
|
### getVueData(key, src)
|
|
79
|
-
|
|
80
|
+
|
|
81
|
+
Resolves a value from a key string; deep paths and template syntax (e.g. `{{user.Name}}`).
|
|
80
82
|
|
|
81
83
|
### bindData(obj)
|
|
82
|
-
|
|
84
|
+
|
|
85
|
+
Resolves all dynamic values in an object.
|
|
83
86
|
|
|
84
87
|
### createWatch(obj)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
- Executes actions when watched values change.
|
|
88
|
+
|
|
89
|
+
Vue watchers from JSON config; supports deep watch; runs actions on change.
|
|
88
90
|
|
|
89
91
|
### loginFUN()
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
|
|
93
|
+
Login redirect: opens a login window or redirects to the login page.
|
|
92
94
|
|
|
93
95
|
### errorMess(code, message)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
|
|
97
|
+
Standard error message by HTTP status.
|
|
98
|
+
|
|
99
|
+
- `code` (String|Number): HTTP status; `message` (String): custom message.
|
|
@@ -1,183 +1,168 @@
|
|
|
1
|
-
# f-sheet —
|
|
1
|
+
# f-sheet — Data-Entry Grid (AG Grid)
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Owns: **`f-sheet` (AG Grid): import, props, columns, built-in cell renderers, range select/fill/clipboard, API wiring**.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Excel-style entry grid, **entirely AG Grid Community** — customize with AG Grid knowledge (https://www.ag-grid.com/, Community). FUI adds: toolbar (add/delete/save/export Excel), change tracking, range select + fill handle + TSV copy/paste, API wiring.
|
|
6
6
|
|
|
7
|
-
> **
|
|
7
|
+
> **vs `f-table`** (rows edited via dialog form): `f-sheet` edits **in cells**, for bulk entry (paste rows, fast multi-cell edits). Never hand-write an entry grid as `uc-*.vue`.
|
|
8
8
|
|
|
9
|
-
>
|
|
9
|
+
> Source: `scripts/fsheet.js`, **one file for V2 and V3** (`beforeDestroy` + `beforeUnmount`). Template uses **Vuetify 3** props/classes (`variant="text"`, `density="comfortable"`, `text-primary`, `text-subtitle-1`, `text-caption`); on V2 the toolbar works but styling may be off. Uses `ajaxCALL`/`confirm`/`jsonToExcel` ([component-design.md](component-design.md) §12).
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## Required import
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Exactly 2 files, **in this order**, via `fui import new` (missing → unusable):
|
|
16
16
|
|
|
17
17
|
```
|
|
18
18
|
/include/ag-grid/ag-grid-community.min.js
|
|
19
19
|
/include/ag-grid/fsheet.js
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
`fui import list` (projectId + moduleId) → `fui import new` missing ones; removing f-sheet and nothing else uses them → `fui import delete`. See [component-quickref.md](component-quickref.md).
|
|
23
23
|
|
|
24
24
|
---
|
|
25
25
|
|
|
26
26
|
## Props
|
|
27
27
|
|
|
28
|
-
| Prop (kebab-case
|
|
29
|
-
|
|
30
|
-
| `label`
|
|
31
|
-
| `:columns`
|
|
32
|
-
| `:items`
|
|
33
|
-
| `row-key`
|
|
34
|
-
| `:height`
|
|
35
|
-
| `:allow-add`
|
|
36
|
-
| `:allow-delete`
|
|
37
|
-
| `readonly`
|
|
38
|
-
| `update-api`
|
|
39
|
-
| `delete-api`
|
|
40
|
-
| `:save-extra`
|
|
41
|
-
| `:default-item`
|
|
28
|
+
| Prop (kebab-case in `attr`) | Type | Meaning |
|
|
29
|
+
| --------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
30
|
+
| `label` | string | Title, shown on toolbar |
|
|
31
|
+
| `:columns` | array | **AG Grid colDefs**. Empty → inferred from `items[0]` (`{ field, headerName: field }`) |
|
|
32
|
+
| `:items` | array | rowData |
|
|
33
|
+
| `row-key` | string | PK field (default `id`) — tracks changed/new/deleted rows |
|
|
34
|
+
| `:height` | number | empty = auto-grow; `<=0` = fill to screen bottom leaving `abs(height)` px; `>0` = fixed px |
|
|
35
|
+
| `:allow-add` | bool | Add row button |
|
|
36
|
+
| `:allow-delete` | bool | Checkbox column + Delete button |
|
|
37
|
+
| `readonly` | bool | Lock all editing (also fill handle) |
|
|
38
|
+
| `update-api` | string | tAPI endpoint **saving each changed row** (`ajaxCALL`, auto-prepends `apiDomain`). Missing → Save `disabled` |
|
|
39
|
+
| `delete-api` | string | tAPI endpoint deleting one row |
|
|
40
|
+
| `:save-extra` | object | Extra params **merged into every save/delete payload** (e.g. `{ LopID: vueData.lopID }`); via `mapData`, dynamic `vueData.x` allowed |
|
|
41
|
+
| `:default-item` | object | New-row template on Add; via `mapData`, dynamic `vueData.x` allowed (not only literals) |
|
|
42
42
|
|
|
43
43
|
---
|
|
44
44
|
|
|
45
|
-
##
|
|
45
|
+
## Columns = AG Grid colDef
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
| Key | Meaning |
|
|
48
|
+
| ----------------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
49
|
+
| `field` / `headerName` | data field / label |
|
|
50
|
+
| `editable` | **on by default** (`defaultColDef.editable: !readonly`); read-only column → `"editable": false` |
|
|
51
|
+
| `width` / `minWidth` / `flex` | default `flex:1`, `minWidth:80` |
|
|
52
|
+
| `pinned` | `'left'`/`'right'` |
|
|
53
|
+
| `sortable` / `filter` / `resizable` | all on by default |
|
|
54
|
+
| `valueFormatter` / `valueGetter` | AG Grid functions |
|
|
55
|
+
| `cellEditor` | AG Grid built-in name (e.g. `agDateStringCellEditor`) or own global function name |
|
|
56
|
+
| `cellRenderer` | one of 4 f-sheet built-ins (below) or own global function name |
|
|
57
|
+
| `type` | **registered columnType name — only `"number"` / `"date"`**, not a free data type |
|
|
48
58
|
|
|
49
|
-
|
|
50
|
-
|---|---|
|
|
51
|
-
| `field` | Tên field trong dòng dữ liệu |
|
|
52
|
-
| `headerName` | Nhãn cột |
|
|
53
|
-
| `editable` | Cho sửa ô — **mặc định bật** (f-sheet đặt `editable: !readonly` trong `defaultColDef`); cột chỉ đọc khai `"editable": false` |
|
|
54
|
-
| `width` / `minWidth` / `flex` | Bề rộng cột (mặc định `flex:1`, `minWidth:80`) |
|
|
55
|
-
| `pinned` | `'left'`/`'right'` cố định cột |
|
|
56
|
-
| `sortable` / `filter` / `resizable` | Mặc định đều bật |
|
|
57
|
-
| `valueFormatter` / `valueGetter` | Định dạng/hiển thị (hàm AG Grid) |
|
|
58
|
-
| `cellEditor` | Editor tuỳ chỉnh — tên có sẵn của AG Grid (vd `agDateStringCellEditor`) hoặc tên hàm global tự viết |
|
|
59
|
-
| `cellRenderer` | Renderer tuỳ chỉnh — 4 renderer dựng sẵn của f-sheet (xem bên dưới) hoặc tên hàm global tự viết |
|
|
60
|
-
| `type` | **Tên columnType đã đăng ký** — chỉ có `"number"` và `"date"`. **KHÔNG phải** chỗ khai kiểu dữ liệu tự do (xem mục columnType ngay dưới) |
|
|
59
|
+
Other features (cellClassRules, aggregation...) → AG Grid docs; colDef passes straight through.
|
|
61
60
|
|
|
62
|
-
|
|
61
|
+
### columnType: only `number` and `date`
|
|
63
62
|
|
|
64
|
-
|
|
63
|
+
`type` references `gridOptions.columnTypes`; only two registered (`FS_COLUMN_TYPES`, top of `scripts/fsheet.js`). Unregistered name (`"date_time"`, `"currency"`, `"text"`, `"string"`, `"boolean"`…):
|
|
65
64
|
|
|
66
|
-
|
|
65
|
+
- AG Grid **ignores it** (logs only `warning #36 colDef.type 'x' does not correspond to defined gridOptions.columnTypes`) → raw text, **no** format/parse/filter.
|
|
66
|
+
- f-sheet adds a `console.error` naming column + valid names (scans group `children` too) — **visible in `fui module simulate --render`**; AG Grid's warning isn't.
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
Other types (currency, percent, datetime…) → declare `valueFormatter`/`valueParser`/`filter` on the colDef, never a new `type`.
|
|
69
69
|
|
|
70
|
-
-
|
|
71
|
-
- f-sheet phát thêm một `console.error` nêu đích danh tên cột + danh sách tên hợp lệ (quét cả colDef nằm trong `children` của column group). Dòng này **hiện lên trong `module_simulate({ renderUI: true })`** — warning gốc của AG Grid thì không.
|
|
70
|
+
### Built-in cell renderers
|
|
72
71
|
|
|
73
|
-
|
|
72
|
+
Use `"cellRenderer": "name"` + `cellRendererParams`; nothing to declare in `script.js`:
|
|
74
73
|
|
|
75
|
-
|
|
74
|
+
| Renderer | Purpose | `cellRendererParams` |
|
|
75
|
+
| ---------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
76
|
+
| `fsHtmlCellRenderer` | raw HTML `value` (like f-table `t-html`) | _(none)_ |
|
|
77
|
+
| `fsLinkCellRenderer` | link | `urlField`/`textField` (row field for URL/label, default `value`), `icon` (mdi, optional), `target`: `'dialog'` → `openWindow({id: wid, title, url, onclose})`, else `<a>` target (default `_blank`) |
|
|
78
|
+
| `fsButtonCellRenderer` | small button | `label`, `icon` (mdi, optional), `color` (default `#1976d2`); click: `url` → `openWindow({id: wid, title, url, onclose})`, no `url` → `tableActionEvent({action, item: data})` |
|
|
79
|
+
| `fsMenuCellRenderer` | `⋮` per-row dropdown | `items`: array `{icon, text, color, action}` or `function(params)` returning it (per-row); `icon` for trigger (default `mdi-dots-vertical`). Click → `tableActionEvent({action: item.action, item: data})` |
|
|
76
80
|
|
|
77
|
-
f-
|
|
81
|
+
`openWindow`/`tableActionEvent` are FUI globals (as in f-table `t-link`/`t-button`/`t-menu`). **Own global functions** also work for `cellRenderer`/`cellEditor`/`cellEditorParams`/`cellRendererParams`: define in `script.js`, reference by string name; auto-registered (incl. group `children`).
|
|
78
82
|
|
|
79
|
-
|
|
80
|
-
|---|---|---|
|
|
81
|
-
| `fsHtmlCellRenderer` | In `value` ra dạng HTML thô (giống `t-html` của f-table) | *(không cần)* |
|
|
82
|
-
| `fsLinkCellRenderer` | Ô dạng link | `urlField`/`textField` (field khác trong dòng làm URL/nhãn, mặc định dùng `value`), `icon` (mdi, tuỳ chọn), `target` — `'dialog'` mở qua `openWindow({id: wid, title, url, onclose})`, còn lại là target của thẻ `<a>` (mặc định `_blank`) |
|
|
83
|
-
| `fsButtonCellRenderer` | Ô dạng nút bấm nhỏ | `label`, `icon` (mdi, tuỳ chọn), `color` (mặc định `#1976d2`); bấm vào: có `url` → `openWindow({id: wid, title, url, onclose})`, không có `url` → `tableActionEvent({action, item: data})` (action đặt tên trong `action`) |
|
|
84
|
-
| `fsMenuCellRenderer` | Nút `⋮` mở menu thả xuống theo dòng | `items` — mảng `{icon, text, color, action}` hoặc hàm `function(params)` trả về mảng đó (để tính động theo dòng); `icon` cho nút mở menu (mặc định `mdi-dots-vertical`). Bấm một item → `tableActionEvent({action: item.action, item: data})` |
|
|
83
|
+
### `"type": "number"` — auto-attached (only if colDef doesn't declare it)
|
|
85
84
|
|
|
86
|
-
|
|
85
|
+
| Key | Behavior |
|
|
86
|
+
| ---------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
87
|
+
| `cellStyle` | right-aligned |
|
|
88
|
+
| `valueFormatter` | `toLocaleString('en-US', { maximumFractionDigits: 10 })` → `1,234,567.89`; **display only**, editor shows raw number |
|
|
89
|
+
| `valueParser` | empty/`null`/`undefined` → real `null` (not `""`); numeric string → `Number`; invalid → `null`. Also on Excel paste |
|
|
90
|
+
| `filter` | `agNumberColumnFilter` |
|
|
87
91
|
|
|
88
|
-
|
|
92
|
+
### `"type": "date"` — auto-attached (only if colDef doesn't declare it)
|
|
89
93
|
|
|
90
|
-
|
|
94
|
+
| Key | Behavior |
|
|
95
|
+
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
96
|
+
| `cellStyle` | centered |
|
|
97
|
+
| `valueFormatter` | `dd/mm/yyyy`; non-date → **raw string** shown (junk stays visible) |
|
|
98
|
+
| `valueParser` | accepts `dd/mm/yyyy`, `dd-mm-yyyy`, `yyyy-mm-dd`, ISO `2026-08-15T00:00:00` → stores `yyyy-mm-dd`; empty/invalid → `null`. Also on Excel paste |
|
|
99
|
+
| `filter` | `agDateColumnFilter` |
|
|
91
100
|
|
|
92
|
-
|
|
101
|
+
**Value contract (what the SP gets):** **`yyyy-mm-dd`** or `null` — matches `f-date` and tAPI `OPENJSON ... NgayX date '$.NgayX'`. Invalid (`31/02/2026`, `15/13/2026`) → `null`, no rollover. **Copy/Excel export use the raw value** (`2026-08-15`) — intentional, lossless round-trip.
|
|
93
102
|
|
|
94
|
-
|
|
95
|
-
|---|---|
|
|
96
|
-
| `cellStyle` | Canh **phải** |
|
|
97
|
-
| `valueFormatter` | Phân cách nghìn `toLocaleString('en-US', { maximumFractionDigits: 10 })` → `1,234,567.89`. Chỉ áp lúc **hiển thị** — click vào ô sửa vẫn thấy số thô |
|
|
98
|
-
| `valueParser` | Parse khi rời ô sửa: rỗng/`null`/`undefined` → `null` thật (không phải `""`), chuỗi số → `Number`, chuỗi hỏng → `null`. Áp cho cả paste-từ-Excel |
|
|
99
|
-
| `filter` | `agNumberColumnFilter` (lọc lớn hơn/nhỏ hơn/bằng thay vì lọc text) |
|
|
103
|
+
#### Date picker
|
|
100
104
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
Khai `"type": "date"` là đủ, f-sheet tự gắn 4 thứ (mỗi thứ chỉ gắn khi colDef **chưa** tự khai):
|
|
104
|
-
|
|
105
|
-
| Tự gắn | Hành vi |
|
|
106
|
-
|---|---|
|
|
107
|
-
| `cellStyle` | Canh **giữa** |
|
|
108
|
-
| `valueFormatter` | Hiển thị `dd/mm/yyyy`. Giá trị không phải ngày → in **chuỗi thô** (để dữ liệu rác hiện ra, không biến ô thành trống) |
|
|
109
|
-
| `valueParser` | Nhận `dd/mm/yyyy`, `dd-mm-yyyy`, `yyyy-mm-dd` và ISO datetime `2026-08-15T00:00:00` → lưu `yyyy-mm-dd`. Rỗng → `null`. Sai → `null`. Áp cho cả paste-từ-Excel |
|
|
110
|
-
| `filter` | `agDateColumnFilter` (lọc trước/sau/bằng ngày) |
|
|
111
|
-
|
|
112
|
-
**Hợp đồng giá trị — đây là thứ quyết định SP nhận được gì:** ô ngày luôn giữ chuỗi **`yyyy-mm-dd`** (hoặc `null`). Khớp thẳng với `f-date` (cũng emit `yyyy-mm-dd`) và với `OPENJSON ... NgayX date '$.NgayX'` phía tAPI — không phải convert gì thêm.
|
|
113
|
-
|
|
114
|
-
- **Ngày không hợp lệ về `null`, ô thành rỗng** — giống hệt cột số. `31/02/2026` và `15/13/2026` bị từ chối (không âm thầm cuộn sang `03/03/2026` / `15/01/2027`).
|
|
115
|
-
- **Copy và Xuất Excel lấy giá trị thô** ⇒ ra `2026-08-15`, không phải `15/08/2026`. Cố ý: dán ngược vào lưới thì parse lại được, round-trip không mất mát.
|
|
116
|
-
|
|
117
|
-
#### Muốn có date picker
|
|
118
|
-
|
|
119
|
-
`type: "date"` lo hiển thị/parse/lọc, **không tự gắn editor** — sửa ô vẫn là gõ text. Cần picker thì khai thêm:
|
|
105
|
+
`type: "date"` adds **no editor** (text typing). For a picker:
|
|
120
106
|
|
|
121
107
|
```json
|
|
122
108
|
{ "field": "NgayThi", "headerName": "Ngày thi", "type": "date", "cellEditor": "agDateStringCellEditor" }
|
|
123
109
|
```
|
|
124
110
|
|
|
125
|
-
|
|
111
|
+
AG Grid built-in. Reads the **raw value**: ISO datetime (`2026-08-15T00:00:00`) opens **empty** until edited once → SP returns `CONVERT(date, NgayThi)`. Not attached by default because Enter would write `null` over the date.
|
|
126
112
|
|
|
127
|
-
>
|
|
113
|
+
> **`fsheetDate` was removed.** Old `"cellEditor": "fsheetDate"` → `"type": "date"` (+ `agDateStringCellEditor`). String `cellEditor`/`cellRenderer` resolves only if `window[name]` is a function; unknown names **silently** fall back to the text editor.
|
|
128
114
|
|
|
129
|
-
###
|
|
115
|
+
### `:height`
|
|
130
116
|
|
|
131
|
-
|
|
|
132
|
-
|
|
133
|
-
|
|
|
134
|
-
| `<= 0`
|
|
135
|
-
| `> 0`
|
|
117
|
+
| Value | Behavior |
|
|
118
|
+
| --------- | ------------------------------------------------------------- |
|
|
119
|
+
| _(empty)_ | **auto-grow** — `domLayout: 'autoHeight'`, no inner scrollbar |
|
|
120
|
+
| `<= 0` | **fill to screen bottom, leaving `abs(height)` px** |
|
|
121
|
+
| `> 0` | fixed px (e.g. `":height": 300`) |
|
|
136
122
|
|
|
137
|
-
|
|
123
|
+
`<=0` = `window.innerHeight - getBoundingClientRect().top - abs(height)` (min 200px), measured after layout, updated on `window.resize` — only the bottom gap matters.
|
|
138
124
|
|
|
139
|
-
-
|
|
140
|
-
-
|
|
141
|
-
-
|
|
142
|
-
- ⚠
|
|
143
|
-
- ⚠ Số âm **không** có nghĩa "viewport trừ đi N". Module cũ khai `":height": -220` phải sửa thành `-16`, nếu không lưới hụt mất ~200px.
|
|
125
|
+
- Main table: `":height": -16` (scrolls inside grid; lint D9 warns if `:height` missing).
|
|
126
|
+
- Dialog: **positive** px.
|
|
127
|
+
- Short/lookup tables: omit (auto-grow, exempt from D9). ⚠ Auto-grow renders every row, no virtualization — hundreds of rows → set `:height`.
|
|
128
|
+
- ⚠ Negative ≠ "viewport minus N": old `-220` → `-16`, else ~200px short.
|
|
144
129
|
|
|
145
130
|
---
|
|
146
131
|
|
|
147
|
-
##
|
|
132
|
+
## API wiring — response contract
|
|
148
133
|
|
|
149
|
-
|
|
134
|
+
Called as `ajaxCALL(api, { ...saveExtra, ...row })`. **SP returns one row:**
|
|
150
135
|
|
|
151
136
|
```
|
|
152
137
|
SELECT Success = 1, Message = N'Đã lưu' -- hoặc Success = 0 khi lỗi nghiệp vụ
|
|
153
138
|
```
|
|
154
139
|
|
|
155
|
-
|
|
140
|
+
Reads `res.data[0]`: `Message` → snackbar, `Success` → marks success. See [tapi-reference.md](tapi-reference.md).
|
|
156
141
|
|
|
157
|
-
- **
|
|
158
|
-
-
|
|
159
|
-
-
|
|
160
|
-
-
|
|
142
|
+
- **New rows**: temp **negative** key (−1, −2…), **light green**; on save key → `0` in payload → SP INSERTs.
|
|
143
|
+
- **Edited cells**: **light yellow**; toolbar shows "N rows changed".
|
|
144
|
+
- Save runs **per row, in parallel**; all OK → baseline refreshed, marks cleared, `saved` emitted.
|
|
145
|
+
- Delete existing rows: with `delete-api` → `confirm`, then API per row; without → local, no prompt. New rows → always local, no prompt, no API.
|
|
161
146
|
|
|
162
147
|
---
|
|
163
148
|
|
|
164
|
-
##
|
|
149
|
+
## Built-in (don't code)
|
|
165
150
|
|
|
166
|
-
-
|
|
167
|
-
-
|
|
168
|
-
-
|
|
169
|
-
-
|
|
170
|
-
-
|
|
171
|
-
- Toolbar: **
|
|
151
|
+
- Inline edit + change tracking.
|
|
152
|
+
- Range select: drag or Shift+click.
|
|
153
|
+
- Fill handle: drag bottom-right square to repeat the source block (along the longer drag direction).
|
|
154
|
+
- TSV Copy/Cut/Paste (Excel/Google Sheets): Ctrl+C/X/V in grid, or right-click (Cut/Copy/Copy with Headers/Paste).
|
|
155
|
+
- Escape clears selection.
|
|
156
|
+
- Toolbar: **Export Excel** (always, `jsonToExcel`) · **Add** (`allow-add`) · **Save** (when changes; `disabled` without `update-api`) · **Discard changes** (when changes) · **Delete selected** (`allow-delete`, multi-select, only with selection).
|
|
172
157
|
|
|
173
|
-
## Events &
|
|
158
|
+
## Events & methods (`$refs`)
|
|
174
159
|
|
|
175
|
-
- Emit: `change(data, field, value)` (
|
|
176
|
-
-
|
|
160
|
+
- Emit: `change(data, field, value)` (each cell change) · `save(rows)` (Save clicked, before API) · `saved` (all saved).
|
|
161
|
+
- Methods: `getChangedRows()` · `addRow()` · `deleteRow(row)` · `deleteSelected()` · `discardAll()` · `exportExcel()`.
|
|
177
162
|
|
|
178
163
|
---
|
|
179
164
|
|
|
180
|
-
##
|
|
165
|
+
## module.json example
|
|
181
166
|
|
|
182
167
|
```json
|
|
183
168
|
{
|
|
@@ -188,11 +173,11 @@ f-sheet đọc `res.data[0]` → hiện snackbar `Message`; `Success` quyết đ
|
|
|
188
173
|
":items": "dsDiem",
|
|
189
174
|
"row-key": "DiemID",
|
|
190
175
|
":columns": [
|
|
191
|
-
{ "field": "MaSV",
|
|
176
|
+
{ "field": "MaSV", "headerName": "Mã SV", "editable": false, "width": 120, "pinned": "left" },
|
|
192
177
|
{ "field": "HoTen", "headerName": "Họ tên", "editable": false },
|
|
193
|
-
{ "field": "Diem",
|
|
194
|
-
{ "field": "NgayThi","headerName": "Ngày thi", "type": "date" },
|
|
195
|
-
{ "field": "GhiChu","headerName": "Ghi chú" }
|
|
178
|
+
{ "field": "Diem", "headerName": "Điểm", "type": "number" },
|
|
179
|
+
{ "field": "NgayThi", "headerName": "Ngày thi", "type": "date" },
|
|
180
|
+
{ "field": "GhiChu", "headerName": "Ghi chú" }
|
|
196
181
|
],
|
|
197
182
|
":allow-add": true,
|
|
198
183
|
":allow-delete": true,
|
|
@@ -205,14 +190,14 @@ f-sheet đọc `res.data[0]` → hiện snackbar `Message`; `Success` quyết đ
|
|
|
205
190
|
}
|
|
206
191
|
```
|
|
207
192
|
|
|
208
|
-
- `dsDiem`
|
|
209
|
-
- `Diem_Save`/`Diem_Delete
|
|
210
|
-
-
|
|
193
|
+
- `dsDiem` loaded first by a `data[]` action (`API`/`OUT`).
|
|
194
|
+
- `Diem_Save`/`Diem_Delete`: tAPI SPs returning `{ Success, Message }` per row.
|
|
195
|
+
- Detail window from toolbar/column button/menu → `openWindow`: [ui-crosswindow-patterns.md](ui-crosswindow-patterns.md) §5.
|
|
211
196
|
|
|
212
197
|
## Checklist
|
|
213
198
|
|
|
214
|
-
1.
|
|
215
|
-
2. `row-key`
|
|
216
|
-
3.
|
|
217
|
-
4. `:height
|
|
218
|
-
5.
|
|
199
|
+
1. Both **AG Grid files** imported via `fui import new`, in order (`ag-grid-community.min.js` then `fsheet.js`).
|
|
200
|
+
2. `row-key` = real PK; `update-api`/`delete-api` SPs return `{ Success, Message }`.
|
|
201
|
+
3. AG Grid colDef; link/button/menu → 4 built-in renderers; `type: "number"`/`"date"` only (no manual `cellStyle`/`valueFormatter`/`valueParser`); other types → `valueFormatter`/`valueParser`.
|
|
202
|
+
4. `:height`: main `-16`, dialog positive, empty only for short tables.
|
|
203
|
+
5. Don't rebuild grid/CSS — config via `columns`; range select/fill/copy-paste are built in.
|