@fui-org/fui-cli 0.2.0 → 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.
Files changed (212) hide show
  1. package/README.md +13 -1
  2. package/dist/fui.js +160 -43
  3. package/package.json +4 -2
  4. package/skills/fui/SKILL.md +131 -66
  5. package/skills/fui-skill/README.md +112 -0
  6. package/skills/fui-skill/SKILL.md +269 -0
  7. package/skills/fui-skill/assets/projectdefaultstyle.css +518 -0
  8. package/skills/fui-skill/design-md/airbnb/DESIGN.md +545 -0
  9. package/skills/fui-skill/design-md/airbnb/README.md +5 -0
  10. package/skills/fui-skill/design-md/airtable/DESIGN.md +554 -0
  11. package/skills/fui-skill/design-md/airtable/README.md +5 -0
  12. package/skills/fui-skill/design-md/apple/DESIGN.md +562 -0
  13. package/skills/fui-skill/design-md/apple/README.md +5 -0
  14. package/skills/fui-skill/design-md/asu/DESIGN.md +179 -0
  15. package/skills/fui-skill/design-md/asu/README.md +107 -0
  16. package/skills/fui-skill/design-md/binance/DESIGN.md +634 -0
  17. package/skills/fui-skill/design-md/binance/README.md +5 -0
  18. package/skills/fui-skill/design-md/bmw/DESIGN.md +544 -0
  19. package/skills/fui-skill/design-md/bmw/README.md +5 -0
  20. package/skills/fui-skill/design-md/bmw-m/DESIGN.md +503 -0
  21. package/skills/fui-skill/design-md/bmw-m/README.md +5 -0
  22. package/skills/fui-skill/design-md/bugatti/DESIGN.md +454 -0
  23. package/skills/fui-skill/design-md/bugatti/README.md +5 -0
  24. package/skills/fui-skill/design-md/cal/DESIGN.md +542 -0
  25. package/skills/fui-skill/design-md/cal/README.md +5 -0
  26. package/skills/fui-skill/design-md/claude/DESIGN.md +589 -0
  27. package/skills/fui-skill/design-md/claude/README.md +5 -0
  28. package/skills/fui-skill/design-md/clay/DESIGN.md +541 -0
  29. package/skills/fui-skill/design-md/clay/README.md +5 -0
  30. package/skills/fui-skill/design-md/clickhouse/DESIGN.md +544 -0
  31. package/skills/fui-skill/design-md/clickhouse/README.md +5 -0
  32. package/skills/fui-skill/design-md/cohere/DESIGN.md +451 -0
  33. package/skills/fui-skill/design-md/cohere/README.md +5 -0
  34. package/skills/fui-skill/design-md/coinbase/DESIGN.md +570 -0
  35. package/skills/fui-skill/design-md/coinbase/README.md +5 -0
  36. package/skills/fui-skill/design-md/composio/DESIGN.md +506 -0
  37. package/skills/fui-skill/design-md/composio/README.md +5 -0
  38. package/skills/fui-skill/design-md/cursor/DESIGN.md +537 -0
  39. package/skills/fui-skill/design-md/cursor/README.md +5 -0
  40. package/skills/fui-skill/design-md/elevenlabs/DESIGN.md +504 -0
  41. package/skills/fui-skill/design-md/elevenlabs/README.md +5 -0
  42. package/skills/fui-skill/design-md/expo/DESIGN.md +526 -0
  43. package/skills/fui-skill/design-md/expo/README.md +5 -0
  44. package/skills/fui-skill/design-md/ferrari/DESIGN.md +531 -0
  45. package/skills/fui-skill/design-md/ferrari/README.md +5 -0
  46. package/skills/fui-skill/design-md/figma/DESIGN.md +578 -0
  47. package/skills/fui-skill/design-md/figma/README.md +5 -0
  48. package/skills/fui-skill/design-md/framer/DESIGN.md +544 -0
  49. package/skills/fui-skill/design-md/framer/README.md +5 -0
  50. package/skills/fui-skill/design-md/fui/DESIGN.md +532 -0
  51. package/skills/fui-skill/design-md/hashicorp/DESIGN.md +575 -0
  52. package/skills/fui-skill/design-md/hashicorp/README.md +5 -0
  53. package/skills/fui-skill/design-md/ibm/DESIGN.md +550 -0
  54. package/skills/fui-skill/design-md/ibm/README.md +5 -0
  55. package/skills/fui-skill/design-md/intercom/DESIGN.md +546 -0
  56. package/skills/fui-skill/design-md/intercom/README.md +5 -0
  57. package/skills/fui-skill/design-md/kraken/DESIGN.md +125 -0
  58. package/skills/fui-skill/design-md/kraken/README.md +5 -0
  59. package/skills/fui-skill/design-md/lamborghini/DESIGN.md +288 -0
  60. package/skills/fui-skill/design-md/lamborghini/README.md +5 -0
  61. package/skills/fui-skill/design-md/linear.app/DESIGN.md +548 -0
  62. package/skills/fui-skill/design-md/linear.app/README.md +5 -0
  63. package/skills/fui-skill/design-md/lovable/DESIGN.md +298 -0
  64. package/skills/fui-skill/design-md/lovable/README.md +5 -0
  65. package/skills/fui-skill/design-md/mastercard/DESIGN.md +365 -0
  66. package/skills/fui-skill/design-md/mastercard/README.md +5 -0
  67. package/skills/fui-skill/design-md/meta/DESIGN.md +683 -0
  68. package/skills/fui-skill/design-md/meta/README.md +5 -0
  69. package/skills/fui-skill/design-md/minimax/DESIGN.md +746 -0
  70. package/skills/fui-skill/design-md/minimax/README.md +5 -0
  71. package/skills/fui-skill/design-md/mintlify/DESIGN.md +852 -0
  72. package/skills/fui-skill/design-md/mintlify/README.md +5 -0
  73. package/skills/fui-skill/design-md/miro/DESIGN.md +825 -0
  74. package/skills/fui-skill/design-md/miro/README.md +5 -0
  75. package/skills/fui-skill/design-md/mistral.ai/DESIGN.md +773 -0
  76. package/skills/fui-skill/design-md/mistral.ai/README.md +5 -0
  77. package/skills/fui-skill/design-md/mongodb/DESIGN.md +767 -0
  78. package/skills/fui-skill/design-md/mongodb/README.md +5 -0
  79. package/skills/fui-skill/design-md/nike/DESIGN.md +575 -0
  80. package/skills/fui-skill/design-md/nike/README.md +5 -0
  81. package/skills/fui-skill/design-md/notion/DESIGN.md +821 -0
  82. package/skills/fui-skill/design-md/notion/README.md +5 -0
  83. package/skills/fui-skill/design-md/nvidia/DESIGN.md +640 -0
  84. package/skills/fui-skill/design-md/nvidia/README.md +5 -0
  85. package/skills/fui-skill/design-md/ollama/DESIGN.md +539 -0
  86. package/skills/fui-skill/design-md/ollama/README.md +5 -0
  87. package/skills/fui-skill/design-md/opencode.ai/DESIGN.md +521 -0
  88. package/skills/fui-skill/design-md/opencode.ai/README.md +5 -0
  89. package/skills/fui-skill/design-md/pinterest/DESIGN.md +597 -0
  90. package/skills/fui-skill/design-md/pinterest/README.md +5 -0
  91. package/skills/fui-skill/design-md/playstation/DESIGN.md +661 -0
  92. package/skills/fui-skill/design-md/playstation/README.md +5 -0
  93. package/skills/fui-skill/design-md/posthog/DESIGN.md +690 -0
  94. package/skills/fui-skill/design-md/posthog/README.md +5 -0
  95. package/skills/fui-skill/design-md/raycast/DESIGN.md +669 -0
  96. package/skills/fui-skill/design-md/raycast/README.md +5 -0
  97. package/skills/fui-skill/design-md/renault/DESIGN.md +589 -0
  98. package/skills/fui-skill/design-md/renault/README.md +5 -0
  99. package/skills/fui-skill/design-md/replicate/DESIGN.md +616 -0
  100. package/skills/fui-skill/design-md/replicate/README.md +5 -0
  101. package/skills/fui-skill/design-md/resend/DESIGN.md +585 -0
  102. package/skills/fui-skill/design-md/resend/README.md +5 -0
  103. package/skills/fui-skill/design-md/revolut/DESIGN.md +636 -0
  104. package/skills/fui-skill/design-md/revolut/README.md +5 -0
  105. package/skills/fui-skill/design-md/runwayml/DESIGN.md +244 -0
  106. package/skills/fui-skill/design-md/runwayml/README.md +5 -0
  107. package/skills/fui-skill/design-md/sanity/DESIGN.md +357 -0
  108. package/skills/fui-skill/design-md/sanity/README.md +5 -0
  109. package/skills/fui-skill/design-md/sentry/DESIGN.md +551 -0
  110. package/skills/fui-skill/design-md/sentry/README.md +5 -0
  111. package/skills/fui-skill/design-md/shopify/DESIGN.md +516 -0
  112. package/skills/fui-skill/design-md/shopify/README.md +5 -0
  113. package/skills/fui-skill/design-md/slack/DESIGN.md +482 -0
  114. package/skills/fui-skill/design-md/spacex/DESIGN.md +363 -0
  115. package/skills/fui-skill/design-md/spacex/README.md +5 -0
  116. package/skills/fui-skill/design-md/spotify/DESIGN.md +246 -0
  117. package/skills/fui-skill/design-md/spotify/README.md +5 -0
  118. package/skills/fui-skill/design-md/starbucks/DESIGN.md +580 -0
  119. package/skills/fui-skill/design-md/starbucks/README.md +5 -0
  120. package/skills/fui-skill/design-md/stripe/DESIGN.md +487 -0
  121. package/skills/fui-skill/design-md/stripe/README.md +5 -0
  122. package/skills/fui-skill/design-md/supabase/DESIGN.md +462 -0
  123. package/skills/fui-skill/design-md/supabase/README.md +5 -0
  124. package/skills/fui-skill/design-md/superhuman/DESIGN.md +448 -0
  125. package/skills/fui-skill/design-md/superhuman/README.md +5 -0
  126. package/skills/fui-skill/design-md/tesla/DESIGN.md +286 -0
  127. package/skills/fui-skill/design-md/tesla/README.md +5 -0
  128. package/skills/fui-skill/design-md/theverge/DESIGN.md +339 -0
  129. package/skills/fui-skill/design-md/theverge/README.md +5 -0
  130. package/skills/fui-skill/design-md/together.ai/DESIGN.md +633 -0
  131. package/skills/fui-skill/design-md/together.ai/README.md +5 -0
  132. package/skills/fui-skill/design-md/uber/DESIGN.md +636 -0
  133. package/skills/fui-skill/design-md/uber/README.md +5 -0
  134. package/skills/fui-skill/design-md/vercel/DESIGN.md +736 -0
  135. package/skills/fui-skill/design-md/vercel/README.md +5 -0
  136. package/skills/fui-skill/design-md/vodafone/DESIGN.md +538 -0
  137. package/skills/fui-skill/design-md/vodafone/README.md +5 -0
  138. package/skills/fui-skill/design-md/voltagent/DESIGN.md +521 -0
  139. package/skills/fui-skill/design-md/voltagent/README.md +5 -0
  140. package/skills/fui-skill/design-md/warp/DESIGN.md +526 -0
  141. package/skills/fui-skill/design-md/warp/README.md +5 -0
  142. package/skills/fui-skill/design-md/webflow/DESIGN.md +588 -0
  143. package/skills/fui-skill/design-md/webflow/README.md +5 -0
  144. package/skills/fui-skill/design-md/wired/DESIGN.md +497 -0
  145. package/skills/fui-skill/design-md/wired/README.md +5 -0
  146. package/skills/fui-skill/design-md/wise/DESIGN.md +544 -0
  147. package/skills/fui-skill/design-md/wise/README.md +5 -0
  148. package/skills/fui-skill/design-md/x.ai/DESIGN.md +465 -0
  149. package/skills/fui-skill/design-md/x.ai/README.md +5 -0
  150. package/skills/fui-skill/design-md/zapier/DESIGN.md +537 -0
  151. package/skills/fui-skill/design-md/zapier/README.md +5 -0
  152. package/skills/fui-skill/examples/component.vue +162 -0
  153. package/skills/fui-skill/examples/f-table-patterns.json +331 -0
  154. package/skills/fui-skill/examples/module-patterns.json +973 -0
  155. package/skills/fui-skill/examples/project-patterns.json +222 -0
  156. package/skills/fui-skill/metadata.json +75 -0
  157. package/skills/fui-skill/references/INDEX.md +144 -0
  158. package/skills/fui-skill/references/advanced-techniques.md +160 -0
  159. package/skills/fui-skill/references/coding-standards.md +112 -0
  160. package/skills/fui-skill/references/component-design.md +455 -0
  161. package/skills/fui-skill/references/component-quickref.md +77 -0
  162. package/skills/fui-skill/references/component-table.md +276 -0
  163. package/skills/fui-skill/references/components-dialog.md +192 -0
  164. package/skills/fui-skill/references/components-display.md +147 -0
  165. package/skills/fui-skill/references/components-echart.md +391 -0
  166. package/skills/fui-skill/references/components-input.md +359 -0
  167. package/skills/fui-skill/references/controls-patterns.md +847 -0
  168. package/skills/fui-skill/references/controls-styling-vocabulary.md +140 -0
  169. package/skills/fui-skill/references/db-table-design.md +77 -0
  170. package/skills/fui-skill/references/db-workflow.md +504 -0
  171. package/skills/fui-skill/references/default-function.md +415 -0
  172. package/skills/fui-skill/references/design-modes.md +85 -0
  173. package/skills/fui-skill/references/echart-templates.md +481 -0
  174. package/skills/fui-skill/references/fastproject.md +97 -0
  175. package/skills/fui-skill/references/fsheet.md +218 -0
  176. package/skills/fui-skill/references/fullstack-workflow.md +351 -0
  177. package/skills/fui-skill/references/module-data-patterns.md +126 -0
  178. package/skills/fui-skill/references/module-json-anatomy.md +137 -0
  179. package/skills/fui-skill/references/module-structure.md +260 -0
  180. package/skills/fui-skill/references/new-session.md +108 -0
  181. package/skills/fui-skill/references/pdfmake.md +60 -0
  182. package/skills/fui-skill/references/permission-system.md +169 -0
  183. package/skills/fui-skill/references/platform-architecture.md +294 -0
  184. package/skills/fui-skill/references/project-config.md +335 -0
  185. package/skills/fui-skill/references/project-provisioning.md +383 -0
  186. package/skills/fui-skill/references/script-map.md +296 -0
  187. package/skills/fui-skill/references/sql-clr-functions.md +224 -0
  188. package/skills/fui-skill/references/system-design.md +116 -0
  189. package/skills/fui-skill/references/tapi-file-api.md +191 -0
  190. package/skills/fui-skill/references/tapi-permission-patterns.md +158 -0
  191. package/skills/fui-skill/references/tapi-reference.md +549 -0
  192. package/skills/fui-skill/references/tools-registry.md +460 -0
  193. package/skills/fui-skill/references/ui-crosswindow-patterns.md +317 -0
  194. package/skills/fui-skill/references/ui-dialog-patterns.md +229 -0
  195. package/skills/fui-skill/references/ui-layout-patterns.md +176 -0
  196. package/skills/fui-skill/references/ui-patterns.md +315 -0
  197. package/skills/fui-skill/references/ui-screenshot-review.md +94 -0
  198. package/skills/fui-skill/references/ui-table-cell-patterns.md +316 -0
  199. package/skills/fui-skill/references/ui-templates.md +29 -0
  200. package/skills/fui-skill/references/verification.md +246 -0
  201. package/skills/fui-skill/references/watcher-patterns.md +196 -0
  202. package/skills/fui-skill/references/websocket-realtime.md +254 -0
  203. package/skills/fui-skill/scripts/component-3.0.js +2549 -0
  204. package/skills/fui-skill/scripts/component.js +3142 -0
  205. package/skills/fui-skill/scripts/componentTable-3.0.js +909 -0
  206. package/skills/fui-skill/scripts/componentTable.js +769 -0
  207. package/skills/fui-skill/scripts/defaultfunction-3.0.js +781 -0
  208. package/skills/fui-skill/scripts/defaultfunction.js +966 -0
  209. package/skills/fui-skill/scripts/fastproject-3.0.js +870 -0
  210. package/skills/fui-skill/scripts/fastproject.js +828 -0
  211. package/skills/fui-skill/scripts/fechart.js +890 -0
  212. package/skills/fui-skill/scripts/fsheet.js +1330 -0
@@ -0,0 +1,162 @@
1
+ <template>
2
+ <div class="uc-component-name">
3
+ <v-card outlined>
4
+ <v-card-title v-if="title" class="subtitle-1 font-weight-bold">
5
+ <slot name="title">
6
+ {{ title }}
7
+ </slot>
8
+ </v-card-title>
9
+
10
+ <v-card-text>
11
+ <div v-if="loading">
12
+ <slot name="loading">
13
+ Loading...
14
+ </slot>
15
+ </div>
16
+ <div v-else-if="!hasItems">
17
+ <slot name="empty">
18
+ No data
19
+ </slot>
20
+ </div>
21
+ <div v-else>
22
+ <slot :items="localItems" :selected-item="localValue">
23
+ <v-list dense>
24
+ <v-list-item
25
+ v-for="(item, index) in localItems"
26
+ :key="item.id || item.value || index"
27
+ @click="handleSelect(item)"
28
+ >
29
+ <v-list-item-content>
30
+ <v-list-item-title>{{ getItemLabel(item) }}</v-list-item-title>
31
+ </v-list-item-content>
32
+ </v-list-item>
33
+ </v-list>
34
+ </slot>
35
+
36
+ <v-btn
37
+ v-if="showAction"
38
+ small
39
+ color="primary"
40
+ :disabled="disabled"
41
+ @click="handleAction"
42
+ >
43
+ {{ actionLabel }}
44
+ </v-btn>
45
+ </div>
46
+ </v-card-text>
47
+ </v-card>
48
+ </div>
49
+ </template>
50
+
51
+ <script>
52
+ /**
53
+ * Description: Reusable starter component. Prefer generic props, emits, and slots.
54
+ * Usage: <uc-component-name :items="rows" :value="selectedRow" @select="handleSelect"></uc-component-name>
55
+ * NOTE: No "name:" property — FUI resolves name from filename automatically.
56
+ */
57
+ export default {
58
+ props: {
59
+ title: {
60
+ type: String,
61
+ default: ''
62
+ },
63
+ value: {
64
+ type: [String, Number, Object, Array],
65
+ default: null
66
+ },
67
+ items: {
68
+ type: Array,
69
+ default: function() {
70
+ return [];
71
+ }
72
+ },
73
+ itemText: {
74
+ type: String,
75
+ default: 'label'
76
+ },
77
+ loading: {
78
+ type: Boolean,
79
+ default: false
80
+ },
81
+ disabled: {
82
+ type: Boolean,
83
+ default: false
84
+ },
85
+ showAction: {
86
+ type: Boolean,
87
+ default: true
88
+ },
89
+ actionLabel: {
90
+ type: String,
91
+ default: 'Action'
92
+ },
93
+ options: {
94
+ type: Object,
95
+ default: function() {
96
+ return {};
97
+ }
98
+ }
99
+ },
100
+ data() {
101
+ return {
102
+ localValue: null,
103
+ localItems: []
104
+ }
105
+ },
106
+ computed: {
107
+ hasItems() {
108
+ return this.localItems.length > 0;
109
+ },
110
+ resolvedItemText() {
111
+ return this.options.itemText || this.itemText;
112
+ },
113
+ resolvedItemValue() {
114
+ return this.options.itemValue || 'value';
115
+ }
116
+ },
117
+ watch: {
118
+ value: {
119
+ handler(val) {
120
+ this.localValue = val;
121
+ },
122
+ immediate: true
123
+ },
124
+ items: {
125
+ handler(val) {
126
+ this.localItems = Array.isArray(val) ? val : [];
127
+ },
128
+ immediate: true
129
+ }
130
+ },
131
+ methods: {
132
+ getItemLabel(item) {
133
+ if (!item || typeof item !== 'object') {
134
+ return item;
135
+ }
136
+
137
+ return item[this.resolvedItemText] || item.label || item.name || '';
138
+ },
139
+ getItemValue(item) {
140
+ if (!item || typeof item !== 'object') {
141
+ return item;
142
+ }
143
+
144
+ return item[this.resolvedItemValue] || item.value || item.id || item;
145
+ },
146
+ handleSelect(item) {
147
+ var nextValue = this.getItemValue(item);
148
+ this.localValue = nextValue;
149
+ this.$emit('input', nextValue);
150
+ this.$emit('select', item);
151
+ this.$emit('change', nextValue);
152
+ },
153
+ handleAction() {
154
+ this.$emit('action', {
155
+ value: this.localValue,
156
+ items: this.localItems
157
+ });
158
+ }
159
+ }
160
+ }
161
+ </script>
162
+
@@ -0,0 +1,331 @@
1
+ {
2
+ "_comment": "f-table comprehensive reference — props, header types, and usage patterns. f-table dùng cho CẢ bảng CRUD lẫn bảng chỉ xem (readonly = không khai :update-api). Ưu tiên hơn v-data-table.",
3
+
4
+ "_default_attrs_auto": "FUI auto-inject các props sau (không cần khai báo lại): :dense true, :fixed-header true, :items-per-page 50, :hide-default-footer true, mobile-breakpoint 0.",
5
+
6
+ "_auto_headers": "Nếu KHÔNG truyền :headers, f-table tự build header từ row đầu tiên của items: mỗi key → cột { text: key, value: key, divider: true }, giá trị số tự gắn el t-num; có :update-api edit/delete → tự thêm cột ctrl-update. Rebuild khi items đổi. Chỉ dùng khi tên field từ API đã là label hiển thị được; cần label riêng / t-* renderer / width / ẩn cột → khai :headers tường minh.",
7
+
8
+ "_props_display": {
9
+ "label": "String — tiêu đề bảng hiển thị trong header",
10
+ ":items": "Array state — data source",
11
+ "item-key": "String — field làm unique key (bắt buộc khi dùng selection hoặc CRUD)",
12
+ ":items-per-page": "Number — -1 = tất cả rows, không phân trang. Default: 50",
13
+ ":fixed-header": "Boolean — sticky header khi scroll. Tự bật khi :height có hiệu lực, chỉ khai khi cần tắt",
14
+ ":hide-default-footer": "Boolean — ẩn footer pagination. Default: true",
15
+ "excel": "Boolean — nút xuất Excel. true = dùng tên file mặc định",
16
+ ":height": "Number — bỏ trống = tự giãn theo số dòng; <=0 = fill tới đáy màn hình chừa abs(n) px (bảng chính dùng -16, tự đo vị trí thật, tự theo dõi resize); >0 = px cố định (bảng trong dialog)",
17
+ "max-height": "Number — giới hạn chiều cao tối đa (dùng khi bảng nằm trong dialog)",
18
+ ":item-class": "Function string — class CSS cho row theo điều kiện. Ví dụ: 'item => item.Active==0 ? \"danger\" : \"\"'",
19
+ "sum-format": "STRING template — 1 dòng text tổng dưới bảng (v-card-actions, không thẳng cột): 'Tổng: [[DangKy]] | [[NhapHoc]]' — [[Field]] = sumBy(items, Field) format '0,0'. Attr KHÔNG có ':' prefix.",
20
+ ":sum-format": "OBJECT — hàng tổng THẬT trong bảng (slot body.append, thẳng theo từng cột): { \"DangKy\": \"0,0\", \"HocPhi\": \"0,0.0\" } — key = value của cột, value = numeral format riêng. Attr CÓ ':' prefix. User cần 'tổng theo cột / hàng tổng trong bảng' → dùng dạng này; cần 'dòng tóm tắt chung' → dạng string. KHÔNG tự dựng hàng tổng thủ công."
21
+ },
22
+
23
+ "_props_selection": {
24
+ ":show-select": "Boolean — hiện checkbox chọn row",
25
+ "v-model": "Array state variable — chứa các row đã chọn (dùng cùng :show-select)"
26
+ },
27
+
28
+ "_props_crud": {
29
+ ":disabled-update": "Boolean/Expression — ẩn nút thêm/sửa/xóa. Ví dụ: 'vueData.user.SystemRight!=9'",
30
+ ":update-form": "Array of Control Objects — form fields dùng trong dialog thêm mới / chỉnh sửa",
31
+ ":update-form-attr": "Object — cấu hình dialog form: { width: 700 }. Mặc định: auto width",
32
+ ":update-api": "Object — { default-item, new, edit, delete }. Bỏ key nào không cần"
33
+ },
34
+
35
+ "_header_column_fields": {
36
+ "text": "String — tiêu đề cột",
37
+ "value": "String — field name trong data item (dùng để bind dữ liệu)",
38
+ "align": "'left' | 'center' | 'right' — canh lề. Default: left",
39
+ "width": "String — '200px', '10%' — cố định độ rộng cột",
40
+ "divider": "Boolean true — đường kẻ dọc phân cách sau cột này",
41
+ "el": "Component — t-check | t-select | t-button | t-link | t-menu | v-chip-group | v-icon",
42
+ "attr": "Object — props của component el (khi có el)",
43
+ "innerHTML": "String/Array — nội dung (dùng cho v-icon, v-chip-group)"
44
+ },
45
+
46
+ "_header_types": {
47
+ "t-check": "Toggle boolean — on-icon/off-icon, action chain khi click",
48
+ "t-select": "Dropdown inline — edit ngay trong ô, thường có CONFIRM trước khi lưu",
49
+ "t-button": "Nút/icon — :color/:icon-text/:label có thể là expression động từ item",
50
+ "t-link": "Text dạng link — :url là expression, target là attr thường",
51
+ "t-menu": "Context menu — :items bind vào menuChucNang từ data[]",
52
+ "v-chip-group": "Hiển thị mảng tags — v-for v-chip bên trong innerHTML",
53
+ "v-icon": "Icon tĩnh hoặc có v-on:click — innerHTML là tên icon",
54
+ "divider": "{ divider: true } — đường kẻ phân cách nhóm cột (không phải component)"
55
+ },
56
+
57
+ "example_all_header_types": {
58
+ "_note": "f-table với đầy đủ các loại header — dùng làm tham chiếu khi chọn header type",
59
+ "el": "f-table",
60
+ "attr": {
61
+ "label": "Danh sách",
62
+ "item-key": "ID",
63
+ ":items": "dsItems",
64
+ "excel": true,
65
+ ":show-select": true,
66
+ "v-model": "sSelected",
67
+ ":item-class": "item => item.IsBlocked ? 'danger' : ''",
68
+ ":height": -16,
69
+ ":headers": [
70
+ { "text": "ID", "value": "ID", "align": "center", "width": "80px" },
71
+ { "text": "Tên", "value": "Name" },
72
+ {
73
+ "_note": "t-check — toggle boolean, action chain sau khi toggle",
74
+ "text": "Kích hoạt", "value": "Enable", "align": "center",
75
+ "el": "t-check",
76
+ "attr": {
77
+ "on-icon": "mdi-check", "off-icon": "mdi-lock",
78
+ ":action": [
79
+ { "API": "/EntitySetActive", "IN": { "ID": "item.ID" } },
80
+ { "dsItems": [] }, { "CALL": "getData" }
81
+ ]
82
+ }
83
+ },
84
+ {
85
+ "_note": "t-select — dropdown inline, CONFIRM trước khi lưu",
86
+ "text": "Phân loại", "value": "Level", "el": "t-select", "width": "200px",
87
+ "attr": {
88
+ ":items": "vueData.dsLevels", "item-text": "Note", "item-value": "Level",
89
+ ":action": [{
90
+ "CONFIRM": "Xác nhận thay đổi phân loại?",
91
+ "API": "/EntityUpdateLevel",
92
+ "IN": { "ID": "item.ID", "Level": "item.Level" },
93
+ "CALLBACK": { "MESS": "Cập nhật thành công." }
94
+ }]
95
+ }
96
+ },
97
+ {
98
+ "_note": "t-button — :color/:icon-text/:label động theo item data",
99
+ "text": "Chi tiết", "value": "SubCount", "align": "center", "el": "t-button",
100
+ "attr": {
101
+ ":color": "(item.SubCount > 0 ? 'primary' : 'red')",
102
+ ":icon-text": "`${item.SubCount > 0 ? 'mdi-check-bold' : 'mdi-lock'}`",
103
+ ":label": "item.SubCount",
104
+ ":action": [
105
+ { "sID": "item.ID" }, { "CALL": "getSubItems" }, { "dlSub": true }
106
+ ]
107
+ }
108
+ },
109
+ {
110
+ "_note": "t-link — text link, :url là expression từ item",
111
+ "text": "Trang", "value": "PageName", "el": "t-link",
112
+ "attr": { ":url": "item.pageUrl", "target": "_blank" }
113
+ },
114
+ {
115
+ "_note": "divider: true — đường kẻ dọc phân cách nhóm cột. Đặt trên cột đầu tiên của nhóm mới",
116
+ "divider": true, "text": "Thao tác tổng hợp", "value": "FunctionName",
117
+ "el": "v-chip-group",
118
+ "attr": { "column": true, "v-if": "item.FunctionName" },
119
+ "innerHTML": [{
120
+ "el": "v-chip",
121
+ "attr": {
122
+ ":small": true, "color": "primary", "outlined": "",
123
+ "v-for": "fn in item.FunctionName", ":key": "fn.ID",
124
+ "v-on:click": "vueData.dlFunc = true; CALL(setFunc(item, item.FunctionName));"
125
+ },
126
+ "innerHTML": "<div>{{fn.Code}}-{{fn.Name}}</div>"
127
+ }]
128
+ },
129
+ {
130
+ "_note": "v-icon với v-on:click — icon click để mở dialog hoặc gọi script function",
131
+ "text": " ", "value": "EditAction", "align": "center", "el": "v-icon",
132
+ "attr": {
133
+ "dense": "", "color": "primary",
134
+ "v-on:click": "vueData.dlEdit = true; CALL(setEditItem(item));"
135
+ },
136
+ "innerHTML": "mdi-folder-edit-outline"
137
+ },
138
+ {
139
+ "_note": "t-menu — context menu, :items bind menuChucNang từ data[]",
140
+ "el": "t-menu", "text": "Thao tác", "value": "Actions",
141
+ "width": "150px", "align": "center",
142
+ "attr": { ":items": "vueData.menuChucNang" }
143
+ }
144
+ ]
145
+ },
146
+ "w": 12
147
+ },
148
+
149
+ "example_crud_full": {
150
+ "_note": "ctrl-update đầy đủ: new + edit + delete + default-item + update-form-attr",
151
+ "el": "f-table",
152
+ "attr": {
153
+ "label": "Danh sách",
154
+ "item-key": "ID",
155
+ ":items": "dsItems",
156
+ ":disabled-update": "vueData.user.SystemRight!=9",
157
+ ":update-form-attr": { "width": 600 },
158
+ ":headers": [
159
+ { "text": "ID", "value": "ID" },
160
+ { "text": "Tên", "value": "Name" },
161
+ { "text": "Email", "value": "Email" },
162
+ { "text": "Cập nhật", "value": "ctrl-update", "align": "center" }
163
+ ],
164
+ ":update-form": [
165
+ {
166
+ "_note": "v-if: dialogModel=='new' — chỉ hiện field ID khi tạo mới",
167
+ "el": "v-text-field",
168
+ "attr": { "v-if": "dialogModel=='new'", "v-model": "ID", "label": "Mã" }
169
+ },
170
+ { "el": "v-text-field", "attr": { "v-model": "Name", "label": "Tên" } },
171
+ { "el": "v-text-field", "attr": { "v-model": "Email", "label": "Email", ":required": false } }
172
+ ],
173
+ ":update-api": {
174
+ "_note_default_item": "default-item: giá trị khởi tạo khi tạo mới. Có thể dùng state expression: 'CategoryID': 'sCategoryID'",
175
+ "default-item": { "ID": "", "Name": "", "Email": "" },
176
+ "new": {
177
+ "API": "/EntityInsert",
178
+ "IN": { "ID": "item.ID", "Name": "item.Name", "Email": "item.Email" },
179
+ "CALLBACK": { "CALL": "getData" }
180
+ },
181
+ "edit": {
182
+ "CONFIRM": "Xác nhận cập nhật?",
183
+ "API": "/EntityUpdate",
184
+ "IN": { "ID": "item.ID", "Name": "item.Name", "Email": "item.Email" },
185
+ "CALLBACK": { "CALL": "getData" }
186
+ },
187
+ "delete": {
188
+ "CONFIRM": "Xác nhận xóa <span style='color:red'>{{item.Name}}</span>?",
189
+ "API": "/EntityDelete",
190
+ "IN": { "ID": "item.ID" },
191
+ "CALLBACK": [{ "MESS": "Xóa thành công." }, { "CALL": "getData" }]
192
+ }
193
+ }
194
+ },
195
+ "w": 12
196
+ },
197
+
198
+ "example_default_item_only": {
199
+ "_note": ":update-api với CHỈ default-item — inject extra fields vào items khi load. Không có new/edit/delete",
200
+ "_use_case": "Khi items cần thêm field client-side mà server không trả về. Ví dụ: xAA[] cho v-chip-group, selected: false",
201
+ "el": "f-table",
202
+ "attr": {
203
+ "item-key": "ID",
204
+ ":items": "dsItems",
205
+ ":show-select": true,
206
+ "v-model": "sSelected",
207
+ ":headers": [
208
+ { "text": "ID", "value": "ID" },
209
+ { "text": "Tên", "value": "Name" },
210
+ { "text": "Tags", "value": "Tags", "el": "v-chip-group", "attr": { "v-model": "item.xAA", "column": true } }
211
+ ],
212
+ ":update-api": {
213
+ "_note": "Chỉ dùng default-item để inject xAA vào mỗi item — không có CRUD",
214
+ "default-item": { "xAA": [] }
215
+ }
216
+ }
217
+ },
218
+
219
+ "example_sum_row_in_table": {
220
+ "_note": ":sum-format dạng OBJECT — hàng tổng thật trong bảng, thẳng theo từng cột (body.append). Key = value cột, value = numeral format riêng từng cột",
221
+ "el": "f-table",
222
+ "w": 12,
223
+ "attr": {
224
+ "label": "Thống kê tuyển sinh",
225
+ ":items": "dsThongKe",
226
+ ":headers": [
227
+ { "text": "Ngành", "value": "TenNganh" },
228
+ { "text": "Đăng ký", "value": "DangKy", "el": "t-num" },
229
+ { "text": "Nhập học", "value": "NhapHoc", "el": "t-num" },
230
+ { "text": "Học phí", "value": "HocPhi", "el": "t-num" }
231
+ ],
232
+ ":sum-format": { "DangKy": "0,0", "NhapHoc": "0,0", "HocPhi": "0,0.0" }
233
+ }
234
+ },
235
+
236
+ "example_sum_text_line": {
237
+ "_note": "sum-format dạng STRING — 1 dòng text tổng dưới bảng (v-card-actions), không thẳng cột. Attr không có ':' prefix vì là string tĩnh",
238
+ "el": "f-table",
239
+ "w": 12,
240
+ "attr": {
241
+ "label": "Thống kê tuyển sinh",
242
+ ":items": "dsThongKe",
243
+ "sum-format": "Tổng đăng ký: [[DangKy]] | Nhập học: [[NhapHoc]]"
244
+ }
245
+ },
246
+
247
+ "example_in_dialog": {
248
+ "_note": "f-table trong dialog — add users pattern. v-toolbar thứ 2 làm filter bar trong dialog",
249
+ "el": "v-dialog",
250
+ "attr": { "v-model": "dlAddUser", "width": 800, "max-height": 800, ":scrollable": true },
251
+ "innerHTML": [{
252
+ "el": "v-card",
253
+ "attr": { "class": "pa-0" },
254
+ "innerHTML": [
255
+ {
256
+ "_note": "v-toolbar 1 — tiêu đề + nút đóng",
257
+ "el": "v-toolbar", "attr": { "dense": "", "flat": "" },
258
+ "innerHTML": [
259
+ { "el": "v-toolbar-title", "attr": {}, "innerHTML": "Thêm users" },
260
+ { "el": "v-spacer" },
261
+ { "el": "v-btn", "innerHTML": "<v-icon>mdi-close</v-icon>", "attr": { "icon": "", "v-on:click": "vueData.dlAddUser = false" } }
262
+ ],
263
+ "w": 12
264
+ },
265
+ {
266
+ "_note": "v-toolbar 2 — filter bar trong dialog. Dùng thay vì v-card-text + row riêng",
267
+ "el": "v-toolbar", "attr": { "dense": "", "flat": "" },
268
+ "innerHTML": [
269
+ {
270
+ "el": "v-select", "attr": {
271
+ "style": "width:300px", "v-model": "sDepartment",
272
+ "label": "Department", ":items": "dsDepartment",
273
+ "item-text": "DepartmentName", "item-value": "DepartmentID",
274
+ ":required": false
275
+ }
276
+ },
277
+ {
278
+ "el": "v-text-field", "attr": {
279
+ "class": "ml-2", "style": "width:150px",
280
+ "v-model": "sUserSearch", "label": "UserID", ":required": false
281
+ }
282
+ },
283
+ {
284
+ "el": "f-button", "attr": {
285
+ ":checkvalid": false, "color": "primary", "icon-text": "mdi-magnify",
286
+ ":action": [{ "CALL": "getUserByDept" }]
287
+ }
288
+ }
289
+ ],
290
+ "w": 12
291
+ },
292
+ {
293
+ "el": "v-card-text", "attr": { "class": "px-4" },
294
+ "innerHTML": [{
295
+ "_note": "f-table trong dialog — max-height thay vì :height để không tràn dialog",
296
+ "el": "f-table",
297
+ "attr": {
298
+ "label": "Danh sách users",
299
+ "item-key": "UserID",
300
+ ":items": "dsUserDept",
301
+ ":show-select": true,
302
+ "v-model": "sUserDeptSelected",
303
+ ":items-per-page": -1,
304
+ ":hide-default-footer": true,
305
+ "max-height": 400,
306
+ ":headers": [
307
+ { "text": "UserID", "value": "UserID" },
308
+ { "text": "Username", "value": "UserName" },
309
+ { "text": "Fullname", "value": "FullName" }
310
+ ]
311
+ },
312
+ "w": 12
313
+ }]
314
+ },
315
+ {
316
+ "el": "v-card-actions", "attr": {}, "w": 12,
317
+ "innerHTML": [
318
+ { "el": "v-spacer", "attr": {} },
319
+ {
320
+ "el": "f-button", "attr": {
321
+ ":checkvalid": false, "color": "primary", "label": "Save",
322
+ "icon-text": "mdi-content-save",
323
+ ":action": { "CALL": "addUsers" }
324
+ }
325
+ }
326
+ ]
327
+ }
328
+ ]
329
+ }]
330
+ }
331
+ }