mvframe 1.1.15 → 1.1.17

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.
@@ -19,6 +19,7 @@ alwaysApply: true
19
19
  | 方法 | 用途 |
20
20
  |------|------|
21
21
  | `$getImg(url)` | 获取图片 URL,支持相对路径和 `/` 开头绝对路径 |
22
+ | `$l(key, vars?)` | 多语言文案;`vars` 支持 `{name}` 变量占位替换 |
22
23
  | `$getLang()` | 获取当前语言 |
23
24
  | `$d` | **dayjs**:`globalThis.$d` 与默认导出一致;`$d()`、`$d(ts)`、`$d().format(...)`、`$d().add(n, 'day')` 等,勿在业务中重复 `import dayjs`(插件仅在应用入口统一 `extend`) |
24
25
  | `$md5(v)` | 提取数字并拼接(简易 md5) |
@@ -46,6 +47,7 @@ alwaysApply: true
46
47
  ## 使用建议
47
48
 
48
49
  - 直接调用全局方法即可,无需在业务代码中 import util
50
+ - 多语言变量统一使用 `$l("helloUser", { name: userName })`,字典文案写作 `"Hello {name}"`;变量名仅使用字母、数字、下划线、点、短横线或 `$`,缺失变量会保留原 `{name}` 占位
49
51
  - 新增工具方法时,应挂载到 `globalThis` 并补充到本 rules
50
52
 
51
53
  ## 全局封装方法的注释规范
package/README.cn.md CHANGED
@@ -189,12 +189,17 @@ yarn notify
189
189
  # 或发布包命令
190
190
  yarn exec mvframe-notify
191
191
 
192
- # 同时启动 yarn dev 与通知服务
192
+ # 启动 MVFrame 封装的 Vite dev
193
193
  yarn d
194
194
  # 或发布包命令
195
195
  yarn exec mvframe-d
196
+
197
+ # 同时启动 Vite dev 与通知服务
198
+ yarn exec mvframe-d -n
196
199
  ```
197
200
 
201
+ `mvframe-d` 默认只启动封装后的 Vite dev server;追加 `-n` / `--notify` 时才启动通知服务。通知服务启动失败只打印异常,不会停止 Vite。
202
+
198
203
  服务读取宿主项目根目录的 `.env.mvframe-notify`(可用 `--env` 指定):
199
204
 
200
205
  ```env
@@ -265,7 +270,7 @@ await notify("需要发送到钉钉的消息");
265
270
 
266
271
  ## 命令行:项目目录雏形(推荐)
267
272
 
268
- 在**空目录或已有 Vite 工程根目录**执行,生成 `src/views`、`src/component`、`src/api`、`src/assets/img`、`src/assets/style`、`src/router`、`src/pinia/chip`、`src/config` 及示例 `main.js` / `App.vue`(已 `app.use(mvframe, …)` 挂好路由、Pinia `storeChips`、config,并写入 `components.async: ["VTable"]`),同时写入/更新宿主项目 **`AGENTS.md`** 的 MVFrame Codex 规则,其中包含 **每次 AI 完成开发后执行 `yarn exec mvframe-notify --once --message "..."` 发送完成通知** 的要求,并复制 **`/.cursor/rules/*.mdc`**(与 mvframe 仓库内 Cursor 规则一致)。若不存在则附带 `index.html` 与 `vite.config.js`。会**合并** `package.json` 的 `scripts` / `dependencies` / `devDependencies`(与 Vite 模板一致;**同名脚本和包保留你原有值**),初始化 `.env.mvframe-notify.example` / `.env.local.example` 与 `config.notify`,并自动执行 **`yarn install`**,最后请执行 **`yarn dev`**;需要同时启动通知服务时显式执行 **`yarn exec mvframe-d`**。加 `--no-package-json` 可不改动 `package.json` 且跳过安装。
273
+ 在**空目录或已有 Vite 工程根目录**执行,生成 `src/views`、`src/component`、`src/api`、`src/assets/img`、`src/assets/style`、`src/router`、`src/pinia/chip`、`src/config` 及示例 `main.js` / `App.vue`(已 `app.use(mvframe, …)` 挂好路由、Pinia `storeChips`、config,并写入 `components.async: ["VTable"]`),同时写入/更新宿主项目 **`AGENTS.md`** 的 MVFrame Codex 规则,其中包含 **每次 AI 完成开发后执行 `yarn exec mvframe-notify --once --message "..."` 发送完成通知** 的要求,并复制 **`/.cursor/rules/*.mdc`**(与 mvframe 仓库内 Cursor 规则一致)。若不存在则附带 `index.html` 与 `vite.config.js`。会**合并** `package.json` 的 `scripts` / `dependencies` / `devDependencies`(与 Vite 模板一致;**同名脚本和包保留你原有值**),初始化 `.env.mvframe-notify.example` / `.env.local.example` 与 `config.notify`,并自动执行 **`yarn install`**,最后请执行 **`yarn dev`**;需要同时启动通知服务时显式执行 **`yarn exec mvframe-d -n`**。加 `--no-package-json` 可不改动 `package.json` 且跳过安装。
269
274
 
270
275
  ```bash
271
276
  cd /path/to/your-app
@@ -353,7 +358,7 @@ yarn exec mvframe-install-cursor-skill
353
358
 
354
359
  - 新增 `mvframe-notify`:只支持钉钉机器人的本地通知服务,钉钉 webhook / secret 留在 Node 环境变量。
355
360
  - 新增 `mvframe/notify` 与全局 `$notify`:前端通过 `config.notify` 请求本地通知服务。
356
- - 新增框架命令 `yarn d` / `mvframe-d`:同时启动 `yarn dev` 与钉钉通知服务。
361
+ - 新增框架命令 `yarn d` / `mvframe-d`:启动 MVFrame 封装的 Vite dev,追加 `-n` 时同时启动钉钉通知服务。
357
362
  - `mvframe-init-app` 初始化 `config.notify`、带测试钉钉机器人的 `.env.mvframe-notify` / `.env.mvframe-notify.example` 与 `.env.local.example`,不自动覆盖宿主 `d` 脚本。
358
363
  - `VTable` 默认使用异步全局注册;`mvframe-init-app` 会在 `main.js` 写入 `components.async: ["VTable"]`。
359
364
 
package/README.md CHANGED
@@ -189,8 +189,11 @@ yarn exec mvframe-notify
189
189
 
190
190
  yarn d
191
191
  yarn exec mvframe-d
192
+ yarn exec mvframe-d -n
192
193
  ```
193
194
 
195
+ `mvframe-d` starts the wrapped Vite dev server only. Add `-n` / `--notify` when the notify service should also run; notify startup failures are reported without stopping Vite.
196
+
194
197
  The service reads `.env.mvframe-notify` from the host root:
195
198
 
196
199
  ```env
@@ -252,7 +255,7 @@ The floating label shell is implemented centrally in `src/style/chip/element.scs
252
255
 
253
256
  ## CLI: project skeleton
254
257
 
255
- From an **empty folder or existing Vite root**, generates `src/views`, `src/component`, `src/api`, `src/assets/img`, `src/assets/style`, `src/router`, `src/pinia/chip`, `src/config`, plus starter `main.js` / `App.vue` with `app.use(mvframe, …)` (routes, Pinia `storeChips`, config, and `components.async: ["VTable"]`). It also writes/updates host-project **`AGENTS.md`** with MVFrame Codex rules, including a requirement that AI send a completion message with `yarn exec mvframe-notify --once --message "..."` after each finished development task, and copies **`/.cursor/rules/*.mdc`** from the package (same as this repo’s Cursor rules). Adds `index.html` and `vite.config.js` only if missing (use `--force` to overwrite). **Merges** `scripts` / `dependencies` / `devDependencies` into `package.json` (existing values win for shared keys), initializes `.env.mvframe-notify.example` / `.env.local.example` and `config.notify`, then runs **`yarn install`**; use `--no-package-json` to skip package changes and install. Then run **`yarn dev`** or explicitly run **`yarn exec mvframe-d`** to start Vite with the notify service.
258
+ From an **empty folder or existing Vite root**, generates `src/views`, `src/component`, `src/api`, `src/assets/img`, `src/assets/style`, `src/router`, `src/pinia/chip`, `src/config`, plus starter `main.js` / `App.vue` with `app.use(mvframe, …)` (routes, Pinia `storeChips`, config, and `components.async: ["VTable"]`). It also writes/updates host-project **`AGENTS.md`** with MVFrame Codex rules, including a requirement that AI send a completion message with `yarn exec mvframe-notify --once --message "..."` after each finished development task, and copies **`/.cursor/rules/*.mdc`** from the package (same as this repo’s Cursor rules). Adds `index.html` and `vite.config.js` only if missing (use `--force` to overwrite). **Merges** `scripts` / `dependencies` / `devDependencies` into `package.json` (existing values win for shared keys), initializes `.env.mvframe-notify.example` / `.env.local.example` and `config.notify`, then runs **`yarn install`**; use `--no-package-json` to skip package changes and install. Then run **`yarn dev`** or explicitly run **`yarn exec mvframe-d -n`** to start Vite with the notify service.
256
259
 
257
260
  ```bash
258
261
  cd /path/to/your-app
@@ -338,7 +341,7 @@ Default target is **`./.cursor/skills/mvframe-app-init`** under the current work
338
341
 
339
342
  - Added `mvframe-notify`, a DingTalk-only local Node notification service.
340
343
  - Added `mvframe/notify` and global `$notify` for browser calls through `config.notify`.
341
- - Added framework command `yarn d` / `mvframe-d` to run `yarn dev` with the notify service.
344
+ - Added framework command `yarn d` / `mvframe-d` to run the MVFrame-wrapped Vite dev server; add `-n` to start the notify service too.
342
345
  - `mvframe-init-app` now initializes `config.notify`, `.env.mvframe-notify` / `.env.mvframe-notify.example` with the MVFrame test DingTalk robot, and `.env.local.example` without forcing host `d` scripts.
343
346
  - `VTable` now uses async global registration by default; `mvframe-init-app` writes `components.async: ["VTable"]` in `main.js`.
344
347
 
@@ -1,114 +1,112 @@
1
- import { M as q, g as D, s as z } from "./vendor.js";
2
- import { a as je, m as Ue, b as Be, c as Ne, p as Fe, u as We } from "./vendor.js";
3
- import H from "axios";
4
- const G = "lang", Se = (e, t) => {
1
+ import { M as z, g as D, s as G } from "./vendor.js";
2
+ import { a as Ve, m as Ue, b as Be, c as Ne, p as Fe, u as We } from "./vendor.js";
3
+ import j from "axios";
4
+ const Y = "lang", Se = (e, t) => {
5
5
  var i, a;
6
6
  const n = typeof window < "u", r = () => {
7
- var p;
7
+ var d;
8
8
  if (!n)
9
9
  return { innerWidth: 1920, innerHeight: 1080 };
10
- const o = window, l = typeof navigator < "u" ? o.navigator : {}, u = o.screen || {}, m = o.visualViewport, c = {
11
- innerWidth: o.innerWidth,
12
- innerHeight: o.innerHeight,
13
- outerWidth: o.outerWidth,
14
- outerHeight: o.outerHeight,
15
- screenWidth: u.width ?? o.innerWidth,
16
- screenHeight: u.height ?? o.innerHeight,
17
- availWidth: u.availWidth ?? o.innerWidth,
18
- availHeight: u.availHeight ?? o.innerHeight,
19
- devicePixelRatio: o.devicePixelRatio || 1,
20
- bodyHeight: o.innerHeight - ((p = t.pinia) != null && p.useTab ? 36 : 0) - 64 - 32,
21
- drawerHeight: parseInt(o.innerHeight * 0.9),
22
- pageHeight: o.innerHeight - 64 - 32,
23
- pageWidth: o.innerWidth
10
+ const s = window, l = typeof navigator < "u" ? s.navigator : {}, u = s.screen || {}, p = s.visualViewport, h = {
11
+ innerWidth: s.innerWidth,
12
+ innerHeight: s.innerHeight,
13
+ outerWidth: s.outerWidth,
14
+ outerHeight: s.outerHeight,
15
+ screenWidth: u.width ?? s.innerWidth,
16
+ screenHeight: u.height ?? s.innerHeight,
17
+ availWidth: u.availWidth ?? s.innerWidth,
18
+ availHeight: u.availHeight ?? s.innerHeight,
19
+ devicePixelRatio: s.devicePixelRatio || 1,
20
+ bodyHeight: s.innerHeight - ((d = t.pinia) != null && d.useTab ? 36 : 0) - 64 - 32,
21
+ drawerHeight: parseInt(s.innerHeight * 0.9),
22
+ pageHeight: s.innerHeight - 64 - 32,
23
+ pageWidth: s.innerWidth
24
24
  };
25
- m && (c.visualViewportWidth = m.width, c.visualViewportHeight = m.height, c.visualViewportScale = m.scale);
26
- const f = l.userAgent || "";
27
- return c.env = {
28
- userAgent: f,
25
+ p && (h.visualViewportWidth = p.width, h.visualViewportHeight = p.height, h.visualViewportScale = p.scale);
26
+ const c = l.userAgent || "";
27
+ return h.env = {
28
+ userAgent: c,
29
29
  language: l.language || "",
30
30
  languages: l.languages ? [...l.languages] : [],
31
31
  platform: l.platform || "",
32
32
  cookieEnabled: !!l.cookieEnabled,
33
33
  onLine: l.onLine !== !1,
34
34
  maxTouchPoints: l.maxTouchPoints || 0,
35
- isTouch: "ontouchstart" in o || (l.maxTouchPoints || 0) > 0,
35
+ isTouch: "ontouchstart" in s || (l.maxTouchPoints || 0) > 0,
36
36
  isMobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile/i.test(
37
- f
37
+ c
38
38
  )
39
- }, console.info(c), c;
40
- }, s = () => {
39
+ }, console.info(h), h;
40
+ }, o = () => {
41
41
  var l;
42
- const o = r();
42
+ const s = r();
43
43
  globalThis.$config = globalThis.$config || {}, globalThis.$config.options = {
44
44
  ...globalThis.$config.options || {},
45
- ...o
45
+ ...s
46
46
  }, (l = e == null ? void 0 : e.config) != null && l.globalProperties && (e.config.globalProperties.$config = globalThis.$config);
47
47
  };
48
- s(), n && (window.addEventListener("resize", s, { passive: !0 }), (a = (i = window.visualViewport) == null ? void 0 : i.addEventListener) == null || a.call(i, "resize", s, {
48
+ o(), n && (window.addEventListener("resize", o, { passive: !0 }), (a = (i = window.visualViewport) == null ? void 0 : i.addEventListener) == null || a.call(i, "resize", o, {
49
49
  passive: !0
50
50
  }));
51
51
  }, Ae = (e, t) => {
52
- var l, u, m;
53
- const n = t || {}, r = Array.isArray(n.use) && n.use.length > 0 ? n.use : q;
52
+ var u, p, h;
53
+ const n = t || {}, r = Array.isArray(n.use) && n.use.length > 0 ? n.use : z;
54
54
  globalThis.$config = globalThis.$config || {}, globalThis.$config.langUse = r.filter(
55
55
  (c) => c && c.use !== !1 && c.value
56
- ), (l = e == null ? void 0 : e.config) != null && l.globalProperties && (e.config.globalProperties.$config = globalThis.$config);
57
- const i = (typeof localStorage < "u" ? localStorage.getItem(G) : null) || ((u = globalThis.$config) == null ? void 0 : u.lang) || "en_us", a = Object.assign(
56
+ ), (u = e == null ? void 0 : e.config) != null && u.globalProperties && (e.config.globalProperties.$config = globalThis.$config);
57
+ const i = (typeof localStorage < "u" ? localStorage.getItem(Y) : null) || ((p = globalThis.$config) == null ? void 0 : p.lang) || "en_us", a = Object.assign(
58
58
  {},
59
59
  D(i),
60
- ((m = globalThis.$config) == null ? void 0 : m.langMaps) || {},
60
+ ((h = globalThis.$config) == null ? void 0 : h.langMaps) || {},
61
61
  n.langMaps || {}
62
- ), o = (c, f) => {
63
- if (c)
64
- if (f && globalThis.$getType(f) === "Object") {
65
- let p = a[c] || c;
66
- return Object.keys(f).forEach((d) => {
67
- p[`{${d}}`] = f[d];
68
- }), p;
69
- } else
70
- return a[c] || c;
71
- else
62
+ ), s = (c, d) => !d || globalThis.$getType(d) !== "Object" ? c : String(c).replace(
63
+ /\{([A-Za-z0-9_.$-]+)\}/g,
64
+ (m, C) => Object.prototype.hasOwnProperty.call(d, C) ? d[C] : m
65
+ ), l = (c, d) => {
66
+ if (c) {
67
+ const m = a[c] || c;
68
+ return s(m, d);
69
+ } else
72
70
  return c ?? "";
73
71
  };
74
72
  globalThis.$patchLangMaps = (c) => {
75
73
  c && globalThis.$getType(c) === "Object" && Object.assign(a, c);
76
- }, globalThis.$l = o, e.config.globalProperties.$l = o, e.config.globalProperties.$patchLangMaps = globalThis.$patchLangMaps, String.prototype.$l = function() {
74
+ }, globalThis.$l = l, e.config.globalProperties.$l = l, e.config.globalProperties.$patchLangMaps = globalThis.$patchLangMaps, String.prototype.$l = function() {
77
75
  return $l(this);
78
76
  };
79
- }, $e = (e, t) => {
77
+ }, Le = (e, t) => {
80
78
  if (!e || !t) return !1;
81
- const n = e.getBoundingClientRect(), r = t.getBoundingClientRect(), s = r.right > n.left && r.left < n.right, i = r.bottom > n.top && r.top < n.bottom;
82
- return s && i;
83
- }, Y = (e, t) => {
79
+ const n = e.getBoundingClientRect(), r = t.getBoundingClientRect(), o = r.right > n.left && r.left < n.right, i = r.bottom > n.top && r.top < n.bottom;
80
+ return o && i;
81
+ }, K = (e, t) => {
84
82
  if (e === t) return !0;
85
83
  if (e == null || t == null || typeof e != "object" || typeof t != "object")
86
84
  return JSON.stringify(e) === JSON.stringify(t);
87
85
  const n = Object.keys(e), r = Object.keys(t);
88
86
  if (n.length !== r.length) return !1;
89
- for (const s of n)
90
- if (!r.includes(s) || !Y(e[s], t[s])) return !1;
87
+ for (const o of n)
88
+ if (!r.includes(o) || !K(e[o], t[o])) return !1;
91
89
  return !0;
92
- }, x = "download", K = 150, X = (e, t = x) => {
93
- const n = t || x, r = String(e ?? "").trim();
90
+ }, O = "download", X = 150, J = (e, t = O) => {
91
+ const n = t || O, r = String(e ?? "").trim();
94
92
  if (!r) return n;
95
93
  const i = r.replace(/[/\\?%*:|"<>]/g, "_").replace(/\.\./g, "_").split(/[/\\]/).pop() || n, a = 200;
96
94
  return i.length > a ? i.slice(0, a) : i;
97
- }, J = (e) => {
95
+ }, Z = (e) => {
98
96
  const t = ((e == null ? void 0 : e.type) || "").toLowerCase();
99
97
  return t ? t.includes("spreadsheet") || t.includes("ms-excel") || t.includes("excel") && t.includes("application") : !1;
100
98
  }, S = (e, t) => {
101
- const n = URL.createObjectURL(e), r = X(t), s = document.createElement("a");
102
- s.href = n, s.download = r, s.style.display = "none", document.body.appendChild(s);
99
+ const n = URL.createObjectURL(e), r = J(t), o = document.createElement("a");
100
+ o.href = n, o.download = r, o.style.display = "none", document.body.appendChild(o);
103
101
  try {
104
- s.click();
102
+ o.click();
105
103
  } finally {
106
- document.body.removeChild(s), setTimeout(() => URL.revokeObjectURL(n), K);
104
+ document.body.removeChild(o), setTimeout(() => URL.revokeObjectURL(n), X);
107
105
  }
108
106
  }, Q = (e) => {
109
107
  if (!e || e.source !== void 0 || e.type === void 0)
110
108
  return e;
111
- const { type: t, data: n, url: r, headers: s, name: i, filename: a, init: o, ...l } = e, u = a ?? i;
109
+ const { type: t, data: n, url: r, headers: o, name: i, filename: a, init: s, ...l } = e, u = a ?? i;
112
110
  return t === "csv" ? {
113
111
  ...l,
114
112
  source: "inline",
@@ -119,100 +117,100 @@ const G = "lang", Se = (e, t) => {
119
117
  ...l,
120
118
  source: "fetch",
121
119
  url: r,
122
- init: { ...o || {}, headers: s ?? (o == null ? void 0 : o.headers) },
120
+ init: { ...s || {}, headers: o ?? (s == null ? void 0 : s.headers) },
123
121
  response: "blob",
124
122
  expectExcel: !0,
125
123
  filename: u
126
124
  } : e;
127
- }, Le = async (e = {}) => {
125
+ }, $e = async (e = {}) => {
128
126
  const t = Q(e), {
129
127
  source: n = "inline",
130
128
  content: r,
131
- blob: s,
129
+ blob: o,
132
130
  bom: i = !0,
133
131
  mime: a,
134
- url: o,
132
+ url: s,
135
133
  init: l,
136
134
  response: u = "blob",
137
- openIn: m = "self",
138
- expectExcel: c,
139
- filename: f,
140
- name: p,
141
- error: d = () => {
135
+ openIn: p = "self",
136
+ expectExcel: h,
137
+ filename: c,
138
+ name: d,
139
+ error: m = () => {
142
140
  },
143
141
  // 避免 legacy 字段渗入后续逻辑
144
- type: _e,
142
+ type: C,
145
143
  data: Te,
146
144
  headers: we,
147
145
  ...Me
148
- } = t, M = f ?? p;
146
+ } = t, M = c ?? d;
149
147
  try {
150
148
  if (n === "inline") {
151
- if (s instanceof Blob) {
152
- S(s, M);
149
+ if (o instanceof Blob) {
150
+ S(o, M);
153
151
  return;
154
152
  }
155
153
  if (r == null) {
156
- d(new Error("content or blob is required for inline"));
154
+ m(new Error("content or blob is required for inline"));
157
155
  return;
158
156
  }
159
- const h = typeof r == "string" ? r : String(r), v = i ? "\uFEFF" + h : h, R = a || (i ? "text/csv;charset=utf-8" : "text/plain;charset=utf-8");
160
- S(new Blob([v], { type: R }), M);
157
+ const f = typeof r == "string" ? r : String(r), R = i ? "\uFEFF" + f : f, v = a || (i ? "text/csv;charset=utf-8" : "text/plain;charset=utf-8");
158
+ S(new Blob([R], { type: v }), M);
161
159
  return;
162
160
  }
163
161
  if (n === "fetch") {
164
- if (!o) {
165
- d(new Error("url is required for fetch"));
162
+ if (!s) {
163
+ m(new Error("url is required for fetch"));
166
164
  return;
167
165
  }
168
- const h = await fetch(o, l);
169
- if (!h.ok) {
170
- d(new Error(`fetch failed: ${h.status}`));
166
+ const f = await fetch(s, l);
167
+ if (!f.ok) {
168
+ m(new Error(`fetch failed: ${f.status}`));
171
169
  return;
172
170
  }
173
171
  if (u === "text") {
174
- const R = await h.text(), F = i ? "\uFEFF" + R : R, W = a || (i ? "text/csv;charset=utf-8" : "text/plain;charset=utf-8");
175
- S(new Blob([F], { type: W }), M);
172
+ const v = await f.text(), W = i ? "\uFEFF" + v : v, q = a || (i ? "text/csv;charset=utf-8" : "text/plain;charset=utf-8");
173
+ S(new Blob([W], { type: q }), M);
176
174
  return;
177
175
  }
178
- const v = await h.blob();
179
- if (c && !J(v)) {
180
- d(new Error("excel does not exist"));
176
+ const R = await f.blob();
177
+ if (h && !Z(R)) {
178
+ m(new Error("excel does not exist"));
181
179
  return;
182
180
  }
183
- S(v, M);
181
+ S(R, M);
184
182
  return;
185
183
  }
186
184
  if (n === "open") {
187
- if (!o) {
188
- d(new Error("url is required for open"));
185
+ if (!s) {
186
+ m(new Error("url is required for open"));
189
187
  return;
190
188
  }
191
- m === "blank" ? window.open(o, "_blank", "noopener,noreferrer") : window.location.href = o;
189
+ p === "blank" ? window.open(s, "_blank", "noopener,noreferrer") : window.location.href = s;
192
190
  return;
193
191
  }
194
- d(new Error(`unknown source: ${n}`));
195
- } catch (h) {
196
- d(h instanceof Error ? h : new Error(String(h)));
192
+ m(new Error(`unknown source: ${n}`));
193
+ } catch (f) {
194
+ m(f instanceof Error ? f : new Error(String(f)));
197
195
  }
198
196
  };
199
- function Z(e, t, n) {
197
+ function ee(e, t, n) {
200
198
  if (t === "" || t === void 0 || t === null)
201
199
  return "";
202
- const r = globalThis.$fa, s = globalThis.$fu, i = (n == null ? void 0 : n.precision) ?? 2, a = n == null ? void 0 : n.unit;
203
- if ((a === "currency" || a === "%") && s) {
204
- const o = {
200
+ const r = globalThis.$fa, o = globalThis.$fu, i = (n == null ? void 0 : n.precision) ?? 2, a = n == null ? void 0 : n.unit;
201
+ if ((a === "currency" || a === "%") && o) {
202
+ const s = {
205
203
  [e]: {
206
204
  unit: a === "currency" ? "currency" : "%",
207
205
  precision: i
208
206
  }
209
207
  };
210
208
  try {
211
- return s({
209
+ return o({
212
210
  prop: e,
213
211
  currency: n == null ? void 0 : n.currency,
214
212
  value: t,
215
- obj: o
213
+ obj: s
216
214
  });
217
215
  } catch {
218
216
  }
@@ -226,33 +224,33 @@ function Z(e, t, n) {
226
224
  return String(t);
227
225
  }
228
226
  function Pe(e, t, n = {}) {
229
- const { columns: r = [] } = e || {}, { resolveMetric: s } = n;
227
+ const { columns: r = [] } = e || {}, { resolveMetric: o } = n;
230
228
  return !r.length || !t || typeof t != "object" ? [] : r.map((i) => {
231
229
  const a = i.property ?? i.prop ?? "";
232
230
  if (!a)
233
231
  return "";
234
- let o = t[a];
235
- if (o === void 0 && (o = ""), o === "")
232
+ let s = t[a];
233
+ if (s === void 0 && (s = ""), s === "")
236
234
  return "";
237
- const l = typeof s == "function" ? s(a) : void 0;
235
+ const l = typeof o == "function" ? o(a) : void 0;
238
236
  try {
239
- return Z(a, o, l);
237
+ return ee(a, s, l);
240
238
  } catch {
241
- return String(o);
239
+ return String(s);
242
240
  }
243
241
  });
244
242
  }
245
- const C = "mvframe_primary", V = "mvframe_theme", I = "mvframe_theme_name", ee = "dark", A = "main", $ = "mv-theme-", T = { r: 255, g: 255, b: 255 }, te = { r: 0, g: 0, b: 0 }, j = [1, 3, 5, 7, 9], ne = [
243
+ const I = "mvframe_primary", V = "mvframe_theme", x = "mvframe_theme_name", te = "dark", A = "main", L = "mv-theme-", T = { r: 255, g: 255, b: 255 }, ne = { r: 0, g: 0, b: 0 }, U = [1, 3, 5, 7, 9], re = [
246
244
  "--el-color-primary-light-3",
247
245
  "--el-color-primary-light-5",
248
246
  "--el-color-primary-light-7",
249
247
  "--el-color-primary-light-8",
250
248
  "--el-color-primary-light-9",
251
249
  "--el-color-primary-dark-2"
252
- ], re = j.map(
250
+ ], oe = U.map(
253
251
  (e) => `--color-primary${e}`
254
252
  );
255
- function L(e) {
253
+ function $(e) {
256
254
  let t = String(e).trim().replace(/^#/, "");
257
255
  if (t.length === 3 && (t = t.split("").map((r) => r + r).join("")), t.length >= 8 && (t = t.slice(0, 6)), t.length !== 6 || Number.isNaN(parseInt(t, 16)))
258
256
  return null;
@@ -264,122 +262,122 @@ function L(e) {
264
262
  };
265
263
  }
266
264
  function y(e, t, n) {
267
- const r = (s) => Math.max(0, Math.min(255, Math.round(s)));
268
- return `#${[r(e), r(t), r(n)].map((s) => s.toString(16).padStart(2, "0")).join("")}`;
265
+ const r = (o) => Math.max(0, Math.min(255, Math.round(o)));
266
+ return `#${[r(e), r(t), r(n)].map((o) => o.toString(16).padStart(2, "0")).join("")}`;
269
267
  }
270
- function U(e, t, n, r) {
271
- const s = (a) => Math.max(0, Math.min(255, Math.round(a))), i = Math.max(0, Math.min(1, r));
272
- return `rgba(${s(e)}, ${s(t)}, ${s(n)}, ${i})`;
268
+ function B(e, t, n, r) {
269
+ const o = (a) => Math.max(0, Math.min(255, Math.round(a))), i = Math.max(0, Math.min(1, r));
270
+ return `rgba(${o(e)}, ${o(t)}, ${o(n)}, ${i})`;
273
271
  }
274
272
  function se(e) {
275
273
  const t = [e.r, e.g, e.b].map((n) => (n /= 255, n <= 0.03928 ? n / 12.92 : ((n + 0.055) / 1.055) ** 2.4));
276
274
  return 0.2126 * t[0] + 0.7152 * t[1] + 0.0722 * t[2];
277
275
  }
278
- function B(e) {
276
+ function N(e) {
279
277
  return se(e) > 0.5 ? "#1a1a1a" : "#ffffff";
280
278
  }
281
279
  function b(e, t, n) {
282
- const r = n / 100, s = 1 - r;
280
+ const r = n / 100, o = 1 - r;
283
281
  return {
284
- r: e.r * r + t.r * s,
285
- g: e.g * r + t.g * s,
286
- b: e.b * r + t.b * s
282
+ r: e.r * r + t.r * o,
283
+ g: e.g * r + t.g * o,
284
+ b: e.b * r + t.b * o
287
285
  };
288
286
  }
289
- function oe(e, t = "light") {
290
- const n = L(e);
287
+ function ie(e, t = "light") {
288
+ const n = $(e);
291
289
  if (!n)
292
290
  return null;
293
- const r = b(T, n, 30), s = b(T, n, 50), i = b(T, n, 70), a = b(T, n, 80), o = b(T, n, 90), l = b(te, n, 20);
291
+ const r = b(T, n, 30), o = b(T, n, 50), i = b(T, n, 70), a = b(T, n, 80), s = b(T, n, 90), l = b(ne, n, 20);
294
292
  return {
295
293
  "--el-color-primary-light-3": y(r.r, r.g, r.b),
296
- "--el-color-primary-light-5": y(s.r, s.g, s.b),
297
- "--el-color-primary-light-7": t === "dark" ? U(n.r, n.g, n.b, 0.7) : y(i.r, i.g, i.b),
294
+ "--el-color-primary-light-5": y(o.r, o.g, o.b),
295
+ "--el-color-primary-light-7": t === "dark" ? B(n.r, n.g, n.b, 0.7) : y(i.r, i.g, i.b),
298
296
  "--el-color-primary-light-8": y(a.r, a.g, a.b),
299
- "--el-color-primary-light-9": y(o.r, o.g, o.b),
297
+ "--el-color-primary-light-9": y(s.r, s.g, s.b),
300
298
  "--el-color-primary-dark-2": y(l.r, l.g, l.b)
301
299
  };
302
300
  }
303
- function ie(e) {
304
- const t = L(e);
301
+ function ae(e) {
302
+ const t = $(e);
305
303
  return t ? Object.fromEntries(
306
- j.map((n) => [
304
+ U.map((n) => [
307
305
  `--color-primary${n}`,
308
- U(t.r, t.g, t.b, n / 10)
306
+ B(t.r, t.g, t.b, n / 10)
309
307
  ])
310
308
  ) : null;
311
309
  }
312
- function ae(e) {
310
+ function le(e) {
313
311
  e.style.removeProperty("--el-color-primary"), e.style.removeProperty("--color-on-primary-text");
314
- for (const t of re)
312
+ for (const t of oe)
315
313
  e.style.removeProperty(t);
316
- for (const t of ne)
314
+ for (const t of re)
317
315
  e.style.removeProperty(t);
318
316
  }
319
- function N(e) {
317
+ function F(e) {
320
318
  const t = String(e ?? "").trim().toLowerCase();
321
319
  return t && t.replace(/[^a-z0-9_-]/g, "-").replace(/-+/g, "-") || A;
322
320
  }
323
- function le(e) {
321
+ function ce(e) {
324
322
  const t = [...e.classList].find(
325
- (n) => n.startsWith($)
323
+ (n) => n.startsWith(L)
326
324
  );
327
- return t ? t.slice($.length) : A;
328
- }
329
- function ce(e) {
330
- [...e.classList].filter((t) => t.startsWith($)).forEach((t) => e.classList.remove(t));
325
+ return t ? t.slice(L.length) : A;
331
326
  }
332
327
  function ue(e) {
333
- return e.classList.contains("light") ? "light" : e.classList.contains("dark") ? "dark" : ee;
328
+ [...e.classList].filter((t) => t.startsWith(L)).forEach((t) => e.classList.remove(t));
329
+ }
330
+ function he(e) {
331
+ return e.classList.contains("light") ? "light" : e.classList.contains("dark") ? "dark" : te;
334
332
  }
335
- function he(e, t) {
336
- const n = N(t);
337
- return ce(e), e.classList.add(`${$}${n}`), n;
333
+ function de(e, t) {
334
+ const n = F(t);
335
+ return ue(e), e.classList.add(`${L}${n}`), n;
338
336
  }
339
- function de(e, t, n = "light") {
340
- const r = L(t.startsWith("#") ? t : `#${t}`);
337
+ function me(e, t, n = "light") {
338
+ const r = $(t.startsWith("#") ? t : `#${t}`);
341
339
  if (!r)
342
340
  return !1;
343
- const s = y(r.r, r.g, r.b);
344
- e.style.setProperty("--color-primary", s), e.style.setProperty("--el-color-primary", s), e.style.setProperty("--color-on-primary-text", B(r));
345
- const i = ie(s);
346
- i && Object.entries(i).forEach(([o, l]) => e.style.setProperty(o, l));
347
- const a = oe(s, n);
348
- return a && Object.entries(a).forEach(([o, l]) => e.style.setProperty(o, l)), !0;
341
+ const o = y(r.r, r.g, r.b);
342
+ e.style.setProperty("--color-primary", o), e.style.setProperty("--el-color-primary", o), e.style.setProperty("--color-on-primary-text", N(r));
343
+ const i = ae(o);
344
+ i && Object.entries(i).forEach(([s, l]) => e.style.setProperty(s, l));
345
+ const a = ie(o, n);
346
+ return a && Object.entries(a).forEach(([s, l]) => e.style.setProperty(s, l)), !0;
349
347
  }
350
- function me(e = {}) {
351
- const t = document.documentElement, n = (e.mode ?? ue(t)) === "light" ? "light" : "dark", r = e.theme ?? le(t);
352
- if (he(t, r), e.primary != null && e.primary !== "") {
353
- const s = String(e.primary).trim();
354
- if (!de(t, s, n)) {
355
- t.style.setProperty("--color-primary", s), t.style.setProperty("--el-color-primary", s);
356
- const i = L(s.startsWith("#") ? s : `#${s}`);
357
- i && t.style.setProperty("--color-on-primary-text", B(i));
348
+ function fe(e = {}) {
349
+ const t = document.documentElement, n = (e.mode ?? he(t)) === "light" ? "light" : "dark", r = e.theme ?? ce(t);
350
+ if (de(t, r), e.primary != null && e.primary !== "") {
351
+ const o = String(e.primary).trim();
352
+ if (!me(t, o, n)) {
353
+ t.style.setProperty("--color-primary", o), t.style.setProperty("--el-color-primary", o);
354
+ const i = $(o.startsWith("#") ? o : `#${o}`);
355
+ i && t.style.setProperty("--color-on-primary-text", N(i));
358
356
  }
359
- } else (e.primary === null || e.primary === "") && (t.style.removeProperty("--color-primary"), ae(t));
357
+ } else (e.primary === null || e.primary === "") && (t.style.removeProperty("--color-primary"), le(t));
360
358
  t.classList.toggle("light", n === "light"), t.classList.toggle("dark", n === "dark");
361
359
  }
362
360
  function Ce(e) {
363
- e.primary !== void 0 && (e.primary == null || e.primary === "" ? localStorage.removeItem(C) : localStorage.setItem(C, String(e.primary))), e.mode !== void 0 && localStorage.setItem(V, e.mode), e.theme !== void 0 && (e.theme == null || e.theme === "" ? localStorage.removeItem(I) : localStorage.setItem(
364
- I,
365
- N(e.theme)
361
+ e.primary !== void 0 && (e.primary == null || e.primary === "" ? localStorage.removeItem(I) : localStorage.setItem(I, String(e.primary))), e.mode !== void 0 && localStorage.setItem(V, e.mode), e.theme !== void 0 && (e.theme == null || e.theme === "" ? localStorage.removeItem(x) : localStorage.setItem(
362
+ x,
363
+ F(e.theme)
366
364
  ));
367
365
  }
368
366
  function Ie() {
369
- var s;
370
- const e = localStorage.getItem(C), t = localStorage.getItem(V), n = localStorage.getItem(I) || ((s = globalThis.$config) == null ? void 0 : s.theme) || A, r = t === "light" ? "light" : "dark";
371
- me({
367
+ var o;
368
+ const e = localStorage.getItem(I), t = localStorage.getItem(V), n = localStorage.getItem(x) || ((o = globalThis.$config) == null ? void 0 : o.theme) || A, r = t === "light" ? "light" : "dark";
369
+ fe({
372
370
  primary: e != null && e !== "" ? e : null,
373
371
  mode: r,
374
372
  theme: n
375
373
  });
376
374
  }
377
- const fe = { BASE_URL: "/", DEV: !1, MODE: "production", PROD: !0, SSR: !1 };
375
+ const pe = { BASE_URL: "/", DEV: !1, MODE: "production", PROD: !0, SSR: !1 };
378
376
  let w = null;
379
- function O(e) {
380
- z("error", e);
377
+ function H(e) {
378
+ G("error", e);
381
379
  }
382
- function ke(e) {
380
+ function xe(e) {
383
381
  w = e && typeof e == "object" ? e : null;
384
382
  }
385
383
  function P(e) {
@@ -388,15 +386,15 @@ function P(e) {
388
386
  const t = typeof globalThis < "u" ? globalThis.__MVFRAME_ENV__ : null;
389
387
  if (t && t[e] != null && t[e] !== "")
390
388
  return String(t[e]);
391
- const n = typeof import.meta < "u" ? fe : null;
389
+ const n = typeof import.meta < "u" ? pe : null;
392
390
  return n && n[e] != null && n[e] !== "" ? String(n[e]) : "";
393
391
  }
394
- const _ = H.create({
392
+ const _ = j.create({
395
393
  timeout: 0,
396
394
  withCredentials: !1
397
395
  });
398
396
  let g = [];
399
- const ge = H.CancelToken, pe = (e) => {
397
+ const ge = j.CancelToken, ye = (e) => {
400
398
  const t = e.url + "_" + e.headers["Content-HI"] + "_" + e.ex, n = [];
401
399
  if (g.length)
402
400
  for (let r in g)
@@ -415,8 +413,8 @@ const ge = H.CancelToken, pe = (e) => {
415
413
  _.interceptors.request.use(
416
414
  (e) => {
417
415
  e.headers = e.headers || {};
418
- const { login: t, accountInfo: n = {} } = window.$store.launch(), { access_token: r } = t.info, s = e.noaccount === !0 || e.noAccount === !0;
419
- return r && e.headers["Content-HI"] && (e.headers.Authorization = `Bearer ${r}`), n.partner_org_id && !s && (e.data ? e.method.toLowerCase() === "get" ? e.params.accountId = n.partner_org_id : e.data.accountId = n.partner_org_id : e.method.toLowerCase() === "get" ? e.params = { accountId: n.partner_org_id } : e.data = { accountId: n.partner_org_id }), pe(e), e.cancelToken = new ge((i) => {
416
+ const { login: t, accountInfo: n = {} } = window.$store.launch(), { access_token: r } = t.info, o = e.noaccount === !0 || e.noAccount === !0;
417
+ return r && e.headers["Content-HI"] && (e.headers.Authorization = `Bearer ${r}`), n.partner_org_id && !o && (e.data ? e.method.toLowerCase() === "get" ? e.params.accountId = n.partner_org_id : e.data.accountId = n.partner_org_id : e.method.toLowerCase() === "get" ? e.params = { accountId: n.partner_org_id } : e.data = { accountId: n.partner_org_id }), ye(e), e.cancelToken = new ge((i) => {
420
418
  g.push({
421
419
  v: e.url + "_" + e.headers["Content-HI"] + "_" + e.ex,
422
420
  cb: i
@@ -430,17 +428,17 @@ _.interceptors.response.use(
430
428
  var i;
431
429
  if (e == null || typeof e != "object" || Array.isArray(e))
432
430
  return E(t), e;
433
- let { code: n, message: r, msg: s } = e;
434
- if (s = s || r, n === 200)
431
+ let { code: n, message: r, msg: o } = e;
432
+ if (o = o || r, n === 200)
435
433
  E(t);
436
434
  else if (n === 500) {
437
435
  if (t.showMsg !== !1) {
438
436
  const a = (i = t == null ? void 0 : t.headers) != null && i.CONTACT_CUSTOMER_SERVICE ? window.$l("CONTACT_CUSTOMER_SERVICE") : "";
439
- O({
437
+ H({
440
438
  grouping: !0,
441
439
  showClose: !0,
442
440
  duration: 0,
443
- message: [s, a].filter(Boolean).join(" ")
441
+ message: [o, a].filter(Boolean).join(" ")
444
442
  });
445
443
  }
446
444
  E(t);
@@ -448,7 +446,7 @@ _.interceptors.response.use(
448
446
  return e;
449
447
  },
450
448
  (e) => {
451
- var n, r, s, i, a;
449
+ var n, r, o, i, a;
452
450
  let t = !1;
453
451
  if (e && e.response)
454
452
  switch (e.response.status) {
@@ -469,33 +467,33 @@ _.interceptors.response.use(
469
467
  }
470
468
  else
471
469
  (n = e.stack) != null && n.includes("timeout") ? e.message = window.$l("Timeout, Please Refresh") : (e.message = window.$l("Connect Failed"), t = !0);
472
- return t || ((r = e == null ? void 0 : e.response) == null ? void 0 : r.status) !== 403 && O({
470
+ return t || ((r = e == null ? void 0 : e.response) == null ? void 0 : r.status) !== 403 && H({
473
471
  grouping: !0,
474
- message: `${e.message} ${(i = (s = e.config) == null ? void 0 : s.headers) == null ? void 0 : i["Content-HI"]}`
472
+ message: `${e.message} ${(i = (o = e.config) == null ? void 0 : o.headers) == null ? void 0 : i["Content-HI"]}`
475
473
  }), E(e.config), e.code === "ERR_CANCELED" ? Promise.resolve({ code: e.code, msg: e.message }) : Promise.resolve({
476
474
  code: (a = e.response) == null ? void 0 : a.status,
477
475
  msg: e.message
478
476
  });
479
477
  }
480
478
  );
481
- function ye(e) {
479
+ function be(e) {
482
480
  return e.baseURL = P("VITE_APP_BASEURL"), e.method = "get", e.headers = { "Content-Type": "application/x-www-form-urlencoded" }, e.data && (e.params = e.data), _(e);
483
481
  }
484
- function be(e) {
482
+ function Ee(e) {
485
483
  return e.baseURL = P("VITE_APP_BASEURL"), e.method = "get", e.headers = {
486
484
  ...e.headers,
487
485
  "Content-HI": e.url
488
486
  }, e.url = e.ver ? `api/${e.ver}/ads` : "api/v3/ads", e.data && (e.params = e.data), _(e);
489
487
  }
490
- function Ee(e) {
488
+ function _e(e) {
491
489
  if (e.baseURL = P("VITE_APP_BASEURL"), e.method = "post", e.headers = {
492
490
  ...e.headers,
493
491
  "Content-HI": e.url
494
492
  }, e.data && window.$getType(e.data) === "Object") {
495
493
  const n = {};
496
494
  Object.keys(e.data).forEach((r) => {
497
- const s = e.data[r];
498
- [null, "", void 0].includes(s) || (n[r] = s);
495
+ const o = e.data[r];
496
+ [null, "", void 0].includes(o) || (n[r] = o);
499
497
  }), e.data = n;
500
498
  }
501
499
  return e.url = e.ver ? `api/${e.ver}/ads` : "api/v3/ads", _(e);
@@ -505,13 +503,13 @@ function k({
505
503
  url: t,
506
504
  ex: n,
507
505
  method: r = "post",
508
- emptyString: s = !1
506
+ emptyString: o = !1
509
507
  }) {
510
508
  const i = {}, a = [void 0, null];
511
- s === !1 && a.push("");
509
+ o === !1 && a.push("");
512
510
  for (let u in e)
513
511
  a.indexOf(e[u]) === -1 && (i[u] = e[u]);
514
- const { login: o } = window.$store.launch(), { access_token: l } = o.info || {};
512
+ const { login: s } = window.$store.launch(), { access_token: l } = s.info || {};
515
513
  return _({
516
514
  headers: {
517
515
  "Content-Type": "application/json",
@@ -524,40 +522,40 @@ function k({
524
522
  ex: n
525
523
  });
526
524
  }
527
- const xe = k;
525
+ const ke = k;
528
526
  function Oe(e) {
529
- globalThis.$login = ye, globalThis.$get = be, globalThis.$post = Ee, globalThis.$form = k, globalThis.$xform = k;
527
+ globalThis.$login = be, globalThis.$get = Ee, globalThis.$post = _e, globalThis.$form = k, globalThis.$xform = k;
530
528
  }
531
529
  export {
532
- ee as MVFRAME_DEFAULT_THEME_MODE,
530
+ te as MVFRAME_DEFAULT_THEME_MODE,
533
531
  A as MVFRAME_DEFAULT_THEME_NAME,
534
- G as MVFRAME_STORAGE_LANG,
535
- C as MVFRAME_STORAGE_PRIMARY,
532
+ Y as MVFRAME_STORAGE_LANG,
533
+ I as MVFRAME_STORAGE_PRIMARY,
536
534
  V as MVFRAME_STORAGE_THEME,
537
- I as MVFRAME_STORAGE_THEME_NAME,
538
- $ as MVFRAME_THEME_CLASS_PREFIX,
539
- me as applyMvframeTheme,
540
- Y as deepEqual,
541
- Le as download,
542
- Z as formatSummaryCell,
543
- je as getMaps,
535
+ x as MVFRAME_STORAGE_THEME_NAME,
536
+ L as MVFRAME_THEME_CLASS_PREFIX,
537
+ fe as applyMvframeTheme,
538
+ K as deepEqual,
539
+ $e as download,
540
+ ee as formatSummaryCell,
541
+ Ve as getMaps,
544
542
  Oe as installRq,
545
- $e as isInView,
543
+ Le as isInView,
546
544
  Ie as loadMvframeTheme,
547
545
  Ue as mapLang,
548
546
  Be as mapLangPath,
549
547
  Ne as mergeMaps,
550
548
  Fe as patchMaps,
551
549
  Ce as persistMvframeTheme,
552
- X as sanitizeDownloadFileName,
553
- ke as setMvframeRqEnv,
550
+ J as sanitizeDownloadFileName,
551
+ xe as setMvframeRqEnv,
554
552
  k as useForm,
555
- be as useGet,
553
+ Ee as useGet,
556
554
  Ae as useLang,
557
- ye as useLogin,
555
+ be as useLogin,
558
556
  We as useMap,
559
557
  Se as useOptions,
560
- Ee as usePost,
558
+ _e as usePost,
561
559
  Pe as useRemoteSummary,
562
- xe as useXform
560
+ ke as useXform
563
561
  };
package/dist/vendor.js CHANGED
@@ -13917,7 +13917,7 @@ const Hr = (a, o = {}) => {
13917
13917
  }, Jr = {
13918
13918
  name: "Matt Avias Frame",
13919
13919
  copyright: "©2026",
13920
- version: "1.1.15",
13920
+ version: "1.1.17",
13921
13921
  author: "Matt Avias",
13922
13922
  date: "2026-02-26",
13923
13923
  /** 默认语言 key,与 `$getLang`、localStorage `lang` 一致;业务在 app.use(mvframe, { config }) 里覆盖 */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mvframe",
3
3
  "packageManager": "yarn@4.4.1",
4
- "version": "1.1.15",
4
+ "version": "1.1.17",
5
5
  "author": "matt avis",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",
@@ -67,7 +67,9 @@
67
67
  "dist/assets/*",
68
68
  "src/style/chip/mixin.scss",
69
69
  "scripts/build-host.js",
70
+ "scripts/dev-vite-server.js",
70
71
  "scripts/dev-with-notify.js",
72
+ "scripts/flag-assets.js",
71
73
  "scripts/init-rules.js",
72
74
  "scripts/install-codex-agents.js",
73
75
  "scripts/copy-flag-assets.js",
@@ -13,6 +13,7 @@
13
13
  const { spawnSync } = require("child_process");
14
14
  const fs = require("fs");
15
15
  const path = require("path");
16
+ const { copyFlagAssetsTo } = require("./flag-assets.js");
16
17
  const SERVE_JSON = `{
17
18
  "rewrites": [{
18
19
  "source": "**",
@@ -85,6 +86,13 @@ function resolveViteCli(cwd) {
85
86
  );
86
87
  }
87
88
 
89
+ function copyFlagAssets(outAbs) {
90
+ const dest = path.join(outAbs, "assets", "flags");
91
+
92
+ copyFlagAssetsTo(dest);
93
+ console.log(`[mvframe-b] 已复制 ${path.relative(outAbs, dest)}`);
94
+ }
95
+
88
96
  function main() {
89
97
  const cwd = process.cwd();
90
98
  const { mode, outDir } = parseArgs(process.argv);
@@ -100,6 +108,7 @@ function main() {
100
108
  }
101
109
  const outAbs = path.resolve(cwd, outDir);
102
110
  fs.mkdirSync(outAbs, { recursive: true });
111
+ copyFlagAssets(outAbs);
103
112
  const servePath = path.join(outAbs, "serve.json");
104
113
  fs.writeFileSync(servePath, `${SERVE_JSON}\n`, "utf8");
105
114
  console.log(`[mvframe-b] 已写入 ${path.relative(cwd, servePath)}`);
@@ -0,0 +1,200 @@
1
+ #!/usr/bin/env node
2
+ const { spawn } = require("child_process");
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const { pathToFileURL } = require("url");
6
+ const { createRequire } = require("module");
7
+ const { createTempFlagAssets } = require("./flag-assets.js");
8
+
9
+ let child = null;
10
+ let cleanupTemp = null;
11
+ let shuttingDown = false;
12
+
13
+ function resolveViteCli(cwd) {
14
+ let vpkg = "";
15
+ try {
16
+ const projectRequire = createRequire(path.join(cwd, "package.json"));
17
+ vpkg = projectRequire.resolve("vite/package.json");
18
+ } catch {
19
+ // Fall back to node_modules for non-PnP projects.
20
+ }
21
+
22
+ if (!vpkg) {
23
+ vpkg = path.join(cwd, "node_modules", "vite", "package.json");
24
+ }
25
+
26
+ if (fs.existsSync(vpkg)) {
27
+ const p = require(vpkg);
28
+ const bin = typeof p.bin === "string" ? p.bin : p.bin && p.bin.vite;
29
+ if (bin) {
30
+ const cli = path.join(path.dirname(vpkg), bin);
31
+ if (fs.existsSync(cli)) return cli;
32
+ }
33
+ }
34
+ throw new Error(
35
+ "未在当前项目找到 Vite(请先安装依赖;宿主项目可执行 yarn install 后再运行 mvframe-d)",
36
+ );
37
+ }
38
+
39
+ function resolvePackageManager(cwd) {
40
+ const pkgPath = path.join(cwd, "package.json");
41
+ if (fs.existsSync(pkgPath)) {
42
+ const pkg = require(pkgPath);
43
+ const packageManager = String(pkg.packageManager || "");
44
+ if (packageManager.startsWith("pnpm@")) return "pnpm";
45
+ if (packageManager.startsWith("npm@")) return "npx";
46
+ return "yarn";
47
+ }
48
+ return "yarn";
49
+ }
50
+
51
+ function findHostViteConfig(cwd) {
52
+ const names = [
53
+ "vite.config.ts",
54
+ "vite.config.mts",
55
+ "vite.config.js",
56
+ "vite.config.mjs",
57
+ "vite.config.cjs",
58
+ "vite.config.cts",
59
+ ];
60
+ return names.map((name) => path.join(cwd, name)).find(fs.existsSync) || "";
61
+ }
62
+
63
+ function createWrapperConfig({ cwd, flagsRoot, tmpRoot }) {
64
+ const hostConfig = findHostViteConfig(cwd);
65
+ const hostImport = hostConfig
66
+ ? `import hostConfig from ${JSON.stringify(pathToFileURL(hostConfig).href)};`
67
+ : "const hostConfig = {};";
68
+ const source = `
69
+ import fs from "node:fs";
70
+ import path from "node:path";
71
+ ${hostImport}
72
+
73
+ function createFlagAssetsPlugin(flagsRoot) {
74
+ return {
75
+ name: "mvframe-host-flag-assets",
76
+ configureServer(server) {
77
+ server.middlewares.use((req, res, next) => {
78
+ const pathname = req.url?.split("?")[0] || "";
79
+ if (!pathname.startsWith("/assets/flags/")) {
80
+ next();
81
+ return;
82
+ }
83
+
84
+ const relativePath = decodeURIComponent(
85
+ pathname.replace(/^\\/assets\\/flags\\//, ""),
86
+ );
87
+ const normalized = path.posix.normalize(relativePath);
88
+ if (
89
+ normalized.startsWith("../") ||
90
+ !/^(1x1|4x3)\\/[a-z0-9-]+\\.svg$/.test(normalized)
91
+ ) {
92
+ res.statusCode = 404;
93
+ res.end();
94
+ return;
95
+ }
96
+
97
+ const filePath = path.join(flagsRoot, normalized);
98
+ fs.readFile(filePath, (err, content) => {
99
+ if (err) {
100
+ res.statusCode = 404;
101
+ res.end();
102
+ return;
103
+ }
104
+ res.setHeader("Content-Type", "image/svg+xml");
105
+ res.end(content);
106
+ });
107
+ });
108
+ },
109
+ };
110
+ }
111
+
112
+ function toArray(value) {
113
+ if (!value) return [];
114
+ return Array.isArray(value) ? value : [value];
115
+ }
116
+
117
+ export default async function mvframeWrappedConfig(configEnv) {
118
+ const loaded =
119
+ typeof hostConfig === "function" ? await hostConfig(configEnv) : hostConfig;
120
+ const base = loaded || {};
121
+ const server = { ...(base.server || {}) };
122
+ if (server.host == null) {
123
+ server.host = "0.0.0.0";
124
+ }
125
+
126
+ return {
127
+ ...base,
128
+ root: base.root || ${JSON.stringify(cwd)},
129
+ server,
130
+ plugins: [
131
+ ...toArray(base.plugins),
132
+ createFlagAssetsPlugin(${JSON.stringify(flagsRoot)}),
133
+ ],
134
+ };
135
+ }
136
+ `;
137
+ const configPath = path.join(tmpRoot, "mvframe-vite.config.mjs");
138
+ fs.writeFileSync(configPath, source, "utf8");
139
+ return configPath;
140
+ }
141
+
142
+ function shutdown(code = 0) {
143
+ if (shuttingDown) return;
144
+ shuttingDown = true;
145
+ if (child && !child.killed) {
146
+ child.kill("SIGTERM");
147
+ }
148
+ if (cleanupTemp) {
149
+ cleanupTemp();
150
+ }
151
+ setTimeout(() => process.exit(code), 200);
152
+ }
153
+
154
+ process.on("SIGINT", () => shutdown(0));
155
+ process.on("SIGTERM", () => shutdown(0));
156
+
157
+ function main() {
158
+ const cwd = process.cwd();
159
+ const viteEntry = resolveViteCli(cwd);
160
+ const tempFlags = createTempFlagAssets();
161
+ cleanupTemp = tempFlags.cleanup;
162
+ const configPath = createWrapperConfig({
163
+ cwd,
164
+ flagsRoot: tempFlags.flagsRoot,
165
+ tmpRoot: tempFlags.tmpRoot,
166
+ });
167
+
168
+ child = spawn(
169
+ viteEntry.includes(".zip/") ? resolvePackageManager(cwd) : process.execPath,
170
+ viteEntry.includes(".zip/")
171
+ ? ["vite", "--host", "0.0.0.0", "--config", configPath]
172
+ : [viteEntry, "--host", "0.0.0.0", "--config", configPath],
173
+ {
174
+ cwd,
175
+ env: process.env,
176
+ stdio: "inherit",
177
+ shell: false,
178
+ },
179
+ );
180
+
181
+ child.on("exit", (code, signal) => {
182
+ if (shuttingDown) return;
183
+ if (cleanupTemp) {
184
+ cleanupTemp();
185
+ }
186
+ process.exit(code === null ? (signal ? 1 : 0) : code);
187
+ });
188
+
189
+ child.on("error", (error) => {
190
+ console.error(`[mvframe-d] failed to start vite: ${error.message}`);
191
+ shutdown(1);
192
+ });
193
+ }
194
+
195
+ try {
196
+ main();
197
+ } catch (error) {
198
+ console.error(`[mvframe-d] failed to start vite: ${error.message}`);
199
+ process.exit(1);
200
+ }
@@ -1,24 +1,38 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Run Vite and the MVFrame DingTalk notify service together.
3
+ * Run Vite, optionally with the MVFrame DingTalk notify service.
4
4
  * This mirrors `mvframe-b`: the package owns the command, the host may opt in
5
5
  * with `yarn exec mvframe-d` or a local script.
6
6
  */
7
7
  const { spawn } = require("child_process");
8
8
  const path = require("path");
9
- const fs = require("fs");
10
- const { createRequire } = require("module");
11
9
 
12
10
  const children = new Set();
13
11
  let shuttingDown = false;
14
12
 
13
+ function parseArgs(argv) {
14
+ const notifyArgs = [];
15
+ let shouldStartNotify = false;
16
+
17
+ for (const arg of argv) {
18
+ if (arg === "-n" || arg === "--notify") {
19
+ shouldStartNotify = true;
20
+ continue;
21
+ }
22
+ notifyArgs.push(arg);
23
+ }
24
+
25
+ return { notifyArgs, shouldStartNotify };
26
+ }
27
+
15
28
  function spawnChild(name, command, args, options = {}) {
29
+ const { optional = false, ...spawnOptions } = options;
16
30
  const child = spawn(command, args, {
17
31
  cwd: process.cwd(),
18
32
  env: process.env,
19
33
  stdio: "inherit",
20
34
  shell: false,
21
- ...options,
35
+ ...spawnOptions,
22
36
  });
23
37
 
24
38
  children.add(child);
@@ -26,13 +40,28 @@ function spawnChild(name, command, args, options = {}) {
26
40
  child.on("exit", (code, signal) => {
27
41
  children.delete(child);
28
42
  if (shuttingDown) return;
43
+
44
+ if (optional) {
45
+ if (code !== 0) {
46
+ console.error(`[mvframe-d] ${name} exited with ${signal || code}; vite will keep running`);
47
+ }
48
+ return;
49
+ }
50
+
29
51
  if (code !== 0) {
30
52
  console.error(`[mvframe-d] ${name} exited with ${signal || code}`);
31
53
  shutdown(code || 1);
54
+ return;
32
55
  }
56
+ shutdown(0);
33
57
  });
34
58
 
35
59
  child.on("error", (error) => {
60
+ if (optional) {
61
+ children.delete(child);
62
+ console.error(`[mvframe-d] failed to start ${name}: ${error.message}; vite will keep running`);
63
+ return;
64
+ }
36
65
  console.error(`[mvframe-d] failed to start ${name}: ${error.message}`);
37
66
  shutdown(1);
38
67
  });
@@ -54,39 +83,14 @@ function shutdown(code = 0) {
54
83
  process.on("SIGINT", () => shutdown(0));
55
84
  process.on("SIGTERM", () => shutdown(0));
56
85
 
57
- const notifyArgs = process.argv.slice(2);
86
+ const { notifyArgs, shouldStartNotify } = parseArgs(process.argv.slice(2));
58
87
  const notifyScript = path.join(__dirname, "notify-server.js");
88
+ const viteScript = path.join(__dirname, "dev-vite-server.js");
59
89
 
60
- function resolveViteCli(cwd) {
61
- let vpkg = "";
62
- try {
63
- const projectRequire = createRequire(path.join(cwd, "package.json"));
64
- vpkg = projectRequire.resolve("vite/package.json");
65
- } catch {
66
- // Fall back to node_modules for non-PnP projects.
67
- }
68
-
69
- if (!vpkg) {
70
- vpkg = path.join(cwd, "node_modules", "vite", "package.json");
71
- }
72
-
73
- if (fs.existsSync(vpkg)) {
74
- const p = require(vpkg);
75
- const bin = typeof p.bin === "string" ? p.bin : p.bin && p.bin.vite;
76
- if (bin) {
77
- const cli = path.join(path.dirname(vpkg), bin);
78
- if (fs.existsSync(cli)) return cli;
79
- }
80
- }
81
- throw new Error(
82
- "未在当前项目找到 Vite(请先安装依赖;宿主项目可执行 yarn install 后再运行 mvframe-d)",
83
- );
90
+ if (shouldStartNotify) {
91
+ spawnChild("notify", process.execPath, [notifyScript, ...notifyArgs], {
92
+ optional: true,
93
+ });
84
94
  }
85
95
 
86
- spawnChild("notify", process.execPath, [notifyScript, ...notifyArgs]);
87
- try {
88
- const viteEntry = resolveViteCli(process.cwd());
89
- spawnChild("vite", process.execPath, [viteEntry, "--host", "0.0.0.0"]);
90
- } catch {
91
- spawnChild("vite", "yarn", ["vite", "--host", "0.0.0.0"]);
92
- }
96
+ spawnChild("vite", process.execPath, [viteScript]);
@@ -0,0 +1,85 @@
1
+ const { execFileSync } = require("child_process");
2
+ const fs = require("fs");
3
+ const os = require("os");
4
+ const path = require("path");
5
+ const { createRequire } = require("module");
6
+
7
+ const root = path.resolve(__dirname, "..");
8
+ const pnpPath = path.join(root, ".pnp.cjs");
9
+
10
+ if (fs.existsSync(pnpPath)) {
11
+ require(pnpPath).setup();
12
+ }
13
+
14
+ function resolveFlagSource() {
15
+ const projectRequire = createRequire(path.join(root, "package.json"));
16
+ const flagPackagePath = projectRequire.resolve("flag-icons/package.json");
17
+ const flagRoot = path.dirname(flagPackagePath);
18
+ return path.join(flagRoot, "flags");
19
+ }
20
+
21
+ function copyFromZip(zipBackedPath, target, tmpParent) {
22
+ const marker = ".zip/";
23
+ const splitAt = zipBackedPath.indexOf(marker);
24
+ if (splitAt < 0) return false;
25
+
26
+ const zipPath = zipBackedPath.slice(0, splitAt + ".zip".length);
27
+ const innerPath = zipBackedPath.slice(splitAt + marker.length);
28
+ const tmp = fs.mkdtempSync(path.join(tmpParent, ".tmp-flag-icons-"));
29
+
30
+ try {
31
+ execFileSync("unzip", ["-q", zipPath, `${innerPath}/*`, "-d", tmp], {
32
+ stdio: "ignore",
33
+ });
34
+ const extracted = path.join(tmp, innerPath);
35
+ fs.cpSync(extracted, target, { recursive: true });
36
+ } finally {
37
+ fs.rmSync(tmp, { recursive: true, force: true });
38
+ }
39
+
40
+ return true;
41
+ }
42
+
43
+ function copyFlagAssetsTo(dest, options = {}) {
44
+ const src = resolveFlagSource();
45
+ const clean = options.clean !== false;
46
+ const tmpParent = options.tmpParent || path.dirname(dest);
47
+
48
+ if (clean) {
49
+ fs.rmSync(dest, { recursive: true, force: true });
50
+ }
51
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
52
+ fs.mkdirSync(tmpParent, { recursive: true });
53
+
54
+ if (src.includes(".zip/")) {
55
+ copyFromZip(src, dest, tmpParent);
56
+ } else if (fs.existsSync(src)) {
57
+ fs.cpSync(src, dest, { recursive: true });
58
+ } else {
59
+ throw new Error(`[flag-assets] flag-icons assets not found: ${src}`);
60
+ }
61
+
62
+ return dest;
63
+ }
64
+
65
+ function createTempFlagAssets() {
66
+ const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), "mvframe-flags-"));
67
+ const flagsRoot = path.join(tmpRoot, "flags");
68
+
69
+ copyFlagAssetsTo(flagsRoot, {
70
+ tmpParent: tmpRoot,
71
+ });
72
+
73
+ return {
74
+ flagsRoot,
75
+ tmpRoot,
76
+ cleanup() {
77
+ fs.rmSync(tmpRoot, { recursive: true, force: true });
78
+ },
79
+ };
80
+ }
81
+
82
+ module.exports = {
83
+ copyFlagAssetsTo,
84
+ createTempFlagAssets,
85
+ };
@@ -63,9 +63,10 @@ ${getSharedStyleRulesForCodex()}
63
63
 
64
64
  ## 全局方法
65
65
 
66
- - 优先使用 MVFrame 全局方法,不要重复 import 或本地封装等价 helper:\`globalThis.$d\`、\`$fa\`、\`$fu\`、\`$pm\`、\`$db\`、\`$copy\`、\`$deepClone\`、\`$getLang\`、\`$getImg\`、\`$sc\`、\`$c.info\`。
66
+ - 优先使用 MVFrame 全局方法,不要重复 import 或本地封装等价 helper:\`globalThis.$d\`、\`$l\`、\`$fa\`、\`$fu\`、\`$pm\`、\`$db\`、\`$copy\`、\`$deepClone\`、\`$getLang\`、\`$getImg\`、\`$sc\`、\`$c.info\`。
67
67
  - 在模板里,如果这些方法已经通过 Vue globalProperties 注入,直接调用即可。
68
68
  - 对普通 JS 模块,优先使用 \`globalThis.$xxx\`;只有确实需要显式 import 时,再使用 MVFrame 的子路径导出。
69
+ - 多语言变量统一使用 \`$l("helloUser", { name: userName })\`,字典文案写作 \`"Hello {name}"\`;变量名仅使用字母、数字、下划线、点、短横线或 \`$\`,缺失变量会保留原 \`{name}\` 占位。
69
70
 
70
71
  ## 路由、Store 与 Maps
71
72
 
@@ -902,7 +902,7 @@ yarn dev
902
902
  如需同时启动 Vite 与 MVFrame 钉钉通知服务,可显式执行框架命令(与 \`mvframe-b\` 类似由 MVFrame 包提供,不会自动覆盖宿主脚本):
903
903
 
904
904
  \`\`\`bash
905
- yarn exec mvframe-d
905
+ yarn exec mvframe-d -n
906
906
  \`\`\`
907
907
 
908
908
  若需跳过对 \`package.json\` 的修改:\`node scripts/scaffold-app.js --no-package-json\` 或 \`node scripts/scaffold-app.js -n\`。
@@ -1007,7 +1007,7 @@ yarn exec mvframe-notify
1007
1007
  同时启动 Vite 和通知服务:
1008
1008
 
1009
1009
  \`\`\`bash
1010
- yarn exec mvframe-d
1010
+ yarn exec mvframe-d -n
1011
1011
  \`\`\`
1012
1012
 
1013
1013
  前端发送: