@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.
- package/README.md +21 -3
- package/dist/fui-cx180e19.js +379 -0
- package/dist/fui.js +1 -1
- package/package.json +3 -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/skills/fui-target/.claude-plugin/plugin.json +6 -0
- package/skills/fui-target/hooks/hooks.json +1 -0
- package/skills/fui-target/hooks/register.tsx +71 -0
- package/skills/fui-target/types/index.d.ts +7 -0
- package/dist/fui-y8an39cn.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,269 +0,0 @@
|
|
|
1
|
-
# FUI Platform Architecture
|
|
2
|
-
|
|
3
|
-
> Owns: **FUI structure and Project→Module hierarchy: how import/component/set merge, `vueData`/`v_Set`, runtime lifecycle**.
|
|
4
|
-
|
|
5
|
-
Source of truth (not training data): runtime `scripts/fastproject.js` (main), `defaultfunction.js` (shared functions), `component.js`/`componentTable.js` (V3: `componentTable-3.0.js`) — core components (`f-table`, `t-*`, dialog, editor...). `f-echart` (`fechart.js`) and `f-sheet` (`fsheet.js`) are **separate files loaded via imports declared in module/project**, not auto-loaded.
|
|
6
|
-
|
|
7
|
-
> Read BEFORE designing a system/module. Then: per-part config → [module-json-anatomy.md](module-json-anatomy.md); project.json & set → [project-config.md](project-config.md); UI patterns → [ui-patterns.md](ui-patterns.md) (high priority, battle-tested).
|
|
8
|
-
|
|
9
|
-
## 1. What FUI is
|
|
10
|
-
|
|
11
|
-
Metadata-driven low-code: each page (module) declares UI + logic in `module.json`; `fastproject.js` builds the Vue 2 + Vuetify DOM from it. Declare only — never hand-write a Vue component per page.
|
|
12
|
-
|
|
13
|
-
Page load order (pre-bundled, **never re-import**):
|
|
14
|
-
|
|
15
|
-
1. jQuery, Lodash (`_`), Moment, Numeral, Vuetify, vue-toast, jquery-confirm
|
|
16
|
-
2. `defaultfunction.js` — utilities (`openWindow`, `CALL`, `confirm`, `showMessage`, `ajaxCALL`, `jsonToExcel`...)
|
|
17
|
-
3. `component.js` + `componentTable.js` — register all `f-*` / `t-*`
|
|
18
|
-
4. `fastproject.js` — read `module.json`, merge config, build DOM, run actions, attach watch
|
|
19
|
-
5. Page data: `$projectData` (project.json), `$moduleUI` (module.json), `$projectGroupSetting`
|
|
20
|
-
|
|
21
|
-
## 2. Project → Module hierarchy (merge rules — most important)
|
|
22
|
-
|
|
23
|
-
**Project** (shared) parts auto-merge into every **Module** (one page); on conflict **Module wins**.
|
|
24
|
-
|
|
25
|
-
### 2.1 `set`
|
|
26
|
-
|
|
27
|
-
Effective config `v_Set` (fastproject.js):
|
|
28
|
-
|
|
29
|
-
```js
|
|
30
|
-
$.extend(vueData.v_Set, $projectGroupSetting, $projectData, $moduleUI.set);
|
|
31
|
-
// rồi nếu có: $.extend(v_Set, v_Set.domainSetting[domain hiện tại])
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Priority (later overrides earlier):
|
|
35
|
-
|
|
36
|
-
```
|
|
37
|
-
$projectGroupSetting (cấu hình nhóm project — thấp nhất)
|
|
38
|
-
⤵ bị override bởi
|
|
39
|
-
$projectData = project.json (khối "data")
|
|
40
|
-
⤵ bị override bởi
|
|
41
|
-
$moduleUI.set = "set" trong module.json ← ƯU TIÊN CAO NHẤT
|
|
42
|
-
⤵ cuối cùng override bởi
|
|
43
|
-
v_Set.domainSetting[domain] (nếu đang chạy trên domain đó)
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
→ Module inherits all project config (menu, apiDomain, style, login...); declare `set` only for differences. A normal page has **no `set`**. Properties: [project-config.md](project-config.md).
|
|
47
|
-
|
|
48
|
-
### 2.2 `imports` — appended, not replaced
|
|
49
|
-
|
|
50
|
-
Project and module imports both load. `addImport`: `.css` → `<link>`; else `<script>`.
|
|
51
|
-
|
|
52
|
-
Order is **not** framework → project → module: server (`spA_FUI_ModuleDataSelect`) UNIONs framework (per V2/V3), project (`ModuleID IS NULL`) and module scopes, then sorts **once** by `FileSort, FileName`. A module import with small `FileSort` loads **before** a project import. Express order dependencies (e.g. `echarts.min.js` before `fechart.js`) with `FileSort`, never via scope.
|
|
53
|
-
|
|
54
|
-
Framework uses `FileSort` ~1-10. `fui import new`/`fui import update` guard this in code (`resolveImportSort`, `src/tools/module.ts`): empty sort → scope default (project ≥ 20, module ≥ 50); lower value → raised, with an `ℹ️` note in output. They cannot place an import before the framework — if truly needed, deploy via a route outside fui.
|
|
55
|
-
|
|
56
|
-
- Project-scope: shared libs for all modules.
|
|
57
|
-
- Module-scope: that page only (e.g. `echarts.min.js` + `fechart.js` for `f-echart`).
|
|
58
|
-
- `imports/_imports.json` = `[]` is normal when only bundled libs are used.
|
|
59
|
-
|
|
60
|
-
> Adding/removing a component that needs imports (f-echart, f-file-upload, f-editor...) → always `fui import list`, then `fui import new`/`fui import delete`. Import table: [component-quickref.md](component-quickref.md).
|
|
61
|
-
|
|
62
|
-
#### Import kinds by `ContentType`
|
|
63
|
-
|
|
64
|
-
| Kind | `ContentType` | Source | Edit with |
|
|
65
|
-
| ----------------------- | ------------------------------ | --------------------------------------------------------- | ---------------------------------------------------- |
|
|
66
|
-
| **CDN / URL reference** | empty or not JS/CSS | External URL (jsdelivr, cdnjs, custom...) — no local file | `fui import update` (metadata only: url, sort, name) |
|
|
67
|
-
| **Uploaded content** | `text/javascript` / `text/css` | Stored on FUI server; has `fileID` and local `filePath` | `fui import upload` (overwrite content) |
|
|
68
|
-
|
|
69
|
-
User attaches a JS/CSS file and asks for an import:
|
|
70
|
-
|
|
71
|
-
```
|
|
72
|
-
❌ WRONG: fui import new --content-type link --name "<some url>"
|
|
73
|
-
→ creates a CDN reference; file.js is never stored on the server
|
|
74
|
-
|
|
75
|
-
✅ RIGHT:
|
|
76
|
-
1. fui import new ... --content-type text/javascript → metadata (name, sort, scope)
|
|
77
|
-
2. fui import upload <fileId> -f file.js → upload content to FUI server
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
(Flags: `fui import new --help`.)
|
|
81
|
-
|
|
82
|
-
- `fui import upload` syncs to **every local `imports/`** declaring that `fileID` — no per-scope repeat.
|
|
83
|
-
- CDN imports: change URL/sort/name via `fui import update`; content **cannot** be uploaded into them.
|
|
84
|
-
- `fui import get` shows the kind (`ContentType`, `FilePath`); `fui import list` shows `ContentType` for all — check it first to pick the next command.
|
|
85
|
-
|
|
86
|
-
### 2.3 `components`
|
|
87
|
-
|
|
88
|
-
- `component.js` registers all `f-*`/`t-*` **globally**.
|
|
89
|
-
- Project-scope `uc-*.vue` (`{projectId}/components/`) → auto-loaded globally in **every** module, used by name (no `components:{}`).
|
|
90
|
-
- Module-scope `uc-*.vue` (`{moduleId}/components/`) → that module only.
|
|
91
|
-
- Same name → module-scope wins in that module.
|
|
92
|
-
|
|
93
|
-
> Design & scope: [component-design.md](component-design.md).
|
|
94
|
-
|
|
95
|
-
### 2.4 Summary
|
|
96
|
-
|
|
97
|
-
| Part | Project provides | Merge | On conflict |
|
|
98
|
-
| ---------------- | --------------------------------------------- | ------------------------------- | ------------------- |
|
|
99
|
-
| **set / config** | `project.json` (`data`) | Into `v_Set`, then `module.set` | **Module.set wins** |
|
|
100
|
-
| **imports** | project `_imports.json` | **Appended** to module imports | Both load |
|
|
101
|
-
| **components** | project-scope `uc-*.vue` + global `f-*`/`t-*` | Global in every module | Module-scope wins |
|
|
102
|
-
|
|
103
|
-
## 3. Built-in state (`vueData`)
|
|
104
|
-
|
|
105
|
-
Pre-initialized; use directly in `module.json`/`script.js`:
|
|
106
|
-
|
|
107
|
-
| Variable | Meaning |
|
|
108
|
-
| -------------------------------- | -------------------------------------------------------------------------------------- |
|
|
109
|
-
| `user` | Logged-in user (from `v_Set.userInfo`) |
|
|
110
|
-
| `v_Set` | Effective page config (§2.1) — [project-config.md](project-config.md) |
|
|
111
|
-
| `p_domain` | Hostname (e.g. `tsa.example.vn`) |
|
|
112
|
-
| `p_router` / `p_routers` | Path (`/manager/schedule-assignment`) / segments (`["manager","schedule-assignment"]`) |
|
|
113
|
-
| `p_params` | Query string (`?...`) |
|
|
114
|
-
| `p_urlReferrer` | Referrer URL |
|
|
115
|
-
| `v_Loading` / `v_LoadingOverlay` | API loading state (self-managed) |
|
|
116
|
-
| `v_containerOn` | Toggle main content area |
|
|
117
|
-
|
|
118
|
-
Real `vueData` (trimmed) — use for exact paths:
|
|
119
|
-
|
|
120
|
-
```json
|
|
121
|
-
{
|
|
122
|
-
"p_domain": "tsa.example.vn",
|
|
123
|
-
"p_routers": ["manager", "schedule-assignment"],
|
|
124
|
-
"p_router": "/manager/schedule-assignment",
|
|
125
|
-
"p_params": "",
|
|
126
|
-
"user": {
|
|
127
|
-
"UserID": "NV0000001", "UserName": "nguyenvana",
|
|
128
|
-
"LastName": "Nguyễn Văn", "FirstName": "A",
|
|
129
|
-
"Phone": "09xxxxxxxx", "Email": "nguyenvana@example.vn",
|
|
130
|
-
"GroupID": 1, "DepartmentID": "BGH", "ClassID": null,
|
|
131
|
-
"SystemRight": 9, "LastLogin": "2026-06-05 09:16:42",
|
|
132
|
-
"FunctionRight": ["1","2","3","4","5","6","7","8","9","10","11","12","13","14"]
|
|
133
|
-
},
|
|
134
|
-
"v_Set": {
|
|
135
|
-
"title": "Hệ thống quản lý tuyển sinh",
|
|
136
|
-
"apiDomain": "https://tapi.example.vn/",
|
|
137
|
-
"login": "https://app.example.vn",
|
|
138
|
-
"userInfo": "https://tapi.example.vn/acc/userinfo/ts",
|
|
139
|
-
"logo": "https://.../Logo_ChimLac_W.png",
|
|
140
|
-
"ProjectName": "Tuyển Sinh",
|
|
141
|
-
"menuLeft": false,
|
|
142
|
-
"menu": [ { "name": "...", "right": { "FunctionRight": ["10"] }, "submenu": [ ... ] } ],
|
|
143
|
-
"userProfile": {
|
|
144
|
-
"color": "white",
|
|
145
|
-
"url-signout": "https://app.example.vn/Signout",
|
|
146
|
-
"url-change-password": "https://app.example.vn/ChangePassword",
|
|
147
|
-
"url-account": "https://app.example.vn",
|
|
148
|
-
"url-avatar": "https://file.example.vn/me/avatarOrigin/",
|
|
149
|
-
"url-app-list": "https://tapi.example.vn/me/auth/ApplicationList"
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
`user` fields depend on the `userInfo` endpoint; usually `UserID`, `UserName`, `LastName`, `FirstName`, `Phone`, `Email`, `GroupID`, `DepartmentID`, `ClassID`, `SystemRight` (int), `FunctionRight` (**string array**, e.g. `["10","14"]`), `LastLogin`; some systems add `Sex`.
|
|
156
|
-
|
|
157
|
-
> `user.SystemRight` is a **number** (compare `>= 2`); `user.FunctionRight` is a **string array** (`.includes('10')` or `rightTest`). In controls: `vueData.user.UserID`, `vueData.user.SystemRight`, `vueData.v_Set.apiDomain`...
|
|
158
|
-
|
|
159
|
-
### userInfo endpoint
|
|
160
|
-
|
|
161
|
-
Permission DB is reached via **apiName/Alias `acc`**:
|
|
162
|
-
|
|
163
|
-
```
|
|
164
|
-
{apiDomain}/acc/userinfo/{project_apiName}
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
- `{apiDomain}` — tAPI domain (`vueData.v_Set.apiDomain`)
|
|
168
|
-
- `acc` — fixed permission-DB alias
|
|
169
|
-
- `userinfo` — API name
|
|
170
|
-
- `{project_apiName}` — project apiName/code (admin-set, e.g. `quansinh`, `ts`, `qlsv`)
|
|
171
|
-
|
|
172
|
-
Declare `userInfo` in `set` of `project.json` or `module.json`; FUI fetches it on load into `vueData.user`.
|
|
173
|
-
|
|
174
|
-
```json
|
|
175
|
-
// project.json → set
|
|
176
|
-
{
|
|
177
|
-
"userInfo": "https://tapi.example.vn/acc/userinfo/quansinh"
|
|
178
|
-
}
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
```js
|
|
182
|
-
vueData.user.UserID; // mã nhân viên/sinh viên
|
|
183
|
-
vueData.user.UserName; // tên đăng nhập
|
|
184
|
-
vueData.user.SystemRight; // quyền hệ thống (int 0–9)
|
|
185
|
-
vueData.user.FunctionRight; // mảng quyền chức năng ["1","2","10",...]
|
|
186
|
-
vueData.user.DepartmentID; // mã đơn vị
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
In controls (`v-if` by right):
|
|
190
|
-
|
|
191
|
-
```json
|
|
192
|
-
{ "col": { "v-if": "vueData.user.SystemRight >= 5" } }
|
|
193
|
-
{ "col": { "v-if": "vueData.user.FunctionRight.includes('10')" } }
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
In action `IN`:
|
|
197
|
-
|
|
198
|
-
```json
|
|
199
|
-
{ "API": "SP_GetDuLieu", "IN": { "UserID": "vueData.user.UserID", "DeptID": "vueData.user.DepartmentID" } }
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
> tAPI auto-injects `@sys_UserID`, `@sys_UserName`, `@sys_GroupID`... into every SP — never pass them via `IN`. Use `vueData.user.*` only for client-side JS/Vue logic.
|
|
203
|
-
|
|
204
|
-
### URL params → `vueData`
|
|
205
|
-
|
|
206
|
-
`buildParamURL()` sets `vueData[key] = value` for each `?key=value` **before** `data[]` runs. A child module opened via `openWindow`/`redirect` just declares same-named variables and ends `data[]` with `{ "CALL": "apiLoad" }` ([ui-crosswindow-patterns.md](ui-crosswindow-patterns.md)).
|
|
207
|
-
|
|
208
|
-
### User rights
|
|
209
|
-
|
|
210
|
-
Two independent kinds, both in the central permission DB (alias `acc`, `{project_apiName}` = project APIName in `tblModules`): `SystemRight` (rank on project, int) and `FunctionRight` (per function, string array). Use in `v-if` and menu `right`; `rightTest({ SystemRight:[...], FunctionRight:[...] })` checks intersection.
|
|
211
|
-
|
|
212
|
-
Concepts, `tblSysRight`/`tblFunction`, managing definitions (`fui right system|function list|new|update|delete`): [permission-system.md](permission-system.md).
|
|
213
|
-
|
|
214
|
-
## 4. Page init lifecycle (fastproject.js)
|
|
215
|
-
|
|
216
|
-
```
|
|
217
|
-
$(document).ready → loadModuleInfo()
|
|
218
|
-
1. Merge v_Set: $projectGroupSetting ← $projectData ← $moduleUI.set
|
|
219
|
-
2. Áp domainSetting[domain hiện tại] (nếu có)
|
|
220
|
-
3. buildParamURL(): query ?key=value → vueData[key]
|
|
221
|
-
4. Nếu v_Set.userInfo: fetch thông tin user → vueData.user
|
|
222
|
-
5. createModuleDom():
|
|
223
|
-
- runAction($moduleUI.data) → khởi tạo state + chạy action/CALL đầu
|
|
224
|
-
- buildModuleUI($moduleUI.controls) → dựng DOM (container>rows>cols)
|
|
225
|
-
- createWatch_Data / createWatch($moduleUI.watch) → gắn watcher
|
|
226
|
-
- new Vue(...) với Vuetify(v_Set.themeStyle)
|
|
227
|
-
- Kết nối websocket nếu có vueData.webSocket
|
|
228
|
-
- Kiểm tra đăng nhập (v_Set.login)
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
- `data[]` runs top to bottom: state init first, auto-startup `{ "CALL": ... }` last.
|
|
232
|
-
- Put `#PARENT.*` / URL variable assignments **before** fetch CALLs.
|
|
233
|
-
|
|
234
|
-
## 5. Action keys (quick ref)
|
|
235
|
-
|
|
236
|
-
Handled by `runAction`/`vueAction`. Patterns + value resolution: **[controls-patterns.md](controls-patterns.md)**.
|
|
237
|
-
|
|
238
|
-
| Key | Effect |
|
|
239
|
-
| ------------------------------ | ------------------------------------------------------------------------------------------ |
|
|
240
|
-
| `API` | Call endpoint (POST default). Path without `http` → `v_Set.apiDomain` prepended (`fixURL`) |
|
|
241
|
-
| `IN` | Params (mapped from `vueData`) |
|
|
242
|
-
| `OUT` | Result target. Response with only key `data` + string `OUT` → auto-unwrap `d.data` |
|
|
243
|
-
| `METHOD` | Override HTTP method (default POST) |
|
|
244
|
-
| `HEADER` | Override header (default `authorization: Bearer awt`) |
|
|
245
|
-
| `MESS` | Success toast |
|
|
246
|
-
| `MESSBOX` | Message dialog (`showMessage`) |
|
|
247
|
-
| `CALLBACK` | Runs after API/FUN finishes |
|
|
248
|
-
| `ERROROUT` / `ERRORCALLBACK` | Error branch |
|
|
249
|
-
| `CALL` | Call another named action |
|
|
250
|
-
| `CONFIRM` / `CANCEL` | Confirm first; cancel branch |
|
|
251
|
-
| `IF` / `THEN` / `ELSE` | Branch (JS expression on vueData) |
|
|
252
|
-
| `FUN` (+`IN`/`OUT`/`CALLBACK`) | Global function (`openWindow`, `jsonToExcel`, `printPDF`...) |
|
|
253
|
-
| `EXE` | Raw JS (sparingly) |
|
|
254
|
-
| _(plain object)_ | Assigned into `vueData` |
|
|
255
|
-
|
|
256
|
-
`json_data_parse` auto-parses `json_data:Field` response columns into objects ([tapi-reference.md](tapi-reference.md)).
|
|
257
|
-
|
|
258
|
-
## 6. Entry points
|
|
259
|
-
|
|
260
|
-
- `f-*` / `t-*` list + required imports → [component-quickref.md](component-quickref.md).
|
|
261
|
-
- Global utilities (`openWindow`, `CALL`, `confirm`, `showMessage`, `ajaxCALL`, `jsonToExcel`, `groupBy`, `pushRouter`, `rightTest`, `printPDF`, `webSocket_Send`...) → [default-function.md](default-function.md).
|
|
262
|
-
- Global libs (`$`, `_`, `moment`, `numeral`, `Vue.$toast`) → [script-map.md](script-map.md) §0 — read before adding any CDN.
|
|
263
|
-
|
|
264
|
-
## 7. Design rules
|
|
265
|
-
|
|
266
|
-
- Project provides the frame (menu, apiDomain, style, shared components); Module declares only differences — never repeat project config per module.
|
|
267
|
-
- Component used by >1 module → project-scope, never copied per module.
|
|
268
|
-
- Declare imports only where used; shared component → project-scope import.
|
|
269
|
-
- Everything runs on `vueData`; reference state with the `vueData.` prefix in controls/attrs.
|
|
@@ -1,303 +0,0 @@
|
|
|
1
|
-
# Project Config — project.json & module set
|
|
2
|
-
|
|
3
|
-
> Owns: **`project.json`: menu, menuLeft, navigation, domainSetting, `right`, relation to module `set`**.
|
|
4
|
-
|
|
5
|
-
> Platform merge mechanism: [platform-architecture.md](platform-architecture.md) §2.1. This file is the **full property catalog** for project.json and `set`.
|
|
6
|
-
|
|
7
|
-
> **Edit and push:** `project.json` is **file-driven** like `module.json`: `fui project sync` (pull latest) → edit `{projectId}/project.json` → `fui project publish-config [-p project]`. It takes no config arguments, so local never drifts from server. (`fui project update` edits project **metadata**, not runtime config.)
|
|
8
|
-
|
|
9
|
-
## project.json ↔ module.json `set`
|
|
10
|
-
|
|
11
|
-
At render `fastproject.js` merges **3 layers** (later overrides earlier), then the domain override:
|
|
12
|
-
|
|
13
|
-
```
|
|
14
|
-
$projectGroupSetting (cấu hình nhóm project — thấp nhất)
|
|
15
|
-
⤵ override bởi
|
|
16
|
-
project.json (khối "data")
|
|
17
|
-
⤵ override bởi
|
|
18
|
-
module.json "set" ← ưu tiên cao nhất
|
|
19
|
-
⤵ cuối cùng override bởi
|
|
20
|
-
domainSetting[domain hiện tại] (nếu đang chạy trên domain đó)
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Result: `vueData.v_Set` (read via `vueData.v_Set.*`). Module inherits all project config and may override any field. Normal pages **need no `set`**.
|
|
24
|
-
|
|
25
|
-
### `v_Set` properties (project.json.data or module.set; used by `fastproject.js`)
|
|
26
|
-
|
|
27
|
-
| Field | Type | Effect |
|
|
28
|
-
| ----------------- | ---------------- | ------------------------------------------------------------------------------- |
|
|
29
|
-
| `title` | string | Page title (header bar) |
|
|
30
|
-
| `apiDomain` | string | tAPI base URL — prepended to API paths without `http` |
|
|
31
|
-
| `login` | string | Login page URL; runtime opens it on missing token / 401 |
|
|
32
|
-
| `userInfo` | string | User info endpoint → `vueData.user`; empty = no fetch |
|
|
33
|
-
| `menu` | `false` \| array | Horizontal header menu; `false` = hidden (48px tall when shown) |
|
|
34
|
-
| `menuLeft` | array | Left sidebar menu |
|
|
35
|
-
| `menuComponent` | array | Custom components in the menu area |
|
|
36
|
-
| `menuStyle` | object | Top/left menu colors |
|
|
37
|
-
| `logo` | string | Header logo URL |
|
|
38
|
-
| `userProfile` | object/string | Header user profile block |
|
|
39
|
-
| `themeStyle` | object | Passed to `new Vuetify(...)` — page Vuetify theme |
|
|
40
|
-
| `disableValidate` | boolean | `true` = skip form validation on submit |
|
|
41
|
-
| `authDomain` | string | Domain whose cookies `logout()` clears |
|
|
42
|
-
| `fileDomain` | string | File server base URL |
|
|
43
|
-
| `domainSetting` | object | Per-domain config override (multi-domain) |
|
|
44
|
-
| `webSocket` | object | SignalR real-time group config ([websocket-realtime.md](websocket-realtime.md)) |
|
|
45
|
-
|
|
46
|
-
Example — only this landing page hides the header menu:
|
|
47
|
-
|
|
48
|
-
```json
|
|
49
|
-
// module.json — set của trang đó
|
|
50
|
-
"set": {
|
|
51
|
-
"menu": false
|
|
52
|
-
}
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## project.json structure
|
|
56
|
-
|
|
57
|
-
`project.json` holds a single `data` object (not an array like module.json):
|
|
58
|
-
|
|
59
|
-
```json
|
|
60
|
-
{
|
|
61
|
-
"data": {
|
|
62
|
-
"ProjectName": "...",
|
|
63
|
-
"title": "...",
|
|
64
|
-
"apiDomain": "...",
|
|
65
|
-
"login": "...",
|
|
66
|
-
"userInfo": "...",
|
|
67
|
-
"apiFile": "...",
|
|
68
|
-
"menuStyle": { ... },
|
|
69
|
-
"menu": false | [ ... ],
|
|
70
|
-
"menuLeft": [ ... ],
|
|
71
|
-
"menuComponent": [ ... ],
|
|
72
|
-
"domainSetting": { ... }
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### `data` fields
|
|
78
|
-
|
|
79
|
-
Same meaning as the `v_Set` table above, plus:
|
|
80
|
-
|
|
81
|
-
| Field | Type | Description |
|
|
82
|
-
| ------------- | ------ | ---------------------------------------------------------------------------------------------- |
|
|
83
|
-
| `ProjectName` | string | Display name |
|
|
84
|
-
| `title` | string | Default page title |
|
|
85
|
-
| `logo` | string | Menu bar logo URL, e.g. `"/images/fastUI_White.png"` |
|
|
86
|
-
| `apiDomain` | string | tAPI base URL with apiName, e.g. `https://tapi.example2.vn/` or `https://tapi.example.vn/acc/` |
|
|
87
|
-
| `userInfo` | string | Public FUI: `"https://api.fui.vn/fp/userinfo"` |
|
|
88
|
-
| `apiFile` | string | File upload endpoint (optional) |
|
|
89
|
-
| `fileDomain` | string | File server base URL (optional) |
|
|
90
|
-
|
|
91
|
-
## menuStyle
|
|
92
|
-
|
|
93
|
-
Top and left menu colors:
|
|
94
|
-
|
|
95
|
-
```json
|
|
96
|
-
"menuStyle": {
|
|
97
|
-
"topmenu": {
|
|
98
|
-
"bgcolor": "#217D46",
|
|
99
|
-
"textcolor": "white"
|
|
100
|
-
},
|
|
101
|
-
"leftmenu": {
|
|
102
|
-
"bgcolor": "#217D46",
|
|
103
|
-
"textcolor": "white"
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
## menu (top header)
|
|
109
|
-
|
|
110
|
-
- `false` → header bar with menu fully hidden
|
|
111
|
-
- Array → top bar menu items
|
|
112
|
-
|
|
113
|
-
**Fixed height: 48px** when shown. Every "full screen" content height calc (`calc(100vh - Npx)`, `$(window).height() - N`, CSS `height: 100vh` on a container...) must also subtract 48px, or it overflows/scrolls:
|
|
114
|
-
|
|
115
|
-
```css
|
|
116
|
-
/* Có menu hiển thị */
|
|
117
|
-
height: calc(100vh - 48px);
|
|
118
|
-
|
|
119
|
-
/* menu: false → không trừ phần này */
|
|
120
|
-
height: 100vh;
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
Applies to `module.json` (`:height` of `f-table`, `f-echart`...) and to CSS in `header.html`/components for `HTMLOnly=true` pages.
|
|
124
|
-
|
|
125
|
-
## menuLeft (sidebar)
|
|
126
|
-
|
|
127
|
-
Array of sidebar items. One item:
|
|
128
|
-
|
|
129
|
-
```json
|
|
130
|
-
{
|
|
131
|
-
"name": "Tên mục",
|
|
132
|
-
"icon": "mdi-folder-multiple",
|
|
133
|
-
"url": "/duong-dan-module",
|
|
134
|
-
"submenu": [ ... ],
|
|
135
|
-
"right": {
|
|
136
|
-
"SystemRight": [1, 2, 3, 5, 9],
|
|
137
|
-
"FunctionRight": ["10", "20"]
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### Menu item fields
|
|
143
|
-
|
|
144
|
-
| Field | Required | Description |
|
|
145
|
-
| --------- | -------- | ------------------------------------------------ |
|
|
146
|
-
| `name` | ✅ | Display name |
|
|
147
|
-
| `url` | ❌ | Module path (omit for a group with submenu only) |
|
|
148
|
-
| `icon` | ❌ | Material Design icon (`mdi-*`) |
|
|
149
|
-
| `submenu` | ❌ | Child items (same structure) |
|
|
150
|
-
| `right` | ❌ | Visibility by right — missing = visible to all |
|
|
151
|
-
|
|
152
|
-
### Menu visibility (`right`)
|
|
153
|
-
|
|
154
|
-
> `SystemRight` (rank) vs `FunctionRight` (per-function) and managing right definitions: [permission-system.md](permission-system.md).
|
|
155
|
-
|
|
156
|
-
```json
|
|
157
|
-
"right": {
|
|
158
|
-
"SystemRight": [1, 2, 5, 9],
|
|
159
|
-
"FunctionRight": ["10", "20"]
|
|
160
|
-
}
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
- **`SystemRight`**: `user.SystemRight` (number) must be in the array
|
|
164
|
-
- **`FunctionRight`**: `user.FunctionRight` (string array) must intersect the array (at least one code)
|
|
165
|
-
- **`UserID`**: only listed `UserID`s see it — for internal/DEV menus
|
|
166
|
-
- Multiple keys: user must satisfy **all** (`rightTest` checks each key's intersection with `vueData.user[key]`)
|
|
167
|
-
- No `right` → visible to every logged-in user
|
|
168
|
-
|
|
169
|
-
**Real example — DEV menu for a few UserIDs:**
|
|
170
|
-
|
|
171
|
-
```json
|
|
172
|
-
{
|
|
173
|
-
"name": "DEV",
|
|
174
|
-
"right": { "UserID": ["NV0000177", "NV0001078", "NV0000605"] },
|
|
175
|
-
"submenu": [{ "name": "Tra cứu lịch sử OTP", "url": "/hoso-sms-history" }]
|
|
176
|
-
}
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
> Top menu parents usually have only `name` + `right` + `submenu` (no `url`); `url` sits on each `submenu` item.
|
|
180
|
-
|
|
181
|
-
**Real example — menu for level-1 Team lead/BGH only:**
|
|
182
|
-
|
|
183
|
-
```json
|
|
184
|
-
{
|
|
185
|
-
"name": "Cấp 1 - Tổ trưởng",
|
|
186
|
-
"icon": "mdi-account-tie",
|
|
187
|
-
"right": {
|
|
188
|
-
"FunctionRight": ["10"],
|
|
189
|
-
"SystemRight": [5, 9]
|
|
190
|
-
},
|
|
191
|
-
"submenu": [ ... ]
|
|
192
|
-
}
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
→ Visible only if `FunctionRight` contains `"10"` AND `SystemRight` is 5 or 9.
|
|
196
|
-
|
|
197
|
-
## menuComponent
|
|
198
|
-
|
|
199
|
-
Custom Vue components embedded in the menu area (e.g. school-year or role dropdown):
|
|
200
|
-
|
|
201
|
-
```json
|
|
202
|
-
"menuComponent": [
|
|
203
|
-
{ "el": "uc-nien-khoa" },
|
|
204
|
-
{ "el": "uc-vaitro" }
|
|
205
|
-
]
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
Components must be registered in the project's `components/_components.json`.
|
|
209
|
-
|
|
210
|
-
## userProfile (header account block)
|
|
211
|
-
|
|
212
|
-
Header-right avatar/account block:
|
|
213
|
-
|
|
214
|
-
```json
|
|
215
|
-
"userProfile": {
|
|
216
|
-
"color": "white",
|
|
217
|
-
"url-signout": "https://app.example.vn/Signout",
|
|
218
|
-
"url-change-password": "https://app.example.vn/ChangePassword",
|
|
219
|
-
"url-account": "https://app.example.vn",
|
|
220
|
-
"url-avatar": "https://file.example.vn/me/avatarOrigin/",
|
|
221
|
-
"url-app-list": "https://tapi.example.vn/me/auth/ApplicationList"
|
|
222
|
-
}
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
| Field | Meaning |
|
|
226
|
-
| --------------------- | ----------------------------------- |
|
|
227
|
-
| `color` | Text/icon color |
|
|
228
|
-
| `url-signout` | Sign-out URL |
|
|
229
|
-
| `url-change-password` | Change-password URL |
|
|
230
|
-
| `url-account` | Account page URL |
|
|
231
|
-
| `url-avatar` | Avatar base URL (`UserID` appended) |
|
|
232
|
-
| `url-app-list` | App list endpoint (app switcher) |
|
|
233
|
-
|
|
234
|
-
> `menuLeft: false` = no left sidebar (top menu only). `menuLeft: [ ... ]` = sidebar on.
|
|
235
|
-
|
|
236
|
-
## domainSetting (multi-domain)
|
|
237
|
-
|
|
238
|
-
Project on several domains (each with its own tAPI server and DB):
|
|
239
|
-
|
|
240
|
-
```json
|
|
241
|
-
"domainSetting": {
|
|
242
|
-
"sec.example.vn": {
|
|
243
|
-
"apiDomain": "https://tapi.example.vn/acc/",
|
|
244
|
-
"fileDomain": "https://file.example.vn/acc/",
|
|
245
|
-
"login": "https://app.example.vn",
|
|
246
|
-
"userInfo": "https://tapi.example.vn/acc/UserInfo/acc"
|
|
247
|
-
},
|
|
248
|
-
"sec.example3.vn": {
|
|
249
|
-
"apiDomain": "https://api.example3.vn/acc/",
|
|
250
|
-
"fileDomain": "https://file.example3.vn/acc/",
|
|
251
|
-
"login": "https://login.example3.vn",
|
|
252
|
-
"userInfo": "https://api.example3.vn/acc/UserInfo/acc"
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
Key = hostname; runtime applies the current domain's override.
|
|
258
|
-
|
|
259
|
-
## module.json `set` — per-page override
|
|
260
|
-
|
|
261
|
-
`set` can override any project.json field. Common:
|
|
262
|
-
|
|
263
|
-
```json
|
|
264
|
-
"set": {
|
|
265
|
-
"title": "Trang quản lý sinh viên",
|
|
266
|
-
"menu": false,
|
|
267
|
-
"menuLeft": [ ... ]
|
|
268
|
-
}
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
| Use `set` when | Example |
|
|
272
|
-
| ------------------------------ | ----------------------------------------- |
|
|
273
|
-
| Page has its own title | `"title": "Nhập điểm Tiểu học"` |
|
|
274
|
-
| Page hides header menu | `"menu": false` |
|
|
275
|
-
| Page needs a different sidebar | Override `"menuLeft"` with a shorter list |
|
|
276
|
-
| Landing / public page | `"menu": false, "menuLeft": []` |
|
|
277
|
-
|
|
278
|
-
**Do not repeat unchanged fields** — declare only what differs from the project default.
|
|
279
|
-
|
|
280
|
-
## File relation summary
|
|
281
|
-
|
|
282
|
-
```
|
|
283
|
-
project.json.data ← config mặc định cho toàn project
|
|
284
|
-
↓ bị override bởi
|
|
285
|
-
module.json.set ← config riêng cho từng trang
|
|
286
|
-
|
|
287
|
-
Effective config = merge(project.json.data, module.json.set)
|
|
288
|
-
(module.set được ưu tiên)
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
## openWindow — URL parameter rule
|
|
292
|
-
|
|
293
|
-
Pass in the `openWindow` URL **only the parent record ID** the child queries the DB with. Never pass names, labels or any field the child can look up.
|
|
294
|
-
|
|
295
|
-
```json
|
|
296
|
-
// ✅ Đúng — chỉ truyền ID cần thiết
|
|
297
|
-
"url": "`/ContestDetail?ContestID={{sContestID}}"
|
|
298
|
-
|
|
299
|
-
// ❌ Sai — truyền thừa field có thể tra từ DB
|
|
300
|
-
"url": "`/ContestDetail?ContestID={{sContestID}}&ContestName={{sContestName}}"
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
Why: the child loads everything by ID; extra fields lengthen the URL, go stale, and couple the modules.
|