@fui-org/fui-cli 0.2.0 → 0.4.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 +20 -2
- package/dist/fui.js +347 -44
- package/package.json +15 -3
- package/skills/fui/SKILL.md +149 -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,532 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1
|
|
3
|
+
name: FUI-design-system
|
|
4
|
+
description: "FUI design system dựa trên Vuetify 2 + Material Design 2, rút ra từ codebase thực tế. Light mode, enterprise admin. Primary blue (#1976D2) dành cho action chính. Input fields dùng outlined+dense+hide-details theo defaultControlAttr (FUI runtime tự apply — không cần viết lại trong module.json). Icon giữ kích thước mặc định, không tự thêm small/:small. Các control khác loại/khác chiều cao trong cùng một hàng phải được kiểm tra và canh giữa theo chiều dọc bằng align-center; không bù bằng margin thủ công. Dialog: dựng v-dialog thủ công theo anatomy chuẩn mô phỏng phong cách f-dialog (toolbar dense+flat không color, close icon; hàng cuối là v-card-actions căn phải, button rộng tự nhiên; tối đa một action chính có nền, action phụ là text). Form dùng floating label — KHÔNG dùng label div rời. Card trong dialog không dùng elevation hay outlined — dùng class pa-0. f-button mặc định elevation:0, color:primary, checkvalid:false."
|
|
5
|
+
|
|
6
|
+
colors:
|
|
7
|
+
primary: "#1976D2"
|
|
8
|
+
primary-text: "primary--text"
|
|
9
|
+
warning: "#FB8C00"
|
|
10
|
+
success: "#4CAF50"
|
|
11
|
+
error: "#FF5252"
|
|
12
|
+
action-main: "primary"
|
|
13
|
+
action-delete: "warning"
|
|
14
|
+
action-positive: "success"
|
|
15
|
+
action-register: "green"
|
|
16
|
+
conditional: "(condition ? 'red' : 'primary')"
|
|
17
|
+
|
|
18
|
+
icons:
|
|
19
|
+
save: "mdi-content-save"
|
|
20
|
+
delete: "mdi-delete"
|
|
21
|
+
search: "mdi-magnify"
|
|
22
|
+
close: "mdi-close"
|
|
23
|
+
add-user: "mdi-account-multiple-plus"
|
|
24
|
+
remove-user: "mdi-account-multiple-minus"
|
|
25
|
+
edit: "mdi-pencil"
|
|
26
|
+
filter: "mdi-filter"
|
|
27
|
+
refresh: "mdi-refresh"
|
|
28
|
+
upload: "mdi-cloud-upload-outline"
|
|
29
|
+
download: "mdi-download"
|
|
30
|
+
print: "mdi-printer"
|
|
31
|
+
settings: "mdi-cog"
|
|
32
|
+
eye: "mdi-eye"
|
|
33
|
+
lock: "mdi-lock"
|
|
34
|
+
check: "mdi-check-bold"
|
|
35
|
+
|
|
36
|
+
layout:
|
|
37
|
+
main-container: "grid-list-md fluid"
|
|
38
|
+
dialog-container: "hidden-container"
|
|
39
|
+
centered-narrow: "grid-list-md mw-1000"
|
|
40
|
+
page-with-nav: "page-container grid-list-md fluid"
|
|
41
|
+
dialog-inner: "grid-list-md px-4"
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
# FUI Design System
|
|
45
|
+
|
|
46
|
+
Tài liệu này mô tả cách viết UI chuẩn cho FUI modules. Tất cả patterns rút từ codebase thực tế, không phải lý thuyết.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 1. Defaults do FUI Runtime tự apply (không cần viết trong module.json)
|
|
51
|
+
|
|
52
|
+
`defaultControlAttr` trong FUI runtime tự inject các attr sau khi render. **Không cần** viết lại trong module.json:
|
|
53
|
+
|
|
54
|
+
| Component | Defaults tự inject |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `v-text-field` | `outlined, dense, hide-details, required:true` |
|
|
57
|
+
| `v-textarea` | `outlined, dense` |
|
|
58
|
+
| `v-select` | `outlined, dense, hide-details, required:true, menu-props:{offsetY:true}` |
|
|
59
|
+
| `v-combobox` | `outlined, dense, hide-details, required:true, menu-props:{offsetY:true}` |
|
|
60
|
+
| `v-autocomplete` | `outlined, dense, hide-details, auto-select-first:true` |
|
|
61
|
+
| `v-checkbox` | `class:mt-1, hide-details` |
|
|
62
|
+
| `v-switch` | `dense, hide-details, class:my-1 mx-0` |
|
|
63
|
+
| `v-card` | `outlined:true` |
|
|
64
|
+
| `v-btn` | `elevation:0` |
|
|
65
|
+
| `f-button` | `elevation:0, color:primary` |
|
|
66
|
+
| `f-table` | `dense, fixed-header, hide-default-footer, show-search, items-per-page:50` |
|
|
67
|
+
| `f-dialog` | `outlined, dense` |
|
|
68
|
+
| `f-date` | `outlined, dense, hide-details, picker.locale:vi` |
|
|
69
|
+
| `f-time` | `outlined, dense, hide-details` |
|
|
70
|
+
| `f-search` | `outlined, dense, hide-details, auto-select-first:true` |
|
|
71
|
+
|
|
72
|
+
**Hệ quả thực tế:** Khi viết module.json, một input field chỉ cần:
|
|
73
|
+
```json
|
|
74
|
+
{ "el": "v-text-field", "attr": { "v-model": "vueData.form.Name", "label": "Họ và tên" }, "w": 12 }
|
|
75
|
+
```
|
|
76
|
+
Không cần thêm `outlined`, `dense`, `hide-details` — runtime tự thêm.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 2. Colors — Quy tắc dùng màu
|
|
81
|
+
|
|
82
|
+
| Màu | Khi nào dùng |
|
|
83
|
+
|---|---|
|
|
84
|
+
| `primary` | Mọi action chính: Save, Add, Search, View, mở dialog |
|
|
85
|
+
| `warning` | Delete, Permission denied, Remove — destructive nhưng không nguy hiểm cao |
|
|
86
|
+
| `success` | Action positive không xóa dữ liệu: Update permission, Scan |
|
|
87
|
+
| `green` | Đăng ký, Register — dùng với `:outlined:true` |
|
|
88
|
+
| conditional | `"(vueData.item.Active == 0 ? 'red' : 'primary')"` — trạng thái toggle |
|
|
89
|
+
|
|
90
|
+
**Rule cốt lõi:** Chỉ một màu accent trên một màn hình. Không mix nhiều màu cùng cấp.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 3. Toolbar — Chỉ dùng trong dialog
|
|
95
|
+
|
|
96
|
+
Toolbar trong FUI module **không bao giờ có** `color` hay `dark`. Pattern chuẩn bên trong `v-card`:
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"el": "v-toolbar",
|
|
101
|
+
"attr": { "dense": "", "flat": "" },
|
|
102
|
+
"innerHTML": [
|
|
103
|
+
{ "el": "v-toolbar-title", "innerHTML": "Tên Dialog" },
|
|
104
|
+
{ "el": "v-spacer" },
|
|
105
|
+
{
|
|
106
|
+
"el": "v-btn",
|
|
107
|
+
"attr": { "icon": "", "v-on:click": "vueData.dlTen = false" },
|
|
108
|
+
"innerHTML": [{ "el": "v-icon", "innerHTML": "mdi-close" }]
|
|
109
|
+
}
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Không dùng:** `color="primary"`, `dark`, `elevation`, `tile` trên toolbar trong dialog.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 4. Dialog — Cấu trúc chuẩn (v-dialog thủ công, phong cách f-dialog)
|
|
119
|
+
|
|
120
|
+
**Quy tắc gốc:** Dialog dựng bằng `v-dialog` thủ công (AI dễ đọc/chỉnh sửa từng phần), nhưng **diện mạo phải mô phỏng đúng `f-dialog`** của runtime: toolbar `dense flat` không màu + close icon, thân form floating label, hàng cuối là `v-card-actions` căn phải. Button giữ chiều ngang tự nhiên; tối đa một action chính được tô nền, các action phụ dùng **text style**. Component `f-dialog` vẫn hợp lệ cho form rất nhỏ, nhưng chuẩn mặc định là anatomy dưới đây.
|
|
121
|
+
|
|
122
|
+
Dialog luôn nằm trong `hidden-container`. Cấu trúc đầy đủ:
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"prop": "hidden-container",
|
|
127
|
+
"rows": [
|
|
128
|
+
{
|
|
129
|
+
"prop": "",
|
|
130
|
+
"cols": [
|
|
131
|
+
{
|
|
132
|
+
"el": "v-dialog",
|
|
133
|
+
"col": {},
|
|
134
|
+
"attr": { "v-model": "vueData.dlTen", "width": 650 },
|
|
135
|
+
"innerHTML": [
|
|
136
|
+
{
|
|
137
|
+
"el": "v-card",
|
|
138
|
+
"attr": { "class": "pa-0" },
|
|
139
|
+
"innerHTML": [
|
|
140
|
+
{
|
|
141
|
+
"el": "v-toolbar",
|
|
142
|
+
"attr": { "dense": "", "flat": "" },
|
|
143
|
+
"innerHTML": [
|
|
144
|
+
{ "el": "v-toolbar-title", "innerHTML": "Tiêu đề" },
|
|
145
|
+
{ "el": "v-spacer" },
|
|
146
|
+
{ "el": "v-btn", "attr": { "icon": "", "v-on:click": "vueData.dlTen = false" },
|
|
147
|
+
"innerHTML": [{ "el": "v-icon", "innerHTML": "mdi-close" }] }
|
|
148
|
+
]
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"el": "v-container",
|
|
152
|
+
"attr": { "class": "grid-list-md px-4" },
|
|
153
|
+
"innerHTML": [
|
|
154
|
+
{
|
|
155
|
+
"el": "v-layout",
|
|
156
|
+
"w": 12,
|
|
157
|
+
"attr": { "row": "", "wrap": "" },
|
|
158
|
+
"innerHTML": [
|
|
159
|
+
{ "el": "v-text-field", "col": {}, "attr": { "v-model": "vueData.form.FullName", "label": "Họ và tên" }, "w": 12 },
|
|
160
|
+
{ "el": "v-text-field", "col": {}, "attr": { "v-model": "vueData.form.Phone", "label": "Điện thoại" }, "w": 6 },
|
|
161
|
+
{ "el": "v-select", "col": {}, "attr": { "v-model": "vueData.form.DeptID", "label": "Phòng ban",
|
|
162
|
+
":items": "vueData.deptList", "item-text": "DeptName", "item-value": "DeptID" }, "w": 6 }
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
]
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"el": "v-card-actions",
|
|
169
|
+
"attr": { "class": "mr-1 mb-1" },
|
|
170
|
+
"innerHTML": [
|
|
171
|
+
{ "el": "v-spacer" },
|
|
172
|
+
{ "el": "f-button", "attr": { "text": "", "label": "Đặt lại", ":action": { "CALL": "resetForm" } } },
|
|
173
|
+
{ "el": "f-button", "attr": { "color": "primary", "label": "Lưu", "icon-text": "mdi-content-save",
|
|
174
|
+
":checkvalid": false, "action": { "API": "...", "IN": {}, "CALLBACK": {} } } }
|
|
175
|
+
]
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
}
|
|
181
|
+
]
|
|
182
|
+
}
|
|
183
|
+
]
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Anatomy bắt buộc (đúng phong cách f-dialog):**
|
|
188
|
+
| Phần | Quy tắc |
|
|
189
|
+
|---|---|
|
|
190
|
+
| `v-card` | `class="pa-0"` — triệt đệm để toolbar tiêu đề tràn sát mép dialog (spacing của form đã do `v-container px-4` lo); không elevation/outlined vì v-dialog đã tự có bóng đổ. Ưu tiên class Vuetify thay vì `style="padding: 0px;"` |
|
|
191
|
+
| `v-toolbar` | `dense flat` — **không** color/dark; title + `v-spacer` + `v-btn[icon]` mdi-close |
|
|
192
|
+
| Thân | `v-container.grid-list-md.px-4` > `v-layout[row wrap]` > field floating label (xem §5) |
|
|
193
|
+
| `v-card-actions` | Là **hàng cuối** của dialog; `class="mr-1 mb-1"`; `v-spacer` trước nhóm nút → các nút dồn phải |
|
|
194
|
+
| Chiều ngang nút | Theo nội dung tự nhiên; không đặt `w`, `width`, `block`, `flex-grow`, không bọc nút trong cột giãn |
|
|
195
|
+
| Nút hành động chính | Tối đa một nút (ví dụ **Lưu**) dùng `color="primary"`; có thể có icon trái nhưng không tự thu nhỏ icon |
|
|
196
|
+
| Nút hành động phụ | `f-button` kèm `"text": ""`; không tô nền cho action ít quan trọng, giữ nhãn ngắn và số lượng tối thiểu |
|
|
197
|
+
| Nút đóng phụ | Chỉ dùng close icon trên toolbar; không thêm nút "Đóng" ở actions trừ khi user yêu cầu |
|
|
198
|
+
|
|
199
|
+
**Width conventions:**
|
|
200
|
+
| Width | Dùng cho |
|
|
201
|
+
|---|---|
|
|
202
|
+
| 400 | Dialog nhỏ: confirm, function right, module select |
|
|
203
|
+
| 550 | Dialog trung bình: department update |
|
|
204
|
+
| 600 | Add right, department |
|
|
205
|
+
| 650 | Form user info chuẩn |
|
|
206
|
+
| 800 | Dialog lớn có table bên trong |
|
|
207
|
+
|
|
208
|
+
**Không dùng:** `persistent`, `fullscreen`, `scrollable`, `transition` trừ khi có lý do cụ thể.
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## 5. Form Layout bên trong Dialog — floating label
|
|
213
|
+
|
|
214
|
+
**Chuẩn duy nhất: floating label của Vuetify** — mỗi field tự mang `label` trong `attr`. **KHÔNG dùng** pattern label `div` rời bên trái (kiểu w:3 + w:9) — pattern đó đã bị loại bỏ.
|
|
215
|
+
|
|
216
|
+
```json
|
|
217
|
+
{ "el": "v-layout", "w": 12, "attr": { "row": "", "wrap": "" }, "innerHTML": [
|
|
218
|
+
{ "el": "v-text-field", "col": {}, "attr": { "v-model": "vueData.form.FullName", "label": "Họ và tên" }, "w": 12 },
|
|
219
|
+
{ "el": "v-text-field", "col": {}, "attr": { "v-model": "vueData.form.Phone", "label": "Điện thoại" }, "w": 6 },
|
|
220
|
+
{ "el": "v-select", "col": {}, "attr": { "v-model": "vueData.form.DeptID", "label": "Phòng ban",
|
|
221
|
+
":items": "vueData.deptList", "item-text": "DeptName", "item-value": "DeptID" }, "w": 6 },
|
|
222
|
+
{ "el": "v-textarea", "col": {}, "attr": { "v-model": "vueData.form.Note", "label": "Ghi chú" }, "w": 12 }
|
|
223
|
+
]}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Quy tắc chia cột form:**
|
|
227
|
+
- Field dài (họ tên, địa chỉ, ghi chú, textarea) → `w: 12`
|
|
228
|
+
- Field ngắn đi theo cặp → `w: 6` + `w: 6` (hoặc `4+4+4` khi 3 field ngắn)
|
|
229
|
+
- Field optional → thêm `":required": false` (runtime mặc định inject `required: true`)
|
|
230
|
+
- **KHÔNG** thêm class căn chỉnh (`mt-2`, `ml-2`, `flex-md-grow-0`) — floating label tự thẳng hàng trong grid
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## 6. Toolbar chính của màn hình (row filter + buttons)
|
|
235
|
+
|
|
236
|
+
Row đầu tiên của màn hình thường chứa filter + action buttons. Vì các control này thường khác chiều
|
|
237
|
+
cao, row phải dùng `align-center` để cùng trục giữa theo chiều dọc:
|
|
238
|
+
|
|
239
|
+
```json
|
|
240
|
+
{
|
|
241
|
+
"prop": "row wrap align-center",
|
|
242
|
+
"cols": [
|
|
243
|
+
{
|
|
244
|
+
"el": "v-autocomplete",
|
|
245
|
+
"col": { "class": "shrink" },
|
|
246
|
+
"attr": { "class": "flex-md-grow-0 my-2", "v-model": "vueData.sFilter",
|
|
247
|
+
"label": "Lọc theo...", ":items": "vueData.dsList",
|
|
248
|
+
"item-text": "Name", "item-value": "ID", ":required": false },
|
|
249
|
+
"w": "350"
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"el": "f-button",
|
|
253
|
+
"col": { "class": "shrink" },
|
|
254
|
+
"attr": { "class": "my-2", "label": "Tìm", "icon-text": "mdi-magnify",
|
|
255
|
+
":checkvalid": false, "action": { "CALL": "vueData.search" } }
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"el": "f-button",
|
|
259
|
+
"col": { "class": "shrink" },
|
|
260
|
+
"attr": { "class": "my-2", "label": "Thêm", "icon-text": "mdi-account-multiple-plus",
|
|
261
|
+
":checkvalid": false, "action": { "EXE": "vueData.dlThem = true" } }
|
|
262
|
+
}
|
|
263
|
+
]
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Width cho filter inputs trên toolbar:** Dùng pixel (`"w": "350"`, `"w": "200"`) thay vì grid columns.
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## 7. f-button — Quy tắc
|
|
272
|
+
|
|
273
|
+
```json
|
|
274
|
+
{
|
|
275
|
+
"el": "f-button",
|
|
276
|
+
"attr": {
|
|
277
|
+
"label": "Lưu",
|
|
278
|
+
"icon-text": "mdi-content-save",
|
|
279
|
+
":checkvalid": false,
|
|
280
|
+
"action": { "API": "/me/Save", "IN": { "Name": "vueData.form.Name" }, "CALLBACK": { "MESS": "Đã lưu" } }
|
|
281
|
+
},
|
|
282
|
+
"w": 2
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
**`:checkvalid`:**
|
|
287
|
+
- `false` (default): **Hầu hết buttons** — không cần validate form trước
|
|
288
|
+
- `true`: Chỉ khi button là Save của form có validation (user registration, connection string)
|
|
289
|
+
|
|
290
|
+
**Color mapping:**
|
|
291
|
+
| color | label | icon-text | Khi nào |
|
|
292
|
+
|---|---|---|---|
|
|
293
|
+
| `primary` (default) | Lưu | mdi-content-save | Lưu dữ liệu |
|
|
294
|
+
| `primary` | Tìm | mdi-magnify | Search/filter |
|
|
295
|
+
| `primary` | Thêm | mdi-account-multiple-plus | Mở dialog thêm |
|
|
296
|
+
| `warning` | Xóa | mdi-delete | Xóa dữ liệu |
|
|
297
|
+
| `warning` | Từ chối | mdi-cancel | Permission denied |
|
|
298
|
+
| `success` | Cập nhật | mdi-shield-edit | Update quyền |
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## 8. f-table — Cấu trúc chuẩn
|
|
303
|
+
|
|
304
|
+
```json
|
|
305
|
+
{
|
|
306
|
+
"el": "f-table",
|
|
307
|
+
"col": { "v-if": "vueData.user.SystemRight > 1" },
|
|
308
|
+
"attr": {
|
|
309
|
+
"label": "Danh sách",
|
|
310
|
+
":items": "vueData.dataList",
|
|
311
|
+
"item-key": "ID",
|
|
312
|
+
":items-per-page": -1,
|
|
313
|
+
":hide-default-footer": true,
|
|
314
|
+
":height": -16
|
|
315
|
+
},
|
|
316
|
+
"w": 12
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
**`:items-per-page`:**
|
|
321
|
+
- `-1` (default): Hiển thị tất cả, không phân trang — dùng khi có `hide-default-footer: true`
|
|
322
|
+
- `50`: Khi cần phân trang, bỏ `hide-default-footer`
|
|
323
|
+
|
|
324
|
+
**Permission guard:** Luôn đặt `v-if` trên `col` wrapper, không phải trên element:
|
|
325
|
+
```json
|
|
326
|
+
"col": { "v-if": "vueData.user.SystemRight > 1" }
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
**Chiều cao (`:height`)** — cùng quy ước cho `f-table` và `f-sheet`:
|
|
330
|
+
|
|
331
|
+
| Giá trị | Hành vi |
|
|
332
|
+
|---|---|
|
|
333
|
+
| *(bỏ trống)* | Tự giãn theo số dòng — chỉ hợp bảng ngắn/lookup; bảng chính sẽ làm cả trang cuộn |
|
|
334
|
+
| `<= 0` | **Fill tới đáy màn hình, chừa `abs(n)` px** — chuẩn cho bảng chính, dùng `-16` |
|
|
335
|
+
| `> 0` | px cố định — bảng trong dialog (vd `360`) |
|
|
336
|
+
|
|
337
|
+
Chế độ `<=0` tự đo `getBoundingClientRect().top` thật của bảng sau layout, theo dõi `resize`, và tự bật `fixed-header` — **không phải tính tay** theo chiều cao header. Pattern cũ `"$( window ).height()-285"` không dùng nữa (lint D9 cảnh báo).
|
|
338
|
+
|
|
339
|
+
**Inline column types (trong `headers` array):**
|
|
340
|
+
| el | Dùng cho |
|
|
341
|
+
|---|---|
|
|
342
|
+
| `t-button` | Action button trong row |
|
|
343
|
+
| `t-select` | Dropdown inline edit |
|
|
344
|
+
| `t-check` | Toggle on/off |
|
|
345
|
+
| `t-menu` | Context menu cho row |
|
|
346
|
+
| `v-icon` | Icon indicator (conditional color) |
|
|
347
|
+
| `v-chip-group` | Nhóm chip tags |
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## 9. Layout — Container Patterns
|
|
352
|
+
|
|
353
|
+
**Main page container:**
|
|
354
|
+
```json
|
|
355
|
+
{ "prop": "grid-list-md fluid", "rows": [...] }
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
**Centered narrow (form/login page):**
|
|
359
|
+
```json
|
|
360
|
+
{ "prop": "grid-list-md mw-1000", "rows": [...] }
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
**Page với side navigation:**
|
|
364
|
+
```json
|
|
365
|
+
{ "prop": "page-container grid-list-md fluid", "rows": [
|
|
366
|
+
{ "prop": "page-navigation", "cols": [...] },
|
|
367
|
+
{ "prop": "row", "cols": [...] }
|
|
368
|
+
]}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
**Container chứa dialogs (bắt buộc):**
|
|
372
|
+
```json
|
|
373
|
+
{ "prop": "hidden-container", "rows": [
|
|
374
|
+
{ "prop": "", "cols": [ { "el": "v-dialog", ... } ] }
|
|
375
|
+
]}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
## 10. Context Menu — t-menu pattern
|
|
381
|
+
|
|
382
|
+
Khi một row có nhiều actions, dùng `t-menu` thay vì nhiều `t-button`:
|
|
383
|
+
|
|
384
|
+
```json
|
|
385
|
+
// Trong headers array:
|
|
386
|
+
{ "el": "t-menu", "width": "120px", "align": "center", "text": "Tác vụ", "value": "Actions",
|
|
387
|
+
"attr": { ":items": "vueData.menuActions" } }
|
|
388
|
+
|
|
389
|
+
// Trong data section:
|
|
390
|
+
"menuActions": [
|
|
391
|
+
{ "color": "primary", "icon-text": "mdi-pencil", "text": "Chỉnh sửa",
|
|
392
|
+
"action": { "EXE": "vueData.openEdit(item)" } },
|
|
393
|
+
{ "color": "warning", "icon-text": "mdi-delete", "text": "Xóa",
|
|
394
|
+
"action": { "CONFIRM": "Bạn có chắc muốn xóa?", "API": "...", "IN": { "ID": "item.ID" } } }
|
|
395
|
+
]
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
## 11. Phản hồi & xác nhận — CHỈ dùng hệ thống có sẵn của FUI
|
|
401
|
+
|
|
402
|
+
Mọi phản hồi cho user (xác nhận, báo thành công, báo lỗi) đi qua hệ thống có sẵn của platform — **KHÔNG tự dựng** `v-snackbar`, `v-alert`, hay toast/notification tự chế trong controls:
|
|
403
|
+
|
|
404
|
+
| Nhu cầu | Dùng | Cơ chế |
|
|
405
|
+
|---|---|---|
|
|
406
|
+
| Xác nhận trước hành động | `CONFIRM` trong action | jquery-confirm dialog |
|
|
407
|
+
| Báo thành công (thoáng qua) | `MESS` trong CALLBACK | vue-toast góc màn hình |
|
|
408
|
+
| Thông báo cần user đọc kỹ | `MESSBOX` trong action | `showMessage()` hộp thoại |
|
|
409
|
+
| Báo lỗi API | `ERRORCALLBACK` + `MESS`/`MESSBOX` | như trên |
|
|
410
|
+
| Trong script.js / EXE | `Vue.$toast.success/error(...)`, `showMessage({...})` | hàm global sẵn có |
|
|
411
|
+
|
|
412
|
+
### Destructive actions — luôn có CONFIRM
|
|
413
|
+
|
|
414
|
+
Mọi action xóa dữ liệu phải có `CONFIRM`:
|
|
415
|
+
|
|
416
|
+
```json
|
|
417
|
+
{
|
|
418
|
+
"CONFIRM": "Bạn có chắc muốn xóa?",
|
|
419
|
+
"API": "/me/Delete",
|
|
420
|
+
"IN": { "ID": "vueData.selectedID" },
|
|
421
|
+
"CALLBACK": { "CALL": "vueData.loadData" }
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
Update có tác động lớn (system right, connection string) cũng cần `CONFIRM`.
|
|
426
|
+
|
|
427
|
+
### Action ghi — luôn có phản hồi
|
|
428
|
+
|
|
429
|
+
Mọi action ghi dữ liệu (Insert/Update/Delete) phải có `CALLBACK` vừa reload data vừa `MESS` báo kết quả:
|
|
430
|
+
|
|
431
|
+
```json
|
|
432
|
+
{ "API": "/me/Save", "IN": { ... }, "CALLBACK": [ { "MESS": "Đã lưu" }, { "CALL": "vueData.loadData" } ] }
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
## 12. Icons — Bảng chuẩn
|
|
438
|
+
|
|
439
|
+
| Icon | Dùng cho |
|
|
440
|
+
|---|---|
|
|
441
|
+
| `mdi-content-save` | Save / Lưu |
|
|
442
|
+
| `mdi-delete` | Xóa |
|
|
443
|
+
| `mdi-magnify` | Tìm kiếm |
|
|
444
|
+
| `mdi-close` | Đóng dialog |
|
|
445
|
+
| `mdi-refresh` | Tải lại |
|
|
446
|
+
| `mdi-plus` | Thêm mới (generic) |
|
|
447
|
+
| `mdi-pencil` | Sửa |
|
|
448
|
+
| `mdi-account-multiple-plus` | Thêm user |
|
|
449
|
+
| `mdi-account-multiple-minus` | Xóa user |
|
|
450
|
+
| `mdi-account-details` | Chi tiết user |
|
|
451
|
+
| `mdi-shield-edit` | Cập nhật quyền |
|
|
452
|
+
| `mdi-shield-account-outline` | User permission |
|
|
453
|
+
| `mdi-lock-open-plus` | Cấp quyền |
|
|
454
|
+
| `mdi-lock-open-remove` | Thu hồi quyền |
|
|
455
|
+
| `mdi-check-bold` | Trạng thái active |
|
|
456
|
+
| `mdi-lock` | Trạng thái locked |
|
|
457
|
+
| `mdi-cancel` | Từ chối / Denied |
|
|
458
|
+
| `mdi-cloud-upload-outline` | Upload file |
|
|
459
|
+
| `mdi-download` | Tải xuống |
|
|
460
|
+
| `mdi-filter` | Lọc |
|
|
461
|
+
| `mdi-folder-edit-outline` | Xem/sửa chi tiết |
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## 13. Do's and Don'ts
|
|
466
|
+
|
|
467
|
+
### Do
|
|
468
|
+
- Dùng `hidden-container` để wrap tất cả dialogs.
|
|
469
|
+
- Dựng dialog bằng `v-dialog` thủ công theo anatomy §4 — diện mạo mô phỏng `f-dialog`.
|
|
470
|
+
- Dùng `dense flat` cho toolbar bên trong dialog — không thêm color hay dark.
|
|
471
|
+
- Dùng `class="pa-0"` cho v-card trong dialog (không dùng inline style).
|
|
472
|
+
- Form dùng **floating label** (`label` trong attr của field) — w:12 cho field dài, 6+6 cho field ngắn.
|
|
473
|
+
- Với mỗi hàng, kiểm tra trục dọc của các control; hàng trộn input/button/icon/checkbox/label dùng `align-center`, chỉ một cột lệch mới dùng `align-self-center`. Không bù bằng margin thủ công.
|
|
474
|
+
- Hàng cuối của dialog dùng `v-card-actions[class="mr-1 mb-1"]` + `v-spacer`; các nút căn phải và giữ chiều ngang tự nhiên.
|
|
475
|
+
- Chỉ action quan trọng nhất được tô nền `primary`; action phụ dùng `f-button` + `"text": ""`, không tô nền.
|
|
476
|
+
- Giữ kích thước icon mặc định; không tự thêm `small`/`:small` cho icon hoặc nút icon.
|
|
477
|
+
- Đặt `v-if` permission guard trên `col` wrapper, không phải trên element.
|
|
478
|
+
- Dùng `:items-per-page: -1` + `hide-default-footer: true` cho table không cần phân trang.
|
|
479
|
+
- Dùng `CONFIRM` trước mọi action xóa dữ liệu.
|
|
480
|
+
- Dùng pixel width (`"w": "350"`) cho filter inputs trên toolbar row.
|
|
481
|
+
- Dùng `MESS`/`MESSBOX`/`CONFIRM` (hệ thông báo có sẵn) cho mọi phản hồi — xem §11.
|
|
482
|
+
- Dùng `:checkvalid: false` cho hầu hết f-button (chỉ `true` khi cần validate form đăng ký).
|
|
483
|
+
- Conditional color: `"(item.Active == 0 ? 'red' : 'primary')"` cho status toggles.
|
|
484
|
+
|
|
485
|
+
### Don't
|
|
486
|
+
- Đừng viết lại `outlined`, `dense`, `hide-details` trong module.json — runtime tự inject từ `defaultControlAttr`.
|
|
487
|
+
- Đừng dùng label `div` rời bên trái cho form (pattern w:3 + w:9 cũ) — chuẩn là floating label.
|
|
488
|
+
- Đừng dùng `color="primary" dark` cho toolbar trong dialog.
|
|
489
|
+
- Đừng thêm `elevation` hay `outlined` cho v-card trong dialog.
|
|
490
|
+
- Đừng dùng `persistent`, `fullscreen` cho dialog thông thường.
|
|
491
|
+
- Đừng dùng nhiều màu accent trên cùng một màn hình — chỉ primary + một màu semantic.
|
|
492
|
+
- Đừng để button xóa màu `error` (đỏ) — dùng `warning` (cam).
|
|
493
|
+
- Đừng hardcode height cho table — dùng `":height": -16` (fill tới đáy, tự đo) cho bảng chính.
|
|
494
|
+
- Đừng dùng `@click` trong JSON — luôn dùng `v-on:click`.
|
|
495
|
+
- Đừng tự dựng `v-snackbar`/`v-alert`/toast riêng trong controls để báo kết quả — dùng `MESS`/`MESSBOX` có sẵn (§11).
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
## 14. Template `{projectId}/DESIGN.md` — nơi tích luỹ chuẩn riêng của project
|
|
500
|
+
|
|
501
|
+
Khi user góp ý về UI, AI phải ghi quy tắc vào `{projectId}/DESIGN.md` theo template dưới (tạo file nếu chưa có). File này **ghi đè** quy tắc cùng chủ đề của chuẩn chung — mục nào không có thì vẫn theo fui/DESIGN.md. Mỗi quy tắc phải viết ở dạng **tổng quát + ví dụ đúng/sai**, không ghi lại tình huống cụ thể kiểu nhật ký.
|
|
502
|
+
|
|
503
|
+
```markdown
|
|
504
|
+
# DESIGN — {Tên project}
|
|
505
|
+
|
|
506
|
+
> Ghi đè fui/DESIGN.md. Mục không đề cập → theo chuẩn chung.
|
|
507
|
+
> Mỗi quy tắc: phát biểu tổng quát + ví dụ ĐÚNG/SAI (nếu diễn đạt được bằng JSON).
|
|
508
|
+
|
|
509
|
+
## 1. Khung trang (container, mw-*, page-navigation)
|
|
510
|
+
<!-- vd: "Mọi trang nhập liệu dùng mw-1200" -->
|
|
511
|
+
|
|
512
|
+
## 2. Toolbar / hàng filter
|
|
513
|
+
<!-- vd: "Nút Thêm luôn đứng cuối hàng filter, sau nút Tìm" -->
|
|
514
|
+
|
|
515
|
+
## 3. Bảng dữ liệu (f-table)
|
|
516
|
+
<!-- vd: "Cột Tác vụ luôn dùng t-menu khi có ≥2 hành động" -->
|
|
517
|
+
|
|
518
|
+
## 4. Dialog
|
|
519
|
+
<!-- vd: "Dialog form của project này luôn width 600" -->
|
|
520
|
+
|
|
521
|
+
## 5. Form
|
|
522
|
+
<!-- vd: "Field ngày luôn đặt cặp Từ ngày/Đến ngày w:6+6" -->
|
|
523
|
+
|
|
524
|
+
## 6. Màu / icon / nhãn nút
|
|
525
|
+
<!-- vd: "Nút lưu ghi 'Ghi lại' thay vì 'Lưu'" -->
|
|
526
|
+
|
|
527
|
+
## 7. Cấm trong project này
|
|
528
|
+
<!-- vd: "Không dùng v-chip trong bảng" -->
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
**Quy trình ghi (bắt buộc sau mỗi góp ý UI của user):**
|
|
532
|
+
1. Sửa module theo góp ý → 2. Chuyển góp ý thành quy tắc tổng quát, ghi vào đúng mục ở trên → 3. Nếu quy tắc đáng áp dụng cho mọi project → đề xuất user đưa vào fui/DESIGN.md (chuẩn chung), chờ user quyết.
|