@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.
Files changed (212) hide show
  1. package/README.md +18 -3
  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,481 @@
1
+ # f-echart — Chart Type Templates & Real-World Patterns
2
+
3
+ > File này sở hữu: **template `option` theo từng loại chart + pattern module.json đi kèm**. Import/props/config nền tảng xem [components-echart.md](components-echart.md).
4
+
5
+ Thư viện template cho từng loại biểu đồ + các pattern dùng `f-echart` trong module.json. Load file này khi đã biết cần vẽ loại chart nào.
6
+
7
+ > Nền tảng (import, props, config, theme, DataView, lỗi thường gặp): xem [components-echart.md](components-echart.md). **Luôn đọc file core trước** để biết cách import và cấu trúc `option`/`config`.
8
+
9
+ ---
10
+
11
+ ## Templates — Chart types
12
+
13
+ > Quy ước chung cho mọi template dưới đây: chỉ khai cạnh `grid` khi bố cục hoặc user yêu cầu khác mặc định; layout engine tự chừa chỗ theo title/legend. Cách phân biệt `grid` với `boundaryGap` và giá trị mặc định: [components-echart.md](components-echart.md) §Grid padding và boundaryGap. Legend khai kiểu `legend: {}` trong `option` sẽ **neo trên đầu** (dưới title); muốn nó xuống đáy thì `legend: { bottom: 0 }`, hoặc bật qua `config.legend: true` (mặc định của shortcut là đáy).
14
+
15
+ ### Bar chart
16
+
17
+ ```js
18
+ // script.js — callback sau fetch
19
+ vueData.chartOpt = {
20
+ xAxis: { type: 'category', data: d.data.map(r => r.thang) },
21
+ yAxis: { type: 'value' },
22
+ series: [{ type: 'bar', data: d.data.map(r => r.doanhThu), name: 'Doanh thu' }],
23
+ tooltip: { trigger: 'axis' },
24
+ legend: {}
25
+ };
26
+ vueData.rows = d.data;
27
+ ```
28
+
29
+ ### Line chart (có smooth)
30
+
31
+ ```js
32
+ vueData.chartOpt = {
33
+ xAxis: { type: 'category', data: d.data.map(r => r.thang) },
34
+ yAxis: { type: 'value' },
35
+ series: [{ type: 'line', data: d.data.map(r => r.val), smooth: true, areaStyle: {} }],
36
+ tooltip: { trigger: 'axis' }
37
+ };
38
+ ```
39
+
40
+ ### Multi-series + Dual Y-axis
41
+
42
+ ```js
43
+ vueData.chartOpt = {
44
+ xAxis: { type: 'category', data: d.data.map(r => r.thang) },
45
+ yAxis: [{ name: 'VNĐ' }, { name: '%', position: 'right' }],
46
+ series: [
47
+ { type: 'bar', name: 'Doanh thu', data: d.data.map(r => r.doanhThu), yAxisIndex: 0 },
48
+ { type: 'line', name: 'Tăng trưởng', data: d.data.map(r => r.tangTruong), yAxisIndex: 1, smooth: true }
49
+ ],
50
+ tooltip: { trigger: 'axis' },
51
+ legend: {}
52
+ };
53
+ ```
54
+
55
+ ### Stacked bar
56
+
57
+ ```js
58
+ vueData.chartOpt = {
59
+ xAxis: { type: 'category', data: d.data.map(r => r.thang) },
60
+ yAxis: { type: 'value' },
61
+ series: [
62
+ { type: 'bar', name: 'SP A', data: d.data.map(r => r.spA), stack: 'total' },
63
+ { type: 'bar', name: 'SP B', data: d.data.map(r => r.spB), stack: 'total' },
64
+ { type: 'bar', name: 'SP C', data: d.data.map(r => r.spC), stack: 'total' }
65
+ ],
66
+ tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
67
+ legend: {}
68
+ };
69
+ ```
70
+
71
+ ### Pie chart
72
+
73
+ ```js
74
+ vueData.chartOpt = {
75
+ series: [{
76
+ type: 'pie',
77
+ data: d.data.map(r => ({ name: r.khoa, value: r.soLuong })),
78
+ radius: '70%',
79
+ label: { formatter: '{b}: {d}%' }
80
+ }],
81
+ tooltip: { trigger: 'item' },
82
+ legend: { bottom: 0 }
83
+ };
84
+ ```
85
+
86
+ Doughnut: `radius: ['40%', '70%']`
87
+
88
+ ### Scatter plot
89
+
90
+ ```js
91
+ vueData.chartOpt = {
92
+ xAxis: { type: 'value', name: 'Điểm thi' },
93
+ yAxis: { type: 'value', name: 'GPA' },
94
+ series: [{ type: 'scatter', data: d.data.map(r => [r.diemThi, r.gpa, r.hoTen]), symbolSize: 8 }],
95
+ tooltip: {
96
+ formatter: p => `${p.value[2]}<br>Điểm: ${p.value[0]} — GPA: ${p.value[1]}`
97
+ }
98
+ };
99
+ ```
100
+
101
+ ### Gauge
102
+
103
+ ```js
104
+ vueData.chartOpt = {
105
+ series: [{
106
+ type: 'gauge',
107
+ min: 0, max: 100,
108
+ data: [{ value: vueData.cpuPercent, name: 'CPU %' }],
109
+ detail: { formatter: '{value}%' },
110
+ axisLabel: { color: 'auto' }
111
+ }],
112
+ tooltip: {}
113
+ };
114
+ ```
115
+
116
+ ### Radar
117
+
118
+ ```js
119
+ vueData.chartOpt = {
120
+ radar: {
121
+ indicator: [
122
+ { name: 'Toán', max: 10 }, { name: 'Lý', max: 10 },
123
+ { name: 'Hóa', max: 10 }, { name: 'Văn', max: 10 }, { name: 'Anh', max: 10 }
124
+ ]
125
+ },
126
+ series: [{
127
+ type: 'radar',
128
+ data: d.data.map(r => ({
129
+ name: r.hoTen,
130
+ value: [r.toan, r.ly, r.hoa, r.van, r.anh]
131
+ }))
132
+ }],
133
+ tooltip: {},
134
+ legend: {}
135
+ };
136
+ ```
137
+
138
+ ### Heatmap (Cartesian)
139
+
140
+ ```js
141
+ // data: [{x: 'Mon', y: '8h', value: 5}, ...]
142
+ const xData = [...new Set(d.data.map(r => r.x))];
143
+ const yData = [...new Set(d.data.map(r => r.y))];
144
+ vueData.chartOpt = {
145
+ xAxis: { type: 'category', data: xData },
146
+ yAxis: { type: 'category', data: yData },
147
+ visualMap: { min: 0, max: 10, calculable: true },
148
+ series: [{
149
+ type: 'heatmap',
150
+ data: d.data.map(r => [xData.indexOf(r.x), yData.indexOf(r.y), r.value])
151
+ }],
152
+ tooltip: {}
153
+ };
154
+ ```
155
+
156
+ ### Candlestick (OHLC)
157
+
158
+ ```js
159
+ vueData.chartOpt = {
160
+ xAxis: { type: 'category', data: d.data.map(r => r.date) },
161
+ yAxis: { type: 'value', scale: true },
162
+ series: [{
163
+ type: 'candlestick',
164
+ data: d.data.map(r => [r.open, r.close, r.low, r.high])
165
+ }],
166
+ tooltip: { trigger: 'axis' }
167
+ };
168
+ ```
169
+
170
+ ### Funnel
171
+
172
+ ```js
173
+ vueData.chartOpt = {
174
+ series: [{
175
+ type: 'funnel',
176
+ data: d.data.map(r => ({ name: r.buoc, value: r.soLuong })).sort((a, b) => b.value - a.value),
177
+ label: { formatter: '{b}: {d}%' }
178
+ }],
179
+ tooltip: { trigger: 'item' },
180
+ legend: {}
181
+ };
182
+ ```
183
+
184
+ ### Treemap
185
+
186
+ ```js
187
+ // data là hierarchical: { name, value, children: [...] }
188
+ vueData.chartOpt = {
189
+ series: [{
190
+ type: 'treemap',
191
+ data: vueData.budgetTree, // hierarchical array
192
+ roam: false,
193
+ leafDepth: 2,
194
+ label: { show: true }
195
+ }],
196
+ tooltip: {}
197
+ };
198
+ ```
199
+
200
+ ### Tree (org chart, org tree)
201
+
202
+ ```js
203
+ vueData.chartOpt = {
204
+ series: [{
205
+ type: 'tree',
206
+ data: [vueData.orgTree], // single root node
207
+ orient: 'TB', // 'LR' | 'TB' | 'RL' | 'BT'
208
+ expandAndCollapse: true,
209
+ initialTreeDepth: 2,
210
+ label: { position: 'top' },
211
+ leaves: { label: { position: 'bottom' } }
212
+ }],
213
+ tooltip: { trigger: 'item' }
214
+ };
215
+ ```
216
+
217
+ ### Sankey
218
+
219
+ ```js
220
+ // nodes: [{name: '...'}], links: [{source: '...', target: '...', value: N}]
221
+ vueData.chartOpt = {
222
+ series: [{
223
+ type: 'sankey',
224
+ data: vueData.sankeyNodes, // [{name: 'A'}, {name: 'B'}, ...]
225
+ links: vueData.sankeyLinks, // [{source: 'A', target: 'B', value: 5}, ...]
226
+ emphasis: { focus: 'adjacency' },
227
+ lineStyle: { color: 'gradient' }
228
+ }],
229
+ tooltip: { trigger: 'item' }
230
+ };
231
+ ```
232
+
233
+ ### Graph (network)
234
+
235
+ ```js
236
+ vueData.chartOpt = {
237
+ series: [{
238
+ type: 'graph',
239
+ layout: 'force', // 'force' | 'circular' | 'none'
240
+ data: vueData.nodes, // [{name, value, category}, ...]
241
+ links: vueData.edges, // [{source, target}, ...]
242
+ categories: vueData.categories, // [{name}, ...]
243
+ roam: true,
244
+ label: { show: true },
245
+ force: { repulsion: 1000 }
246
+ }],
247
+ legend: {},
248
+ tooltip: {}
249
+ };
250
+ ```
251
+
252
+ ### Calendar heatmap
253
+
254
+ ```js
255
+ // data: [{date: '2024-01-01', count: 5}, ...]
256
+ vueData.chartOpt = {
257
+ calendar: { range: '2024', cellSize: ['auto', 20] },
258
+ visualMap: { min: 0, max: 30, type: 'piecewise', orient: 'horizontal', left: 'center' },
259
+ series: [{
260
+ type: 'heatmap',
261
+ coordinateSystem: 'calendar',
262
+ data: d.data.map(r => [r.date, r.count])
263
+ }],
264
+ tooltip: { formatter: p => `${p.value[0]}: ${p.value[1]}` }
265
+ };
266
+ ```
267
+
268
+ ---
269
+
270
+ ## Zoom + Tooltip format
271
+
272
+ ```js
273
+ // Zoom (trong option)
274
+ vueData.chartOpt = {
275
+ ...baseOpt,
276
+ dataZoom: [{ type: 'inside' }, { type: 'slider', height: 20 }]
277
+ };
278
+ // Hoặc dùng config shortcut:
279
+ // config: { zoom: true }
280
+ ```
281
+
282
+ ```js
283
+ // Tooltip tiền tệ — dùng config shortcut
284
+ // config: { tooltipFormat: 'currency', symbol: '₫', decimals: 0 }
285
+
286
+ // Hoặc custom formatter trong option
287
+ tooltip: {
288
+ formatter: p => {
289
+ const fmt = FEchartFormatter.build('currency', { symbol: '₫', decimals: 0 });
290
+ return `${p.name}: ${fmt(p.value)}`;
291
+ }
292
+ }
293
+ ```
294
+
295
+ ---
296
+
297
+ ## Dataset + encode (khi cần map cột tùy ý)
298
+
299
+ ```js
300
+ // script.js — build option dùng dataset (không map thủ công)
301
+ vueData.chartOpt = {
302
+ dataset: { source: vueData.rows },
303
+ series: [
304
+ { type: 'bar', name: 'Doanh thu', encode: { x: 'thang', y: 'doanhThu' } },
305
+ { type: 'line', name: 'Chi phí', encode: { x: 'thang', y: 'chiPhi' }, yAxisIndex: 1 }
306
+ ],
307
+ xAxis: { type: 'category' },
308
+ yAxis: [{}, { position: 'right' }],
309
+ tooltip: { trigger: 'axis' }
310
+ };
311
+ ```
312
+
313
+ ---
314
+
315
+ ## Patterns thực tế
316
+
317
+ Hai pattern chính khi dùng `f-echart` trong module.json:
318
+
319
+ | Pattern | Khi nào dùng |
320
+ |---|---|
321
+ | **Inline** — viết `option` thẳng vào attr | Chart đơn giản, data đã có trong `vueData`, không cần biến trung gian |
322
+ | **vueData ref** — `option` build trong `script.js` | Data cần fetch từ API; option phức tạp; cần sort/transform trước khi render |
323
+
324
+ ---
325
+
326
+ ### Pattern 1 — Inline pie (không cần script.js)
327
+
328
+ Khi data đã có trong `vueData.rows`, viết `option` thẳng vào attr — không cần biến `chartOpt` hay script.js.
329
+
330
+ **module.json controls:**
331
+ ```json
332
+ {
333
+ "el": "f-echart", "w": "6",
334
+ "attr": {
335
+ ":config": "{ title: 'Cơ cấu sinh viên', height: 350 }",
336
+ ":option": "{
337
+ series: [{
338
+ type: 'pie',
339
+ data: vueData.rows.map(r => ({ name: r.khoa, value: r.soLuong })),
340
+ radius: ['40%', '70%'],
341
+ label: { formatter: '{b}: {d}%' }
342
+ }],
343
+ tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' },
344
+ legend: { bottom: 0 }
345
+ }"
346
+ }
347
+ }
348
+ ```
349
+
350
+ > `vueData.rows` phải được gán trước (ví dụ: từ callback fetch của control khác trong cùng module).
351
+
352
+ ---
353
+
354
+ ### Pattern 2 — Inline horizontal bar
355
+
356
+ Horizontal bar: đổi `xAxis`/`yAxis`, dùng `inverse: true` và `containLabel: true`.
357
+
358
+ **module.json controls:**
359
+ ```json
360
+ {
361
+ "el": "f-echart", "w": "12",
362
+ "attr": {
363
+ ":config": "{ height: Math.max(300, vueData.rows.length * 36) }",
364
+ ":option": "{
365
+ xAxis: { type: 'value' },
366
+ yAxis: {
367
+ type: 'category',
368
+ data: vueData.rows.map(r => r.tenKhoa),
369
+ inverse: true
370
+ },
371
+ grid: { containLabel: true },
372
+ series: [{
373
+ type: 'bar',
374
+ data: vueData.rows.map(r => r.soLuong),
375
+ name: 'Sinh viên',
376
+ label: { show: true, position: 'right' }
377
+ }],
378
+ tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } }
379
+ }"
380
+ }
381
+ }
382
+ ```
383
+
384
+ **Lưu ý:**
385
+ - `containLabel: true` trong `grid` — bắt buộc cho horizontal bar để nhãn `yAxis` không bị cắt.
386
+ - Chỉ khai cạnh `grid` khi user yêu cầu khác mặc định; xem [components-echart.md](components-echart.md) — "Grid padding và boundaryGap".
387
+ - `inverse: true` → item lớn nhất hiển thị ở trên cùng.
388
+ - `height: Math.max(300, rows.length * 36)` — tự co dãn theo số hàng.
389
+
390
+ ---
391
+
392
+ ### Pattern 3 — vueData ref + dynamic height (fetch từ API)
393
+
394
+ Dùng khi option phức tạp hoặc data cần fetch từ API riêng.
395
+
396
+ **module.json controls:**
397
+ ```json
398
+ {
399
+ "el": "f-echart", "w": "12",
400
+ "attr": {
401
+ ":config": "{ title: 'Doanh thu theo tháng', height: 400, dataView: true }",
402
+ ":option": "vueData.chartOpt"
403
+ }
404
+ }
405
+ ```
406
+
407
+ **script.js:**
408
+ ```js
409
+ // Trong callback fetch data
410
+ vueData.rows = d.data.slice().sort((a, b) => a.thang.localeCompare(b.thang));
411
+ vueData.chartOpt = {
412
+ xAxis: { type: 'category', data: vueData.rows.map(r => r.thang) },
413
+ yAxis: [
414
+ { type: 'value', name: 'Triệu đồng', axisLabel: { formatter: v => FEchartFormatter.formatShort(v) } },
415
+ { type: 'value', name: '%', position: 'right', max: 100 }
416
+ ],
417
+ series: [
418
+ { type: 'bar', name: 'Doanh thu', data: vueData.rows.map(r => r.doanhThu), yAxisIndex: 0 },
419
+ { type: 'line', name: 'Tăng trưởng', data: vueData.rows.map(r => r.tangTruong), yAxisIndex: 1, smooth: true }
420
+ ],
421
+ grid: { containLabel: true },
422
+ tooltip: { trigger: 'axis' },
423
+ legend: {}
424
+ };
425
+ ```
426
+
427
+ ---
428
+
429
+ ### Pattern 4 — Conditional option (null guard)
430
+
431
+ Khi option được build từ nhiều nguồn data, dùng điều kiện để tránh render chart với data rỗng.
432
+
433
+ **module.json controls:**
434
+ ```json
435
+ {
436
+ "el": "f-echart", "w": "12",
437
+ "attr": {
438
+ ":config": "{ height: 350 }",
439
+ ":option": "vueData.baseOpt ? Object.assign({}, vueData.baseOpt, { series: vueData.series }) : null"
440
+ }
441
+ }
442
+ ```
443
+
444
+ **script.js:**
445
+ ```js
446
+ // Base option — khởi tạo một lần
447
+ vueData.baseOpt = {
448
+ xAxis: { type: 'category', data: [] },
449
+ yAxis: { type: 'value' },
450
+ tooltip: { trigger: 'axis' },
451
+ legend: {},
452
+ grid: { containLabel: true }
453
+ };
454
+
455
+ // Khi fetch data xong — reactive update
456
+ vueData.baseOpt.xAxis.data = d.data.map(r => r.thang);
457
+ vueData.series = d.data.map((r, i) => ({
458
+ type: 'bar', name: r.name, data: r.values, stack: 'total'
459
+ }));
460
+ // Object.assign trong :option tạo object mới → Vue trigger re-render
461
+ ```
462
+
463
+ > `Object.assign({}, base, override)` trong `:option` expression — tạo object mới mỗi lần evaluate, đảm bảo Vue detect change.
464
+
465
+ ---
466
+
467
+ ### Pattern 5 — Chart không có DataView (phổ biến nhất)
468
+
469
+ Đa số chart production không cần DataView — bỏ `dataView` để gọn. Không cần `:data` prop (không tồn tại).
470
+
471
+ ```json
472
+ {
473
+ "el": "f-echart", "w": "6",
474
+ "attr": {
475
+ ":config": "{ height: 300 }",
476
+ ":option": "vueData.pieOpt"
477
+ }
478
+ }
479
+ ```
480
+
481
+ Chỉ thêm `dataView: true` vào config khi user cần xem bảng số liệu — DataView tự trích xuất từ `option`.
@@ -0,0 +1,97 @@
1
+ # FastProject (Core Framework)
2
+
3
+ > File này sở hữu: **bootstrapper `fastproject.js`: vòng đời khởi tạo project/module**. Bản đồ toàn bộ script xem [script-map.md](script-map.md).
4
+
5
+ This document references the core framework logic defined in `fastproject.js`. This script is responsible for initializing the application, building the UI from JSON configurations, and handling the logic engine.
6
+
7
+ ## Global State
8
+
9
+ ### vueData
10
+ The central reactive state object for the application.
11
+ - `p_domain`, `p_routers`, `p_params`: Routing and environment info.
12
+ - `user`: Current user information.
13
+ - `v_Set`: Application settings (title, menu, attributes).
14
+ - `v_Loading`: Global loading state.
15
+
16
+ ### vueOBJ
17
+ The Vue instance configuration object.
18
+
19
+ ## Core Functions
20
+
21
+ ### loadModuleInfo()
22
+ Initializes the module by:
23
+ 1. Loading project and module settings.
24
+ 2. Building URL parameters.
25
+ 3. Fetching user info (if configured).
26
+ 4. Calling `createModuleDom()`.
27
+
28
+ ### createModuleDom()
29
+ Builds the Vue application structure:
30
+ 1. Executes initial data actions (`$moduleUI.data`).
31
+ 2. Generates the HTML structure using `buildModuleUI`.
32
+ 3. Initializes Vue watchers and WebSocket connections.
33
+ 4. Mounts the Vue instance.
34
+
35
+ ### buildModuleUI(controlsList, target)
36
+ Recursively builds the DOM structure from a JSON list of controls.
37
+ - **Parameters:**
38
+ - `controlsList` (Array): List of control definitions.
39
+ - `target` (Object): Target object for data binding (usually `vueData`).
40
+ - **Returns:** jQuery object containing the generated HTML.
41
+
42
+ ### buildControl(controlsList, flex, target)
43
+ Helper function for `buildModuleUI` to generate individual controls.
44
+ - Supports grid layout (`v-layout`, `v-flex`) and nested components.
45
+ - Handles attribute binding and event mapping.
46
+
47
+ ### runAction(obj, includeData)
48
+ The central logic engine. Executes a sequence of actions defined in JSON.
49
+ - **Parameters:**
50
+ - `obj` (Object|Array): The action(s) to execute.
51
+ - `includeData` (Object): Context data.
52
+ - **Supported Action Types:**
53
+ - `CONFIRM`: Show confirmation dialog.
54
+ - `API`: Call an API.
55
+ - `CALL`: Recursive call to another action.
56
+ - `EXE`: Execute raw JavaScript.
57
+ - `FUN`: Call a global function.
58
+ - `IF/THEN/ELSE`: Conditional logic.
59
+ - `MESS`/`MESSBOX`: Show messages.
60
+ - `IN`/`OUT`: Data mapping.
61
+
62
+ ### vueAction(objAction, includeData, callBack)
63
+ Internal function used by `runAction` to execute a single action step.
64
+
65
+ ### callAPI(objApi, callBack, includeData)
66
+ Executes an API call defined in a JSON action object.
67
+ - Handles `BEFORE`, `AFTER` actions, and success/error callbacks.
68
+ - Automatically maps response data to `vueData` if `OUT` is specified.
69
+
70
+ ### mapData(map, target, src, includeData)
71
+ Maps data from a source object to a target object based on a mapping definition.
72
+ - Supports cross-window data mapping using `#PARENT` or window IDs.
73
+ - **Parameters:**
74
+ - `map` (Object|String): Mapping definition.
75
+ - `target` (Object): Destination object.
76
+ - `src` (Object): Source object.
77
+
78
+ ### getVueData(key, src)
79
+ Resolves a value from a key string, supporting deep paths and template syntax (e.g., `{{user.Name}}`).
80
+
81
+ ### bindData(obj)
82
+ Resolves all dynamic values within an object.
83
+
84
+ ### createWatch(obj)
85
+ Sets up Vue watchers based on a JSON configuration.
86
+ - Supports deep watching.
87
+ - Executes actions when watched values change.
88
+
89
+ ### loginFUN()
90
+ Handles user login redirection.
91
+ - Opens a login window or redirects to the login page.
92
+
93
+ ### errorMess(code, message)
94
+ Displays standard error messages based on HTTP status codes.
95
+ - **Parameters:**
96
+ - `code` (String|Number): HTTP status code.
97
+ - `message` (String): Custom error message.