cloud-web-corejs 1.1.0-dev.53 → 1.1.0-dev.55

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.1.0-dev.53",
4
+ "version": "1.1.0-dev.55",
5
5
  "scripts": {
6
6
  "build:ace-resources": "node build/build-ace-resources.js",
7
7
  "build:tinymce-resources": "node build/build-tinymce-resources.js",
@@ -212,9 +212,11 @@
212
212
  "src/permission.js",
213
213
  "src/index.js",
214
214
  "src/index.next.js",
215
+ "src/index.sync.js",
215
216
  "src/boot-assets.legacy.js",
216
217
  "src/boot-assets.next.js",
217
218
  "src/app-bootstrap.js",
219
+ "src/app-bootstrap.sync.js",
218
220
  "src/public-path.js",
219
221
  "src/microRouter",
220
222
  "src/App.vue"
@@ -0,0 +1,502 @@
1
+ // 同步启动:与 app-bootstrap.js 相同,但 excelImport / VabUpload / jsonImport / langImport 不走 lazyPrototypePlugin。
2
+ // 由 index.sync.js 接入。
3
+ import Vue from "vue";
4
+ import Cookies from "js-cookie";
5
+ import Element from "element-ui";
6
+ import App from "@base/App";
7
+ import store from "@base/store";
8
+ import router, { resetRouter } from "@base/router";
9
+ import settings from "@/settings";
10
+ import { setToken as setAuthToken } from "@base/utils/auth";
11
+ import { loadViewComponentAsync } from "@base/utils/resolveViewComponent";
12
+ import { installRuntimeRecovery } from "@base/utils/runtimeRecovery";
13
+
14
+ import "@base/permission"; // permission control
15
+
16
+ import * as filters from "@base/filters"; // global filters
17
+
18
+ // main.js 文件添加以下代码
19
+
20
+ import BaseKeepAlive from "@base/utils/keepAlive.js";
21
+
22
+ Vue.component("BaseKeepAlive", BaseKeepAlive);
23
+
24
+ import VXETable from "vxe-table";
25
+ import "vxe-table/lib/style.css";
26
+ import "@base/components/table/style.scss";
27
+ import "@base/components/fileLibrary/style.scss";
28
+ import "@base/components/VabUpload/style.scss";
29
+ import "@base/components/xform/styles/table-layout.scss";
30
+ import "@base/components/xform/styles/designer.scss";
31
+ import "@base/components/xform/styles/census.scss";
32
+ import "@base/components/xform/styles/titles.scss";
33
+ import "@base/components/xform/styles/containers.scss";
34
+ import "@base/components/xform/styles/skins.scss";
35
+ import "@base/components/xform/styles/detail-temp.scss";
36
+ import "@base/components/xform/styles/h5-designer.scss";
37
+ import "@base/components/xform/styles/h5-runtime.scss";
38
+ import "@base/components/hiprint/style.scss";
39
+ import "@base/components/wf/style.scss";
40
+
41
+ // 区域选取/复制粘贴:自研实现,通过 window.VXETableMixin 挂载,
42
+ // 必须在下面的 Vue.use(VXETable) 之前求值(core 在 install 时读取一次并 delete)
43
+ import "@base/components/table/plugins/cell-area/index.js";
44
+ import "@base/components/table/plugins/cell-area/index.scss";
45
+
46
+ // 引入扩展插件(官方付费插件,已由上面的自研 cell-area 替代,保留仅作回退参考)
47
+ // import "@base/components/table/plugins/extend-cell-area/vxe-table-extend-cell-area.es6.min.js";
48
+ // import "@base/components/table/plugins/extend-cell-area/vxe-table-extend-cell-area.min.css";
49
+
50
+ /* // 设置授权信息
51
+ VXETable.setup({
52
+ // showAuthLog: true, // 是否在控制台显示授权信息,专业版支持关闭
53
+ // authId: 'gbeumewkoyt2rhf9', // 获取授权后在官网登录后进入“用户中心”查看
54
+ authId: 'gbeumewkoyt2rhft', // 获取授权后在官网登录后进入“用户中心”查看
55
+ // onAuth (e) {
56
+ // // 打印授权状态
57
+ // console.log(e)
58
+ // }
59
+ }) */
60
+
61
+ import Vab from "@base/utils/vab";
62
+ import createCodeEditorAsyncComponent from "@base/components/code-editor/async";
63
+
64
+ Vue.use(Vab);
65
+
66
+ // appCode 兜底派生:子应用(拥有自己的子命名空间,即 WEB_PREFIX !== MAIN_WEB_PREFIX)
67
+ // 若未在自身 settings.js 里维护 appCode,则从 WEB_PREFIX 去前导斜杠派生(/mkweb → mkweb),
68
+ // 免得每个子应用再手填一处、也不会写错。主应用/独立主站两前缀相同 → 保持空。
69
+ // 优先级:mount 里的 props.appCode > settings 显式值 > 此派生。window.WEB_PREFIX /
70
+ // MAIN_WEB_PREFIX 已由上面 vab 的 Object.assign(window, prefixConfig) 设好。
71
+ if (!settings.appCode) {
72
+ const webPrefix = window.WEB_PREFIX || "";
73
+ const mainWebPrefix = window.MAIN_WEB_PREFIX || "";
74
+ if (webPrefix && webPrefix !== mainWebPrefix) {
75
+ settings.appCode = webPrefix.replace(/^\/+/, "");
76
+ }
77
+ }
78
+
79
+ Vue.use(VXETable);
80
+
81
+ /* import tablePluns from "@/mixins/table/index.js"
82
+ VXETable.use(tablePluns) */
83
+
84
+ import "@base/components/table/index.js";
85
+
86
+ import drag from "@base/directive/el-drag-dialog/index.js";
87
+
88
+ Vue.use(drag.install);
89
+
90
+ import elDialogCenter from "@base/directive/el-dialog-center/index.js";
91
+
92
+ Vue.use(elDialogCenter.install);
93
+
94
+ import ErroreBox from "@base/components/errorMsg/index.js";
95
+
96
+ Vue.use(ErroreBox);
97
+
98
+ import ExcelExport from "@base/components/excelExport/index.js";
99
+
100
+ Vue.use(ExcelExport);
101
+
102
+ // 同步入口:不走 lazyPrototypePlugin,启动时直接注册
103
+ import ExcelImport from "@base/components/excelImport/index.js";
104
+
105
+ Vue.use(ExcelImport);
106
+
107
+ import ConfirmDialog from "@base/components/confirmDialog/index.js";
108
+
109
+ Vue.use(ConfirmDialog);
110
+
111
+ import baseAlert from "@base/components/baseAlert/index.js";
112
+
113
+ Vue.use(baseAlert);
114
+
115
+ import FormDialog from "@base/components/formDialog/index.js";
116
+
117
+ Vue.use(FormDialog);
118
+
119
+ import FormDrawer from "@base/components/formDrawer/index.js";
120
+
121
+ Vue.use(FormDrawer);
122
+
123
+ import permission from "@base/directive/permission";
124
+
125
+ Vue.use(permission);
126
+
127
+ import VabUpload from "@base/components/VabUpload/index.js";
128
+
129
+ Vue.use(VabUpload);
130
+
131
+ Vue.component("baseUpload", () =>
132
+ import("@base/components/VabUpload/view.vue")
133
+ );
134
+
135
+ import baseAttachment from "@base/components/baseAttachment/install";
136
+
137
+ Vue.use(baseAttachment);
138
+ Vue.component("attachmentShowList", () =>
139
+ import("@base/components/baseAttachment/showList")
140
+ );
141
+
142
+ import "@base/core-resources/js/base/common.js";
143
+
144
+ import vxeFilter from "@base/components/table/vxeFilter/index.js";
145
+
146
+ Vue.use(vxeFilter);
147
+
148
+ // 首屏优化:低频/非首屏组件转懒注册(名字与组件内 name 一致,写死字符串)
149
+ Vue.component("base-table-export", () =>
150
+ import("@base/components/excelExport/button.vue")
151
+ );
152
+
153
+ /* Vue.component('extendedProperties', () => import('@base/components/extendedProperties/view.vue')); */
154
+
155
+ import LimitNumber from "@base/directive/LimitNumber/index.js";
156
+
157
+ Vue.use(LimitNumber);
158
+
159
+ import baseInputNumber from "@base/components/baseInputNumber/index.vue";
160
+
161
+ Vue.component(baseInputNumber.name, baseInputNumber);
162
+
163
+ import elReadonly from "@base/directive/el-readonly/index.js";
164
+
165
+ Vue.use(elReadonly);
166
+
167
+ import appendToBody from "@base/directive/append-to-body/index.js";
168
+
169
+ Vue.use(appendToBody.install);
170
+
171
+ /*import cnPrint from "@base/components/cnPrint/index.js"
172
+
173
+ Vue.use(cnPrint);*/
174
+
175
+ Vue.component("oplogTable", () =>
176
+ import("@base/components/oplogTable/index.vue")
177
+ );
178
+
179
+ Vue.component("baseInputBatch", () =>
180
+ import("@base/components/baseInputBatch/index.vue")
181
+ );
182
+
183
+ Vue.component("baseArea", () => import("@base/components/baseArea/index.vue"));
184
+
185
+ Vue.component("baseInputExport", () =>
186
+ import("@base/components/baseInputExport/index.vue")
187
+ );
188
+
189
+ Vue.component("advancedSearchDialog", () =>
190
+ import("@base/components/advancedSearchDialog/index.vue")
191
+ );
192
+
193
+ // baseTabs/baseTabPane 必须同步注册,不可懒注册:
194
+ // xform 详情容器(detail-item)把所有 detail-pane 及其内部字段组件放在 <baseTabs> 的默认插槽里。
195
+ // 异步组件未解析时 Vue 只渲染占位注释节点,插槽内的组件不会被实例化,
196
+ // 于是 detail-item 的 mounted 早于内部字段组件的 created(registerToRefList)执行,
197
+ // 模板脚本 onMounted 里的 getWidgetRef('xxx') 首次进入必然拿到 undefined(二次进入因异步工厂已缓存而正常)。
198
+ import baseTabs from "@base/components/baseTabs/index.vue";
199
+ import baseTabPane from "@base/components/baseTabs/baseTabPane.vue";
200
+
201
+ Vue.component(baseTabs.name, baseTabs);
202
+ Vue.component(baseTabPane.name, baseTabPane);
203
+
204
+ import vb_tabs from "@base/components/vb-tabs/index.vue";
205
+ import vb_tab_pane from "@base/components/vb-tabs/tab-pane.vue";
206
+ import xTabs from "@base/components/vb-tabs/x-tabs.vue";
207
+
208
+ Vue.component(vb_tabs.name, vb_tabs);
209
+ Vue.component(vb_tab_pane.name, vb_tab_pane);
210
+ Vue.component(xTabs.name, xTabs);
211
+
212
+ Vue.component("status-tag", () =>
213
+ import("@base/components/statusTag/index.vue")
214
+ );
215
+
216
+ Vue.component("CodeEditor", createCodeEditorAsyncComponent);
217
+
218
+ Vue.component("scriptDescriptionButton", () =>
219
+ import("@base/components/scriptDescription/button")
220
+ );
221
+
222
+ Vue.component("scriptTestButton", () =>
223
+ import("@base/components/scriptTest/button")
224
+ );
225
+
226
+ Vue.component("BaseTextarea", () =>
227
+ import("@base/components/base-textarea/index.vue")
228
+ );
229
+
230
+ import JsonImport from "@base/components/jsonImport/index.js";
231
+
232
+ Vue.use(JsonImport);
233
+
234
+ import LangImport from "@base/components/langImport/index.js";
235
+
236
+ Vue.use(LangImport);
237
+
238
+ //vform
239
+ // import '@base/components/xform/utils/directive'
240
+
241
+ import i18n from "@base/lang/index.js";
242
+
243
+ /**
244
+ * If you don't want to use mock-server
245
+ * you want to use MockJs for mock api
246
+ * you can execute: mockXHR()
247
+ *
248
+ * Currently MockJs will be used in the production environment,
249
+ * please remove it before going online ! ! !
250
+ */
251
+ if (process.env.NODE_ENV === "production") {
252
+ /* const { mockXHR } = require('../mock')
253
+ mockXHR() */
254
+ }
255
+
256
+ Vue.use(Element, {
257
+ size: Cookies.get("size") || "medium", // set element-ui default size
258
+ // locale: enLang // 如果使用中文,无需设置,请删除
259
+ });
260
+ installRuntimeRecovery();
261
+
262
+ // register global utility filters
263
+ Object.keys(filters).forEach((key) => {
264
+ Vue.filter(key, filters[key]);
265
+ });
266
+
267
+ // 详情承载宿主:弹框 remote 分支用它 loadMicroApp 装载归属子应用渲染私有详情页
268
+ Vue.component("micro-view-host", () =>
269
+ import("@base/components/micro-view-host/index.vue")
270
+ );
271
+
272
+ Vue.config.productionTip = false;
273
+
274
+ let instance = null;
275
+
276
+ function render(props = {}) {
277
+ const { container } = props;
278
+ instance = new Vue({
279
+ router,
280
+ store,
281
+ i18n,
282
+ render: (h) => h(App),
283
+ });
284
+ // Synchronous child renders may call global helpers such as $t2.
285
+ // Publish the initialized root before mounting any child component.
286
+ window.$vueRoot = instance;
287
+ instance.$mount(container ? container.querySelector("#app") : "#app");
288
+ }
289
+
290
+ /**
291
+ * 详情承载入口(qiankun 详情承载协议 §5.5)。
292
+ * 主应用/渲染方的 micro-view-host 用 loadMicroApp 装载本应用并置 props.microDetailHost=true,
293
+ * 要求只渲染 targetPath 指向的详情页、把详情页的刷新/关闭/回调桥接回主应用,不出整站壳。
294
+ * 契约字段见 docs/qiankun详情承载子应用对接清单.md。
295
+ *
296
+ * ⚠ parentVue shim 的委托语义需真机联调打磨:详情页 getTarget(this) 命中 shim 后会用到
297
+ * $http/$message/$baseConfirm/$attrs 等——这些经原型委托到宿主根实例(全局插件已装齐),
298
+ * 仅 $baseReload / _handleCallback 覆盖为回主应用的动作。个别详情页若有更深的 $parent 依赖,
299
+ * 按对接清单 §5.6 做最小改造。
300
+ */
301
+ async function mountDetailHost(props = {}) {
302
+ if (props.appCode) settings.appCode = props.appCode;
303
+ if (props.token) {
304
+ setAuthToken(props.token);
305
+ store.commit("user/SET_TOKEN", props.token);
306
+ }
307
+ if (props.lang) i18n.locale = props.lang;
308
+
309
+ const appCode = props.appCode || settings.appCode;
310
+ const resolved = await loadViewComponentAsync(props.targetPath, { appCode });
311
+ const target = resolved.component;
312
+ const bizParams = props.bizParams || {};
313
+ const viewMeta = props.viewMeta || {};
314
+
315
+ // shim 需先于 render 存在(作为 parentVue prop 传入),其 Vue 能力在挂载后经原型委托到根实例
316
+ const shim = {
317
+ $baseReload: () => props.onReload && props.onReload(),
318
+ _handleCallback: (flag) => props.onHandleCallback && props.onHandleCallback(flag),
319
+ };
320
+
321
+ const { container } = props;
322
+ const mountEl = container ? container.querySelector("#app") : "#app";
323
+ instance = new Vue({
324
+ store,
325
+ i18n,
326
+ render(h) {
327
+ if (!target) {
328
+ return h(
329
+ "div",
330
+ { staticClass: "micro-detail-host-missing" },
331
+ "详情页组件未找到:" + (props.targetPath || "")
332
+ );
333
+ }
334
+ return h(target, {
335
+ props: Object.assign({}, bizParams, viewMeta, {
336
+ parentVue: shim,
337
+ _handleCallback: (flag) =>
338
+ props.onHandleCallback && props.onHandleCallback(flag),
339
+ outParam: props.initialOutParam,
340
+ }),
341
+ on: {
342
+ reload: () => props.onReload && props.onReload(),
343
+ close: () => props.onClose && props.onClose(),
344
+ "update:outParam": (v) =>
345
+ props.onUpdateOutParam && props.onUpdateOutParam(v),
346
+ },
347
+ });
348
+ },
349
+ });
350
+ window.$vueRoot = instance;
351
+ instance.$mount(mountEl);
352
+ // #4 listeners 透传:详情页里父级 v-on="listeners" 那批是详情页直接 this.$emit 的,
353
+ // 拦截根子组件的 $emit,任意事件都转发给主应用的 onEmit(按名字派回原 option.on)。
354
+ const child = instance.$children && instance.$children[0];
355
+ if (child && typeof child.$emit === "function") {
356
+ const rawEmit = child.$emit.bind(child);
357
+ child.$emit = (name, ...args) => {
358
+ if (typeof props.onEmit === "function") props.onEmit(name, ...args);
359
+ return rawEmit(name, ...args);
360
+ };
361
+ }
362
+ // 挂载后把 shim 的原型指向根实例:$http/$message/$baseConfirm 等委托过去,
363
+ // 而 shim 自有的 $baseReload/_handleCallback 覆盖生效(详情页动作时才会调用)
364
+ Object.setPrototypeOf(shim, instance);
365
+ window.$vueRoot = instance;
366
+ }
367
+
368
+ if (!window.__POWERED_BY_QIANKUN__) {
369
+ // 独立运行 / 主应用形态:行为与拆分前一致
370
+ render();
371
+ }
372
+
373
+ /**
374
+ * qiankun 子应用生命周期。
375
+ * 引包子应用入口 re-export 即可:export * from "cloud-web-corejs/src/index";
376
+ * 主子通信协议见 docs/qiankun微前端改造-实现方案.md 3.3。
377
+ */
378
+ export async function bootstrap() {}
379
+
380
+ export async function mount(props = {}) {
381
+ if (props.microDetailHost) {
382
+ // 详情承载模式(micro-view-host 装载):不走整站壳/路由/菜单,
383
+ // 只在容器里渲染 props.targetPath 指向的本应用组件。见对接清单文档。
384
+ return mountDetailHost(props);
385
+ }
386
+ if (props.appCode) {
387
+ // 主应用可经 props 覆盖,子应用也可在自身 settings.js 里声明
388
+ settings.appCode = props.appCode;
389
+ }
390
+ if (props.token) {
391
+ // token 存 sessionStorage,按 origin 隔离——跨域/跨端口主应用的登录态子应用天然拿不到,
392
+ // 主应用显式下发 token 即可免登(写入自身登录态后守卫按已登录走 getInfo2)
393
+ setAuthToken(props.token);
394
+ store.commit("user/SET_TOKEN", props.token);
395
+ }
396
+ store.commit("micro/SET_MICRO_CONTEXT", {
397
+ appCode: props.appCode || settings.appCode,
398
+ // 非数组(null/未传)= 自治嵌入模式:子应用自拉菜单、保留自身壳(micro store 据此置 selfManaged)
399
+ menus: Array.isArray(props.menus) ? props.menus : null,
400
+ mainAdapter: props.mainAdapter || null,
401
+ // 主应用经本地调试覆盖装载:允许 URL 直达未配菜单的页面
402
+ debug: !!props.microDebug,
403
+ });
404
+ // 再次挂载时 unmount 已重置路由,而 roles 仍在会使守卫跳过路由生成,这里主动补一次
405
+ if (store.getters.roles && store.getters.roles.length > 0) {
406
+ if (store.state.micro.selfManaged) {
407
+ await store.dispatch("permission/generateRoutes2", {
408
+ flag: store.state.user.userFlag,
409
+ });
410
+ } else {
411
+ await store.dispatch(
412
+ "permission/generateRoutesFromProps",
413
+ props.menus || []
414
+ );
415
+ }
416
+ }
417
+ render(props);
418
+ }
419
+
420
+ /**
421
+ * 保活协议(主应用 loadMicroApp 模式):
422
+ * update({ microActive: false }) —— 容器被隐藏:暂停路由监听(守卫 next(false) +
423
+ * ensureURL 置空,防止对主应用的 URL 变化做出反应、回写 URL 互相打架);
424
+ * update({ microActive: true }) —— 容器重新显示:恢复监听并把当前 hash 同步进路由
425
+ * (含主应用在隐藏期间切到本应用另一菜单的深导航场景)。
426
+ */
427
+ let pausedEnsureURL = null;
428
+
429
+ function pauseSubRouter() {
430
+ if (store.state.micro.routerPaused) return;
431
+ store.commit("micro/SET_ROUTER_PAUSED", true);
432
+ const history = router.history;
433
+ if (history && typeof history.ensureURL === "function") {
434
+ pausedEnsureURL = history.ensureURL;
435
+ history.ensureURL = function () {};
436
+ }
437
+ }
438
+
439
+ function resumeSubRouter() {
440
+ if (store.state.micro.routerPaused) {
441
+ store.commit("micro/SET_ROUTER_PAUSED", false);
442
+ if (pausedEnsureURL) {
443
+ router.history.ensureURL = pausedEnsureURL;
444
+ pausedEnsureURL = null;
445
+ }
446
+ }
447
+ syncSubRouter();
448
+ }
449
+
450
+ function syncSubRouter() {
451
+ const current = window.location.hash.replace(/^#/, "") || "/";
452
+ if (router.currentRoute.fullPath !== current) {
453
+ // vue-router 3.0.2 的 push 不返回 Promise(3.1.0 才加),直接 .catch 会读到
454
+ // undefined 抛错,且此调用发生在 qiankun update 生命周期内——异常会让 parcel 直接
455
+ // died、后续所有 update(含页签刷新转发)失效。仅当 push 返回 Promise 时才吞异常。
456
+ const nav = router.push(current);
457
+ if (nav && typeof nav.catch === "function") {
458
+ nav.catch(() => {});
459
+ }
460
+ }
461
+ }
462
+
463
+ /**
464
+ * 主应用页签"刷新"转发过来时在子应用内部重建当前页组件。
465
+ * 不能套用主应用那招(delCachedView + 跳 /redirect):子应用与主应用共用同一个
466
+ * 浏览器 hash,跳 /redirect 会被主应用 afterEach 判成"离开子应用路由",
467
+ * 容器随即隐藏并暂停子应用路由,重建被掐断——表现就是点刷新没反应。
468
+ * 改为自增序号通知 AppMain 原地销毁重建,全程不碰 URL。
469
+ */
470
+ function refreshCurrentView() {
471
+ store.commit("micro/BUMP_RELOAD_SEQ");
472
+ }
473
+
474
+ export async function update(props = {}) {
475
+ if (props.microActive === false) {
476
+ pauseSubRouter();
477
+ } else if (props.microActive === true) {
478
+ resumeSubRouter();
479
+ }
480
+ if (props.microRefresh) {
481
+ refreshCurrentView();
482
+ }
483
+ }
484
+
485
+ export async function unmount() {
486
+ if (store.state.micro.routerPaused && pausedEnsureURL) {
487
+ router.history.ensureURL = pausedEnsureURL;
488
+ pausedEnsureURL = null;
489
+ }
490
+ if (instance) {
491
+ instance.$destroy();
492
+ if (instance.$el) {
493
+ instance.$el.innerHTML = "";
494
+ }
495
+ instance = null;
496
+ }
497
+ if (window.$vueRoot) {
498
+ window.$vueRoot = null;
499
+ }
500
+ store.commit("micro/CLEAR_MICRO_CONTEXT");
501
+ resetRouter();
502
+ }
@@ -57,6 +57,7 @@ let chartContainers = [],
57
57
  },
58
58
  scriptList: [],
59
59
  formType: 0,
60
+ dialogScope: null,
60
61
  getConfig: {
61
62
  accessType: "1",
62
63
  accessUrl: null,
@@ -1,8 +1,14 @@
1
1
  <template>
2
2
  <el-dialog
3
+ ref="pageDialog"
3
4
  :visible.sync="showDialog"
4
5
  v-el-drag-dialog
5
- v-el-dialog-center
6
+ v-el-dialog-center="!isPageScope"
7
+ :class="{
8
+ 'xform-page-dialog-wrapper': isPageScope,
9
+ 'xform-page-form-dialog-wrapper': isPageScope,
10
+ 'xform-page-dialog-wrapper--top': pageDialogHasTop,
11
+ }"
6
12
  v-bind="dialogConfig"
7
13
  @close="close"
8
14
  >
@@ -13,7 +19,11 @@
13
19
  v-bind="bodyConfig"
14
20
  v-if="listHost"
15
21
  >
16
- <list-view-host :formCode="listFormCode" :param="dialogParam" />
22
+ <list-view-host
23
+ :formCode="listFormCode"
24
+ :param="dialogParam"
25
+ :dialogScope="option.dialogScope"
26
+ />
17
27
  </div>
18
28
  <div class="cont designer-view" v-bind="bodyConfig" id="containt" v-else>
19
29
  <v-form-render
@@ -30,6 +40,7 @@
30
40
  @reload="reload"
31
41
  v-bind="formConfig"
32
42
  :param="dialogParam"
43
+ :dialogScope="option.dialogScope"
33
44
  :dataTableOption="dialogDataTableOption"
34
45
  class="data-table_height"
35
46
  @hook:mounted="handleFormMounted"
@@ -75,6 +86,10 @@
75
86
 
76
87
  <script>
77
88
  import VFormRender from "../../../../../components/xform/form-render/index.vue";
89
+ import {
90
+ pageScopedDialogMixin,
91
+ pageDialogTop,
92
+ } from "@base/components/xform/form-render/pageDialogScope";
78
93
  import {
79
94
  resolveActionButtons,
80
95
  hasButtonPermission,
@@ -95,7 +110,7 @@ export default {
95
110
  visiable: Boolean,
96
111
  option: Object,
97
112
  },
98
- mixins: [],
113
+ mixins: [pageScopedDialogMixin],
99
114
  inject: ["getFormConfig"],
100
115
 
101
116
  mounted() {},
@@ -171,6 +186,15 @@ export default {
171
186
  config = Object.assign({}, config, this.option.dialogConfig, {
172
187
  customClass,
173
188
  });
189
+ if (this.isPageScope) {
190
+ Object.assign(config, {
191
+ appendToBody: false,
192
+ modalAppendToBody: false,
193
+ modal: false,
194
+ lockScroll: false,
195
+ top: pageDialogTop(this.option.dialogConfig?.top),
196
+ });
197
+ }
174
198
  config.title = this.$t1(config.title);
175
199
  return config;
176
200
  },
@@ -236,7 +260,9 @@ export default {
236
260
  method: `post`,
237
261
  data: data,
238
262
  isLoading: true,
239
- loadingTarget: document.body,
263
+ loadingTarget: this.isPageScope
264
+ ? this.option.pageDialogHost
265
+ : document.body,
240
266
  modalStrictly: true,
241
267
  success: (res) => {
242
268
  let formTemplate = res.objx || {};
@@ -1,8 +1,13 @@
1
1
  <template>
2
2
  <el-dialog
3
+ ref="pageDialog"
3
4
  :visible.sync="showDialog"
4
5
  v-el-drag-dialog
5
- v-el-dialog-center
6
+ v-el-dialog-center="!isPageScope"
7
+ :class="{
8
+ 'xform-page-dialog-wrapper': isPageScope,
9
+ 'xform-page-dialog-wrapper--top': pageDialogHasTop,
10
+ }"
6
11
  v-bind="dialogConfig"
7
12
  @close="close"
8
13
  >
@@ -22,6 +27,7 @@
22
27
  :dataTableOption="dataTableOption"
23
28
  v-bind="formConfig"
24
29
  :param="dialogParam"
30
+ :dialogScope="option.dialogScope"
25
31
  class="data-table_height labMargin"
26
32
  />
27
33
  </div>
@@ -72,12 +78,16 @@
72
78
  <script>
73
79
  import { selectDialogMixins } from "../../../../../mixins/selectDialog/index.js";
74
80
  import VFormRender from "../../../../../components/xform/form-render/index.vue";
81
+ import {
82
+ pageScopedDialogMixin,
83
+ pageDialogTop,
84
+ } from "@base/components/xform/form-render/pageDialogScope";
75
85
  import { traverseAllWidgetsNew } from "../../../../../components/xform/utils/util";
76
86
 
77
87
  export default {
78
88
  components: { VFormRender },
79
89
  props: ["visiable", "multi", "rows", "param", "widget", "option"],
80
- mixins: [selectDialogMixins],
90
+ mixins: [selectDialogMixins, pageScopedDialogMixin],
81
91
  inject: ["getFormConfig"],
82
92
  mounted() {},
83
93
  data() {
@@ -172,6 +182,15 @@ export default {
172
182
  config = Object.assign({}, config, this.option.dialogConfig, {
173
183
  customClass,
174
184
  });
185
+ if (this.isPageScope) {
186
+ Object.assign(config, {
187
+ appendToBody: false,
188
+ modalAppendToBody: false,
189
+ modal: false,
190
+ lockScroll: false,
191
+ top: pageDialogTop(this.option.dialogConfig?.top),
192
+ });
193
+ }
175
194
  config.title = this.$t1(config.title);
176
195
  return config;
177
196
  },
@@ -228,7 +247,9 @@ export default {
228
247
  method: `post`,
229
248
  data: data,
230
249
  isLoading: true,
231
- loadingTarget: document.body,
250
+ loadingTarget: this.isPageScope
251
+ ? this.option.pageDialogHost
252
+ : document.body,
232
253
  modalStrictly: true,
233
254
  success: (res) => {
234
255
  let formTemplate = res.objx || {};
@@ -300,7 +321,9 @@ export default {
300
321
  tableAlias: this.formCode,
301
322
  },
302
323
  isLoading: true,
303
- loadingTarget: document.body,
324
+ loadingTarget: this.isPageScope
325
+ ? this.option.pageDialogHost
326
+ : document.body,
304
327
  modalStrictly: true,
305
328
  success: (res) => {
306
329
  let formData = res.objx && res.objx.data ? res.objx.data : {};
@@ -11,16 +11,23 @@
11
11
  :clearable="field.options.clearable"
12
12
  :minlength="field.options.minLength" :maxlength="field.options.maxLength"
13
13
  :show-word-limit="field.options.showWordLimit"
14
- :prefix-icon="field.options.prefixIcon" :suffix-icon="field.options.suffixIcon"
14
+ :prefix-icon="field.options.prefixIcon" :suffix-icon="clickableSuffix ? '' : field.options.suffixIcon"
15
15
  @focus="handleFocusCustomEvent" @blur="handleBlurCustomEvent" @input="handleInputCustomEvent"
16
16
  @change="handleChangeEvent"
17
17
  :style="'width:'+field.options.widgetWidth+' !important;'"
18
18
  :class="{'custom-width':field.options.widgetWidth!=null}">
19
19
  <el-button slot="append" v-if="field.options.appendButton" :disabled="field.options.disabled || field.options.appendButtonDisabled"
20
20
  :class="field.options.buttonIcon" @click.native="emitAppendButtonClick"></el-button>
21
+ <i v-if="clickableSuffix" slot="suffix"
22
+ :class="field.options.suffixIcon"
23
+ class="el-input__icon suffix-icon-clickable"
24
+ @click.stop="handleSuffixIconClick"></i>
21
25
  </el-input>
22
26
  <template v-if="isReadMode">
23
27
  <span class="readonly-mode-field pre-wrap" :title="contentForReadMode">{{contentForReadMode}}</span>
28
+ <i v-if="readModeSuffix" :class="field.options.suffixIcon"
29
+ class="el-input__icon suffix-icon-clickable"
30
+ @click.stop="handleSuffixIconClick"></i>
24
31
  </template>
25
32
  </form-item-wrapper>
26
33
  </template>
@@ -82,6 +89,18 @@
82
89
  contentForReadMode() {
83
90
  return this.fieldModel ? this.fieldModel : ''
84
91
  },
92
+ clickableSuffix() {
93
+ //尾部图标可点击(编辑态):开关开启且已配置suffixIcon;开启后suffix-icon改由slot渲染,避免图标重复
94
+ return !!this.field.options.suffixIconClickable
95
+ && !!this.field.options.suffixIcon
96
+ && !this.isReadMode
97
+ },
98
+ readModeSuffix() {
99
+ //只读模式:el-input不渲染,图标单独补充在只读文本旁
100
+ return !!this.field.options.suffixIconClickable
101
+ && !!this.field.options.suffixIcon
102
+ && this.isReadMode
103
+ },
85
104
 
86
105
  },
87
106
  beforeCreate() {
@@ -108,7 +127,11 @@
108
127
  },
109
128
 
110
129
  methods: {
111
-
130
+ handleSuffixIconClick() {
131
+ if (this.designState) return
132
+ //复用后置按钮的点击链:onAppendButtonClick脚本 → dispatch('appendButtonClick') → handleCustomClickEvent
133
+ this.emitAppendButtonClick()
134
+ }
112
135
  }
113
136
  }
114
137
  </script>
@@ -116,4 +139,7 @@
116
139
  <style lang="scss" scoped>
117
140
  @import "~@base/styles/theme-variables.scss"; //* form-item-wrapper已引入,还需要重复引入吗? *//
118
141
 
142
+ .suffix-icon-clickable {
143
+ cursor: pointer;
144
+ }
119
145
  </style>
@@ -9,11 +9,24 @@
9
9
  @submit.native.prevent
10
10
  >
11
11
  <el-collapse v-model="formActiveCollapseNames" class="setting-collapse">
12
- <el-collapse-item
13
- name="1"
14
- :title="i18nt('designer.setting.basicSetting')"
15
- >
16
- <el-form-item class="form-item-label-top" :label="i18nt('数据库表')">
12
+ <el-collapse-item
13
+ name="1"
14
+ :title="i18nt('designer.setting.basicSetting')"
15
+ >
16
+ <el-form-item
17
+ v-if="formConfig.layoutType === 'PC'"
18
+ class="form-item-label-top"
19
+ label="业务弹框作用域"
20
+ >
21
+ <el-radio-group v-model="dialogScopeValue">
22
+ <el-radio label="global">全局</el-radio>
23
+ <el-radio label="page">当前页面</el-radio>
24
+ </el-radio-group>
25
+ <div style="line-height: 1.6; color: #909399; font-size: 12px">
26
+ 列表和详情模板需分别设置。当前页面模式只遮挡表单内容,顶部页签和左侧菜单仍可操作。
27
+ </div>
28
+ </el-form-item>
29
+ <el-form-item class="form-item-label-top" :label="i18nt('数据库表')">
17
30
  <el-input type="text" v-model="formConfig.entity"></el-input>
18
31
  </el-form-item>
19
32
  <el-form-item class="form-item-label-top" :label="i18nt('数据保存脚本编码')">
@@ -1273,8 +1286,16 @@ $\{wf.starterName\}提交的$\{pm_product_project.product_code\}$\{pm_product_pr
1273
1286
  this.designer.emitEvent("form-css-updated", deepClone(this.cssClassList));
1274
1287
  });
1275
1288
  },
1276
- computed: {
1277
- // formDialog/formDrawer 底部操作按钮配置(存 formConfig,随模板保存)
1289
+ computed: {
1290
+ dialogScopeValue: {
1291
+ get() {
1292
+ return this.formConfig.dialogScope === "page" ? "page" : "global";
1293
+ },
1294
+ set(value) {
1295
+ this.$set(this.formConfig, "dialogScope", value);
1296
+ },
1297
+ },
1298
+ // formDialog/formDrawer 底部操作按钮配置(存 formConfig,随模板保存)
1278
1299
  actionButtons() {
1279
1300
  return this.formConfig.actionButtons || [];
1280
1301
  },
@@ -0,0 +1,23 @@
1
+ <template>
2
+ <el-form-item :label="i18nt('designer.setting.suffixIconClickable')">
3
+ <el-switch v-model="optionModel.suffixIconClickable"></el-switch>
4
+ </el-form-item>
5
+ </template>
6
+
7
+ <script>
8
+ import i18n from "../../../../../components/xform/utils/i18n"
9
+
10
+ export default {
11
+ name: "suffixIconClickable-editor",
12
+ mixins: [i18n],
13
+ props: {
14
+ designer: Object,
15
+ selectedWidget: Object,
16
+ optionModel: Object,
17
+ },
18
+ }
19
+ </script>
20
+
21
+ <style scoped>
22
+
23
+ </style>
@@ -211,6 +211,7 @@ const ADVANCED_PROPERTIES = {
211
211
  // 'showWordLimit': 'showWordLimit-editor',
212
212
  prefixIcon: "prefixIcon-editor",
213
213
  suffixIcon: "suffixIcon-editor",
214
+ suffixIconClickable: "suffixIconClickable-editor",
214
215
  switchWidth: "switchWidth-editor",
215
216
  activeText: "activeText-editor",
216
217
  inactiveText: "inactiveText-editor",
@@ -1202,6 +1202,7 @@ export const basicFields = [
1202
1202
  showWordLimit: !1,
1203
1203
  prefixIcon: "",
1204
1204
  suffixIcon: "",
1205
+ suffixIconClickable: !1,
1205
1206
  /*appendButton: !1,
1206
1207
  appendButtonDisabled: !1,
1207
1208
  buttonIcon: "el-icon-search",*/
@@ -55,6 +55,7 @@ import html2Canvas from "html2canvas";
55
55
  import JsPDF from "jspdf";
56
56
  import formulaDialog from "@base/components/xform/form-designer/form-widget/dialog/formulaDialog.vue";
57
57
  import baseFormulaDialog from "@base/components/xform/form-designer/form-widget/dialog/baseFormulaDialog.vue";
58
+ import { resolveDialogOption } from "@base/components/xform/form-render/pageDialogScope";
58
59
  import QRCode from "qrcode";
59
60
  import { openLuckysheetDialog } from "@base/components/luckysheet";
60
61
  import {
@@ -168,6 +169,10 @@ modules = {
168
169
  type: Boolean,
169
170
  default: false,
170
171
  },
172
+ dialogScope: {
173
+ type: String,
174
+ default: null,
175
+ },
171
176
  },
172
177
  provide() {
173
178
  let e = this;
@@ -5042,14 +5047,24 @@ modules = {
5042
5047
  }
5043
5048
  },*/
5044
5049
  openSearchDialog(option) {
5045
- this.searchDialogOption = option;
5050
+ this.searchDialogOption = resolveDialogOption(
5051
+ option,
5052
+ this.formJsonObj?.formConfig,
5053
+ this.dialogScope,
5054
+ this.$el
5055
+ );
5046
5056
  this.showSearchDialog = true;
5047
5057
  },
5048
5058
  confirmSearchDialog(rows) {
5049
5059
  this.searchDialogOption.confirm && this.searchDialogOption.confirm(rows);
5050
5060
  },
5051
5061
  openFormDialog(option) {
5052
- this.formDialogOption = option;
5062
+ this.formDialogOption = resolveDialogOption(
5063
+ option,
5064
+ this.formJsonObj?.formConfig,
5065
+ this.dialogScope,
5066
+ this.$el
5067
+ );
5053
5068
  this.showFormDialog = true;
5054
5069
  },
5055
5070
  closeFormDialog() {
@@ -0,0 +1,54 @@
1
+ export const PAGE_DIALOG_SCOPE = "page";
2
+
3
+ // 模板里的 top: "25vh" 是按整个窗口居中。当前页面弹框改由页面内容区 flex 居中,
4
+ // 再套视口 vh 会从内容区顶部再下移一截,弹框就偏下。px 等显式偏移仍保留。
5
+ export function pageDialogTop(top) {
6
+ const value = top == null ? "" : String(top).trim();
7
+ if (!value || /vh$/i.test(value)) return "0";
8
+ return value;
9
+ }
10
+
11
+ const PAGE_HOST_SELECTOR = "[data-xform-page-dialog-host]";
12
+
13
+ export function resolveDialogOption(option, formConfig, inheritedScope, element) {
14
+ const source = option || {};
15
+ const scope = source.dialogScope ?? formConfig?.dialogScope ?? inheritedScope;
16
+ if (scope !== PAGE_DIALOG_SCOPE) return source;
17
+
18
+ const host = element?.closest?.(PAGE_HOST_SELECTOR);
19
+ if (!host) {
20
+ console.warn("xform page dialog host not found; using global dialog");
21
+ return { ...source, dialogScope: "global" };
22
+ }
23
+ return { ...source, dialogScope: PAGE_DIALOG_SCOPE, pageDialogHost: host };
24
+ }
25
+
26
+ export const pageScopedDialogMixin = {
27
+ computed: {
28
+ isPageScope() {
29
+ return (
30
+ this.option?.dialogScope === PAGE_DIALOG_SCOPE
31
+ && !!this.option.pageDialogHost
32
+ );
33
+ },
34
+ pageDialogHasTop() {
35
+ return this.isPageScope && pageDialogTop(this.option.dialogConfig?.top) !== "0";
36
+ },
37
+ },
38
+ mounted() {
39
+ if (!this.isPageScope) return;
40
+ const dialog = this.$refs.pageDialog;
41
+ const wrapper = dialog?.$el;
42
+ const host = this.option.pageDialogHost;
43
+ if (!wrapper || !host) return;
44
+ host.appendChild(wrapper);
45
+ this.pageDialogWrapper = wrapper;
46
+ // The surrounding menu and route tabs remain interactive.
47
+ dialog.$refs.dialog?.setAttribute("aria-modal", "false");
48
+ },
49
+ beforeDestroy() {
50
+ const wrapper = this.pageDialogWrapper;
51
+ if (wrapper?.parentNode) wrapper.parentNode.removeChild(wrapper);
52
+ this.pageDialogWrapper = null;
53
+ },
54
+ };
@@ -299,6 +299,7 @@ export default {
299
299
  showWordLimit: "Show Word Limit",
300
300
  prefixIcon: "Prefix Icon",
301
301
  suffixIcon: "Suffix Icon",
302
+ suffixIconClickable: "Clickable Suffix Icon",
302
303
  inputButton: "Input Button Setting",
303
304
  appendButton: "Append Button",
304
305
  appendButtonDisabled: "Button Disabled",
@@ -463,6 +463,7 @@ export default {
463
463
  showWordLimit: "显示字数统计",
464
464
  prefixIcon: "头部Icon",
465
465
  suffixIcon: "尾部Icon",
466
+ suffixIconClickable: "尾部图标可点击",
466
467
  inputButton: "输入框按钮设置",
467
468
  appendButton: "添加后置按钮",
468
469
  appendButtonDisabled: "后置按钮禁用",
@@ -1128,6 +1128,7 @@ export function getDefaultFormConfig() {
1128
1128
  customClass: "",
1129
1129
  functions: "",
1130
1130
  layoutType: "PC",
1131
+ dialogScope: null,
1131
1132
  dataSources: [],
1132
1133
  onBeforeCreated: "",
1133
1134
  onFormCreated: "",
@@ -3,8 +3,9 @@ let modules = {};
3
3
 
4
4
  modules = {
5
5
  install: function(Vue) {
6
- Vue.directive('el-dialog-center', {
7
- bind(el, binding, vnode) {
6
+ Vue.directive('el-dialog-center', {
7
+ bind(el, binding, vnode) {
8
+ if (binding.value === false) return;
8
9
  if (el.children[0].querySelector(
9
10
  ".el-dialog__body")) {
10
11
  let autoTop = (document.body.offsetHeight - el.children[0]
@@ -18,10 +18,39 @@ modules = {
18
18
  }
19
19
  };
20
20
 
21
- dialogHeaderEl.onmousedown = function(e) {
22
- indexUtil.addClass(document.body, 'resize-ing');
23
-
24
- // 鼠标按下,计算当前元素距离可视区的距离
21
+ dialogHeaderEl.onmousedown = function(e) {
22
+ indexUtil.addClass(document.body, 'resize-ing');
23
+
24
+ if (el.classList.contains('xform-page-dialog-wrapper')) {
25
+ const hostRect = el.parentNode.getBoundingClientRect();
26
+ const dialogRect = dragDom.getBoundingClientRect();
27
+ const startX = e.clientX;
28
+ const startY = e.clientY;
29
+ const startLeft = parseFloat(getStyle(dragDom, 'left')) || 0;
30
+ const startTop = parseFloat(getStyle(dragDom, 'top')) || 0;
31
+
32
+ document.onmousemove = function(moveEvent) {
33
+ const deltaX = Math.min(
34
+ Math.max(moveEvent.clientX - startX, hostRect.left - dialogRect.left),
35
+ hostRect.right - dialogRect.right
36
+ );
37
+ const deltaY = Math.min(
38
+ Math.max(moveEvent.clientY - startY, hostRect.top - dialogRect.top),
39
+ hostRect.bottom - dialogRect.bottom
40
+ );
41
+ dragDom.style.left = startLeft + deltaX + 'px';
42
+ dragDom.style.top = startTop + deltaY + 'px';
43
+ vnode.child.$emit('dragDialog');
44
+ };
45
+ document.onmouseup = function() {
46
+ indexUtil.removeClass(document.body, 'resize-ing');
47
+ document.onmousemove = null;
48
+ document.onmouseup = null;
49
+ };
50
+ return;
51
+ }
52
+
53
+ // 鼠标按下,计算当前元素距离可视区的距离
25
54
  let disX = e.clientX - dialogHeaderEl.offsetLeft;
26
55
  let disY = e.clientY - dialogHeaderEl.offsetTop;
27
56
 
@@ -0,0 +1,5 @@
1
+ /**version-1.0*/
2
+ import "./public-path"; // qiankun publicPath 修正,必须保持第一行
3
+ import "normalize.css/normalize.css"; // a modern alternative to CSS resets
4
+ import "./boot-assets.legacy.js";
5
+ export * from "./app-bootstrap.sync.js";
@@ -81,10 +81,7 @@ export const constantRoutes = [
81
81
  path: "/haier/system/salesman/list",
82
82
  component: () => import("@/views/haier/system/salesman/list.vue"),
83
83
  name: "haierSalesmanPilot",
84
- meta: {
85
- title: "业务员",
86
- icon: "user",
87
- },
84
+ meta: { title: "业务员", icon: "user" },
88
85
  },
89
86
  ],
90
87
  },
@@ -78,6 +78,97 @@ body {
78
78
  }
79
79
  }
80
80
  }
81
+
82
+ .app-main #containt.xform-page-dialog-host {
83
+ z-index: 0;
84
+ isolation: isolate;
85
+
86
+ > .xform-page-dialog-wrapper {
87
+ position: absolute !important;
88
+ inset: 0;
89
+ display: flex;
90
+ align-items: center;
91
+ justify-content: center;
92
+ background: transparent;
93
+ overflow: auto !important;
94
+
95
+ &.xform-page-dialog-wrapper--top {
96
+ align-items: flex-start;
97
+ }
98
+
99
+ > .el-dialog {
100
+ flex: none;
101
+ display: flex;
102
+ flex-direction: column;
103
+ max-width: calc(100% - 24px);
104
+ max-height: calc(100% - 24px);
105
+ margin-bottom: 0;
106
+
107
+ &.is-fullscreen {
108
+ max-width: 100%;
109
+ max-height: 100%;
110
+ }
111
+
112
+ > .el-dialog__body {
113
+ min-height: 0;
114
+ overflow: auto;
115
+ }
116
+ }
117
+
118
+ // 业务表单原先用视口 vh 给 .cont 定高。挂进当前页面后,可用高度变小,
119
+ // 需要让标题、内容、底栏按弹框自身高度分配,只在内容区滚动。
120
+ &.xform-page-form-dialog-wrapper {
121
+ overflow: hidden !important;
122
+
123
+ > .el-dialog {
124
+ overflow: hidden;
125
+
126
+ > .el-dialog__header,
127
+ > .el-dialog__footer {
128
+ flex: 0 0 auto;
129
+ }
130
+
131
+ > .el-dialog__body {
132
+ display: flex;
133
+ flex: 0 1 auto;
134
+ flex-direction: column;
135
+ height: auto !important;
136
+ min-height: 0;
137
+ overflow: hidden;
138
+
139
+ > .cont {
140
+ flex: 0 1 auto;
141
+ // 与全局业务弹框的常用高度一致;bodyConfig 的行内高度仍可覆盖。
142
+ height: 70vh;
143
+ min-height: 0;
144
+ overflow-x: hidden;
145
+ overflow-y: auto;
146
+ }
147
+
148
+ // 与旧版全局业务弹框一致,内容四周保留白色留白。
149
+ // 用边框承载留白,滚动时它不会像 padding 一样被卷走。
150
+ > .cont.designer-view:not(.fd-list-host) {
151
+ box-sizing: border-box;
152
+ border: 12px solid #fff;
153
+ padding: 0;
154
+ }
155
+ }
156
+ }
157
+ }
158
+ }
159
+
160
+ // 弹框挂进 #app 后,#containt.designer-view 的 background: none 会作用到弹框内容,
161
+ // 白底被去掉,露出页面底色。这里只把内容区白底加回来。
162
+ .el-dialog__body > #containt {
163
+ background-color: #fff;
164
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
165
+
166
+ &.designer-view {
167
+ background-color: #fff;
168
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
169
+ }
170
+ }
171
+ }
81
172
  /* 外链页面(#/outLinkView、#/form_outLinkView 等)不走 layout,没有 .app-main 撑高度,
82
173
  #containt 只能被内容撑开,列表/详情会塌陷显示不全,这里补上与 .app-main 一致的高度 */
83
174
  #app > #containt {
@@ -1,5 +1,16 @@
1
1
  <template>
2
- <div id="containt">
2
+ <div
3
+ id="containt"
4
+ :class="{
5
+ 'xform-page-dialog-host':
6
+ layoutType === 'PC' && !dialogScope && formConfig.dialogScope === 'page',
7
+ }"
8
+ :data-xform-page-dialog-host="
9
+ layoutType === 'PC' && !dialogScope && formConfig.dialogScope === 'page'
10
+ ? ''
11
+ : null
12
+ "
13
+ >
3
14
  <template v-if="layoutType === 'PC'">
4
15
  <x-tabs
5
16
  ref="xTabs"
@@ -22,6 +33,7 @@
22
33
  visible-key="showEdit"
23
34
  :visiable.sync="showEdit"
24
35
  :parent-target="_self"
36
+ :dialogScope="dialogScope"
25
37
  @reload="reload"
26
38
  @openCopyEditTab="openCopyEditTab"
27
39
  ></vFormRender>
@@ -40,6 +52,7 @@
40
52
  visible-key="showRender"
41
53
  :visiable.sync="showRender"
42
54
  :parent-target="_self"
55
+ :dialogScope="dialogScope"
43
56
  @reload="$reloadHandle"
44
57
  :openEditDialog="openEditDialog"
45
58
  ></vFormRender>
@@ -59,6 +72,7 @@
59
72
  :param="item.param"
60
73
  v-if="item.showContent"
61
74
  :parent-target="_self"
75
+ :dialogScope="dialogScope"
62
76
  @reload="(...args) => reloadAutoContent(...args)"
63
77
  :openEditDialog="openEditDialog1"
64
78
  ></vFormRender>
@@ -78,6 +92,7 @@
78
92
  :param="tab.param"
79
93
  v-if="tab.showContent"
80
94
  :parent-target="_self"
95
+ :dialogScope="dialogScope"
81
96
  @reload="(...args) => onEditTabReload(tab, ...args)"
82
97
  @openCopyEditTab="openCopyEditTab"
83
98
  ></vFormRender>
@@ -107,6 +122,7 @@
107
122
  v-if="showEditDialog && showEdit"
108
123
  visible-key="showEdit"
109
124
  :parent-target="_self"
125
+ :dialogScope="dialogScope"
110
126
  @reload="$reloadHandle"
111
127
  ></vFormRender>
112
128
  </div>
@@ -118,6 +134,7 @@
118
134
  v-if="showRender"
119
135
  visible-key="showRender"
120
136
  :parent-target="_self"
137
+ :dialogScope="dialogScope"
121
138
  @reload="$reloadHandle"
122
139
  :openEditDialog="openEditDialog"
123
140
  ></vFormRender>
@@ -131,6 +148,12 @@ import vFormRender from "../../../../views/user/form/vform/render";
131
148
  export default {
132
149
  name: "form_view:list",
133
150
  components: { vFormRender },
151
+ props: {
152
+ dialogScope: {
153
+ type: String,
154
+ default: null,
155
+ },
156
+ },
134
157
  mounted() {},
135
158
  data() {
136
159
  let that = this;