cloud-web-corejs 1.0.54-dev.776 → 1.0.54-dev.778

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cloud-web-corejs",
3
3
  "private": false,
4
- "version": "1.0.54-dev.776",
4
+ "version": "1.0.54-dev.778",
5
5
  "scripts": {
6
6
  "dev": "vue-cli-service serve",
7
7
  "dev:micro": "vue-cli-service serve --port 17527",
@@ -146,6 +146,7 @@
146
146
  "src/components/jdPrint",
147
147
  "src/components/jsonImport",
148
148
  "src/components/langImport",
149
+ "src/components/micro-view-host",
149
150
  "src/components/mobile",
150
151
  "src/components/onlineTalk",
151
152
  "src/components/oplogTable",
@@ -0,0 +1,66 @@
1
+ /**
2
+ * 详情承载契约(纯常量 + props 构造,无副作用,可完整单测)。
3
+ * micro-view-host(主/渲染方)与子应用「详情承载入口」共同遵守。
4
+ * 完整设计见 docs/qiankun动态详情页承载方案.md 第 5 节。
5
+ *
6
+ * 关键前提:qiankun loadMicroApp 的 props 是同一 JS realm 内的普通对象,
7
+ * 函数可直接传入并被子应用调用——故上行回调用函数 props,不需事件总线;
8
+ * 真正跨不过去的是 Vue 实例(parentVue)与 $parent 链,由子应用侧用 shim 合成。
9
+ */
10
+
11
+ // props 标志:子应用 mount 时据此进入「详情承载」分支(而非常规整站渲染)
12
+ export const DETAIL_HOST_MODE = "microDetailHost";
13
+
14
+ // 上行回调字段名(函数 props)。子应用承载入口据此把详情页的
15
+ // $baseReload / _handleCallback / 关闭 / outParam.sync / 任意 listeners
16
+ // 转调回渲染方(见方案 §5.2 / §5.3 的 parentVue shim)。
17
+ export const DETAIL_HOST_CALLBACKS = [
18
+ "onReload",
19
+ "onHandleCallback",
20
+ "onClose",
21
+ "onUpdateOutParam",
22
+ "onEmit",
23
+ ];
24
+
25
+ /**
26
+ * 构造下发给子应用的 props。
27
+ *
28
+ * @param {object} input
29
+ * @param {string} input.appCode 归属子应用 appCode
30
+ * @param {string} input.targetPath 剥掉 /micro/<appCode> 后的子应用内路径
31
+ * @param {object} input.bizParams 业务字段整包(objTypeCode/formCode/dataId/param/queryParam…)
32
+ * @param {object} input.viewMeta 承载元数据(visibleKey/defaultShowWfContent/viewType)
33
+ * @param {*} input.initialOutParam outParam 初值(替代 .sync 入向)
34
+ * @param {object} input.baseProps 基础 props(token/lang/userInfo/mainAdapter…)
35
+ * @param {object} input.callbacks 上行回调;仅函数值会被收录
36
+ * @returns {object} 传给 loadMicroApp 的 props
37
+ */
38
+ export function buildDetailHostProps(input = {}) {
39
+ const {
40
+ appCode,
41
+ targetPath,
42
+ bizParams,
43
+ viewMeta,
44
+ initialOutParam,
45
+ baseProps,
46
+ callbacks,
47
+ } = input;
48
+
49
+ const props = Object.assign({}, baseProps, {
50
+ [DETAIL_HOST_MODE]: true,
51
+ appCode: appCode || "",
52
+ targetPath: targetPath || "",
53
+ bizParams: bizParams || {},
54
+ viewMeta: viewMeta || {},
55
+ initialOutParam: initialOutParam,
56
+ });
57
+
58
+ const cb = callbacks || {};
59
+ DETAIL_HOST_CALLBACKS.forEach((name) => {
60
+ if (typeof cb[name] === "function") {
61
+ props[name] = cb[name];
62
+ }
63
+ });
64
+
65
+ return props;
66
+ }
@@ -0,0 +1,148 @@
1
+ <template>
2
+ <div :id="containerId" class="micro-view-host" style="height: 100%"></div>
3
+ </template>
4
+
5
+ <script>
6
+ /**
7
+ * 详情承载宿主:在弹框/容器内用 qiankun loadMicroApp 装载归属子应用,
8
+ * 渲染其私有详情页(组件不在当前 bundle,本地 require 拿不到)。
9
+ * 契约见 ./contract.js 与 docs/qiankun动态详情页承载方案.md 第 5 节。
10
+ *
11
+ * ⚠ 依赖子应用侧实现「详情承载入口」(方案 §5.5):mount 时识别 props.microDetailHost,
12
+ * 按 targetPath 解析自身组件、用 bizParams/viewMeta 绑 props、装 parentVue shim 渲染。
13
+ * 在子应用支持该入口前,本组件装载出的仍是子应用默认渲染,未必是目标详情页。
14
+ * 因此暂不接入各弹框站点——它们仍走 $message 短期提示兜底。
15
+ *
16
+ * 多实例:宿主实例名带唯一后缀,与路由保活实例(name=appCode)隔离;
17
+ * 同一 appCode 的保活实例与若干宿主实例可并存。要求子应用容忍多实例并发。
18
+ */
19
+ import { loadMicroApp } from "qiankun";
20
+ import { getToken } from "@base/utils/auth";
21
+ import { getAppRegistry, DEBUG_ENTRY } from "@base/microRouter";
22
+ import { buildDetailHostProps } from "./contract";
23
+
24
+ // 注册表一次会话内不变,缓存首个成功结果,避免每次开弹框都打逻辑参数接口
25
+ let registryCache = null;
26
+ function loadRegistry() {
27
+ if (!registryCache) {
28
+ registryCache = getAppRegistry().catch((e) => {
29
+ registryCache = null; // 失败不缓存,允许下次重试
30
+ return Promise.reject(e);
31
+ });
32
+ }
33
+ return registryCache;
34
+ }
35
+
36
+ let hostSeq = 0;
37
+
38
+ export default {
39
+ name: "MicroViewHost",
40
+ props: {
41
+ // 归属子应用 appCode(helper 的 remote 结果透出)
42
+ owner: { type: String, required: true },
43
+ // 剥掉 /micro/<appCode> 后的子应用内路径
44
+ targetPath: { type: String, default: "" },
45
+ // 业务字段整包
46
+ bizParams: { type: Object, default: () => ({}) },
47
+ // 承载元数据
48
+ viewMeta: { type: Object, default: () => ({}) },
49
+ // outParam 初值
50
+ initialOutParam: { default: undefined },
51
+ },
52
+ data() {
53
+ hostSeq += 1;
54
+ return {
55
+ containerId: "micro-viewhost-" + this.owner + "-" + hostSeq,
56
+ instance: null,
57
+ failed: false,
58
+ };
59
+ },
60
+ mounted() {
61
+ this.load();
62
+ },
63
+ beforeDestroy() {
64
+ this.unmount();
65
+ },
66
+ methods: {
67
+ load() {
68
+ loadRegistry()
69
+ .then((apps) => {
70
+ if (this._isDestroyed || this._isBeingDestroyed) return;
71
+ const app = (apps || []).find((a) => a.appCode === this.owner);
72
+ if (!app || !app.entry) {
73
+ this.fail("未在应用注册表找到子应用或缺 entry:" + this.owner);
74
+ return;
75
+ }
76
+ // 逻辑参数 micro_debug_enabled=true 时,与路由整站装载一致:改用本机约定端口,
77
+ // 不动注册表 entry。本机联调 detail-host 时子应用 devServer 起在 17527 即可。
78
+ const entry = app.debugEnabled ? DEBUG_ENTRY : app.entry;
79
+ if (app.debugEnabled) {
80
+ // eslint-disable-next-line no-console
81
+ console.warn(
82
+ "[MicroViewHost] ⚠ 调试装载:" + this.owner + " → " + entry
83
+ );
84
+ }
85
+ this.mountApp(entry);
86
+ })
87
+ .catch((e) => {
88
+ this.fail("读取应用注册表失败", e);
89
+ });
90
+ },
91
+ mountApp(entry) {
92
+ const props = buildDetailHostProps({
93
+ appCode: this.owner,
94
+ targetPath: this.targetPath,
95
+ bizParams: this.bizParams,
96
+ viewMeta: this.viewMeta,
97
+ initialOutParam: this.initialOutParam,
98
+ baseProps: {
99
+ token: getToken(),
100
+ lang: localStorage.getItem("i18n-lang") || "",
101
+ },
102
+ callbacks: {
103
+ onReload: () => this.$emit("reload"),
104
+ onHandleCallback: (flag) => this.$emit("handle-callback", flag),
105
+ onClose: () => this.$emit("close"),
106
+ onUpdateOutParam: (v) => this.$emit("update-out-param", v),
107
+ onEmit: (name, ...args) => this.$emit("bridge-emit", name, args),
108
+ },
109
+ });
110
+ try {
111
+ this.instance = loadMicroApp({
112
+ name: this.owner + "@detailhost-" + this.containerId,
113
+ entry,
114
+ container: this.$el,
115
+ props,
116
+ });
117
+ const p = this.instance.mountPromise;
118
+ if (p && typeof p.then === "function") {
119
+ p.then(() => this.$emit("mounted")).catch((e) => {
120
+ this.fail("子应用挂载失败:" + this.owner, e);
121
+ });
122
+ }
123
+ } catch (e) {
124
+ this.fail("loadMicroApp 失败:" + this.owner, e);
125
+ }
126
+ },
127
+ unmount() {
128
+ const inst = this.instance;
129
+ if (!inst) return;
130
+ this.instance = null;
131
+ const p = inst.mountPromise || Promise.resolve();
132
+ p.then(() => inst.unmount()).catch(() => {});
133
+ },
134
+ fail(msg, err) {
135
+ this.failed = true;
136
+ // eslint-disable-next-line no-console
137
+ console.error("[MicroViewHost] " + msg, err || "");
138
+ this.$emit("load-error", this.owner);
139
+ },
140
+ },
141
+ };
142
+ </script>
143
+
144
+ <style scoped>
145
+ .micro-view-host {
146
+ width: 100%;
147
+ }
148
+ </style>
@@ -21,6 +21,18 @@ import MenuFallback from "@base/views/user/menuFallback/index.vue";
21
21
  let hostRegistryApps = [];
22
22
  let hostMicroRoutes = [];
23
23
 
24
+ /**
25
+ * 本应用(渲染方)在微前端命名空间里的身份。
26
+ * 子应用取 settings.appCode(派生自各自 WEB_PREFIX);主应用 appCode 恒空,
27
+ * 但它的身份就是 WEB_PREFIX 去斜杠(/sys → sys)——故回落 WEB_PREFIX 派生。
28
+ * 用于:① 宿主自排除(不装载自己);② 组件路径解析剥归属前缀,使
29
+ * /micro/sys/base/user/user/list 等同于 /base/user/user/list(主应用把归属自己的
30
+ * 访问路径剥掉 /micro/<自己> 两段后按常规解析)。
31
+ */
32
+ function getOwnAppCode() {
33
+ return settings.appCode || (window.WEB_PREFIX || "").replace(/^\/+/, "");
34
+ }
35
+
24
36
  // 子应用被"本地调试覆盖"装载时置 true:启用按访问路径直接解析组件的兜底路由,
25
37
  // 使联调期可用 URL 直达尚未配置菜单的页面。正式注册表装载时恒为 false——
26
38
  // 菜单即权限边界,不能让任意路径都能打开组件
@@ -45,7 +57,7 @@ function createDebugPathRoute() {
45
57
  const path = (this.$route && this.$route.path) || "";
46
58
  const componentPath = resolveComponentPath(
47
59
  { url: path },
48
- settings.appCode || ""
60
+ getOwnAppCode()
49
61
  );
50
62
  if (!componentPath) {
51
63
  return h(MenuFallback, { props: { componentPath: path } });
@@ -242,7 +254,7 @@ const actions = {
242
254
  // 主应用 appCode 恒为空(WEB_PREFIX===MAIN_WEB_PREFIX 不派生),但它在注册表里的
243
255
  // 身份是 WEB_PREFIX 去斜杠(/sys → sys)——故回落到 WEB_PREFIX 派生,
244
256
  // 否则注册表误配了主应用自身条目时排不掉、导致主应用自嵌套。
245
- let ownAppCode = settings.appCode || (window.WEB_PREFIX || "").replace(/^\/+/, "");
257
+ let ownAppCode = getOwnAppCode();
246
258
  hostRegistryApps = (apps || []).filter(
247
259
  (app) => app.appCode !== ownAppCode
248
260
  );
@@ -365,8 +377,8 @@ function createRoute3(route3, flag) {
365
377
  param = getUrlParams(path);
366
378
  path = path.substring(0, pIndex);
367
379
  }
368
- // 三步解析第 3 步:/base/ 命名空间转 @base/views;url 首段为本应用 appCode 时剥掉
369
- componentPath = resolveComponentPath(route3, settings.appCode || "");
380
+ // 三步解析第 3 步:/base/ 命名空间转 @base/views;访问路径首段为本应用(含主应用 WEB_PREFIX 身份)时剥 /micro/<自己>
381
+ componentPath = resolveComponentPath(route3, getOwnAppCode());
370
382
  menuCode = route3.menuCode;
371
383
  }
372
384
  } else {
@@ -146,13 +146,20 @@ function requireAppView(rel) {
146
146
  return require("@/views" + rel);
147
147
  }
148
148
 
149
- /** 惰性读取本应用 appCode,避免把整个 store 拉进 resolveViewPath 的单测 */
149
+ /**
150
+ * 惰性读取本应用(渲染方)appCode,避免把 settings 拉进 resolveViewPath 的纯函数单测。
151
+ * 子应用取 settings.appCode(qiankun mount 会写入 props.appCode,与派生一致);
152
+ * 主应用 appCode 恒空、身份是 WEB_PREFIX 去斜杠(/sys → sys)——故回落 WEB_PREFIX。
153
+ * 与 store/modules/permission.js 的 getOwnAppCode 同口径:使 /micro/<自己>/... 被判成本地,
154
+ * 不误判成 remote 去自装载(也修掉子应用独立运行时 micro.appCode 为空的老坑)。
155
+ */
150
156
  function getRendererAppCode() {
157
+ const webPrefix = (window.WEB_PREFIX || "").replace(/^\/+/, "");
151
158
  try {
152
- const store = require("@base/store").default;
153
- return (store && store.state && store.state.micro && store.state.micro.appCode) || "";
159
+ const settings = require("@/settings").default;
160
+ return (settings && settings.appCode) || webPrefix;
154
161
  } catch (e) {
155
- return "";
162
+ return webPrefix;
156
163
  }
157
164
  }
158
165