@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,276 @@
|
|
|
1
|
+
# FUI Table Components (Source-Based)
|
|
2
|
+
|
|
3
|
+
> File này sở hữu: **`f-table` chuyên sâu: mọi props, auto-header, `sum-format`, readonly table**. Điều khiển trong ô (`t-*`) xem [ui-table-cell-patterns.md](ui-table-cell-patterns.md).
|
|
4
|
+
|
|
5
|
+
This file is derived from `scripts/componentTable.js` (V2) and `scripts/componentTable-3.0.js` (V3).
|
|
6
|
+
Focus: `f-table` and `t-*` renderers.
|
|
7
|
+
|
|
8
|
+
> **Xác định phiên bản trước khi viết headers** — V2 và V3 dùng tên field khác nhau, sai tên thì bảng không render. Xem mục "V2 vs V3 — Sự khác biệt quan trọng" cuối file.
|
|
9
|
+
|
|
10
|
+
> `f-table` đảm nhận cả hai vai trò: bảng CRUD và bảng chỉ xem (readonly). Bảng chỉ xem = `f-table` không khai báo `:update-api` (hoặc thêm `:disabled-update true`); có thể bỏ luôn `:headers` để bảng tự dựng header từ dữ liệu (xem Auto Headers bên dưới).
|
|
11
|
+
|
|
12
|
+
## Prefix Reminder
|
|
13
|
+
|
|
14
|
+
- `f-table`: FUI component.
|
|
15
|
+
- `t-*`: FUI cell renderers for table columns.
|
|
16
|
+
- `v-data-table`: Vuetify internal implementation, but CRUD and table action flow comes from FUI wrappers.
|
|
17
|
+
|
|
18
|
+
## f-table
|
|
19
|
+
|
|
20
|
+
### Props (exact from source)
|
|
21
|
+
|
|
22
|
+
`value`, `headers`, `updateForm`, `updateFormAttr`, `updateApi`, `items`, `label`, `excel`, `showSearch`, `sumFormat`, `disabledHover`, `returnObject`, `itemKey`, `itemsPerPage`, `disabledUpdate`, `hideDefaultFooter`, `template`, `headercomponent`, `height`, `fixedHeader`, `fixedCols`
|
|
23
|
+
|
|
24
|
+
### Real Behavior
|
|
25
|
+
|
|
26
|
+
1. If a header item has `el`, table creates custom slot renderer automatically.
|
|
27
|
+
2. If `updateApi.new` or `updateApi['new-action']` exists, add button appears.
|
|
28
|
+
3. CRUD action slots rely on header `value: "ctrl-update"`.
|
|
29
|
+
4. Editing dialog is `f-dialog` with `updateForm`.
|
|
30
|
+
5. Selection result emit:
|
|
31
|
+
- if `returnObject=false`: emit array of `itemKey`
|
|
32
|
+
- if `returnObject=true`: emit selected row objects
|
|
33
|
+
6. Emits row events from slots: `click:row`, `mouseover:row`, `mouseleave:row`.
|
|
34
|
+
7. **Auto headers**: nếu KHÔNG truyền `:headers`, table tự build header từ `items` (xem mục Auto Headers).
|
|
35
|
+
8. **Sum row / sum line**: prop `sum-format` nhận string HOẶC object — hai cách render khác nhau (xem mục sum-format).
|
|
36
|
+
|
|
37
|
+
### Cố định cột bên trái (`fixed-cols`)
|
|
38
|
+
|
|
39
|
+
Khai `fixed-cols="N"` để giữ N cột đầu tiên khi cuộn ngang. Tính năng có ở cả FUI V2 và V3; bỏ prop, đặt `0`, hoặc truyền giá trị không hợp lệ thì bảng hoạt động như cũ.
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"el": "f-table",
|
|
44
|
+
"w": 12,
|
|
45
|
+
"attr": {
|
|
46
|
+
":items": "dsNhanVien",
|
|
47
|
+
"fixed-cols": "2",
|
|
48
|
+
":headers": [
|
|
49
|
+
{ "text": "Mã", "value": "Ma", "width": "100px" },
|
|
50
|
+
{ "text": "Họ tên", "value": "HoTen", "width": "220px" },
|
|
51
|
+
{ "text": "Phòng ban", "value": "PhongBan", "width": "180px" }
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- Nên khai `width` cho từng cột được cố định; nếu bỏ trống, `f-table` dùng `150px`.
|
|
58
|
+
- `width` dạng số được hiểu là pixel; chuỗi CSS như `"120px"` vẫn được giữ nguyên.
|
|
59
|
+
- `fixed-cols` đếm theo thứ tự cột render thực tế. Nếu bật cột chọn dòng/group của Vuetify thì các cột hệ thống đó cũng nằm trong phép đếm.
|
|
60
|
+
- CSS được scope theo từng instance `f-table`, nên nhiều bảng có số cột cố định khác nhau có thể cùng xuất hiện trên một trang.
|
|
61
|
+
|
|
62
|
+
### Auto Headers (khi không truyền `:headers`)
|
|
63
|
+
|
|
64
|
+
Khi bỏ hẳn prop `:headers`, `f-table` tự build header từ row đầu tiên của `items` (qua `buildHeader`):
|
|
65
|
+
|
|
66
|
+
- Mỗi key của row → một cột `{ text: key, value: key, divider: true }`; key có giá trị số → tự gắn `el: "t-num"` (format số bên phải).
|
|
67
|
+
- Nếu có `:update-api` với `edit`/`delete` và không `disabled-update` → tự thêm cột `ctrl-update` cuối bảng.
|
|
68
|
+
- Headers được rebuild mỗi khi `items` đổi shape (watch trên `items`) — an toàn khi data load async.
|
|
69
|
+
|
|
70
|
+
**Khi nào dùng:** bảng hiển thị nhanh, cột đúng bằng field trả về từ API (SP đã alias tên cột đẹp bằng tiếng Việt). **Khi nào KHÔNG dùng (phải khai `:headers` tường minh):** cần label khác tên field, cần ẩn bớt cột, cần `t-*` renderer tùy biến (t-time, t-check, t-link...), cần width/align cụ thể, hoặc data có field kỹ thuật (ID nội bộ, flag) không nên hiển thị.
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{ "el": "f-table", "w": "12", "attr": { "label": "Kết quả", ":items": "dsKetQua", "show-search": true } }
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### sum-format — Tổng cột (2 dạng)
|
|
77
|
+
|
|
78
|
+
Prop `sum-format` có 2 dạng, render hoàn toàn khác nhau:
|
|
79
|
+
|
|
80
|
+
**Dạng 1 — string template → MỘT dòng text tổng dưới bảng** (trong `v-card-actions`, KHÔNG nằm trong `v-data-table`, không thẳng cột):
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
"sum-format": "Tổng đăng ký: [[DangKy]] | Nhập học: [[NhapHoc]]"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
- `[[FieldName]]` được thay bằng `_.sumBy(items, 'FieldName')` format cố định `'0,0'` (numeral).
|
|
87
|
+
- Kết quả là 1 dòng text duy nhất, căn phải, phía dưới bảng (có `v-divider` ngăn cách).
|
|
88
|
+
- Dùng khi: chỉ cần 1 dòng tóm tắt tổng, hoặc tổng của nhiều cột gộp chung 1 câu.
|
|
89
|
+
- Là string tĩnh → khai báo attr KHÔNG có `:` prefix.
|
|
90
|
+
|
|
91
|
+
**Dạng 2 — object → HÀNG TỔNG thật sự trong bảng** (slot `body.append` của `v-data-table`, thẳng theo từng cột):
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
":sum-format": { "DangKy": "0,0", "NhapHoc": "0,0", "HocPhi": "0,0.0" }
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
- Key = `value` của cột trong headers; value = numeral format string riêng cho cột đó (`"0,0"`, `"0,0.0"`, `"0.0%"`, ...).
|
|
98
|
+
- Render một `<tr>` cuối thân bảng: ô của cột có key trong object hiển thị `_.sumBy(items, key)` theo format tương ứng; các cột khác để trống. Tất cả ô căn phải, `font-weight-medium`.
|
|
99
|
+
- Hàng tổng nằm TRONG bảng nên thẳng hàng với cột, cuộn cùng thân bảng.
|
|
100
|
+
- Là object → khai báo attr CÓ `:` prefix.
|
|
101
|
+
|
|
102
|
+
**Chọn dạng nào:** user cần "hàng tổng dưới mỗi cột / dòng tổng trong bảng / tổng thẳng cột" → dạng object. User cần "dòng chữ tổng kết chung" → dạng string. **KHÔNG tự dựng hàng tổng thủ công** (không push row "Tổng" vào items, không tự viết template body.append) — dùng `sum-format`.
|
|
103
|
+
|
|
104
|
+
Ví dụ đầy đủ dạng object:
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"el": "f-table", "w": "12",
|
|
109
|
+
"attr": {
|
|
110
|
+
"label": "Thống kê tuyển sinh",
|
|
111
|
+
":items": "dsThongKe",
|
|
112
|
+
":headers": [
|
|
113
|
+
{ "text": "Ngành", "value": "TenNganh" },
|
|
114
|
+
{ "text": "Đăng ký", "value": "DangKy", "el": "t-num" },
|
|
115
|
+
{ "text": "Nhập học", "value": "NhapHoc", "el": "t-num" }
|
|
116
|
+
],
|
|
117
|
+
":sum-format": { "DangKy": "0,0", "NhapHoc": "0,0" }
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### updateApi Keys Used By Source
|
|
123
|
+
|
|
124
|
+
- `new`
|
|
125
|
+
- `edit`
|
|
126
|
+
- `delete`
|
|
127
|
+
- `default-item`
|
|
128
|
+
- `new-action`
|
|
129
|
+
- `edit-action`
|
|
130
|
+
- `data-out`
|
|
131
|
+
|
|
132
|
+
### Minimal CRUD Example
|
|
133
|
+
|
|
134
|
+
```json
|
|
135
|
+
{
|
|
136
|
+
"el": "f-table",
|
|
137
|
+
"w": "12",
|
|
138
|
+
"attr": {
|
|
139
|
+
"label": "Danh sach nhan vien",
|
|
140
|
+
":items": "items",
|
|
141
|
+
"item-key": "ID",
|
|
142
|
+
":return-object": false,
|
|
143
|
+
"show-search": true,
|
|
144
|
+
"excel": true,
|
|
145
|
+
":headers": [
|
|
146
|
+
{ "text": "Ho ten", "value": "FullName" },
|
|
147
|
+
{ "text": "Email", "value": "Email" },
|
|
148
|
+
{ "text": "Trang thai", "value": "Active", "el": "t-boolean", "align": "center", "width": "90px" },
|
|
149
|
+
{ "text": "Tac vu", "value": "ctrl-update", "align": "center", "width": "120px" }
|
|
150
|
+
],
|
|
151
|
+
":update-form": [
|
|
152
|
+
{ "el": "v-text-field", "attr": { "v-model": "FullName", "label": "Ho ten", ":required": true } },
|
|
153
|
+
{ "el": "v-text-field", "attr": { "v-model": "Email", "label": "Email", ":required": true } }
|
|
154
|
+
],
|
|
155
|
+
":update-api": {
|
|
156
|
+
"default-item": { "FullName": "", "Email": "", "Active": true },
|
|
157
|
+
"new": {
|
|
158
|
+
"API": "/api/staff/create",
|
|
159
|
+
"IN": { "FullName": "item.FullName", "Email": "item.Email", "Active": "item.Active" },
|
|
160
|
+
"CALLBACK": { "CALL": "apiLoadItems" }
|
|
161
|
+
},
|
|
162
|
+
"edit": {
|
|
163
|
+
"API": "/api/staff/update",
|
|
164
|
+
"IN": { "ID": "item.ID", "FullName": "item.FullName", "Email": "item.Email", "Active": "item.Active" },
|
|
165
|
+
"CALLBACK": { "CALL": "apiLoadItems" }
|
|
166
|
+
},
|
|
167
|
+
"delete": {
|
|
168
|
+
"CONFIRM": "Xac nhan xoa?",
|
|
169
|
+
"API": "/api/staff/delete",
|
|
170
|
+
"IN": { "ID": "item.ID" },
|
|
171
|
+
"CALLBACK": { "CALL": "apiLoadItems" }
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Readonly Table
|
|
179
|
+
|
|
180
|
+
Bảng chỉ xem = `f-table` không có `:update-api` (không hiện nút thêm/sửa/xóa) — bỏ `:headers` nếu muốn auto-build:
|
|
181
|
+
|
|
182
|
+
```json
|
|
183
|
+
{
|
|
184
|
+
"el": "f-table",
|
|
185
|
+
"w": "12",
|
|
186
|
+
"attr": {
|
|
187
|
+
"label": "Danh sach xem nhanh",
|
|
188
|
+
":items": "items",
|
|
189
|
+
"item-key": "ID",
|
|
190
|
+
"show-search": true,
|
|
191
|
+
"excel": true,
|
|
192
|
+
":items-per-page": 20
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## t-* Cell Renderers
|
|
198
|
+
|
|
199
|
+
Use in `headers` by setting `el`.
|
|
200
|
+
|
|
201
|
+
Example header:
|
|
202
|
+
|
|
203
|
+
```json
|
|
204
|
+
{ "text": "Ngay tao", "value": "CreatedAt", "el": "t-time", "attr": { "format": "DD/MM/YYYY HH:mm" } }
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Supported `t-*` components
|
|
208
|
+
|
|
209
|
+
- `t-html`
|
|
210
|
+
- `t-label`
|
|
211
|
+
- `t-num`
|
|
212
|
+
- `t-time`
|
|
213
|
+
- `t-boolean`
|
|
214
|
+
- `t-check`
|
|
215
|
+
- `t-text`
|
|
216
|
+
- `t-select`
|
|
217
|
+
- `t-combobox`
|
|
218
|
+
- `t-menu`
|
|
219
|
+
- `t-link`
|
|
220
|
+
- `t-button`
|
|
221
|
+
|
|
222
|
+
### Notes
|
|
223
|
+
|
|
224
|
+
1. Editable renderers (`t-check`, `t-text`, `t-select`, `t-combobox`, `t-menu`, `t-button`) use `tableActionEvent`.
|
|
225
|
+
2. For dialog opening in row actions, use `target: "dialog"` plus `wid`, `url`, `title`, `onclose`.
|
|
226
|
+
3. Apply literal-string rule only in Action `IN` mapping.
|
|
227
|
+
Static component props without `:` are plain strings by default.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## V2 vs V3 — Sự khác biệt quan trọng (nguồn: `componentTable.js` vs `componentTable-3.0.js`)
|
|
232
|
+
|
|
233
|
+
Phiên bản framework được xác định từ `_projectInfo.json` hoặc `_moduleInfo.json` — tra trước khi viết headers.
|
|
234
|
+
|
|
235
|
+
### Header field names
|
|
236
|
+
|
|
237
|
+
**Đây là điểm dễ nhầm nhất.** Hai trường `text`/`value` của V2 đổi tên thành `title`/`key` ở V3:
|
|
238
|
+
|
|
239
|
+
| Trường | V2 (`componentTable.js`) | V3 (`componentTable-3.0.js`) |
|
|
240
|
+
|---|---|---|
|
|
241
|
+
| Nhãn cột | `"text": "Tên cột"` | `"title": "Tên cột"` |
|
|
242
|
+
| Field data | `"value": "TenField"` | `"key": "TenField"` |
|
|
243
|
+
| Cột ctrl | `"value": "ctrl-update"` | `"key": "ctrl-update"` |
|
|
244
|
+
|
|
245
|
+
```json
|
|
246
|
+
// V2 ✅
|
|
247
|
+
{ "text": "Họ tên", "value": "HoTen", "el": "t-label" }
|
|
248
|
+
{ "text": "Tác vụ", "value": "ctrl-update", "align": "center" }
|
|
249
|
+
|
|
250
|
+
// V3 ✅
|
|
251
|
+
{ "title": "Họ tên", "key": "HoTen", "el": "t-label" }
|
|
252
|
+
{ "title": "Tác vụ", "key": "ctrl-update", "align": "center" }
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
> Dùng `text`/`value` trên project V3 → cột render nhưng **tiêu đề biến mất và sort không hoạt động** (Vuetify 3 đọc `title`/`key`, bỏ qua `text`/`value`). Không có lỗi JS nào báo — chỉ nhìn thấy qua ảnh render.
|
|
256
|
+
|
|
257
|
+
### Props bổ sung ở V3
|
|
258
|
+
|
|
259
|
+
| Prop | Mặc định V3 | Ghi chú |
|
|
260
|
+
|---|---|---|
|
|
261
|
+
| `density` | `'compact'` | Mật độ dòng — `'compact'`/`'comfortable'`/`'default'` |
|
|
262
|
+
| `disable-sort` | `false` | Tắt sort toàn bảng |
|
|
263
|
+
| `slots` | `null` | Custom slot động (object `{ name, html }`) |
|
|
264
|
+
| `group-template` | `null` | Template cho nhóm gộp (`groupBy`) |
|
|
265
|
+
| `height` | `null` | Giống V2: null/bỏ trống = tự giãn; ≤0 = fill đáy; >0 = px cố định |
|
|
266
|
+
|
|
267
|
+
### sum-format object dạng V3
|
|
268
|
+
|
|
269
|
+
Ở V3, key của `sum-format` object phải khớp `key` của header (không phải `value`):
|
|
270
|
+
|
|
271
|
+
```json
|
|
272
|
+
// V3 ✅ — key = "DangKy" khớp với header { "key": "DangKy" }
|
|
273
|
+
":sum-format": { "DangKy": "0,0", "NhapHoc": "0,0" }
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Logic giống V2 hoàn toàn — chỉ khác ở chỗ V3 đọc `col.key` thay vì `col.value` nên tên field phải nhất quán.
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# FUI Dialog & Overlay Components
|
|
2
|
+
|
|
3
|
+
> File này sở hữu: **`f-dialog`, `f-window`, `f-editor`**. Pattern dialog thủ công (`v-dialog` + hidden-container) xem [ui-dialog-patterns.md](ui-dialog-patterns.md).
|
|
4
|
+
|
|
5
|
+
Components liên quan đến dialog, overlay, và editor nội dung. Xem prefix/binding rules tại [components-display.md](components-display.md).
|
|
6
|
+
|
|
7
|
+
## f-window
|
|
8
|
+
|
|
9
|
+
- Props (source): `id`
|
|
10
|
+
- Behavior: internal iframe dialog host, thường được mở qua `openWindow(...)`
|
|
11
|
+
- Example:
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"FUN": "openWindow",
|
|
16
|
+
"IN": {
|
|
17
|
+
"id": "`winUser",
|
|
18
|
+
"url": "'/fp/module?mid=123'",
|
|
19
|
+
"title": "Chi tiet user",
|
|
20
|
+
"width": 1100
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## f-editor
|
|
26
|
+
|
|
27
|
+
- Props (source): `value`, `imageapi`, `height`, `toolbar`
|
|
28
|
+
- Emit: `input` with HTML content
|
|
29
|
+
- Behavior: wraps CKEditor with upload auth header
|
|
30
|
+
- Example:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"el": "f-editor",
|
|
35
|
+
"w": "12",
|
|
36
|
+
"attr": {
|
|
37
|
+
"v-model": "formData.contentHtml",
|
|
38
|
+
"imageapi": "/api/editor/upload",
|
|
39
|
+
":height": 360
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## f-editor-dialog
|
|
45
|
+
|
|
46
|
+
- Props (source): `value`, `imageapi`, `label`, `width`, `toolbar`
|
|
47
|
+
- Runtime expectation: `value` là object (`open`, `text`, `object`, `ok`), không phải plain string
|
|
48
|
+
- Behavior: modal editor, write-back on OK
|
|
49
|
+
- Example:
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"el": "f-editor-dialog",
|
|
54
|
+
"w": "6",
|
|
55
|
+
"attr": {
|
|
56
|
+
":value": "editorState",
|
|
57
|
+
"label": "Noi dung mo rong",
|
|
58
|
+
":width": 1000,
|
|
59
|
+
"imageapi": "/api/editor/upload"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## f-dialog
|
|
65
|
+
|
|
66
|
+
Modal dialog tự build form từ mảng `controls`, có hỗ trợ watchers cục bộ, validation, và action buttons.
|
|
67
|
+
|
|
68
|
+
- Props:
|
|
69
|
+
- `value` (Boolean, default: `false`) — v-model để mở/đóng dialog
|
|
70
|
+
- `data` (Object, default: `{}`) — dữ liệu đầu vào, bind bằng `:data.sync`; khi dialog mở dữ liệu này được copy vào các field
|
|
71
|
+
- `dataOut` (Object, default: `{}`) — dữ liệu đầu ra, bind bằng `:data-out.sync`; nhận instance component khi dialog mở
|
|
72
|
+
- `title` (String, default: `''`) — tiêu đề dialog
|
|
73
|
+
- `controls` (Array, default: `[]`) — mảng control definitions để build form; mỗi control có `el`, `attr`, `w` (col width); field nào có `v-model` không bắt đầu bằng `vueData.` sẽ được tạo data cục bộ tự động (khởi tạo `null`)
|
|
74
|
+
- `watch` (Object, default: `{}`) — watchers cục bộ trong dialog; key là tên field, value là action chạy khi field thay đổi; watchers được đăng ký khi dialog mở và hủy khi đóng
|
|
75
|
+
- `button` (Array, default: `[]`) — mảng button definitions (xem cấu trúc button bên dưới)
|
|
76
|
+
- `disableValidate` (Boolean, default: `false`) — bỏ qua form validation khi `true`
|
|
77
|
+
- `width` (Number, default: `800`) — chiều rộng dialog (px)
|
|
78
|
+
- `openAction` (Object, default: `null`) — action chạy ngay khi dialog mở
|
|
79
|
+
|
|
80
|
+
- Emits:
|
|
81
|
+
- `input` — mở/đóng dialog (dùng với v-model)
|
|
82
|
+
- `update:data-out` — phát ra instance component khi dialog mở (để parent truy cập data cục bộ)
|
|
83
|
+
- `update:data` — phát ra `v_outData` khi button có `getoutdata: true` được click (sau khi validation pass)
|
|
84
|
+
|
|
85
|
+
- Vòng đời khi mở (`value = true`):
|
|
86
|
+
1. Reset tất cả field về giá trị từ `:data` (gọi `setDefaultData`)
|
|
87
|
+
2. Đăng ký watchers từ prop `watch`
|
|
88
|
+
3. Chạy `openAction` nếu có
|
|
89
|
+
4. Emit `update:data-out` với instance component
|
|
90
|
+
|
|
91
|
+
- Vòng đời khi đóng (`value = false`):
|
|
92
|
+
1. Hủy tất cả watchers đã đăng ký
|
|
93
|
+
|
|
94
|
+
- Cấu trúc button object:
|
|
95
|
+
- `label` (String) — text hiển thị trên button
|
|
96
|
+
- `color` (String, default: `"primary"`) — màu button
|
|
97
|
+
- `elevation` (Number, default: `0`) — độ nổi
|
|
98
|
+
- `text` (Boolean, default: `true`) — dạng text button
|
|
99
|
+
- `type` (String) — ví dụ `"submit"`
|
|
100
|
+
- `:disabled` (String) — biểu thức Vue để disable button, ví dụ `"!checkBoxValue"`
|
|
101
|
+
- `v-if` (String) — biểu thức Vue để ẩn/hiện button, ví dụ `"ModuleID==1"`
|
|
102
|
+
- `icon-text` (String) — icon MDI hiển thị bên trái label
|
|
103
|
+
- `checkvalid` (Boolean) — validate form trước khi chạy action; nếu không pass thì dừng
|
|
104
|
+
- `getoutdata` (Boolean) — sync field values vào `v_outData` rồi emit `update:data`; cũng trigger validation
|
|
105
|
+
- `action` (Array | Function) — danh sách actions chạy khi click; context truyền vào gồm tất cả fields trong `v_outData` và key `dData` trỏ về `v_outData`
|
|
106
|
+
|
|
107
|
+
- Lưu ý:
|
|
108
|
+
- Button click được debounce 500ms (leading edge) để tránh double-click
|
|
109
|
+
- Controls hỗ trợ `br: true` để xuống hàng (row break)
|
|
110
|
+
- Template được build tĩnh lúc `data()` init, không re-render khi prop `controls` thay đổi
|
|
111
|
+
- `watch` trong prop template là `:watch` (bind động), khác với `watch` mặc định của Vue
|
|
112
|
+
- **Không dùng `f-dialog` bên trong template của component:** `f-dialog` chỉ hoạt động khi được khai báo trực tiếp trong `controls` của cấu trúc JSON module. Nếu đặt trong template của một Vue component, nó sẽ không hoạt động đúng.
|
|
113
|
+
- **Khai báo biến `vueData` trước khi dùng trong controls:** Nếu một control bind vào `vueData.someVar`, biến đó phải được khai báo trước trong `data` của module — Vue không thể thiết lập reactivity cho biến chưa tồn tại lúc init.
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
"data": [
|
|
117
|
+
{ "projectList": [] }
|
|
118
|
+
],
|
|
119
|
+
"controls": [
|
|
120
|
+
{
|
|
121
|
+
"prop": "fluid pa-0",
|
|
122
|
+
"rows": [{ "prop": "", "cols": [
|
|
123
|
+
{
|
|
124
|
+
"el": "v-autocomplete",
|
|
125
|
+
"attr": {
|
|
126
|
+
"v-model": "pid",
|
|
127
|
+
"label": "Module name",
|
|
128
|
+
":items": "vueData.projectList",
|
|
129
|
+
"item-text": "ModuleName",
|
|
130
|
+
"item-value": "ModuleID"
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
]}]
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
- Ví dụ đầy đủ:
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"el": "f-dialog",
|
|
143
|
+
"attr": {
|
|
144
|
+
"v-model": "dialogOpen",
|
|
145
|
+
":data.sync": "dialogData",
|
|
146
|
+
"title": "Nhap du lieu",
|
|
147
|
+
":open-action": { "MESSBOX": "Bạn vừa mở dialog" },
|
|
148
|
+
":controls": [
|
|
149
|
+
{ "el": "v-text-field", "attr": { "v-model": "Domain", "label": "Domain" }, "w": 4 },
|
|
150
|
+
{ "el": "v-text-field", "attr": { "v-model": "ModuleID", "label": "ModuleID" }, "w": 3 },
|
|
151
|
+
{ "el": "v-text-field", "attr": { "v-model": "ModuleName", "label": "ModuleName" }, "w": 8 },
|
|
152
|
+
{
|
|
153
|
+
"el": "v-checkbox",
|
|
154
|
+
"attr": { ":label": "`Tôi đã hiểu và đồng ý: ${checkBoxValue}`", "v-model": "checkBoxValue" }
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"el": "v-select",
|
|
158
|
+
"attr": {
|
|
159
|
+
"label": "select", "v-model": "bienselect",
|
|
160
|
+
":items": "vueData.Mang", "item-text": "AppName", "item-value": "AppListID"
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
],
|
|
164
|
+
":watch": {
|
|
165
|
+
"bienselect": { "MESSBOX": "Watch Select {{bienselect}}" },
|
|
166
|
+
"Domain": { "MESSBOX": "Watch textbox {{Domain}}" }
|
|
167
|
+
},
|
|
168
|
+
":button": [
|
|
169
|
+
{
|
|
170
|
+
"label": "Submit OK",
|
|
171
|
+
"type": "submit",
|
|
172
|
+
":disabled": "!checkBoxValue",
|
|
173
|
+
"action": [
|
|
174
|
+
{ "ModuleName": "gan gia tri cho ModuleName" },
|
|
175
|
+
{ "MESSBOX": "thong bao 1" },
|
|
176
|
+
{ "dialogOpen": false }
|
|
177
|
+
]
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"label": "Chay mot API",
|
|
181
|
+
"checkvalid": true,
|
|
182
|
+
"v-if": "ModuleID==1",
|
|
183
|
+
"action": [{ "API": "/chaymotapi" }]
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"label": "Close",
|
|
187
|
+
"action": [{ "dialogOpen": false }]
|
|
188
|
+
}
|
|
189
|
+
]
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
```
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# FUI Display & Presentation Components
|
|
2
|
+
|
|
3
|
+
> File này sở hữu: **component hiển thị: `f-label`, `f-title`, `f-box`, `f-header`, `f-slider`, chip/badge**.
|
|
4
|
+
|
|
5
|
+
Components dùng để hiển thị thông tin, chart, media. File này cũng chứa prefix/binding rules áp dụng cho tất cả f-* components.
|
|
6
|
+
|
|
7
|
+
## Prefix và Binding Rules
|
|
8
|
+
|
|
9
|
+
- `f-*`: FUI components (định nghĩa trong FUI runtime)
|
|
10
|
+
- `v-*`: Vuetify components
|
|
11
|
+
- `uc-*`: Custom module components từ `components/`
|
|
12
|
+
- Trong `module.json`, truyền props qua `attr`
|
|
13
|
+
- Dùng kebab-case trong JSON cho custom props (`api-upload`, `item-value`)
|
|
14
|
+
- Giá trị động dùng `:prop`
|
|
15
|
+
- Dùng `v-on:*` trong JSON (không dùng `@*`)
|
|
16
|
+
- Props không có `:` (ví dụ `url`, `api-upload`) là plain string mặc định
|
|
17
|
+
- Literal-string forcing (backtick/quote) chỉ dùng trong Action `IN` mapping, không dùng cho static props
|
|
18
|
+
|
|
19
|
+
## Minimal Control Pattern
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"el": "f-date",
|
|
24
|
+
"w": "6",
|
|
25
|
+
"attr": {
|
|
26
|
+
"v-model": "formData.fromDate",
|
|
27
|
+
"label": "From date"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## f-label
|
|
35
|
+
|
|
36
|
+
- Props (source): `items`, `text`, `color`, `iconText`
|
|
37
|
+
- Behavior: render `v-chip` từ `text` và/hoặc `items`
|
|
38
|
+
- Example:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"el": "f-label",
|
|
43
|
+
"w": "12",
|
|
44
|
+
"attr": {
|
|
45
|
+
"text": "Trang thai",
|
|
46
|
+
"icon-text": "mdi-information"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## f-box
|
|
52
|
+
|
|
53
|
+
- Props (source): `rowFormat`, `items`, `label`, `edit`, `saveclick`
|
|
54
|
+
- Emit: `input` khi dữ liệu nội bộ thay đổi
|
|
55
|
+
- Behavior: hiển thị/chỉnh sửa key-value rows, tự build row format từ data nếu thiếu
|
|
56
|
+
- `rowFormat`: mảng `{ text, value, noEdit }` — `noEdit: true` khóa cột đó khi `edit=true`
|
|
57
|
+
- `items`: object hoặc array; object tự động wrap thành array 1 phần tử
|
|
58
|
+
- Example:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"el": "f-box",
|
|
63
|
+
"w": "12",
|
|
64
|
+
"attr": {
|
|
65
|
+
"label": "Thong tin",
|
|
66
|
+
":items": "detailData",
|
|
67
|
+
":edit": "isEditMode",
|
|
68
|
+
":row-format": [
|
|
69
|
+
{ "text": "Mã", "value": "StudentID", "noEdit": true },
|
|
70
|
+
{ "text": "Họ tên", "value": "FullName" },
|
|
71
|
+
{ "text": "Ngày sinh", "value": "BirthDate" }
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## f-header
|
|
78
|
+
|
|
79
|
+
- Props (source): `label`
|
|
80
|
+
- Example:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"el": "f-header",
|
|
85
|
+
"w": "12",
|
|
86
|
+
"attr": { "label": "Bao cao tong hop" }
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## f-title
|
|
91
|
+
|
|
92
|
+
- Props (source): `label`
|
|
93
|
+
- Example:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"el": "f-title",
|
|
98
|
+
"w": "12",
|
|
99
|
+
"attr": { "label": "Danh sach ho so" }
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## f-slider
|
|
104
|
+
|
|
105
|
+
- Props (source): `items`, `itemAttr`
|
|
106
|
+
- Behavior: bọc `v-carousel` và `v-carousel-item`
|
|
107
|
+
- Example:
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"el": "f-slider",
|
|
112
|
+
"w": "12",
|
|
113
|
+
"attr": {
|
|
114
|
+
":items": "slideItems",
|
|
115
|
+
":item-attr": { "contain": true }
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## f-echart
|
|
121
|
+
|
|
122
|
+
→ Xem [`components-echart.md`](components-echart.md) — tài liệu đầy đủ về props, config, global module `FEchartFormatter` và ví dụ.
|
|
123
|
+
|
|
124
|
+
## f-pdfmake
|
|
125
|
+
|
|
126
|
+
- Props (source): `data`
|
|
127
|
+
- Behavior: render PDF trong iframe, re-render khi `data` thay đổi (deep watch)
|
|
128
|
+
- Example:
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"el": "f-pdfmake",
|
|
133
|
+
"w": "12",
|
|
134
|
+
"attr": {
|
|
135
|
+
":data": "pdfDefinition",
|
|
136
|
+
"height": "550"
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Practical Notes
|
|
144
|
+
|
|
145
|
+
1. Hầu hết `f-*` components forward unknown attrs qua `v-bind="$attrs"` — Vuetify attrs vẫn hoạt động nếu child là Vuetify control.
|
|
146
|
+
2. Literal-string rule chỉ áp dụng khi truyền API/path strings trong Action `IN` mapping.
|
|
147
|
+
3. Xem `references/component-table.md` cho `f-table`.
|