@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,63 +1,61 @@
|
|
|
1
1
|
# FUI Vue Component Design Rules
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Owns: **`uc-*.vue` rules: module/project scope, no `name:`/`components:{}`, props/emits/slots, no `_injectStyle`, manual `<style scoped>` scoping, verification (`fui component preview`, push project components before module render), `{projectId}/COMPONENTS.md`**. Approved classes/props: [controls-styling-vocabulary.md](controls-styling-vocabulary.md).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Mandatory for every `uc-*.vue`, dialog components included.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
## 1.
|
|
9
|
+
## 1. Two scopes: module vs project
|
|
10
10
|
|
|
11
|
-
|
|
|
12
|
-
|
|
13
|
-
| **
|
|
14
|
-
| **Registry**
|
|
15
|
-
| **
|
|
16
|
-
| **Auto-load**
|
|
17
|
-
| **
|
|
11
|
+
| | Module-scope | Project-scope (global) |
|
|
12
|
+
| -------------- | ---------------------------------------------------- | ----------------------------------------- |
|
|
13
|
+
| **File** | `{projectId}/modules/{moduleId}/components/uc-*.vue` | `{projectId}/components/uc-*.vue` |
|
|
14
|
+
| **Registry** | `modules/{moduleId}/components/_components.json` | `{projectId}/components/_components.json` |
|
|
15
|
+
| **Visible in** | That module only | **All modules in the project** |
|
|
16
|
+
| **Auto-load** | In its module | Automatic — **nothing to declare** |
|
|
17
|
+
| **Use when** | Used by one module | Reused across modules |
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
### Quy tắc chọn scope
|
|
19
|
+
### Choosing scope
|
|
22
20
|
|
|
23
21
|
```
|
|
24
22
|
Component này sẽ dùng ở nhiều module? → project-scope
|
|
25
23
|
Component chỉ dùng trong một module? → module-scope
|
|
26
24
|
```
|
|
27
25
|
|
|
28
|
-
###
|
|
26
|
+
### Commands per scope
|
|
29
27
|
|
|
30
|
-
|
|
|
31
|
-
|
|
32
|
-
| **
|
|
33
|
-
| **
|
|
34
|
-
| **
|
|
35
|
-
|
|
|
36
|
-
| **Sync
|
|
37
|
-
| **
|
|
28
|
+
| Operation | Module-scope | Project-scope (global) |
|
|
29
|
+
| -------------------------- | --------------------------------------------------- | -------------------------------------------------- |
|
|
30
|
+
| **Create** (not on server) | `fui component new <name>` — uses session module | `fui component new <name> -p <pid>` — NO module |
|
|
31
|
+
| **Update** (on server) | `fui component update <name>` — uses session module | `fui component update <name> -p <pid>` — NO module |
|
|
32
|
+
| **Delete** | `fui component delete <name>` — uses session module | `fui component delete <name> -p <pid>` — NO module |
|
|
33
|
+
| **Read source** | `fui component get <name> -p <pid> -m <mid>` | `fui component get <name> -p <pid>` — omit module |
|
|
34
|
+
| **Sync list** | `fui component list -p <pid> -m <mid>` | `fui component list -p <pid>` — omit module |
|
|
35
|
+
| **Workspace file** | `{moduleDir}/components/uc-foo.vue` | `{projectDir}/components/uc-foo.vue` |
|
|
38
36
|
|
|
39
|
-
**
|
|
37
|
+
**Single rule:** module given → module-scope · no module, only project → project-scope. Flags: `fui component --help`.
|
|
40
38
|
|
|
41
|
-
**
|
|
39
|
+
**Create ≠ update — no implicit upsert.** Both read the **local** `.vue` (must exist on disk) and derive `ComID` from `_components.json` (never pass it):
|
|
42
40
|
|
|
43
|
-
- `
|
|
44
|
-
- `
|
|
41
|
+
- `fui component new` — INSERT only. Refreshes `_components.json` **from the server first**, then checks the name; duplicate = **hard error** (INSERT on a stale cache creates **two same-name records**, unfixable from fui). Re-syncs after to get the real `ComID`.
|
|
42
|
+
- `fui component update` — UPDATE only. No `ComID` = **hard error**, never creates: never created (→ `fui component new`) or stale cache (→ `fui component list`, retry).
|
|
45
43
|
|
|
46
|
-
|
|
44
|
+
`fui component delete` looks up ComID in local `_components.json`; stale → `fui component list` first.
|
|
47
45
|
|
|
48
|
-
**`
|
|
46
|
+
**`fui module publish html` excludes project-scope components** — push them separately (`fui component new`/`update`).
|
|
49
47
|
|
|
50
48
|
---
|
|
51
49
|
|
|
52
|
-
## 1a.
|
|
50
|
+
## 1a. Existing project components — `{projectId}/COMPONENTS.md`
|
|
53
51
|
|
|
54
|
-
|
|
52
|
+
Before designing a project-scope component, **check `{projectId}/COMPONENTS.md`** (if present): existing project `uc-*.vue` with purpose and main props. Don't rebuild one that exists.
|
|
55
53
|
|
|
56
54
|
```
|
|
57
|
-
{
|
|
55
|
+
{workspace}/{projectId}/COMPONENTS.md ← kiểm tra TRƯỚC khi tạo component project-scope mới
|
|
58
56
|
```
|
|
59
57
|
|
|
60
|
-
**
|
|
58
|
+
**Accumulation:** after creating/updating a reusable project component, append an entry; no file → create with:
|
|
61
59
|
|
|
62
60
|
```markdown
|
|
63
61
|
# {projectId} — Danh sách component project-scope
|
|
@@ -70,24 +68,21 @@ Trước khi thiết kế một component cấp project mới, **phải kiểm t
|
|
|
70
68
|
**Ghi chú:** điều gì cần biết khi dùng (nếu có)
|
|
71
69
|
```
|
|
72
70
|
|
|
73
|
-
>
|
|
71
|
+
> Mirrors `{projectId}/DESIGN.md` ([design-modes.md](design-modes.md) §2-3). **Never auto-remove entries** — remove only after `fui component delete` removed it from the server.
|
|
74
72
|
|
|
75
73
|
---
|
|
76
74
|
|
|
77
|
-
## 2.
|
|
75
|
+
## 2. Naming and file layout
|
|
78
76
|
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
- **Registry**: khai báo trong `components/_components.json` (chỉ cần `comName`, không tự đặt `comID`)
|
|
77
|
+
- Prefix `uc-` (User Component; vs `f-*` FUI runtime, `v-*` Vuetify), kebab-case: `uc-trangthai-sukien.vue`, `uc-user-profile.vue`
|
|
78
|
+
- Only in `components/` at module or project root; no subfolders
|
|
79
|
+
- Registry `components/_components.json`: only `comName`, never set `comID`
|
|
83
80
|
|
|
84
81
|
---
|
|
85
82
|
|
|
86
|
-
## 3.
|
|
87
|
-
|
|
88
|
-
FUI tự động scan và đăng ký toàn bộ `uc-*.vue` ở cấp **global**. Tuyệt đối không khai báo `components: { ... }` bên trong một component — nó không hoạt động trong môi trường FUI.
|
|
83
|
+
## 3. Registration — NO `components: {}`, NO `name:`
|
|
89
84
|
|
|
90
|
-
|
|
85
|
+
FUI auto-registers every `uc-*.vue` **globally**. Never declare `components: { ... }` (doesn't work in FUI) or `name:` (FUI derives it from the filename; may conflict):
|
|
91
86
|
|
|
92
87
|
```js
|
|
93
88
|
// ❌ SAI — không cần và có thể gây xung đột
|
|
@@ -105,8 +100,8 @@ export default {
|
|
|
105
100
|
```js
|
|
106
101
|
// ❌ SAI — không dùng trong FUI
|
|
107
102
|
export default {
|
|
108
|
-
components: {
|
|
109
|
-
}
|
|
103
|
+
components: { "uc-user-card": UcUserCard },
|
|
104
|
+
};
|
|
110
105
|
|
|
111
106
|
// ✅ ĐÚNG — dùng trực tiếp tag trong template
|
|
112
107
|
// <uc-user-card :data="data" />
|
|
@@ -116,9 +111,8 @@ export default {
|
|
|
116
111
|
|
|
117
112
|
## 4. Props
|
|
118
113
|
|
|
119
|
-
-
|
|
120
|
-
-
|
|
121
|
-
- Default của Array/Object phải dùng `function()`, không dùng arrow function:
|
|
114
|
+
- `script`: camelCase (`userName`, `itemList`); `template`: kebab-case (`:user-name="userName"`)
|
|
115
|
+
- Array/Object defaults use `function()`, not arrow functions:
|
|
122
116
|
|
|
123
117
|
```js
|
|
124
118
|
// ❌ SAI
|
|
@@ -128,24 +122,23 @@ props: { items: { default: () => [] } }
|
|
|
128
122
|
props: { items: { default: function() { return [] } } }
|
|
129
123
|
```
|
|
130
124
|
|
|
131
|
-
-
|
|
132
|
-
- Không đặt tên props gắn chặt với một màn hình cụ thể nếu component có thể dùng lại
|
|
125
|
+
- Prefer neutral reusable names (`items`, `value`, `label`, `loading`, `readonly`, `disabled`, `options`, `config`), not screen-specific ones
|
|
133
126
|
|
|
134
127
|
---
|
|
135
128
|
|
|
136
129
|
## 5. Emits
|
|
137
130
|
|
|
138
|
-
-
|
|
139
|
-
-
|
|
140
|
-
- Dialog
|
|
131
|
+
- Emit to the parent; never mutate parent state
|
|
132
|
+
- Standard: `input`, `change`, `select`, `submit`, `remove`, `action`
|
|
133
|
+
- Dialog components always close with `('input', false)` — Vue 2 `v-model` compatible
|
|
141
134
|
|
|
142
135
|
---
|
|
143
136
|
|
|
144
|
-
## 6. Template syntax
|
|
137
|
+
## 6. Template syntax constraints
|
|
145
138
|
|
|
146
|
-
###
|
|
139
|
+
### No backticks in `<template>`
|
|
147
140
|
|
|
148
|
-
|
|
141
|
+
Breaks in Vue 2 templates; concatenate:
|
|
149
142
|
|
|
150
143
|
```html
|
|
151
144
|
<!-- ❌ SAI -->
|
|
@@ -155,11 +148,11 @@ Template strings (backtick) không hoạt động đúng trong Vue 2 template. D
|
|
|
155
148
|
:label="'Total (' + items.length + ')'"
|
|
156
149
|
```
|
|
157
150
|
|
|
158
|
-
###
|
|
151
|
+
### No `@` shorthand in JSON
|
|
159
152
|
|
|
160
|
-
|
|
153
|
+
`module.json`: always `v-on:click`, never `@click`. `.vue` templates: `@click` is fine.
|
|
161
154
|
|
|
162
|
-
### Vue 2
|
|
155
|
+
### Vue 2 needs a single root element
|
|
163
156
|
|
|
164
157
|
```html
|
|
165
158
|
<!-- ✅ ĐÚNG -->
|
|
@@ -172,13 +165,13 @@ Trong `module.json` luôn dùng `v-on:click`, không dùng `@click`. Trong `.vue
|
|
|
172
165
|
|
|
173
166
|
---
|
|
174
167
|
|
|
175
|
-
## 7. Style & class —
|
|
168
|
+
## 7. Style & class — use existing Vuetify classes, DON'T invent
|
|
176
169
|
|
|
177
|
-
**
|
|
170
|
+
**Use Vuetify utility classes for ALL spacing/flex/text/color/size. New class only when truly special** (effect/layout Vuetify lacks) — invented classes break consistency.
|
|
178
171
|
|
|
179
|
-
### ❌
|
|
172
|
+
### ❌ NEVER inject CSS via JavaScript
|
|
180
173
|
|
|
181
|
-
|
|
174
|
+
No `<style>` created in JS and appended to `document.head` (`_injectStyle`) — severe anti-pattern (dodges the no-`<style>` rule, spawns invented classes):
|
|
182
175
|
|
|
183
176
|
```js
|
|
184
177
|
// ❌ SAI NGHIÊM TRỌNG — không bao giờ làm thế này trong .vue
|
|
@@ -191,10 +184,10 @@ methods: {
|
|
|
191
184
|
}
|
|
192
185
|
```
|
|
193
186
|
|
|
194
|
-
`<style scoped>`
|
|
187
|
+
`<style scoped>` is allowed for custom CSS (rarely needed), but **does not scope**: FUI concatenates every module component's `ComCSS` into ONE stylesheet (`ComponentCSSBuild()`) — no SFC compile, no `data-v-xxxx`. **Scope manually**:
|
|
195
188
|
|
|
196
|
-
1.
|
|
197
|
-
2.
|
|
189
|
+
1. Template root gets a class = component name (`uc-invoice-list` → `class="uc-invoice-list"`).
|
|
190
|
+
2. EVERY selector starts from that class — **no bare selectors** (`.title`, `.header`...); they leak into every component in the module.
|
|
198
191
|
|
|
199
192
|
```vue
|
|
200
193
|
<template>
|
|
@@ -207,58 +200,57 @@ methods: {
|
|
|
207
200
|
</template>
|
|
208
201
|
|
|
209
202
|
<style scoped>
|
|
210
|
-
.uc-invoice-list__toolbar {
|
|
211
|
-
|
|
212
|
-
|
|
203
|
+
.uc-invoice-list__toolbar {
|
|
204
|
+
display: flex;
|
|
205
|
+
align-items: center;
|
|
206
|
+
justify-content: space-between;
|
|
207
|
+
}
|
|
208
|
+
.uc-invoice-list__title {
|
|
209
|
+
font-weight: 600;
|
|
210
|
+
font-size: 14px;
|
|
211
|
+
}
|
|
212
|
+
.uc-invoice-list__table {
|
|
213
|
+
margin-top: 8px;
|
|
214
|
+
}
|
|
213
215
|
</style>
|
|
214
216
|
```
|
|
215
217
|
|
|
216
218
|
```vue
|
|
217
219
|
<!-- ❌ SAI — selector trần, đụng với component khác cùng module có class .title/.toolbar -->
|
|
218
220
|
<style scoped>
|
|
219
|
-
.title {
|
|
220
|
-
|
|
221
|
+
.title {
|
|
222
|
+
font-weight: 600;
|
|
223
|
+
}
|
|
224
|
+
.toolbar {
|
|
225
|
+
display: flex;
|
|
226
|
+
}
|
|
221
227
|
</style>
|
|
222
228
|
```
|
|
223
229
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
### Trước khi đặt một class mới → tra bộ từ vựng đã duyệt
|
|
230
|
+
Module-wide CSS → `style.css` (`fui module publish css`); `header.html` still works but isn't the only option.
|
|
227
231
|
|
|
228
|
-
|
|
229
|
-
breakpoint, kích thước) + thứ tự ưu tiên + điều kiện được định nghĩa class riêng:
|
|
230
|
-
→ [controls-styling-vocabulary.md](controls-styling-vocabulary.md) §3.
|
|
232
|
+
### Before adding a class → check the approved vocabulary
|
|
231
233
|
|
|
232
|
-
|
|
233
|
-
không có `w`/`col` của grid FUI (đó là cú pháp của `module.json`, runtime FUI dịch ra class), nên
|
|
234
|
-
phải viết grid Vuetify trực tiếp.
|
|
234
|
+
Allowed Vuetify classes/props (spacing, flex, text, color, radius, elevation, breakpoint, size), priority, when a custom class is allowed → [controls-styling-vocabulary.md](controls-styling-vocabulary.md) §3. Applies unchanged in `.vue`, **except** no FUI grid `w`/`col` (`module.json` syntax translated by the runtime) — write the Vuetify grid directly.
|
|
235
235
|
|
|
236
|
-
**
|
|
237
|
-
(canonical: [controls-patterns.md](controls-patterns.md) §Vuetify version):
|
|
236
|
+
**Grid syntax DIFFERS by framework** — FUI V2 = Vuetify 1.5, FUI V3 = Vuetify 3 (canonical: [controls-patterns.md](controls-patterns.md) §Vuetify version):
|
|
238
237
|
|
|
239
|
-
|
|
|
240
|
-
|
|
241
|
-
|
|
|
242
|
-
| `v-flex`
|
|
243
|
-
| `v-layout`
|
|
244
|
-
| prop
|
|
238
|
+
| | V2 (Vuetify 1.5) | V3 (Vuetify 3) |
|
|
239
|
+
| ------------------ | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
240
|
+
| Columns | `v-layout` > `v-flex xs8` | `v-row` > `v-col cols="8"` |
|
|
241
|
+
| `v-flex` | ✅ | ❌ **does not exist** — renders as an inert HTML element: no error, no `[Vue warn]`, just **layout gone** |
|
|
242
|
+
| `v-layout` | ✅ grid row | ⚠️ **exists with a different meaning**: app layout wrapper (with `v-main`, as `fastproject-3.0.js` uses), NOT a grid row. Using it instead of `v-row` gives a flex container without grid gutter/breakpoints |
|
|
243
|
+
| bare prop `shrink` | ✅ (`v-flex` prop) | ❌ no such prop → inert DOM attribute. Use `class="shrink"` |
|
|
245
244
|
|
|
246
|
-
|
|
247
|
-
đổi sang `v-layout`/`v-flex` tương ứng.
|
|
245
|
+
§8 is **V3** (`v-row`/`v-col`); V2 projects use `v-layout`/`v-flex`. Silent breakage both ways: `v-flex` in V3 **shows content with wrong layout**, nothing reports it. Fixing an old component → `fui component preview` on **the project's framework** before pushing.
|
|
248
246
|
|
|
249
|
-
|
|
250
|
-
nội dung nhưng sai bố cục**, và không tầng nào báo. Sửa component cũ thì kiểm bằng `component_preview`
|
|
251
|
-
ở **đúng framework của project** trước khi push.
|
|
252
|
-
|
|
253
|
-
CSS tùy chỉnh riêng component (nếu thật sự cần) đặt trong `<style scoped>` của chính `.vue` đó, tự
|
|
254
|
-
scope thủ công theo quy tắc ở mục 7 phía trên — không đặt trong `header.html` trừ khi CSS đó dùng
|
|
255
|
-
chung cho nhiều component/toàn module.
|
|
247
|
+
Component-specific CSS → its own `<style scoped>`, manually scoped — not `header.html` unless shared by several components/the module.
|
|
256
248
|
|
|
257
249
|
---
|
|
258
250
|
|
|
259
|
-
## 8.
|
|
251
|
+
## 8. Standard dialog in `uc-*.vue` — STANDARD TEMPLATE
|
|
260
252
|
|
|
261
|
-
|
|
253
|
+
EVERY form dialog: `v-dialog` + `v-card` with these **fixed conventions**. Vuetify utility classes only — no invented classes, no `style`.
|
|
262
254
|
|
|
263
255
|
```html
|
|
264
256
|
<v-dialog v-model="editDialog" max-width="600">
|
|
@@ -274,12 +266,17 @@ Dùng `v-dialog` + `v-card` với **quy ước spacing/size cố định** dư
|
|
|
274
266
|
<v-card-text class="px-3 py-1">
|
|
275
267
|
<v-row>
|
|
276
268
|
<v-col cols="8">
|
|
277
|
-
<v-text-field v-model="editItem.RoundName" label="Tên vòng thi"
|
|
278
|
-
hide-details outlined dense></v-text-field>
|
|
269
|
+
<v-text-field v-model="editItem.RoundName" label="Tên vòng thi" hide-details outlined dense></v-text-field>
|
|
279
270
|
</v-col>
|
|
280
271
|
<v-col cols="4">
|
|
281
|
-
<v-text-field
|
|
282
|
-
|
|
272
|
+
<v-text-field
|
|
273
|
+
v-model.number="editItem.RoundOrder"
|
|
274
|
+
label="Thứ tự"
|
|
275
|
+
type="number"
|
|
276
|
+
hide-details
|
|
277
|
+
outlined
|
|
278
|
+
dense
|
|
279
|
+
></v-text-field>
|
|
283
280
|
</v-col>
|
|
284
281
|
</v-row>
|
|
285
282
|
</v-card-text>
|
|
@@ -294,51 +291,51 @@ Dùng `v-dialog` + `v-card` với **quy ước spacing/size cố định** dư
|
|
|
294
291
|
</v-dialog>
|
|
295
292
|
```
|
|
296
293
|
|
|
297
|
-
###
|
|
294
|
+
### Mandatory conventions (don't change arbitrarily)
|
|
298
295
|
|
|
299
|
-
|
|
|
300
|
-
|
|
301
|
-
| `v-dialog`
|
|
302
|
-
| `v-card-title`
|
|
303
|
-
| `v-card-text`
|
|
304
|
-
|
|
|
305
|
-
| `v-card-actions` |
|
|
306
|
-
|
|
|
307
|
-
|
|
|
308
|
-
|
|
|
296
|
+
| Part | Class/prop | Note |
|
|
297
|
+
| ---------------- | ---------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
298
|
+
| `v-dialog` | `max-width="600"` | 600 normal form; 400 small; 800–900 wide form |
|
|
299
|
+
| `v-card-title` | `d-flex align-center px-3 pt-2 pb-3 subtitle-1 font-weight-bold` | Compact title + X button (`v-btn icon` → `mdi-close`) on the right via `v-spacer` |
|
|
300
|
+
| `v-card-text` | `px-3 py-1` | Consistent content padding |
|
|
301
|
+
| Input fields | `outlined dense hide-details` | Compact, equal height; columns via `v-row` + `v-col cols="N"` |
|
|
302
|
+
| `v-card-actions` | **Last row**; `pa-3` + `v-spacer` before buttons | All actions right-aligned |
|
|
303
|
+
| Button width | No `block`, `width`, grow class or stretched column wrapper | Natural width from label |
|
|
304
|
+
| Primary button | At most one with `color="primary" elevation="0"` + `:loading="saving"` | Filled to show priority; `:loading` during API call |
|
|
305
|
+
| Secondary button | `text`, no background `color` | Minor actions; understated |
|
|
309
306
|
|
|
310
|
-
-
|
|
311
|
-
-
|
|
312
|
-
-
|
|
313
|
-
-
|
|
307
|
+
- Mode-dependent title: `{{ editItem.ID ? 'Chỉnh sửa' : 'Thêm mới' }}`.
|
|
308
|
+
- Numbers: `v-model.number` + `type="number"`.
|
|
309
|
+
- Close: `@click="dialogVar = false"`; also set `false` in the callback after a successful save.
|
|
310
|
+
- Keep default icon size; never add `small`/`:small` to `v-icon` or icon buttons.
|
|
314
311
|
|
|
315
|
-
###
|
|
312
|
+
### Variants
|
|
316
313
|
|
|
317
|
-
- **Toolbar header** (
|
|
318
|
-
- **Fullscreen** (
|
|
314
|
+
- **Toolbar header** (color/icon emphasis): replace `v-card-title` with `v-toolbar dense flat` + `v-toolbar-title`.
|
|
315
|
+
- **Fullscreen** (large/multi-area form): `<v-dialog v-model="..." fullscreen>` + `v-toolbar` header, content in `v-container class="grid-list-md"`.
|
|
319
316
|
|
|
320
317
|
---
|
|
321
318
|
|
|
322
|
-
## 9.
|
|
319
|
+
## 9. Design for reuse
|
|
323
320
|
|
|
324
|
-
-
|
|
325
|
-
- Expose loading/empty/disabled/readonly
|
|
326
|
-
-
|
|
327
|
-
-
|
|
321
|
+
- Shape as list, card, dialog body, filter panel, summary block or form section where possible
|
|
322
|
+
- Expose loading/empty/disabled/readonly via props/slots, don't hardcode a workflow
|
|
323
|
+
- API calls, routing, permissions stay in `module.json` or parent — component = presentation
|
|
324
|
+
- module.json `controls` > ~200 lines → extract UI to a Vue component; module.json keeps data/API
|
|
328
325
|
|
|
329
326
|
---
|
|
330
327
|
|
|
331
|
-
## 10.
|
|
328
|
+
## 10. No `f-dialog` inside a component template
|
|
332
329
|
|
|
333
|
-
`f-dialog`
|
|
330
|
+
`f-dialog` works only directly in the module's `controls` JSON. In `uc-*.vue` use the §8 v-dialog.
|
|
334
331
|
|
|
335
332
|
---
|
|
336
333
|
|
|
337
|
-
## 11.
|
|
334
|
+
## 11. `<script>` syntax limits
|
|
338
335
|
|
|
339
|
-
###
|
|
336
|
+
### No `async / await / finally`
|
|
340
337
|
|
|
341
|
-
|
|
338
|
+
Unsupported by the FUI `.vue` parser; use callbacks:
|
|
342
339
|
|
|
343
340
|
```js
|
|
344
341
|
// ❌ SAI
|
|
@@ -352,27 +349,27 @@ mounted() {
|
|
|
352
349
|
}
|
|
353
350
|
```
|
|
354
351
|
|
|
355
|
-
###
|
|
352
|
+
### No template literals (backticks) in `<script>`
|
|
356
353
|
|
|
357
|
-
|
|
354
|
+
Only work in standalone `script.js`:
|
|
358
355
|
|
|
359
356
|
```js
|
|
360
357
|
// ❌ SAI — trong .vue <script>
|
|
361
|
-
var url = `/api/Student/${this.studentID}
|
|
358
|
+
var url = `/api/Student/${this.studentID}`;
|
|
362
359
|
|
|
363
360
|
// ✅ ĐÚNG
|
|
364
|
-
var url =
|
|
361
|
+
var url = "/api/Student/" + this.studentID;
|
|
365
362
|
```
|
|
366
363
|
|
|
367
364
|
---
|
|
368
365
|
|
|
369
|
-
## 12.
|
|
366
|
+
## 12. Reuse `defaultfunction.js` — DON'T rewrite
|
|
370
367
|
|
|
371
|
-
|
|
368
|
+
**Before writing logic (API call, confirm, notify, format, group, copy...) → check [default-function.md](default-function.md).** Write your own only if nothing fits.
|
|
372
369
|
|
|
373
|
-
###
|
|
370
|
+
### API calls — `ajaxCALL` (NOT hand-rolled `fetch`/`axios`/`$.ajax`)
|
|
374
371
|
|
|
375
|
-
`fetch`
|
|
372
|
+
`fetch` fails cross-domain (CORS/credentials). `ajaxCALL` handles credentials, Bearer token and base domain (`v_Set.apiDomain`) — don't prepend it.
|
|
376
373
|
|
|
377
374
|
```js
|
|
378
375
|
// ❌ SAI
|
|
@@ -387,7 +384,7 @@ ajaxCALL('spAPI_RoundList', { ContestID: this.contestID }, function(res) {
|
|
|
387
384
|
})
|
|
388
385
|
```
|
|
389
386
|
|
|
390
|
-
###
|
|
387
|
+
### Confirm — `confirm` (NOT `window.confirm`)
|
|
391
388
|
|
|
392
389
|
```js
|
|
393
390
|
confirm({
|
|
@@ -397,59 +394,55 @@ confirm({
|
|
|
397
394
|
});
|
|
398
395
|
```
|
|
399
396
|
|
|
400
|
-
###
|
|
397
|
+
### Notify — `showMessage` or `Vue.$toast`
|
|
401
398
|
|
|
402
399
|
```js
|
|
403
|
-
showMessage({ title:
|
|
404
|
-
showMessage({ title:
|
|
405
|
-
Vue.$toast.success(
|
|
400
|
+
showMessage({ title: "Đã lưu thành công" }); // hộp thoại
|
|
401
|
+
showMessage({ title: "Lỗi", message: "...", type: "red" });
|
|
402
|
+
Vue.$toast.success("Đã lưu", { position: "top" }); // toast góc màn hình
|
|
406
403
|
```
|
|
407
404
|
|
|
408
|
-
###
|
|
405
|
+
### Other common helpers (don't rewrite)
|
|
409
406
|
|
|
410
|
-
`groupBy` · `findInArray` · `jsonToExcel` (
|
|
407
|
+
`groupBy` · `findInArray` · `jsonToExcel` (Excel export) · `printPDF` · `copyToClipboard` · `openWindow` · `pushRouter` · `rightTest` (permission check) · `generateID` · `capacityText` · `buildHeader` (auto f-table headers). Details: [default-function.md](default-function.md).
|
|
411
408
|
|
|
412
|
-
>
|
|
409
|
+
> Globals — never add a CDN for them: `_` (Lodash: `_.groupBy`, `_.sumBy`, `_.cloneDeep`...), `moment` (dates), `numeral` (numbers).
|
|
413
410
|
|
|
414
411
|
---
|
|
415
412
|
|
|
416
|
-
## 13.
|
|
413
|
+
## 13. Verify with `fui component preview` BEFORE assembling into the module
|
|
417
414
|
|
|
418
|
-
|
|
415
|
+
Seen only after assembly, component bugs and assembly bugs mix. `fui component preview` renders **one component** on its own page from the **local** `.vue` (no push needed) with sample data passed directly.
|
|
419
416
|
|
|
420
417
|
```
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
scenario: [ { click: "Xem" }, { assert: "vueData.selected != null" } ] }
|
|
430
|
-
],
|
|
431
|
-
devices: ["desktop", "mobile"] // mặc định
|
|
432
|
-
})
|
|
418
|
+
fui component preview uc-invoice-list -p <pid> --cases '[
|
|
419
|
+
{ "name": "danh sách rỗng", "props": { "items": [] } },
|
|
420
|
+
{ "name": "có dữ liệu", "props": { "items": [ {...}, {...} ], "title": "Hoá đơn" } },
|
|
421
|
+
{ "name": "click chọn dòng", "props": { "items": [...] },
|
|
422
|
+
"scenario": [ { "click": "Xem" }, { "assert": "vueData.selected != null" } ] }
|
|
423
|
+
]'
|
|
424
|
+
# -p only → project-scope; add -m <mid> → module-scope (same inference as fui component new/update)
|
|
425
|
+
# devices default: desktop + mobile
|
|
433
426
|
```
|
|
434
427
|
|
|
435
|
-
- **Props**:
|
|
436
|
-
- **`cases × devices` ≤ 8
|
|
437
|
-
- `slot` (
|
|
438
|
-
- `scenario`
|
|
439
|
-
-
|
|
440
|
-
-
|
|
428
|
+
- **Props**: arrays/objects as **real values** (pushed into `data[]`, bound `:prop`). Strings → static attrs; keys starting `:`/`v-` kept verbatim (use `v-on:`/`v-slot:`, **not** `@`/`#`).
|
|
429
|
+
- **`cases × devices` ≤ 8** (each render = real browser session).
|
|
430
|
+
- Also accepted: `slot` (`innerHTML` content), `vueData`, mocks, `user` (test permission gates), `viewport` (force low height to expose self-measuring components). Flags: `fui component preview --help`.
|
|
431
|
+
- `scenario` uses **the exact `--render` grammar on the real DOM**: `set`/`click`/`call`/`exe`/`assert`; pick rows with `nth` (no `item`/`index`).
|
|
432
|
+
- **Module `style.css` NOT loaded** — component must stand on its own `<style>` + project theme.
|
|
433
|
+
- Returns: screenshots (max 4 inline, rest as paths) + JS errors + `[Vue warn]` + DOM audit. **Read the images and fix** before pushing.
|
|
441
434
|
|
|
442
|
-
###
|
|
435
|
+
### Project components: MUST push before rendering a module that uses them
|
|
443
436
|
|
|
444
|
-
`
|
|
437
|
+
`fui module simulate --render` builds the project layer from the **server** bundle; unpushed local edits **don't appear** (screenshot lies). So `--render` **hard-blocks** (no override) when a local project component differs from the server bundle.
|
|
445
438
|
|
|
446
439
|
```
|
|
447
440
|
sửa uc-*.vue cấp project
|
|
448
|
-
→
|
|
449
|
-
→
|
|
450
|
-
→
|
|
441
|
+
→ fui component preview (kiểm chứng bản local, chưa push)
|
|
442
|
+
→ fui component new (lần đầu) hoặc fui component update (các lần sau) — push lên server
|
|
443
|
+
→ fui module simulate --render ← chỉ chạy được sau khi đã push
|
|
451
444
|
```
|
|
452
445
|
|
|
453
|
-
|
|
446
|
+
Blocked and **server is newer** (edited in web IDE) → `fui project sync`; **don't push over it** (erases their work).
|
|
454
447
|
|
|
455
|
-
|
|
448
|
+
**Module-level** components are exempt: the module layer renders from local files.
|