cloud-web-corejs 1.0.54-dev.774 → 1.0.54-dev.777
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 +3 -1
- package/src/components/micro-view-host/contract.js +66 -0
- package/src/components/micro-view-host/index.vue +148 -0
- package/src/components/mobile/wf/mixins/wfModifyDialogMixin.js +51 -47
- package/src/components/wf/wf.js +4 -1
- package/src/components/xform/form-designer/form-widget/dialog/fileReferenceDialog.vue +35 -15
- package/src/index.js +87 -0
- package/src/microRouter/index.js +1 -1
- package/src/store/modules/permission.js +42 -39
- package/src/utils/resolveViewComponent.js +191 -0
- package/src/views/user/file_view_ins/list.vue +22 -1
- package/src/views/user/home/index.vue +3 -10
- package/src/views/user/notify_message/dialog.vue +22 -1
- package/src/views/user/outLink/form_view.vue +5 -14
- package/src/views/user/outLink/index.vue +6 -1
- package/src/views/user/outLink/view.vue +5 -13
- package/src/views/user/wf/iframe/index.vue +6 -1
- package/src/views/user/wf/iframe/index2.vue +6 -1
- package/src/views/user/wf/wf_manage/list.vue +22 -1
- package/src/views/user/wf/wf_manage/list2.vue +22 -1
- package/src/views/user/wf/wf_manage/wfContentDialog.vue +23 -1
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cloud-web-corejs",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.0.54-dev.
|
|
4
|
+
"version": "1.0.54-dev.777",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "vue-cli-service serve",
|
|
7
|
+
"dev:micro": "vue-cli-service serve --port 17527",
|
|
7
8
|
"lint": "eslint --ext .js,.vue src",
|
|
8
9
|
"build:prod": "vue-cli-service build",
|
|
9
10
|
"build:stage": "vue-cli-service build --mode staging",
|
|
@@ -145,6 +146,7 @@
|
|
|
145
146
|
"src/components/jdPrint",
|
|
146
147
|
"src/components/jsonImport",
|
|
147
148
|
"src/components/langImport",
|
|
149
|
+
"src/components/micro-view-host",
|
|
148
150
|
"src/components/mobile",
|
|
149
151
|
"src/components/onlineTalk",
|
|
150
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>
|
|
@@ -1,47 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
this
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
this
|
|
38
|
-
this.$
|
|
39
|
-
},
|
|
40
|
-
|
|
41
|
-
this
|
|
42
|
-
this.
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
1
|
+
import {requireViewCompat} from "@base/utils/resolveViewComponent";
|
|
2
|
+
|
|
3
|
+
let mixin = {};
|
|
4
|
+
let configUtil = {
|
|
5
|
+
baseUrl: process.env.VUE_APP_BASE_API,
|
|
6
|
+
// 归属自己 / 包内组件本地渲染;归属别家子应用(remote)或缺文件时返回 null,
|
|
7
|
+
// 不再抛错崩溃。归属解析见 @base/utils/resolveViewComponent。
|
|
8
|
+
requireView: (url) => {
|
|
9
|
+
return requireViewCompat(url);
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
mixin = {
|
|
13
|
+
name: "wfModifyMixin",
|
|
14
|
+
props: {
|
|
15
|
+
dataId: [String, Number],
|
|
16
|
+
code: [String, Number],
|
|
17
|
+
visible: Boolean,
|
|
18
|
+
paramData: Object,
|
|
19
|
+
parentVue: Object,
|
|
20
|
+
wfInfo: Object,
|
|
21
|
+
},
|
|
22
|
+
data() {
|
|
23
|
+
return {
|
|
24
|
+
showModifyDialog: false,
|
|
25
|
+
showBillEdit: false,
|
|
26
|
+
content: "",
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
async mounted() {
|
|
30
|
+
this.openWfModifyDialog(this.code);
|
|
31
|
+
},
|
|
32
|
+
methods: {
|
|
33
|
+
openWfModifyDialog() {
|
|
34
|
+
let row = this.paramData;
|
|
35
|
+
let url = row.mobileurl + ".vue";
|
|
36
|
+
this.showModifyDialog = true;
|
|
37
|
+
this.content = configUtil.requireView(url);
|
|
38
|
+
this.$openEditView("showBillEdit");
|
|
39
|
+
},
|
|
40
|
+
close() {
|
|
41
|
+
this.$destroy();
|
|
42
|
+
this.$el.parentElement.removeChild(this.$el);
|
|
43
|
+
},
|
|
44
|
+
refreshEdit() {
|
|
45
|
+
this.showModifyDialog = false;
|
|
46
|
+
this.parentVue.$baseReload()
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default mixin;
|
package/src/components/wf/wf.js
CHANGED
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
import {getToken} from "../../utils/auth";
|
|
3
3
|
import settingConfig from "@/settings.js";
|
|
4
4
|
import {selectDialogMixins} from "../../mixins/selectDialog";
|
|
5
|
+
import {requireViewCompat} from "@base/utils/resolveViewComponent";
|
|
5
6
|
|
|
6
7
|
let configUtil = {
|
|
7
8
|
baseUrl: process.env.VUE_APP_BASE_API,
|
|
8
9
|
getToken,
|
|
10
|
+
// 归属自己 / 包内组件本地渲染;归属别家子应用(remote)或缺文件时返回 null,
|
|
11
|
+
// 不再抛错崩溃。归属解析见 @base/utils/resolveViewComponent。
|
|
9
12
|
requireView: (url) => {
|
|
10
|
-
return
|
|
13
|
+
return requireViewCompat(url);
|
|
11
14
|
},
|
|
12
15
|
};
|
|
13
16
|
|
|
@@ -11,6 +11,18 @@
|
|
|
11
11
|
:_dataId.sync="dataId" :defaultShowWfContent="defaultShowWfContent" :_isOutLink="true"
|
|
12
12
|
:parent-target="_self"
|
|
13
13
|
@reload="$reloadHandle" v-bind="queryParam" v-on="listeners"></component>
|
|
14
|
+
<micro-view-host
|
|
15
|
+
v-else-if="showWfContent && remoteView"
|
|
16
|
+
:owner="remoteView.owner"
|
|
17
|
+
:target-path="remoteView.targetPath"
|
|
18
|
+
:biz-params="remoteView.bizParams"
|
|
19
|
+
:view-meta="remoteView.viewMeta"
|
|
20
|
+
:initial-out-param="outParam"
|
|
21
|
+
@reload="$reloadHandle"
|
|
22
|
+
@update-out-param="outParam = $event"
|
|
23
|
+
@bridge-emit="onBridgeEmit"
|
|
24
|
+
@close="showWfContent = false"
|
|
25
|
+
></micro-view-host>
|
|
14
26
|
</div>
|
|
15
27
|
<span slot="footer" class="dialog-footer" v-if="option.showFooter!==false" v-bind="option.footerConfig">
|
|
16
28
|
<el-button type="primary" plain class="button-sty" @click="close">
|
|
@@ -26,6 +38,7 @@
|
|
|
26
38
|
</template>
|
|
27
39
|
|
|
28
40
|
<script>
|
|
41
|
+
import { loadViewComponent } from "@base/utils/resolveViewComponent";
|
|
29
42
|
|
|
30
43
|
export default {
|
|
31
44
|
components: {},
|
|
@@ -62,6 +75,7 @@ export default {
|
|
|
62
75
|
|
|
63
76
|
showWfContent: true,
|
|
64
77
|
wfContent: null,
|
|
78
|
+
remoteView: null,
|
|
65
79
|
outParam: null,
|
|
66
80
|
// dataId: null,
|
|
67
81
|
defaultShowWfContent: null,
|
|
@@ -174,23 +188,29 @@ export default {
|
|
|
174
188
|
|
|
175
189
|
this.showWfContent = true;
|
|
176
190
|
|
|
177
|
-
let
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
191
|
+
let res = loadViewComponent(url);
|
|
192
|
+
this.remoteView =
|
|
193
|
+
res.kind === "remote"
|
|
194
|
+
? {
|
|
195
|
+
owner: res.owner,
|
|
196
|
+
targetPath: res.targetPath,
|
|
197
|
+
bizParams: this.queryParam,
|
|
198
|
+
viewMeta: {
|
|
199
|
+
visibleKey: "showWfContent",
|
|
200
|
+
defaultShowWfContent: this.defaultShowWfContent,
|
|
201
|
+
_isOutLink: true,
|
|
202
|
+
_dataId: this.dataId,
|
|
203
|
+
},
|
|
204
|
+
}
|
|
205
|
+
: null;
|
|
206
|
+
this.wfContent = res.component;
|
|
192
207
|
},
|
|
193
208
|
|
|
209
|
+
// remote 承载态下,把子应用桥接回来的任意事件按名字派回原 option.on 监听
|
|
210
|
+
onBridgeEmit(name, args) {
|
|
211
|
+
let fn = this.listeners && this.listeners[name];
|
|
212
|
+
if (typeof fn === "function") fn.apply(null, args || []);
|
|
213
|
+
},
|
|
194
214
|
|
|
195
215
|
reload(e, option) {
|
|
196
216
|
let updateParam = option?.updateParam || {};
|
package/src/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import store from "@base/store";
|
|
|
12
12
|
import router, { resetRouter } from "@base/router";
|
|
13
13
|
import settings from "@/settings";
|
|
14
14
|
import { setToken as setAuthToken } from "@base/utils/auth";
|
|
15
|
+
import { loadViewComponent } from "@base/utils/resolveViewComponent";
|
|
15
16
|
|
|
16
17
|
import "@/icons"; // icon
|
|
17
18
|
import "@base/permission"; // permission control
|
|
@@ -238,6 +239,11 @@ Object.keys(filters).forEach((key) => {
|
|
|
238
239
|
Vue.filter(key, filters[key]);
|
|
239
240
|
});
|
|
240
241
|
|
|
242
|
+
// 详情承载宿主:弹框 remote 分支用它 loadMicroApp 装载归属子应用渲染私有详情页
|
|
243
|
+
Vue.component("micro-view-host", () =>
|
|
244
|
+
import("@base/components/micro-view-host/index.vue")
|
|
245
|
+
);
|
|
246
|
+
|
|
241
247
|
Vue.config.productionTip = false;
|
|
242
248
|
|
|
243
249
|
let instance = null;
|
|
@@ -253,6 +259,82 @@ function render(props = {}) {
|
|
|
253
259
|
window.$vueRoot = instance;
|
|
254
260
|
}
|
|
255
261
|
|
|
262
|
+
/**
|
|
263
|
+
* 详情承载入口(qiankun 详情承载协议 §5.5)。
|
|
264
|
+
* 主应用/渲染方的 micro-view-host 用 loadMicroApp 装载本应用并置 props.microDetailHost=true,
|
|
265
|
+
* 要求只渲染 targetPath 指向的详情页、把详情页的刷新/关闭/回调桥接回主应用,不出整站壳。
|
|
266
|
+
* 契约字段见 docs/qiankun详情承载子应用对接清单.md。
|
|
267
|
+
*
|
|
268
|
+
* ⚠ parentVue shim 的委托语义需真机联调打磨:详情页 getTarget(this) 命中 shim 后会用到
|
|
269
|
+
* $http/$message/$baseConfirm/$attrs 等——这些经原型委托到宿主根实例(全局插件已装齐),
|
|
270
|
+
* 仅 $baseReload / _handleCallback 覆盖为回主应用的动作。个别详情页若有更深的 $parent 依赖,
|
|
271
|
+
* 按对接清单 §5.6 做最小改造。
|
|
272
|
+
*/
|
|
273
|
+
function mountDetailHost(props = {}) {
|
|
274
|
+
if (props.appCode) settings.appCode = props.appCode;
|
|
275
|
+
if (props.token) {
|
|
276
|
+
setAuthToken(props.token);
|
|
277
|
+
store.commit("user/SET_TOKEN", props.token);
|
|
278
|
+
}
|
|
279
|
+
if (props.lang) i18n.locale = props.lang;
|
|
280
|
+
|
|
281
|
+
const appCode = props.appCode || settings.appCode;
|
|
282
|
+
const resolved = loadViewComponent(props.targetPath, { appCode });
|
|
283
|
+
const target = resolved.component;
|
|
284
|
+
const bizParams = props.bizParams || {};
|
|
285
|
+
const viewMeta = props.viewMeta || {};
|
|
286
|
+
|
|
287
|
+
// shim 需先于 render 存在(作为 parentVue prop 传入),其 Vue 能力在挂载后经原型委托到根实例
|
|
288
|
+
const shim = {
|
|
289
|
+
$baseReload: () => props.onReload && props.onReload(),
|
|
290
|
+
_handleCallback: (flag) => props.onHandleCallback && props.onHandleCallback(flag),
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
const { container } = props;
|
|
294
|
+
const mountEl = container ? container.querySelector("#app") : "#app";
|
|
295
|
+
instance = new Vue({
|
|
296
|
+
store,
|
|
297
|
+
i18n,
|
|
298
|
+
render(h) {
|
|
299
|
+
if (!target) {
|
|
300
|
+
return h(
|
|
301
|
+
"div",
|
|
302
|
+
{ staticClass: "micro-detail-host-missing" },
|
|
303
|
+
"详情页组件未找到:" + (props.targetPath || "")
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
return h(target, {
|
|
307
|
+
props: Object.assign({}, bizParams, viewMeta, {
|
|
308
|
+
parentVue: shim,
|
|
309
|
+
_handleCallback: (flag) =>
|
|
310
|
+
props.onHandleCallback && props.onHandleCallback(flag),
|
|
311
|
+
outParam: props.initialOutParam,
|
|
312
|
+
}),
|
|
313
|
+
on: {
|
|
314
|
+
reload: () => props.onReload && props.onReload(),
|
|
315
|
+
close: () => props.onClose && props.onClose(),
|
|
316
|
+
"update:outParam": (v) =>
|
|
317
|
+
props.onUpdateOutParam && props.onUpdateOutParam(v),
|
|
318
|
+
},
|
|
319
|
+
});
|
|
320
|
+
},
|
|
321
|
+
}).$mount(mountEl);
|
|
322
|
+
// #4 listeners 透传:详情页里父级 v-on="listeners" 那批是详情页直接 this.$emit 的,
|
|
323
|
+
// 拦截根子组件的 $emit,任意事件都转发给主应用的 onEmit(按名字派回原 option.on)。
|
|
324
|
+
const child = instance.$children && instance.$children[0];
|
|
325
|
+
if (child && typeof child.$emit === "function") {
|
|
326
|
+
const rawEmit = child.$emit.bind(child);
|
|
327
|
+
child.$emit = (name, ...args) => {
|
|
328
|
+
if (typeof props.onEmit === "function") props.onEmit(name, ...args);
|
|
329
|
+
return rawEmit(name, ...args);
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
// 挂载后把 shim 的原型指向根实例:$http/$message/$baseConfirm 等委托过去,
|
|
333
|
+
// 而 shim 自有的 $baseReload/_handleCallback 覆盖生效(详情页动作时才会调用)
|
|
334
|
+
Object.setPrototypeOf(shim, instance);
|
|
335
|
+
window.$vueRoot = instance;
|
|
336
|
+
}
|
|
337
|
+
|
|
256
338
|
if (!window.__POWERED_BY_QIANKUN__) {
|
|
257
339
|
// 独立运行 / 主应用形态:行为与拆分前一致
|
|
258
340
|
render();
|
|
@@ -266,6 +348,11 @@ if (!window.__POWERED_BY_QIANKUN__) {
|
|
|
266
348
|
export async function bootstrap() {}
|
|
267
349
|
|
|
268
350
|
export async function mount(props = {}) {
|
|
351
|
+
if (props.microDetailHost) {
|
|
352
|
+
// 详情承载模式(micro-view-host 装载):不走整站壳/路由/菜单,
|
|
353
|
+
// 只在容器里渲染 props.targetPath 指向的本应用组件。见对接清单文档。
|
|
354
|
+
return mountDetailHost(props);
|
|
355
|
+
}
|
|
269
356
|
if (props.appCode) {
|
|
270
357
|
// 主应用可经 props 覆盖,子应用也可在自身 settings.js 里声明
|
|
271
358
|
settings.appCode = props.appCode;
|
package/src/microRouter/index.js
CHANGED
|
@@ -31,7 +31,7 @@ const CONTAINER_WRAPPER_ID = "Appmicro";
|
|
|
31
31
|
* 调试态不落任何存储、不读 URL 查询参数——路径本身就是开关,因此入口只能是约定值。
|
|
32
32
|
* 各子应用把 devServer 端口固定为 17527 即可零配置被主应用装载。
|
|
33
33
|
*/
|
|
34
|
-
const DEBUG_ENTRY = "http://localhost:17527/";
|
|
34
|
+
export const DEBUG_ENTRY = "http://localhost:17527/";
|
|
35
35
|
|
|
36
36
|
// 保活管理:appCode → { instance, el };离开子应用路由只隐藏容器不卸载,
|
|
37
37
|
// 切回直接显示并经 update 生命周期同步路由,页面状态(页签/表格/表单)得以保留
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { constantRoutes } from "@base/router";
|
|
2
|
-
import { asyncRoutes, sidebarRoutes } from "@base/router/modules/system";
|
|
3
|
-
import Layout from "@/layout";
|
|
4
|
-
import { getRouters } from "../../api/menu";
|
|
1
|
+
import { constantRoutes } from "@base/router";
|
|
2
|
+
import { asyncRoutes, sidebarRoutes } from "@base/router/modules/system";
|
|
3
|
+
import Layout from "@/layout";
|
|
4
|
+
import { getRouters } from "../../api/menu";
|
|
5
5
|
import router from "@base/router";
|
|
6
6
|
import storeConfig from "../config/index";
|
|
7
7
|
import settings from "@/settings";
|
|
8
8
|
import {
|
|
9
9
|
resolveComponentPath,
|
|
10
|
-
resolveOwner,
|
|
11
|
-
dispatchMenus,
|
|
12
|
-
} from "@base/utils/menuAdapter";
|
|
13
|
-
import {
|
|
14
|
-
getAppRegistry,
|
|
15
|
-
registerSubApps,
|
|
16
|
-
buildSubAppRoutes,
|
|
17
|
-
} from "@base/microRouter";
|
|
18
|
-
import MenuFallback from "@base/views/user/menuFallback/index.vue";
|
|
10
|
+
resolveOwner,
|
|
11
|
+
dispatchMenus,
|
|
12
|
+
} from "@base/utils/menuAdapter";
|
|
13
|
+
import {
|
|
14
|
+
getAppRegistry,
|
|
15
|
+
registerSubApps,
|
|
16
|
+
buildSubAppRoutes,
|
|
17
|
+
} from "@base/microRouter";
|
|
18
|
+
import MenuFallback from "@base/views/user/menuFallback/index.vue";
|
|
19
19
|
|
|
20
20
|
// qiankun 宿主态(仅 settings.microMainEnabled 的主应用登录后填充)
|
|
21
21
|
let hostRegistryApps = [];
|
|
@@ -230,34 +230,37 @@ const actions = {
|
|
|
230
230
|
},
|
|
231
231
|
// qiankun 宿主编排:拉注册表 → 按归属切分 → 注册子应用,再走常规路由生成。
|
|
232
232
|
// 非宿主(未开 microMainEnabled / 自身被 qiankun 挂载)直接透传。
|
|
233
|
-
setupHostAndRoutes({ dispatch, commit, rootState }, rows = []) {
|
|
233
|
+
setupHostAndRoutes({ dispatch, commit, rootState }, rows = []) {
|
|
234
234
|
let isHost =
|
|
235
235
|
settings.microMainEnabled === true && !window.__POWERED_BY_QIANKUN__;
|
|
236
|
-
if (!isHost) {
|
|
237
|
-
return dispatch("setSidebarRoute", rows);
|
|
238
|
-
}
|
|
239
|
-
return getAppRegistry().then((apps) => {
|
|
240
|
-
// 自排除:自身也在注册表时(子应用开宿主形态互访别家应用)不装载自己,
|
|
241
|
-
// 否则会自嵌套且自身菜单被误判为"派发给子应用"
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
);
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
236
|
+
if (!isHost) {
|
|
237
|
+
return dispatch("setSidebarRoute", rows);
|
|
238
|
+
}
|
|
239
|
+
return getAppRegistry().then((apps) => {
|
|
240
|
+
// 自排除:自身也在注册表时(子应用开宿主形态互访别家应用)不装载自己,
|
|
241
|
+
// 否则会自嵌套且自身菜单被误判为"派发给子应用"而跳过本地路由。
|
|
242
|
+
// 主应用 appCode 恒为空(WEB_PREFIX===MAIN_WEB_PREFIX 不派生),但它在注册表里的
|
|
243
|
+
// 身份是 WEB_PREFIX 去斜杠(/sys → sys)——故回落到 WEB_PREFIX 派生,
|
|
244
|
+
// 否则注册表误配了主应用自身条目时排不掉、导致主应用自嵌套。
|
|
245
|
+
let ownAppCode = settings.appCode || (window.WEB_PREFIX || "").replace(/^\/+/, "");
|
|
246
|
+
hostRegistryApps = (apps || []).filter(
|
|
247
|
+
(app) => app.appCode !== ownAppCode
|
|
248
|
+
);
|
|
249
|
+
commit(
|
|
250
|
+
"SET_REGISTRY_APP_CODES",
|
|
251
|
+
hostRegistryApps.map((app) => app.appCode)
|
|
252
|
+
);
|
|
253
|
+
let subAppMenus = dispatchMenus(rows, hostRegistryApps);
|
|
254
|
+
hostMicroRoutes = buildSubAppRoutes(hostRegistryApps, subAppMenus);
|
|
255
|
+
if (hostRegistryApps.length) {
|
|
256
|
+
registerSubApps(hostRegistryApps, {
|
|
257
|
+
subAppMenus,
|
|
258
|
+
userInfo: buildUserInfoSnapshot(rootState.user),
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
return dispatch("setSidebarRoute", rows);
|
|
262
|
+
});
|
|
263
|
+
},
|
|
261
264
|
// qiankun 子应用模式:主应用经 props 下发菜单,替代 getRouters 自拉
|
|
262
265
|
generateRoutesFromProps({ dispatch, rootState }, menus = []) {
|
|
263
266
|
// 调试覆盖装载时允许 URL 直达未配菜单的页面(handleMenuRoutes 追加兜底路由)
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 动态详情页组件解析(qiankun 微前端兼容)。
|
|
3
|
+
*
|
|
4
|
+
* 全库有一批「用运行时字符串 require 视图组件、就地渲染详情页」的站点
|
|
5
|
+
* (wf 单据详情、消息通知、外链单页、表单文件引用…),历史上各自散着
|
|
6
|
+
* 4 套前缀判断(白名单 / @base·@/ 前缀嗅探 / form 硬分叉 / 裸拼)。本文件
|
|
7
|
+
* 把解析逻辑收敛到一处,并让它在微前端下正确区分组件归属。
|
|
8
|
+
*
|
|
9
|
+
* 归属三类(对齐 docs/qiankun接入协议.md 的命名空间语义):
|
|
10
|
+
* ① base —— 组件在 cloud-web-corejs 包内(@base/views),任何应用都有
|
|
11
|
+
* ② localPrivate —— 渲染方自己的私有视图(@/views)
|
|
12
|
+
* ③ remote —— 归属别的子应用的私有视图;组件不在当前 bundle,
|
|
13
|
+
* 不能本地 require,交调用方走 micro-view-host 装载或兜底
|
|
14
|
+
* (详见 docs/qiankun动态详情页承载方案.md 第 5 节)
|
|
15
|
+
*
|
|
16
|
+
* 核心归属/剥前缀/base 命名空间的判断复用 menuAdapter.resolveComponentPath,
|
|
17
|
+
* 本文件只在其上加:白名单、.vue 归一、remote 判定、require 落地、缺文件兜底。
|
|
18
|
+
* 因此无需注册表——归属靠访问路径结构 + 本应用 appCode 比较即可;独立运行 /
|
|
19
|
+
* 主应用态(appCode 为空、无 /micro/ 前缀)会自动退化为与历史一致的本地解析。
|
|
20
|
+
*
|
|
21
|
+
* webpack 硬约束:@base/views 与 @/views 两条动态 require 必须保留字面前缀,
|
|
22
|
+
* 不可把前缀变量化,否则 webpack 无法收集 context。包被消费时 @base 指向包内
|
|
23
|
+
* views、@/ 指向消费应用 views——这正是 base / localPrivate 的语义来源。
|
|
24
|
+
*/
|
|
25
|
+
import {
|
|
26
|
+
getOwnerSegment,
|
|
27
|
+
resolveComponentPath,
|
|
28
|
+
MICRO_SEGMENT,
|
|
29
|
+
MICRO_DEBUG_SEGMENT,
|
|
30
|
+
} from "@base/utils/menuAdapter";
|
|
31
|
+
|
|
32
|
+
const BASE_VIEW_PREFIX = "@base/views";
|
|
33
|
+
const APP_VIEW_PREFIX = "@/views";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 历史遗留的包内共享组件:以普通 /user/... 写法表达(未走 /base 命名空间),
|
|
37
|
+
* 必须落到 @base。微前端下的包内组件应改用 /base/... 或 @base/views 前缀,
|
|
38
|
+
* 由 resolveComponentPath 正确处理;本白名单只兜底存量写法。
|
|
39
|
+
*/
|
|
40
|
+
export const BASE_VIEW_WHITELIST = [
|
|
41
|
+
"/user/bill_setting/h5_view",
|
|
42
|
+
"/user/form/view/list",
|
|
43
|
+
"/user/form/view/edit",
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
function stripVue(p) {
|
|
47
|
+
return p.replace(/\.vue$/i, "");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function ensureVue(p) {
|
|
51
|
+
return /\.vue$/i.test(p) ? p : p + ".vue";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function ensureLeadingSlash(p) {
|
|
55
|
+
if (!p) return p;
|
|
56
|
+
return p.charAt(0) === "/" ? p : "/" + p;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function firstSegment(p) {
|
|
60
|
+
return String(p || "").replace(/^\//, "").split("?")[0].split("/")[0];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isMicroPath(p) {
|
|
64
|
+
const seg = firstSegment(p);
|
|
65
|
+
return seg === MICRO_SEGMENT || seg === MICRO_DEBUG_SEGMENT;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** 剥掉 /micro/<appCode> 或 /micro_debug/<appCode> 两段,得子应用内部路径 */
|
|
69
|
+
function stripMicroPrefix(p) {
|
|
70
|
+
const clean = ensureLeadingSlash(String(p || ""));
|
|
71
|
+
const parts = clean.split("/"); // ["", "micro", "appA", "user", ...]
|
|
72
|
+
return "/" + parts.slice(3).join("/");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 解析组件来源(纯函数,无 require、无副作用,可完整单测)。
|
|
77
|
+
*
|
|
78
|
+
* @param {string} rawUrl 组件来源路径:menu url / option.url / row.url /
|
|
79
|
+
* row.billUrl / row.mobileurl / defaultHomePage 等,
|
|
80
|
+
* 可带或不带 .vue 尾缀。
|
|
81
|
+
* @param {object} options
|
|
82
|
+
* @param {string} [options.route] 访问路径,用于归属判断(双字段写法下
|
|
83
|
+
* url 是组件来源、route 才带 /micro/ 归属段)
|
|
84
|
+
* @param {string} [options.appCode] 本应用(渲染方)appCode;主应用为空字符串
|
|
85
|
+
* @returns {object} 三态描述:
|
|
86
|
+
* { kind: 'empty' }
|
|
87
|
+
* { kind: 'base', base: true, rel: '/user/xxx.vue' }
|
|
88
|
+
* { kind: 'localPrivate', base: false, rel: '/user/xxx.vue' }
|
|
89
|
+
* { kind: 'remote', owner: 'appB', targetPath: '/user/xxx' }
|
|
90
|
+
* { kind: 'unknown', raw: '@other/xxx' } // 罕见的其它 @ 别名,调用方自行决定
|
|
91
|
+
*/
|
|
92
|
+
export function resolveViewPath(rawUrl, options = {}) {
|
|
93
|
+
const raw = String(rawUrl == null ? "" : rawUrl);
|
|
94
|
+
if (!raw) return { kind: "empty" };
|
|
95
|
+
|
|
96
|
+
const route = options.route;
|
|
97
|
+
const appCode = options.appCode || "";
|
|
98
|
+
|
|
99
|
+
// 1. 白名单:存量普通写法的包内共享组件 → @base
|
|
100
|
+
if (BASE_VIEW_WHITELIST.indexOf(stripVue(raw)) >= 0) {
|
|
101
|
+
return { kind: "base", base: true, rel: ensureVue(raw) };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// 2. 委托 menuAdapter:处理 @ 前缀、/micro/ 剥离与归属、/base 命名空间
|
|
105
|
+
const path = resolveComponentPath({ url: raw }, appCode);
|
|
106
|
+
if (!path) return { kind: "empty" };
|
|
107
|
+
|
|
108
|
+
// 3. 单字段 remote:/micro/<别家>/... 时 resolveComponentPath 原样返回
|
|
109
|
+
if (isMicroPath(path)) {
|
|
110
|
+
return {
|
|
111
|
+
kind: "remote",
|
|
112
|
+
owner: getOwnerSegment(path),
|
|
113
|
+
targetPath: stripMicroPrefix(path),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// 4. 双字段 remote 防御:url 无 /micro/ 前缀,但 route 归属别家
|
|
118
|
+
const routeOwner = getOwnerSegment(String(route || ""));
|
|
119
|
+
if (routeOwner && routeOwner !== appCode) {
|
|
120
|
+
return { kind: "remote", owner: routeOwner, targetPath: ensureLeadingSlash(raw) };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// 5. 落位到 @base/views 或 @/views
|
|
124
|
+
if (path.indexOf(BASE_VIEW_PREFIX) === 0) {
|
|
125
|
+
return { kind: "base", base: true, rel: ensureVue(path.slice(BASE_VIEW_PREFIX.length)) };
|
|
126
|
+
}
|
|
127
|
+
if (path.indexOf(APP_VIEW_PREFIX) === 0) {
|
|
128
|
+
return { kind: "localPrivate", base: false, rel: ensureVue(path.slice(APP_VIEW_PREFIX.length)) };
|
|
129
|
+
}
|
|
130
|
+
if (path.charAt(0) === "@") {
|
|
131
|
+
// 其它 @ 别名(罕见):不猜测归属,交回调用方
|
|
132
|
+
return { kind: "unknown", raw: path };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// 原始 /xxx → 渲染方私有 @/views
|
|
136
|
+
return { kind: "localPrivate", base: false, rel: ensureVue(ensureLeadingSlash(path)) };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ——— 以下为 require 落地层(依赖 webpack context,不进纯函数单测) ———
|
|
140
|
+
|
|
141
|
+
function requireBaseView(rel) {
|
|
142
|
+
return require("@base/views" + rel);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function requireAppView(rel) {
|
|
146
|
+
return require("@/views" + rel);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** 惰性读取本应用 appCode,避免把整个 store 拉进 resolveViewPath 的单测 */
|
|
150
|
+
function getRendererAppCode() {
|
|
151
|
+
try {
|
|
152
|
+
const store = require("@base/store").default;
|
|
153
|
+
return (store && store.state && store.state.micro && store.state.micro.appCode) || "";
|
|
154
|
+
} catch (e) {
|
|
155
|
+
return "";
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* 解析并加载详情页组件。resolveViewPath 的运行时外壳。
|
|
161
|
+
*
|
|
162
|
+
* @param {string} rawUrl 同 resolveViewPath
|
|
163
|
+
* @param {object} [options] 同 resolveViewPath;appCode 缺省时从 store 读取
|
|
164
|
+
* @returns {object} resolveViewPath 的结果,附加 component 字段:
|
|
165
|
+
* - base / localPrivate:component 为组件对象(require 失败或缺文件时为 null,附 error)
|
|
166
|
+
* - remote / empty / unknown:component 为 null,由调用方决定后续(装载子应用 / 兜底提示)
|
|
167
|
+
*/
|
|
168
|
+
export function loadViewComponent(rawUrl, options = {}) {
|
|
169
|
+
const opts = Object.assign({}, options);
|
|
170
|
+
if (opts.appCode == null) opts.appCode = getRendererAppCode();
|
|
171
|
+
|
|
172
|
+
const result = resolveViewPath(rawUrl, opts);
|
|
173
|
+
if (result.kind !== "base" && result.kind !== "localPrivate") {
|
|
174
|
+
return Object.assign({ component: null }, result);
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
const mod = result.base ? requireBaseView(result.rel) : requireAppView(result.rel);
|
|
178
|
+
return Object.assign({ component: mod && mod.default }, result);
|
|
179
|
+
} catch (e) {
|
|
180
|
+
return Object.assign({ component: null, error: e }, result);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 兼容旧签名的便捷封装:直接返回组件对象(或 null)。
|
|
186
|
+
* 供 components/wf/wf.js、mobile wfModifyDialogMixin.js 的 requireView 平滑替换——
|
|
187
|
+
* 它们历史上返回 require(...).default。remote / 缺文件时返回 null(不再抛错崩溃)。
|
|
188
|
+
*/
|
|
189
|
+
export function requireViewCompat(rawUrl, options = {}) {
|
|
190
|
+
return loadViewComponent(rawUrl, options).component;
|
|
191
|
+
}
|
|
@@ -219,6 +219,15 @@
|
|
|
219
219
|
:_viewType="1"
|
|
220
220
|
@reload="$reloadHandle"
|
|
221
221
|
></component>
|
|
222
|
+
<micro-view-host
|
|
223
|
+
v-else-if="showWfContent && remoteView"
|
|
224
|
+
:owner="remoteView.owner"
|
|
225
|
+
:target-path="remoteView.targetPath"
|
|
226
|
+
:biz-params="remoteView.bizParams"
|
|
227
|
+
:view-meta="remoteView.viewMeta"
|
|
228
|
+
@reload="$reloadHandle"
|
|
229
|
+
@close="showWfContent = false"
|
|
230
|
+
></micro-view-host>
|
|
222
231
|
</div>
|
|
223
232
|
</el-dialog>
|
|
224
233
|
</div>
|
|
@@ -230,6 +239,7 @@
|
|
|
230
239
|
import ElImageViewer from "@base/components/VabUpload/image-viewer";
|
|
231
240
|
import {treeScollx} from "@base/utils/global";
|
|
232
241
|
import propertiesDialog from './propertiesDialog';
|
|
242
|
+
import { loadViewComponent } from "@base/utils/resolveViewComponent";
|
|
233
243
|
|
|
234
244
|
export default {
|
|
235
245
|
name: 'file_view_ins:list',
|
|
@@ -340,6 +350,7 @@ export default {
|
|
|
340
350
|
showWfDialog: false,
|
|
341
351
|
showWfContent: true,
|
|
342
352
|
wfContent: null,
|
|
353
|
+
remoteView: null,
|
|
343
354
|
wfDataId: '',
|
|
344
355
|
};
|
|
345
356
|
},
|
|
@@ -860,7 +871,17 @@ export default {
|
|
|
860
871
|
this.wfDataId = !id || typeof id == 'object' ? 0 : id;
|
|
861
872
|
this.showWfDialog = true;
|
|
862
873
|
this.showWfContent = true;
|
|
863
|
-
|
|
874
|
+
let res = loadViewComponent(url);
|
|
875
|
+
this.remoteView =
|
|
876
|
+
res.kind === "remote"
|
|
877
|
+
? {
|
|
878
|
+
owner: res.owner,
|
|
879
|
+
targetPath: res.targetPath,
|
|
880
|
+
bizParams: { _dataId: this.wfDataId },
|
|
881
|
+
viewMeta: { visibleKey: "showWfContent", defaultShowWfContent: true, viewType: 1 },
|
|
882
|
+
}
|
|
883
|
+
: null;
|
|
884
|
+
this.wfContent = res.component;
|
|
864
885
|
},
|
|
865
886
|
}
|
|
866
887
|
};
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
<script>
|
|
14
14
|
import corejsConfig from "@/corejsConfig";
|
|
15
15
|
import settingConfig from "@/settings";
|
|
16
|
+
import { loadViewComponent } from "@base/utils/resolveViewComponent";
|
|
16
17
|
|
|
17
18
|
export default {
|
|
18
19
|
name: 'home',
|
|
@@ -79,9 +80,6 @@ export default {
|
|
|
79
80
|
let userInfo = this.userInfo;
|
|
80
81
|
let flag = userInfo.flag;
|
|
81
82
|
|
|
82
|
-
let str1 = "@base/views";
|
|
83
|
-
let str2 = "@/views";
|
|
84
|
-
|
|
85
83
|
if (menuUrl && flag !== 1) {
|
|
86
84
|
//超级管理员不使用角色首页
|
|
87
85
|
url = menuUrl + '.vue';
|
|
@@ -89,13 +87,8 @@ export default {
|
|
|
89
87
|
let defaultHomePage = this.userInfo.defaultHomePage;
|
|
90
88
|
url = defaultHomePage || settingConfig.defaultHomePage || '@base/views/user/home/default.vue'
|
|
91
89
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
} else if (url.startsWith(str2)) {
|
|
95
|
-
this.homeContent = require('@/views' + url.slice(str2.length)).default;
|
|
96
|
-
} else {
|
|
97
|
-
this.homeContent = require('@/views' + url).default;
|
|
98
|
-
}
|
|
90
|
+
// 首页菜单不会归属别的子应用,无需 remote 兜底;归属解析见 @base/utils/resolveViewComponent
|
|
91
|
+
this.homeContent = loadViewComponent(url).component;
|
|
99
92
|
|
|
100
93
|
this.showHomeContent = true;
|
|
101
94
|
this.flag = 1;
|
|
@@ -25,11 +25,21 @@
|
|
|
25
25
|
:parent-target="_self"
|
|
26
26
|
@reload="$reloadHandle"
|
|
27
27
|
></component>
|
|
28
|
+
<micro-view-host
|
|
29
|
+
v-else-if="showWfContent && remoteView"
|
|
30
|
+
:owner="remoteView.owner"
|
|
31
|
+
:target-path="remoteView.targetPath"
|
|
32
|
+
:biz-params="remoteView.bizParams"
|
|
33
|
+
:view-meta="remoteView.viewMeta"
|
|
34
|
+
@reload="$reloadHandle"
|
|
35
|
+
@close="showWfContent = false"
|
|
36
|
+
></micro-view-host>
|
|
28
37
|
</div>
|
|
29
38
|
</el-dialog>
|
|
30
39
|
</template>
|
|
31
40
|
|
|
32
41
|
<script>
|
|
42
|
+
import { loadViewComponent } from "@base/utils/resolveViewComponent";
|
|
33
43
|
export default {
|
|
34
44
|
props: {},
|
|
35
45
|
data() {
|
|
@@ -38,6 +48,7 @@ export default {
|
|
|
38
48
|
wfUrl2: "",
|
|
39
49
|
showWfContent: true,
|
|
40
50
|
wfContent: null,
|
|
51
|
+
remoteView: null,
|
|
41
52
|
wfDataId: "",
|
|
42
53
|
param: {},
|
|
43
54
|
};
|
|
@@ -102,7 +113,17 @@ export default {
|
|
|
102
113
|
this.wfDataId = !id || typeof id == "object" ? 0 : id;
|
|
103
114
|
// this.showWfDialog = true;
|
|
104
115
|
this.showWfContent = true;
|
|
105
|
-
|
|
116
|
+
let res = loadViewComponent(url);
|
|
117
|
+
this.remoteView =
|
|
118
|
+
res.kind === "remote"
|
|
119
|
+
? {
|
|
120
|
+
owner: res.owner,
|
|
121
|
+
targetPath: res.targetPath,
|
|
122
|
+
bizParams: this.param,
|
|
123
|
+
viewMeta: { visibleKey: "showWfContent", _isNotifyMessage: true },
|
|
124
|
+
}
|
|
125
|
+
: null;
|
|
126
|
+
this.wfContent = res.component;
|
|
106
127
|
}
|
|
107
128
|
this.showWfDialog2 = true;
|
|
108
129
|
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
<script>
|
|
11
11
|
import indexUtil from "@base/utils/index.js"
|
|
12
|
+
import { loadViewComponent } from "@base/utils/resolveViewComponent"
|
|
12
13
|
import {
|
|
13
14
|
setReportGlobalParam
|
|
14
15
|
} from "@base/components/xform/utils/util";
|
|
@@ -93,23 +94,13 @@ export default {
|
|
|
93
94
|
let url = purl + '.vue';
|
|
94
95
|
this.queryParam = queryParam;
|
|
95
96
|
this.showWfContent = true;
|
|
96
|
-
// this.wfContent = require('@/views' + url).default;
|
|
97
|
-
let t = "@base/views";
|
|
98
|
-
let urlArr = [
|
|
99
|
-
'/user/bill_setting/h5_view.vue',
|
|
100
|
-
'/user/form/view/list.vue',
|
|
101
|
-
'/user/form/view/edit.vue'
|
|
102
|
-
]
|
|
103
97
|
this.initUserInfo(async () => {
|
|
104
98
|
await this.initI18n();
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
let path = url.slice(t.length);
|
|
109
|
-
this.wfContent = require('@base/views' + path).default;
|
|
110
|
-
} else {
|
|
111
|
-
this.wfContent = require('@/views' + url).default;
|
|
99
|
+
let res = loadViewComponent(url);
|
|
100
|
+
if (res.kind === "remote") {
|
|
101
|
+
this.$message({ message: "该单据归属子应用 " + res.owner + ",请从对应入口打开", type: "warning" });
|
|
112
102
|
}
|
|
103
|
+
this.wfContent = res.component;
|
|
113
104
|
})
|
|
114
105
|
},
|
|
115
106
|
initUserInfo(callback) {
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
<script>
|
|
15
15
|
import { getToken } from "@base/utils/auth";
|
|
16
|
+
import { loadViewComponent } from "@base/utils/resolveViewComponent";
|
|
16
17
|
|
|
17
18
|
export default {
|
|
18
19
|
name: "outLink",
|
|
@@ -27,7 +28,11 @@ export default {
|
|
|
27
28
|
let url = this.$route.query.url;
|
|
28
29
|
let route = this.$route.query.route;
|
|
29
30
|
if (route) {
|
|
30
|
-
|
|
31
|
+
let res = loadViewComponent(route);
|
|
32
|
+
if (res.kind === "remote") {
|
|
33
|
+
this.$message({ message: "该页面归属子应用 " + res.owner + ",请从对应入口打开", type: "warning" });
|
|
34
|
+
}
|
|
35
|
+
this.content = res.component;
|
|
31
36
|
this.type = 2;
|
|
32
37
|
} else {
|
|
33
38
|
let params = this.getCustomReqUrlAndCleanUrl(url);
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
<script>
|
|
11
11
|
import indexUtil from "@base/utils/index.js"
|
|
12
|
+
import { loadViewComponent } from "@base/utils/resolveViewComponent"
|
|
12
13
|
|
|
13
14
|
export default {
|
|
14
15
|
data() {
|
|
@@ -85,22 +86,13 @@ export default {
|
|
|
85
86
|
this.queryParam = queryParam;
|
|
86
87
|
this.showWfContent = true;
|
|
87
88
|
|
|
88
|
-
let t = "@base/views";
|
|
89
|
-
let urlArr = [
|
|
90
|
-
'/user/bill_setting/h5_view.vue',
|
|
91
|
-
'/user/form/view/list.vue',
|
|
92
|
-
'/user/form/view/edit.vue'
|
|
93
|
-
]
|
|
94
89
|
this.initUserInfo(() => {
|
|
95
90
|
this.initI18n();
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
let path = url.slice(t.length);
|
|
100
|
-
this.wfContent = require('@base/views' + path).default;
|
|
101
|
-
} else {
|
|
102
|
-
this.wfContent = require('@/views' + url).default;
|
|
91
|
+
let res = loadViewComponent(url);
|
|
92
|
+
if (res.kind === "remote") {
|
|
93
|
+
this.$message({ message: "该单据归属子应用 " + res.owner + ",请从对应入口打开", type: "warning" });
|
|
103
94
|
}
|
|
95
|
+
this.wfContent = res.component;
|
|
104
96
|
})
|
|
105
97
|
},
|
|
106
98
|
initUserInfo(callback) {
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
</template>
|
|
14
14
|
|
|
15
15
|
<script>
|
|
16
|
+
import { loadViewComponent } from "@base/utils/resolveViewComponent";
|
|
16
17
|
export default {
|
|
17
18
|
data() {
|
|
18
19
|
return {
|
|
@@ -36,7 +37,11 @@ export default {
|
|
|
36
37
|
this.wfDataId = !id || typeof id == 'object' ? 0 : id;
|
|
37
38
|
// this.showWfDialog = true;
|
|
38
39
|
this.showWfContent = true;
|
|
39
|
-
|
|
40
|
+
let res = loadViewComponent(url);
|
|
41
|
+
if (res.kind === "remote") {
|
|
42
|
+
this.$message({ message: "该单据归属子应用 " + res.owner + ",请从对应入口打开", type: "warning" });
|
|
43
|
+
}
|
|
44
|
+
this.wfContent = res.component;
|
|
40
45
|
|
|
41
46
|
}
|
|
42
47
|
}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
</template>
|
|
13
13
|
|
|
14
14
|
<script>
|
|
15
|
+
import { loadViewComponent } from "@base/utils/resolveViewComponent";
|
|
15
16
|
export default {
|
|
16
17
|
data() {
|
|
17
18
|
return {
|
|
@@ -34,7 +35,11 @@ export default {
|
|
|
34
35
|
}
|
|
35
36
|
let url = purl + '.vue';
|
|
36
37
|
this.showWfContent = true;
|
|
37
|
-
|
|
38
|
+
let res = loadViewComponent(url);
|
|
39
|
+
if (res.kind === "remote") {
|
|
40
|
+
this.$message({ message: "该单据归属子应用 " + res.owner + ",请从对应入口打开", type: "warning" });
|
|
41
|
+
}
|
|
42
|
+
this.wfContent = res.component;
|
|
38
43
|
|
|
39
44
|
},
|
|
40
45
|
login() {
|
|
@@ -12,6 +12,15 @@
|
|
|
12
12
|
:_viewType="1"
|
|
13
13
|
@reload="$reloadHandle"
|
|
14
14
|
></component>
|
|
15
|
+
<micro-view-host
|
|
16
|
+
v-else-if="showWfContent && remoteView"
|
|
17
|
+
:owner="remoteView.owner"
|
|
18
|
+
:target-path="remoteView.targetPath"
|
|
19
|
+
:biz-params="remoteView.bizParams"
|
|
20
|
+
:view-meta="remoteView.viewMeta"
|
|
21
|
+
@reload="$reloadHandle"
|
|
22
|
+
@close="showWfContent = false"
|
|
23
|
+
></micro-view-host>
|
|
15
24
|
</el-tab-pane>
|
|
16
25
|
<el-tab-pane :label="$t1('我的流程')" name="second">
|
|
17
26
|
<div class="tree-box fl">
|
|
@@ -415,6 +424,7 @@
|
|
|
415
424
|
import { treeScollx } from "@base/utils/global.js";
|
|
416
425
|
import wfObjConfigDialog from "../../../../views/user/wf/wf_obj_config/dialog.vue";
|
|
417
426
|
import userDialog from "@base/views/user/user/dialog";
|
|
427
|
+
import { loadViewComponent } from "@base/utils/resolveViewComponent";
|
|
418
428
|
|
|
419
429
|
export default {
|
|
420
430
|
name: "wf_manage:list",
|
|
@@ -448,6 +458,7 @@ export default {
|
|
|
448
458
|
|
|
449
459
|
param: {},
|
|
450
460
|
wfContent: null,
|
|
461
|
+
remoteView: null,
|
|
451
462
|
showWfContent: false,
|
|
452
463
|
|
|
453
464
|
showCurrentTaskUserDialog: false,
|
|
@@ -657,7 +668,17 @@ export default {
|
|
|
657
668
|
_dataId: wfDataId,
|
|
658
669
|
};
|
|
659
670
|
let url = row.url + ".vue";
|
|
660
|
-
|
|
671
|
+
let res = loadViewComponent(url);
|
|
672
|
+
this.remoteView =
|
|
673
|
+
res.kind === "remote"
|
|
674
|
+
? {
|
|
675
|
+
owner: res.owner,
|
|
676
|
+
targetPath: res.targetPath,
|
|
677
|
+
bizParams: this.param,
|
|
678
|
+
viewMeta: { visibleKey: "showWfContent", defaultShowWfContent: true, viewType: 1 },
|
|
679
|
+
}
|
|
680
|
+
: null;
|
|
681
|
+
this.wfContent = res.component;
|
|
661
682
|
}
|
|
662
683
|
this.activeName = "first";
|
|
663
684
|
this.$openEditView("showWfContent");
|
|
@@ -12,6 +12,15 @@
|
|
|
12
12
|
:_viewType="1"
|
|
13
13
|
@reload="$reloadHandle"
|
|
14
14
|
></component>
|
|
15
|
+
<micro-view-host
|
|
16
|
+
v-else-if="showWfContent && remoteView"
|
|
17
|
+
:owner="remoteView.owner"
|
|
18
|
+
:target-path="remoteView.targetPath"
|
|
19
|
+
:biz-params="remoteView.bizParams"
|
|
20
|
+
:view-meta="remoteView.viewMeta"
|
|
21
|
+
@reload="$reloadHandle"
|
|
22
|
+
@close="showWfContent = false"
|
|
23
|
+
></micro-view-host>
|
|
15
24
|
</el-tab-pane>
|
|
16
25
|
<el-tab-pane :label="$t1('我的流程2')" name="second">
|
|
17
26
|
<div class="tree-box fl">
|
|
@@ -314,6 +323,7 @@
|
|
|
314
323
|
<script>
|
|
315
324
|
import { treeScollx } from "@base/utils/global.js";
|
|
316
325
|
import wfObjConfigDialog from "../wf_obj_config/dialog.vue";
|
|
326
|
+
import { loadViewComponent } from "@base/utils/resolveViewComponent";
|
|
317
327
|
|
|
318
328
|
export default {
|
|
319
329
|
name: "wf_manage:list2",
|
|
@@ -347,6 +357,7 @@ export default {
|
|
|
347
357
|
|
|
348
358
|
param: {},
|
|
349
359
|
wfContent: null,
|
|
360
|
+
remoteView: null,
|
|
350
361
|
showWfContent: false,
|
|
351
362
|
};
|
|
352
363
|
},
|
|
@@ -543,7 +554,17 @@ export default {
|
|
|
543
554
|
_dataId: wfDataId,
|
|
544
555
|
};
|
|
545
556
|
let url = row.url + ".vue";
|
|
546
|
-
|
|
557
|
+
let res = loadViewComponent(url);
|
|
558
|
+
this.remoteView =
|
|
559
|
+
res.kind === "remote"
|
|
560
|
+
? {
|
|
561
|
+
owner: res.owner,
|
|
562
|
+
targetPath: res.targetPath,
|
|
563
|
+
bizParams: this.param,
|
|
564
|
+
viewMeta: { visibleKey: "showWfContent", defaultShowWfContent: true, viewType: 1 },
|
|
565
|
+
}
|
|
566
|
+
: null;
|
|
567
|
+
this.wfContent = res.component;
|
|
547
568
|
}
|
|
548
569
|
this.activeName = "first";
|
|
549
570
|
this.$openEditView("showWfContent");
|
|
@@ -26,11 +26,22 @@
|
|
|
26
26
|
@reload="$reloadHandle"
|
|
27
27
|
:_handleCallback="handleCallback"
|
|
28
28
|
></component>
|
|
29
|
+
<micro-view-host
|
|
30
|
+
v-else-if="showWfContent && remoteView"
|
|
31
|
+
:owner="remoteView.owner"
|
|
32
|
+
:target-path="remoteView.targetPath"
|
|
33
|
+
:biz-params="remoteView.bizParams"
|
|
34
|
+
:view-meta="remoteView.viewMeta"
|
|
35
|
+
@reload="$reloadHandle"
|
|
36
|
+
@handle-callback="handleCallback"
|
|
37
|
+
@close="showWfContent = false"
|
|
38
|
+
></micro-view-host>
|
|
29
39
|
</div>
|
|
30
40
|
</el-dialog>
|
|
31
41
|
</template>
|
|
32
42
|
|
|
33
43
|
<script>
|
|
44
|
+
import { loadViewComponent } from "@base/utils/resolveViewComponent";
|
|
34
45
|
export default {
|
|
35
46
|
name: "wfContentDialog",
|
|
36
47
|
props: {
|
|
@@ -44,6 +55,7 @@ export default {
|
|
|
44
55
|
return {
|
|
45
56
|
param: {},
|
|
46
57
|
wfContent: null,
|
|
58
|
+
remoteView: null,
|
|
47
59
|
showWfContent: false,
|
|
48
60
|
showWfDialog: true,
|
|
49
61
|
};
|
|
@@ -98,7 +110,17 @@ export default {
|
|
|
98
110
|
_dataId: wfDataId,
|
|
99
111
|
});
|
|
100
112
|
let url = this.option.url + ".vue";
|
|
101
|
-
|
|
113
|
+
let res = loadViewComponent(url);
|
|
114
|
+
this.remoteView =
|
|
115
|
+
res.kind === "remote"
|
|
116
|
+
? {
|
|
117
|
+
owner: res.owner,
|
|
118
|
+
targetPath: res.targetPath,
|
|
119
|
+
bizParams: this.param,
|
|
120
|
+
viewMeta: { visibleKey: "showWfContent", defaultShowWfContent: true, viewType: 1 },
|
|
121
|
+
}
|
|
122
|
+
: null;
|
|
123
|
+
this.wfContent = res.component;
|
|
102
124
|
}
|
|
103
125
|
this.showWfContent = true;
|
|
104
126
|
},
|