@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,203 +0,0 @@
|
|
|
1
|
-
# f-sheet — Data-Entry Grid (AG Grid)
|
|
2
|
-
|
|
3
|
-
> Owns: **`f-sheet` (AG Grid): import, props, columns, built-in cell renderers, range select/fill/clipboard, API wiring**.
|
|
4
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Required import
|
|
14
|
-
|
|
15
|
-
Exactly 2 files, **in this order**, via `fui import new` (missing → unusable):
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
/include/ag-grid/ag-grid-community.min.js
|
|
19
|
-
/include/ag-grid/fsheet.js
|
|
20
|
-
```
|
|
21
|
-
|
|
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
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
## Props
|
|
27
|
-
|
|
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
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
## Columns = AG Grid colDef
|
|
46
|
-
|
|
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 |
|
|
58
|
-
|
|
59
|
-
Other features (cellClassRules, aggregation...) → AG Grid docs; colDef passes straight through.
|
|
60
|
-
|
|
61
|
-
### columnType: only `number` and `date`
|
|
62
|
-
|
|
63
|
-
`type` references `gridOptions.columnTypes`; only two registered (`FS_COLUMN_TYPES`, top of `scripts/fsheet.js`). Unregistered name (`"date_time"`, `"currency"`, `"text"`, `"string"`, `"boolean"`…):
|
|
64
|
-
|
|
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
|
-
|
|
68
|
-
Other types (currency, percent, datetime…) → declare `valueFormatter`/`valueParser`/`filter` on the colDef, never a new `type`.
|
|
69
|
-
|
|
70
|
-
### Built-in cell renderers
|
|
71
|
-
|
|
72
|
-
Use `"cellRenderer": "name"` + `cellRendererParams`; nothing to declare in `script.js`:
|
|
73
|
-
|
|
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})` |
|
|
80
|
-
|
|
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`).
|
|
82
|
-
|
|
83
|
-
### `"type": "number"` — auto-attached (only if colDef doesn't declare it)
|
|
84
|
-
|
|
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` |
|
|
91
|
-
|
|
92
|
-
### `"type": "date"` — auto-attached (only if colDef doesn't declare it)
|
|
93
|
-
|
|
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` |
|
|
100
|
-
|
|
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.
|
|
102
|
-
|
|
103
|
-
#### Date picker
|
|
104
|
-
|
|
105
|
-
`type: "date"` adds **no editor** (text typing). For a picker:
|
|
106
|
-
|
|
107
|
-
```json
|
|
108
|
-
{ "field": "NgayThi", "headerName": "Ngày thi", "type": "date", "cellEditor": "agDateStringCellEditor" }
|
|
109
|
-
```
|
|
110
|
-
|
|
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.
|
|
112
|
-
|
|
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.
|
|
114
|
-
|
|
115
|
-
### `:height`
|
|
116
|
-
|
|
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`) |
|
|
122
|
-
|
|
123
|
-
`<=0` = `window.innerHeight - getBoundingClientRect().top - abs(height)` (min 200px), measured after layout, updated on `window.resize` — only the bottom gap matters.
|
|
124
|
-
|
|
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.
|
|
129
|
-
|
|
130
|
-
---
|
|
131
|
-
|
|
132
|
-
## API wiring — response contract
|
|
133
|
-
|
|
134
|
-
Called as `ajaxCALL(api, { ...saveExtra, ...row })`. **SP returns one row:**
|
|
135
|
-
|
|
136
|
-
```
|
|
137
|
-
SELECT Success = 1, Message = N'Đã lưu' -- hoặc Success = 0 khi lỗi nghiệp vụ
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
Reads `res.data[0]`: `Message` → snackbar, `Success` → marks success. See [tapi-reference.md](tapi-reference.md).
|
|
141
|
-
|
|
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.
|
|
146
|
-
|
|
147
|
-
---
|
|
148
|
-
|
|
149
|
-
## Built-in (don't code)
|
|
150
|
-
|
|
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).
|
|
157
|
-
|
|
158
|
-
## Events & methods (`$refs`)
|
|
159
|
-
|
|
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()`.
|
|
162
|
-
|
|
163
|
-
---
|
|
164
|
-
|
|
165
|
-
## module.json example
|
|
166
|
-
|
|
167
|
-
```json
|
|
168
|
-
{
|
|
169
|
-
"el": "f-sheet",
|
|
170
|
-
"w": 12,
|
|
171
|
-
"attr": {
|
|
172
|
-
"label": "Bảng điểm",
|
|
173
|
-
":items": "dsDiem",
|
|
174
|
-
"row-key": "DiemID",
|
|
175
|
-
":columns": [
|
|
176
|
-
{ "field": "MaSV", "headerName": "Mã SV", "editable": false, "width": 120, "pinned": "left" },
|
|
177
|
-
{ "field": "HoTen", "headerName": "Họ tên", "editable": false },
|
|
178
|
-
{ "field": "Diem", "headerName": "Điểm", "type": "number" },
|
|
179
|
-
{ "field": "NgayThi", "headerName": "Ngày thi", "type": "date" },
|
|
180
|
-
{ "field": "GhiChu", "headerName": "Ghi chú" }
|
|
181
|
-
],
|
|
182
|
-
":allow-add": true,
|
|
183
|
-
":allow-delete": true,
|
|
184
|
-
"update-api": "Diem_Save",
|
|
185
|
-
"delete-api": "Diem_Delete",
|
|
186
|
-
":save-extra": { "LopID": "vueData.lopID" },
|
|
187
|
-
":default-item": { "Diem": 0 },
|
|
188
|
-
":height": -16
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
```
|
|
192
|
-
|
|
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.
|
|
196
|
-
|
|
197
|
-
## Checklist
|
|
198
|
-
|
|
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.
|
|
@@ -1,313 +0,0 @@
|
|
|
1
|
-
# Full-Stack Module Workflow
|
|
2
|
-
|
|
3
|
-
> Owns: **the 6-step UI-first fullstack module workflow (analyze → UI with hard-coded data → lock contract → SP → API wiring → static verification)** and **the Design Review Gate procedure** (SKILL.md §3 holds only the rule "must pass the gate"; the steps live here). tAPI conventions: [tapi-reference.md](tapi-reference.md); multi-module design: [system-design.md](system-design.md).
|
|
4
|
-
|
|
5
|
-
**UI-first:** build UI (FUI) with hard-coded data, confirm visuals with `fui module simulate --render`, THEN lock the API (tAPI) contract and write SPs. Fixing data shape while it is a literal in `data[]` is far cheaper than after `IN`/`OUT`/`watch` depend on it. No step calls a real API/SP to "test" — verification = read + reason + mock ([verification.md](verification.md)). Read [tapi-reference.md](tapi-reference.md) before step 3.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Step 1 — Analyze requirements
|
|
10
|
-
|
|
11
|
-
**1.1 Business need:** list / search / filter? add / edit / delete? report / statistics? workflow (approve, reject, status)?
|
|
12
|
-
|
|
13
|
-
**1.2 Data (initial estimate — locked in step 3):** main entity and linked entities; which fields are displayed, which are input.
|
|
14
|
-
|
|
15
|
-
**1.3 Permissions and auth:**
|
|
16
|
-
|
|
17
|
-
- Login required? (no → use `AUTH_` in the SP)
|
|
18
|
-
- Rights by `sys_SystemRight`? → handle in the SP body
|
|
19
|
-
|
|
20
|
-
**Output:** feature list + main entity names (types/column names not yet locked).
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## Step 1b — Design Review Gate (mandatory, before the first line of code)
|
|
25
|
-
|
|
26
|
-
SKILL.md §3 = the **rule** (every new system/page/function passes); this = the **procedure**, for fullstack and UI-only modules.
|
|
27
|
-
|
|
28
|
-
1. **Business efficiency** — steps to finish the task, data truly needed, redundant steps.
|
|
29
|
-
2. **Project patterns** — `fui module list` + `fui module get` on similar modules (layout, control naming, action placement, filter/table/dialog). Match existing pages; **never invent a new style when a convention exists**.
|
|
30
|
-
3. **Sketch the UI** in words/rough layout — controls, placement, dialog/form flow.
|
|
31
|
-
4. **Self-review** — friendly? step count? Add/Edit/Delete, filters, pagination where expected? consistent? Issues → **fix the sketch first**, never in code.
|
|
32
|
-
5. Only then write code (step 2+).
|
|
33
|
-
|
|
34
|
-
**Choose the build approach:**
|
|
35
|
-
|
|
36
|
-
| Approach | When |
|
|
37
|
-
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
38
|
-
| **A — plain module.json** | Simple page: data display, single-table CRUD, basic form. Fewer files, easy to maintain. |
|
|
39
|
-
| **B — Vue component (`uc-*.vue`)** | Complex UI: multi-area dashboard, custom layout, UI logic reused in many places, or `controls` over ~200 lines ([component-design.md](component-design.md)). |
|
|
40
|
-
|
|
41
|
-
> Unspecified → **propose** one with a short reason and **wait for confirmation**; never choose silently.
|
|
42
|
-
|
|
43
|
-
**Component priority**: `f-*` first (`f-button` over `v-btn`, `f-table` over `v-data-table` for EVERY table, `f-echart` for every chart); `v-*` only when no FUI equivalent exists. → [component-quickref.md](component-quickref.md)
|
|
44
|
-
|
|
45
|
-
**Design System gate** (parallel): decide App-mode vs Web-mode and check `{projectId}/DESIGN.md` **before** sketching — separate aesthetic rules; never mix. → [design-modes.md](design-modes.md)
|
|
46
|
-
|
|
47
|
-
**Output:** self-reviewed sketch, approach A/B locked (user-confirmed if we proposed it), aesthetic mode decided.
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## Step 2 — Build UI with hard-coded data
|
|
52
|
-
|
|
53
|
-
Whole UI on **literal** data in `data[]`, no API yet. Structure: [module-json-anatomy.md](module-json-anatomy.md), [controls-patterns.md](controls-patterns.md).
|
|
54
|
-
|
|
55
|
-
```json
|
|
56
|
-
"data": [
|
|
57
|
-
{ "keyword": "" },
|
|
58
|
-
{ "classId": "" },
|
|
59
|
-
{ "studentList": [
|
|
60
|
-
{ "StudentID": "SV001", "FullName": "Nguyễn Văn A", "ClassID": "C01", "ClassName": "Lớp 10A", "GPA": 8.5 },
|
|
61
|
-
{ "StudentID": "SV002", "FullName": "Trần Thị B", "ClassID": "C02", "ClassName": "Lớp 10B", "GPA": 7.2 }
|
|
62
|
-
] },
|
|
63
|
-
{ "form": {} },
|
|
64
|
-
{ "dialogOpen": false }
|
|
65
|
-
]
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
`f-table`/`v-dialog`/form patterns: [component-table.md](component-table.md), [ui-templates.md](ui-templates.md).
|
|
69
|
-
|
|
70
|
-
**Visual QA now:** `fui module simulate --render` (vueData override: `fui module simulate --help`). Read screenshot + DOM audit; fix display bugs (horizontal overflow, broken dialog, missing labels...) before moving on.
|
|
71
|
-
|
|
72
|
-
**Output:** `module.json` with complete layout, running on hard-coded data, clean `--render` QA.
|
|
73
|
-
|
|
74
|
-
---
|
|
75
|
-
|
|
76
|
-
## Step 3 — Lock data shape + design API endpoints
|
|
77
|
-
|
|
78
|
-
From the step-2 fields (visually confirmed before becoming an SP contract), lock exact field names + types (→ SQL column types) and the source entity/table of each. Map features to SPs as `spAPI_{Entity}{Action}`; full naming (`spAPI_*` / `spAPI_AUTH_*` / `spAPIFILE_*`, `@url1_`, response contract) is in [tapi-reference.md](tapi-reference.md).
|
|
79
|
-
|
|
80
|
-
| Feature | SP name | Main params |
|
|
81
|
-
| ----------------- | ---------------------------- | ---------------------- |
|
|
82
|
-
| List | `spAPI_{Entity}List` | Filter params (custom) |
|
|
83
|
-
| Detail | `spAPI_{Entity}Get` | `@url1_{EntityID}` |
|
|
84
|
-
| Insert | `spAPI_{Entity}Insert` | Entity fields |
|
|
85
|
-
| Update | `spAPI_{Entity}Update` | ID + fields to update |
|
|
86
|
-
| Delete | `spAPI_{Entity}Delete` | `@url1_{EntityID}` |
|
|
87
|
-
| Lookup / dropdown | `spAPI_AUTH_{Entity}Options` | No auth, returns list |
|
|
88
|
-
|
|
89
|
-
**Example — "Student management"** (matches step-2 fields `StudentID`, `FullName`, `ClassID`, `ClassName`, `GPA`):
|
|
90
|
-
|
|
91
|
-
```
|
|
92
|
-
spAPI_StudentList -- danh sách, lọc theo ClassID + Keyword — trả đúng các cột đã hiển thị ở bước 2
|
|
93
|
-
spAPI_StudentGet -- chi tiết theo url1=StudentID
|
|
94
|
-
spAPI_StudentInsert -- thêm mới
|
|
95
|
-
spAPI_StudentUpdate -- cập nhật
|
|
96
|
-
spAPI_StudentDelete -- xoá theo url1=StudentID
|
|
97
|
-
spAPI_AUTH_ClassOptions -- dropdown danh sách lớp (không cần auth)
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
**Output:** full SP list; names + params + response shape match the fields used in the UI.
|
|
101
|
-
|
|
102
|
-
---
|
|
103
|
-
|
|
104
|
-
## Step 4 — Write SQL stored procedures
|
|
105
|
-
|
|
106
|
-
Per tAPI rules ([tapi-reference.md](tapi-reference.md)) and the step-3 contract.
|
|
107
|
-
|
|
108
|
-
**SELECT (list):**
|
|
109
|
-
|
|
110
|
-
```sql
|
|
111
|
-
CREATE PROCEDURE spAPI_StudentList
|
|
112
|
-
@Keyword nvarchar(200) = NULL,
|
|
113
|
-
@ClassID varchar(20) = NULL,
|
|
114
|
-
@sys_UserID varchar(9)
|
|
115
|
-
AS BEGIN
|
|
116
|
-
SELECT s.StudentID, s.FullName, s.ClassID, c.ClassName, s.GPA
|
|
117
|
-
FROM tblStudent s
|
|
118
|
-
JOIN tblClass c ON s.ClassID = c.ClassID
|
|
119
|
-
WHERE (@Keyword IS NULL OR s.FullName LIKE '%' + @Keyword + '%')
|
|
120
|
-
AND (@ClassID IS NULL OR s.ClassID = @ClassID)
|
|
121
|
-
ORDER BY s.FullName
|
|
122
|
-
END
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
**INSERT:**
|
|
126
|
-
|
|
127
|
-
```sql
|
|
128
|
-
CREATE PROCEDURE spAPI_StudentInsert
|
|
129
|
-
@StudentID varchar(9),
|
|
130
|
-
@FullName nvarchar(100),
|
|
131
|
-
@ClassID varchar(20),
|
|
132
|
-
@sys_UserID varchar(9)
|
|
133
|
-
AS BEGIN
|
|
134
|
-
IF EXISTS (SELECT 1 FROM tblStudent WHERE StudentID = @StudentID)
|
|
135
|
-
BEGIN
|
|
136
|
-
RAISERROR(N'Mã sinh viên đã tồn tại', 16, 1)
|
|
137
|
-
RETURN
|
|
138
|
-
END
|
|
139
|
-
INSERT INTO tblStudent (StudentID, FullName, ClassID, CreateUser, CreateTime)
|
|
140
|
-
VALUES (@StudentID, @FullName, @ClassID, @sys_UserID, GETDATE())
|
|
141
|
-
SELECT mess = N'Thêm thành công', id = @StudentID
|
|
142
|
-
END
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
**DELETE:**
|
|
146
|
-
|
|
147
|
-
```sql
|
|
148
|
-
CREATE PROCEDURE spAPI_StudentDelete
|
|
149
|
-
@url1_StudentID varchar(9),
|
|
150
|
-
@sys_UserID varchar(9)
|
|
151
|
-
AS BEGIN
|
|
152
|
-
DELETE FROM tblStudent WHERE StudentID = @url1_StudentID
|
|
153
|
-
SELECT mess = N'Đã xoá', id = @url1_StudentID
|
|
154
|
-
END
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
**GET (detail, convert_to_object):**
|
|
158
|
-
|
|
159
|
-
```sql
|
|
160
|
-
CREATE PROCEDURE spAPI_StudentGet
|
|
161
|
-
@url1_StudentID varchar(9),
|
|
162
|
-
@sys_UserID varchar(9)
|
|
163
|
-
AS BEGIN
|
|
164
|
-
SELECT convert_to_object = '',
|
|
165
|
-
s.StudentID, s.FullName, s.ClassID, c.ClassName, s.GPA, s.Email
|
|
166
|
-
FROM tblStudent s
|
|
167
|
-
JOIN tblClass c ON s.ClassID = c.ClassID
|
|
168
|
-
WHERE s.StudentID = @url1_StudentID
|
|
169
|
-
END
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
> `convert_to_object = ''` when the SP returns exactly one record → response is an object instead of `data[0][0]`.
|
|
173
|
-
|
|
174
|
-
Deploy with `fui sp save` + `fui sp deploy` (never call the endpoint to "try it" — see step 6).
|
|
175
|
-
|
|
176
|
-
**NEVER put `GRANT EXECUTE` in the .sql file.** A `CREATE PROCEDURE` body runs **to end of batch**; `_sql_execute_NonQuery` sends one batch and **does not support `GO`** (client directive, not T-SQL). A `GRANT` after `END` is **swallowed into the SP body** — runs on every call, never grants at deploy. No error; the endpoint just returns a permission error while the SP looks right.
|
|
177
|
-
|
|
178
|
-
`fui sp deploy` **auto-grants** new procedures (not FUNCTIONs — functions need no EXECUTE for `[public]`), then **re-checks `sys.database_permissions`** and reports:
|
|
179
|
-
|
|
180
|
-
- `✓ [public] đã có quyền EXECUTE trên "..."` — done.
|
|
181
|
-
- `❗ [public] CHƯA có quyền EXECUTE ...` — the output prints a runnable command; copy verbatim:
|
|
182
|
-
`fui exec "GRANT EXECUTE ON [dbo].[spAPI_StudentList] TO [public] AS [dbo]" --db ...`
|
|
183
|
-
- Grant failed but deploy succeeded → **the SP is already on the server**; run the GRANT above, **do not redeploy**.
|
|
184
|
-
|
|
185
|
-
Deploying via `fui exec` with `CREATE PROCEDURE` → **no auto-grant, no tAPI param-cache clear**; fui warns and names the two commands to run next.
|
|
186
|
-
|
|
187
|
-
**Output:** all step-3 SPs deployed.
|
|
188
|
-
|
|
189
|
-
---
|
|
190
|
-
|
|
191
|
-
## Step 5 — Replace hard-coded data with API bindings
|
|
192
|
-
|
|
193
|
-
Keep the step-2 layout; replace `data[]` literals with named `IN`/`OUT`/`CALLBACK` actions on the deployed SPs.
|
|
194
|
-
|
|
195
|
-
**5.1 Actions replacing hard-coded data**
|
|
196
|
-
|
|
197
|
-
```json
|
|
198
|
-
"data": [
|
|
199
|
-
{ "keyword": "" },
|
|
200
|
-
{ "classId": "" },
|
|
201
|
-
{ "studentList": [] },
|
|
202
|
-
|
|
203
|
-
{
|
|
204
|
-
"fetchStudents": {
|
|
205
|
-
"API": "/{apiName}/StudentList",
|
|
206
|
-
"IN": { "Keyword": "vueData.keyword", "ClassID": "vueData.classId" },
|
|
207
|
-
"OUT": "studentList"
|
|
208
|
-
}
|
|
209
|
-
},
|
|
210
|
-
{
|
|
211
|
-
"saveStudent": {
|
|
212
|
-
"API": "/{apiName}/StudentInsert",
|
|
213
|
-
"IN": {
|
|
214
|
-
"StudentID": "vueData.form.StudentID",
|
|
215
|
-
"FullName": "vueData.form.FullName",
|
|
216
|
-
"ClassID": "vueData.form.ClassID"
|
|
217
|
-
},
|
|
218
|
-
"CALLBACK": [
|
|
219
|
-
{ "CALL": "vueData.fetchStudents" },
|
|
220
|
-
{ "MESS": "Thêm thành công" },
|
|
221
|
-
{ "EXE": "vueData.dialogOpen = false" }
|
|
222
|
-
]
|
|
223
|
-
}
|
|
224
|
-
},
|
|
225
|
-
{
|
|
226
|
-
"deleteStudent": {
|
|
227
|
-
"API": "/{apiName}/StudentDelete/`{{vueData.selectedID}}",
|
|
228
|
-
"CONFIRM": "Bạn có chắc muốn xoá sinh viên này?",
|
|
229
|
-
"CALLBACK": { "CALL": "vueData.fetchStudents" }
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
]
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
**5.2 `watch` to reload when filters change**
|
|
236
|
-
|
|
237
|
-
```json
|
|
238
|
-
"watch": {
|
|
239
|
-
"keyword": { "CALL": "vueData.fetchStudents" },
|
|
240
|
-
"classId": { "CALL": "vueData.fetchStudents" }
|
|
241
|
-
}
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
**5.3** Append `{ "CALL": "vueData.fetchStudents" }` at the end of `data[]` to auto-load on open.
|
|
245
|
-
|
|
246
|
-
**Output:** `module.json` fully wired, layout unchanged from step 2.
|
|
247
|
-
|
|
248
|
-
---
|
|
249
|
-
|
|
250
|
-
## Step 6 — Static verification and finish
|
|
251
|
-
|
|
252
|
-
Pre-publish checklist — **no step calls a real API/SP/DML**:
|
|
253
|
-
|
|
254
|
-
**API/SP** — full checklist (naming, params, security, `GRANT EXECUTE`, deploy workflow): [verification.md](verification.md). Here:
|
|
255
|
-
|
|
256
|
-
- [ ] `AUTH_` on endpoints that need no login
|
|
257
|
-
- [ ] `fui sp verify` per new SP — reads the real body, infers response shape/error contract, checks params, emits a `--mocks` snippet (no endpoint call)
|
|
258
|
-
- [ ] **Write** APIs: read the body and reason (WHERE, transaction, RAISERROR) — no trial run
|
|
259
|
-
|
|
260
|
-
**module.json:**
|
|
261
|
-
|
|
262
|
-
- [ ] Each action's `API` path matches `/{apiName}/{FunctionName}`
|
|
263
|
-
- [ ] `IN` params match SP param names exactly (case-sensitive)
|
|
264
|
-
- [ ] Route params (url1, url2) go via the URL, not `IN`
|
|
265
|
-
- [ ] `OUT` receives the right type (array vs object per SP) — check against the shape inferred by `fui sp verify`
|
|
266
|
-
- [ ] `watch` declared for auto-reload filters
|
|
267
|
-
- [ ] `data[]` declares the initial fetch action and ends with a startup `{ "CALL": ... }`
|
|
268
|
-
|
|
269
|
-
**Final verification, in order:** `fui module validate` (syntax/rule errors) → `fui module outline` (text review of UI structure) → `fui module simulate --mocks '{...}'` using the `fui sp verify` snippet (action/watch/dialog flow) → if display is still in doubt, a last `fui module simulate --render` with the same `--mocks`. (`fui module check` runs validate + outline + simulate in one step.)
|
|
270
|
-
|
|
271
|
-
**Output:** module works end-to-end, UI ↔ API connected, zero real calls during verification.
|
|
272
|
-
|
|
273
|
-
---
|
|
274
|
-
|
|
275
|
-
## Complete output example
|
|
276
|
-
|
|
277
|
-
### SPs (step 4)
|
|
278
|
-
|
|
279
|
-
Each SP is **its own file** via `fui sp save` → `fui sp deploy`. No GRANT in the file, no `GO` (step 4); tAPI params **must not have default values** — `fui sp deploy` hard-blocks them.
|
|
280
|
-
|
|
281
|
-
```sql
|
|
282
|
-
-- 1. Danh sách (file spAPI_StudentList.sql)
|
|
283
|
-
CREATE PROCEDURE spAPI_StudentList @Keyword nvarchar(200), @ClassID varchar(20), @sys_UserID varchar(9)
|
|
284
|
-
AS BEGIN
|
|
285
|
-
SELECT s.StudentID, s.FullName, s.ClassID, s.GPA
|
|
286
|
-
FROM tblStudent s WHERE (@Keyword = '' OR s.FullName LIKE '%'+@Keyword+'%') AND (@ClassID = '' OR s.ClassID = @ClassID)
|
|
287
|
-
END
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
```sql
|
|
291
|
-
-- 2. Thêm mới (file spAPI_StudentInsert.sql)
|
|
292
|
-
CREATE PROCEDURE spAPI_StudentInsert @StudentID varchar(9), @FullName nvarchar(100), @ClassID varchar(20), @sys_UserID varchar(9)
|
|
293
|
-
AS BEGIN
|
|
294
|
-
INSERT INTO tblStudent(StudentID, FullName, ClassID, CreateUser, CreateTime) VALUES(@StudentID, @FullName, @ClassID, @sys_UserID, GETDATE())
|
|
295
|
-
SELECT mess = N'Thêm thành công'
|
|
296
|
-
END
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
### module.json actions (step 5)
|
|
300
|
-
|
|
301
|
-
```json
|
|
302
|
-
"fetchStudents": { "API": "/me/StudentList", "IN": { "Keyword": "vueData.keyword" }, "OUT": "studentList" },
|
|
303
|
-
"addStudent": { "API": "/me/StudentInsert", "IN": { "StudentID": "vueData.form.StudentID", "FullName": "vueData.form.FullName", "ClassID": "vueData.form.ClassID" }, "CALLBACK": [ { "CALL": "vueData.fetchStudents" }, { "MESS": "Đã thêm" } ] }
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
---
|
|
307
|
-
|
|
308
|
-
## Key notes
|
|
309
|
-
|
|
310
|
-
- **`{apiName}`** in the API path is the app's tAPI apiName (e.g. `me`, `lms`, `hr`). Ask the user if unknown. **A project may use several apiNames** (one database each) — each alias needs its own `fui db add`, and the alias in the path is the `--db` argument of DB commands ([db-workflow.md](db-workflow.md) §4).
|
|
311
|
-
- **Route params** (`@url1_`) go via the URL, not `IN`, using the backtick prefix: `"API": "/me/StudentDelete/\`{{vueData.selectedID}}"`
|
|
312
|
-
- **SP with multiple SELECTs** → `data[0]`, `data[1]`... — declare explicitly in `OUT` or split with `EXE`.
|
|
313
|
-
- **`convert_to_object = ''`** → flat object response: read `vueData.studentDetail.FullName`, not `vueData.studentDetail[0].FullName`.
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
# module.json `data[]` — State declaration & value resolution
|
|
2
|
-
|
|
3
|
-
> Owns: **`data[]` declaration patterns: three element kinds, order state → named action → auto-startup**. Value resolution: [controls-patterns.md](controls-patterns.md) §0; nested key syntax (dot/bracket/`#PARENT`): [controls-patterns.md](controls-patterns.md) §1; cross-window: [ui-crosswindow-patterns.md](ui-crosswindow-patterns.md).
|
|
4
|
-
|
|
5
|
-
FUI processes `data[]` **sequentially top to bottom**; each object assigns/runs based on how its value is written. Examples come from `ex/ex-v3-1SetData` + `ex-v3-2CauTruc` (official FUI demo modules).
|
|
6
|
-
|
|
7
|
-
> Overview of the 4 blocks: [module-json-anatomy.md](module-json-anatomy.md). Engine: [platform-architecture.md](platform-architecture.md) §5.
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## 1. Three element kinds in `data[]`
|
|
12
|
-
|
|
13
|
-
```json
|
|
14
|
-
"data": [
|
|
15
|
-
{ "keyword": "", "dsUser": [], "dlOpen": false }, // (a) khởi tạo state
|
|
16
|
-
{ "getUser": { "API": "...", "IN": {...}, "OUT": "dsUser" } }, // (b) named action
|
|
17
|
-
{ "API": "...", "OUT": "dsInit" }, // (c) action tự chạy khi load
|
|
18
|
-
{ "CALL": "getUser" } // (c) auto-startup
|
|
19
|
-
]
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
- (a) no action key → creates reactive var in `vueData`.
|
|
23
|
-
- (b) key is a **function name** → reusable action (invoke via `CALL`).
|
|
24
|
-
- (c) object is itself an action (`API`/`CALL`/`FUN`…) → **runs on page load**, in order.
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
## 2. Value resolution — HOW you write it decides the VALUE (common mistake)
|
|
29
|
-
|
|
30
|
-
Full rules (`getVueData`: backtick / `{{ }}` / string with spaces / string without spaces → JS eval) live in [controls-patterns.md §0](controls-patterns.md#0-value-resolution-rules-fundamental) — Tier A, always loaded; not repeated here.
|
|
31
|
-
|
|
32
|
-
> **Consequence for `data[]`:** to assign a **fixed string without spaces** (id, url, code) → **wrap in backticks** (``"`winUser"``) or single quotes (`"'winUser'"`), otherwise FUI treats it as a variable. This is the most common `data`/`IN` bug.
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
## 3. Keys as nested paths (deep set)
|
|
37
|
-
|
|
38
|
-
The left-hand key is also resolved (dot / bracket / dynamic index / `#PARENT`) — full syntax in [controls-patterns.md §1](controls-patterns.md#1-data-keys-and-assignment) _(Tier A, already loaded)_.
|
|
39
|
-
|
|
40
|
-
---
|
|
41
|
-
|
|
42
|
-
## 4. Auto-run action: inline `IN`/`OUT`/`API` on load
|
|
43
|
-
|
|
44
|
-
A standalone action object in `data[]` runs on load; no name needed:
|
|
45
|
-
|
|
46
|
-
```json
|
|
47
|
-
{ "API": "https://tapi.example.vn/me/auth/ApplicationList", "OUT": "Mang" },
|
|
48
|
-
{ "IN": { "ABC": "`gdsgdsg", "DEF": "val5", "CBV": 1233 }, "OUT": "DoiTuong" }
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
→ loads the page's initial data (catalogs, dropdowns, table data).
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
## 5. Named action + CALLBACK (reusable)
|
|
56
|
-
|
|
57
|
-
```json
|
|
58
|
-
{
|
|
59
|
-
"cmdSETData": [{ "MESS": "Thông báo" }, { "#Win1.GiaTriSetTuCHA": "Giá trị set từ CHA" }],
|
|
60
|
-
"apiChart": {
|
|
61
|
-
"API": "/ts/TS_Report_ForChart/{{ab}}",
|
|
62
|
-
"IN": { "sachID": "apiLoadFBUser", "modeY": 12345 },
|
|
63
|
-
"OUT": "DSDoiQuaTang",
|
|
64
|
-
"CALLBACK": { "AAA": "val2" }
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
Invoke with `{ "CALL": "cmdSETData" }` from `controls`, `watch` or another action. `CALLBACK` runs after the API completes (see [ui-patterns.md](ui-patterns.md) §7).
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
## 6. `watch` with `v_old` — previous value
|
|
74
|
-
|
|
75
|
-
In `watch`, `v_old.<field>` gives the value **before the change**:
|
|
76
|
-
|
|
77
|
-
```json
|
|
78
|
-
"watch": {
|
|
79
|
-
"val4": {
|
|
80
|
-
"API": "ts/auth/QuanHuyen_Select",
|
|
81
|
-
"IN": { "MaTinhTP": "tinhID" },
|
|
82
|
-
"OUT": "DS_QUAN_HUYEN",
|
|
83
|
-
"CALLBACK": { "BAC": "v_old.abcdeID" }
|
|
84
|
-
},
|
|
85
|
-
"taoID": { "dungthu": "v_old.taoID" }
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
`v_old`, `deep-watch` details: [watcher-patterns.md](watcher-patterns.md).
|
|
90
|
-
|
|
91
|
-
---
|
|
92
|
-
|
|
93
|
-
## 7. Cross-window exchange inside `data[]`
|
|
94
|
-
|
|
95
|
-
`data[]` can read/write other windows via `#PARENT.*` / `#WinID.*` keys/values — place **before** fetch CALLs:
|
|
96
|
-
|
|
97
|
-
```json
|
|
98
|
-
"data": [
|
|
99
|
-
{
|
|
100
|
-
"LayDuLieuWinCha": "#PARENT.Win1", // đọc data cha
|
|
101
|
-
"#PARENT.abcdef": 1234567890, // ghi xuống cha
|
|
102
|
-
"#Win1": { "CALL": "cmdTHONGBao" } // gọi lệnh ở Win1
|
|
103
|
-
}
|
|
104
|
-
]
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
Full: [ui-crosswindow-patterns.md](ui-crosswindow-patterns.md).
|
|
108
|
-
|
|
109
|
-
---
|
|
110
|
-
|
|
111
|
-
## 8. `data[]` checklist
|
|
112
|
-
|
|
113
|
-
1. Initialize **every** state var in the first object (including `[]`, `false`, `null`) so reactivity works.
|
|
114
|
-
2. Named actions in the middle; auto-startup (`CALL`/`API`) **last**.
|
|
115
|
-
3. Fixed space-free strings → **backticks**; never let FUI read them as variables.
|
|
116
|
-
4. `#PARENT.*` / URL vars before fetch CALLs.
|
|
117
|
-
5. No complex logic in `data` — move to `script.js` (functions) or sparing `EXE`.
|