@fui-org/fui-cli 2.1.4 → 2.2.1
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 +16 -7
- package/dist/fui-xg17j3f9.js +396 -0
- package/dist/fui.js +1 -1
- package/package.json +1 -1
- package/skills/fui/SKILL.md +152 -39
- package/skills/{fui-skill → fui}/assets/projectdefaultstyle.css +489 -489
- package/skills/{fui-skill → fui}/examples/component.vue +162 -162
- package/skills/{fui-skill → fui}/references/INDEX.md +4 -5
- package/skills/{fui-skill → fui}/references/advanced-techniques.md +170 -168
- package/skills/{fui-skill → fui}/references/component-design.md +2 -2
- package/skills/{fui-skill → fui}/references/component-quickref.md +78 -78
- package/skills/{fui-skill → fui}/references/component-table.md +287 -287
- package/skills/{fui-skill → fui}/references/components-dialog.md +191 -191
- package/skills/{fui-skill → fui}/references/components-display.md +141 -141
- package/skills/{fui-skill → fui}/references/components-echart.md +316 -316
- package/skills/{fui-skill → fui}/references/components-input.md +335 -335
- package/skills/{fui-skill → fui}/references/controls-patterns.md +2 -2
- package/skills/{fui-skill → fui}/references/controls-styling-vocabulary.md +173 -173
- package/skills/{fui-skill → fui}/references/db-workflow.md +9 -9
- package/skills/{fui-skill → fui}/references/default-function.md +456 -456
- package/skills/{fui-skill → fui}/references/design-modes.md +57 -57
- package/skills/{fui-skill → fui}/references/echart-templates.md +489 -489
- package/skills/{fui-skill → fui}/references/fastproject.md +99 -99
- package/skills/{fui-skill → fui}/references/fullstack-workflow.md +314 -313
- package/skills/{fui-skill → fui}/references/module-data-patterns.md +117 -117
- package/skills/{fui-skill → fui}/references/module-json-anatomy.md +132 -132
- package/skills/{fui-skill → fui}/references/module-structure.md +144 -144
- package/skills/{fui-skill → fui}/references/new-session.md +3 -20
- package/skills/{fui-skill → fui}/references/pdfmake.md +60 -60
- package/skills/{fui-skill → fui}/references/permission-system.md +1 -1
- package/skills/{fui-skill → fui}/references/platform-architecture.md +269 -269
- package/skills/{fui-skill → fui}/references/project-config.md +303 -303
- package/skills/{fui-skill → fui}/references/project-provisioning.md +4 -4
- package/skills/{fui-skill → fui}/references/script-map.md +262 -262
- package/skills/{fui-skill → fui}/references/sql-clr-functions.md +225 -225
- package/skills/{fui-skill → fui}/references/system-design.md +3 -3
- package/skills/{fui-skill → fui}/references/tapi-permission-patterns.md +156 -156
- package/skills/{fui-skill → fui}/references/tapi-reference.md +474 -474
- package/skills/fui/references/tools-registry.md +214 -0
- package/skills/{fui-skill → fui}/references/ui-crosswindow-patterns.md +321 -321
- package/skills/{fui-skill → fui}/references/ui-dialog-patterns.md +255 -255
- package/skills/{fui-skill → fui}/references/ui-layout-patterns.md +176 -176
- package/skills/{fui-skill → fui}/references/ui-patterns.md +303 -303
- package/skills/{fui-skill → fui}/references/ui-screenshot-review.md +95 -95
- package/skills/{fui-skill → fui}/references/ui-table-cell-patterns.md +318 -318
- package/skills/{fui-skill → fui}/references/verification.md +18 -18
- package/skills/{fui-skill → fui}/references/watcher-patterns.md +163 -163
- package/skills/{fui-skill → fui}/references/websocket-realtime.md +271 -271
- package/skills/{fui-skill → fui}/scripts/component-3.0.js +2715 -2715
- package/skills/{fui-skill → fui}/scripts/component.js +3147 -3147
- package/skills/{fui-skill → fui}/scripts/componentTable-3.0.js +1038 -1038
- package/skills/{fui-skill → fui}/scripts/componentTable.js +891 -891
- package/skills/{fui-skill → fui}/scripts/defaultfunction-3.0.js +866 -866
- package/skills/{fui-skill → fui}/scripts/defaultfunction.js +1051 -1051
- package/skills/{fui-skill → fui}/scripts/fastproject-3.0.js +870 -870
- package/skills/{fui-skill → fui}/scripts/fastproject.js +828 -828
- package/dist/fui-h4z7zhk2.js +0 -381
- package/skills/fui-skill/SKILL.md +0 -139
- package/skills/fui-skill/references/tools-registry.md +0 -84
- /package/skills/{fui-skill → fui}/assets/projectdefaultstyle-3.0.css +0 -0
- /package/skills/{fui-skill → fui}/design-md/airbnb/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/airbnb/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/airtable/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/airtable/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/apple/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/apple/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/asu/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/asu/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/binance/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/binance/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/bmw/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/bmw/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/bmw-m/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/bmw-m/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/bugatti/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/bugatti/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/cal/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/cal/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/claude/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/claude/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/clay/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/clay/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/clickhouse/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/clickhouse/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/cohere/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/cohere/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/coinbase/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/coinbase/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/composio/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/composio/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/cursor/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/cursor/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/elevenlabs/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/elevenlabs/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/expo/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/expo/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/ferrari/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/ferrari/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/figma/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/figma/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/framer/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/framer/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/fui/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/hashicorp/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/hashicorp/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/ibm/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/ibm/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/intercom/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/intercom/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/kraken/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/kraken/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/lamborghini/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/lamborghini/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/linear.app/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/linear.app/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/lovable/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/lovable/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mastercard/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mastercard/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/meta/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/meta/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/minimax/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/minimax/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mintlify/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mintlify/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/miro/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/miro/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mistral.ai/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mistral.ai/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mongodb/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mongodb/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/nike/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/nike/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/notion/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/notion/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/nvidia/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/nvidia/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/ollama/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/ollama/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/opencode.ai/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/opencode.ai/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/pinterest/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/pinterest/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/playstation/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/playstation/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/posthog/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/posthog/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/raycast/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/raycast/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/renault/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/renault/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/replicate/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/replicate/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/resend/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/resend/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/revolut/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/revolut/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/runwayml/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/runwayml/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/sanity/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/sanity/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/sentry/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/sentry/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/shopify/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/shopify/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/slack/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/spacex/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/spacex/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/spotify/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/spotify/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/starbucks/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/starbucks/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/stripe/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/stripe/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/supabase/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/supabase/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/superhuman/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/superhuman/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/tesla/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/tesla/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/theverge/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/theverge/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/together.ai/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/together.ai/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/uber/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/uber/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/vercel/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/vercel/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/vodafone/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/vodafone/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/voltagent/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/voltagent/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/warp/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/warp/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/webflow/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/webflow/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/wired/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/wired/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/wise/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/wise/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/x.ai/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/x.ai/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/zapier/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/zapier/README.md +0 -0
- /package/skills/{fui-skill → fui}/examples/f-table-patterns.json +0 -0
- /package/skills/{fui-skill → fui}/examples/module-patterns.json +0 -0
- /package/skills/{fui-skill → fui}/examples/project-patterns.json +0 -0
- /package/skills/{fui-skill → fui}/references/coding-standards.md +0 -0
- /package/skills/{fui-skill → fui}/references/db-table-design.md +0 -0
- /package/skills/{fui-skill → fui}/references/fsheet.md +0 -0
- /package/skills/{fui-skill → fui}/references/tapi-file-api.md +0 -0
- /package/skills/{fui-skill → fui}/references/ui-templates.md +0 -0
- /package/skills/{fui-skill → fui}/scripts/fechart.js +0 -0
- /package/skills/{fui-skill → fui}/scripts/fsheet.js +0 -0
|
@@ -1,456 +1,456 @@
|
|
|
1
|
-
# Default Functions
|
|
2
|
-
|
|
3
|
-
> Owns: **FUI utility functions usable in `FUN`/`EXE`/`script.js`** (openWindow, ajaxCALL, jsonToExcel, groupBy...). Source locations: [script-map.md](script-map.md).
|
|
4
|
-
|
|
5
|
-
Globals defined in `defaultfunction.js`, auto-loaded in every FUI V2 module.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Global Variables
|
|
10
|
-
|
|
11
|
-
| Variable | Meaning |
|
|
12
|
-
| ----------- | ------------------------------------------- |
|
|
13
|
-
| `$isMobile` | `true` if mobile user agent |
|
|
14
|
-
| `$isPhone` | `true` if phone (not tablet) |
|
|
15
|
-
| `$isApple` | `true` if Apple device (iPad, iPhone, iPod) |
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
## Dialogs & Messages
|
|
20
|
-
|
|
21
|
-
### confirm(obj)
|
|
22
|
-
|
|
23
|
-
Styled OK/Cancel dialog; wraps `$.confirm` (jquery-confirm).
|
|
24
|
-
|
|
25
|
-
| Param | Meaning |
|
|
26
|
-
| --------- | --------------------------------------------------------- |
|
|
27
|
-
| `title` | Title |
|
|
28
|
-
| `message` | Body |
|
|
29
|
-
| `action` | Function run on OK |
|
|
30
|
-
| `cancel` | Function run on Cancel (optional) |
|
|
31
|
-
| `type` | Color: `'blue'` (default), `'red'`, `'green'`, `'orange'` |
|
|
32
|
-
| `icon` | Icon class, e.g. `'mdi mdi-delete'` |
|
|
33
|
-
|
|
34
|
-
```js
|
|
35
|
-
confirm({
|
|
36
|
-
title: "Xác nhận xóa",
|
|
37
|
-
message: "Bạn có chắc muốn xóa bản ghi này không?",
|
|
38
|
-
type: "red",
|
|
39
|
-
icon: "mdi mdi-delete",
|
|
40
|
-
action: function () {
|
|
41
|
-
CALL(vueData.actDelete);
|
|
42
|
-
},
|
|
43
|
-
});
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
### showMessage(obj)
|
|
49
|
-
|
|
50
|
-
Message dialog (Close button only); wraps `$.dialog`.
|
|
51
|
-
|
|
52
|
-
| Param | Meaning |
|
|
53
|
-
| --------- | ----------------------------------- |
|
|
54
|
-
| `title` | Title |
|
|
55
|
-
| `message` | Body |
|
|
56
|
-
| `type` | Color: `'blue'`, `'red'`, `'green'` |
|
|
57
|
-
| `icon` | Icon class |
|
|
58
|
-
| `onclose` | FUI action object run after close |
|
|
59
|
-
|
|
60
|
-
```js
|
|
61
|
-
showMessage({ title: "Thông báo", message: "Lưu thành công!" });
|
|
62
|
-
|
|
63
|
-
showMessage({
|
|
64
|
-
title: "Lỗi",
|
|
65
|
-
message: "Không tìm thấy dữ liệu",
|
|
66
|
-
type: "red",
|
|
67
|
-
icon: "mdi mdi-alert-circle",
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
// Chạy action sau khi đóng
|
|
71
|
-
showMessage({
|
|
72
|
-
title: "Hoàn tất",
|
|
73
|
-
message: "Import xong!",
|
|
74
|
-
onclose: vueData.actReload,
|
|
75
|
-
});
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
---
|
|
79
|
-
|
|
80
|
-
## Navigation & Window
|
|
81
|
-
|
|
82
|
-
### pushRouter(router)
|
|
83
|
-
|
|
84
|
-
Updates the browser URL without reload — sync URL with UI state.
|
|
85
|
-
|
|
86
|
-
```js
|
|
87
|
-
pushRouter("/fp/don-hang/danh-sach");
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
---
|
|
91
|
-
|
|
92
|
-
### openWindow(obj)
|
|
93
|
-
|
|
94
|
-
Opens an FUI window (`f-window`) overlay.
|
|
95
|
-
|
|
96
|
-
| Param | Meaning |
|
|
97
|
-
| -------- | --------------------------------------------------------- |
|
|
98
|
-
| `url` | Content URL (required) |
|
|
99
|
-
| `title` | Window title |
|
|
100
|
-
| `id` | Identifier (auto if omitted) — prevents duplicate windows |
|
|
101
|
-
| `width` | Width (px or %) |
|
|
102
|
-
| `height` | Height |
|
|
103
|
-
|
|
104
|
-
```js
|
|
105
|
-
// Cách đơn giản — chỉ truyền URL
|
|
106
|
-
openWindow("/fp/san-pham/chi-tiet?id=123");
|
|
107
|
-
|
|
108
|
-
// Đầy đủ options
|
|
109
|
-
openWindow({
|
|
110
|
-
id: "winChiTiet",
|
|
111
|
-
url: "/fp/san-pham/chi-tiet?id=" + vueData.selectedId,
|
|
112
|
-
title: "Chi tiết sản phẩm",
|
|
113
|
-
width: "80%",
|
|
114
|
-
});
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
> Called inside an `f-window` (iframe) → FUI switches to `windowSendMessage('#PARENT', 'openWindow', obj)` to open in the parent.
|
|
118
|
-
|
|
119
|
-
---
|
|
120
|
-
|
|
121
|
-
### redirect(obj, query)
|
|
122
|
-
|
|
123
|
-
Navigates the current page to another URL.
|
|
124
|
-
|
|
125
|
-
```js
|
|
126
|
-
redirect("/fp/trang-chu");
|
|
127
|
-
redirect({ url: "/fp/don-hang", query: true }); // giữ lại query params hiện tại
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
---
|
|
131
|
-
|
|
132
|
-
### reload()
|
|
133
|
-
|
|
134
|
-
Reloads the page.
|
|
135
|
-
|
|
136
|
-
```js
|
|
137
|
-
reload();
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
---
|
|
141
|
-
|
|
142
|
-
### windowSendMessage(window, cmd, data)
|
|
143
|
-
|
|
144
|
-
`postMessage` to another window/iframe — communication between `f-window`s.
|
|
145
|
-
|
|
146
|
-
| Param | Meaning |
|
|
147
|
-
| -------- | ----------------------------------------------------------------- |
|
|
148
|
-
| `window` | Window object, `'#PARENT'` (parent), or `'#iframeId'` (iframe ID) |
|
|
149
|
-
| `cmd` | Command name |
|
|
150
|
-
| `data` | Payload |
|
|
151
|
-
|
|
152
|
-
```js
|
|
153
|
-
// Gửi lên cửa sổ cha
|
|
154
|
-
windowSendMessage("#PARENT", "refreshData", { id: vueData.selectedId });
|
|
155
|
-
|
|
156
|
-
// Gửi đến iframe có id="iframeChild"
|
|
157
|
-
windowSendMessage("#iframeChild", "loadItem", { itemId: 5 });
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
---
|
|
161
|
-
|
|
162
|
-
## AJAX
|
|
163
|
-
|
|
164
|
-
### ajaxCALL(URL, DATA, callBack, errorCallBack, header)
|
|
165
|
-
|
|
166
|
-
AJAX POST. Pass only the path — domain is added via `fixURL`.
|
|
167
|
-
|
|
168
|
-
```js
|
|
169
|
-
ajaxCALL("/SP_GetDonHang", { maKH: vueData.maKH }, function (res) {
|
|
170
|
-
vueData.danhSach = res.data;
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
// Với error handler
|
|
174
|
-
ajaxCALL(
|
|
175
|
-
"/SP_SaveDonHang",
|
|
176
|
-
vueData.form,
|
|
177
|
-
function (res) {
|
|
178
|
-
Vue.$toast.success("Lưu thành công", { position: "top" });
|
|
179
|
-
},
|
|
180
|
-
function (err) {
|
|
181
|
-
showMessage({ title: "Lỗi", message: err.message, type: "red" });
|
|
182
|
-
},
|
|
183
|
-
);
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
---
|
|
187
|
-
|
|
188
|
-
## File Export
|
|
189
|
-
|
|
190
|
-
### jsonToExcel(Obj)
|
|
191
|
-
|
|
192
|
-
Exports JSON to `.xlsx`. Auto-loads ExcelJS.
|
|
193
|
-
|
|
194
|
-
**Single sheet:**
|
|
195
|
-
|
|
196
|
-
```js
|
|
197
|
-
jsonToExcel({
|
|
198
|
-
data: vueData.danhSach, // Array of objects
|
|
199
|
-
filename: "danh-sach.xlsx",
|
|
200
|
-
worksheet: "DanhSach",
|
|
201
|
-
});
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
**Multi sheet:**
|
|
205
|
-
|
|
206
|
-
```js
|
|
207
|
-
jsonToExcel({
|
|
208
|
-
filename: "bao-cao.xlsx",
|
|
209
|
-
sheets: [
|
|
210
|
-
{ name: "Sheet1", data: vueData.list1 },
|
|
211
|
-
{ name: "Sheet2", data: vueData.list2 },
|
|
212
|
-
],
|
|
213
|
-
});
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
Without `columns`, the columns are the keys of the **first row**, headers are the key names, values are raw. A field missing from the first row is missing from the whole file.
|
|
217
|
-
|
|
218
|
-
**Pick columns, headers and formats — `columns`** (`f-table excel="UI"` also uses `columns`, but only `header`/`key`, no formatting):
|
|
219
|
-
|
|
220
|
-
```js
|
|
221
|
-
jsonToExcel({
|
|
222
|
-
data: vueData.dsHang, // the original array of objects — no need to map each row
|
|
223
|
-
filename: "kho.xlsx",
|
|
224
|
-
worksheet: "Kho",
|
|
225
|
-
columns: [
|
|
226
|
-
{ header: "Tên hàng", key: "Ten" },
|
|
227
|
-
{ header: "Số lượng", key: "SoLuong", type: "number", numFmt: "#,##0", sum: true },
|
|
228
|
-
{ header: "Thành tiền", key: "ThanhTien", type: "number", numFmt: "#,##0.00", sum: "#,##0" },
|
|
229
|
-
{ header: "Ngày nhập", key: "NgayNhap", type: "date", numFmt: "dd/mm/yyyy" },
|
|
230
|
-
{ header: "Ghi chú", key: "GhiChuHtml", type: "html", width: 40 },
|
|
231
|
-
],
|
|
232
|
-
});
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
| Field | Meaning |
|
|
236
|
-
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
237
|
-
| `header` | Column title. May repeat (two "Tổng" columns do not overwrite each other) |
|
|
238
|
-
| `key` | Row field; nested paths `a.b` are supported |
|
|
239
|
-
| `type` | `'number'`: numeric string → number. `'date'`: ISO/`yyyy-mm-dd` string → real date in **local time** (no one-day shift from UTC). `'html'`: strip tags, keep text. Omitted: as is (object/array → JSON string) |
|
|
240
|
-
| `numFmt` | **Excel** format code (not numeral/moment): `#,##0`, `#,##0.00`, `0.0%`, `dd/mm/yyyy hh:mm`. `'#,##0;-#,##0;'` hides zeros but keeps the value |
|
|
241
|
-
| `width` | Width in characters; omitted, it is estimated from the first 100 rows |
|
|
242
|
-
| `sum` | `true` or a numFmt → adds a total row at the end of the sheet with a `SUM` formula over the exported rows |
|
|
243
|
-
|
|
244
|
-
- With `columns`, the header row is bold and frozen. Each sheet in `sheets` can have its own `columns`: `{ name, data, columns }`.
|
|
245
|
-
- Only fields listed in `columns` go into the file. This is the clean export (no IDs or technical fields leak) and it is lighter than mapping to a new array of objects just to rename keys.
|
|
246
|
-
|
|
247
|
-
---
|
|
248
|
-
|
|
249
|
-
## Data Utilities
|
|
250
|
-
|
|
251
|
-
### groupBy(arrayObj, groupField, sumArr)
|
|
252
|
-
|
|
253
|
-
Groups objects by a field and sums numeric columns; returns grouped array with `count`.
|
|
254
|
-
|
|
255
|
-
```js
|
|
256
|
-
// groupBy(data, 'Khoa', ['SLNghiHoc', 'SLTotNghiep'])
|
|
257
|
-
var result = groupBy(vueData.data, "phongBan", ["soLuong", "doanhThu"]);
|
|
258
|
-
// result: [{ phongBan: 'A', soLuong: 10, doanhThu: 5000, count: 3 }, ...]
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
> For complex grouping use Lodash `_.groupBy`.
|
|
262
|
-
|
|
263
|
-
---
|
|
264
|
-
|
|
265
|
-
### findInArray(obj)
|
|
266
|
-
|
|
267
|
-
Finds an element by condition.
|
|
268
|
-
|
|
269
|
-
```js
|
|
270
|
-
var item = findInArray({ array: vueData.list, value: { id: 5 } });
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
> Usually prefer the shorter Lodash `_.find(array, condition)`.
|
|
274
|
-
|
|
275
|
-
---
|
|
276
|
-
|
|
277
|
-
### fillData(obj)
|
|
278
|
-
|
|
279
|
-
Copies data from a source array into a target object by key and mapping.
|
|
280
|
-
|
|
281
|
-
- **Parameters:** `{ src, des, key, map }` — src: source array, des: target object, key: matching value, map: field mapping
|
|
282
|
-
|
|
283
|
-
---
|
|
284
|
-
|
|
285
|
-
### buildHeader(obj, mapCol)
|
|
286
|
-
|
|
287
|
-
Builds `headers` for `f-table` from data. No `mapCol` → headers from the first record's keys (numeric columns get `el: 't-num'`); with `mapCol` → mapped from `{ text, value }`.
|
|
288
|
-
|
|
289
|
-
```js
|
|
290
|
-
// Tự dựng header từ dữ liệu API
|
|
291
|
-
vueData.headers = buildHeader(vueData.dsData);
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
### capacityText(numb)
|
|
295
|
-
|
|
296
|
-
Bytes → size string (`'1.5 Mb'`, `'320 Kb'`) for file sizes.
|
|
297
|
-
|
|
298
|
-
### appCommand(cmdData)
|
|
299
|
-
|
|
300
|
-
Sends a command to the native app (React Native / iOS webkit / Android) when FUI is embedded in a mobile app.
|
|
301
|
-
|
|
302
|
-
---
|
|
303
|
-
|
|
304
|
-
## PDF
|
|
305
|
-
|
|
306
|
-
### printPDF(obj)
|
|
307
|
-
|
|
308
|
-
Builds and prints/downloads a PDF with `pdfMake`. Auto-loads pdfMake.
|
|
309
|
-
|
|
310
|
-
```js
|
|
311
|
-
printPDF({
|
|
312
|
-
data: docDefinition, // pdfMake docDefinition object
|
|
313
|
-
download: true, // true = tải file, false = mở viewer
|
|
314
|
-
callBack: function () {
|
|
315
|
-
console.log("Done");
|
|
316
|
-
},
|
|
317
|
-
});
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
---
|
|
321
|
-
|
|
322
|
-
## Clipboard & String
|
|
323
|
-
|
|
324
|
-
### copyToClipboard(textToCopy)
|
|
325
|
-
|
|
326
|
-
Copies to clipboard; uses `navigator.clipboard` when available (HTTPS), else `execCommand`.
|
|
327
|
-
|
|
328
|
-
```js
|
|
329
|
-
copyToClipboard(vueData.maHoaDon);
|
|
330
|
-
copyToClipboard(JSON.stringify(vueData.data));
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
---
|
|
334
|
-
|
|
335
|
-
### fileNameClear(fname)
|
|
336
|
-
|
|
337
|
-
Strips special characters from a file name (keeps letters, digits, spaces, dashes).
|
|
338
|
-
|
|
339
|
-
```js
|
|
340
|
-
var safeName = fileNameClear(vueData.tenFile); // "report (2025)!" → "report 2025"
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
---
|
|
344
|
-
|
|
345
|
-
### hashCode(s)
|
|
346
|
-
|
|
347
|
-
Integer hash of a string (for unique keys).
|
|
348
|
-
|
|
349
|
-
```js
|
|
350
|
-
var key = hashCode("unique-string-" + Date.now());
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
---
|
|
354
|
-
|
|
355
|
-
### generateID()
|
|
356
|
-
|
|
357
|
-
Random string ID.
|
|
358
|
-
|
|
359
|
-
```js
|
|
360
|
-
var newId = "win_" + generateID();
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
---
|
|
364
|
-
|
|
365
|
-
## Cookie & Auth
|
|
366
|
-
|
|
367
|
-
### getCookie(cname) / setCookie(name, value, days, domain)
|
|
368
|
-
|
|
369
|
-
Read/write browser cookies.
|
|
370
|
-
|
|
371
|
-
```js
|
|
372
|
-
var token = getCookie("awt");
|
|
373
|
-
setCookie("theme", "dark", 30); // hết hạn sau 30 ngày
|
|
374
|
-
setCookie("lang", "vi", 365, ".fui.vn"); // share cookie toàn domain
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
---
|
|
378
|
-
|
|
379
|
-
### logout(cookiesName, domain, url)
|
|
380
|
-
|
|
381
|
-
Clears the cookie and redirects to login.
|
|
382
|
-
|
|
383
|
-
```js
|
|
384
|
-
logout(); // xóa cookie 'awt', redirect về login mặc định
|
|
385
|
-
logout("myToken", ".fui.vn", "/login");
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
---
|
|
389
|
-
|
|
390
|
-
## Permissions
|
|
391
|
-
|
|
392
|
-
### rightTest(rightObject)
|
|
393
|
-
|
|
394
|
-
Checks whether the current user has the required rights, against `vueData.user`.
|
|
395
|
-
|
|
396
|
-
```js
|
|
397
|
-
// Kiểm tra user có role 'admin' hoặc 'manager'
|
|
398
|
-
if (rightTest({ role: ['admin', 'manager'] })) {
|
|
399
|
-
vueData.showDelete = true;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
// Kiểm tra nhiều điều kiện cùng lúc (AND)
|
|
403
|
-
if (rightTest({ dept: 'IT', level: [1, 2] })) { ... }
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
---
|
|
407
|
-
|
|
408
|
-
## Color Utilities
|
|
409
|
-
|
|
410
|
-
### colorLib(color)
|
|
411
|
-
|
|
412
|
-
Color utility (hex, rgb, hsl), mostly for charts.
|
|
413
|
-
|
|
414
|
-
```js
|
|
415
|
-
var c = colorLib("#4e73df");
|
|
416
|
-
c.hexString(); // '#4e73df'
|
|
417
|
-
c.rgbString(); // 'rgb(78, 115, 223)'
|
|
418
|
-
c.lighten(0.2); // làm sáng 20%
|
|
419
|
-
c.darken(0.1); // làm tối 10%
|
|
420
|
-
c.alpha(0.5).rgbString(); // 'rgba(78, 115, 223, 0.5)'
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
### transparentize(value, opacity)
|
|
424
|
-
|
|
425
|
-
Shortcut for a transparent color.
|
|
426
|
-
|
|
427
|
-
```js
|
|
428
|
-
transparentize("#4e73df", 0.5); // 'rgba(78, 115, 223, 0.5)'
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
---
|
|
432
|
-
|
|
433
|
-
## Script Loader
|
|
434
|
-
|
|
435
|
-
### loadScripts(scriptsArray, callbackFunc)
|
|
436
|
-
|
|
437
|
-
Loads scripts by URL, then runs the callback — on-demand libraries.
|
|
438
|
-
|
|
439
|
-
```js
|
|
440
|
-
loadScripts(["/include/pdfmake/pdfmake.min.js", "/include/pdfmake/vfs_fonts.js"], function () {
|
|
441
|
-
printPDF({ data: docDef, download: true });
|
|
442
|
-
});
|
|
443
|
-
```
|
|
444
|
-
|
|
445
|
-
---
|
|
446
|
-
|
|
447
|
-
## Device Detection
|
|
448
|
-
|
|
449
|
-
### extractHostname(url) / getDomainWithoutSubdomain(url)
|
|
450
|
-
|
|
451
|
-
Extract hostname/domain from a URL. Internal; rarely used directly.
|
|
452
|
-
|
|
453
|
-
```js
|
|
454
|
-
extractHostname("https://api.fui.vn/fp/test"); // 'api.fui.vn'
|
|
455
|
-
getDomainWithoutSubdomain("https://api.fui.vn"); // 'fui.vn'
|
|
456
|
-
```
|
|
1
|
+
# Default Functions
|
|
2
|
+
|
|
3
|
+
> Owns: **FUI utility functions usable in `FUN`/`EXE`/`script.js`** (openWindow, ajaxCALL, jsonToExcel, groupBy...). Source locations: [script-map.md](script-map.md).
|
|
4
|
+
|
|
5
|
+
Globals defined in `defaultfunction.js`, auto-loaded in every FUI V2 module.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Global Variables
|
|
10
|
+
|
|
11
|
+
| Variable | Meaning |
|
|
12
|
+
| ----------- | ------------------------------------------- |
|
|
13
|
+
| `$isMobile` | `true` if mobile user agent |
|
|
14
|
+
| `$isPhone` | `true` if phone (not tablet) |
|
|
15
|
+
| `$isApple` | `true` if Apple device (iPad, iPhone, iPod) |
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Dialogs & Messages
|
|
20
|
+
|
|
21
|
+
### confirm(obj)
|
|
22
|
+
|
|
23
|
+
Styled OK/Cancel dialog; wraps `$.confirm` (jquery-confirm).
|
|
24
|
+
|
|
25
|
+
| Param | Meaning |
|
|
26
|
+
| --------- | --------------------------------------------------------- |
|
|
27
|
+
| `title` | Title |
|
|
28
|
+
| `message` | Body |
|
|
29
|
+
| `action` | Function run on OK |
|
|
30
|
+
| `cancel` | Function run on Cancel (optional) |
|
|
31
|
+
| `type` | Color: `'blue'` (default), `'red'`, `'green'`, `'orange'` |
|
|
32
|
+
| `icon` | Icon class, e.g. `'mdi mdi-delete'` |
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
confirm({
|
|
36
|
+
title: "Xác nhận xóa",
|
|
37
|
+
message: "Bạn có chắc muốn xóa bản ghi này không?",
|
|
38
|
+
type: "red",
|
|
39
|
+
icon: "mdi mdi-delete",
|
|
40
|
+
action: function () {
|
|
41
|
+
CALL(vueData.actDelete);
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
### showMessage(obj)
|
|
49
|
+
|
|
50
|
+
Message dialog (Close button only); wraps `$.dialog`.
|
|
51
|
+
|
|
52
|
+
| Param | Meaning |
|
|
53
|
+
| --------- | ----------------------------------- |
|
|
54
|
+
| `title` | Title |
|
|
55
|
+
| `message` | Body |
|
|
56
|
+
| `type` | Color: `'blue'`, `'red'`, `'green'` |
|
|
57
|
+
| `icon` | Icon class |
|
|
58
|
+
| `onclose` | FUI action object run after close |
|
|
59
|
+
|
|
60
|
+
```js
|
|
61
|
+
showMessage({ title: "Thông báo", message: "Lưu thành công!" });
|
|
62
|
+
|
|
63
|
+
showMessage({
|
|
64
|
+
title: "Lỗi",
|
|
65
|
+
message: "Không tìm thấy dữ liệu",
|
|
66
|
+
type: "red",
|
|
67
|
+
icon: "mdi mdi-alert-circle",
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Chạy action sau khi đóng
|
|
71
|
+
showMessage({
|
|
72
|
+
title: "Hoàn tất",
|
|
73
|
+
message: "Import xong!",
|
|
74
|
+
onclose: vueData.actReload,
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Navigation & Window
|
|
81
|
+
|
|
82
|
+
### pushRouter(router)
|
|
83
|
+
|
|
84
|
+
Updates the browser URL without reload — sync URL with UI state.
|
|
85
|
+
|
|
86
|
+
```js
|
|
87
|
+
pushRouter("/fp/don-hang/danh-sach");
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
### openWindow(obj)
|
|
93
|
+
|
|
94
|
+
Opens an FUI window (`f-window`) overlay.
|
|
95
|
+
|
|
96
|
+
| Param | Meaning |
|
|
97
|
+
| -------- | --------------------------------------------------------- |
|
|
98
|
+
| `url` | Content URL (required) |
|
|
99
|
+
| `title` | Window title |
|
|
100
|
+
| `id` | Identifier (auto if omitted) — prevents duplicate windows |
|
|
101
|
+
| `width` | Width (px or %) |
|
|
102
|
+
| `height` | Height |
|
|
103
|
+
|
|
104
|
+
```js
|
|
105
|
+
// Cách đơn giản — chỉ truyền URL
|
|
106
|
+
openWindow("/fp/san-pham/chi-tiet?id=123");
|
|
107
|
+
|
|
108
|
+
// Đầy đủ options
|
|
109
|
+
openWindow({
|
|
110
|
+
id: "winChiTiet",
|
|
111
|
+
url: "/fp/san-pham/chi-tiet?id=" + vueData.selectedId,
|
|
112
|
+
title: "Chi tiết sản phẩm",
|
|
113
|
+
width: "80%",
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
> Called inside an `f-window` (iframe) → FUI switches to `windowSendMessage('#PARENT', 'openWindow', obj)` to open in the parent.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
### redirect(obj, query)
|
|
122
|
+
|
|
123
|
+
Navigates the current page to another URL.
|
|
124
|
+
|
|
125
|
+
```js
|
|
126
|
+
redirect("/fp/trang-chu");
|
|
127
|
+
redirect({ url: "/fp/don-hang", query: true }); // giữ lại query params hiện tại
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
### reload()
|
|
133
|
+
|
|
134
|
+
Reloads the page.
|
|
135
|
+
|
|
136
|
+
```js
|
|
137
|
+
reload();
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
### windowSendMessage(window, cmd, data)
|
|
143
|
+
|
|
144
|
+
`postMessage` to another window/iframe — communication between `f-window`s.
|
|
145
|
+
|
|
146
|
+
| Param | Meaning |
|
|
147
|
+
| -------- | ----------------------------------------------------------------- |
|
|
148
|
+
| `window` | Window object, `'#PARENT'` (parent), or `'#iframeId'` (iframe ID) |
|
|
149
|
+
| `cmd` | Command name |
|
|
150
|
+
| `data` | Payload |
|
|
151
|
+
|
|
152
|
+
```js
|
|
153
|
+
// Gửi lên cửa sổ cha
|
|
154
|
+
windowSendMessage("#PARENT", "refreshData", { id: vueData.selectedId });
|
|
155
|
+
|
|
156
|
+
// Gửi đến iframe có id="iframeChild"
|
|
157
|
+
windowSendMessage("#iframeChild", "loadItem", { itemId: 5 });
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## AJAX
|
|
163
|
+
|
|
164
|
+
### ajaxCALL(URL, DATA, callBack, errorCallBack, header)
|
|
165
|
+
|
|
166
|
+
AJAX POST. Pass only the path — domain is added via `fixURL`.
|
|
167
|
+
|
|
168
|
+
```js
|
|
169
|
+
ajaxCALL("/SP_GetDonHang", { maKH: vueData.maKH }, function (res) {
|
|
170
|
+
vueData.danhSach = res.data;
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Với error handler
|
|
174
|
+
ajaxCALL(
|
|
175
|
+
"/SP_SaveDonHang",
|
|
176
|
+
vueData.form,
|
|
177
|
+
function (res) {
|
|
178
|
+
Vue.$toast.success("Lưu thành công", { position: "top" });
|
|
179
|
+
},
|
|
180
|
+
function (err) {
|
|
181
|
+
showMessage({ title: "Lỗi", message: err.message, type: "red" });
|
|
182
|
+
},
|
|
183
|
+
);
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## File Export
|
|
189
|
+
|
|
190
|
+
### jsonToExcel(Obj)
|
|
191
|
+
|
|
192
|
+
Exports JSON to `.xlsx`. Auto-loads ExcelJS.
|
|
193
|
+
|
|
194
|
+
**Single sheet:**
|
|
195
|
+
|
|
196
|
+
```js
|
|
197
|
+
jsonToExcel({
|
|
198
|
+
data: vueData.danhSach, // Array of objects
|
|
199
|
+
filename: "danh-sach.xlsx",
|
|
200
|
+
worksheet: "DanhSach",
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Multi sheet:**
|
|
205
|
+
|
|
206
|
+
```js
|
|
207
|
+
jsonToExcel({
|
|
208
|
+
filename: "bao-cao.xlsx",
|
|
209
|
+
sheets: [
|
|
210
|
+
{ name: "Sheet1", data: vueData.list1 },
|
|
211
|
+
{ name: "Sheet2", data: vueData.list2 },
|
|
212
|
+
],
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Without `columns`, the columns are the keys of the **first row**, headers are the key names, values are raw. A field missing from the first row is missing from the whole file.
|
|
217
|
+
|
|
218
|
+
**Pick columns, headers and formats — `columns`** (`f-table excel="UI"` also uses `columns`, but only `header`/`key`, no formatting):
|
|
219
|
+
|
|
220
|
+
```js
|
|
221
|
+
jsonToExcel({
|
|
222
|
+
data: vueData.dsHang, // the original array of objects — no need to map each row
|
|
223
|
+
filename: "kho.xlsx",
|
|
224
|
+
worksheet: "Kho",
|
|
225
|
+
columns: [
|
|
226
|
+
{ header: "Tên hàng", key: "Ten" },
|
|
227
|
+
{ header: "Số lượng", key: "SoLuong", type: "number", numFmt: "#,##0", sum: true },
|
|
228
|
+
{ header: "Thành tiền", key: "ThanhTien", type: "number", numFmt: "#,##0.00", sum: "#,##0" },
|
|
229
|
+
{ header: "Ngày nhập", key: "NgayNhap", type: "date", numFmt: "dd/mm/yyyy" },
|
|
230
|
+
{ header: "Ghi chú", key: "GhiChuHtml", type: "html", width: 40 },
|
|
231
|
+
],
|
|
232
|
+
});
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
| Field | Meaning |
|
|
236
|
+
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
237
|
+
| `header` | Column title. May repeat (two "Tổng" columns do not overwrite each other) |
|
|
238
|
+
| `key` | Row field; nested paths `a.b` are supported |
|
|
239
|
+
| `type` | `'number'`: numeric string → number. `'date'`: ISO/`yyyy-mm-dd` string → real date in **local time** (no one-day shift from UTC). `'html'`: strip tags, keep text. Omitted: as is (object/array → JSON string) |
|
|
240
|
+
| `numFmt` | **Excel** format code (not numeral/moment): `#,##0`, `#,##0.00`, `0.0%`, `dd/mm/yyyy hh:mm`. `'#,##0;-#,##0;'` hides zeros but keeps the value |
|
|
241
|
+
| `width` | Width in characters; omitted, it is estimated from the first 100 rows |
|
|
242
|
+
| `sum` | `true` or a numFmt → adds a total row at the end of the sheet with a `SUM` formula over the exported rows |
|
|
243
|
+
|
|
244
|
+
- With `columns`, the header row is bold and frozen. Each sheet in `sheets` can have its own `columns`: `{ name, data, columns }`.
|
|
245
|
+
- Only fields listed in `columns` go into the file. This is the clean export (no IDs or technical fields leak) and it is lighter than mapping to a new array of objects just to rename keys.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Data Utilities
|
|
250
|
+
|
|
251
|
+
### groupBy(arrayObj, groupField, sumArr)
|
|
252
|
+
|
|
253
|
+
Groups objects by a field and sums numeric columns; returns grouped array with `count`.
|
|
254
|
+
|
|
255
|
+
```js
|
|
256
|
+
// groupBy(data, 'Khoa', ['SLNghiHoc', 'SLTotNghiep'])
|
|
257
|
+
var result = groupBy(vueData.data, "phongBan", ["soLuong", "doanhThu"]);
|
|
258
|
+
// result: [{ phongBan: 'A', soLuong: 10, doanhThu: 5000, count: 3 }, ...]
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
> For complex grouping use Lodash `_.groupBy`.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
### findInArray(obj)
|
|
266
|
+
|
|
267
|
+
Finds an element by condition.
|
|
268
|
+
|
|
269
|
+
```js
|
|
270
|
+
var item = findInArray({ array: vueData.list, value: { id: 5 } });
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
> Usually prefer the shorter Lodash `_.find(array, condition)`.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
### fillData(obj)
|
|
278
|
+
|
|
279
|
+
Copies data from a source array into a target object by key and mapping.
|
|
280
|
+
|
|
281
|
+
- **Parameters:** `{ src, des, key, map }` — src: source array, des: target object, key: matching value, map: field mapping
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
### buildHeader(obj, mapCol)
|
|
286
|
+
|
|
287
|
+
Builds `headers` for `f-table` from data. No `mapCol` → headers from the first record's keys (numeric columns get `el: 't-num'`); with `mapCol` → mapped from `{ text, value }`.
|
|
288
|
+
|
|
289
|
+
```js
|
|
290
|
+
// Tự dựng header từ dữ liệu API
|
|
291
|
+
vueData.headers = buildHeader(vueData.dsData);
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### capacityText(numb)
|
|
295
|
+
|
|
296
|
+
Bytes → size string (`'1.5 Mb'`, `'320 Kb'`) for file sizes.
|
|
297
|
+
|
|
298
|
+
### appCommand(cmdData)
|
|
299
|
+
|
|
300
|
+
Sends a command to the native app (React Native / iOS webkit / Android) when FUI is embedded in a mobile app.
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## PDF
|
|
305
|
+
|
|
306
|
+
### printPDF(obj)
|
|
307
|
+
|
|
308
|
+
Builds and prints/downloads a PDF with `pdfMake`. Auto-loads pdfMake.
|
|
309
|
+
|
|
310
|
+
```js
|
|
311
|
+
printPDF({
|
|
312
|
+
data: docDefinition, // pdfMake docDefinition object
|
|
313
|
+
download: true, // true = tải file, false = mở viewer
|
|
314
|
+
callBack: function () {
|
|
315
|
+
console.log("Done");
|
|
316
|
+
},
|
|
317
|
+
});
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Clipboard & String
|
|
323
|
+
|
|
324
|
+
### copyToClipboard(textToCopy)
|
|
325
|
+
|
|
326
|
+
Copies to clipboard; uses `navigator.clipboard` when available (HTTPS), else `execCommand`.
|
|
327
|
+
|
|
328
|
+
```js
|
|
329
|
+
copyToClipboard(vueData.maHoaDon);
|
|
330
|
+
copyToClipboard(JSON.stringify(vueData.data));
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
### fileNameClear(fname)
|
|
336
|
+
|
|
337
|
+
Strips special characters from a file name (keeps letters, digits, spaces, dashes).
|
|
338
|
+
|
|
339
|
+
```js
|
|
340
|
+
var safeName = fileNameClear(vueData.tenFile); // "report (2025)!" → "report 2025"
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
### hashCode(s)
|
|
346
|
+
|
|
347
|
+
Integer hash of a string (for unique keys).
|
|
348
|
+
|
|
349
|
+
```js
|
|
350
|
+
var key = hashCode("unique-string-" + Date.now());
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
### generateID()
|
|
356
|
+
|
|
357
|
+
Random string ID.
|
|
358
|
+
|
|
359
|
+
```js
|
|
360
|
+
var newId = "win_" + generateID();
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## Cookie & Auth
|
|
366
|
+
|
|
367
|
+
### getCookie(cname) / setCookie(name, value, days, domain)
|
|
368
|
+
|
|
369
|
+
Read/write browser cookies.
|
|
370
|
+
|
|
371
|
+
```js
|
|
372
|
+
var token = getCookie("awt");
|
|
373
|
+
setCookie("theme", "dark", 30); // hết hạn sau 30 ngày
|
|
374
|
+
setCookie("lang", "vi", 365, ".fui.vn"); // share cookie toàn domain
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
### logout(cookiesName, domain, url)
|
|
380
|
+
|
|
381
|
+
Clears the cookie and redirects to login.
|
|
382
|
+
|
|
383
|
+
```js
|
|
384
|
+
logout(); // xóa cookie 'awt', redirect về login mặc định
|
|
385
|
+
logout("myToken", ".fui.vn", "/login");
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
## Permissions
|
|
391
|
+
|
|
392
|
+
### rightTest(rightObject)
|
|
393
|
+
|
|
394
|
+
Checks whether the current user has the required rights, against `vueData.user`.
|
|
395
|
+
|
|
396
|
+
```js
|
|
397
|
+
// Kiểm tra user có role 'admin' hoặc 'manager'
|
|
398
|
+
if (rightTest({ role: ['admin', 'manager'] })) {
|
|
399
|
+
vueData.showDelete = true;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Kiểm tra nhiều điều kiện cùng lúc (AND)
|
|
403
|
+
if (rightTest({ dept: 'IT', level: [1, 2] })) { ... }
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
## Color Utilities
|
|
409
|
+
|
|
410
|
+
### colorLib(color)
|
|
411
|
+
|
|
412
|
+
Color utility (hex, rgb, hsl), mostly for charts.
|
|
413
|
+
|
|
414
|
+
```js
|
|
415
|
+
var c = colorLib("#4e73df");
|
|
416
|
+
c.hexString(); // '#4e73df'
|
|
417
|
+
c.rgbString(); // 'rgb(78, 115, 223)'
|
|
418
|
+
c.lighten(0.2); // làm sáng 20%
|
|
419
|
+
c.darken(0.1); // làm tối 10%
|
|
420
|
+
c.alpha(0.5).rgbString(); // 'rgba(78, 115, 223, 0.5)'
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### transparentize(value, opacity)
|
|
424
|
+
|
|
425
|
+
Shortcut for a transparent color.
|
|
426
|
+
|
|
427
|
+
```js
|
|
428
|
+
transparentize("#4e73df", 0.5); // 'rgba(78, 115, 223, 0.5)'
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
## Script Loader
|
|
434
|
+
|
|
435
|
+
### loadScripts(scriptsArray, callbackFunc)
|
|
436
|
+
|
|
437
|
+
Loads scripts by URL, then runs the callback — on-demand libraries.
|
|
438
|
+
|
|
439
|
+
```js
|
|
440
|
+
loadScripts(["/include/pdfmake/pdfmake.min.js", "/include/pdfmake/vfs_fonts.js"], function () {
|
|
441
|
+
printPDF({ data: docDef, download: true });
|
|
442
|
+
});
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
## Device Detection
|
|
448
|
+
|
|
449
|
+
### extractHostname(url) / getDomainWithoutSubdomain(url)
|
|
450
|
+
|
|
451
|
+
Extract hostname/domain from a URL. Internal; rarely used directly.
|
|
452
|
+
|
|
453
|
+
```js
|
|
454
|
+
extractHostname("https://api.fui.vn/fp/test"); // 'api.fui.vn'
|
|
455
|
+
getDomainWithoutSubdomain("https://api.fui.vn"); // 'fui.vn'
|
|
456
|
+
```
|