@fui-org/fui-cli 0.1.1 → 0.3.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 +18 -3
- package/dist/fui.js +160 -43
- package/package.json +4 -2
- package/skills/fui/SKILL.md +131 -66
- package/skills/fui-skill/README.md +112 -0
- package/skills/fui-skill/SKILL.md +269 -0
- package/skills/fui-skill/assets/projectdefaultstyle.css +518 -0
- package/skills/fui-skill/design-md/airbnb/DESIGN.md +545 -0
- package/skills/fui-skill/design-md/airbnb/README.md +5 -0
- package/skills/fui-skill/design-md/airtable/DESIGN.md +554 -0
- package/skills/fui-skill/design-md/airtable/README.md +5 -0
- package/skills/fui-skill/design-md/apple/DESIGN.md +562 -0
- package/skills/fui-skill/design-md/apple/README.md +5 -0
- package/skills/fui-skill/design-md/asu/DESIGN.md +179 -0
- package/skills/fui-skill/design-md/asu/README.md +107 -0
- package/skills/fui-skill/design-md/binance/DESIGN.md +634 -0
- package/skills/fui-skill/design-md/binance/README.md +5 -0
- package/skills/fui-skill/design-md/bmw/DESIGN.md +544 -0
- package/skills/fui-skill/design-md/bmw/README.md +5 -0
- package/skills/fui-skill/design-md/bmw-m/DESIGN.md +503 -0
- package/skills/fui-skill/design-md/bmw-m/README.md +5 -0
- package/skills/fui-skill/design-md/bugatti/DESIGN.md +454 -0
- package/skills/fui-skill/design-md/bugatti/README.md +5 -0
- package/skills/fui-skill/design-md/cal/DESIGN.md +542 -0
- package/skills/fui-skill/design-md/cal/README.md +5 -0
- package/skills/fui-skill/design-md/claude/DESIGN.md +589 -0
- package/skills/fui-skill/design-md/claude/README.md +5 -0
- package/skills/fui-skill/design-md/clay/DESIGN.md +541 -0
- package/skills/fui-skill/design-md/clay/README.md +5 -0
- package/skills/fui-skill/design-md/clickhouse/DESIGN.md +544 -0
- package/skills/fui-skill/design-md/clickhouse/README.md +5 -0
- package/skills/fui-skill/design-md/cohere/DESIGN.md +451 -0
- package/skills/fui-skill/design-md/cohere/README.md +5 -0
- package/skills/fui-skill/design-md/coinbase/DESIGN.md +570 -0
- package/skills/fui-skill/design-md/coinbase/README.md +5 -0
- package/skills/fui-skill/design-md/composio/DESIGN.md +506 -0
- package/skills/fui-skill/design-md/composio/README.md +5 -0
- package/skills/fui-skill/design-md/cursor/DESIGN.md +537 -0
- package/skills/fui-skill/design-md/cursor/README.md +5 -0
- package/skills/fui-skill/design-md/elevenlabs/DESIGN.md +504 -0
- package/skills/fui-skill/design-md/elevenlabs/README.md +5 -0
- package/skills/fui-skill/design-md/expo/DESIGN.md +526 -0
- package/skills/fui-skill/design-md/expo/README.md +5 -0
- package/skills/fui-skill/design-md/ferrari/DESIGN.md +531 -0
- package/skills/fui-skill/design-md/ferrari/README.md +5 -0
- package/skills/fui-skill/design-md/figma/DESIGN.md +578 -0
- package/skills/fui-skill/design-md/figma/README.md +5 -0
- package/skills/fui-skill/design-md/framer/DESIGN.md +544 -0
- package/skills/fui-skill/design-md/framer/README.md +5 -0
- package/skills/fui-skill/design-md/fui/DESIGN.md +532 -0
- package/skills/fui-skill/design-md/hashicorp/DESIGN.md +575 -0
- package/skills/fui-skill/design-md/hashicorp/README.md +5 -0
- package/skills/fui-skill/design-md/ibm/DESIGN.md +550 -0
- package/skills/fui-skill/design-md/ibm/README.md +5 -0
- package/skills/fui-skill/design-md/intercom/DESIGN.md +546 -0
- package/skills/fui-skill/design-md/intercom/README.md +5 -0
- package/skills/fui-skill/design-md/kraken/DESIGN.md +125 -0
- package/skills/fui-skill/design-md/kraken/README.md +5 -0
- package/skills/fui-skill/design-md/lamborghini/DESIGN.md +288 -0
- package/skills/fui-skill/design-md/lamborghini/README.md +5 -0
- package/skills/fui-skill/design-md/linear.app/DESIGN.md +548 -0
- package/skills/fui-skill/design-md/linear.app/README.md +5 -0
- package/skills/fui-skill/design-md/lovable/DESIGN.md +298 -0
- package/skills/fui-skill/design-md/lovable/README.md +5 -0
- package/skills/fui-skill/design-md/mastercard/DESIGN.md +365 -0
- package/skills/fui-skill/design-md/mastercard/README.md +5 -0
- package/skills/fui-skill/design-md/meta/DESIGN.md +683 -0
- package/skills/fui-skill/design-md/meta/README.md +5 -0
- package/skills/fui-skill/design-md/minimax/DESIGN.md +746 -0
- package/skills/fui-skill/design-md/minimax/README.md +5 -0
- package/skills/fui-skill/design-md/mintlify/DESIGN.md +852 -0
- package/skills/fui-skill/design-md/mintlify/README.md +5 -0
- package/skills/fui-skill/design-md/miro/DESIGN.md +825 -0
- package/skills/fui-skill/design-md/miro/README.md +5 -0
- package/skills/fui-skill/design-md/mistral.ai/DESIGN.md +773 -0
- package/skills/fui-skill/design-md/mistral.ai/README.md +5 -0
- package/skills/fui-skill/design-md/mongodb/DESIGN.md +767 -0
- package/skills/fui-skill/design-md/mongodb/README.md +5 -0
- package/skills/fui-skill/design-md/nike/DESIGN.md +575 -0
- package/skills/fui-skill/design-md/nike/README.md +5 -0
- package/skills/fui-skill/design-md/notion/DESIGN.md +821 -0
- package/skills/fui-skill/design-md/notion/README.md +5 -0
- package/skills/fui-skill/design-md/nvidia/DESIGN.md +640 -0
- package/skills/fui-skill/design-md/nvidia/README.md +5 -0
- package/skills/fui-skill/design-md/ollama/DESIGN.md +539 -0
- package/skills/fui-skill/design-md/ollama/README.md +5 -0
- package/skills/fui-skill/design-md/opencode.ai/DESIGN.md +521 -0
- package/skills/fui-skill/design-md/opencode.ai/README.md +5 -0
- package/skills/fui-skill/design-md/pinterest/DESIGN.md +597 -0
- package/skills/fui-skill/design-md/pinterest/README.md +5 -0
- package/skills/fui-skill/design-md/playstation/DESIGN.md +661 -0
- package/skills/fui-skill/design-md/playstation/README.md +5 -0
- package/skills/fui-skill/design-md/posthog/DESIGN.md +690 -0
- package/skills/fui-skill/design-md/posthog/README.md +5 -0
- package/skills/fui-skill/design-md/raycast/DESIGN.md +669 -0
- package/skills/fui-skill/design-md/raycast/README.md +5 -0
- package/skills/fui-skill/design-md/renault/DESIGN.md +589 -0
- package/skills/fui-skill/design-md/renault/README.md +5 -0
- package/skills/fui-skill/design-md/replicate/DESIGN.md +616 -0
- package/skills/fui-skill/design-md/replicate/README.md +5 -0
- package/skills/fui-skill/design-md/resend/DESIGN.md +585 -0
- package/skills/fui-skill/design-md/resend/README.md +5 -0
- package/skills/fui-skill/design-md/revolut/DESIGN.md +636 -0
- package/skills/fui-skill/design-md/revolut/README.md +5 -0
- package/skills/fui-skill/design-md/runwayml/DESIGN.md +244 -0
- package/skills/fui-skill/design-md/runwayml/README.md +5 -0
- package/skills/fui-skill/design-md/sanity/DESIGN.md +357 -0
- package/skills/fui-skill/design-md/sanity/README.md +5 -0
- package/skills/fui-skill/design-md/sentry/DESIGN.md +551 -0
- package/skills/fui-skill/design-md/sentry/README.md +5 -0
- package/skills/fui-skill/design-md/shopify/DESIGN.md +516 -0
- package/skills/fui-skill/design-md/shopify/README.md +5 -0
- package/skills/fui-skill/design-md/slack/DESIGN.md +482 -0
- package/skills/fui-skill/design-md/spacex/DESIGN.md +363 -0
- package/skills/fui-skill/design-md/spacex/README.md +5 -0
- package/skills/fui-skill/design-md/spotify/DESIGN.md +246 -0
- package/skills/fui-skill/design-md/spotify/README.md +5 -0
- package/skills/fui-skill/design-md/starbucks/DESIGN.md +580 -0
- package/skills/fui-skill/design-md/starbucks/README.md +5 -0
- package/skills/fui-skill/design-md/stripe/DESIGN.md +487 -0
- package/skills/fui-skill/design-md/stripe/README.md +5 -0
- package/skills/fui-skill/design-md/supabase/DESIGN.md +462 -0
- package/skills/fui-skill/design-md/supabase/README.md +5 -0
- package/skills/fui-skill/design-md/superhuman/DESIGN.md +448 -0
- package/skills/fui-skill/design-md/superhuman/README.md +5 -0
- package/skills/fui-skill/design-md/tesla/DESIGN.md +286 -0
- package/skills/fui-skill/design-md/tesla/README.md +5 -0
- package/skills/fui-skill/design-md/theverge/DESIGN.md +339 -0
- package/skills/fui-skill/design-md/theverge/README.md +5 -0
- package/skills/fui-skill/design-md/together.ai/DESIGN.md +633 -0
- package/skills/fui-skill/design-md/together.ai/README.md +5 -0
- package/skills/fui-skill/design-md/uber/DESIGN.md +636 -0
- package/skills/fui-skill/design-md/uber/README.md +5 -0
- package/skills/fui-skill/design-md/vercel/DESIGN.md +736 -0
- package/skills/fui-skill/design-md/vercel/README.md +5 -0
- package/skills/fui-skill/design-md/vodafone/DESIGN.md +538 -0
- package/skills/fui-skill/design-md/vodafone/README.md +5 -0
- package/skills/fui-skill/design-md/voltagent/DESIGN.md +521 -0
- package/skills/fui-skill/design-md/voltagent/README.md +5 -0
- package/skills/fui-skill/design-md/warp/DESIGN.md +526 -0
- package/skills/fui-skill/design-md/warp/README.md +5 -0
- package/skills/fui-skill/design-md/webflow/DESIGN.md +588 -0
- package/skills/fui-skill/design-md/webflow/README.md +5 -0
- package/skills/fui-skill/design-md/wired/DESIGN.md +497 -0
- package/skills/fui-skill/design-md/wired/README.md +5 -0
- package/skills/fui-skill/design-md/wise/DESIGN.md +544 -0
- package/skills/fui-skill/design-md/wise/README.md +5 -0
- package/skills/fui-skill/design-md/x.ai/DESIGN.md +465 -0
- package/skills/fui-skill/design-md/x.ai/README.md +5 -0
- package/skills/fui-skill/design-md/zapier/DESIGN.md +537 -0
- package/skills/fui-skill/design-md/zapier/README.md +5 -0
- package/skills/fui-skill/examples/component.vue +162 -0
- package/skills/fui-skill/examples/f-table-patterns.json +331 -0
- package/skills/fui-skill/examples/module-patterns.json +973 -0
- package/skills/fui-skill/examples/project-patterns.json +222 -0
- package/skills/fui-skill/metadata.json +75 -0
- package/skills/fui-skill/references/INDEX.md +144 -0
- package/skills/fui-skill/references/advanced-techniques.md +160 -0
- package/skills/fui-skill/references/coding-standards.md +112 -0
- package/skills/fui-skill/references/component-design.md +455 -0
- package/skills/fui-skill/references/component-quickref.md +77 -0
- package/skills/fui-skill/references/component-table.md +276 -0
- package/skills/fui-skill/references/components-dialog.md +192 -0
- package/skills/fui-skill/references/components-display.md +147 -0
- package/skills/fui-skill/references/components-echart.md +391 -0
- package/skills/fui-skill/references/components-input.md +359 -0
- package/skills/fui-skill/references/controls-patterns.md +847 -0
- package/skills/fui-skill/references/controls-styling-vocabulary.md +140 -0
- package/skills/fui-skill/references/db-table-design.md +77 -0
- package/skills/fui-skill/references/db-workflow.md +504 -0
- package/skills/fui-skill/references/default-function.md +415 -0
- package/skills/fui-skill/references/design-modes.md +85 -0
- package/skills/fui-skill/references/echart-templates.md +481 -0
- package/skills/fui-skill/references/fastproject.md +97 -0
- package/skills/fui-skill/references/fsheet.md +218 -0
- package/skills/fui-skill/references/fullstack-workflow.md +351 -0
- package/skills/fui-skill/references/module-data-patterns.md +126 -0
- package/skills/fui-skill/references/module-json-anatomy.md +137 -0
- package/skills/fui-skill/references/module-structure.md +260 -0
- package/skills/fui-skill/references/new-session.md +108 -0
- package/skills/fui-skill/references/pdfmake.md +60 -0
- package/skills/fui-skill/references/permission-system.md +169 -0
- package/skills/fui-skill/references/platform-architecture.md +294 -0
- package/skills/fui-skill/references/project-config.md +335 -0
- package/skills/fui-skill/references/project-provisioning.md +383 -0
- package/skills/fui-skill/references/script-map.md +296 -0
- package/skills/fui-skill/references/sql-clr-functions.md +224 -0
- package/skills/fui-skill/references/system-design.md +116 -0
- package/skills/fui-skill/references/tapi-file-api.md +191 -0
- package/skills/fui-skill/references/tapi-permission-patterns.md +158 -0
- package/skills/fui-skill/references/tapi-reference.md +549 -0
- package/skills/fui-skill/references/tools-registry.md +460 -0
- package/skills/fui-skill/references/ui-crosswindow-patterns.md +317 -0
- package/skills/fui-skill/references/ui-dialog-patterns.md +229 -0
- package/skills/fui-skill/references/ui-layout-patterns.md +176 -0
- package/skills/fui-skill/references/ui-patterns.md +315 -0
- package/skills/fui-skill/references/ui-screenshot-review.md +94 -0
- package/skills/fui-skill/references/ui-table-cell-patterns.md +316 -0
- package/skills/fui-skill/references/ui-templates.md +29 -0
- package/skills/fui-skill/references/verification.md +246 -0
- package/skills/fui-skill/references/watcher-patterns.md +196 -0
- package/skills/fui-skill/references/websocket-realtime.md +254 -0
- package/skills/fui-skill/scripts/component-3.0.js +2549 -0
- package/skills/fui-skill/scripts/component.js +3142 -0
- package/skills/fui-skill/scripts/componentTable-3.0.js +909 -0
- package/skills/fui-skill/scripts/componentTable.js +769 -0
- package/skills/fui-skill/scripts/defaultfunction-3.0.js +781 -0
- package/skills/fui-skill/scripts/defaultfunction.js +966 -0
- package/skills/fui-skill/scripts/fastproject-3.0.js +870 -0
- package/skills/fui-skill/scripts/fastproject.js +828 -0
- package/skills/fui-skill/scripts/fechart.js +890 -0
- package/skills/fui-skill/scripts/fsheet.js +1330 -0
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
# FUI Table Cell Patterns — f-table & in-cell controls
|
|
2
|
+
|
|
3
|
+
> File này sở hữu: **điều khiển trong ô `f-table` (`t-*`), `ctrl-update`, show-select, chip-group, chọn `t-button` vs `t-menu`**. Props bảng xem [component-table.md](component-table.md).
|
|
4
|
+
|
|
5
|
+
Các pattern cho `f-table` và điều khiển ngay trong ô bảng (`t-check`, `t-button`, `t-select`, `t-menu`, `ctrl-update`, `show-select`, `v-chip-group`). Rút ra từ project **security-manager**.
|
|
6
|
+
|
|
7
|
+
> Xem thêm: [ui-patterns.md](ui-patterns.md) (data/watch/toolbar), [ui-dialog-patterns.md](ui-dialog-patterns.md), [component-table.md](component-table.md).
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 1. f-table Cơ Bản với Fixed Header
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"el": "f-table",
|
|
16
|
+
"attr": {
|
|
17
|
+
"label": "User list",
|
|
18
|
+
":items-per-page": 50,
|
|
19
|
+
":height": -16,
|
|
20
|
+
":items": "dsUser",
|
|
21
|
+
"item-key": "UserID",
|
|
22
|
+
":hide-default-footer": false,
|
|
23
|
+
":item-class": "item => item.ChuaKichHoat>0 ? 'danger' : ''",
|
|
24
|
+
":headers": [
|
|
25
|
+
{ "align": "center", "text": "UserID", "value": "UserID" },
|
|
26
|
+
{ "text": "Username", "value": "UserName" },
|
|
27
|
+
{ "text": "Fullname", "value": "FullName" }
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"w": 12
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Kỹ thuật:**
|
|
35
|
+
- **QUY TẮC chiều cao bảng (lint D9)**: bảng data chính của module khai `":height": -16` — f-table tự **đo vị trí thật** của bảng sau khi layout (`getBoundingClientRect().top`) rồi fill tới đáy màn hình chừa 16px, và tự bật `fixed-header`. Cuộn data chỉ cuộn **trong bảng**, header không trôi, trang không có 2 thanh cuộn lồng nhau. Tự cập nhật khi resize cửa sổ và khi `items` đổi.
|
|
36
|
+
|
|
37
|
+
| `:height` | Hành vi |
|
|
38
|
+
|---|---|
|
|
39
|
+
| *(bỏ trống)* | Tự giãn theo số dòng — bảng ngắn/lookup chủ ý; bảng chính thì sai (cả trang sẽ cuộn) |
|
|
40
|
+
| `<= 0` | Fill tới đáy, chừa `abs(height)` px — **chuẩn cho bảng chính** |
|
|
41
|
+
| `> 0` | px cố định — **bảng trong dialog** (vd `":height": 360`) |
|
|
42
|
+
|
|
43
|
+
Cùng ba chế độ này áp cho `f-sheet` — xem [fsheet.md](fsheet.md) §Chiều cao.
|
|
44
|
+
|
|
45
|
+
⚠ Pattern cũ `":height": "$( window ).height()-285"` **không dùng nữa** — nó bắt bạn tự đoán tổng chiều cao toolbar/filter/menu, sai là hụt hoặc tràn. Biểu thức trả số **dương** nên vẫn chạy như px cố định (không vỡ), nhưng mất khả năng tự đo; lint D9 cảnh báo để bạn thay bằng `-16`.
|
|
46
|
+
- `:item-class`: highlight row theo điều kiện — `"item => item.Active==0 ? 'danger' : ''"`
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 2. t-check — Toggle trong Table Cell
|
|
51
|
+
|
|
52
|
+
Dùng trong `headers` để render checkbox/icon toggle, kích hoạt API khi click.
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"text": "Active",
|
|
57
|
+
"value": "Enable",
|
|
58
|
+
"align": "center",
|
|
59
|
+
"el": "t-check",
|
|
60
|
+
"attr": {
|
|
61
|
+
"on-icon": "mdi-check",
|
|
62
|
+
"off-icon": "mdi-lock",
|
|
63
|
+
":action": [
|
|
64
|
+
{ "API": "/SM_Users_SetActive", "IN": { "UserID": "item.UserID" } },
|
|
65
|
+
{ "dsUser": [] },
|
|
66
|
+
{ "CALL": "getUser" }
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 3. t-button — Button trong Table Cell
|
|
75
|
+
|
|
76
|
+
Dùng khi cần button/icon với action trong cell. Hỗ trợ icon động.
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"text": "Allow",
|
|
81
|
+
"value": "Locked",
|
|
82
|
+
"align": "center",
|
|
83
|
+
"el": "t-button",
|
|
84
|
+
"attr": {
|
|
85
|
+
"color": "primary",
|
|
86
|
+
":outlined": false,
|
|
87
|
+
":icon-text": "`${ item.Locked==0 ? 'mdi-check-bold':'mdi-lock'}`",
|
|
88
|
+
":action": [
|
|
89
|
+
{ "API": "/SM_Computer_SetLocked", "IN": { "ComputerID": "item.ComputerID" } },
|
|
90
|
+
{ "dsComputer": [] },
|
|
91
|
+
{ "CALL": "getComputer" }
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 4. t-select — Dropdown Inline trong Table Cell
|
|
100
|
+
|
|
101
|
+
Dùng để edit field ngay trong bảng, trigger API khi chọn.
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"text": "SystemRight",
|
|
106
|
+
"value": "SysRight",
|
|
107
|
+
"el": "t-select",
|
|
108
|
+
"width": "250px",
|
|
109
|
+
"attr": {
|
|
110
|
+
"class": "flex-md-grow-0 my-2",
|
|
111
|
+
":items": "vueData.dsSystemRight",
|
|
112
|
+
"item-text": "Note",
|
|
113
|
+
"item-value": "SysRight",
|
|
114
|
+
":action": [
|
|
115
|
+
{
|
|
116
|
+
"CONFIRM": "Bạn có chắc cập nhật System Right cho user này không?",
|
|
117
|
+
"API": "/SM_UserModule_UpdateSystemRight",
|
|
118
|
+
"IN": {
|
|
119
|
+
"ModuleID": "sModuleID",
|
|
120
|
+
"UserID": "item.UserID",
|
|
121
|
+
"SysRight": "item.SysRight"
|
|
122
|
+
},
|
|
123
|
+
"CALLBACK": { "MESS": "Cập nhật thành công." }
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 5. t-menu — Context Menu trong Table (menuChucNang Pattern)
|
|
133
|
+
|
|
134
|
+
Định nghĩa menu items trong `data[]`, ref qua `t-menu` trong headers.
|
|
135
|
+
|
|
136
|
+
**Bước 1 — Định nghĩa `menuChucNang` trong `data[]`:**
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"menuChucNang": [
|
|
141
|
+
{
|
|
142
|
+
"color": "primary",
|
|
143
|
+
"icon-text": "mdi-account-details",
|
|
144
|
+
"text": "Update Info",
|
|
145
|
+
"action": [
|
|
146
|
+
{
|
|
147
|
+
"addNew": 0,
|
|
148
|
+
"dongChon": "item",
|
|
149
|
+
"sUserID": "item.UserID",
|
|
150
|
+
"sUserName": "item.UserName",
|
|
151
|
+
"sLastName": "item.LastName",
|
|
152
|
+
"sFirstName": "item.FirstName"
|
|
153
|
+
},
|
|
154
|
+
{ "dlUserInfo": true }
|
|
155
|
+
]
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"color": "primary",
|
|
159
|
+
"icon-text": "mdi-shield-account-outline",
|
|
160
|
+
"text": "User Permission",
|
|
161
|
+
"action": [
|
|
162
|
+
{
|
|
163
|
+
"dongChon": "item",
|
|
164
|
+
"sUserID": "item.UserID",
|
|
165
|
+
"sFullName": "item.FullName"
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"FUN": "openWindow",
|
|
169
|
+
"IN": {
|
|
170
|
+
"id": "`WinPer",
|
|
171
|
+
"title": "`User Permission",
|
|
172
|
+
"url": "`/UserPermission"
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
]
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Bước 2 — Dùng `t-menu` trong `headers`:**
|
|
182
|
+
|
|
183
|
+
```json
|
|
184
|
+
{
|
|
185
|
+
"el": "t-menu",
|
|
186
|
+
"width": "120px",
|
|
187
|
+
"align": "center",
|
|
188
|
+
"text": "Update",
|
|
189
|
+
"value": "Update",
|
|
190
|
+
"attr": { ":items": "vueData.menuChucNang" }
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Pattern xử lý:**
|
|
195
|
+
- `"dongChon": "item"` — lưu bản ghi hiện tại vào `dongChon`
|
|
196
|
+
- Các field khác `"sUserID": "item.UserID"` — copy field từ item vào state
|
|
197
|
+
- `{ "dlXxx": true }` — mở dialog sau khi state đã sẵn sàng
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## 6. ctrl-update CRUD Pattern
|
|
202
|
+
|
|
203
|
+
CRUD trực tiếp trong bảng — không cần viết dialog thủ công.
|
|
204
|
+
|
|
205
|
+
```json
|
|
206
|
+
{
|
|
207
|
+
"el": "f-table",
|
|
208
|
+
"attr": {
|
|
209
|
+
":items": "dsFunctionRight",
|
|
210
|
+
"item-key": "FunctionID",
|
|
211
|
+
":headers": [
|
|
212
|
+
{ "text": "Code", "value": "FunctionCode" },
|
|
213
|
+
{ "text": "Name", "value": "FunctionName" },
|
|
214
|
+
{ "text": "Update", "value": "ctrl-update" }
|
|
215
|
+
],
|
|
216
|
+
":update-form": [
|
|
217
|
+
{
|
|
218
|
+
"el": "v-text-field", "w": 12,
|
|
219
|
+
"attr": { "v-model": "FunctionCode", "label": "Function Code", ":required": true }
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"el": "v-text-field", "w": 12,
|
|
223
|
+
"attr": { "v-model": "FunctionName", "label": "Function Name" }
|
|
224
|
+
}
|
|
225
|
+
],
|
|
226
|
+
":update-api": {
|
|
227
|
+
"new": {
|
|
228
|
+
"API": "/SM_Function_Insert",
|
|
229
|
+
"IN": { "ModuleID": "sModuleID", "FunctionCode": "item.FunctionCode", "FunctionName": "item.FunctionName" },
|
|
230
|
+
"CALLBACK": { "CALL": "getFunctionRight" }
|
|
231
|
+
},
|
|
232
|
+
"edit": {
|
|
233
|
+
"API": "/SM_Function_Update",
|
|
234
|
+
"IN": { "FunctionID": "item.FunctionID", "FunctionCode": "item.FunctionCode", "FunctionName": "item.FunctionName" },
|
|
235
|
+
"CALLBACK": { "CALL": "getFunctionRight" }
|
|
236
|
+
},
|
|
237
|
+
"delete": {
|
|
238
|
+
"CONFIRM": "Bạn có chắc muốn xóa quyền này không?",
|
|
239
|
+
"API": "/SM_Function_Delete",
|
|
240
|
+
"IN": { "FunctionID": "item.FunctionID" },
|
|
241
|
+
"CALLBACK": [
|
|
242
|
+
{ "MESS": "Xóa thành công" },
|
|
243
|
+
{ "CALL": "getFunctionRight" }
|
|
244
|
+
]
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**Khi nào dùng ctrl-update:** Khi form edit đơn giản (2-5 fields) và không cần layout phức tạp.
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## 7. f-table với show-select (Multi-select)
|
|
256
|
+
|
|
257
|
+
```json
|
|
258
|
+
{
|
|
259
|
+
"el": "f-table",
|
|
260
|
+
"attr": {
|
|
261
|
+
":show-select": true,
|
|
262
|
+
"v-model": "sUserSelected",
|
|
263
|
+
":items": "dsUsers",
|
|
264
|
+
"item-key": "UserID",
|
|
265
|
+
":items-per-page": -1,
|
|
266
|
+
":hide-default-footer": true,
|
|
267
|
+
":update-api": { "default-item": { "xAA": [] } },
|
|
268
|
+
":headers": [...]
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
- `v-model`: nhận array các item được chọn
|
|
274
|
+
- `:update-api.default-item`: inject default field vào mỗi item khi load (ở đây `xAA: []` cho chip-group)
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## 8. v-chip-group trong Table Cell
|
|
279
|
+
|
|
280
|
+
Hiển thị danh sách tags trong cell, click để mở dialog.
|
|
281
|
+
|
|
282
|
+
```json
|
|
283
|
+
{
|
|
284
|
+
"text": "FunctionRight",
|
|
285
|
+
"value": "FunctionName",
|
|
286
|
+
"el": "v-chip-group",
|
|
287
|
+
"attr": {
|
|
288
|
+
"v-model": "item.xAA",
|
|
289
|
+
"column": true,
|
|
290
|
+
"v-if": "item.FunctionName"
|
|
291
|
+
},
|
|
292
|
+
"innerHTML": [
|
|
293
|
+
{
|
|
294
|
+
"el": "v-chip",
|
|
295
|
+
"attr": {
|
|
296
|
+
":small": true,
|
|
297
|
+
"color": "primary",
|
|
298
|
+
"outlined": "",
|
|
299
|
+
"v-for": "fn in item.FunctionName",
|
|
300
|
+
":key": "fn",
|
|
301
|
+
"v-on:click": "vueData.dlFunction = true; CALL(setFunction(item, item.FunctionName));"
|
|
302
|
+
},
|
|
303
|
+
"innerHTML": "<div>{{fn.FunctionCode}}-{{fn.FunctionName}}</div>"
|
|
304
|
+
}
|
|
305
|
+
]
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Khi nào dùng `t-button` vs `t-menu`
|
|
312
|
+
|
|
313
|
+
- **`t-button`**: hành động duy nhất là xem/load dữ liệu liên quan → 1 click trực tiếp
|
|
314
|
+
- **`t-menu`**: có nhiều hành động **hoặc** hành động thay đổi trạng thái (Kích hoạt, Chốt điểm, Xóa...)
|
|
315
|
+
|
|
316
|
+
> Không bọc "Xem chi tiết" trong `t-menu` — thêm 1 click thừa. Dùng `t-button` thay. Xem thêm Master-Detail trong [ui-layout-patterns.md](ui-layout-patterns.md).
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# UI Templates — thư mục `examples/`
|
|
2
|
+
|
|
3
|
+
> File này sở hữu: **mô tả 4 file mẫu trong `examples/` và cách dùng lại chúng**. Quy tắc viết
|
|
4
|
+
> `controls`/action xem [controls-patterns.md](controls-patterns.md); pattern f-table chi tiết xem
|
|
5
|
+
> [component-table.md](component-table.md).
|
|
6
|
+
|
|
7
|
+
`examples/` chứa **file tham chiếu thật** — không phải template rỗng để copy nguyên khối. Đọc để lấy
|
|
8
|
+
đúng cú pháp/pattern cho tình huống đang làm, rồi viết lại theo nghiệp vụ thực tế.
|
|
9
|
+
|
|
10
|
+
## Các file có sẵn
|
|
11
|
+
|
|
12
|
+
| File | Dùng khi |
|
|
13
|
+
|---|---|
|
|
14
|
+
| `component.vue` | Custom Vue component mẫu (`uc-*`) — cấu trúc chuẩn `<template>` + `<script>`, không `name:`, không `components:{}`, không `<style>` |
|
|
15
|
+
| `module-patterns.json` | **Tham chiếu module hoàn chỉnh** — data/watch/controls kết hợp: menuChucNang, TypeLoad, addNew flag dialog, nested IF/THEN/ELSE, bulk action, openWindow+button+ctrlhotkey, `_.find`, pushRouter, f-menu inline, row-prop-object |
|
|
16
|
+
| `f-table-patterns.json` | **Tham chiếu f-table chuyên sâu** — tất cả props, mọi loại header (`t-check`/`t-select`/`t-button`/`t-link`/`t-menu`/`v-chip-group`/`v-icon`/divider), `ctrl-update` đầy đủ, f-table trong dialog, default-item-only |
|
|
17
|
+
| `project-patterns.json` | **Tham chiếu `project.json`** — cấu trúc đầy đủ project config: menuLeft/menu/menuStyle/menuComponent/domainSetting, `right` theo SystemRight+FunctionRight, quan hệ với `set` của module.json (override title/menu/apiDomain theo từng trang) |
|
|
18
|
+
|
|
19
|
+
## Cách dùng
|
|
20
|
+
|
|
21
|
+
1. Xác định tình huống → mở file tham chiếu tương ứng ở trên.
|
|
22
|
+
2. Lấy **đúng đoạn pattern cần dùng** (một action, một header, một khối dialog) — không copy cả file.
|
|
23
|
+
3. Thay API bằng endpoint thật, đổi tên field/label theo nghiệp vụ.
|
|
24
|
+
4. Ghép vào `data` / `controls` / `watch` sẵn có của module.
|
|
25
|
+
5. Chạy `module_validate` rồi `module_outline` trước khi publish.
|
|
26
|
+
|
|
27
|
+
**Không có filesystem access (SSE/remote)?** Đọc file mẫu qua `skill_reference_get`, sửa nội dung,
|
|
28
|
+
rồi stage bằng `module_stage_json` / `component_stage` trước khi gọi tool publish
|
|
29
|
+
(xem [tools-registry.md](tools-registry.md)).
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# FUI Definition-of-Done Checklists
|
|
2
|
+
|
|
3
|
+
> File này sở hữu: **checklist definition-of-done trước khi publish (module.json, `.vue`, SP, deploy workflow)** và **ma trận chọn tầng kiểm chứng theo triệu chứng**.
|
|
4
|
+
|
|
5
|
+
Use these checklists before publishing any artifact. Each item is a gate — a module/SP/component is not ready if any required item is unchecked.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Chọn tầng kiểm chứng theo TRIỆU CHỨNG (đọc trước khi render)
|
|
10
|
+
|
|
11
|
+
Năm tầng, chênh nhau khoảng **hai bậc** về chi phí mỗi lượt:
|
|
12
|
+
|
|
13
|
+
| Tầng | Lệnh | Chi phí | Thấy được gì |
|
|
14
|
+
|---|---|---|---|
|
|
15
|
+
| 1 | `module_validate` | tức thì, chỉ đọc file | lỗi quy tắc/tham chiếu tĩnh |
|
|
16
|
+
| 2 | `module_outline` | tức thì | cấu trúc layout, action mồ côi, dialog không ai mở |
|
|
17
|
+
| 3 | `module_simulate` | ~1 s | luồng chạy: action chain, watch, OUT gán gì |
|
|
18
|
+
| 4 | `component_preview` | browser, 1 component | lỗi của riêng một `uc-*.vue` |
|
|
19
|
+
| 5 | `module_simulate({renderUI:true})` | browser, ~10–30 s | **hình ảnh thật**: layout, chiều cao, style, responsive |
|
|
20
|
+
|
|
21
|
+
**Quy tắc:** đi từ tầng rẻ nhất **bắt được triệu chứng đó**, không mặc định leo thẳng lên tầng 5. Tầng 5 là tầng duy nhất thấy được hình ảnh, nhưng cũng là tầng duy nhất **không nói được vì sao** — nó chỉ chụp lại hậu quả.
|
|
22
|
+
|
|
23
|
+
| Triệu chứng | Tầng rẻ nhất bắt được | Vì sao |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| Trang trắng / app rỗng, **không** JS error, **không** `[Vue warn]` | **1** `module_validate` | dấu hiệu kinh điển của statement trong một `:attr` — Vue nuốt lỗi compile template, browser không có gì để báo |
|
|
26
|
+
| `[Vue warn] Property or method "x" is not defined` | **1** | biến dùng trong template chưa khai trong `data[]` |
|
|
27
|
+
| Nút bấm không làm gì | **1** (CALL target) → **3** (luồng thật) | |
|
|
28
|
+
| `Unknown custom element: <f-…>` / component trống | **1** | sai tên component, hoặc thiếu import bắt buộc |
|
|
29
|
+
| Chart không vẽ ra gì | **1** (thiếu `echarts.min.js`/`fechart.js`) → **5** (canvas 0-size) | thiếu import chiếm phần lớn số ca |
|
|
30
|
+
| Cột lệch, một hàng quá chật | **2** `module_outline` (Σw > 12) | |
|
|
31
|
+
| Dialog không mở được | **2** (`⚠ không thấy lệnh mở`) → **3** | |
|
|
32
|
+
| Action chạy sai thứ tự · watch lặp vô hạn · CONFIRM/MESS không đúng nhánh | **3** `module_simulate` | |
|
|
33
|
+
| Số liệu sai · `undefined`/`NaN` hiện trên trang | **3** | gần như luôn là `OUT`/mapData trỏ sai khoá, không phải lỗi hiển thị |
|
|
34
|
+
| API trả không đúng shape mong đợi | `db_sp_verify` (suy luận tĩnh, **không gọi endpoint nào**) | suy luận từ thân SP thật + sinh sẵn `apiMocks` cho tầng 3. Không phải "zero HTTP" nguyên văn: khi chưa có `.sql` local nó lấy `OBJECT_DEFINITION`, và `checkGrant: true` hỏi `sys.database_permissions` — cả hai là **đọc metadata**, không chạy SP |
|
|
35
|
+
| Một `uc-*.vue` hiển thị sai | **4** `component_preview` | chứng minh component đúng trước ⇒ mọi lỗi còn lại là lỗi lắp ráp |
|
|
36
|
+
| Bảng tràn ngang · chiều cao sai · style rò rỉ · khoảng cách xấu · vỡ ở mobile | **5** `renderUI` | không tầng nào khác thấy được hình học |
|
|
37
|
+
| Import/asset không nạp được | **5**, đọc section `⛔ MÔI TRƯỜNG THIẾU FILE` | lỗi của môi trường, **không** sửa module theo nó |
|
|
38
|
+
| Nghi "thư viện platform có bug" | **5**, kiểm section `⛔ ASSET CŨ` TRƯỚC khi kết luận | asset stale ⇒ đang chạy bản trên đĩa, mọi kết luận về CDN đều vô giá trị |
|
|
39
|
+
| Nút/menu **có gác quyền** không hiện với user thật (nhưng hiện trong preview) | **1** `module_validate` sau khi chạy `right_function_list` | mã quyền chưa được định nghĩa ⇒ `rightTest()` luôn false, không lỗi JS. Tầng 3/5 **cấp sẵn** đúng mã quét được nên chúng luôn hiện — xem [permission-system.md](permission-system.md) |
|
|
40
|
+
|
|
41
|
+
**Không kết luận về platform từ một lượt render có asset stale.** renderUI revalidate mọi asset mỗi lượt (conditional GET), nên bình thường bạn đang xem đúng bản CDN hiện tại — dòng trace ghi `N revalidate 304`. Nhưng nếu report có khối `⛔ ASSET CŨ, KHÔNG XÁC MINH ĐƯỢC` thì mạng hỏng và trang đang chạy bằng bản trên đĩa: câu "thư viện X có bug" rút ra từ lượt đó **không dùng được**. Nối mạng render lại, hoặc `refreshAssets: true` để ép tải mới. Dòng `ℹ️ ASSET PLATFORM ĐÃ ĐỔI` nghĩa là file nền tảng vừa đổi giữa hai lượt — hành vi đổi mà `module.json` không đụng tới thì tìm nguyên nhân ở đó trước.
|
|
42
|
+
|
|
43
|
+
**Đọc report renderUI đúng thứ tự:** khối `═══ CHẨN ĐOÁN ═══` ở đầu đã xếp mọi thứ hỏng vào ba nhóm theo **nơi phải sửa** — `[MÔI TRƯỜNG]` (sửa môi trường trước, lỗi hai nhóm dưới có thể chỉ là hệ quả) · `[MODULE]` (module.json/script.js/component) · `[HIỂN THỊ]` (DOM audit + ảnh). Dòng `↪` gợi ý tầng rẻ hơn lẽ ra bắt được triệu chứng đó.
|
|
44
|
+
|
|
45
|
+
**Dấu hiệu phải DỪNG render lại:** dòng `Δ so với lượt trước` báo *không chỉ số nào đổi*. Nghĩa là thay đổi vừa rồi không chạm tới lỗi đang có — render lại lần nữa với cùng hướng sửa chỉ tốn thêm một lượt. Quay xuống tầng 1–3 để biết **vì sao**, rồi mới lên lại tầng 5.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Module Checklist
|
|
50
|
+
|
|
51
|
+
### Structure
|
|
52
|
+
|
|
53
|
+
- [ ] `_moduleInfo.json` exists with `ModuleID`, `ModuleName`, `Framework`, `mTitle`, `HTMLOnly`
|
|
54
|
+
- [ ] `module.json` exists and is valid JSON (no trailing commas, no comments) — **validate trước khi ghi**: sau mỗi lần edit JSON dài, mentally check hoặc re-read để đảm bảo không có trailing comma sau element cuối cùng trong mảng/object
|
|
55
|
+
- [ ] If custom components are used: `components/_components.json` exists and lists all `uc-*.vue` files
|
|
56
|
+
- [ ] `imports/_imports.json` exists if module imports external JS/CSS
|
|
57
|
+
|
|
58
|
+
### module.json — Data
|
|
59
|
+
|
|
60
|
+
- [ ] All reactive state variables declared in `data[]` before being referenced in actions
|
|
61
|
+
- [ ] All named actions are reachable (at least one `CALL` or `watch` or button click references each)
|
|
62
|
+
- [ ] No hardcoded IDs — inputs reference `vueData.someVar` not literal numbers
|
|
63
|
+
- [ ] `OUT` keys match declared state variable names exactly (case-sensitive)
|
|
64
|
+
|
|
65
|
+
### module.json — Actions
|
|
66
|
+
|
|
67
|
+
- [ ] Every `API` action has both `IN` and `OUT` (or `CALLBACK`) defined
|
|
68
|
+
- [ ] Every delete action has `CONFIRM` before `API`
|
|
69
|
+
- [ ] Every mutating action has a `CALLBACK` that either reloads data or shows `MESS`
|
|
70
|
+
- [ ] Literal string values in `IN` use backtick prefix or single-quote wrap: `` "`winId" `` or `"'text'"`
|
|
71
|
+
- [ ] `IF/THEN/ELSE` branches all have matching action structures
|
|
72
|
+
- [ ] No raw `EXE` blocks that duplicate logic already expressible in actions
|
|
73
|
+
|
|
74
|
+
### module.json — Controls
|
|
75
|
+
|
|
76
|
+
- [ ] `controls` array starts with `{ "prop": "fluid grid-list-md", "rows": [...] }`
|
|
77
|
+
- [ ] Every item in `cols` has a `w` property
|
|
78
|
+
- [ ] Events use `v-on:click` not `@click`
|
|
79
|
+
- [ ] No `children` key — nesting uses `innerHTML` array
|
|
80
|
+
- [ ] Permission gates use `col: { "v-if": "vueData.user.SystemRight>=N" }` (not on `attr`)
|
|
81
|
+
- [ ] **Mọi mã `FunctionRight`/`SystemRight` đem gác đã TỒN TẠI thật** — đã chạy `right_function_list`/`right_system_list` (cũng là thứ tạo cache cho `module_validate` đối chiếu), mã chưa có thì `right_function_new`/`right_system_new` TRƯỚC. Mã bịa ra làm control biến mất im lặng và **preview vẫn hiện đúng** nên ảnh render không phát hiện được — xem [permission-system.md](permission-system.md)
|
|
82
|
+
- [ ] All `v-if` expressions include `vueData.` prefix where referencing state
|
|
83
|
+
- [ ] Dialog containers use `el: "hidden-container"` — one per dialog
|
|
84
|
+
|
|
85
|
+
### module.json — Watch
|
|
86
|
+
|
|
87
|
+
- [ ] Watch keys reference declared state variables
|
|
88
|
+
- [ ] `deep-watch` used for nested object/array observation
|
|
89
|
+
- [ ] No watch entry calls an action that also triggers the same watch (infinite loop risk)
|
|
90
|
+
|
|
91
|
+
### UI Quality
|
|
92
|
+
|
|
93
|
+
- [ ] Vuetify classes/props used before inline `style` (đúng version của project: FUI V2 = Vuetify 1.5, FUI V3 = Vuetify 3)
|
|
94
|
+
- [ ] `f-*` components chosen over raw `v-*` when FUI equivalent exists
|
|
95
|
+
- [ ] Tables use `f-table` (not `v-data-table`) — cả CRUD lẫn read-only (read-only = không khai `:update-api`)
|
|
96
|
+
- [ ] Tổng cột dùng `sum-format` (object → hàng tổng trong bảng; string → dòng text dưới bảng) — không tự dựng hàng tổng thủ công
|
|
97
|
+
- [ ] Charts dùng **`f-echart`** — không dùng `v-chart`, `<canvas>`, hay lib khác
|
|
98
|
+
- [ ] Chart tuân thủ **Quy ước hiển thị mặc định** trong components-echart.md
|
|
99
|
+
- [ ] Date/time fields use `f-date`/`f-time` (not `v-text-field` + manual parsing)
|
|
100
|
+
|
|
101
|
+
### Import JS/CSS
|
|
102
|
+
|
|
103
|
+
- [ ] Với mỗi component có import (xem bảng trong `component-quickref.md`): đã gọi `file_import_list` để kiểm tra — import đang có hay chưa
|
|
104
|
+
- [ ] Nếu thêm component cần import và chưa có → `file_import_new` cho từng file thiếu
|
|
105
|
+
- [ ] Nếu bỏ component có import → kiểm tra import đó còn dùng ở component/module khác không; nếu không còn → `file_import_delete`
|
|
106
|
+
- [ ] **Nếu có `f-echart`**: cả hai import phải có và đúng thứ tự — `echarts.min.js` trước, `fechart.js` sau:
|
|
107
|
+
- `/include/chart/echarts.min.js`
|
|
108
|
+
- `/include/chart/fechart.js`
|
|
109
|
+
|
|
110
|
+
### Validate trước khi publish
|
|
111
|
+
|
|
112
|
+
- [ ] Module mới có cả UI lẫn API: đã dựng UI bằng dữ liệu cứng trong `data[]` + `module_simulate({ renderUI: true })` QA hình ảnh TRƯỚC khi chốt contract API và viết SP — xem quy trình đầy đủ ở [fullstack-workflow.md](fullstack-workflow.md)
|
|
113
|
+
- [ ] Chạy `module_validate` sau khi sửa `module.json` — sửa hết **error** (CALL target không tồn tại, `@`/`#` shorthand, `children`, grid structure sai...)
|
|
114
|
+
- [ ] Warning được review từng cái — có thể là chủ ý (component chưa có trong list, param optional...), nhưng không được bỏ qua mà không đọc
|
|
115
|
+
- [ ] Warning nhóm **`[design]`** (toolbar dialog có màu, nút xóa màu đỏ, width dialog lạ, form không floating label, delete thiếu CONFIRM, nút Đóng thừa, tự dựng v-snackbar/v-alert thay vì MESS/MESSBOX, f-table/f-sheet bảng chính thiếu `":height": -16` nên cả trang cuộn thay vì cuộn trong bảng...) = vi phạm chuẩn thẩm mỹ mặc định — **phải sửa**, trừ khi chính user đã yêu cầu rõ kiểu khác trong phiên này
|
|
116
|
+
- [ ] Strict mode (`FUI_MCP_STRICT=1`): error sẽ CHẶN publish — không thể bỏ qua
|
|
117
|
+
- [ ] Chạy `module_outline` và ĐỌC cây layout để tự review cấu trúc UI: mỗi row có Σw hợp lý (≤12)? dialog nào có `⚠ không thấy lệnh mở`? action nào có `⚠ không thấy nơi gọi`? state nào `⚠ không thấy dùng`?
|
|
118
|
+
- [ ] Với module có logic runtime phức tạp (action chain, watch cascade, dialog flow): chạy `module_simulate` với kịch bản luồng chính + `apiMocks` (shape lấy từ snippet do `db_sp_verify` sinh sẵn) + assert điều kiện then chốt — sửa mọi `⚠` và assert ✘ trong trace trước khi publish. **Lưu ý**: `apiMocks` bạn truyền luôn thắng, nhưng một API tĩnh KHÔNG có mock mà SP đích đã xác nhận chỉ đọc (`db_sp_verify`/đã có `.sql` local) sẽ tự động được gọi thật (giới hạn 8 lượt/lần, có cache `_testdata/`) thay vì rơi thẳng `{data:[]}` — đọc dòng "Live/Cache data" trong report để biết SP nào lấy từ đâu; SP có lệnh ghi thì không bao giờ bị gọi thật
|
|
119
|
+
- [ ] **`apiMocks` của SP đã tồn tại phải đến từ `db_sp_verify`, không tự đoán** — thấy `module_simulate` trả cảnh báo `🚨 CẤU TRÚC MOCK CHƯA ĐƯỢC KIỂM CHỨNG` thì dừng, chạy `db_sp_verify` rồi copy nguyên văn snippet nó sinh ra, không tự sửa tay rồi bỏ qua. Bịa cấu trúc chỉ hợp lệ cho SP thật sự chưa tồn tại (chưa deploy)
|
|
120
|
+
- [ ] **QA hiển thị cuối cùng (khi có Playwright)**: chạy `module_simulate({ renderUI: true, vueData: {..demo data..}, apiMocks: {...} })` — render browser thật, ĐỌC screenshot trả về (luôn có ảnh inline — PNG quá lớn tự nén JPEG) + DOM audit (app rỗng? tràn ngang? text "undefined"/"NaN"? ảnh vỡ? canvas chart 0-size?) + JS error/`[Vue warn]` + state cuối vueData — tự fix lỗi hiển thị rồi render lại cho tới khi sạch. **Có section `⛔ MÔI TRƯỜNG THIẾU FILE` thì đọc nó TRƯỚC**: import/asset chưa nạp được là lỗi môi trường (chạy lệnh nó gợi ý — `project_sync`/`module_get`), các lỗi JS/hiển thị bên dưới có thể chỉ là hệ quả — đừng sửa module.json theo chúng — cách ĐỌC ảnh có hệ thống: xem `ui-screenshot-review.md`. Chart/animation render thiếu trong ảnh → tăng `settleMs` (vd 1500). Dialog đang mở được chụp riêng `render-dialog.jpg`. Module có dùng trên mobile → render thêm lượt `device: "mobile"`. Không có Playwright → bỏ qua bước này (tool sẽ trả hướng dẫn cài)
|
|
121
|
+
- [ ] **Vừa sửa cả cấp project lẫn cấp module** (component project, import project, `project.json`/menu): publish phần **cấp project** TRƯỚC rồi mới render — renderUI lấy `$projectData` + component project + CSS project từ server (`_aset`), nên bản project chưa publish sẽ không xuất hiện trong ảnh; ngược lại phần cấp module dựng cục bộ, cứ sửa-render-sửa thoải mái rồi publish sau. Riêng **component cấp project** thì không còn là lời nhắc: renderUI đối chiếu từng `uc-*.vue` local với bundle server và **chặn cứng** (không có cờ bỏ qua) nếu lệch — kiểm chứng bản local bằng `component_preview`, rồi `component_new`/`component_update`, rồi mới render. Bị chặn vì bản server mới hơn (ai đó sửa trên web IDE) → `project_sync`, đừng push đè
|
|
122
|
+
|
|
123
|
+
### Publish Workflow — Smart (sửa cái nào, up cái đó)
|
|
124
|
+
|
|
125
|
+
Không phải lúc nào cũng dùng `module_publish_html`. Chọn tool theo phần đã thay đổi:
|
|
126
|
+
|
|
127
|
+
- [ ] Chỉ sửa `module.json` → dùng `module_publish_json` (không cần preview/approval)
|
|
128
|
+
- [ ] Sửa `header.html` / `body.html` / title → `module_preview` → user approve → `module_publish_html` (đã kèm module.json, không cần gọi thêm `module_publish_json`)
|
|
129
|
+
- [ ] Sửa `script.js` (kể cả làm rỗng) → `module_publish_script` — **⚠️ `module_publish_html` không clear script rỗng trên server**
|
|
130
|
+
- [ ] Sửa `uc-*.vue` → `component_new` (lần đẩy đầu tiên) hoặc `component_update` (các lần sau), per file — `component_update` lỗi cứng nếu component chưa có trên server, không âm thầm tạo
|
|
131
|
+
- [ ] Nhiều phần → gọi tool tương ứng cho từng phần, lần lượt
|
|
132
|
+
|
|
133
|
+
Khi dùng `module_publish_html`:
|
|
134
|
+
- [ ] `module_preview` đã chạy và diff đã được review
|
|
135
|
+
- [ ] User đã xác nhận rõ ràng
|
|
136
|
+
- [ ] Có approval token từ `module_preview`
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Stored Procedure Checklist
|
|
141
|
+
|
|
142
|
+
### Naming
|
|
143
|
+
|
|
144
|
+
- [ ] Prefix is `spAPI_` (e.g., `spAPI_ContractList`, `spAPI_ContractInsert`)
|
|
145
|
+
- [ ] Name follows pattern: `spAPI_{Entity}{Action}` where Action is `List`/`Select`/`Insert`/`Update`/`Delete`/`Save`
|
|
146
|
+
- [ ] No spaces, no lowercase prefix (`sp_`, `SP_`, etc.)
|
|
147
|
+
|
|
148
|
+
### Parameters
|
|
149
|
+
|
|
150
|
+
- [ ] `@sys_UserID int` present in all write operations (INSERT/UPDATE/DELETE)
|
|
151
|
+
- [ ] `@sys_SystemRight int` present when permission check is needed
|
|
152
|
+
- [ ] Input parameters declared before system parameters
|
|
153
|
+
- [ ] No unused parameters
|
|
154
|
+
|
|
155
|
+
### Security
|
|
156
|
+
|
|
157
|
+
- [ ] Permission check at top: `IF @sys_SystemRight < N BEGIN RAISERROR(N'[Unauthorized]Bạn không có quyền...', 16, 1) RETURN END` — severity luôn là `16`, prefix `[Unauthorized]` bắt buộc trên lỗi thiếu quyền để tAPI trả HTTP 401 (xem [tapi-reference.md](tapi-reference.md) §5)
|
|
158
|
+
- [ ] No direct string concatenation for SQL (use parameterized queries)
|
|
159
|
+
- [ ] File `.sql` **KHÔNG chứa `GRANT EXECUTE`** — thân `CREATE PROCEDURE` kéo dài tới hết batch, mà tAPI gửi một batch và không hỗ trợ `GO`, nên câu GRANT viết sau `END` bị **nuốt vào thân SP**: nó chạy mỗi lần gọi SP chứ không cấp quyền lúc deploy, và không có lỗi nào nổi lên. `db_sp_deploy` tự cấp quyền cho procedure mới rồi **hỏi lại `sys.database_permissions` để xác nhận**
|
|
160
|
+
- [ ] Kết quả `db_sp_deploy` báo `✓ [public] đã có quyền EXECUTE` — nếu thấy `❗` thì chạy đúng câu GRANT nó in ra (**đừng deploy lại**, SP đã lên server rồi). Deploy SP qua `db_sql_execute_nonquery` thì không có auto-grant; tool cảnh báo và nêu lệnh cần chạy. Nghi ngờ về sau: `db_sp_verify({ name, checkGrant: true })`
|
|
161
|
+
|
|
162
|
+
### Logic
|
|
163
|
+
|
|
164
|
+
- [ ] SP returns exactly what FUI `OUT` expects (column names match exactly)
|
|
165
|
+
- [ ] Error conditions use `RAISERROR(N'...', 16, 1)` followed by `RETURN` (not silent failures)
|
|
166
|
+
- [ ] Transactions used for multi-step writes
|
|
167
|
+
- [ ] SP logic reviewed statically (read the body, reason about branches/edge cases) before deploy — never smoke-tested against the live endpoint
|
|
168
|
+
|
|
169
|
+
### Deploy Workflow
|
|
170
|
+
|
|
171
|
+
- [ ] `db_sp_save` called first (save to local, no DB change)
|
|
172
|
+
- [ ] Full SP body reviewed in local file before deploy
|
|
173
|
+
- [ ] Summary presented to user: SP name, operation type (CREATE/ALTER), affected tables
|
|
174
|
+
- [ ] User has explicitly confirmed before `db_sp_deploy`
|
|
175
|
+
- [ ] Sau deploy bất kỳ API nào (đọc hay ghi) sắp wire vào module.json → `db_sp_verify` một lần: suy luận tĩnh response shape/contract lỗi từ thân SP thật, đối chiếu params — **không gọi endpoint nào**. (Không phải "zero HTTP" nguyên văn: chưa có `.sql` local thì nó lấy `OBJECT_DEFINITION`, `checkGrant: true` thì hỏi `sys.database_permissions` — cả hai là *đọc metadata*, không chạy SP)
|
|
176
|
+
- [ ] API **ghi** (Insert/Update/Delete) → kiểm tra tính đúng bằng cách đọc thân SP (`db_sp_get`/`db_sp_verify`) và suy luận logic tĩnh (WHERE, transaction, RAISERROR); test luồng UI gọi API ghi bằng `module_simulate({ apiMocks: {...} })` với dữ liệu giả (snippet có sẵn từ `db_sp_verify`), không gọi API thật
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Vue Component Checklist (`uc-*.vue`)
|
|
181
|
+
|
|
182
|
+
### File
|
|
183
|
+
|
|
184
|
+
- [ ] Filename starts with `uc-` prefix
|
|
185
|
+
- [ ] Registered in `_components.json`
|
|
186
|
+
- [ ] `<style scoped>` block (nếu có): mọi selector đã tự tiền tố bằng class định danh của component — `scoped` KHÔNG scope thật (server chỉ nối text `ComCSS`), selector trần sẽ leak sang component khác. Xem [component-design.md](component-design.md)
|
|
187
|
+
- [ ] No backtick template strings inside `<template>`
|
|
188
|
+
|
|
189
|
+
### API Design
|
|
190
|
+
|
|
191
|
+
- [ ] All inputs declared as `props` with types
|
|
192
|
+
- [ ] Component emits events upward (`input`, `change`, `select`, `action`) rather than mutating parent state
|
|
193
|
+
- [ ] Props use neutral names (`items`, `value`, `label`) not screen-specific names
|
|
194
|
+
- [ ] Loading, empty, and error states handled (prop or slot)
|
|
195
|
+
|
|
196
|
+
### Behavior
|
|
197
|
+
|
|
198
|
+
- [ ] Component does not fetch data directly unless it is explicitly a data-owning component
|
|
199
|
+
- [ ] No hardcoded route/module paths inside the component
|
|
200
|
+
- [ ] No permission logic inside component — permission gating stays in `module.json`
|
|
201
|
+
|
|
202
|
+
### Kiểm chứng trong không gian riêng (trước khi ráp vào module / trước khi push)
|
|
203
|
+
|
|
204
|
+
- [ ] Đã chạy `component_preview` với **ít nhất 2 case**: một case dữ liệu bình thường và một case biên (danh sách rỗng / chuỗi rất dài / thiếu trường) — component sai ở case biên là lỗi hay gặp nhất
|
|
205
|
+
- [ ] Đã ĐỌC ảnh chụp của **cả desktop lẫn mobile** (mặc định tool render cả hai): không tràn ngang, không vỡ layout ở 390px, không text "undefined"/"NaN"
|
|
206
|
+
- [ ] Không còn JS error / `[Vue warn]` trong report
|
|
207
|
+
- [ ] Component có tương tác → `scenario` với `click`/`set` + `assert` đã chạy đúng (dùng `nth`, không `item`/`index`)
|
|
208
|
+
- [ ] Component tự đo chiều cao (chart, table) → thử thêm `viewport` chiều cao thấp
|
|
209
|
+
- [ ] **Component cấp project**: đã push (`component_new` lần đầu / `component_update` các lần sau) NGAY SAU khi preview sạch — renderUI của module sẽ chặn cứng nếu bản local còn lệch bản server
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Import File Checklist
|
|
214
|
+
|
|
215
|
+
- [ ] File type matches declared `ContentType` (`.js` → `application/javascript`, `.css` → `text/css`)
|
|
216
|
+
- [ ] `sort` >= 40 khi thêm import mới — giá trị 1–39 dành cho hệ thống, không dùng
|
|
217
|
+
- [ ] Content tested locally before `file_import_upload_content`
|
|
218
|
+
- [ ] No sensitive data (tokens, passwords) in JS/CSS import files
|
|
219
|
+
- [ ] If updating an existing file: `file_import_get` called first to review current content
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Debug Workflow — Sau khi publish có lỗi
|
|
224
|
+
|
|
225
|
+
Khi server báo lỗi hoặc trang hiển thị sai sau khi publish:
|
|
226
|
+
|
|
227
|
+
1. **Review file vừa sửa trước tiên** — đọc lại toàn bộ file đã chỉnh sửa trong lần publish đó, không nhảy sang nguyên nhân khác
|
|
228
|
+
2. Nếu file trông đúng: chạy `module_preview` để xem diff — kiểm tra server đang lưu gì so với local
|
|
229
|
+
3. Nếu preview báo `Controls: 0` / `Data keys: 0`: đó là server đang giữ bản cũ bị lỗi, không phải local — push lại để ghi đè
|
|
230
|
+
4. Chỉ khi local file đã xác nhận đúng mà lỗi vẫn còn: mới kiểm tra các file khác (header.html, script.js, imports)
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Quick Risk Gate
|
|
235
|
+
|
|
236
|
+
Before any mutating tool call, answer:
|
|
237
|
+
|
|
238
|
+
| Question | If NO → |
|
|
239
|
+
|---|---|
|
|
240
|
+
| Is this a ReadOnly tool? | Confirm intent with user |
|
|
241
|
+
| Have I shown the user a summary? | Show summary first, then wait |
|
|
242
|
+
| Is this a 🔴 Destructive tool? | Require explicit user confirmation |
|
|
243
|
+
| For `module_publish_html`: do I have an approval token? | Run `module_preview` first |
|
|
244
|
+
| For `db_sp_deploy`: has user seen the SP body? | Show SP body, wait for OK |
|
|
245
|
+
|
|
246
|
+
See [tools-registry.md](tools-registry.md) for the full per-tool classification.
|