cloud-web-corejs 1.1.0-dev.6 → 1.1.0-dev.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -0
- package/bin/core-resources.js +16 -0
- package/bin/create-child-app.js +34 -0
- package/docs/child-app/README.md +95 -0
- package/docs/child-app/activiti-resources.md +63 -0
- package/docs/child-app/generate-prompt.md +55 -0
- package/docs/child-app/luckysheet-resources.md +80 -0
- package/docs/child-app/public-resources-plan.md +288 -0
- package/docs/child-app/resources-implementation.md +101 -0
- package/docs/child-app/tinymce-resources.md +88 -0
- package/docs/child-app/validation.md +34 -0
- package/docs/qiankun/346/216/245/345/205/245/345/215/217/350/256/256.md +298 -0
- package/docs/qiankun/350/257/246/346/203/205/346/211/277/350/275/275/345/255/220/345/272/224/347/224/250/345/257/271/346/216/245/346/270/205/345/215/225.md +111 -0
- package/package.json +29 -4
- package/resource-tools/index.js +126 -0
- package/src/app-bootstrap.js +531 -0
- package/src/app-bootstrap.sync.js +502 -0
- package/src/boot-assets.legacy.js +13 -0
- package/src/boot-assets.next.js +7 -0
- package/src/components/Qrcode/fileParse.vue +11 -0
- package/src/components/Tinymce/dynamicLoadScript.js +51 -59
- package/src/components/Tinymce/index.vue +382 -336
- package/src/components/Tinymce/mce-chrome.scss +150 -0
- package/src/components/VabUpload/image-viewer.vue +18 -10
- package/src/components/VabUpload/index.js +11 -4
- package/src/components/VabUpload/index.vue +1 -1
- package/src/components/VabUpload/mixins/fileLibraryDialog.js +2 -0
- package/src/components/VabUpload/mixins.js +72 -40
- package/src/components/VabUpload/partUploadConfig.js +95 -0
- package/src/components/VabUpload/privateProfileDialogMixins.js +2 -0
- package/src/components/VabUpload/style.scss +282 -0
- package/src/components/VabUpload/view.vue +19 -18
- package/src/components/baseArea/index.vue +2 -2
- package/src/components/baseInputExport/mixins.js +1 -6
- package/src/components/bizTab/BizTabListPage.vue +66 -33
- package/src/components/bizTab/README.md +3 -1
- package/src/components/bizTab/bizBillDetailMixin.js +2 -0
- package/src/components/code-editor/ace-chrome.scss +17 -0
- package/src/components/code-editor/index.vue +361 -340
- package/src/components/errorMsg/index.vue +142 -13
- package/src/components/errorMsg/mixins.js +53 -0
- package/src/components/excelExport/conditionExportConfig.js +112 -0
- package/src/components/excelExport/exportColumnMemory.js +118 -0
- package/src/components/excelExport/exportFieldDialog.vue +50 -38
- package/src/components/excelExport/exportType.js +8 -0
- package/src/components/excelExport/index.js +30 -13
- package/src/components/excelExport/index.vue +7 -1
- package/src/components/excelExport/mixins.js +782 -293
- package/src/components/excelImport/index.vue +156 -156
- package/src/components/excelImport/mixins.js +888 -834
- package/src/components/fileLibrary/mixins/indexMixins.js +2 -0
- package/src/components/fileLibrary/style.scss +579 -0
- package/src/components/formDialog/index.vue +11 -8
- package/src/components/hiprint/style.scss +188 -0
- package/src/components/hiprint/view/json-view.vue +4 -4
- package/src/components/jdPrint/mixins.js +2 -0
- package/src/components/jsonImport/index.vue +1 -1
- package/src/components/jsonImport/mixins.js +6 -10
- package/src/components/langImport/index.vue +1 -1
- package/src/components/langImport/mixins.js +6 -10
- package/src/components/luckysheet/loadResources.js +64 -0
- package/src/components/luckysheet/view.vue +239 -210
- package/src/components/mobile/buttonGroup/index.vue +1 -1
- package/src/components/mobile/wf/addTaskUserdialog.vue +100 -80
- package/src/components/mobile/wf/content.vue +1734 -1662
- package/src/components/mobile/wf/deleteTaskUserDialog.vue +73 -54
- package/src/components/mobile/wf/selectUserDialog.vue +118 -0
- package/src/components/mobile/wf/setCandidateDialog.vue +69 -48
- package/src/components/mobile/wf/urgingDialog.vue +75 -52
- package/src/components/mobile/wf/wfModifyDialog.vue +4 -0
- package/src/components/obsUpload/index.js +4 -1
- package/src/components/obsUpload/index.vue +1 -1
- package/src/components/obsUpload/mixins.js +45 -15
- package/src/components/onlineTalk/index.vue +4 -4
- package/src/components/onlineTalk/mixins.js +21 -7
- package/src/components/table/index.js +96 -81
- package/src/components/table/plugins/cell-area/index.js +10 -3
- package/src/components/table/style.scss +1399 -0
- package/src/components/table/vxeFilter/mixin.js +28 -18
- package/src/components/wf/content.vue +3 -2
- package/src/components/wf/content2.vue +1 -1
- package/src/components/wf/style.scss +265 -0
- package/src/components/wf/wf.js +7 -0
- package/src/components/wf/wfActionItems.js +3 -0
- package/src/components/wf/wfStartDialog.vue +1 -0
- package/src/components/wf/wfTransferEnabled.js +54 -0
- package/src/components/wf/wfUtil.js +47 -29
- package/src/components/wf/wfVisibility.js +6 -0
- package/src/components/xform/docs/2026-07 table/344/270/216excelExport/344/277/256/345/244/215/345/217/212/345/257/274/345/207/272/344/274/230/345/214/226.md" +64 -57
- package/src/components/xform/docs/2026-08 xform H5 P0 /345/256/236/347/216/260/350/247/204/346/240/274.md" +1 -1
- package/src/components/xform/docs/2026-08 xform /347/247/273/345/212/250/347/253/257/345/270/203/345/261/200/345/257/271/351/275/220 bill_setting /346/226/271/346/241/210.md" +1 -1
- package/src/components/xform/docs/2026-09 /345/212/250/346/200/201/345/255/227/346/256/265/350/247/204/345/210/231/344/270/216/346/265/201/347/250/213/346/216/247/345/210/266/346/211/247/350/241/214/351/241/272/345/272/217/350/220/275/345/234/260/346/226/271/346/241/210.md" +409 -0
- package/src/components/xform/docs/2026-09 /346/235/241/344/273/266/345/257/274/345/207/272/345/244/247/346/225/260/346/215/256/351/207/217/345/264/251/346/272/203/346/216/222/346/237/245.md" +389 -0
- package/src/components/xform/docs/2026-09 /346/265/217/350/247/210/345/231/250/345/264/251/346/272/203/346/262/273/347/220/206P0/344/273/243/347/240/201/350/257/204/345/256/241.md" +255 -0
- package/src/components/xform/docs/2026-09 /346/265/217/350/247/210/345/231/250/345/264/251/346/272/203/346/262/273/347/220/206P0/346/265/213/350/257/225/351/252/214/350/257/201/345/256/236/346/226/275/346/226/207/346/241/243.md" +595 -0
- package/src/components/xform/docs/2026-09 /347/274/226/350/276/221/350/241/250/350/241/214/345/206/205/344/277/235/345/255/230/346/240/241/351/252/214/350/214/203/345/233/264/344/270/216/345/210/227/345/277/205/345/241/253/350/247/243/346/236/220/344/277/256/345/244/215.md" +233 -0
- package/src/components/xform/docs/2026-09 /350/241/250/345/215/225/345/257/274/345/205/245/351/200/232/351/201/223/346/242/263/347/220/206/344/270/216/350/220/275/345/234/260/346/226/271/346/241/210.md" +745 -0
- package/src/components/xform/docs//346/265/217/350/247/210/345/231/250/345/264/251/346/272/203/346/262/273/347/220/206/344/270/216/344/277/256/345/244/215/350/220/275/345/234/260/346/226/271/346/241/210.md +324 -0
- package/src/components/xform/form-designer/designer.js +2133 -2100
- package/src/components/xform/form-designer/form-widget/container-widget/data-table-mixin.js +7 -0
- package/src/components/xform/form-designer/form-widget/container-widget/data-table-widget.vue +4 -2
- package/src/components/xform/form-designer/form-widget/container-widget/detail-h5-widget.vue +243 -227
- package/src/components/xform/form-designer/form-widget/container-widget/h5-card-pane-widget.vue +228 -207
- package/src/components/xform/form-designer/form-widget/container-widget/h5-card-widget.vue +165 -136
- package/src/components/xform/form-designer/form-widget/dialog/formDialog.vue +30 -4
- package/src/components/xform/form-designer/form-widget/dialog/importDialog.vue +190 -185
- package/src/components/xform/form-designer/form-widget/dialog/importDialogMixin.js +2657 -1774
- package/src/components/xform/form-designer/form-widget/dialog/searchFormDialog.vue +27 -4
- package/src/components/xform/form-designer/form-widget/field-widget/a-link-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/a-text-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/area-select-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/autocomplete-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/baseAttachment-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/button-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/cascader-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/census-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/checkbox-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/color-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/copy_button-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/date-range-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/date-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/descriptions-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/divider-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/download-button-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/dropdown-item-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/dropdown-widget.vue +35 -4
- package/src/components/xform/form-designer/form-widget/field-widget/echart-bar-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/echart-category-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/echart-pie-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/fieldMixin.js +64 -10
- package/src/components/xform/form-designer/form-widget/field-widget/file-upload-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/form-item-wrapper.vue +14 -4
- package/src/components/xform/form-designer/form-widget/field-widget/html-text-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/import-button-widget.vue +19 -6
- package/src/components/xform/form-designer/form-widget/field-widget/import2-button-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/index.js +10 -1
- package/src/components/xform/form-designer/form-widget/field-widget/input-batch-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/input-widget.vue +29 -3
- package/src/components/xform/form-designer/form-widget/field-widget/multiSearch-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/news-list-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/number-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/oplog-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/picture-upload-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/print-button-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/print-detail-button-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/project-tag-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/radio-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/rate-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/rich-editor-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/row-col-select-widget.vue +64 -0
- package/src/components/xform/form-designer/form-widget/field-widget/save_submit_wf_button-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/script-input-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/search_button-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/select-export-button-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/select-export-item-button-widget.vue +6 -2
- package/src/components/xform/form-designer/form-widget/field-widget/select-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/singerSearch-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/singleUpload-widget.vue +145 -145
- package/src/components/xform/form-designer/form-widget/field-widget/slider-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/static-content-wrapper.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/static-text-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/status-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/switch-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/table-export-button-widget.vue +3 -2
- package/src/components/xform/form-designer/form-widget/field-widget/tempStorage-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/text-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/textarea-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/time-range-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/time-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/title-head-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/vabSearch-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/vabUpload-widget.vue +3 -3
- package/src/components/xform/form-designer/form-widget/field-widget/vabUpload2-widget.vue +25 -1
- package/src/components/xform/form-designer/form-widget/field-widget/vue-page-widget.vue +1 -1
- package/src/components/xform/form-designer/indexMixin.js +27 -0
- package/src/components/xform/form-designer/setting-panel/form-dynamicField-setting.vue +687 -602
- package/src/components/xform/form-designer/setting-panel/form-setting.vue +269 -36
- package/src/components/xform/form-designer/setting-panel/property-editor/container-data-table/data-table-editor.vue +335 -12
- package/src/components/xform/form-designer/setting-panel/property-editor/container-data-table/table-column-dialog.vue +23 -7
- package/src/components/xform/form-designer/setting-panel/property-editor/container-detail/detail-temp-edito.vue +13 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/container-list-h5/list-h5-editor.vue +846 -860
- package/src/components/xform/form-designer/setting-panel/property-editor/container-tab/tab-lazyRender-editor.vue +27 -0
- package/src/components/xform/form-designer/setting-panel/property-editor/event-handler/onTabChange-editor.vue +28 -0
- package/src/components/xform/form-designer/setting-panel/property-editor/event-handler/onTabClick-editor.vue +28 -0
- package/src/components/xform/form-designer/setting-panel/property-editor/field-import-button/import-button-editor.vue +62 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-import-button/import2-button-editor.vue +142 -2
- package/src/components/xform/form-designer/setting-panel/property-editor/field-table-export-button/empty-number-input.vue +51 -0
- package/src/components/xform/form-designer/setting-panel/property-editor/field-table-export-button/select-export-item-button-editor.vue +27 -2
- package/src/components/xform/form-designer/setting-panel/property-editor/field-table-export-button/table-export-button-editor.vue +33 -3
- package/src/components/xform/form-designer/setting-panel/property-editor/project-tag-editor.vue +2 -4
- package/src/components/xform/form-designer/setting-panel/property-editor/suffixIconClickable-editor.vue +23 -0
- package/src/components/xform/form-designer/setting-panel/propertyRegister.js +18 -4
- package/src/components/xform/form-designer/toolbar-panel/index.vue +884 -874
- package/src/components/xform/form-designer/toolbar-panel/indexMixin.js +13 -0
- package/src/components/xform/form-designer/widget-panel/index.vue +11 -7
- package/src/components/xform/form-designer/widget-panel/indexMixin.js +15 -2
- package/src/components/xform/form-designer/widget-panel/widgetsConfig.js +152 -9
- package/src/components/xform/form-render/container-item/containerItemMixin.js +93 -8
- package/src/components/xform/form-render/container-item/data-table-item.vue +352 -347
- package/src/components/xform/form-render/container-item/data-table-mixin.js +7261 -5985
- package/src/components/xform/form-render/container-item/detail-h5-item.vue +48 -19
- package/src/components/xform/form-render/container-item/detail-item.vue +350 -446
- package/src/components/xform/form-render/container-item/dynamicFieldMixin.js +55 -1
- package/src/components/xform/form-render/container-item/list-h5-item.vue +261 -178
- package/src/components/xform/form-render/container-item/panel-item.vue +1 -1
- package/src/components/xform/form-render/container-item/tab-item.vue +177 -129
- package/src/components/xform/form-render/fieldControlEngine.js +218 -0
- package/src/components/xform/form-render/fieldControlMixin.js +536 -0
- package/src/components/xform/form-render/index.vue +164 -153
- package/src/components/xform/form-render/indexMixin.js +5443 -5311
- package/src/components/xform/form-render/pageDialogScope.js +54 -0
- package/src/components/xform/icon-picker/index.vue +1 -1
- package/src/components/xform/lang/en-US.js +8 -0
- package/src/components/xform/lang/zh-CN.js +9 -0
- package/src/components/xform/mixins/businessLock.js +59 -0
- package/src/components/xform/mixins/defaultHandle.js +713 -707
- package/src/components/xform/mixins/scriptHttp.js +42 -21
- package/src/components/xform/mixins/wfStart.js +105 -0
- package/src/components/xform/mixins/wfVisibility.js +33 -0
- package/src/components/xform/styles/census.scss +288 -0
- package/src/components/xform/styles/containers.scss +215 -0
- package/src/components/xform/styles/designer.scss +904 -0
- package/src/components/xform/styles/detail-temp.scss +71 -0
- package/src/components/xform/styles/h5-designer.scss +191 -0
- package/src/components/xform/styles/h5-runtime.scss +520 -0
- package/src/components/xform/styles/h5.scss +836 -516
- package/src/components/xform/styles/skins.scss +398 -0
- package/src/components/xform/styles/table-layout.scss +91 -0
- package/src/components/xform/styles/titles.scss +255 -0
- package/src/components/xform/utils/dynamicSchemaUtil.js +385 -361
- package/src/components/xform/utils/fixedQueryUtil.js +29 -4
- package/src/components/xform/utils/serviceNameCache.js +69 -0
- package/src/components/xform/utils/tableColumnHelper.js +46 -4
- package/src/components/xform/utils/util.js +1776 -1708
- package/src/core-resources/css/h5.scss +548 -0
- package/src/core-resources/css/iconfont.css +1447 -0
- package/src/core-resources/font/iconfont.ttf +0 -0
- package/src/core-resources/font/iconfont.woff +0 -0
- package/src/core-resources/font/iconfont.woff2 +0 -0
- package/src/core-resources/images/default-header.png +0 -0
- package/src/core-resources/images/ico-default_wenjian.svg +1 -0
- package/src/core-resources/images/ico-excel.svg +1 -0
- package/src/core-resources/images/ico-ftl.svg +7 -0
- package/src/core-resources/images/ico-html.svg +1 -0
- package/src/core-resources/images/ico-java.svg +1 -0
- package/src/core-resources/images/ico-music.svg +1 -0
- package/src/core-resources/images/ico-pdf.svg +1 -0
- package/src/core-resources/images/ico-photo.svg +1 -0
- package/src/core-resources/images/ico-ppt.svg +1 -0
- package/src/core-resources/images/ico-psd.svg +1 -0
- package/src/core-resources/images/ico-service.png +0 -0
- package/src/core-resources/images/ico-txt.svg +1 -0
- package/src/core-resources/images/ico-video.svg +1 -0
- package/src/core-resources/images/ico-vue.svg +8 -0
- package/src/core-resources/images/ico-wenjianjia.svg +1 -0
- package/src/core-resources/images/ico-wrod.svg +1 -0
- package/src/core-resources/images/ico-xml.svg +1 -0
- package/src/core-resources/images/ico-yasuobao.svg +1 -0
- package/src/core-resources/images/icon-error.png +0 -0
- package/src/core-resources/images/icon-tips.png +0 -0
- package/src/core-resources/images/nodata.png +0 -0
- package/src/core-resources/images/nodata2.png +0 -0
- package/src/directive/append-to-body/index.js +48 -0
- package/src/directive/el-dialog-center/index.js +3 -2
- package/src/directive/el-drag-dialog/drag.js +33 -4
- package/src/icons/index.js +9 -0
- package/src/icons/svg/404.svg +1 -0
- package/src/icons/svg/alert.svg +1 -0
- package/src/icons/svg/bug.svg +1 -0
- package/src/icons/svg/button.svg +1 -0
- package/src/icons/svg/card.svg +1 -0
- package/src/icons/svg/cascader-field.svg +1 -0
- package/src/icons/svg/census.svg +1 -0
- package/src/icons/svg/chart.svg +1 -0
- package/src/icons/svg/checkbox-field.svg +1 -0
- package/src/icons/svg/clipboard.svg +1 -0
- package/src/icons/svg/color-field.svg +1 -0
- package/src/icons/svg/component.svg +1 -0
- package/src/icons/svg/custom-component.svg +1 -0
- package/src/icons/svg/dashboard.svg +1 -0
- package/src/icons/svg/data-table.svg +1 -0
- package/src/icons/svg/date-field.svg +1 -0
- package/src/icons/svg/date-range-field.svg +1 -0
- package/src/icons/svg/descriptions.svg +1 -0
- package/src/icons/svg/divider.svg +1 -0
- package/src/icons/svg/document.svg +1 -0
- package/src/icons/svg/documentation.svg +1 -0
- package/src/icons/svg/drag.svg +1 -0
- package/src/icons/svg/echart-category.svg +1 -0
- package/src/icons/svg/echart-pie.svg +1 -0
- package/src/icons/svg/echart.svg +1 -0
- package/src/icons/svg/edit.svg +1 -0
- package/src/icons/svg/education.svg +1 -0
- package/src/icons/svg/email.svg +1 -0
- package/src/icons/svg/example.svg +1 -0
- package/src/icons/svg/excel.svg +1 -0
- package/src/icons/svg/exit-fullscreen.svg +1 -0
- package/src/icons/svg/eye-open.svg +1 -0
- package/src/icons/svg/eye.svg +1 -0
- package/src/icons/svg/file-upload-field.svg +1 -0
- package/src/icons/svg/form.svg +1 -0
- package/src/icons/svg/fullscreen.svg +1 -0
- package/src/icons/svg/github.svg +1 -0
- package/src/icons/svg/grid.svg +1 -0
- package/src/icons/svg/guide.svg +1 -0
- package/src/icons/svg/html-text.svg +1 -0
- package/src/icons/svg/ico-more.svg +1 -0
- package/src/icons/svg/ico-wenjianjia.svg +1 -0
- package/src/icons/svg/icon.svg +1 -0
- package/src/icons/svg/input-batch.svg +1 -0
- package/src/icons/svg/international.svg +1 -0
- package/src/icons/svg/language.svg +1 -0
- package/src/icons/svg/link.svg +1 -0
- package/src/icons/svg/list-export.svg +1 -0
- package/src/icons/svg/list.svg +1 -0
- package/src/icons/svg/lock.svg +1 -0
- package/src/icons/svg/message.svg +1 -0
- package/src/icons/svg/money.svg +1 -0
- package/src/icons/svg/nested.svg +1 -0
- package/src/icons/svg/news-list.svg +1 -0
- package/src/icons/svg/node-tree.svg +1 -0
- package/src/icons/svg/number-field.svg +1 -0
- package/src/icons/svg/password.svg +1 -0
- package/src/icons/svg/pdf.svg +1 -0
- package/src/icons/svg/people.svg +1 -0
- package/src/icons/svg/peoples.svg +1 -0
- package/src/icons/svg/picture-upload-field.svg +1 -0
- package/src/icons/svg/qq.svg +1 -0
- package/src/icons/svg/query.svg +1 -0
- package/src/icons/svg/radio-field.svg +1 -0
- package/src/icons/svg/rate-field.svg +1 -0
- package/src/icons/svg/redo.svg +1 -0
- package/src/icons/svg/rich-editor-field.svg +1 -0
- package/src/icons/svg/search.svg +1 -0
- package/src/icons/svg/searchbox.svg +1 -0
- package/src/icons/svg/section.svg +1 -0
- package/src/icons/svg/select-field.svg +1 -0
- package/src/icons/svg/shopping.svg +1 -0
- package/src/icons/svg/size.svg +1 -0
- package/src/icons/svg/skill.svg +1 -0
- package/src/icons/svg/slider-field.svg +1 -0
- package/src/icons/svg/slot-component.svg +1 -0
- package/src/icons/svg/slot-field.svg +1 -0
- package/src/icons/svg/star.svg +1 -0
- package/src/icons/svg/static-text.svg +1 -0
- package/src/icons/svg/status.svg +1 -0
- package/src/icons/svg/sub-form.svg +1 -0
- package/src/icons/svg/switch-field.svg +1 -0
- package/src/icons/svg/tab.svg +1 -0
- package/src/icons/svg/table.svg +1 -0
- package/src/icons/svg/text-field.svg +1 -0
- package/src/icons/svg/text.svg +1 -0
- package/src/icons/svg/textarea-field.svg +1 -0
- package/src/icons/svg/theme.svg +1 -0
- package/src/icons/svg/time-field.svg +1 -0
- package/src/icons/svg/time-range-field.svg +1 -0
- package/src/icons/svg/tips-text.svg +1 -0
- package/src/icons/svg/title-head.svg +1 -0
- package/src/icons/svg/tree-pane.svg +1 -0
- package/src/icons/svg/tree-table.svg +1 -0
- package/src/icons/svg/tree.svg +1 -0
- package/src/icons/svg/undo.svg +1 -0
- package/src/icons/svg/uploadbox.svg +1 -0
- package/src/icons/svg/user.svg +1 -0
- package/src/icons/svg/vf-box.svg +1 -0
- package/src/icons/svg/vf-dialog.svg +1 -0
- package/src/icons/svg/vf-drawer.svg +1 -0
- package/src/icons/svg/vue-sfc.svg +1 -0
- package/src/icons/svg/wechat.svg +1 -0
- package/src/icons/svg/zip.svg +1 -0
- package/src/index.js +2 -510
- package/src/index.next.js +5 -0
- package/src/index.sync.js +5 -0
- package/src/layout/components/Sidebar/default.vue +1656 -1655
- package/src/layout/components/TagsView/index.vue +330 -323
- package/src/layout/components/TagsView/style.scss +92 -0
- package/src/layout/components/watermark/index.vue +1 -1
- package/src/layout/defaultLayout.vue +2 -2
- package/src/router/index.js +43 -48
- package/src/router/modules/customer.js +12 -0
- package/src/store/modules/settings.js +1 -1
- package/src/store/modules/tagsView.js +241 -217
- package/src/store/modules/user.js +16 -12
- package/src/styles/btn.scss +315 -0
- package/src/styles/dialog.scss +1710 -0
- package/src/styles/element-ui.scss +1076 -0
- package/src/styles/element-variables.scss +31 -0
- package/src/styles/global.scss +115 -0
- package/src/styles/index.scss +245 -0
- package/src/styles/layout-skins.scss +840 -0
- package/src/styles/legacy-base.scss +19 -0
- package/src/styles/menu-icons.scss +75 -0
- package/src/styles/mixin.scss +80 -0
- package/src/styles/nprogress.scss +14 -0
- package/src/styles/page-shell.scss +723 -0
- package/src/styles/sidebar.scss +296 -0
- package/src/styles/split-handle.scss +52 -0
- package/src/styles/theme-variables.scss +7 -0
- package/src/styles/transition.scss +48 -0
- package/src/styles/utilities.scss +253 -0
- package/src/styles/variables.scss +72 -0
- package/src/utils/baseDictsCache.js +197 -0
- package/src/utils/chunkLoadError.js +24 -0
- package/src/utils/featureResources.js +57 -0
- package/src/utils/importLimit.js +72 -0
- package/src/utils/pdfUtil.js +6 -1
- package/src/utils/request.js +149 -9
- package/src/utils/resolveViewComponent.js +45 -90
- package/src/utils/runtimeRecovery.js +105 -0
- package/src/utils/swiperLoader.js +20 -0
- package/src/utils/vab.js +1334 -1283
- package/src/utils/xlsxLoader.js +29 -0
- package/src/views/bd/setting/formVersion/compareContMixin.scss +1 -1
- package/src/views/bd/setting/form_template/edit.vue +378 -356
- package/src/views/bd/setting/form_template/formDesignerDialog.vue +6 -0
- package/src/views/bd/setting/form_template/formTemplateType.js +43 -0
- package/src/views/bd/setting/form_template/list.vue +304 -303
- package/src/views/bd/setting/form_template/mixins/edit.js +344 -280
- package/src/views/bd/setting/form_template/mixins/list.js +749 -721
- package/src/views/bd/setting/form_template/mixins/list2.js +412 -411
- package/src/views/bd/setting/form_template/mixins/wf_list.js +431 -430
- package/src/views/mobile/user/area/dialog.vue +1 -1
- package/src/views/mobile/user/user/dialog.vue +1 -1
- package/src/views/user/bill_setting/mixins/wf.js +8 -0
- package/src/views/user/bill_setting/render.vue +1 -1
- package/src/views/user/commMenu/index.vue +3 -1
- package/src/views/user/commMenu/style.scss +123 -0
- package/src/views/user/common_attribute/edit.vue +2 -0
- package/src/views/user/common_attribute/itemEdit.vue +2 -0
- package/src/views/user/file_view_ins/list.vue +970 -970
- package/src/views/user/form/form_template/list.vue +527 -506
- package/src/views/user/form/vform/designer.vue +823 -821
- package/src/views/user/form/view/list.vue +24 -1
- package/src/views/user/home/default.vue +1124 -1117
- package/src/views/user/home/default2.vue +12 -8
- package/src/views/user/home/index.vue +102 -102
- package/src/views/user/home/wjl/content.vue +1581 -1569
- package/src/views/user/intf_permission/edit.vue +230 -0
- package/src/views/user/intf_permission/list.vue +196 -0
- package/src/views/user/menuFallback/index.vue +23 -0
- package/src/views/user/notify_message/dialog.vue +139 -139
- package/src/views/user/outLink/form_view.vue +202 -202
- package/src/views/user/outLink/index.vue +110 -110
- package/src/views/user/role/edit.vue +4 -0
- package/src/views/user/role/role-box.scss +83 -0
- package/src/views/user/role/voc_edit.vue +4 -0
- package/src/views/user/user/list.vue +28 -6
- package/src/views/user/wf/iframe/index.vue +51 -51
- package/src/views/user/wf/iframe/index2.vue +64 -64
- package/src/views/user/wf/wf_diy_attribute/edit.vue +1 -1
- package/src/views/user/wf/wf_manage/list2.vue +871 -871
- package/src/views/user/wf/wf_manage/wfContentDialog.vue +177 -126
- package/src/views/user/wf/wf_obj_config/activiti_wf.vue +134 -133
- package/src/views/user/wf/wf_obj_config/importItemDialog.vue +1 -1
- package/src/views/user/wf/wf_obj_config/list.vue +747 -746
- package/src/views/user/wf/wf_obj_config/list_form.vue +374 -373
- package/templates/child-app/.env +3 -0
- package/templates/child-app/README.md +49 -0
- package/templates/child-app/app.config.js +6 -0
- package/templates/child-app/babel.config.js +1 -0
- package/templates/child-app/core-resources.config.js +15 -0
- package/templates/child-app/gitignore +7 -0
- package/templates/child-app/package.json +34 -0
- package/templates/child-app/public/index.html +12 -0
- package/templates/child-app/src/assets/401_images/401.gif +0 -0
- package/templates/child-app/src/assets/404_images/404.png +0 -0
- package/templates/child-app/src/assets/404_images/404_cloud.png +0 -0
- package/templates/child-app/src/assets/logo.png +0 -0
- package/templates/child-app/src/corejsConfig.js +2 -0
- package/templates/child-app/src/icons/index.js +2 -0
- package/templates/child-app/src/icons/svg/child-demo.svg +1 -0
- package/templates/child-app/src/layout/index.vue +4 -0
- package/templates/child-app/src/main.js +5 -0
- package/templates/child-app/src/prefixConfig.js +13 -0
- package/templates/child-app/src/resources/css/login.scss +29 -0
- package/templates/child-app/src/resources/images/bg-login5.jpg +0 -0
- package/templates/child-app/src/resources/images/home-img.png +0 -0
- package/templates/child-app/src/router/modules/customer.js +3 -0
- package/templates/child-app/src/settings.js +25 -0
- package/templates/child-app/src/styles/app.scss +2 -0
- package/templates/child-app/src/views/demo/detail.vue +19 -0
- package/templates/child-app/src/views/demo/list.vue +38 -0
- package/templates/child-app/src/views/user/login/index.vue +18 -0
- package/templates/child-app/vue.config.js +107 -0
- package/src/components/xform/form-render/container-item/dynamicFieldEngine.js +0 -285
- package/src/components/xform/form-render/formDynamicFieldMixin.js +0 -131
- package/src/views/demo/bizTab/bill/billConfig.js +0 -41
- package/src/views/demo/bizTab/bill/detail.vue +0 -436
- package/src/views/demo/bizTab/bill/list.vue +0 -288
- package/src/views/demo/bizTab/bill/productDialog.vue +0 -176
- package/src/views/demo/bizTab/simple/billApi.js +0 -123
- package/src/views/demo/bizTab/simple/detail.vue +0 -407
- package/src/views/demo/bizTab/simple/list.vue +0 -217
- package/src/views/demo/bizTab/standalone/index.vue +0 -121
- package/src/views/demo/bizTab/wf/billConfig.js +0 -44
- package/src/views/demo/bizTab/wf/detail.vue +0 -661
- package/src/views/demo/bizTab/wf/list.vue +0 -242
- package/src/views/user/outLink/cc_form_view.vue +0 -188
- /package/src/{resources → core-resources}/js/base/common.js +0 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
# qiankun 微前端接入协议
|
|
2
|
+
|
|
3
|
+
> 适用对象:接入本体系的 **主应用**(引包 / 未引包・异构技术栈均可)与 **子应用**(引包)。
|
|
4
|
+
> 配套实现方案:`docs/qiankun微前端改造-实现方案.md`。本文是对外的最小接入契约,实现细节以方案文档为准。
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 1. 核心约定(一段话版本)
|
|
9
|
+
|
|
10
|
+
菜单的**访问路径**(`route || url`)形如 `/micro/{appCode}/...` 时归属子应用:固定前缀 `micro` 之后的那一段命中应用注册表里的 `appCode`,该菜单就由对应子应用渲染;不带 `/micro/` 前缀的一律归主应用。**表单菜单的唯一识别标识是 `type === 5`**。`base` 是保留段,表示组件在 `cloud-web-corejs` npm 包内(任何引包应用都能渲染,不表达归属)。qiankun 的 activeRule 直接由 appCode 推导(`#/micro/{appCode}`),因此菜单路径无需任何改写即可触发子应用装载。
|
|
11
|
+
|
|
12
|
+
访问路径的四段语义:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
/micro/mkweb/base/user/user/list
|
|
16
|
+
└─┬──┘ └─┬─┘ └┬─┘ └──────┬─────┘
|
|
17
|
+
微前端 归属 来源 组件路径
|
|
18
|
+
固定前缀 appCode base=包内 剥掉前三段后的余量
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**为什么用固定前缀而不是"首段即 appCode"**:主应用自身的一级视图目录(`/user`、`/pmd`、`/yx`……)与 appCode 处在同一命名空间时会互相劫持——注册一个与视图目录同名的 appCode 会吞掉主应用整棵子树,而新增一个视图目录又会反向撞掉已在运行的 appCode。`/micro/` 让两者结构性隔离,不需要维护保留字清单。
|
|
22
|
+
|
|
23
|
+
## 2. 应用注册表
|
|
24
|
+
|
|
25
|
+
- **载体**:逻辑参数,编码 `micro_app_registry`。
|
|
26
|
+
- **获取**(需登录态,与业务接口同一套 token):
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
POST {BASE_API}/user/logic_param/getParamValue
|
|
30
|
+
Body: { "paramCode": "micro_app_registry" }
|
|
31
|
+
返回: objx 字段为 JSON 字符串
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- **JSON 结构**(数组):
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
[
|
|
38
|
+
{
|
|
39
|
+
"appCode": "appA", // 必填,^[A-Za-z][A-Za-z0-9_-]*$
|
|
40
|
+
"appName": "营销子应用", // 展示名,缺省用 appCode
|
|
41
|
+
"entry": "//xxx.com/appA/", // 必填,非空字符串(见下方说明)
|
|
42
|
+
"enabled": true // 停用置 false,无需删条目
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- **appCode 命名禁区**:不得为 `base`(组件来源命名空间)、`micro` 或 `micro_debug`(前缀自身)。因为 appCode 活在 `/micro/` 命名空间内,**无需再回避各应用 `@/views` 一级目录名**。
|
|
48
|
+
- **`entry` 只能是字符串,不分环境**。曾经支持 `{ development, production }` 对象写法,已废弃——注册表存在后端逻辑参数里,本身就按环境分库,主应用连哪个后端就拿到哪份注册表,再按前端 `NODE_ENV` 分一次是重复机制。本机联调走 2.1 的 `/micro_debug/` 命名空间,显式且不依赖构建环境。写成对象会被 `validateRegistry` 判为非法条目并跳过。
|
|
49
|
+
- **`entry` 必须指向 `index.html` 的真实所在目录**,`/mkweb/` 这类前缀不能省,原因见 4.1。建议用协议相对地址(`//host/...`)跟随主应用的 http/https。
|
|
50
|
+
- 校验参考实现:`cloud-web-corejs/src/utils/menuAdapter.js` 的 `validateRegistry`(非法条目跳过并显式报错,请勿静默吞掉)。
|
|
51
|
+
|
|
52
|
+
### 2.1 本机调试(切换命名空间,无状态)
|
|
53
|
+
|
|
54
|
+
**前置:逻辑参数 `micro_debug_enabled` 必须为 `true`**,默认关闭。见本节末尾的安全说明。
|
|
55
|
+
|
|
56
|
+
把地址里的 `/micro/` 改成 `/micro_debug/`,该子应用即从**本机约定端口**装载,其余一切不变:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
正式:http://主应用域名/sys/index.html#/micro/mkweb/base/user/user/list
|
|
60
|
+
调试:http://主应用域名/sys/index.html#/micro_debug/mkweb/base/user/user/list
|
|
61
|
+
^^^^^^^^^^^ → http://localhost:17527/
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
两个命名空间**归属相同、菜单相同、组件解析完全相同,只有 entry 不同**。因此:
|
|
65
|
+
|
|
66
|
+
- **联调不用改数据库**——菜单表里还是 `/micro/mkweb/...`,主应用下发 props 时才把路径换到调试命名空间;
|
|
67
|
+
- **不需要和子应用的 `settings.appCode` 对暗号**——appCode 仍是 `mkweb`,菜单照常派发;
|
|
68
|
+
- **调试态不落任何存储**,路径本身就是开关。关掉调试 = 把 `/micro_debug/` 改回 `/micro/`,或直接关标签页。分享链接不会让别人莫名其妙进入调试态,也不存在"几天前的调试残留导致线上白屏"。
|
|
69
|
+
|
|
70
|
+
同一个 appCode 的正式态与调试态是**两个独立保活实例**(容器 `#Appmicro-mkweb` 与 `#Appmicro-mkweb_micro_debug`),可以同时开着两个页签对比。首次装载调试实例时控制台有 ⚠ 告警。
|
|
71
|
+
|
|
72
|
+
| 项 | 约定值 |
|
|
73
|
+
|---|---|
|
|
74
|
+
| 调试 entry | `http://localhost:17527/`(包内常量 `DEBUG_ENTRY`) |
|
|
75
|
+
|
|
76
|
+
**开关:逻辑参数 `micro_debug_enabled`(默认关闭)**
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
POST {BASE_API}/user/logic_param/getParamValue
|
|
80
|
+
Body: { "paramCode": "micro_debug_enabled" }
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
| 值 | 含义 |
|
|
84
|
+
|---|---|
|
|
85
|
+
| `true` | 开启(忽略大小写与首尾空格) |
|
|
86
|
+
| 其余一切——不存在 / 空 / `false` / 认不出的值 | **关闭**(默认;取值失败、超时也回落到这里) |
|
|
87
|
+
|
|
88
|
+
只认 `true` 一个字面量、其余一律关闭,是有意的安全默认:认不出就不放行,不会因为写了个形近值(`1`、`on`、`是`)而把某个环境悄悄放开。开关是全局的,不区分应用。
|
|
89
|
+
|
|
90
|
+
**为什么单独一条参数、而不是放注册表字段或 `settings.js`**:
|
|
91
|
+
- 不放 `settings.js` —— 那是构建期常量、发版即锁死,同一份产物部署到测试和生产就区分不了;逻辑参数按环境分库,运维改值即刻生效,不用重新发版。
|
|
92
|
+
- 不放注册表 —— 注册表描述"有哪些应用",是相对静态的结构;调试开关是环境级运维动作,两者生命周期不同。分开之后开关调试不必编辑注册表 JSON,少一类把注册表改坏的风险,两个参数还能配不同的操作权限。
|
|
93
|
+
|
|
94
|
+
主应用在登录后**并行**取这两条参数(`Promise.all`,互不依赖),不额外增加串行耗时。
|
|
95
|
+
|
|
96
|
+
> ⚠ **默认关闭是安全要求,不是保守**:`/micro_debug/` 会让当前页面去加载**访问者本机 17527 端口**的代码,并经 props 把 token 交给它。正常情况那是开发者自己的 devServer,但只要有恶意程序占住这个端口,一条链接就能让它拿到该环境的登录态。**生产环境不应配置 `micro_debug_enabled`**(或显式置 `0`)。
|
|
97
|
+
>
|
|
98
|
+
> 关闭状态下的表现:全部应用都没开时**连路由都不注册**,`/micro_debug/...` 直接落 404;有别的应用开着而当前这个没开,则命中通配路由并在控制台报错说明原因,不会静默白屏。
|
|
99
|
+
|
|
100
|
+
> **端口是固定的,不可配**。这是无状态设计的代价:没有存储也没有查询参数,就没有地方放"用哪个端口"。要调的子应用把 devServer 端口设成 17527 即可(`vue.config.js` 里写死,不要用 `--port` 覆盖)。
|
|
101
|
+
> 调试 entry **只写端口、不带应用前缀**,这样一个约定值对所有子应用通用(各应用 `WEB_PREFIX` 不同:`/sys`、`/mkweb`……)。代价是子应用 devServer 必须把根路径做成 `publicPath` 的别名,见 4.1。
|
|
102
|
+
|
|
103
|
+
**调试直达(免配菜单)**:调试命名空间装载的子应用会收到 `props.microDebug = true`,据此追加一条按访问路径解析组件的兜底路由(剥归属前缀 → `/base` 命名空间 → `loadView`,解析不出落提示页)。因此联调期可以直接用 URL 打开**尚未配置菜单**的页面:
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
http://主应用域名/sys/index.html#/micro_debug/mkweb/base/user/positon/list
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
> 正式命名空间**不会**收到该标记——菜单即权限边界,不能让任意路径都打得开组件。
|
|
110
|
+
> 派发模式下子应用路由完全来自 `props.menus`,没有这条兜底时访问未配菜单的路径会由子应用自身跳 404(表现为主应用已把地址交出去、页面却是 404)。
|
|
111
|
+
|
|
112
|
+
## 3. 菜单识别与派发(主应用职责)
|
|
113
|
+
|
|
114
|
+
1. 登录后并行获取:全量菜单 `POST {BASE_API}/user/menu/currentList` + 上述注册表。
|
|
115
|
+
2. 对每条菜单:取访问路径 `route || url`(忽略查询串);首段为 `micro`(或 `micro_debug`)且第二段命中注册表 `appCode` → 归属该子应用;其余(无微前端前缀 / `appCode` 未命中)→ 主应用。菜单表里只会出现 `micro`,`micro_debug` 由主应用在下发 props 时临时改写,不落库。
|
|
116
|
+
3. **表单菜单(`type === 5`)与普通菜单走同一归属规则**,代码层面不做任何特殊处理。但**表单渲染器在 npm 包内**(`@base/views/user/form/view/list`),未引包子应用没有这个组件,所以「表单菜单只挂在引包子应用名下」是一条**配置纪律**,由配置人保证。曾用注册表字段 `hasCorejs` 做过强制校验,已移除——见下方说明。
|
|
117
|
+
|
|
118
|
+
> **为什么不用代码强制**:校验的兜底动作只能是「退回主应用渲染」,而这恰恰违背本方案的前提(表单依赖归属应用的私有代码,主应用代渲染必然行为错乱)。且未引包子应用根本不跑本包,配置错了在联调第一天就会暴露,不会潜伏到线上。字段本身还引入了更隐蔽的故障:漏写即视同"不能渲染表单",菜单被静默改道。
|
|
119
|
+
> 将来若确实需要能力校验,正确形态是**由子应用自己声明能力**(它才知道自己能渲染什么),而不是在注册表里让配置人替它猜。
|
|
120
|
+
4. 归属子应用的菜单:主应用不为其生成本地组件路由,只保证 URL 进入 `#/micro/{appCode}/...` 后有一条通配路由不落 404;菜单原路径即可触发 activeRule。调试命名空间全局只需一条 `/micro_debug/:appCode/*`,不按应用展开。
|
|
121
|
+
5. 参考实现(零依赖纯函数,可 deep-import):
|
|
122
|
+
`cloud-web-corejs/src/utils/menuAdapter.js` → `isFormMenu / resolveOwner / dispatchMenus / validateRegistry / resolveEntry`。
|
|
123
|
+
|
|
124
|
+
## 4. 子应用注册(主应用职责)
|
|
125
|
+
|
|
126
|
+
| 项 | 约定 |
|
|
127
|
+
|---|---|
|
|
128
|
+
| name | `appCode`(调试实例为 `{appCode}@micro_debug`,与正式实例各自保活) |
|
|
129
|
+
| entry | 注册表 `entry` 原样;调试实例固定 `http://localhost:17527/` |
|
|
130
|
+
| activeRule | hash 前缀匹配:`#/micro/{appCode}` 及其 `/...`、`?...` 形态;调试实例同理匹配 `#/micro_debug/{appCode}` |
|
|
131
|
+
| container | 主应用自定(引包主应用固定 `#Appmicro`) |
|
|
132
|
+
| 注册范围 | 全部 `enabled` 应用(qiankun 惰性加载,无需按菜单筛选) |
|
|
133
|
+
|
|
134
|
+
引包主应用:**零代码配置**——`microMainEnabled` 默认开启,配好第 2 节的逻辑参数注册表即自动完成本节与第 3 节(包内已实现);注册表未配置时无任何宿主行为。不想当宿主的应用在自身 `settings.js` 显式置 `microMainEnabled: false`。
|
|
135
|
+
未引包主应用:按本文自行调用 `registerMicroApps` + `start()`。
|
|
136
|
+
|
|
137
|
+
> **沙箱红线**:`start()` 保持默认沙箱(ProxySandbox),**严禁配置 `sandbox: { loose: true }`**。
|
|
138
|
+
> loose 模式下子应用对 window 的写入穿透到真实 window,`window.$vueRoot`、前缀常量等会被主子互相覆盖,本协议的隔离结论全部失效。
|
|
139
|
+
|
|
140
|
+
> **互访形态**:`microMainEnabled` 默认开启,任何引包应用(含子应用)独立运行时天然是宿主——所在环境配置了注册表即可装载其他应用实现互访。宿主逻辑会**自动排除注册表中与自身 `appCode` 相同的条目**(防自嵌套)。代价自评估:任意两应用间需互放 CORS(同域网关则无此项)、系统出现多个等价入口;不想参与互访的应用置 `microMainEnabled: false` 退出。被 qiankun 挂载时宿主行为始终强制关闭,不会出现嵌套装载。
|
|
141
|
+
|
|
142
|
+
### 4.1 entry 与 publicPath 的绑定关系
|
|
143
|
+
|
|
144
|
+
**entry 必须指向子应用 `index.html` 的真实所在目录**,不能随意省略路径段。原因:qiankun 取 entry 的目录作为 `__INJECTED_PUBLIC_PATH_BY_QIANKUN__` 注入子应用,`public-path.js` 用它覆盖 `__webpack_public_path__`,此后**所有懒加载 chunk 都从这里取**。本体系的视图全是 `() => import()`,entry 与真实 publicPath 不一致时首页能出、点第一个菜单必 404。
|
|
145
|
+
|
|
146
|
+
各应用 `publicPath = WEB_PREFIX + "/"`,而 `WEB_PREFIX` 各不相同(`/sys`、`/mkweb`……),所以正式注册表的 `entry` 要带各自前缀,例如 `//xxx.com/mkweb/`。
|
|
147
|
+
|
|
148
|
+
**但调试默认值要保持通用**,不能写死某个应用的前缀。做法是给子应用 devServer 加根路径别名,把不带前缀的请求改写到 `publicPath` 下(`vue.config.js` → `devServer.setupMiddlewares`,包内模板已含):
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
/ -> /mkweb/ (entry 从根拿 index.html)
|
|
152
|
+
/js/app.js -> /mkweb/js/app.js (注入 publicPath 为根,懒加载 chunk 回落到真实位置)
|
|
153
|
+
/mkweb/... -> 原样 (已带前缀不改写)
|
|
154
|
+
/ws -> 原样 (dev-server 自身端点放行)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
这样调试入口统一写 `http://localhost:17527/`,一个默认值对所有子应用通用;仅开发服务器生效,生产部署路径不变,原带前缀的地址同时照常可用。
|
|
158
|
+
|
|
159
|
+
> 不要试图改用 `publicPath: "/"` 达到同样效果:`WEB_PREFIX` 由 `utils/vab.js` 注入为 `window.WEB_PREFIX`,ace/tinymce 等静态资源路径(`window.WEB_PREFIX + "/base/..."`)与登录流程的前缀比对都依赖它,跟着改会连带打断开发环境登录跳转。
|
|
160
|
+
|
|
161
|
+
## 5. props 下发协议(主 → 子,mount 时)
|
|
162
|
+
|
|
163
|
+
```js
|
|
164
|
+
{
|
|
165
|
+
appCode: "appA", // 子应用编码
|
|
166
|
+
menus: [ /* 菜单行数组 */ ], // 归属该子应用的菜单子集(currentList 原始行结构)
|
|
167
|
+
token: "...", // 登录 token。存 sessionStorage 按 origin 隔离,跨域/跨端口主应用
|
|
168
|
+
// 必须显式下发;引包子应用 mount 时写入自身登录态实现免登,
|
|
169
|
+
// token 失效则自动回落到子应用登录页
|
|
170
|
+
lang: "zh", // 当前语言(localStorage "i18n-lang")
|
|
171
|
+
userInfo: { // 登录信息快照(注册时快照,非实时)
|
|
172
|
+
userId: "...",
|
|
173
|
+
loginAccount: "...",
|
|
174
|
+
name: "...",
|
|
175
|
+
nickName: "...",
|
|
176
|
+
companyCode: "...",
|
|
177
|
+
companyInfoId: "...",
|
|
178
|
+
roles: [],
|
|
179
|
+
userFlag: null
|
|
180
|
+
},
|
|
181
|
+
mainAdapter: { // 主应用回调,子应用跳主应用路由的唯一合法通道
|
|
182
|
+
navigate(path) {}, // 跳转主应用路由
|
|
183
|
+
openTab(path) {}, // 打开主应用页签
|
|
184
|
+
closeTab(view) {} // 关闭当前/指定页签
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
> **`lang` 与 `userInfo` 主要服务于未引包子应用**——它们没有本包的 i18n 机制,也没有 `getInfo2` 可调,只能靠这两个 props 拿到语言和登录态。
|
|
190
|
+
> **引包子应用有意不消费它们**:语言读同源共享的 localStorage `i18n-lang`(下方说明),登录态用 token 自行调 `getInfo2` 填 `user` store。两者都是比"注册时快照"更权威、不会过期的来源;再存一份 props 副本只会让业务代码读到哪个全看运气。所以包内看不到消费方是设计结果,不是遗漏,请勿据此删除这两个字段。
|
|
191
|
+
|
|
192
|
+
**运行期变化——语言为整页刷新语义,无需广播**:主应用切语言 = 后端 switchLanguage + 写 localStorage `i18n-lang` + `location.reload()`;reload 后子应用随页面重挂,启动时读取**同源共享**的 localStorage(qiankun 沙箱不隔离 localStorage),语言天然一致。登出同理由主应用真正卸载子应用覆盖。`initGlobalState` 作为**预留机制**,当前无必须事件;将来出现真实运行期事件时按以下信封启用,不再另行设计:
|
|
193
|
+
|
|
194
|
+
```js
|
|
195
|
+
// 主应用 initGlobalState 初始状态
|
|
196
|
+
{ event: null }
|
|
197
|
+
// 广播:setGlobalState({ event: { type: "xxx", payload: {...}, seq: 自增 } })
|
|
198
|
+
// seq 保证同 type 连发也触发变更;event 字段所有权归主应用,子应用只读;
|
|
199
|
+
// 子应用 mount 时 props.onGlobalStateChange(handler, true) 挂监听,unmount 由 qiankun 自动清理
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**保活协议**:主应用以 `loadMicroApp` 保活模式装载子应用——切走只隐藏容器不卸载,切回显示。**登出时主应用必须真正卸载全部保活子应用**(引包主应用已内置:resetToken → unmountAllMicroApps;异构主应用自行调用各实例 `unmount()`),否则换账号后切回子应用会复活上一个用户的实例。子应用需导出 `update(props)` 生命周期并响应 `props.microActive`:`false` = 容器已隐藏,暂停自身路由对 URL 变化的响应(否则会与主应用互相回写 URL);`true` = 容器恢复显示,恢复路由响应并把当前 hash 同步为自身当前路由。引包子应用无需自行实现(包内已内置);异构子应用若不实现 `update`,隐藏期间其路由仍在监听,浏览器前进/后退可能引发 URL 互踩,须自行处理。
|
|
203
|
+
**刷新协议**:页签"刷新"按钮由主应用渲染,但子应用页面不在主应用 `router-view` 内——主应用那套 `delCachedView` + `/redirect` 重建对它无效,走一圈只是容器隐藏再显示、实例毫发无损,表现为**点刷新没反应**。因此主应用检测到当前路由 `meta.isMicroApp` 时改为下发 `update({ microRefresh: <时间戳> })`,由子应用**原地销毁重建**当前页组件。时间戳保证连续点击每次都是新值。异构子应用响应该字段即可;不响应则刷新按钮在该应用页面上无效果。
|
|
204
|
+
|
|
205
|
+
> ⚠ **子应用重建时不得跳 `/redirect`**(主应用自身刷新用的那一招):主子共用同一个浏览器 hash,跳 `/redirect` 会被主应用 `afterEach` 判成"离开子应用路由",容器随即隐藏并下发 `microActive: false` 暂停子应用路由,重建被掐断——表现和不实现 `update` 一样,点刷新没反应。引包侧的做法是自增一个序号,由 `AppMain` 用 `v-if` 开关销毁重建组件,全程不碰 URL;异构子应用同理,用框架自身的强制重挂机制(如改 `key`)即可。
|
|
206
|
+
|
|
207
|
+
**异构子应用推荐做法**:qiankun 挂载时路由用 **memory 模式**(vue-router 4 `createMemoryHistory` / react-router `MemoryRouter`),子应用完全不读写浏览器 URL,天然满足暂停要求——只需在 `mount` 与 `microActive: true` 时把当前 hash 剥掉 `/{appCode}` 前缀后同步为自身路由。参考工程:`vue3-qiankun-child-demo`(Vue 3 + vue-router 4 最小接入示例)。
|
|
208
|
+
|
|
209
|
+
**自治嵌入模式(menus 不下发)**:主应用 props 里 `menus` 传 `null` 或不传(**非数组**)时,引包子应用进入自治模式——自拉全量菜单、保留自身侧边栏/页签壳,整站运行在容器内,登录也由子应用自己的登录页完成(token 存 sessionStorage,**按 origin 隔离**,跨端口/域的主应用无法复用既有登录态)。适合异构/未引包主应用把整个平台当"整站组件"嵌入、不关心菜单派发的场景,主应用零后端对接。注意语义区分:`menus: []`(空数组)= 标准派发模式但无菜单;`menus: null / 缺省` = 自治模式。参考工程:`vue3-qiankun-main-demo`(Vue 3 异构主应用,自治嵌入 cloud-web-corejs)。
|
|
210
|
+
|
|
211
|
+
## 6. 引包子应用接入步骤
|
|
212
|
+
|
|
213
|
+
新建引包工程请优先使用 [子应用模板与接入契约](./child-app/README.md),其中包含完整的应用文件和构建配置。下述片段仅说明微前端接入,不是完整脚手架。
|
|
214
|
+
|
|
215
|
+
1. **统一版本**:`cloud-web-corejs` 升级到基准版本(接入硬性前置)。
|
|
216
|
+
2. **声明身份**:自身 `settings.js` 填 `appCode`(与注册表一致)。
|
|
217
|
+
3. **入口导出生命周期**(新模板使用资源内置入口):
|
|
218
|
+
|
|
219
|
+
```js
|
|
220
|
+
// main.js
|
|
221
|
+
export * from "cloud-web-corejs/src/index.next.js";
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
旧工程的 `src/index.js` 入口仍兼容,但要求应用提供旧版 styles/icons;切换新入口需同步使用模板的 Sass/SVG 配置。
|
|
225
|
+
|
|
226
|
+
4. **打包配置**(vue.config.js):
|
|
227
|
+
|
|
228
|
+
```js
|
|
229
|
+
const packageName = require("./package.json").name;
|
|
230
|
+
const prefixConfig = require("./src/prefixConfig.js");
|
|
231
|
+
module.exports = {
|
|
232
|
+
devServer: {
|
|
233
|
+
headers: { "Access-Control-Allow-Origin": "*" }, // qiankun 跨域拉取
|
|
234
|
+
// 根路径别名:让调试 entry 免写应用前缀(见 4.1),仅开发服务器生效
|
|
235
|
+
setupMiddlewares: (middlewares) => {
|
|
236
|
+
const base = prefixConfig.WEB_PREFIX;
|
|
237
|
+
const passThrough = ["/ws", "/sockjs-node", "/webpack-dev-server", "/__"];
|
|
238
|
+
middlewares.unshift({
|
|
239
|
+
name: "qiankun-root-alias",
|
|
240
|
+
middleware: (req, res, next) => {
|
|
241
|
+
const url = req.url || "/";
|
|
242
|
+
const skip
|
|
243
|
+
= url.startsWith(base + "/")
|
|
244
|
+
|| url === base
|
|
245
|
+
|| passThrough.some((p) => url.startsWith(p));
|
|
246
|
+
if (!skip) {
|
|
247
|
+
req.url = base + (url === "/" ? "/" : url);
|
|
248
|
+
}
|
|
249
|
+
next();
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
return middlewares;
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
configureWebpack: {
|
|
256
|
+
output: {
|
|
257
|
+
library: `${packageName}-[name]`,
|
|
258
|
+
libraryTarget: "umd",
|
|
259
|
+
chunkLoadingGlobal: `webpackJsonp_${packageName}`, // webpack5 字段(webpack4 用 jsonpFunction)
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
> **package.json 的 `name` 必须各应用唯一**——webpack5 默认 chunk 注册全局名派生自它,
|
|
266
|
+
> 从模板复制工程不改 name 会导致主子 chunk 互相吞掉对方模块,
|
|
267
|
+
> 报错形如 `Cannot find module './node_modules/webpack-dev-server/client/...'`。
|
|
268
|
+
|
|
269
|
+
> **index.html 里 webpack 注入点之后不得再有任何 `<script>`**(含 `</body>` 之后的外链 SDK)——
|
|
270
|
+
> import-html-entry 取 html 最后一个 script 的导出当生命周期来源,尾部脚本会劫持入口判定,
|
|
271
|
+
> 报错 `You need to export lifecycle functions in xxx entry`(即使 main.js 导出正确)。
|
|
272
|
+
> 外链 SDK 一律放在 body 内靠前位置或 `<head>`。
|
|
273
|
+
|
|
274
|
+
5. **菜单配置**:普通私有页面访问路径为 `/micro/{appCode}/xx/xx`;包内页面为 `/micro/{appCode}/base/xx/xx`,也可用 `url=/base/xx/xx` 配合 `route=/micro/{appCode}/base/xx/xx`。表单菜单使用 `type === 5`,归属同样由 `route || url` 的 `/micro/{appCode}/` 前缀决定,表单编码和其他字段按实际后端契约填写。
|
|
275
|
+
6. **独立运行零改动**:`window.__POWERED_BY_QIANKUN__` 为假时走原有完整流程(自拉菜单、自建路由、自带壳)。
|
|
276
|
+
|
|
277
|
+
## 7. 部署 / 运维前置
|
|
278
|
+
|
|
279
|
+
- 子应用 nginx/网关放开对主应用域名的 CORS(qiankun 以 fetch 拉取子应用 entry 与静态资源)。
|
|
280
|
+
- token cookie 的域必须覆盖主、子应用。
|
|
281
|
+
- 各应用 `VUE_APP_BASE_API` / 接口前缀指向同一套网关。
|
|
282
|
+
|
|
283
|
+
## 8. 禁止事项
|
|
284
|
+
|
|
285
|
+
1. **跨应用组件引用**:A 应用的表单/脚本不得打开 B 应用的页面或弹框(qiankun 沙箱下不可实现,表单设计规范同步约束)。
|
|
286
|
+
2. **子应用直接操作主应用 router/store**:跳主应用路由一律走 `props.mainAdapter`。
|
|
287
|
+
3. **appCode 撞名**:见第 2 节命名禁区,注册前先核对各应用 `@/views` 一级目录。
|
|
288
|
+
4. **静默吞掉注册表校验错误**:非法条目必须显式报错(控制台/监控),否则故障表现为"子应用打不开"极难排查。
|
|
289
|
+
5. **流程/表单设计器类菜单配到子应用名下**:流程设计(activiti-explorer)经 iframe 以 `window.parent.xxx` 回调宿主页面,qiankun 沙箱内的赋值对真实 window 不可见,此类页面在子应用内必然失效——**必须归属主应用**。涉及菜单:流程管理配置(wf_obj_config)、表单模板的流程设计入口(form_template 各 list)。移动端原生壳回调(`window.fileUpload`)同理。
|
|
290
|
+
6. **`window.onxxx =` 直赋值注册事件**:沙箱代理上收不到真实事件,一律使用 `addEventListener`(沙箱会在卸载时自动清理)。
|
|
291
|
+
|
|
292
|
+
## 9. 兜底行为(体系内已实现,异构接入方对齐语义即可)
|
|
293
|
+
|
|
294
|
+
- **"归属别家"的判定依据 = 访问路径首段命中注册表里的 appCode**(2026-07-17 修正:不能用"首段 ≠ 自身 appCode"判定——主应用 appCode 为空会把一切加载失败误判成别家)。注册表未配置/不可用时永远不出"去主平台"文案。
|
|
295
|
+
- 应用独立运行点到别家菜单(首段命中注册表且非自身):提示页"该菜单归属应用「xx」,当前应用未部署对应页面,请在主平台中访问"(非异常,不弹错)。
|
|
296
|
+
- 主应用侧(appCode 为空)出现归属子应用的菜单走到本地加载:提示"检查应用注册表与子应用部署"(本应委派 qiankun 渲染,视为注册/部署异常)。
|
|
297
|
+
- 其余组件加载失败(含菜单指向不存在的组件、注册表解析失败):提示"页面组件加载失败,请检查菜单配置或应用注册表"。
|
|
298
|
+
- 边界:**没有路由的 URL 仍走全局 `*` → 404 页**;兜底提示页只出现在"菜单存在但组件加载失败"的路由上。
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# qiankun 详情承载 · 子应用对接清单
|
|
2
|
+
|
|
3
|
+
> 对象:被主应用(或另一引包应用)通过 `micro-view-host` 在弹框内装载、用来渲染**本子应用私有详情页**的子应用工程。
|
|
4
|
+
> 背景与整体设计:`docs/qiankun动态详情页承载方案.md`(§5 契约)。归属/命名空间:`docs/qiankun接入协议.md`。
|
|
5
|
+
> 一句话:当主应用要在弹框里打开一张**归属你、且组件在你 bundle 里**的单据详情页时,会 `loadMicroApp` 你的应用并下发一组约定 props;你需要在 `mount` 里认出这个模式,把目标详情页渲染出来,并把详情页的「刷新 / 关闭 / 回调」桥接回主应用。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. 触发方式
|
|
10
|
+
|
|
11
|
+
主应用的 `micro-view-host` 组件对归属你的 remote 详情页调用:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
loadMicroApp({
|
|
15
|
+
name: "<yourAppCode>@detailhost-<uniqueId>", // 唯一实例名,与路由保活实例(name=appCode)隔离
|
|
16
|
+
entry: "<注册表里你的 entry>",
|
|
17
|
+
container: <弹框内的独立容器 div>,
|
|
18
|
+
props: { …见第 2 节… }
|
|
19
|
+
})
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
与既有「路由驱动整站装载」是**两条独立通道**:整站装载走 `#/micro/<appCode>/...` 路由 + 保活;详情承载是弹框内的一次性实例,关框即 `unmount`。二者可能**同一个 appCode 同时存在多个实例**(一个保活整站 + 若干详情弹框)。
|
|
23
|
+
|
|
24
|
+
## 2. 你会收到的 props
|
|
25
|
+
|
|
26
|
+
| prop | 类型 | 含义 |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| `microDetailHost` | `true` | **模式标志**:为 `true` 时进入「详情承载」分支,**不要**渲染整站壳(无侧边栏/页签/登录/URL 读写) |
|
|
29
|
+
| `appCode` | string | 你的 appCode |
|
|
30
|
+
| `targetPath` | string | 已剥掉 `/micro/<appCode>` 的**子应用内路径**(如 `/user/bill/edit` 或 `/base/user/x`) |
|
|
31
|
+
| `bizParams` | object | 业务字段整包:`objTypeCode`/`formCode`/`dataId`/`_dataId`/`objId`/`param`/`queryParam` 等,**展开**绑给详情页 |
|
|
32
|
+
| `viewMeta` | object | 承载元数据:`{ visibleKey, defaultShowWfContent, viewType }`,按需绑给详情页 |
|
|
33
|
+
| `initialOutParam` | any | `outParam` 初值(对应旧 `:outParam.sync` 的入向) |
|
|
34
|
+
| `token` | string | 主应用当前 token——**必须写入你的鉴权态**,否则详情页内接口 401 |
|
|
35
|
+
| `lang` | string | 当前语言——设置你的 i18n locale |
|
|
36
|
+
| `onReload` | function | 上行回调,见第 4 节 |
|
|
37
|
+
| `onHandleCallback` | function | 同上 |
|
|
38
|
+
| `onClose` | function | 同上 |
|
|
39
|
+
| `onUpdateOutParam` | function | 同上 |
|
|
40
|
+
| `onEmit` | function | 同上 |
|
|
41
|
+
|
|
42
|
+
> 字段与函数名的权威来源:`src/components/micro-view-host/contract.js`(`DETAIL_HOST_MODE`、`DETAIL_HOST_CALLBACKS`、`buildDetailHostProps`)。**函数能直接传**是因为 `loadMicroApp` 的 props 与你同一个 JS realm——直接调用即可,无需事件总线。
|
|
43
|
+
|
|
44
|
+
## 3. mount 里要做的事
|
|
45
|
+
|
|
46
|
+
> **引包应用(`main.js` 为 `export * from "cloud-web-corejs/src/index"`)此分支已由 corejs 内置**——corejs `src/index.js` 的 `mount()` 已实现 `if (props.microDetailHost) return mountDetailHost(props)`,你**无需重写**,升级到含该实现的 corejs 版本即可。本节仅供:① 自定义了 `mount`(未纯 re-export corejs)的应用;② 异构技术栈子应用。引包应用只需过一遍第 6 节验收(尤其确认自己的私有详情页在承载态下行为正常)。
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
export async function mount(props) {
|
|
50
|
+
if (props.microDetailHost) {
|
|
51
|
+
return mountDetailHost(props); // ← 详情承载分支(corejs 已内置)
|
|
52
|
+
}
|
|
53
|
+
return mountFullSite(props); // ← 既有整站分支(不变)
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`mountDetailHost(props)` 需:
|
|
58
|
+
|
|
59
|
+
1. **同步鉴权与语言**:用 `props.token` 写入你的 token 存储(`setToken`),`props.lang` 设 i18n locale——详情页里的接口/文案依赖它。
|
|
60
|
+
2. **解析目标组件**:用 `props.targetPath` 解析出你 bundle 内的组件。可直接复用包内 helper:
|
|
61
|
+
`(await loadViewComponentAsync(props.targetPath, { appCode: props.appCode })).component`
|
|
62
|
+
(旧同步 `loadViewComponent` 已废弃并会抛错;必须等待异步解析完成后再渲染。)
|
|
63
|
+
(`targetPath` 无 `/micro/` 前缀,会解析成你的 `@/views` 或包内 `@base/views`。)
|
|
64
|
+
3. **渲染**:在 `container` 里 new 一个**独立 Vue 实例**(**router 建议用 memory 模式或不建 router**,绝不读写浏览器 URL),把组件渲染出来,绑定:
|
|
65
|
+
- `v-bind="props.bizParams"`(展开业务字段)
|
|
66
|
+
- `viewMeta` 里的 `visibleKey`/`defaultShowWfContent`/`viewType`(按详情页原有 prop 名)
|
|
67
|
+
- `:outParam` 初值 = `props.initialOutParam`
|
|
68
|
+
- 注入 **parentVue shim**(第 4 节)
|
|
69
|
+
4. **保存实例句柄**,供 `unmount` 用。
|
|
70
|
+
|
|
71
|
+
`unmount(props)` 需销毁该 Vue 实例、清空容器。**支持并发多实例**:每次 `mount` 用各自的容器与实例,不共享会互相踩的全局单例。
|
|
72
|
+
|
|
73
|
+
## 4. parentVue shim(关键,决定详情页不用重写)
|
|
74
|
+
|
|
75
|
+
现存详情页靠 `getTarget(this)` 走 `$parent` 链、`parentVue.$baseReload()`、`_handleCallback(flag)`、`this.$emit(...)`、`:outParam.sync` 与父级通信。跨应用后这些够不到主应用。**做法:合成一个 shim 对象注入给详情页,让它落在 `getTarget/parentVue` 能命中的位置,方法转调 props 回调**:
|
|
76
|
+
|
|
77
|
+
| 详情页里的调用 | shim 转调 |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `parentVue.$baseReload()` / `getTarget(this).$baseReload()` | `props.onReload()` |
|
|
80
|
+
| `this.$emit(name, ...args)`(父级 `v-on="listeners"` 那批) | `props.onEmit(name, ...args)` |
|
|
81
|
+
| `_handleCallback(flag)`(flag ∈ 1..4) | `props.onHandleCallback(flag)` |
|
|
82
|
+
| 关闭当前弹框 / `window.close` / `window.opener` 语义 | `props.onClose()` |
|
|
83
|
+
| `outParam` 变化(旧 `.sync` 出向) | `props.onUpdateOutParam(v)` |
|
|
84
|
+
|
|
85
|
+
主应用侧 `micro-view-host` 已把这些 props 回调对应 emit 成 `@reload`/`@handle-callback`/`@close`/`@update-out-param`/`@bridge-emit`,主应用弹框据此接回原有 handler。**你只需保证详情页调到 shim。**
|
|
86
|
+
|
|
87
|
+
> 详情页侧的最小改造(若无法完全靠 shim 落位):① `getTarget(this)` 能命中 shim;② 承载态短路 `window.opener` 直连,改走 `onClose`/`onEmit`。见方案 §5.6。
|
|
88
|
+
|
|
89
|
+
## 5. 不要做的事
|
|
90
|
+
|
|
91
|
+
- ❌ 渲染整站壳(侧边栏 / 页签 / 登录页)——`microDetailHost` 模式只出详情页本身。
|
|
92
|
+
- ❌ 读写浏览器 URL / hash——详情承载不是导航;用 memory 路由或无路由。
|
|
93
|
+
- ❌ 依赖全局单例(同一个 store/router 实例被多个详情弹框共享)——必须容忍并发多实例。
|
|
94
|
+
- ❌ 直接摸主应用 router / DOM——跨应用只走 props 回调。
|
|
95
|
+
|
|
96
|
+
## 6. 验收清单(联调时逐条过)
|
|
97
|
+
|
|
98
|
+
- [ ] `props.microDetailHost` 为真时只渲染详情页,无整站壳、无 URL 变化。
|
|
99
|
+
- [ ] `targetPath` 能正确解析到目标组件(`/base/...` → 包内;`/user/...` → 你的私有页)。
|
|
100
|
+
- [ ] 详情页内接口带上 `props.token`、文案按 `props.lang`。
|
|
101
|
+
- [ ] `bizParams`/`viewMeta`/`initialOutParam` 正确绑到详情页(对照旧弹框 `v-bind="param"` 等)。
|
|
102
|
+
- [ ] 详情页「提交/驳回/…」触发 `onHandleCallback(flag)`,主应用弹框收到 `@handle-callback` 并按 flag 关框/刷新。
|
|
103
|
+
- [ ] 详情页刷新触发 `onReload`;关闭触发 `onClose`;`outParam` 变化触发 `onUpdateOutParam`。
|
|
104
|
+
- [ ] 同一 appCode **同时**开着「整站保活实例」+「≥2 个详情弹框实例」互不串扰。
|
|
105
|
+
- [ ] 关框 `unmount` 后容器清空、无内存/监听泄漏,可重复开关。
|
|
106
|
+
|
|
107
|
+
## 7. 参考
|
|
108
|
+
|
|
109
|
+
- 主应用侧宿主实现:`src/components/micro-view-host/index.vue` + `contract.js`。
|
|
110
|
+
- 归属/组件路径解析:`src/utils/menuAdapter.js`、`src/utils/resolveViewComponent.js`。
|
|
111
|
+
- 整体方案与逐处站点:`docs/qiankun动态详情页承载方案.md`。
|
package/package.json
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cloud-web-corejs",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.1.0-dev.
|
|
4
|
+
"version": "1.1.0-dev.61",
|
|
5
5
|
"scripts": {
|
|
6
|
+
"build:ace-resources": "node build/build-ace-resources.js",
|
|
7
|
+
"build:tinymce-resources": "node build/build-tinymce-resources.js",
|
|
8
|
+
"build:luckysheet-resources": "node build/build-luckysheet-resources.js",
|
|
9
|
+
"build:activiti-resources": "node build/build-activiti-resources.js",
|
|
10
|
+
"check:resource-tools": "node --test tests/resources/*.test.js",
|
|
11
|
+
"check:package-size": "node build/check-package-size.js",
|
|
12
|
+
"create:child": "node bin/create-child-app.js",
|
|
13
|
+
"check:child-app": "node build/check-child-app.js",
|
|
14
|
+
"check:child-browser": "node build/check-child-browser.js",
|
|
6
15
|
"dev": "vue-cli-service serve",
|
|
7
16
|
"dev:micro": "vue-cli-service serve --port 17527",
|
|
17
|
+
"check:package-resources": "node build/check-package-resources.js",
|
|
18
|
+
"check:minimal-consumer": "node build/check-minimal-consumer-build.js",
|
|
8
19
|
"lint": "eslint --ext .js,.vue src",
|
|
9
20
|
"build:prod": "vue-cli-service build",
|
|
10
21
|
"build:stage": "vue-cli-service build --mode staging",
|
|
@@ -13,7 +24,7 @@
|
|
|
13
24
|
"new": "plop",
|
|
14
25
|
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
|
|
15
26
|
"test:unit": "jest --clearCache && vue-cli-service test:unit",
|
|
16
|
-
"test:ci": "npm run lint && npm run test:unit",
|
|
27
|
+
"test:ci": "npm run check:resource-tools && npm run check:package-resources && npm run check:package-size && npm run check:minimal-consumer && npm run lint && npm run test:unit",
|
|
17
28
|
"updateCorejs": "npm install cloud-web-corejs --registry https://registry.npmjs.org",
|
|
18
29
|
"publishDev": "npm publish --tag dev"
|
|
19
30
|
},
|
|
@@ -123,6 +134,13 @@
|
|
|
123
134
|
"npm": ">= 3.0.0"
|
|
124
135
|
},
|
|
125
136
|
"files": [
|
|
137
|
+
"bin/core-resources.js",
|
|
138
|
+
"resource-tools",
|
|
139
|
+
"bin/create-child-app.js",
|
|
140
|
+
"templates/child-app",
|
|
141
|
+
"docs/child-app",
|
|
142
|
+
"docs/qiankun接入协议.md",
|
|
143
|
+
"docs/qiankun详情承载子应用对接清单.md",
|
|
126
144
|
"src/components/advancedSearchDialog",
|
|
127
145
|
"src/components/baseAlert",
|
|
128
146
|
"src/components/baseAttachment",
|
|
@@ -175,7 +193,6 @@
|
|
|
175
193
|
"src/components/bizTab",
|
|
176
194
|
"src/api",
|
|
177
195
|
"src/views/bd",
|
|
178
|
-
"src/views/demo",
|
|
179
196
|
"src/views/support",
|
|
180
197
|
"src/views/user",
|
|
181
198
|
"src/views/mobile/user",
|
|
@@ -183,7 +200,9 @@
|
|
|
183
200
|
"src/mixins",
|
|
184
201
|
"src/directive",
|
|
185
202
|
"src/store",
|
|
186
|
-
"src/resources
|
|
203
|
+
"src/core-resources",
|
|
204
|
+
"src/styles",
|
|
205
|
+
"src/icons",
|
|
187
206
|
"src/lang/index.js",
|
|
188
207
|
"src/lang/locale/en/login.js",
|
|
189
208
|
"src/lang/locale/zh/login.js",
|
|
@@ -192,6 +211,12 @@
|
|
|
192
211
|
"src/router",
|
|
193
212
|
"src/permission.js",
|
|
194
213
|
"src/index.js",
|
|
214
|
+
"src/index.next.js",
|
|
215
|
+
"src/index.sync.js",
|
|
216
|
+
"src/boot-assets.legacy.js",
|
|
217
|
+
"src/boot-assets.next.js",
|
|
218
|
+
"src/app-bootstrap.js",
|
|
219
|
+
"src/app-bootstrap.sync.js",
|
|
195
220
|
"src/public-path.js",
|
|
196
221
|
"src/microRouter",
|
|
197
222
|
"src/App.vue"
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const crypto = require("crypto");
|
|
4
|
+
const hash = data => crypto.createHash("sha256").update(data).digest("hex");
|
|
5
|
+
const fail = message => { throw new Error(`[core-resources] ${message}`); };
|
|
6
|
+
function safePath(root, relative) {
|
|
7
|
+
if (typeof relative !== "string" || !relative || relative.includes("\\") ||
|
|
8
|
+
relative.split("/").some(p => !p || p === "." || p === "..") || path.isAbsolute(relative)) {
|
|
9
|
+
fail(`Unsafe path: ${relative}`);
|
|
10
|
+
}
|
|
11
|
+
const full = path.join(root, relative);
|
|
12
|
+
// Reject symlinks in every existing ancestor, including the destination root.
|
|
13
|
+
for (let current = full; ; current = path.dirname(current)) {
|
|
14
|
+
if (fs.existsSync(current) || (() => { try { return fs.lstatSync(current).isSymbolicLink(); } catch (_) { return false; } })()) {
|
|
15
|
+
if (fs.lstatSync(current).isSymbolicLink()) fail(`Symlink: ${current}`);
|
|
16
|
+
}
|
|
17
|
+
if (path.dirname(current) === current) break;
|
|
18
|
+
}
|
|
19
|
+
return full;
|
|
20
|
+
}
|
|
21
|
+
function readChecked(root, record, key = "file") {
|
|
22
|
+
const full = safePath(root, record[key]);
|
|
23
|
+
if (!fs.existsSync(full) || !fs.statSync(full).isFile()) fail(`Missing file: ${full}`);
|
|
24
|
+
const data = fs.readFileSync(full);
|
|
25
|
+
if (data.length !== record.size || hash(data) !== record.sha256) fail(`Integrity mismatch: ${full}`);
|
|
26
|
+
return data;
|
|
27
|
+
}
|
|
28
|
+
function assertExactTree(root, expected) {
|
|
29
|
+
const found = [];
|
|
30
|
+
function walk(directory, prefix = "") {
|
|
31
|
+
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
|
|
32
|
+
const relative = prefix + entry.name;
|
|
33
|
+
const full = safePath(root, relative);
|
|
34
|
+
if (entry.isDirectory()) walk(full, relative + "/");
|
|
35
|
+
else if (entry.isFile()) found.push(relative);
|
|
36
|
+
else fail(`Unsupported generated entry: ${relative}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
walk(root);
|
|
40
|
+
if (JSON.stringify(found.sort()) !== JSON.stringify([...expected].sort())) fail(`Unexpected generated files: ${root}`);
|
|
41
|
+
}
|
|
42
|
+
function plan(root) {
|
|
43
|
+
const configPath = path.join(root, "core-resources.config.js");
|
|
44
|
+
delete require.cache[configPath];
|
|
45
|
+
const config = require(configPath);
|
|
46
|
+
if (config.schemaVersion !== 1) fail("Unsupported config schemaVersion");
|
|
47
|
+
const runtime = { schemaVersion: 1, features: {} };
|
|
48
|
+
const records = [];
|
|
49
|
+
for (const [feature, option] of Object.entries(config.features || {})) {
|
|
50
|
+
if (!["codeEditor", "richText", "spreadsheet", "workflowDesigner"].includes(feature)) fail(`Unknown feature: ${feature}`);
|
|
51
|
+
if (option === false) continue;
|
|
52
|
+
const upstreamVersions = { codeEditor: "1.11.0", richText: "4.9.2", spreadsheet: "2.1.13", workflowDesigner: "5.17.0" };
|
|
53
|
+
if (!option || typeof option !== "object" || !option.package || !option.version) fail(`${feature}: package/version/profile required`);
|
|
54
|
+
const packageRoot = path.dirname(require.resolve(`${option.package}/package.json`, { paths: [root] }));
|
|
55
|
+
const pkg = JSON.parse(fs.readFileSync(safePath(packageRoot, "package.json")));
|
|
56
|
+
const manifest = JSON.parse(fs.readFileSync(safePath(packageRoot, "resources.json")));
|
|
57
|
+
const coreVersion = require("../package.json").version;
|
|
58
|
+
if (pkg.version !== option.version || manifest.version !== option.version || manifest.schemaVersion !== 1 ||
|
|
59
|
+
manifest.feature !== feature || manifest.compatibleCore !== coreVersion || manifest.upstreamVersion !== upstreamVersions[feature]) {
|
|
60
|
+
fail(`${feature}: incompatible artifact, expected exact version ${option.version} / Core ${coreVersion}`);
|
|
61
|
+
}
|
|
62
|
+
const profile = manifest.profiles[option.profile];
|
|
63
|
+
if (!profile) fail(`${feature}: unknown profile ${option.profile}`);
|
|
64
|
+
safePath(root, manifest.basePath.replace(/\/$/, ""));
|
|
65
|
+
runtime.features[feature] = { version: option.version, profile: option.profile, modes: profile.modes, locales: profile.locales, basePath: manifest.basePath };
|
|
66
|
+
const featureStart = records.length;
|
|
67
|
+
for (const record of manifest.files) {
|
|
68
|
+
// Validate even unselected records, so malformed manifests never pass silently.
|
|
69
|
+
safePath(packageRoot, record.file);
|
|
70
|
+
safePath(root, record.target);
|
|
71
|
+
if (!record.profiles.includes(option.profile)) continue;
|
|
72
|
+
if (records.some(r => r.target === record.target)) fail(`Duplicate target: ${record.target}`);
|
|
73
|
+
const appPath = safePath(path.join(root, "public"), record.target);
|
|
74
|
+
if (fs.existsSync(appPath)) fail(`Application public collision: ${record.target}`);
|
|
75
|
+
records.push({ ...record, data: readChecked(packageRoot, record) });
|
|
76
|
+
}
|
|
77
|
+
if (records.length === featureStart) fail(`${feature}: empty artifact`);
|
|
78
|
+
}
|
|
79
|
+
const snapshot = { runtime, files: records.map(({ target, size, sha256 }) => ({ target, size, sha256 })) };
|
|
80
|
+
return { runtime, records, snapshot, id: hash(JSON.stringify(snapshot)) };
|
|
81
|
+
}
|
|
82
|
+
function prepare(root, checkOnly = false) {
|
|
83
|
+
root = path.resolve(root);
|
|
84
|
+
const result = plan(root);
|
|
85
|
+
const generations = safePath(root, ".core-resources/generations");
|
|
86
|
+
const destination = safePath(generations, result.id);
|
|
87
|
+
if (!fs.existsSync(destination)) {
|
|
88
|
+
if (checkOnly) fail("Resources not prepared; run resources:prepare");
|
|
89
|
+
fs.mkdirSync(generations, { recursive: true });
|
|
90
|
+
const staging = fs.mkdtempSync(path.join(generations, ".stage-"));
|
|
91
|
+
fs.mkdirSync(path.join(staging, "public"));
|
|
92
|
+
for (const record of result.records) {
|
|
93
|
+
const target = safePath(path.join(staging, "public"), record.target);
|
|
94
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
95
|
+
fs.writeFileSync(target, record.data, { flag: "wx" });
|
|
96
|
+
}
|
|
97
|
+
fs.writeFileSync(path.join(staging, "ownership.json"), JSON.stringify(result.snapshot));
|
|
98
|
+
fs.renameSync(staging, destination);
|
|
99
|
+
}
|
|
100
|
+
const ownership = safePath(destination, "ownership.json");
|
|
101
|
+
if (fs.readFileSync(ownership, "utf8") !== JSON.stringify(result.snapshot)) fail(`Modified ownership: ${destination}`);
|
|
102
|
+
const directory = safePath(destination, "public");
|
|
103
|
+
assertExactTree(destination, ["ownership.json", ...result.records.map(r => "public/" + r.target)]);
|
|
104
|
+
for (const record of result.records) readChecked(directory, record, "target");
|
|
105
|
+
return { ...result, directory };
|
|
106
|
+
}
|
|
107
|
+
class ResourcesPlugin {
|
|
108
|
+
constructor(root) { this.root = root; }
|
|
109
|
+
apply(compiler) {
|
|
110
|
+
const prepared = prepare(this.root, true);
|
|
111
|
+
new compiler.webpack.DefinePlugin({ __CORE_RESOURCES__: JSON.stringify(prepared.runtime) }).apply(compiler);
|
|
112
|
+
compiler.hooks.thisCompilation.tap("CoreResources", compilation => {
|
|
113
|
+
compilation.hooks.processAssets.tap({ name: "CoreResources", stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS }, () => {
|
|
114
|
+
const current = prepare(this.root, true);
|
|
115
|
+
if (current.id !== prepared.id) fail("Configuration changed; restart dev/build");
|
|
116
|
+
for (const record of current.records) {
|
|
117
|
+
if (compilation.getAsset(record.target)) fail(`Build asset collision: ${record.target}`);
|
|
118
|
+
// Vendor artifacts are already minified and hash-locked. Terser must
|
|
119
|
+
// not rewrite them (or extract license comments into another file).
|
|
120
|
+
compilation.emitAsset(record.target, new compiler.webpack.sources.RawSource(record.data), { minimized: true });
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
module.exports = { prepare, plan, safePath, readChecked, ResourcesPlugin };
|